diff --git a/hypothesis-python/RELEASE.rst b/hypothesis-python/RELEASE.rst new file mode 100644 index 0000000000..dcaa79e967 --- /dev/null +++ b/hypothesis-python/RELEASE.rst @@ -0,0 +1,3 @@ +RELEASE_TYPE: patch + +This patch enables and fixes many more of :pypi:`ruff`\ 's lint rules. diff --git a/hypothesis-python/examples/test_binary_search.py b/hypothesis-python/examples/test_binary_search.py index c264c95880..8d5054737a 100644 --- a/hypothesis-python/examples/test_binary_search.py +++ b/hypothesis-python/examples/test_binary_search.py @@ -70,10 +70,7 @@ def binary_search(ls, v): def is_sorted(ls): """Is this list sorted?""" - for i in range(len(ls) - 1): - if ls[i] > ls[i + 1]: - return False - return True + return all(x <= y for x, y in zip(ls, ls[1:])) Values = st.integers() diff --git a/hypothesis-python/setup.py b/hypothesis-python/setup.py index 1ff60893be..5f1bb92b98 100644 --- a/hypothesis-python/setup.py +++ b/hypothesis-python/setup.py @@ -37,7 +37,8 @@ def local_file(name): warnings.warn( "This version of setuptools is too old to handle license_files " "metadata key. For more info, see: " - "https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#metadata" + "https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#metadata", + stacklevel=1, ) diff --git a/hypothesis-python/src/_hypothesis_pytestplugin.py b/hypothesis-python/src/_hypothesis_pytestplugin.py index 765eee3aac..8fb9c0d3d6 100644 --- a/hypothesis-python/src/_hypothesis_pytestplugin.py +++ b/hypothesis-python/src/_hypothesis_pytestplugin.py @@ -91,7 +91,7 @@ def __call__(self, msg): Note that the pytest developers no longer support your version either! Disabling the Hypothesis pytest plugin... """ - warnings.warn(PYTEST_TOO_OLD_MESSAGE % (pytest.__version__,)) + warnings.warn(PYTEST_TOO_OLD_MESSAGE % (pytest.__version__,), stacklevel=1) else: diff --git a/hypothesis-python/src/hypothesis/_settings.py b/hypothesis-python/src/hypothesis/_settings.py index e0e879942d..6248c8217e 100644 --- a/hypothesis-python/src/hypothesis/_settings.py +++ b/hypothesis-python/src/hypothesis/_settings.py @@ -231,6 +231,7 @@ def _define_setting( cls, name, description, + *, default, options=None, validator=None, diff --git a/hypothesis-python/src/hypothesis/control.py b/hypothesis-python/src/hypothesis/control.py index c246744db8..c020fd0c6a 100644 --- a/hypothesis-python/src/hypothesis/control.py +++ b/hypothesis-python/src/hypothesis/control.py @@ -24,7 +24,7 @@ def reject() -> NoReturn: - raise UnsatisfiedAssumption() + raise UnsatisfiedAssumption def assume(condition: object) -> bool: @@ -35,7 +35,7 @@ def assume(condition: object) -> bool: true, and let Hypothesis try to avoid similar examples in future. """ if not condition: - raise UnsatisfiedAssumption() + raise UnsatisfiedAssumption return True @@ -62,7 +62,7 @@ def current_build_context() -> "BuildContext": class BuildContext: - def __init__(self, data, is_final=False, close_on_capture=True): + def __init__(self, data, *, is_final=False, close_on_capture=True): assert isinstance(data, ConjectureData) self.data = data self.tasks = [] diff --git a/hypothesis-python/src/hypothesis/core.py b/hypothesis-python/src/hypothesis/core.py index 5f8c0db73f..e7302fbd3e 100644 --- a/hypothesis-python/src/hypothesis/core.py +++ b/hypothesis-python/src/hypothesis/core.py @@ -694,6 +694,7 @@ def __init__(self, test_runner, stuff, test, settings, random, wrapped_test): def execute_once( self, data, + *, print_example=False, is_final=False, expected_failure=None, @@ -1493,7 +1494,7 @@ def find( def test(v): if condition(v): last[:] = [v] - raise Found() + raise Found if random is not None: test = seed(random.getrandbits(64))(test) diff --git a/hypothesis-python/src/hypothesis/database.py b/hypothesis-python/src/hypothesis/database.py index 971356c597..c53bf48518 100644 --- a/hypothesis-python/src/hypothesis/database.py +++ b/hypothesis-python/src/hypothesis/database.py @@ -61,11 +61,11 @@ def _db_for_path(path=None): path = storage_directory("examples") if not _usable_dir(path): # pragma: no cover warnings.warn( - HypothesisWarning( - "The database setting is not configured, and the default " - "location is unusable - falling back to an in-memory " - f"database for this session. {path=}" - ) + "The database setting is not configured, and the default " + "location is unusable - falling back to an in-memory " + f"database for this session. {path=}", + HypothesisWarning, + stacklevel=3, ) return InMemoryExampleDatabase() if path in (None, ":memory:"): @@ -488,11 +488,11 @@ def _prepare_for_io(self) -> None: self._access_cache[keypath].add(PurePath(filename)) except BadZipFile: warnings.warn( - HypothesisWarning( - "The downloaded artifact from GitHub is invalid. " - "This could be because the artifact was corrupted, " - "or because the artifact was not created by Hypothesis. " - ) + "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 @@ -534,18 +534,17 @@ def _initialize_db(self) -> None: self._artifact = new_artifact elif found_artifact is not None: warnings.warn( - HypothesisWarning( - "Using an expired artifact as a fallback for the database: " - f"{found_artifact}" - ) + "Using an expired artifact as a fallback for the database: " + f"{found_artifact}", + HypothesisWarning, + stacklevel=2, ) self._artifact = found_artifact else: warnings.warn( - HypothesisWarning( - "Couldn't acquire a new or existing artifact. " - "Disabling database." - ) + "Couldn't acquire a new or existing artifact. Disabling database.", + HypothesisWarning, + stacklevel=2, ) self._disabled = True return @@ -587,7 +586,7 @@ def _get_bytes(self, url: str) -> Optional[bytes]: # pragma: no cover ) if warning_message is not None: - warnings.warn(HypothesisWarning(warning_message)) + warnings.warn(warning_message, HypothesisWarning, stacklevel=4) return None return response_bytes @@ -624,7 +623,9 @@ def _fetch_artifact(self) -> Optional[Path]: # pragma: no cover f.write(artifact_bytes) except OSError: warnings.warn( - HypothesisWarning("Could not save the latest artifact from GitHub. ") + "Could not save the latest artifact from GitHub. ", + HypothesisWarning, + stacklevel=3, ) return None diff --git a/hypothesis-python/src/hypothesis/executors.py b/hypothesis-python/src/hypothesis/executors.py index 67895467e4..b7ea77dfb1 100644 --- a/hypothesis-python/src/hypothesis/executors.py +++ b/hypothesis-python/src/hypothesis/executors.py @@ -10,7 +10,7 @@ def default_executor(function): # pragma: nocover - raise NotImplementedError() # We don't actually use this any more + raise NotImplementedError # We don't actually use this any more def setup_teardown_executor(setup, teardown): diff --git a/hypothesis-python/src/hypothesis/extra/_array_helpers.py b/hypothesis-python/src/hypothesis/extra/_array_helpers.py index 93b88408ab..67021390f0 100644 --- a/hypothesis-python/src/hypothesis/extra/_array_helpers.py +++ b/hypothesis-python/src/hypothesis/extra/_array_helpers.py @@ -275,7 +275,7 @@ def broadcastable_shapes( # We are unsure if gufuncs allow frozen dimensions to be optional, but it's # easy enough to support here - and so we will unless we learn otherwise. _DIMENSION = r"\w+\??" # Note that \w permits digits too! -_SHAPE = rf"\((?:{_DIMENSION}(?:,{_DIMENSION})" + r"{0,31})?\)" +_SHAPE = rf"\((?:{_DIMENSION}(?:,{_DIMENSION}){{0,31}})?\)" _ARGUMENT_LIST = f"{_SHAPE}(?:,{_SHAPE})*" _SIGNATURE = rf"^{_ARGUMENT_LIST}->{_SHAPE}$" _SIGNATURE_MULTIPLE_OUTPUT = rf"^{_ARGUMENT_LIST}->{_ARGUMENT_LIST}$" @@ -286,7 +286,7 @@ class _GUfuncSig(NamedTuple): result_shape: Shape -def _hypothesis_parse_gufunc_signature(signature, all_checks=True): +def _hypothesis_parse_gufunc_signature(signature, *, all_checks=True): # Disable all_checks to better match the Numpy version, for testing if not re.match(_SIGNATURE, signature): if re.match(_SIGNATURE_MULTIPLE_OUTPUT, signature): diff --git a/hypothesis-python/src/hypothesis/extra/array_api.py b/hypothesis-python/src/hypothesis/extra/array_api.py index 5078adafc6..7b39b09a27 100644 --- a/hypothesis-python/src/hypothesis/extra/array_api.py +++ b/hypothesis-python/src/hypothesis/extra/array_api.py @@ -114,6 +114,7 @@ def warn_on_missing_dtypes(xp: Any, stubs: List[str]) -> None: f"Array module {xp.__name__} does not have the following " f"dtypes in its namespace: {f_stubs}", HypothesisWarning, + stacklevel=3, ) @@ -450,9 +451,7 @@ def do_draw(self, data): else: self.check_set_value(val, val_0d, self.elements_strategy) - result = self.xp.reshape(result, self.shape) - - return result + return self.xp.reshape(result, self.shape) def _arrays( @@ -911,6 +910,7 @@ def make_strategies_namespace( warn( f"Could not determine whether module {xp.__name__} is an Array API library", HypothesisWarning, + stacklevel=2, ) try: @@ -1013,7 +1013,7 @@ def floating_dtypes( class StrategiesNamespace(SimpleNamespace): def __init__(self, **kwargs): for attr in ["name", "api_version"]: - if attr not in kwargs.keys(): + if attr not in kwargs: raise ValueError(f"'{attr}' kwarg required") super().__init__(**kwargs) diff --git a/hypothesis-python/src/hypothesis/extra/ghostwriter.py b/hypothesis-python/src/hypothesis/extra/ghostwriter.py index 08e68c0638..515faec7cc 100644 --- a/hypothesis-python/src/hypothesis/extra/ghostwriter.py +++ b/hypothesis-python/src/hypothesis/extra/ghostwriter.py @@ -435,10 +435,9 @@ def _guess_strategy_by_argname(name: str) -> st.SearchStrategy: return st.nothing() if ( - name.endswith("_name") + name.endswith(("_name", "label")) or (name.endswith("name") and "_" not in name) or ("string" in name and "as" not in name) - or name.endswith("label") or name in STRING_NAMES ): return st.text() @@ -747,7 +746,7 @@ def _get_module(obj): raise RuntimeError(f"Could not find module for ufunc {obj.__name__} ({obj!r}") -def _get_qualname(obj, include_module=False): +def _get_qualname(obj, *, include_module=False): # Replacing angle-brackets for objects defined in `..` qname = getattr(obj, "__qualname__", obj.__name__) qname = qname.replace("<", "_").replace(">", "_").replace(" ", "") diff --git a/hypothesis-python/src/hypothesis/internal/cache.py b/hypothesis-python/src/hypothesis/internal/cache.py index 891b2111f5..86241d3737 100644 --- a/hypothesis-python/src/hypothesis/internal/cache.py +++ b/hypothesis-python/src/hypothesis/internal/cache.py @@ -162,7 +162,7 @@ def new_entry(self, key, value): Returns the score to associate with the key. """ - raise NotImplementedError() + raise NotImplementedError def on_access(self, key, value, score): """Called every time a key that is already in the map is read or diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/choicetree.py b/hypothesis-python/src/hypothesis/internal/conjecture/choicetree.py index 38bcc3a571..c5de31ab3a 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/choicetree.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/choicetree.py @@ -89,7 +89,7 @@ def choose( node.children[i] = DeadNode node.live_child_count -= 1 assert node.live_child_count == 0 - raise DeadBranch() + raise DeadBranch def finish(self) -> Sequence[int]: """Record the decisions made in the underlying tree and return diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/data.py b/hypothesis-python/src/hypothesis/internal/conjecture/data.py index 0b43d9c1b1..ba346ab90c 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/data.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/data.py @@ -240,7 +240,7 @@ def run(self) -> Any: self.bytes_read = blocks.endpoints[self.block_count] self.block(self.block_count) self.block_count += 1 - self.__pop(False) + self.__pop(discarded=False) elif record >= START_EXAMPLE_RECORD: self.__push(record - START_EXAMPLE_RECORD) else: @@ -248,19 +248,19 @@ def run(self) -> Any: STOP_EXAMPLE_DISCARD_RECORD, STOP_EXAMPLE_NO_DISCARD_RECORD, ) - self.__pop(record == STOP_EXAMPLE_DISCARD_RECORD) + self.__pop(discarded=record == STOP_EXAMPLE_DISCARD_RECORD) return self.finish() def __push(self, label_index: int) -> None: i = self.example_count assert i < len(self.examples) - self.start_example(i, label_index) + self.start_example(i, label_index=label_index) self.example_count += 1 self.example_stack.append(i) - def __pop(self, discarded: bool) -> None: + def __pop(self, *, discarded: bool) -> None: i = self.example_stack.pop() - self.stop_example(i, discarded) + self.stop_example(i, discarded=discarded) def begin(self) -> None: """Called at the beginning of the run to initialise any @@ -276,7 +276,7 @@ def block(self, i: int) -> None: """Called with each ``draw_bits`` call, with ``i`` the index of the corresponding block in ``self.examples.blocks``""" - def stop_example(self, i: int, discarded: bool) -> None: + def stop_example(self, i: int, *, discarded: bool) -> None: """Called at the end of each example, with ``i`` the index of the example and ``discarded`` being ``True`` if ``stop_example`` was called with ``discard=True``.""" @@ -342,7 +342,7 @@ def start_example(self, label: int) -> None: self.labels.append(label) self.trail.append(START_EXAMPLE_RECORD + i) - def stop_example(self, discard: bool) -> None: + def stop_example(self, *, discard: bool) -> None: if discard: self.trail.append(STOP_EXAMPLE_DISCARD_RECORD) else: @@ -379,10 +379,10 @@ def begin(self): self.starts = IntList.of_length(len(self.examples)) self.ends = IntList.of_length(len(self.examples)) - def start_example(self, i: int, label_index: int) -> None: + def start_example(self, i: int, *, label_index: int) -> None: self.starts[i] = self.bytes_read - def stop_example(self, i: int, discarded: bool) -> None: + def stop_example(self, i: int, *, discarded: bool) -> None: self.ends[i] = self.bytes_read def finish(self) -> Tuple[IntList, IntList]: @@ -407,7 +407,7 @@ def begin(self) -> None: def finish(self) -> FrozenSet[int]: return frozenset(self.result) - def stop_example(self, i: int, discarded: bool) -> None: + def stop_example(self, i: int, *, discarded: bool) -> None: if discarded: self.result.add(i) @@ -422,7 +422,7 @@ def block(self, i: int) -> None: if not self.examples.blocks.trivial(i): self.nontrivial[self.example_stack[-1]] = 1 - def stop_example(self, i: int, discarded: bool) -> None: + def stop_example(self, i: int, *, discarded: bool) -> None: if self.nontrivial[i]: if self.example_stack: self.nontrivial[self.example_stack[-1]] = 1 @@ -435,7 +435,7 @@ def finish(self) -> FrozenSet[int]: trivial: FrozenSet[int] = calculated_example_property(_trivial) class _parentage(ExampleProperty): - def stop_example(self, i: int, discarded: bool) -> None: + def stop_example(self, i: int, *, discarded: bool) -> None: if i > 0: self.result[i] = self.example_stack[-1] @@ -746,7 +746,7 @@ def conclude_test( Note that this is called after ``freeze`` has completed. """ - def draw_bits(self, n_bits: int, forced: bool, value: int) -> None: + def draw_bits(self, n_bits: int, *, forced: bool, value: int) -> None: """Called when ``draw_bits`` is called on on the observed ``ConjectureData``. * ``n_bits`` is the number of bits drawn. @@ -973,14 +973,14 @@ def start_example(self, label: int) -> None: self.__example_record.start_example(label) self.labels_for_structure_stack.append({label}) - def stop_example(self, discard: bool = False) -> None: + def stop_example(self, *, discard: bool = False) -> None: if self.frozen: return if discard: self.has_discards = True self.depth -= 1 assert self.depth >= -1 - self.__example_record.stop_example(discard) + self.__example_record.stop_example(discard=discard) labels_for_structure = self.labels_for_structure_stack.pop() @@ -1082,7 +1082,7 @@ def draw_bits(self, n: int, *, forced: Optional[int] = None) -> int: buf = bytes(buf) result = int_from_bytes(buf) - self.observer.draw_bits(n, forced is not None, result) + self.observer.draw_bits(n, forced=forced is not None, value=result) self.__example_record.draw_bits(n, forced) initial = self.index diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/datatree.py b/hypothesis-python/src/hypothesis/internal/conjecture/datatree.py index e61f33732a..b39666eec1 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/datatree.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/datatree.py @@ -283,18 +283,18 @@ def simulate_test_function(self, data): n_bits, forced=node.values[i] if i in node.forced else None ) if v != previous: - raise PreviouslyUnseenBehaviour() + raise PreviouslyUnseenBehaviour if isinstance(node.transition, Conclusion): t = node.transition data.conclude_test(t.status, t.interesting_origin) elif node.transition is None: - raise PreviouslyUnseenBehaviour() + raise PreviouslyUnseenBehaviour elif isinstance(node.transition, Branch): v = data.draw_bits(node.transition.bit_length) try: node = node.transition.children[v] except KeyError as err: - raise PreviouslyUnseenBehaviour() from err + raise PreviouslyUnseenBehaviour from err else: assert isinstance(node.transition, Killed) data.observer.kill_branch() diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/dfa/__init__.py b/hypothesis-python/src/hypothesis/internal/conjecture/dfa/__init__.py index 40b87f69b6..8beb4ad588 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/dfa/__init__.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/dfa/__init__.py @@ -53,16 +53,16 @@ def __cache(self, name): @property def start(self): """Returns the starting state.""" - raise NotImplementedError() + raise NotImplementedError def is_accepting(self, i): """Returns if state ``i`` is an accepting one.""" - raise NotImplementedError() + raise NotImplementedError def transition(self, i, c): """Returns the state that i transitions to on reading character c from a string.""" - raise NotImplementedError() + raise NotImplementedError @property def alphabet(self): diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/engine.py b/hypothesis-python/src/hypothesis/internal/conjecture/engine.py index 57a6e0c725..73937d1015 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/engine.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/engine.py @@ -549,7 +549,7 @@ def exit_with(self, reason): self.statistics["targets"] = dict(self.best_observed_targets) self.debug(f"exit_with({reason.name})") self.exit_reason = reason - raise RunIsComplete() + raise RunIsComplete def should_generate_more(self): # End the generation phase where we would have ended it if no bugs had @@ -1014,7 +1014,7 @@ def check_result(result): class DiscardObserver(DataObserver): def kill_branch(self): - raise ContainsDiscard() + raise ContainsDiscard observer = DiscardObserver() else: diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/junkdrawer.py b/hypothesis-python/src/hypothesis/internal/conjecture/junkdrawer.py index 006cb325a3..ec12b028b8 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/junkdrawer.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/junkdrawer.py @@ -306,6 +306,7 @@ def __exit__(self, *args, **kwargs): "The recursion limit will not be reset, since it was changed " "from another thread or during execution of a test.", HypothesisWarning, + stacklevel=2, ) diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/shrinker.py b/hypothesis-python/src/hypothesis/internal/conjecture/shrinker.py index 4503804afd..735e28dcbc 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/shrinker.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/shrinker.py @@ -412,7 +412,7 @@ def cached_test_function(self, buffer): result = self.engine.cached_test_function(buffer) self.incorporate_test_data(result) if self.calls - self.calls_at_last_shrink >= self.max_stall: - raise StopShrinking() + raise StopShrinking return result def debug(self, msg): diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py b/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py index ece89e94da..23f4f96224 100644 --- a/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py +++ b/hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py @@ -146,7 +146,7 @@ def check_invariants(self, value): Does nothing by default. """ - raise NotImplementedError() + raise NotImplementedError def short_circuit(self): """Possibly attempt to do some shrinking. @@ -154,14 +154,14 @@ def short_circuit(self): If this returns True, the ``run`` method will terminate early without doing any more work. """ - raise NotImplementedError() + raise NotImplementedError def left_is_better(self, left, right): """Returns True if the left is strictly simpler than the right according to the standards of this shrinker.""" - raise NotImplementedError() + raise NotImplementedError def run_step(self): """Run a single step of the main shrink loop, attempting to improve the current value.""" - raise NotImplementedError() + raise NotImplementedError diff --git a/hypothesis-python/src/hypothesis/internal/entropy.py b/hypothesis-python/src/hypothesis/internal/entropy.py index 00f29810fa..8715635462 100644 --- a/hypothesis-python/src/hypothesis/internal/entropy.py +++ b/hypothesis-python/src/hypothesis/internal/entropy.py @@ -124,18 +124,17 @@ def my_WORKING_hook(): f"`register_random` was passed `r={r}` which will be " "garbage collected immediately after `register_random` creates a " "weakref to it. This will prevent Hypothesis from managing this " - "source of RNG. See the docs for `register_random` for more " + "PRNG. See the docs for `register_random` for more " "details." ) else: warnings.warn( - HypothesisWarning( - "It looks like `register_random` was passed an object " - "that could be garbage collected immediately after " - "`register_random` creates a weakref to it. This will " - "prevent Hypothesis from managing this source of RNG. " - "See the docs for `register_random` for more details." - ) + "It looks like `register_random` was passed an object that could " + "be garbage collected immediately after `register_random` creates " + "a weakref to it. This will prevent Hypothesis from managing this " + "PRNG. See the docs for `register_random` for more details.", + HypothesisWarning, + stacklevel=2, ) RANDOMS_TO_MANAGE[next(_RKEY)] = r @@ -153,7 +152,8 @@ def get_seeder_and_restorer( to force determinism on simulation or scheduling frameworks which avoid using the global random state. See e.g. #1709. """ - assert isinstance(seed, int) and 0 <= seed < 2**32 + assert isinstance(seed, int) + assert 0 <= seed < 2**32 states: dict = {} if "numpy" in sys.modules: diff --git a/hypothesis-python/src/hypothesis/internal/floats.py b/hypothesis-python/src/hypothesis/internal/floats.py index d2cb2c94f8..e0cd95d374 100644 --- a/hypothesis-python/src/hypothesis/internal/floats.py +++ b/hypothesis-python/src/hypothesis/internal/floats.py @@ -119,6 +119,7 @@ def next_up_normal(value, width, allow_subnormal): def make_float_clamper( min_float: float = 0.0, max_float: float = math.inf, + *, allow_zero: bool = False, # Allows +0.0 (even if minfloat > 0) ) -> Optional[Callable[[float], float]]: """ diff --git a/hypothesis-python/src/hypothesis/internal/reflection.py b/hypothesis-python/src/hypothesis/internal/reflection.py index 8afda719c5..c3584db9f8 100644 --- a/hypothesis-python/src/hypothesis/internal/reflection.py +++ b/hypothesis-python/src/hypothesis/internal/reflection.py @@ -420,8 +420,7 @@ def extract_lambda_source(f): source = WHITESPACE.sub(" ", source) source = SPACE_FOLLOWS_OPEN_BRACKET.sub("(", source) source = SPACE_PRECEDES_CLOSE_BRACKET.sub(")", source) - source = source.strip() - return source + return source.strip() def get_pretty_function_description(f): diff --git a/hypothesis-python/src/hypothesis/stateful.py b/hypothesis-python/src/hypothesis/stateful.py index cc6f29af98..871d3545bb 100644 --- a/hypothesis-python/src/hypothesis/stateful.py +++ b/hypothesis-python/src/hypothesis/stateful.py @@ -447,7 +447,8 @@ def do_draw(self, data): class Bundle(SearchStrategy[Ex]): - def __init__(self, name: str, consume: bool = False) -> None: + # TODO: deprecate passing `consume` as a positional argument + def __init__(self, name: str, consume: bool = False) -> None: # noqa # bool posarg self.name = name self.__reference_strategy = BundleReferenceStrategy(name, consume) diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/core.py b/hypothesis-python/src/hypothesis/strategies/_internal/core.py index 3a9a6d0ead..8eda89efa5 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/core.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/core.py @@ -1249,6 +1249,7 @@ def from_type_guarded(thing): "to resolve to a strategy which can generate more than one value, " "or silence this warning.", SmallSearchSpaceWarning, + stacklevel=2, ) return builds(thing, **kwargs) # And if it's an abstract type, we'll resolve to a union of subclasses instead. diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/numbers.py b/hypothesis-python/src/hypothesis/strategies/_internal/numbers.py index b67c6ba1b6..5ea77356f9 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/numbers.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/numbers.py @@ -168,7 +168,8 @@ def integers( SMALLEST_SUBNORMAL = next_up(0.0) SIGNALING_NAN = int_to_float(0x7FF8_0000_0000_0001) # nonzero mantissa -assert math.isnan(SIGNALING_NAN) and math.copysign(1, SIGNALING_NAN) == 1 +assert math.isnan(SIGNALING_NAN) +assert math.copysign(1, SIGNALING_NAN) == 1 NASTY_FLOATS = sorted( [ @@ -263,11 +264,15 @@ def __init__( if _sign_aware_lte(0.0, max_value): pos_min = max(min_value, smallest_nonzero_magnitude) allow_zero = _sign_aware_lte(min_value, 0.0) - self.pos_clamper = make_float_clamper(pos_min, max_value, allow_zero) + self.pos_clamper = make_float_clamper( + pos_min, max_value, allow_zero=allow_zero + ) if _sign_aware_lte(min_value, -0.0): neg_max = min(max_value, -smallest_nonzero_magnitude) allow_zero = _sign_aware_lte(-0.0, max_value) - self.neg_clamper = make_float_clamper(-neg_max, -min_value, allow_zero) + self.neg_clamper = make_float_clamper( + -neg_max, -min_value, allow_zero=allow_zero + ) self.forced_sign_bit: Optional[int] = None if (self.pos_clamper is None) != (self.neg_clamper is None): @@ -506,7 +511,8 @@ def floats( min_value = next_up_normal(min_value, width, assumed_allow_subnormal) if min_value == min_arg: assert min_value == min_arg == 0 - assert is_negative(min_arg) and not is_negative(min_value) + assert is_negative(min_arg) + assert not is_negative(min_value) min_value = next_up_normal(min_value, width, assumed_allow_subnormal) assert min_value > min_arg # type: ignore if max_value is not None and ( @@ -515,7 +521,8 @@ def floats( max_value = next_down_normal(max_value, width, assumed_allow_subnormal) if max_value == max_arg: assert max_value == max_arg == 0 - assert is_negative(max_value) and not is_negative(max_arg) + assert is_negative(max_value) + assert not is_negative(max_arg) max_value = next_down_normal(max_value, width, assumed_allow_subnormal) assert max_value < max_arg # type: ignore diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/random.py b/hypothesis-python/src/hypothesis/strategies/_internal/random.py index 94b5e0d793..40eb936606 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/random.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/random.py @@ -40,16 +40,16 @@ def __deepcopy__(self, table): return self.__copy__() def __repr__(self): - raise NotImplementedError() + raise NotImplementedError def seed(self, seed): - raise NotImplementedError() + raise NotImplementedError def getstate(self): - raise NotImplementedError() + raise NotImplementedError def setstate(self, state): - raise NotImplementedError() + raise NotImplementedError def _hypothesis_log_random(self, method, kwargs, result): if not (self.__note_method_calls and should_note()): @@ -62,7 +62,7 @@ def _hypothesis_log_random(self, method, kwargs, result): report(f"{self!r}.{method}({argstr}) -> {result!r}") def _hypothesis_do_random(self, method, kwargs): - raise NotImplementedError() + raise NotImplementedError RANDOM_METHODS = [ @@ -97,15 +97,15 @@ def _hypothesis_do_random(self, method, kwargs): # Fake shims to get a good signature def getrandbits(self, n: int) -> int: # type: ignore - raise NotImplementedError() + raise NotImplementedError def random(self) -> float: # type: ignore - raise NotImplementedError() + raise NotImplementedError def _randbelow(self, n: int) -> int: # type: ignore - raise NotImplementedError() + raise NotImplementedError STUBS = {f.__name__: f for f in [getrandbits, random, _randbelow]} @@ -212,7 +212,7 @@ def __convert_result(self, method, kwargs, result): original = list(seq) for i, i2 in enumerate(result): seq[i] = original[i2] - return + return None return result def _hypothesis_do_random(self, method, kwargs): diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/recursive.py b/hypothesis-python/src/hypothesis/strategies/_internal/recursive.py index 58b218ab07..7709b45460 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/recursive.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/recursive.py @@ -57,7 +57,7 @@ def do_validate(self): def do_draw(self, data): assert self.currently_capped if self.marker <= 0: - raise LimitReached() + raise LimitReached self.marker -= 1 return data.draw(self.base_strategy) diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py b/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py index 3835091a40..de4b7985c9 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/strategies.py @@ -837,7 +837,7 @@ def do_draw(self, data: ConjectureData) -> Any: return result except UnsatisfiedAssumption: data.stop_example(discard=True) - raise UnsatisfiedAssumption() + raise UnsatisfiedAssumption @property def branches(self) -> List[SearchStrategy[Ex]]: diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/strings.py b/hypothesis-python/src/hypothesis/strategies/_internal/strings.py index e1dc1f4da5..f1eb143ed6 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/strings.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/strings.py @@ -158,6 +158,7 @@ def filter(self, condition): f"You applied str.{condition.__name__} as a filter, but this allows " f"all nonempty strings! Did you mean str.is{condition.__name__}?", HypothesisWarning, + stacklevel=2, ) # We use ListStrategy filter logic for the conditions that *only* imply # the string is nonempty. Here, we increment the min_size but still apply diff --git a/hypothesis-python/src/hypothesis/strategies/_internal/types.py b/hypothesis-python/src/hypothesis/strategies/_internal/types.py index 913da037c3..b86f42d8f5 100644 --- a/hypothesis-python/src/hypothesis/strategies/_internal/types.py +++ b/hypothesis-python/src/hypothesis/strategies/_internal/types.py @@ -178,7 +178,7 @@ def type_sorting_key(t): """Minimise to None, then non-container types, then container types.""" - if t is None or t is type(None): # noqa: E721 + if t is None or t is type(None): return (-1, repr(t)) t = get_origin(t) or t try: diff --git a/hypothesis-python/src/hypothesis/vendor/pretty.py b/hypothesis-python/src/hypothesis/vendor/pretty.py index b9158573eb..5965938d93 100644 --- a/hypothesis-python/src/hypothesis/vendor/pretty.py +++ b/hypothesis-python/src/hypothesis/vendor/pretty.py @@ -420,7 +420,7 @@ def repr_call( class Printable: def output(self, stream, output_width): # pragma: no cover - raise NotImplementedError() + raise NotImplementedError class Text(Printable): diff --git a/hypothesis-python/tests/array_api/conftest.py b/hypothesis-python/tests/array_api/conftest.py index ada10e8b94..630df48363 100644 --- a/hypothesis-python/tests/array_api/conftest.py +++ b/hypothesis-python/tests/array_api/conftest.py @@ -63,15 +63,15 @@ class InvalidArgumentWarning(UserWarning): "HYPOTHESIS_TEST_ARRAY_API='all', but no entry points where found" ) xp_and_xps_pairs = [(mock_xp, mock_xps)] - for name, ep in name_to_entry_point.items(): + for ep in name_to_entry_point.values(): xp = ep.load() try: xps = make_strategies_namespace(xp, api_version=api_version) except InvalidArgument as e: - warnings.warn(str(e), InvalidArgumentWarning) + warnings.warn(str(e), InvalidArgumentWarning, stacklevel=1) else: xp_and_xps_pairs.append((xp, xps)) - elif test_xp_option in name_to_entry_point.keys(): + elif test_xp_option in name_to_entry_point: ep = name_to_entry_point[test_xp_option] xp = ep.load() xps = make_strategies_namespace(xp, api_version=api_version) diff --git a/hypothesis-python/tests/array_api/test_arrays.py b/hypothesis-python/tests/array_api/test_arrays.py index ad78ab6be8..9b96f01959 100644 --- a/hypothesis-python/tests/array_api/test_arrays.py +++ b/hypothesis-python/tests/array_api/test_arrays.py @@ -276,14 +276,14 @@ def test_may_fill_unique_arrays_with_nan(xp, xps): def test_may_not_fill_unique_array_with_non_nan(xp, xps): """Unique strategy with just fill elements of 0.0 raises helpful error.""" + strat = xps.arrays( + dtype=xp.float32, + shape=10, + elements={"allow_nan": False}, + unique=True, + fill=st.just(0.0), + ) with pytest.raises(InvalidArgument): - strat = xps.arrays( - dtype=xp.float32, - shape=10, - elements={"allow_nan": False}, - unique=True, - fill=st.just(0.0), - ) strat.example() diff --git a/hypothesis-python/tests/array_api/test_indices.py b/hypothesis-python/tests/array_api/test_indices.py index d89b6b3936..e08c251b5b 100644 --- a/hypothesis-python/tests/array_api/test_indices.py +++ b/hypothesis-python/tests/array_api/test_indices.py @@ -127,7 +127,7 @@ def test_generate_valid_indices(xp, xps, allow_newaxis, allow_ellipsis, data): assert None not in _indexer # i.e. xp.newaxis # Check index is composed of valid objects for i in _indexer: - assert isinstance(i, int) or isinstance(i, slice) or i is None or i == Ellipsis + assert isinstance(i, (int, slice)) or i is None or i == Ellipsis # Check indexer does not flat index nonexpanding_indexer = [i for i in _indexer if i is not None] if Ellipsis in _indexer: diff --git a/hypothesis-python/tests/array_api/test_pretty.py b/hypothesis-python/tests/array_api/test_pretty.py index 3c730ed250..2c69c8d96e 100644 --- a/hypothesis-python/tests/array_api/test_pretty.py +++ b/hypothesis-python/tests/array_api/test_pretty.py @@ -50,7 +50,7 @@ def test_namespaced_methods_meta(xp, xps, name): # function signatures. make_strategies_namespace() exists to wrap these # top-level methods by binding the passed xp argument, and so the namespace # it returns should not expose xp in any of its function signatures. - assert "xp" not in signature(func).parameters.keys() + assert "xp" not in signature(func).parameters @pytest.mark.parametrize( diff --git a/hypothesis-python/tests/common/debug.py b/hypothesis-python/tests/common/debug.py index 495bfe37d6..11dd9c2787 100644 --- a/hypothesis-python/tests/common/debug.py +++ b/hypothesis-python/tests/common/debug.py @@ -35,7 +35,7 @@ def wrapped_condition(x): if runtime: runtime[0] += TIME_INCREMENT if runtime[0] >= timeout_after: - raise Timeout() + raise Timeout result = condition(x) if result and not runtime: runtime.append(0.0) diff --git a/hypothesis-python/tests/conftest.py b/hypothesis-python/tests/conftest.py index f64c7e7387..4364da5ad7 100644 --- a/hypothesis-python/tests/conftest.py +++ b/hypothesis-python/tests/conftest.py @@ -50,12 +50,12 @@ def pytest_addoption(parser): @pytest.fixture(scope="function", autouse=True) -def gc_before_each_test(): +def _gc_before_each_test(): gc.collect() @pytest.fixture(scope="function", autouse=True) -def consistently_increment_time(monkeypatch): +def _consistently_increment_time(monkeypatch): """Rather than rely on real system time we monkey patch time.time so that it passes at a consistent rate between calls. diff --git a/hypothesis-python/tests/conjecture/test_engine.py b/hypothesis-python/tests/conjecture/test_engine.py index 45b5001650..9cc9ffd682 100644 --- a/hypothesis-python/tests/conjecture/test_engine.py +++ b/hypothesis-python/tests/conjecture/test_engine.py @@ -369,7 +369,7 @@ def x(data): def test_does_not_save_on_interrupt(): def interrupts(data): - raise KeyboardInterrupt() + raise KeyboardInterrupt db = InMemoryExampleDatabase() @@ -1014,7 +1014,7 @@ def test(data): while True: data.start_example(1) b = data.draw_bits(8) - data.stop_example(b != 0) + data.stop_example(discard=b != 0) if len(data.buffer) == 1: s = bytes(data.buffer) assert s not in starts diff --git a/hypothesis-python/tests/conjecture/test_inquisitor.py b/hypothesis-python/tests/conjecture/test_inquisitor.py index 177251068c..3ffcda6b58 100644 --- a/hypothesis-python/tests/conjecture/test_inquisitor.py +++ b/hypothesis-python/tests/conjecture/test_inquisitor.py @@ -55,7 +55,8 @@ def test_inquisitor_comments_basic_fail_if_either(a, b, c, d, e): ) @given(st.text(), st.text(), st.text()) def test_inquisitor_comments_basic_fail_if_not_all(a, b, c): - assert a and b and c + condition = a and b and c + assert condition @fails_with_output( diff --git a/hypothesis-python/tests/conjecture/test_junkdrawer.py b/hypothesis-python/tests/conjecture/test_junkdrawer.py index f0b0f8f5eb..13bfc2d031 100644 --- a/hypothesis-python/tests/conjecture/test_junkdrawer.py +++ b/hypothesis-python/tests/conjecture/test_junkdrawer.py @@ -132,7 +132,7 @@ def test_int_list_equality(): assert ls != x assert x != ls - assert not (x == ls) + assert not (x == ls) # noqa assert x == x assert x == y diff --git a/hypothesis-python/tests/conjecture/test_optimiser.py b/hypothesis-python/tests/conjecture/test_optimiser.py index 9a0e457c4d..7dbd675490 100644 --- a/hypothesis-python/tests/conjecture/test_optimiser.py +++ b/hypothesis-python/tests/conjecture/test_optimiser.py @@ -67,8 +67,8 @@ def test_optimises_when_last_element_is_empty(): def test(data): data.target_observations["n"] = data.draw_bits(8) - data.start_example(1) - data.stop_example(1) + data.start_example(label=1) + data.stop_example() runner = ConjectureRunner(test, settings=TEST_SETTINGS) runner.cached_test_function([250]) diff --git a/hypothesis-python/tests/conjecture/test_shrinker.py b/hypothesis-python/tests/conjecture/test_shrinker.py index 0ae9885bcb..6361fb5492 100644 --- a/hypothesis-python/tests/conjecture/test_shrinker.py +++ b/hypothesis-python/tests/conjecture/test_shrinker.py @@ -112,14 +112,13 @@ def shrinker(data): def test_can_pass_to_an_indirect_descendant(monkeypatch): def tree(data): - data.start_example(1) + data.start_example(label=1) n = data.draw_bits(1) - label = data.draw_bits(8) + data.draw_bits(8) if n: tree(data) tree(data) - data.stop_example(1) - return label + data.stop_example(discard=True) initial = bytes([1, 10, 0, 0, 1, 0, 0, 10, 0, 0]) target = bytes([0, 10]) @@ -186,10 +185,10 @@ def test_can_reorder_examples(): def shrinker(data): total = 0 for _ in range(5): - data.start_example(0) + data.start_example(label=0) if data.draw_bits(8): total += data.draw_bits(9) - data.stop_example(0) + data.stop_example() if total == 2: data.mark_interesting() @@ -286,7 +285,7 @@ def test_finding_a_minimal_balanced_binary_tree(): def tree(data): # Returns height of a binary tree and whether it is height balanced. - data.start_example("tree") + data.start_example(label=0) n = data.draw_bits(1) if n == 0: result = (1, True) @@ -294,7 +293,7 @@ def tree(data): h1, b1 = tree(data) h2, b2 = tree(data) result = (1 + max(h1, h2), b1 and b2 and abs(h1 - h2) <= 1) - data.stop_example("tree") + data.stop_example() return result # Starting from an unbalanced tree of depth six diff --git a/hypothesis-python/tests/conjecture/test_test_data.py b/hypothesis-python/tests/conjecture/test_test_data.py index 0efd0f129d..98f6c9bc3b 100644 --- a/hypothesis-python/tests/conjecture/test_test_data.py +++ b/hypothesis-python/tests/conjecture/test_test_data.py @@ -102,7 +102,7 @@ def test_can_mark_invalid_with_why(): class BoomStrategy(SearchStrategy): def do_draw(self, data): data.draw_bytes(1) - raise ValueError() + raise ValueError def test_closes_interval_on_error_in_strategy(): @@ -129,10 +129,10 @@ def test_does_not_double_freeze_in_interval_close(): def test_triviality(): d = ConjectureData.for_buffer([1, 0, 1]) - d.start_example(1) + d.start_example(label=1) d.draw_bits(1) d.draw_bits(1) - d.stop_example(1) + d.stop_example() d.write(bytes([2])) d.freeze() @@ -237,8 +237,8 @@ class LoggingObserver(DataObserver): def __init__(self): self.log = [] - def draw_bits(self, *args): - self.log.append(("draw",) + args) + def draw_bits(self, n_bits: int, *, forced: bool, value: int) -> None: + self.log.append(("draw", n_bits, forced, value)) def conclude_test(self, *args): assert x.frozen @@ -461,13 +461,13 @@ def test_example_equality(): examples = list(d.examples) for ex1, ex2 in itertools.combinations(examples, 2): assert ex1 != ex2 - assert not (ex1 == ex2) + assert not (ex1 == ex2) # noqa for ex in examples: assert ex == ex - not (ex != ex) + assert not (ex != ex) # noqa - assert not (ex == "hello") + assert not (ex == "hello") # noqa assert ex != "hello" diff --git a/hypothesis-python/tests/cover/test_annotations.py b/hypothesis-python/tests/cover/test_annotations.py index f0e9068712..57520a154a 100644 --- a/hypothesis-python/tests/cover/test_annotations.py +++ b/hypothesis-python/tests/cover/test_annotations.py @@ -84,7 +84,7 @@ def f(*, a, b=2): assert convert_positional_arguments(f, (), {}) -def to_wrap_with_composite(draw: None, strat: bool, nothing: list) -> int: +def to_wrap_with_composite(draw: None, strat: float, nothing: list) -> int: return draw(st.none()) diff --git a/hypothesis-python/tests/cover/test_arbitrary_data.py b/hypothesis-python/tests/cover/test_arbitrary_data.py index 25ea056bf2..2054796682 100644 --- a/hypothesis-python/tests/cover/test_arbitrary_data.py +++ b/hypothesis-python/tests/cover/test_arbitrary_data.py @@ -28,7 +28,7 @@ def test(data): y = data.draw(st.sampled_from(x)) x.remove(y) if y in x: - raise ValueError() + raise ValueError with raises(ValueError) as err: test() @@ -56,7 +56,7 @@ def test_given_twice_is_same(): def test(data1, data2): data1.draw(st.integers()) data2.draw(st.integers()) - raise ValueError() + raise ValueError with raises(ValueError) as err: test() diff --git a/hypothesis-python/tests/cover/test_attrs_inference.py b/hypothesis-python/tests/cover/test_attrs_inference.py index e4fe7dca74..6dce6a4c00 100644 --- a/hypothesis-python/tests/cover/test_attrs_inference.py +++ b/hypothesis-python/tests/cover/test_attrs_inference.py @@ -50,7 +50,7 @@ class Inferrables: typing_list = attr.ib(type=typing.List[int]) typing_list_of_list = attr.ib(type=typing.List[typing.List[int]]) typing_dict = attr.ib(type=typing.Dict[str, int]) - typing_union = attr.ib(type=typing.Optional[bool]) + typing_optional = attr.ib(type=typing.Optional[bool]) typing_union = attr.ib(type=typing.Union[str, int]) has_default = attr.ib(default=0) diff --git a/hypothesis-python/tests/cover/test_charmap.py b/hypothesis-python/tests/cover/test_charmap.py index 4c6a64d46a..fe45fefb5e 100644 --- a/hypothesis-python/tests/cover/test_charmap.py +++ b/hypothesis-python/tests/cover/test_charmap.py @@ -153,7 +153,7 @@ def test_can_handle_race_between_exist_and_create(monkeypatch): def test_exception_in_write_does_not_lead_to_broken_charmap(monkeypatch): def broken(*args, **kwargs): - raise ValueError() + raise ValueError cm._charmap = None monkeypatch.setattr(os.path, "exists", lambda p: False) @@ -180,7 +180,7 @@ def test_exclude_characters_are_included_in_key(): def test_error_writing_charmap_file_is_suppressed(monkeypatch): def broken_mkstemp(dir): - raise RuntimeError() + raise RuntimeError monkeypatch.setattr(tempfile, "mkstemp", broken_mkstemp) diff --git a/hypothesis-python/tests/cover/test_control.py b/hypothesis-python/tests/cover/test_control.py index 41c1eb1c55..fe6518d372 100644 --- a/hypothesis-python/tests/cover/test_control.py +++ b/hypothesis-python/tests/cover/test_control.py @@ -112,7 +112,7 @@ def test_raises_error_if_cleanup_fails_but_block_does_not(): with bc(): def foo(): - raise ValueError() + raise ValueError cleanup(foo) assert _current_build_context.value is None diff --git a/hypothesis-python/tests/cover/test_direct_strategies.py b/hypothesis-python/tests/cover/test_direct_strategies.py index 2e5310c5c5..024758f89c 100644 --- a/hypothesis-python/tests/cover/test_direct_strategies.py +++ b/hypothesis-python/tests/cover/test_direct_strategies.py @@ -356,7 +356,8 @@ def test_is_in_bounds(x): @given(ds.fractions(min_value=-1, max_value=1, max_denominator=1000)) def test_fraction_is_in_bounds(x): - assert -1 <= x <= 1 and abs(x.denominator) <= 1000 + assert -1 <= x <= 1 + assert abs(x.denominator) <= 1000 @given(ds.fractions(min_value=fractions.Fraction(1, 2))) @@ -489,7 +490,8 @@ def test_data_explicitly_rejects_non_strategies(data, value, label): @given(ds.integers().filter(bool).filter(lambda x: x % 3)) def test_chained_filter(x): - assert x and x % 3 + assert x + assert x % 3 def test_chained_filter_tracks_all_conditions(): diff --git a/hypothesis-python/tests/cover/test_error_in_draw.py b/hypothesis-python/tests/cover/test_error_in_draw.py index 08fb8fe981..200a8f7698 100644 --- a/hypothesis-python/tests/cover/test_error_in_draw.py +++ b/hypothesis-python/tests/cover/test_error_in_draw.py @@ -20,7 +20,7 @@ def test(d): try: d.draw(st.lists(st.integers(), min_size=3, unique=True)) finally: - raise ValueError() + raise ValueError with pytest.raises(ValueError) as err: test() diff --git a/hypothesis-python/tests/cover/test_executors.py b/hypothesis-python/tests/cover/test_executors.py index 808788df0c..4dd5a69646 100644 --- a/hypothesis-python/tests/cover/test_executors.py +++ b/hypothesis-python/tests/cover/test_executors.py @@ -28,7 +28,7 @@ def execute_example(self, function): @given(booleans()) def boom(self, b): def f(): - raise ValueError() + raise ValueError return f @@ -56,11 +56,11 @@ def execute_example(self, f): @given(integers()) @example(1) def test_no_boom_on_example(self, x): - raise ValueError() + raise ValueError @given(integers()) def test_no_boom(self, x): - raise ValueError() + raise ValueError @given(integers()) def test_boom(self, x): diff --git a/hypothesis-python/tests/cover/test_flakiness.py b/hypothesis-python/tests/cover/test_flakiness.py index 18f7f7634a..afddec8e44 100644 --- a/hypothesis-python/tests/cover/test_flakiness.py +++ b/hypothesis-python/tests/cover/test_flakiness.py @@ -29,7 +29,7 @@ def test_fails_only_once_is_flaky(): def rude(x): if first_call[0]: first_call[0] = False - raise Nope() + raise Nope with pytest.raises(Flaky): rude() @@ -114,11 +114,11 @@ def test(x): elif i == 2: reject() else: - raise Nope() + raise Nope try: test() except (Nope, Unsatisfiable, Flaky): pass except UnsatisfiedAssumption: - raise SatisfyMe() from None + raise SatisfyMe from None diff --git a/hypothesis-python/tests/cover/test_float_nastiness.py b/hypothesis-python/tests/cover/test_float_nastiness.py index d0a7977d72..8be1bbdac4 100644 --- a/hypothesis-python/tests/cover/test_float_nastiness.py +++ b/hypothesis-python/tests/cover/test_float_nastiness.py @@ -196,11 +196,10 @@ def test_no_single_floats_in_range(): low = 2.0**25 + 1 high = low + 2 st.floats(low, high).validate() # Note: OK for 64bit floats - with pytest.raises(InvalidArgument): - """Unrepresentable bounds are deprecated; but we're not testing that - here.""" - with warnings.catch_warnings(): - warnings.simplefilter("ignore") + with warnings.catch_warnings(): + # Unrepresentable bounds are deprecated, but we're not testing that here + warnings.simplefilter("ignore") + with pytest.raises(InvalidArgument): st.floats(low, high, width=32).validate() diff --git a/hypothesis-python/tests/cover/test_health_checks.py b/hypothesis-python/tests/cover/test_health_checks.py index c1b115159b..3600373836 100644 --- a/hypothesis-python/tests/cover/test_health_checks.py +++ b/hypothesis-python/tests/cover/test_health_checks.py @@ -76,7 +76,7 @@ def unhealthy_filter(x): @HEALTH_CHECK_SETTINGS @given(st.integers().filter(unhealthy_filter)) def test1(x): - raise ValueError() + raise ValueError with raises(FailedHealthCheck): test1() @@ -86,7 +86,7 @@ def test1(x): @settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow]) @given(st.integers().filter(unhealthy_filter)) def test2(x): - raise ValueError() + raise ValueError with raises(ValueError): test2() diff --git a/hypothesis-python/tests/cover/test_lazy_import.py b/hypothesis-python/tests/cover/test_lazy_import.py index e789490e08..8f76fde360 100644 --- a/hypothesis-python/tests/cover/test_lazy_import.py +++ b/hypothesis-python/tests/cover/test_lazy_import.py @@ -47,5 +47,5 @@ def test_hypothesis_does_not_import_test_runners(tmp_path): fname.write_text(SHOULD_NOT_IMPORT_TEST_RUNNERS, encoding="utf-8") subprocess.check_call( [sys.executable, str(fname)], - env={**os.environ, **{"HYPOTHESIS_NO_PLUGINS": "1"}}, + env={**os.environ, "HYPOTHESIS_NO_PLUGINS": "1"}, ) diff --git a/hypothesis-python/tests/cover/test_lookup.py b/hypothesis-python/tests/cover/test_lookup.py index 8cf045ff76..ac53257eeb 100644 --- a/hypothesis-python/tests/cover/test_lookup.py +++ b/hypothesis-python/tests/cover/test_lookup.py @@ -443,7 +443,8 @@ def test_raises_for_arg_with_unresolvable_annotation(): @given(a=..., b=...) def test_can_use_type_hints(a: int, b: float): - assert isinstance(a, int) and isinstance(b, float) + assert isinstance(a, int) + assert isinstance(b, float) def test_error_if_has_unresolvable_hints(): @@ -534,8 +535,8 @@ def test_override_args_for_namedtuple(thing): @pytest.mark.parametrize("thing", [typing.Optional, typing.List, typing.Type]) def test_cannot_resolve_bare_forward_reference(thing): + t = thing["ConcreteFoo"] with pytest.raises(InvalidArgument): - t = thing["ConcreteFoo"] st.from_type(t).example() @@ -560,7 +561,8 @@ class TypedTree(typing.TypedDict): def test_resolving_recursive_typeddict(): tree = st.from_type(TypedTree).example() assert isinstance(tree, dict) - assert len(tree) == 1 and "nxt" in tree + assert len(tree) == 1 + assert "nxt" in tree class MyList: diff --git a/hypothesis-python/tests/cover/test_phases.py b/hypothesis-python/tests/cover/test_phases.py index 8ccca601ed..fd12d7cf7d 100644 --- a/hypothesis-python/tests/cover/test_phases.py +++ b/hypothesis-python/tests/cover/test_phases.py @@ -60,7 +60,7 @@ def delete(self, key, value): pass def fetch(self, key): - raise ValueError() + raise ValueError def close(self): pass @@ -81,7 +81,7 @@ def test_will_save_when_reuse_not_in_phases(): @settings(database=database, phases=(Phase.generate,)) @given(st.integers()) def test_usage(i): - raise ValueError() + raise ValueError with pytest.raises(ValueError): test_usage() diff --git a/hypothesis-python/tests/cover/test_pretty.py b/hypothesis-python/tests/cover/test_pretty.py index 2497c16db3..6dbde8fa8a 100644 --- a/hypothesis-python/tests/cover/test_pretty.py +++ b/hypothesis-python/tests/cover/test_pretty.py @@ -282,7 +282,7 @@ def __class__(self): raise ValueError("I am horrible") def __repr__(self): - raise BadException() + raise BadException def test_really_bad_repr(): @@ -579,7 +579,8 @@ def test_re_evals(): re.compile("foo", re.MULTILINE | re.UNICODE), ]: r2 = eval(pretty.pretty(r), globals()) - assert r.pattern == r2.pattern and r.flags == r2.flags + assert r.pattern == r2.pattern + assert r.flags == r2.flags def test_print_builtin_function(): diff --git a/hypothesis-python/tests/cover/test_regex.py b/hypothesis-python/tests/cover/test_regex.py index 4ce0d1144a..e1f067a058 100644 --- a/hypothesis-python/tests/cover/test_regex.py +++ b/hypothesis-python/tests/cover/test_regex.py @@ -64,7 +64,7 @@ def unicode_regex(pattern): return re.compile(pattern, re.UNICODE) -def _test_matching_pattern(pattern, isvalidchar, is_unicode=False): +def _test_matching_pattern(pattern, *, isvalidchar, is_unicode=False): r = unicode_regex(pattern) if is_unicode else ascii_regex(pattern) codepoints = range(0, sys.maxunicode + 1) if is_unicode else range(1, 128) @@ -97,7 +97,7 @@ def pred(s): else: pred = predicate - _test_matching_pattern(category, pred, is_unicode) + _test_matching_pattern(category, isvalidchar=pred, is_unicode=is_unicode) @pytest.mark.parametrize( diff --git a/hypothesis-python/tests/cover/test_regressions.py b/hypothesis-python/tests/cover/test_regressions.py index 7fe60892df..1f0100d7a3 100644 --- a/hypothesis-python/tests/cover/test_regressions.py +++ b/hypothesis-python/tests/cover/test_regressions.py @@ -97,7 +97,7 @@ def test_regression_issue_1230(): @given(strategy) def test_false_is_false(params): assume(params.get("0") not in ("", "\x00")) - raise ValueError() + raise ValueError with pytest.raises(ValueError): test_false_is_false() diff --git a/hypothesis-python/tests/cover/test_reproduce_failure.py b/hypothesis-python/tests/cover/test_reproduce_failure.py index cb954ace4c..db3942f02d 100644 --- a/hypothesis-python/tests/cover/test_reproduce_failure.py +++ b/hypothesis-python/tests/cover/test_reproduce_failure.py @@ -173,7 +173,7 @@ def test_does_not_print_reproduction_for_large_data_examples_by_default(): def test(data): b = data.draw(st.binary(min_size=1000, max_size=1000)) if len(zlib.compress(b)) > 1000: - raise ValueError() + raise ValueError with capture_out() as o: with pytest.raises(ValueError): @@ -190,7 +190,7 @@ def test_does_not_print_reproduction_if_told_not_to(): @settings(print_blob=False) @given(st.integers().map(lambda x: Foo())) def test(i): - raise ValueError() + raise ValueError with capture_out() as o: with pytest.raises(ValueError): diff --git a/hypothesis-python/tests/cover/test_seed_printing.py b/hypothesis-python/tests/cover/test_seed_printing.py index 8b65d79b7e..bb73344b65 100644 --- a/hypothesis-python/tests/cover/test_seed_printing.py +++ b/hypothesis-python/tests/cover/test_seed_printing.py @@ -66,7 +66,7 @@ def test_uses_global_force(monkeypatch): @given(st.integers()) def test(i): - raise ValueError() + raise ValueError output = [] @@ -89,7 +89,7 @@ def test_does_print_on_reuse_from_database(): @given(st.integers()) def test(i): assume(passes_healthcheck) - raise ValueError() + raise ValueError with capture_out() as o: with pytest.raises(FailedHealthCheck): diff --git a/hypothesis-python/tests/cover/test_settings.py b/hypothesis-python/tests/cover/test_settings.py index 3095b5109e..b176713111 100644 --- a/hypothesis-python/tests/cover/test_settings.py +++ b/hypothesis-python/tests/cover/test_settings.py @@ -204,7 +204,7 @@ def test_database_type_must_be_ExampleDatabase(db, bad_db): def test_cannot_define_settings_once_locked(): with pytest.raises(InvalidState): - settings._define_setting("hi", "there", 4) + settings._define_setting("hi", "there", default=4) def test_cannot_assign_default(): @@ -344,19 +344,25 @@ def test_deadline_given_none(): def test_deadline_given_valid_int(): x = settings(deadline=1000).deadline assert isinstance(x, datetime.timedelta) - assert x.days == 0 and x.seconds == 1 and x.microseconds == 0 + assert x.days == 0 + assert x.seconds == 1 + assert x.microseconds == 0 def test_deadline_given_valid_float(): x = settings(deadline=2050.25).deadline assert isinstance(x, datetime.timedelta) - assert x.days == 0 and x.seconds == 2 and x.microseconds == 50250 + assert x.days == 0 + assert x.seconds == 2 + assert x.microseconds == 50250 def test_deadline_given_valid_timedelta(): x = settings(deadline=datetime.timedelta(days=1, microseconds=15030000)).deadline assert isinstance(x, datetime.timedelta) - assert x.days == 1 and x.seconds == 15 and x.microseconds == 30000 + assert x.days == 1 + assert x.seconds == 15 + assert x.microseconds == 30000 @pytest.mark.parametrize( @@ -419,13 +425,12 @@ class NonStateMachine: def test_assigning_to_settings_attribute_on_state_machine_raises_error(): - with pytest.raises(AttributeError): - - class StateMachine(RuleBasedStateMachine): - @rule(x=st.none()) - def a_rule(self, x): - assert x is None + class StateMachine(RuleBasedStateMachine): + @rule(x=st.none()) + def a_rule(self, x): + assert x is None + with pytest.raises(AttributeError): StateMachine.settings = settings() state_machine_instance = StateMachine() diff --git a/hypothesis-python/tests/cover/test_simple_characters.py b/hypothesis-python/tests/cover/test_simple_characters.py index d90a8b1d60..4dd8532739 100644 --- a/hypothesis-python/tests/cover/test_simple_characters.py +++ b/hypothesis-python/tests/cover/test_simple_characters.py @@ -103,8 +103,8 @@ def test_whitelisted_characters_overlap_blacklisted_characters(): whitelist_characters=good_chars, blacklist_characters=bad_chars, ).example() - assert repr(good_chars) in str(exc) - assert repr(bad_chars) in str(exc) + assert repr(good_chars) in str(exc) + assert repr(bad_chars) in str(exc) def test_whitelisted_characters_override(): diff --git a/hypothesis-python/tests/cover/test_slippage.py b/hypothesis-python/tests/cover/test_slippage.py index 5d8d4d2b83..cbdd4a9839 100644 --- a/hypothesis-python/tests/cover/test_slippage.py +++ b/hypothesis-python/tests/cover/test_slippage.py @@ -47,7 +47,7 @@ def test(i): assume(1003 < abs(i)) target[0] = i exc_class = TypeError if target[0] == i else ValueError - raise exc_class() + raise exc_class output = capture_reports(test) assert "TypeError" in output @@ -96,7 +96,7 @@ def test(i): if target[0] is None: target[0] = i exc_class = TypeError if target[0] == i else ValueError - raise exc_class() + raise exc_class with pytest.raises(ExceptionGroup): test() @@ -120,13 +120,13 @@ def test(i): if i == target[0]: if bug_fixed and fix == TypeError: return - raise TypeError() + raise TypeError if len(target) == 1: target.append(i) if bug_fixed and fix == ValueError: return if i == target[1]: - raise ValueError() + raise ValueError with pytest.raises(ExceptionGroup): test() @@ -153,11 +153,11 @@ def test(i): if not target: target.append(i) if i == target[0]: - raise TypeError() + raise TypeError if len(target) == 1: target.append(i) if i == target[1]: - raise ValueError() + raise ValueError with pytest.raises(ExceptionGroup): test() @@ -216,28 +216,24 @@ def test(i): if not target: target.append(i) if i == target[0]: - raise TypeError() + raise TypeError if flaky_failed_once[0] and not flaky_fixed: return if len(target) == 1: target.append(i) if i == target[1]: flaky_failed_once[0] = True - raise ValueError() + raise ValueError - try: + with pytest.raises(ExceptionGroup) as err: test() - raise AssertionError("Expected test() to raise an error") - except ExceptionGroup as err: - assert any(isinstance(e, Flaky) for e in err.exceptions) + assert any(isinstance(e, Flaky) for e in err.value.exceptions) flaky_fixed = True - try: + with pytest.raises(ExceptionGroup) as err: test() - raise AssertionError("Expected test() to raise an error") - except ExceptionGroup as err: - assert not any(isinstance(e, Flaky) for e in err.exceptions) + assert not any(isinstance(e, Flaky) for e in err.value.exceptions) @pytest.mark.parametrize("allow_multi", [True, False]) diff --git a/hypothesis-python/tests/cover/test_stateful.py b/hypothesis-python/tests/cover/test_stateful.py index d74baebcf4..2a6a5faa47 100644 --- a/hypothesis-python/tests/cover/test_stateful.py +++ b/hypothesis-python/tests/cover/test_stateful.py @@ -166,7 +166,8 @@ def check(self, value1, value2): def test_multiple(): none = multiple() some = multiple(1, 2.01, "3", b"4", 5) - assert len(none.values) == 0 and len(some.values) == 5 + assert len(none.values) == 0 + assert len(some.values) == 5 assert set(some.values) == {1, 2.01, "3", b"4", 5} @@ -424,7 +425,7 @@ def __init__(self): @precondition(lambda self: False) @rule() def test_blah(self): - raise ValueError() + raise ValueError @rule() def test_foo(self): @@ -443,7 +444,7 @@ def __init__(self): @invariant() def test_blah(self): - raise ValueError() + raise ValueError @rule() def do_stuff(self): @@ -485,12 +486,12 @@ def __init__(self): @invariant() @precondition(lambda _: False) def an_invariant(self): - raise ValueError() + raise ValueError @precondition(lambda _: False) @invariant() def another_invariant(self): - raise ValueError() + raise ValueError @rule() def do_stuff(self): @@ -560,7 +561,7 @@ def invariant_1(self): @precondition(lambda self: self.first_invariant_ran) @invariant() def invariant_2(self): - raise ValueError() + raise ValueError @rule() def do_stuff(self): @@ -581,7 +582,7 @@ def __init__(self): @precondition(lambda self: False) @invariant() def test_blah(self): - raise ValueError() + raise ValueError @rule() def test_foo(self): @@ -602,7 +603,7 @@ def __init__(self): @invariant() def test_blah(self): if self.num == 0: - raise ValueError() + raise ValueError @rule() def test_foo(self): @@ -621,7 +622,7 @@ def initialize_1(self): @invariant() def invariant_1(self): - raise ValueError() + raise ValueError @rule() def rule_1(self): @@ -671,7 +672,7 @@ def invariant_3(self): def rule_1(self): self.num += 1 if self.num == 2: - raise ValueError() + raise ValueError with pytest.raises(ValueError) as err: run_state_machine_as_test(BadRuleWithGoodInvariants) @@ -971,7 +972,7 @@ def test_steps_printed_despite_pytest_fail(): class RaisesProblem(RuleBasedStateMachine): @rule() def oops(self): - pytest.fail() + pytest.fail("note that this raises a BaseException") with pytest.raises(Failed) as err: run_state_machine_as_test(RaisesProblem) diff --git a/hypothesis-python/tests/cover/test_subnormal_floats.py b/hypothesis-python/tests/cover/test_subnormal_floats.py index 4877ce8ed5..e07207c961 100644 --- a/hypothesis-python/tests/cover/test_subnormal_floats.py +++ b/hypothesis-python/tests/cover/test_subnormal_floats.py @@ -31,7 +31,6 @@ def kw(marks=(), **kwargs): @pytest.mark.parametrize( "kwargs", [ - kw(min_value=1), kw(min_value=1), kw(max_value=-1), kw(min_value=float_info.min), diff --git a/hypothesis-python/tests/cover/test_testdecorators.py b/hypothesis-python/tests/cover/test_testdecorators.py index bc0dece41d..888e444235 100644 --- a/hypothesis-python/tests/cover/test_testdecorators.py +++ b/hypothesis-python/tests/cover/test_testdecorators.py @@ -164,7 +164,7 @@ def test_does_not_catch_interrupt_during_falsify(): def flaky_base_exception(x): if not calls[0]: calls[0] = 1 - raise KeyboardInterrupt() + raise KeyboardInterrupt with raises(KeyboardInterrupt): flaky_base_exception() @@ -336,7 +336,7 @@ def test_can_run_with_database_in_thread(): @given(integers()) def test_blah(x): - raise ValueError() + raise ValueError def run_test(): try: @@ -464,7 +464,7 @@ def test_prints_notes_once_on_failure(): def test(xs): note("Hi there") if sum(xs) <= 100: - raise ValueError() + raise ValueError with raises(ValueError) as err: test() @@ -479,4 +479,5 @@ def test_empty_lists(xs): def test_given_usable_inline_on_lambdas(): xs = [] given(booleans())(lambda x: xs.append(x))() - assert len(xs) == 2 and set(xs) == {False, True} + assert len(xs) == 2 + assert set(xs) == {False, True} diff --git a/hypothesis-python/tests/cover/test_traceback_elision.py b/hypothesis-python/tests/cover/test_traceback_elision.py index 31106de46b..66e0e057a8 100644 --- a/hypothesis-python/tests/cover/test_traceback_elision.py +++ b/hypothesis-python/tests/cover/test_traceback_elision.py @@ -20,7 +20,7 @@ def test_tracebacks_omit_hypothesis_internals(verbosity): @settings(verbosity=verbosity) @given(st.just(False)) def simplest_failure(x): - raise ValueError() + raise ValueError try: simplest_failure() diff --git a/hypothesis-python/tests/cover/test_type_lookup.py b/hypothesis-python/tests/cover/test_type_lookup.py index 5babf51103..1b913a1672 100644 --- a/hypothesis-python/tests/cover/test_type_lookup.py +++ b/hypothesis-python/tests/cover/test_type_lookup.py @@ -339,7 +339,7 @@ def test_generic_origin_concrete_builds(): class AbstractFoo(abc.ABC): - def __init__(self, x): + def __init__(self, x): # noqa: B027 pass @abc.abstractmethod @@ -369,7 +369,7 @@ def test_gen_abstract(foo): class AbstractBar(abc.ABC): - def __init__(self, x): + def __init__(self, x): # noqa: B027 pass @abc.abstractmethod diff --git a/hypothesis-python/tests/datetime/test_pytz_timezones.py b/hypothesis-python/tests/datetime/test_pytz_timezones.py index e2c9658216..3a3db14bc6 100644 --- a/hypothesis-python/tests/datetime/test_pytz_timezones.py +++ b/hypothesis-python/tests/datetime/test_pytz_timezones.py @@ -85,8 +85,9 @@ def test_overflow_in_simplify(): def test_timezones_arg_to_datetimes_must_be_search_strategy(): with pytest.raises(InvalidArgument): datetimes(timezones=pytz.all_timezones).validate() + + tz = [pytz.timezone(t) for t in pytz.all_timezones] with pytest.raises(InvalidArgument): - tz = [pytz.timezone(t) for t in pytz.all_timezones] datetimes(timezones=tz).validate() diff --git a/hypothesis-python/tests/django/toystore/models.py b/hypothesis-python/tests/django/toystore/models.py index 270f7d6f8e..89a49af1b0 100644 --- a/hypothesis-python/tests/django/toystore/models.py +++ b/hypothesis-python/tests/django/toystore/models.py @@ -43,7 +43,7 @@ class Customish(models.Model): class Customer(models.Model): name = models.CharField(max_length=100, unique=True) email = models.EmailField(max_length=100, unique=True) - gender = models.CharField(max_length=50, null=True) + gender = models.CharField(max_length=50, null=True) # noqa # avoid nullable strs age = models.IntegerField() birthday = models.DateTimeField() @@ -103,7 +103,7 @@ class MandatoryComputed(models.Model): def __init__(self, **kw): if "company" in kw: - raise RuntimeError() + raise RuntimeError cname = kw["name"] + "_company" kw["company"] = Company.objects.create(name=cname) super().__init__(**kw) diff --git a/hypothesis-python/tests/nocover/test_build_signature.py b/hypothesis-python/tests/nocover/test_build_signature.py index c92136e8b1..5044a807d0 100644 --- a/hypothesis-python/tests/nocover/test_build_signature.py +++ b/hypothesis-python/tests/nocover/test_build_signature.py @@ -16,7 +16,7 @@ from tests.common.debug import find_any -def use_this_signature(self, a: int, b: bool = None, *, x: float, y: str): +def use_this_signature(self, a: int, b: list = None, *, x: float, y: str): pass @@ -43,7 +43,7 @@ class ModelForFromType(Model): def __init__(self, **kwargs): assert set(kwargs) == {"a", "b", "x", "y"} self.b = kwargs["b"] - assert self.b is None or isinstance(self.b, bool) + assert self.b is None or isinstance(self.b, list) @given(st.from_type(ModelForFromType)) @@ -53,7 +53,7 @@ def test_from_type_uses_signature_attribute(val): def test_from_type_can_be_default_or_annotation(): find_any(st.from_type(ModelForFromType), lambda m: m.b is None) - find_any(st.from_type(ModelForFromType), lambda m: isinstance(m.b, bool)) + find_any(st.from_type(ModelForFromType), lambda m: isinstance(m.b, list)) def use_annotations( @@ -105,7 +105,7 @@ def test_build_with_non_types_in_signature(val): class UnconventionalSignature: - def __init__(x: int = 0, self: bool = True): # noqa: B902 + def __init__(x: int = 0, self: bool = True): # noqa assert not isinstance(x, int) x.self = self diff --git a/hypothesis-python/tests/nocover/test_duplication.py b/hypothesis-python/tests/nocover/test_duplication.py index 7d53f625f3..186b75c42d 100644 --- a/hypothesis-python/tests/nocover/test_duplication.py +++ b/hypothesis-python/tests/nocover/test_duplication.py @@ -46,7 +46,7 @@ def test_mostly_does_not_duplicate_blocks_even_when_failing(n): def test(b): counts[b] += 1 if len(counts) > 3: - raise ValueError() + raise ValueError try: test() diff --git a/hypothesis-python/tests/nocover/test_nesting.py b/hypothesis-python/tests/nocover/test_nesting.py index 4546fba07e..5aed586fe3 100644 --- a/hypothesis-python/tests/nocover/test_nesting.py +++ b/hypothesis-python/tests/nocover/test_nesting.py @@ -25,7 +25,7 @@ def test_blah(x): ) def test_nest(y): if y >= x: - raise ValueError() + raise ValueError with raises(ValueError): test_nest() diff --git a/hypothesis-python/tests/nocover/test_testdecorators.py b/hypothesis-python/tests/nocover/test_testdecorators.py index a62744e592..8d7f73bdc5 100644 --- a/hypothesis-python/tests/nocover/test_testdecorators.py +++ b/hypothesis-python/tests/nocover/test_testdecorators.py @@ -50,13 +50,12 @@ def test_signature_mismatch_error_message(): def bad_test(): pass - try: + with pytest.raises( + InvalidArgument, + match=r"bad_test\(\) got an unexpected keyword argument 'x', " + r"from `x=integers\(\)` in @given", + ): bad_test() - except InvalidArgument as e: - assert ( - str(e) == "bad_test() got an unexpected keyword argument 'x', " - "from `x=integers()` in @given" - ) @given(data=st.data(), keys=st.lists(st.integers(), unique=True)) diff --git a/hypothesis-python/tests/numpy/test_gen_data.py b/hypothesis-python/tests/numpy/test_gen_data.py index e1981e3596..3f494c7221 100644 --- a/hypothesis-python/tests/numpy/test_gen_data.py +++ b/hypothesis-python/tests/numpy/test_gen_data.py @@ -134,7 +134,8 @@ def test_minimise_array_shapes(min_dims, dim_range, min_side, side_range): max_side=min_side + side_range, ) ) - assert len(smallest) == min_dims and all(k == min_side for k in smallest) + assert len(smallest) == min_dims + assert all(k == min_side for k in smallest) @pytest.mark.parametrize( @@ -194,7 +195,8 @@ def test_minimise_array_strategy(): nps.array_shapes(max_dims=3, max_side=3), ) ) - assert smallest.dtype == np.dtype("bool") and not smallest.any() + assert smallest.dtype == np.dtype("bool") + assert not smallest.any() @given(nps.array_dtypes(allow_subarrays=False)) @@ -475,7 +477,8 @@ def test_minimize_tuple_axes(ndim, data): min_size = data.draw(st.integers(0, ndim), label="min_size") max_size = data.draw(st.integers(min_size, ndim), label="max_size") smallest = minimal(nps.valid_tuple_axes(ndim, min_size=min_size, max_size=max_size)) - assert len(smallest) == min_size and all(k > -1 for k in smallest) + assert len(smallest) == min_size + assert all(k > -1 for k in smallest) @settings(deadline=None, max_examples=10) @@ -522,7 +525,8 @@ def test_broadcastable_shape_bounds_are_satisfied(shape, data): if max_side is None: max_side = max(tuple(shape[::-1][:max_dims]) + (min_side,)) + 2 - assert isinstance(bshape, tuple) and all(isinstance(s, int) for s in bshape) + assert isinstance(bshape, tuple) + assert all(isinstance(s, int) for s in bshape) assert min_dims <= len(bshape) <= max_dims assert all(min_side <= s <= max_side for s in bshape) @@ -566,12 +570,13 @@ def test_mutually_broadcastable_shape_bounds_are_satisfied( assert all(isinstance(s, int) for s in result) for bshape in shapes: - assert isinstance(bshape, tuple) and all(isinstance(s, int) for s in bshape) + assert isinstance(bshape, tuple) + assert all(isinstance(s, int) for s in bshape) assert min_dims <= len(bshape) <= max_dims assert all(min_side <= s <= max_side for s in bshape) -def _draw_valid_bounds(data, shape, max_dims, permit_none=True): +def _draw_valid_bounds(data, shape, max_dims, *, permit_none=True): if max_dims == 0 or not shape: return 0, None @@ -801,7 +806,8 @@ def test_mutually_broadcastable_shape_adjusts_max_dim_with_default_bounds( ) except InvalidArgument: # There is no satisfiable `max_dims` for us to tune - assert min_dims == 4 and (max_side == 3 or base_shape[0] == 0) + assert min_dims == 4 + assert max_side == 3 or base_shape[0] == 0 return if max_side == 3 or base_shape[0] == 0: diff --git a/hypothesis-python/tests/pandas/test_argument_validation.py b/hypothesis-python/tests/pandas/test_argument_validation.py index 749dc0298d..6ebe474c5a 100644 --- a/hypothesis-python/tests/pandas/test_argument_validation.py +++ b/hypothesis-python/tests/pandas/test_argument_validation.py @@ -122,10 +122,10 @@ def test_confusing_object_dtype_aliases(): not IntegerDtype, reason="Nullable types not available in this version of Pandas" ) def test_pandas_nullable_types_class(): + st = pdst.series(dtype=pd.core.arrays.integer.Int8Dtype) with pytest.raises( InvalidArgument, match="Otherwise it would be treated as dtype=object" ): - st = pdst.series(dtype=pd.core.arrays.integer.Int8Dtype) find_any(st, lambda s: s.isna().any()) diff --git a/pyproject.toml b/pyproject.toml index a1d9483d01..b1df650c37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,59 +1,76 @@ [tool.ruff] select = [ "ASYNC", # flake8-async + "B", # flake8-bugbear "C4", # flake8-comprehensions + "COM", # flake8-commas + "DJ", # flake8-django "E", # pycodestyle "F", # Pyflakes + "FBT", # flake8-boolean-trap + "FLY", # flynt "G", # flake8-logging-format "INT", # flake8-gettext "ISC", # flake8-implicit-str-concat + "NPY", # NumPy-specific rules + "PD", # pandas-vet + "PIE", # flake8-pie "PLE", # Pylint errors + "PT", # flake8-pytest-style + "RET504", # flake8-return + "RSE", # flake8-raise + "SIM", # flake8-simplify "T10", # flake8-debugger "TID", # flake8-tidy-imports "UP", # pyupgrade "W", # pycodestyle "YTT", # flake8-2020 - # "A", # flake8-builtins - # "ANN", # flake8-annotations - # "ARG", # flake8-unused-arguments - # "B", # flake8-bugbear - # "BLE", # flake8-blind-except - # "COM", # flake8-commas - # "D", # pydocstyle - # "DJ", # flake8-django # "DTZ", # flake8-datetimez - # "EM", # flake8-errmsg - # "ERA", # eradicate - # "EXE", # flake8-executable - # "FA", # flake8-future-annotations - # "FBT", # flake8-boolean-trap - # "FLY", # flynt - # "I", # isort - # "ICN", # flake8-import-conventions - # "INP", # flake8-no-pep420 - # "N", # pep8-naming - # "NPY", # NumPy-specific rules - # "PD", # pandas-vet - # "PGH", # pygrep-hooks - # "PIE", # flake8-pie - # "PL", # Pylint - # "PT", # flake8-pytest-style # "PTH", # flake8-use-pathlib - # "Q", # flake8-quotes - # "RET", # flake8-return - # "RSE", # flake8-raise # "RUF", # Ruff-specific rules # "S", # flake8-bandit - # "SIM", # flake8-simplify - # "SLF", # flake8-self - # "TCH", # flake8-type-checking - # "TD", # flake8-todos - # "TRY", # tryceratops ] -ignore = ["C408", "E731", "E741", "S101", "UP031"] +ignore = [ + "B008", + "B018", + "B023", # todo: function defs not binding loop variables + #"B028", # todo: add stacklevel= to warnings + "C408", + "COM812", + "DJ008", + "E721", + "E731", + "E741", + "FBT002", # todo: make bool-default arguments kwonly + "FBT003", + "PD011", + "PD901", + "PT001", + "PT003", + "PT006", + "PT007", + "PT009", + "PT011", + "PT012", + "PT013", + "PT017", + "PT019", + "PT023", + "PT027", + "S101", + "SIM102", + "SIM105", + "SIM108", + "SIM114", + "SIM117", + "SIM300", + "UP031", +] line-length = 125 target-version = "py38" [tool.ruff.per-file-ignores] +"hypothesis-python/src/hypothesis/core.py" = ["B030", "B904", "FBT001"] "hypothesis-python/src/hypothesis/internal/compat.py" = ["F401"] "hypothesis-python/tests/nocover/test_imports.py" = ["F403", "F405"] +"hypothesis-python/tests/numpy/test_randomness.py" = ["NPY002"] diff --git a/tooling/setup.py b/tooling/setup.py index 16c431e495..3f84ed61f2 100644 --- a/tooling/setup.py +++ b/tooling/setup.py @@ -32,5 +32,5 @@ def local_file(name): license="MPL v2", description="A library for property-based testing", python_requires=">=3.7", - long_description=open(README).read(), + long_description=open(README).read(), # noqa ) diff --git a/tooling/src/hypothesistooling/__main__.py b/tooling/src/hypothesistooling/__main__.py index 1338b7d83f..c584dbc1f7 100644 --- a/tooling/src/hypothesistooling/__main__.py +++ b/tooling/src/hypothesistooling/__main__.py @@ -73,7 +73,7 @@ def codespell(*files): @task() def lint(): - pip_tool("ruff", "."), + pip_tool("ruff", ".") codespell(*(f for f in tools.all_files() if not f.endswith("by-domain.txt"))) @@ -207,7 +207,7 @@ def warn(msg): o.write("\n") codespell("--write-changes", *files_to_format, *doc_files_to_format) - pip_tool("ruff", "--fix-only", "."), + pip_tool("ruff", "--fix-only", ".") pip_tool("shed", *files_to_format, *doc_files_to_format) @@ -236,7 +236,7 @@ def check_not_changed(): @task() -def compile_requirements(upgrade=False): +def compile_requirements(*, upgrade=False): if upgrade: extra = ["--upgrade", "--rebuild"] else: diff --git a/tooling/src/hypothesistooling/projects/hypothesispython.py b/tooling/src/hypothesistooling/projects/hypothesispython.py index a2c1473405..f04965b5e9 100644 --- a/tooling/src/hypothesistooling/projects/hypothesispython.py +++ b/tooling/src/hypothesistooling/projects/hypothesispython.py @@ -100,7 +100,7 @@ def update_changelog_and_version(): ), f"{__version__=} {lines[i + 3]=}" beginning = "\n".join(lines[:i]) rest = "\n".join(lines[i:]) - assert "\n".join((beginning, rest)) == contents + assert f"{beginning}\n{rest}" == contents break release_type, release_contents = parse_release_file() @@ -120,7 +120,7 @@ def update_changelog_and_version(): rm.replace_assignment(VERSION_FILE, "__version_info__", repr(new_version_info)) - heading_for_new_version = " - ".join((new_version_string, rm.release_date_string())) + heading_for_new_version = f"{new_version_string} - {rm.release_date_string()}" border_for_new_version = "-" * len(heading_for_new_version) new_changelog_parts = [ @@ -250,7 +250,7 @@ def tag_name(): return PYTHON_TAG_PREFIX + __version__ -def get_autoupdate_message(domainlist_changed: bool) -> str: +def get_autoupdate_message(domainlist_changed): if domainlist_changed: return ( "This patch updates our vendored `list of top-level domains " diff --git a/whole-repo-tests/test_validate_branch_check.py b/whole-repo-tests/test_validate_branch_check.py index 99faed829c..59e8d5a0d5 100644 --- a/whole-repo-tests/test_validate_branch_check.py +++ b/whole-repo-tests/test_validate_branch_check.py @@ -79,15 +79,13 @@ def test_reports_uncovered_branches(tmp_path): output = run_validate_branch_check(tmp_path, check=False) assert output.returncode == 1 - assert output.stdout == "\n".join( - [ - "Some branches were not properly covered.", - "", - "The following were always True:", - " * branch that is always taken", - "", - "The following were always False:", - " * some other branch that is never taken", - "", - ] - ) + expected = """\ +Some branches were not properly covered. + +The following were always True: + * branch that is always taken + +The following were always False: + * some other branch that is never taken +""" + assert output.stdout == expected