### Execute test run with argument preparation Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Handles the setup of test arguments, printing of examples, and observability hooks during a single test run. ```python def run(data: ConjectureData) -> None: # Set up dynamic context needed by a single test run. if self.stuff.selfy is not None: data.hypothesis_runner = self.stuff.selfy # Generate all arguments to the test function. args = self.stuff.args kwargs = dict(self.stuff.kwargs) if example_kwargs is None: kw, argslices = context.prep_args_kwargs_from_strategies( self.stuff.given_kwargs ) else: kw = example_kwargs argslices = {} kwargs.update(kw) if expected_failure is not None: nonlocal text_repr text_repr = repr_call(test, args, kwargs) if print_example or current_verbosity() >= Verbosity.verbose: printer = RepresentationPrinter(context=context) if print_example: printer.text("Falsifying example:") else: printer.text("Trying example:") if self.print_given_args: printer.text(" ") printer.repr_call( test.__name__, args, kwargs, force_split=True, arg_slices=argslices, leading_comment=( "# " + context.data.slice_comments[(0, 0)] if (0, 0) in context.data.slice_comments else None ), avoid_realization=data.provider.avoid_realization, ) report(printer.getvalue()) if observability_enabled(): printer = RepresentationPrinter(context=context) printer.repr_call( test.__name__, args, kwargs, force_split=True, arg_slices=argslices, leading_comment=( "# " + context.data.slice_comments[(0, 0)] if (0, 0) in context.data.slice_comments else None ), avoid_realization=data.provider.avoid_realization, ) self._string_repr = printer.getvalue() try: return test(*args, **kwargs) except TypeError as e: # If we sampled from a sequence of strategies, AND failed with a # TypeError, *AND that exception mentions SearchStrategy*, add a note: if ( "SearchStrategy" in str(e) and data._sampled_from_all_strategies_elements_message is not None ): msg, format_arg = data._sampled_from_all_strategies_elements_message add_note(e, msg.format(format_arg)) raise finally: if data._stateful_repr_parts is not None: self._string_repr = "\n".join(data._stateful_repr_parts) if observability_enabled(): printer = RepresentationPrinter(context=context) for name, value in data._observability_args.items(): if name.startswith("generate:Draw "): try: value = data.provider.realize(value) except BackendCannotProceed: # pragma: no cover value = "" printer.text(f"\n{name.removeprefix('generate:')}: ") printer.pretty(value) self._string_repr += printer.getvalue() ``` -------------------------------- ### Get Example Value from Strategy Source: https://hypothesis.readthedocs.io/en/latest/_sources/tutorial/introduction.rst.txt Demonstrates the use of the `.example()` method on a Hypothesis strategy to retrieve a sample value. This method is intended for interactive use (REPL) and not for use within tests. ```pycon >>> st.lists(st.integers() | st.floats(allow_nan=False)).example() [-5.969063e-08, 15283673678, 18717, -inf] ``` -------------------------------- ### Example Execution Utilities Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Provides default and runner-specific execution logic for test examples. ```python def default_executor(data, function): return function(data) def get_executor(runner): try: execute_example = runner.execute_example except AttributeError: pass else: return lambda data, function: execute_example(partial(function, data)) if hasattr(runner, "setup_example") or hasattr(runner, "teardown_example"): setup = getattr(runner, "setup_example", None) or (lambda: None) teardown = getattr(runner, "teardown_example", None) or (lambda ex: None) def execute(data, function): token = None try: token = setup() return function(data) finally: teardown(token) return execute return default_executor ``` -------------------------------- ### Find minimal example Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Searches for the minimal example from a strategy that satisfies a given condition. ```python def find( specifier: SearchStrategy[Ex], condition: Callable[[Any], bool], *, settings: Settings | None = None, random: Random | None = None, database_key: bytes | None = None, ) -> Ex: """Returns the minimal example from the given strategy ``specifier`` that matches the predicate function ``condition``.""" if settings is None: settings = Settings(max_examples=2000) settings = Settings( settings, suppress_health_check=list(HealthCheck), report_multiple_bugs=False ) if database_key is None and settings.database is not None: # Note: The database key is not guaranteed to be unique. If not, replaying # of database examples may fail to reproduce due to being replayed on the # wrong condition. database_key = function_digest(condition) if not isinstance(specifier, SearchStrategy): raise InvalidArgument( f"Expected SearchStrategy but got {specifier!r} of " f"type {type(specifier).__name__}" ) specifier.validate() last: list[Ex] = [] @settings @given(specifier) def test(v): if condition(v): last[:] = [v] raise Found if random is not None: test = seed(random.getrandbits(64))(test) test._hypothesis_internal_database_key = database_key # type: ignore try: test() except Found: return last[0] raise NoSuchExample(get_pretty_function_description(condition)) ``` -------------------------------- ### Using @example for Specific Inputs Source: https://hypothesis.readthedocs.io/en/latest/_sources/tutorial/replaying-failures.rst.txt Use the `@example` decorator to explicitly provide inputs that Hypothesis will always run. These explicit examples run before randomly generated ones and do not undergo shrinking. ```python # two mersenne primes @example(2**17 - 1) @example(2**19 - 1) @given(st.integers()) def test_integers(n): pass test_integers() ``` ```python @example(2**17 - 1) @given(st.integers()) def test_something_with_integers(n): assert n < 100 ``` -------------------------------- ### Install Hypothesis Source: https://hypothesis.readthedocs.io/en/latest/_sources/quickstart.rst.txt Use pip to install the Hypothesis library. ```shell pip install hypothesis ``` -------------------------------- ### Configure Hypothesis Entry Point in pyproject.toml Source: https://hypothesis.readthedocs.io/en/latest/_sources/extensions.rst.txt Declare the Hypothesis setup hook as an entry point in your pyproject.toml file. This allows Hypothesis to automatically discover and run your setup function upon import. ```toml [project.entry-points.hypothesis] _ = "mymodule.a_submodule" ``` ```toml [project.entry-points.hypothesis] _ = "mymodule:_hypothesis_setup_hook" ``` -------------------------------- ### Generate interactive strategy examples Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/strategies/_internal/strategies.html Provides a method to generate an example value for exploration, intended for REPL use only. ```python def example(self) -> Ex: # FIXME """Provide an example of the sort of value that this strategy generates. This method is designed for use in a REPL, and will raise an error if called from inside |@given| or a strategy definition. For serious use, see |@composite| or |st.data|. """ if getattr(sys, "ps1", None) is None and ( # The main module's __spec__ is None when running interactively # or running a source file directly. # See https://docs.python.org/3/reference/import.html#main-spec. sys.modules["__main__"].__spec__ is not None # __spec__ is also None under pytest-xdist. To avoid an unfortunate # missed alarm here, always warn under pytest. or os.environ.get("PYTEST_CURRENT_TEST") is not None ): # pragma: no branch # The other branch *is* covered in cover/test_interactive_example.py; # but as that uses `pexpect` for an interactive session `coverage` # doesn't see it. warnings.warn( "The `.example()` method is good for exploring strategies, but should " "only be used interactively. We recommend using `@given` for tests - " "it performs better, saves and replays failures to avoid flakiness, " f"and reports minimal examples. (strategy: {self!r})", NonInteractiveExampleWarning, stacklevel=2, ) ``` -------------------------------- ### Generate example data in REPL Source: https://hypothesis.readthedocs.io/en/latest/tutorial/introduction.html Using the .example() method to inspect generated data during interactive development. ```python >>> st.lists(st.integers() | st.floats(allow_nan=False)).example() [-5.969063e-08, 15283673678, 18717, -inf] ``` -------------------------------- ### DirectoryBasedExampleDatabase configuration Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Example .gitignore configuration for sharing a directory-based database. ```text # Ignore files cached by Hypothesis... .hypothesis/* # except for the examples directory !.hypothesis/examples/ ``` -------------------------------- ### Execute Falsifying Example Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Re-runs a falsifying example to verify failure consistency and generate reproduction decorators. ```python ran_example = runner.new_conjecture_data( falsifying_example.choices, max_choices=len(falsifying_example.choices) ) ran_example.slice_comments = falsifying_example.slice_comments tb = None origin = None assert falsifying_example.expected_exception is not None assert falsifying_example.expected_traceback is not None try: with with_reporter(fragments.append): self.execute_once( ran_example, print_example=True, is_final=True, expected_failure=( falsifying_example.expected_exception, falsifying_example.expected_traceback, ), ) except StopTest as e: # Link the expected exception from the first run. Not sure # how to access the current exception, if it failed # differently on this run. In fact, in the only known # reproducer, the StopTest is caused by OVERRUN before the # test is even executed. Possibly because all initial examples # failed until the final non-traced replay, and something was # exhausted? Possibly a FIXME, but sufficiently weird to # ignore for now. err = FlakyFailure( "Inconsistent results: An example failed on the " "first run but now succeeds (or fails with another " "error, or is for some reason not runnable).", # (note: e is a BaseException) [falsifying_example.expected_exception or e], ) errors_to_report.append(ReportableError(fragments, err)) except UnsatisfiedAssumption as e: # pragma: no cover # ironically flaky err = FlakyFailure( "Unreliable assumption: An example which satisfied " "assumptions on the first run now fails it.", [e], ) errors_to_report.append(ReportableError(fragments, err)) except BaseException as e: # If we have anything for explain-mode, this is the time to report. fragments.extend(explanations[falsifying_example.interesting_origin]) error_with_tb = e.with_traceback(get_trimmed_traceback()) errors_to_report.append(ReportableError(fragments, error_with_tb)) tb = format_exception(e, get_trimmed_traceback(e)) origin = InterestingOrigin.from_exception(e) else: # execute_once() will always raise either the expected error, or Flaky. raise NotImplementedError("This should be unreachable") finally: ran_example.freeze() if observability_enabled(): # log our observability line for the final failing example tc = make_testcase( run_start=self._start_timestamp, property=self.test_identifier, data=ran_example, how_generated="minimal failing example", representation=self._string_repr, arguments=ran_example._observability_args, timing=self._timing_features, coverage=None, # Not recorded when we're replaying the MFE status="passed" if sys.exc_info()[0] else "failed", status_reason=str(origin or "unexpected/flaky pass"), metadata={"traceback": tb}, ) deliver_observation(tc) # Whether or not replay actually raised the exception again, we want # to print the reproduce_failure decorator for the failing example. if self.settings.print_blob: fragments.append( "\nYou can reproduce this example by temporarily adding " f"{reproduction_decorator(falsifying_example.choices)} " "as a decorator on your test case" ) ``` -------------------------------- ### Test with assume and example decorator Source: https://hypothesis.readthedocs.io/en/latest/changelog.html Demonstrates the improved interaction between assume() and the @example() decorator, preventing UnsatisfiedAssumption errors. ```python @given(value=floats(0, 1)) @example(value=0.56789) # used to make the test fail! @pytest.mark.parametrize("threshold", [0.5, 1]) def test_foo(threshold, value): assume(value < threshold) ... ``` -------------------------------- ### Run specific inputs with @example Source: https://hypothesis.readthedocs.io/en/latest/tutorial/replaying-failures.html Use the @example decorator to ensure specific inputs are always tested alongside randomly generated ones. ```python # two mersenne primes @example(2**17 - 1) @example(2**19 - 1) @given(st.integers()) def test_integers(n): pass test_integers() ``` -------------------------------- ### DirectoryBasedExampleDatabase implementation Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Methods for managing examples stored as files within a directory structure. ```python class DirectoryBasedExampleDatabase(ExampleDatabase): """Use a directory to store Hypothesis examples as files. Each test corresponds to a directory, and each example to a file within that directory. While the contents are fairly opaque, a |DirectoryBasedExampleDatabase| can be shared by checking the directory into version control, for example with the following ``.gitignore``:: # Ignore files cached by Hypothesis... .hypothesis/* # except for the examples directory !.hypothesis/examples/ Note however that this only makes sense if you also pin to an exact version of Hypothesis, and we would usually recommend implementing a shared database with a network datastore - see |ExampleDatabase|, and the |MultiplexedDatabase| helper. """ # we keep a database entry of the full values of all the database keys. # currently only used for inverse mapping of hash -> key in change listening. _metakeys_name: ClassVar[bytes] = b".hypothesis-keys" _metakeys_hash: ClassVar[str] = _hash(_metakeys_name) def __init__(self, path: StrPathT) -> None: super().__init__() self.path = Path(path) self.keypaths: dict[bytes, Path] = {} self._observer: BaseObserver | None = None self._ensure_directory_exists_called = False def _ensure_directory_exists(self) -> None: # disk hits are expensive: early-return for performance if self._ensure_directory_exists_called: return self.path.mkdir(exist_ok=True, parents=True) self._ensure_directory_exists_called = True def __repr__(self) -> str: return f"DirectoryBasedExampleDatabase({self.path!r})" def __eq__(self, other: object) -> bool: return ( isinstance(other, DirectoryBasedExampleDatabase) and self.path == other.path ) def _key_path(self, key: bytes) -> Path: try: return self.keypaths[key] except KeyError: pass self.keypaths[key] = self.path / _hash(key) return self.keypaths[key] def _value_path(self, key: bytes, value: bytes) -> Path: return self._key_path(key) / _hash(value) def fetch(self, key: bytes) -> Iterable[bytes]: kp = self._key_path(key) if not kp.is_dir(): return try: for path in os.listdir(kp): try: yield (kp / path).read_bytes() except OSError: pass except OSError: # pragma: no cover # the `kp` directory might have been deleted in the meantime pass def save(self, key: bytes, value: bytes) -> None: key_path = self._key_path(key) if key_path.name != self._metakeys_hash: # add this key to our meta entry of all keys - taking care to avoid # infinite recursion. self.save(self._metakeys_name, key) ``` -------------------------------- ### GitHub Actions workflow for example database artifacts Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Download example database artifacts in a GitHub Actions workflow to support test execution. ```yaml - name: Download example database uses: dawidd6/action-download-artifact@v9 with: name: hypothesis-example-db path: .hypothesis/examples if_no_artifact_found: warn workflow_conclusion: completed - name: Run tests run: pytest ``` -------------------------------- ### Label test examples with via Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Attach machine-readable labels to examples for documentation or tooling purposes. This method is a no-op at runtime. ```python # Annotating examples is optional and does not change runtime behavior @example(...) @example(...).via("regression test for issue #42") @example(...).via("discovered failure") def test(x): pass ``` -------------------------------- ### Injecting explicit inputs with @example Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Use @example to provide specific values that Hypothesis will test before generating random inputs. These inputs do not count towards max_examples and do not undergo shrinking. ```python @example("Hello world") @example("some string with special significance") @given(st.text()) def test_strings(s): pass ``` -------------------------------- ### Passing positional and keyword arguments to @example Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Arguments to @example must be provided as either positional or keyword arguments, but not both simultaneously. These values are treated as concrete inputs rather than strategies. ```python @example(1, 2) @example(x=1, y=2) @given(st.integers(), st.integers()) def test(x, y): pass ``` -------------------------------- ### InMemoryExampleDatabase implementation Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Methods for managing examples in an in-memory database structure. ```python def __eq__(self, other: object) -> bool: return isinstance(other, InMemoryExampleDatabase) and self.data is other.data def fetch(self, key: bytes) -> Iterable[bytes]: yield from self.data.get(key, ()) def save(self, key: bytes, value: bytes) -> None: value = bytes(value) values = self.data.setdefault(key, set()) changed = value not in values values.add(value) if changed: self._broadcast_change(("save", (key, value))) def delete(self, key: bytes, value: bytes) -> None: value = bytes(value) values = self.data.get(key, set()) changed = value in values values.discard(value) if changed: self._broadcast_change(("delete", (key, value))) def _start_listening(self) -> None: # declare compatibility with the listener api, but do the actual # implementation in .delete and .save, since we know we are the only # writer to .data. pass def _stop_listening(self) -> None: pass ``` -------------------------------- ### Example usage of binary_operation Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/extra/ghostwriter.html Demonstrates how to invoke the binary_operation ghostwriter with specific operator properties. ```python ghostwriter.binary_operation( operator.mul, identity=1, distributes_over=operator.add, style="unittest", ) ``` -------------------------------- ### example.xfail(condition=True, *, reason='', raises=BaseException) Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Marks a specific example as an expected failure, similar to pytest.mark.xfail. ```APIDOC ## example.xfail(condition=True, *, reason='', raises=BaseException) ### Description Marks the associated example as an expected failure. This is useful for documenting known issues or testing that specific inputs trigger expected exceptions. ### Parameters - **condition** (bool) - Optional - A boolean indicating if the failure is expected. Defaults to True. - **reason** (str) - Optional - A string explaining why the example is expected to fail. - **raises** (type[BaseException] | tuple[type[BaseException], ...]) - Optional - The exception type or tuple of types expected to be raised. ### Usage Example ```python @example(1).xfail(reason="Known bug") @given(st.integers()) def test(x): pass ``` ``` -------------------------------- ### Initialize Array API Strategies Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/extra/array_api.html Demonstrates how to initialize the array API namespace and generate an example array. ```python >>> xp.__array_api_version__ # xp is your desired array library '2021.12' >>> xps = make_strategies_namespace(xp) >>> xps.api_version '2021.12' >>> x = xps.arrays(xp.int8, (2, 3)).example() >>> x Array([[-8, 6, 3], [-6, 4, 6]], dtype=int8) >>> x.__array_namespace__() is xp True ``` -------------------------------- ### Example Test Failure Report Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/_settings.html An example of how a minimal failing example is reported by Hypothesis. ```python test_x_divided_by_y( x=0, # or any other generated value y=0, ) ``` -------------------------------- ### Handle failure reproduction and explicit examples Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Logic for checking reproduction decorators and executing explicit examples defined via @example. ```python if ( reproduce_failure := wrapped_test._hypothesis_internal_use_reproduce_failure ) is not None: expected_version, failure = reproduce_failure if expected_version != __version__: raise InvalidArgument( "Attempting to reproduce a failure from a different " f"version of Hypothesis. This failure is from {expected_version}, but " f"you are currently running {__version__!r}. Please change your " "Hypothesis version to a matching one." ) try: state.execute_once( ConjectureData.for_choices(decode_failure(failure)), print_example=True, is_final=True, ) raise DidNotReproduce( "Expected the test to raise an error, but it " "completed successfully." ) except StopTest: raise DidNotReproduce( "The shape of the test data has changed in some way " "from where this blob was defined. Are you sure " "you're running the same test?" ) from None except UnsatisfiedAssumption: raise DidNotReproduce( "The test data failed to satisfy an assumption in the " "test. Have you added it since this blob was generated?" ) from None # There was no @reproduce_failure, so start by running any explicit # examples from @example decorators. if errors := list( execute_explicit_examples( state, wrapped_test, arguments, kwargs, original_sig ) ): # If we're not going to report multiple bugs, we would have # stopped running explicit examples at the first failure. assert len(errors) == 1 or state.settings.report_multiple_bugs # If an explicit example raised a 'skip' exception, ensure it's never # wrapped up in an exception group. Because we break out of the loop # immediately on finding a skip, if present it's always the last error. if isinstance(errors[-1].exception, skip_exceptions_to_reraise()): # Covered by `test_issue_3453_regression`, just in a subprocess. del errors[:-1] # pragma: no cover if state.settings.verbosity < Verbosity.verbose: # keep only one error per interesting origin, unless # verbosity is high errors = _simplify_explicit_errors(errors) _raise_to_user(errors, state.settings, [], " in explicit examples") # If there were any explicit examples, they all ran successfully. # The next step is to use the Conjecture engine to run the test on # many different inputs. ran_explicit_examples = ( Phase.explicit in state.settings.phases and getattr(wrapped_test, "hypothesis_explicit_examples", ()) ) SKIP_BECAUSE_NO_EXAMPLES = unittest.SkipTest( "Hypothesis has been told to run no examples for this test." ) if not ( Phase.reuse in settings.phases or Phase.generate in settings.phases ): if not ran_explicit_examples: raise SKIP_BECAUSE_NO_EXAMPLES return ``` -------------------------------- ### SearchStrategy.example() Source: https://hypothesis.readthedocs.io/en/latest/reference/strategies.html Provides an example of the value generated by the strategy. This is intended for REPL use and will raise an error if called within a test context. ```APIDOC ## example() ### Description Provides an example of the sort of value that this strategy generates. This method is designed for use in a REPL, and will raise an error if called from inside @given or a strategy definition. ``` -------------------------------- ### Execute explicit examples Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Validates and executes explicit examples provided to a test function, ensuring argument consistency between @given and @example. ```python def execute_explicit_examples(state, wrapped_test, arguments, kwargs, original_sig): assert isinstance(state, StateForActualGivenExecution) posargs = [ p.name for p in original_sig.parameters.values() if p.kind is p.POSITIONAL_OR_KEYWORD ] for example in reversed(getattr(wrapped_test, "hypothesis_explicit_examples", ())): assert isinstance(example, Example) # All of this validation is to check that @example() got "the same" arguments # as @given, i.e. corresponding to the same parameters, even though they might # be any mixture of positional and keyword arguments. if example.args: assert not example.kwargs if any( p.kind is p.POSITIONAL_ONLY for p in original_sig.parameters.values() ): raise InvalidArgument( "Cannot pass positional arguments to @example() when decorating " "a test function which has positional-only parameters." ) if len(example.args) > len(posargs): raise InvalidArgument( "example has too many arguments for test. Expected at most " f"{len(posargs)} but got {len(example.args)}" ) example_kwargs = dict( zip(posargs[-len(example.args) :], example.args, strict=True) ) else: example_kwargs = dict(example.kwargs) given_kws = ", ".join( repr(k) for k in sorted(wrapped_test.hypothesis._given_kwargs) ) example_kws = ", ".join(repr(k) for k in sorted(example_kwargs)) if given_kws != example_kws: raise InvalidArgument( f"Inconsistent args: @given() got strategies for {given_kws}, " f"but @example() got arguments for {example_kws}" ) from None # This is certainly true because the example_kwargs exactly match the params # reserved by @given(), which are then remove from the function signature. assert set(example_kwargs).isdisjoint(kwargs) example_kwargs.update(kwargs) if Phase.explicit not in state.settings.phases: continue ``` -------------------------------- ### Define settings using strategy builds Source: https://hypothesis.readthedocs.io/en/latest/changelog.html Demonstrates the use of st.builds to capture settings. Note that this pattern is not recommended for general use. ```python import hypothesis.strategies as st from hypothesis import settings CURRENT_SETTINGS = st.builds(lambda: settings.default) ``` -------------------------------- ### Change Number of Examples with max_examples Source: https://hypothesis.readthedocs.io/en/latest/_sources/tutorial/settings.rst.txt Adjust the number of examples Hypothesis generates for a test using the `max_examples` setting. The default is 100. This example sets it to 5. ```python from hypothesis import given, settings, strategies as st @given(st.integers()) @settings(max_examples=5) def test(n): print("prints five times") ``` -------------------------------- ### Initialize File System Listener Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Sets up a watchdog observer to monitor file system changes, requiring the watchdog library. ```python def _start_listening(self) -> None: try: from watchdog.events import ( DirCreatedEvent, DirDeletedEvent, DirMovedEvent, FileCreatedEvent, FileDeletedEvent, FileMovedEvent, FileSystemEventHandler, ) from watchdog.observers import Observer except ImportError: warnings.warn( f"listening for changes in a {self.__class__.__name__} " "requires the watchdog library. To install, run " "`pip install hypothesis[watchdog]`", HypothesisWarning, stacklevel=4, ) return hash_to_key = {_hash(key): key for key in self.fetch(self._metakeys_name)} _metakeys_hash = self._metakeys_hash _broadcast_change = self._broadcast_change class Handler( FileSystemEventHandler ): # pragma: no cover # skipped in test_database.py for now def on_created(_self, event: FileCreatedEvent | DirCreatedEvent) -> None: # we only registered for the file creation event assert not isinstance(event, DirCreatedEvent) # watchdog events are only bytes if we passed a byte path to # .schedule assert isinstance(event.src_path, str) value_path = Path(event.src_path) # the parent dir represents the key, and its name is the key hash key_hash = value_path.parent.name if key_hash == _metakeys_hash: try: hash_to_key[value_path.name] = value_path.read_bytes() except OSError: # pragma: no cover # this might occur if all the values in a key have been # deleted and DirectoryBasedExampleDatabase removes its # metakeys entry (which is `value_path` here`). pass return ``` -------------------------------- ### Implement a SQLite-backed ExampleDatabase Source: https://hypothesis.readthedocs.io/en/latest/_sources/how-to/custom-database.rst.txt A custom database implementation using sqlite3 as the underlying storage mechanism. ```python import sqlite3 from collections.abc import Iterable from hypothesis.database import ExampleDatabase class SQLiteExampleDatabase(ExampleDatabase): def __init__(self, db_path: str): self.conn = sqlite3.connect(db_path) self.conn.execute(""" CREATE TABLE examples ( key BLOB, value BLOB, UNIQUE (key, value) ) """) def save(self, key: bytes, value: bytes) -> None: self.conn.execute( "INSERT OR IGNORE INTO examples VALUES (?, ?)", (key, value), ) def fetch(self, key: bytes) -> Iterable[bytes]: cursor = self.conn.execute("SELECT value FROM examples WHERE key = ?", (key,)) yield from [value[0] for value in cursor.fetchall()] def delete(self, key: bytes, value: bytes) -> None: self.conn.execute( "DELETE FROM examples WHERE key = ? AND value = ?", (key, value), ) ``` -------------------------------- ### Instantiate Database for Path Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Internal factory function to determine the appropriate ExampleDatabase implementation based on the provided path or environment configuration. ```python def _db_for_path( path: StrPathT | UniqueIdentifier | Literal[":memory:"] | None = None, ) -> "ExampleDatabase": if path is not_set: if os.getenv("HYPOTHESIS_DATABASE_FILE") is not None: # pragma: no cover raise HypothesisException( "The $HYPOTHESIS_DATABASE_FILE environment variable no longer has any " "effect. Configure your database location via a settings profile instead.\n" "https://hypothesis.readthedocs.io/en/latest/settings.html#settings-profiles" ) storage_dir = storage_directory("examples", intent_to_write=False) if not _usable_dir(storage_dir.path): # pragma: no cover warnings.warn( "The database setting is not configured, and the default " "location is unusable - falling back to an in-memory " f"database for this session. path={storage_dir.path!r}", HypothesisWarning, stacklevel=3, ) return InMemoryExampleDatabase() return _StorageDirectoryDatabase(storage_dir) if path in (None, ":memory:"): return InMemoryExampleDatabase() path = cast(StrPathT, path) return DirectoryBasedExampleDatabase(path) ``` -------------------------------- ### Pytest failure output Source: https://hypothesis.readthedocs.io/en/latest/quickstart.html Example of a test failure output showing the falsifying example. ```text $ pytest example.py ... @given(st.integers()) def test_integers(n): > assert n < 50 E assert 50 < 50 E Falsifying example: test_integers( E n=50, E ) ``` -------------------------------- ### Example Hypothesis Failure Output Source: https://hypothesis.readthedocs.io/en/latest/_sources/tutorial/adding-notes.rst.txt This is an example of the default output Hypothesis provides when a test fails. ```text Falsifying example: test_a_thing(x=1, y="foo") ``` -------------------------------- ### @example(*args, **kwargs) Source: https://hypothesis.readthedocs.io/en/latest/reference/api.html Adds an explicit input to a Hypothesis test. Hypothesis will attempt these inputs before generating random data. Arguments must be values, not strategies. ```APIDOC ## @example(*args, **kwargs) ### Description Adds an explicit input to a Hypothesis test, which Hypothesis will always try before generating random inputs. This combines the randomized nature of Hypothesis generation with a traditional parametrized test. ### Parameters - **args** (positional) - Optional - Positional arguments to pass to the test function. - **kwargs** (keyword) - Optional - Keyword arguments to pass to the test function. ``` -------------------------------- ### Explicit example non-shrinking behavior Source: https://hypothesis.readthedocs.io/en/latest/tutorial/replaying-failures.html Inputs provided via @example do not undergo shrinking when a test fails. ```python @example(2**17 - 1) @given(st.integers()) def test_something_with_integers(n): assert n < 100 ``` -------------------------------- ### example.via(whence) Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Attaches a machine-readable label to an example to document its origin. This is an optional metadata method that does not affect runtime behavior. ```APIDOC ## example.via(whence) ### Description Attaches a machine-readable label noting the origin of an example. This method is optional and intended for self-documenting code or external tooling. ### Parameters - **whence** (str) - Required - A string label describing the origin of the example. ``` -------------------------------- ### Validate @example decorator arguments Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Checks if strategies were incorrectly passed to the @example decorator instead of concrete values. ```python if isinstance(err, failure_exceptions_to_catch()) and any( isinstance(arg, SearchStrategy) for arg in example.args + tuple(example.kwargs.values()) ): new = HypothesisWarning( "The @example() decorator expects to be passed values, but " "you passed strategies instead. See https://hypothesis." "readthedocs.io/en/latest/reference/api.html#hypothesis" ".example for details." ) new.__cause__ = err err = new ``` -------------------------------- ### Prepare database for I/O Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Internal method to validate the downloaded artifact and initialize the access cache. ```python def _prepare_for_io(self) -> None: assert self._artifact is not None, "Artifact not loaded." if self._initialized: # pragma: no cover return # Test that the artifact is valid try: with ZipFile(self._artifact) as f: if f.testzip(): # pragma: no cover raise BadZipFile # Turns out that testzip() doesn't work quite well # doing the cache initialization here instead # will give us more coverage of the artifact. # Cache the files inside each keypath self._access_cache = {} with ZipFile(self._artifact) as zf: namelist = zf.namelist() # Iterate over files in the artifact for filename in namelist: fileinfo = zf.getinfo(filename) if fileinfo.is_dir(): self._access_cache.setdefault(PurePath(filename), set()) else: # Get the keypath from the filename keypath = PurePath(filename).parent # Add the file to the keypath self._access_cache.setdefault(keypath, set()).add( PurePath(filename) ) except BadZipFile: warnings.warn( "The downloaded artifact from GitHub is invalid. " "This could be because the artifact was corrupted, " "or because the artifact was not created by Hypothesis. ", HypothesisWarning, stacklevel=3, ) self._disabled = True self._initialized = True ``` -------------------------------- ### Setup and cache rules for state machines Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/stateful.html Caches rule sorting and strategy generation per machine class to optimize instantiation performance. ```python @classmethod @lru_cache def _setup_for( cls, machine_type: type[RuleBasedStateMachine] ) -> tuple[list["Rule"], frozenset[str], SearchStrategy]: # Cache (per machine class) the work of sorting the rules and building # the sampled_from strategy, which is O(number of rules) and would # otherwise be repeated every time the machine is instantiated; see # https://github.com/HypothesisWorks/hypothesis/issues/4465. rules = machine_type.setup_state().rules.copy() # The order is a bit arbitrary. Primarily we're trying to group rules # that write to the same location together, and to put rules with no # target first as they have less effect on the structure. We order from # fewer to more arguments on grounds that it will plausibly need less # data. This probably won't work especially well and we could be # smarter about it, but it's better than just doing it in definition # order. rules.sort( key=lambda rule: ( sorted(rule.targets), len(rule.arguments), rule.function.__name__, ) ) rule_names = frozenset(r.function.__name__ for r in rules) return (rules, rule_names, st.sampled_from(rules)) ``` -------------------------------- ### Custom executor running tests twice Source: https://hypothesis.readthedocs.io/en/latest/_sources/reference/api.rst.txt An example of an executor that runs the test logic twice for each generated example. ```python from unittest import TestCase class TestTryReallyHard(TestCase): @given(integers()) def test_something(self, i): perform_some_unreliable_operation(i) def execute_example(self, f): f() return f() ``` -------------------------------- ### Hypothesis Test Output Example Source: https://hypothesis.readthedocs.io/en/latest/_sources/quickstart.rst.txt Example output showing Hypothesis generating multiple integer inputs for a test. ```none called with 0 called with -18588 called with -672780074 called with 32616 ... ``` -------------------------------- ### Initialize Watchdog Observer Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/database.html Starts the file system observer for the database directory, ensuring the directory exists beforehand. ```python # If we add a listener to a DirectoryBasedExampleDatabase whose database # directory doesn't yet exist, the watchdog observer will not fire any # events, even after the directory gets created. # # Ensure the directory exists before starting the observer. self._ensure_directory_exists() self._observer = Observer() self._observer.schedule( Handler(), # remove type: ignore when released # https://github.com/gorakhargosh/watchdog/pull/1096 self.path, # type: ignore recursive=True, event_filter=[FileCreatedEvent, FileDeletedEvent, FileMovedEvent], ) self._observer.start() def _stop_listening(self) -> None: assert self._observer is not None self._observer.stop() self._observer.join() self._observer = None ``` -------------------------------- ### Define a Rule-Based State Machine Source: https://hypothesis.readthedocs.io/en/latest/_sources/stateful.rst.txt This example demonstrates the basic structure of a state machine for comparing a database implementation with an in-memory model. It sets up temporary directories, initializes the database and model, and defines bundles for keys and values. ```python import shutil import tempfile from collections import defaultdict import hypothesis.strategies as st from hypothesis.database import DirectoryBasedExampleDatabase from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule class DatabaseComparison(RuleBasedStateMachine): def __init__(self): super().__init__() self.tempd = tempfile.mkdtemp() self.database = DirectoryBasedExampleDatabase(self.tempd) self.model = defaultdict(set) keys = Bundle("keys") values = Bundle("values") @rule(target=keys, k=st.binary()) def add_key(self, k): return k @rule(target=values, v=st.binary()) def add_value(self, v): return v @rule(k=keys, v=values) def save(self, k, v): self.model[k].add(v) ``` -------------------------------- ### Hypothesis Test Failing Example Source: https://hypothesis.readthedocs.io/en/latest/_sources/quickstart.rst.txt Illustrates a Hypothesis test that is designed to fail, showing the falsifying example found by pytest. ```python # contents of example.py from hypothesis import given, strategies as st @given(st.integers(0, 200)) def test_integers(n): assert n < 50 ``` -------------------------------- ### Registering a Hypothesis Backend Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/internal/conjecture/providers.html Demonstrates how to register a custom backend by adding a provider class or import path to the AVAILABLE_PROVIDERS dictionary. ```python from hypothesis.internal.conjecture.providers import AVAILABLE_PROVIDERS AVAILABLE_PROVIDERS["hypothesis"] = "hypothesis.internal.conjecture.providers.HypothesisProvider" # or AVAILABLE_PROVIDERS["hypothesis"] = HypothesisProvider ``` -------------------------------- ### Install Hypothesis CLI and Codemods Source: https://hypothesis.readthedocs.io/en/latest/_sources/changelog.rst.txt Use this command to install the necessary dependencies for using Hypothesis codemods and CLI features. ```bash pip install "hypothesis[cli,codemods]" ``` -------------------------------- ### Define Rules and Bundles for State Machines Source: https://hypothesis.readthedocs.io/en/latest/_sources/stateful.rst.txt Create a state machine with bundles for folders and files, and define rules for creating them. Initializes are used to populate bundles. ```python import hypothesis.strategies as st from hypothesis.stateful import Bundle, RuleBasedStateMachine, initialize, rule name_strategy = st.text(min_size=1).filter(lambda x: "/" not in x) class NumberModifier(RuleBasedStateMachine): folders = Bundle("folders") files = Bundle("files") @initialize(target=folders) def init_folders(self): return "/" @rule(target=folders, parent=folders, name=name_strategy) def create_folder(self, parent, name): return f"{parent}/{name}" @rule(target=files, parent=folders, name=name_strategy) def create_file(self, parent, name): return f"{parent}/{name}" ``` -------------------------------- ### Demonstrate assume() filtering Source: https://hypothesis.readthedocs.io/en/latest/explanation/example-count.html Examples rejected by assume() or .filter() do not count towards the max_examples limit and trigger retries. ```python from hypothesis import assume, given, strategies as st @given(st.integers()) def test_function(n): assume(n % 2 == 0) ``` -------------------------------- ### Annotate test examples with xfail Source: https://hypothesis.readthedocs.io/en/latest/_modules/hypothesis/core.html Use @example to define specific test cases, including those expected to fail with a specific exception. ```python @example(x=1, y=0).xfail(raises=ZeroDivisionError) @given(x=st.just(1), y=st.integers()) # Missing `.filter(bool)`! def test_fraction(x, y): # This test will try the explicit example and see it fail as # expected, then go on to generate more examples from the # strategy. If we happen to generate y=0, the test will fail # because only the explicit example is treated as xfailing. x / y ```