-
Notifications
You must be signed in to change notification settings - Fork 628
Stabilize observability #4563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Stabilize observability #4563
Conversation
c224f58 to
8d25f1c
Compare
a1bc62b to
d4a3459
Compare
0dd0605 to
8630d99
Compare
8630d99 to
4eb82da
Compare
Zac-HD
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(incomplete thoughts)
| coverage: bool = True | ||
| choices: bool = False | ||
| callbacks: tuple[Callable, ...] = field(default=(_deliver_to_file,)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| coverage: bool = True | |
| choices: bool = False | |
| callbacks: tuple[Callable, ...] = field(default=(_deliver_to_file,)) | |
| coverage: Literal["line", "branch"] | Collection[Literal["line", "branch"]] | None = None | |
| choices: Literal["values", "nodes"] | None = None | |
| callbacks: tuple[Callable[[dict], None], ...] = (_deliver_to_file,) |
plus validation to ensure that callbacks is nonempty, and a __or__/.union() method to merge configs
Alternatively we could make it easy to get the standard callback by making it a staticmethod on the ObservabilitySettings class 🤔
| # supported for backwards compat. These two were always marked experimental, so | ||
| # they can be removed whenever. 6 months would be more than generous. | ||
| if ( | ||
| envvar_value := os.environ.get("HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY") | ||
| ) is not None: # pragma: no cover | ||
| envvar_observability = ObservabilitySettings() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's also note_deprecation about this, so there's an explicit warning.
Alternatively I'd be fine with immediately and loudly breaking it; IMO "silently does nothing" is the worst option.
Zac-HD
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more notes after our in-person conversation; settings issue coming soon.
| When observability is enabled, Hypothesis will log various observations to jsonlines files in the | ||
| ``.hypothesis/observed/`` directory. You can load and explore these with e.g. | ||
| :func:`pd.read_json(".hypothesis/observed/*_testcases.jsonl", lines=True) <pandas.read_json>`, | ||
| or by using the :pypi:`sqlite-utils` and :pypi:`datasette` libraries:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs to note that callbacks can be customized / this is the default only.
| Choices metadata | ||
| ++++++++++++++++ | ||
|
|
||
| These additional metadata elements are included in ``metadata`` (as e.g. ``metadata["choice_nodes"]`` or ``metadata["choice_spans"]``), if and only if |OBSERVABILITY_CHOICES| is set. | ||
| These additional metadata elements are included in ``metadata`` (as e.g. ``metadata["choice_nodes"]`` or ``metadata["choice_spans"]``), if and only if observability is configured to include choices (see |ObservabilityConfig|). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want a similar heading for Coverage metadata, now that it's off by default?
And also note that the format of that is unstable, since we might want to switch representations
| Observability | ||
| ------------- | ||
|
|
||
| .. autofunction:: hypothesis.internal.observability.add_observability_callback | ||
| .. autofunction:: hypothesis.internal.observability.remove_observability_callback | ||
| .. autofunction:: hypothesis.internal.observability.with_observability_callback | ||
| .. autofunction:: hypothesis.internal.observability.observability_enabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
observability_enabled() should also be deleted, in favor of checking settings().observability is not None as we discussed.
| f.unlink(missing_ok=True) | ||
| envvar_value := os.environ.get("HYPOTHESIS_OBSERVABILITY") | ||
| ) is not None: # pragma: no cover | ||
| enabled = envvar_value in {"True", "true", "1"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think here we want to explicitly error if it's set and not in True/true/1/False/false/0; otherwise you can get the awkward situation where =yes is silently accepted, and then treated as false.
Closes #4387.
@settings(observability=...)takesTrue,False, orObservabilitySettings. If not set, inherits fromHYPOTHESIS_OBSERVABILITY, which is either true or false (noObservabilitySettingsparsing/control).HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_NOCOVERremoved with no deprecation periodHYPOTHESIS_EXPERIMENTAL_OBSERVABILITYandHYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_CHOICESkept for backwards-compat, but will be removed eventuallyobservability.OBSERVABILITY_COLLECT_COVERAGEandobservability.OBSERVABILITY_CHOICESreplaced withobservability.OBSERVABILITY_SETTINGSFor a future PR: with observability callbacks, there's no way to control
ObservabilitySettings. You don't want to set@settings(observability=ObservabilitySettings(...))on the test, because this would write to.hypothesis/observed, and you just want the observations in-memory.You can do this by monkeypatching
observability.OBSERVABILITY_SETTINGS. (indeed, hypofuzz does this right now). I'd like to get rid of that var, and addadd_observability_callback(options: ObservabilitySettings). But semantic questions like "what if two callbacks where only one setscoverage=True" have to be answered. I do think this can be done, I just don't want to do it right now. So I've left the var in, but undocumented.old description
@settings(observability=...)takes three possible values:observability=Trueenables observabilityobservability=Falsedisables observabilityobservability=[option1, option2], likeobservability=["coverage"], enables observability, and also enables whatever options are specified@settings(observability=...)is not set, inherit fromHYPOTHESIS_OBSERVABILITYenvvarHYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_NOCOVERremoved with no deprecation periodHYPOTHESIS_EXPERIMENTAL_OBSERVABILITYandHYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_CHOICESkept for backwards-compat because it was easy, but are now-undocumented and will be removed at some pointI'd like to keep a very clear separation between
@settings(observability=...), andadd_observability_callback. IMO the former should always write to/be related to.hypothesis/observed, and the latter should never be (ie it's sent in-memory).This brings up a non-trivial issue, probably for a future PR: when adding observability callbacks, there's no way to control the
coverageandchoicesoptions. You don't want to set@settings(observability=["choices"])on the test/profile, because this would write to.hypothesis/observed, and you just want the observations in-memory. Previously this was done withobservability.OBSERVABILITY_COLLECT_COVERAGEandobservability.OBSERVABILITY_CHOICES. I'd like to get rid of those vars eventually, and addadd_observability_callback(options=["coverage"]). But semantic questions like "what if two callbacks where only one sets options=["coverage"] have to be answered. I do think this can be done, I just don't want to do it right now. So I've left those vars in, though now un-documented.OBSERVABILITY_SETTINGSI'd also love to write a hypothesis.works blog post about this, at some point..
[cc @hgoldstein95]