Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tighten up some internal type annotations #3395

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RELEASE_TYPE: patch

This patch improves some internal type annotations.
4 changes: 2 additions & 2 deletions hypothesis-python/src/hypothesis/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def __init__(
# The intended use is "like **kwargs, but more tractable for tooling".
max_examples: int = not_set, # type: ignore
derandomize: bool = not_set, # type: ignore
database: Union[None, "ExampleDatabase"] = not_set, # type: ignore
database: Optional["ExampleDatabase"] = not_set, # type: ignore
verbosity: "Verbosity" = not_set, # type: ignore
phases: Collection["Phase"] = not_set, # type: ignore
stateful_step_count: int = not_set, # type: ignore
Expand All @@ -160,7 +160,7 @@ def __init__(
if parent is not None:
check_type(settings, parent, "parent")
if derandomize not in (not_set, False):
if database not in (not_set, None):
if database not in (not_set, None): # type: ignore
raise InvalidArgument(
"derandomize=True implies database=None, so passing "
f"database={database!r} too is invalid."
Expand Down
8 changes: 4 additions & 4 deletions hypothesis-python/src/hypothesis/internal/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@
WINDOWS = platform.system() == "Windows"


def escape_unicode_characters(s):
def escape_unicode_characters(s: str) -> str:
return codecs.encode(s, "unicode_escape").decode("ascii")


def int_from_bytes(data):
def int_from_bytes(data: typing.Union[bytes, bytearray]) -> int:
return int.from_bytes(data, "big")


def int_to_bytes(i, size):
def int_to_bytes(i: int, size: int) -> bytes:
return i.to_bytes(size, "big")


def int_to_byte(i):
def int_to_byte(i: int) -> bytes:
return bytes([i])


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def __init__(self):
self.n: "Optional[int]" = None

@property
def exhausted(self):
def exhausted(self) -> bool:
return self.live_child_count == 0


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from typing_extensions import dataclass_transform

from hypothesis.strategies import SearchStrategy
from hypothesis.strategies._internal.strategies import Ex
else:

def dataclass_transform():
Expand Down Expand Up @@ -816,7 +817,7 @@ def __init__(
self.max_length = max_length
self.is_find = False
self.overdraw = 0
self.__prefix = prefix
self.__prefix = bytes(prefix)
self.__random = random

assert random is not None or max_length <= len(prefix)
Expand Down Expand Up @@ -907,7 +908,7 @@ def note(self, value: Any) -> None:
value = repr(value)
self.output += value

def draw(self, strategy: "SearchStrategy[Any]", label: Optional[int] = None) -> Any:
def draw(self, strategy: "SearchStrategy[Ex]", label: Optional[int] = None) -> "Ex":
if self.is_find and not strategy.supports_find:
raise InvalidArgument(
f"Cannot use strategy {strategy!r} within a call to find "
Expand Down
2 changes: 1 addition & 1 deletion hypothesis-python/src/hypothesis/internal/filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ConstructivePredicate(NamedTuple):
predicate: Optional[Predicate]

@classmethod
def unchanged(cls, predicate):
def unchanged(cls, predicate: Predicate) -> "ConstructivePredicate":
return cls({}, predicate)


Expand Down
20 changes: 13 additions & 7 deletions hypothesis-python/src/hypothesis/internal/floats.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,18 @@

import math
import struct
from decimal import Decimal
from fractions import Fraction
from sys import float_info
from typing import Callable, Optional
from typing import Callable, Optional, Union

try:
from typing import TypeAlias
except ImportError:
TypeAlias = object # type: ignore
Comment on lines +18 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the pyright fail case I think you want to fall back on TypeAlias being Any:

try:
    from typing import TypeAlias
except ImportError:
    try:
        from typing_extensions import TypeAlias
    except ImportError:
        from typing import Any as TypeAlias

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix I went with was "instead of moving the Real alias, just use SupportsFloat like a sensible person"; see the other PR for that 😁

Copy link
Contributor

@rsokl rsokl Jul 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix I went with was "instead of moving the Real alias, just use SupportsFloat like a sensible person"; see the other PR for that 😁

🤩

I am sooooo stealing this for some of my projects!


# See https://github.com/python/mypy/issues/3186 - numbers.Real is wrong!
Real: TypeAlias = Union[int, float, Fraction, Decimal]

# Format codes for (int, float) sized types, used for byte-wise casts.
# See https://docs.python.org/3/library/struct.html#format-characters
Expand All @@ -36,19 +46,15 @@ def float_of(x, width):
return reinterpret_bits(float(x), "!e", "!e")


def sign(x):
def is_negative(x: Real) -> bool:
try:
return math.copysign(1.0, x)
return math.copysign(1.0, x) < 0
except TypeError:
raise TypeError(
f"Expected float but got {x!r} of type {type(x).__name__}"
) from None


def is_negative(x):
return sign(x) < 0


def count_between_floats(x, y, width=64):
assert x <= y
if is_negative(x):
Expand Down
14 changes: 5 additions & 9 deletions hypothesis-python/src/hypothesis/strategies/_internal/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
integer_range,
)
from hypothesis.internal.entropy import get_seeder_and_restorer
from hypothesis.internal.floats import Real
from hypothesis.internal.reflection import (
define_function_signature,
get_pretty_function_description,
Expand Down Expand Up @@ -85,12 +86,7 @@
from hypothesis.strategies._internal.functions import FunctionStrategy
from hypothesis.strategies._internal.lazy import LazyStrategy
from hypothesis.strategies._internal.misc import just, none, nothing
from hypothesis.strategies._internal.numbers import (
IntegersStrategy,
Real,
floats,
integers,
)
from hypothesis.strategies._internal.numbers import IntegersStrategy, floats, integers
from hypothesis.strategies._internal.recursive import RecursiveStrategy
from hypothesis.strategies._internal.shared import SharedStrategy
from hypothesis.strategies._internal.strategies import (
Expand Down Expand Up @@ -889,7 +885,7 @@ def builds(
"target to construct."
)

if infer in args:
if infer in args: # type: ignore # we only annotated the allowed types
# Avoid an implementation nightmare juggling tuples and worse things
raise InvalidArgument(
"... was passed as a positional argument to "
Expand Down Expand Up @@ -1396,9 +1392,9 @@ def fraction_to_decimal(val):
special: List[Decimal] = []
if allow_nan or (allow_nan is None and (None in (min_value, max_value))):
special.extend(map(Decimal, ("NaN", "-NaN", "sNaN", "-sNaN")))
if allow_infinity or (allow_infinity is max_value is None):
if allow_infinity or (allow_infinity is None and max_value is None):
special.append(Decimal("Infinity"))
if allow_infinity or (allow_infinity is min_value is None):
if allow_infinity or (allow_infinity is None and min_value is None):
special.append(Decimal("-Infinity"))
return strat | (sampled_from(special) if special else nothing())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@
# obtain one at https://mozilla.org/MPL/2.0/.

import math
from decimal import Decimal
from fractions import Fraction
from sys import float_info
from typing import Optional, Union
from typing import Optional

from hypothesis.control import reject
from hypothesis.errors import InvalidArgument
Expand All @@ -23,6 +21,7 @@
get_integer_predicate_bounds,
)
from hypothesis.internal.floats import (
Real,
float_of,
int_to_float,
is_negative,
Expand All @@ -42,8 +41,6 @@
from hypothesis.strategies._internal.strategies import SearchStrategy
from hypothesis.strategies._internal.utils import cacheable, defines_strategy

# See https://github.com/python/mypy/issues/3186 - numbers.Real is wrong!
Real = Union[int, float, Fraction, Decimal]
ONE_BOUND_INTEGERS_LABEL = d.calc_label_from_name("trying a one-bound int allowing 0")


Expand Down
20 changes: 0 additions & 20 deletions hypothesis-python/tests/cover/test_internal_helpers.py

This file was deleted.

1 change: 1 addition & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ no_implicit_reexport = True
follow_imports = silent
ignore_missing_imports = True

strict_equality = True
warn_no_return = True
warn_unused_ignores = True
warn_unused_configs = True
Expand Down