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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add type hints to the public API, with generic Strategy type #1253
Conversation
115f439
to
e7be891
Compare
Ready for review! |
Ping @HypothesisWorks/hypothesis-python-contributors for review! |
LGFM. @Zac-HD |
I picked comments over stubs for a couple of reasons.
There's a constant |
Thank you! |
Ping @DRMacIver for review - it's been almost two weeks! I'd really like to get this merged soon so I can focus on PyCon preparation 馃槃 |
|
||
except ImportError: # pragma: no cover | ||
Ex = 'key' # type: ignore | ||
Generic = {Ex: object} # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actual cracked up at this hack.
(It's a perfectly reasonable solution but for some reason struck me as very funny)
pass # pragma: no cover | ||
|
||
|
||
@overload # noqa: F811 # redefinition of sampled_from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should just turn off this warning in config? I'm not sure it gives us much of use and these noqa
s are annoying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe my tendency to never-weaken-default-settings is going too far here, yes.
hypothesis-python/docs/details.rst
Outdated
up our type hints. | ||
|
||
.. note:: | ||
Hypothesis' type hints may make breaking changes between minor releases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the paragraphs below be part of this note? They qualify it, so I think it makes sense to have them logically grouped.
It also might be nice to make clear that we do plan to stabilise it eventually (but not before the main typing module becomes non-provisional)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expanding note, yes. IMO the plans to stabilise are implicit, and I'd rather leave them that way until we have some more experience and understanding of how often they break over time.
hypothesis-python/docs/details.rst
Outdated
|
||
.. doctest:: | ||
|
||
>>> from hypothesis.strategies import SearchStrategy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this doctest really add much? It seems weird in context as it's only asserting something about the dynamic subtyping behaviour in a section where we talk about how the only valid use case of this type is static type checking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...I'll take it out, you're right.
History: this is how I found the problem with unannotated decorators erasing type hints. More on that below...
hypothesis-python/docs/details.rst
Outdated
- ``integers()`` is of type ``SearchStrategy[int]``. | ||
- ``lists(integers())`` is of type ``SearchStrategy[List[int]]``. | ||
- ``SearchStrategy[bool]`` is a subtype of ``SearchStrategy[int]``, | ||
because ``bool`` is a subtype of ``int``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: bool
being a subtype of int
is weird enough that I'd probably prefer a different example. Maybe just that it's a subtype of SearchStrategy[Any]
?
hypothesis-python/docs/details.rst
Outdated
Please do not inherit from, compare to, or otherwise use the | ||
:class:`~hypothesis.strategies.SearchStrategy` in any way outside of type | ||
hints. This is a private, internal interface that is *only* available for | ||
type checking, and may be changed or removed in any minor release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a bit strong. We can probably commit to keeping the name around without a major release bump.
def given(*given_arguments, **given_kwargs): | ||
# type: (*SearchStrategy, **SearchStrategy) -> Callable | ||
def given( | ||
*given_arguments, # type: Union[SearchStrategy, UniqueIdentifier] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't need to be as part of this PR, but it would be nice to tighten up these types to be more specific about which UniqueIdentifier
is permitted here, if only so the UniqueIdentifier
type doesn't appear in our public APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll include that too; it's pretty easy to toss in class InferType(UniqueIdentifier): ...
, infer = InferType('infer')
(better name welcome), and edit the hints.
Note on release plans: as this stands, there are no automated tests that will catch regressions in the type hints as seen by downstream users. With some distance from the initial implementation, that makes me uncomfortable - I'm pretty sure that means that they'll break soon, or simply aren't working at all yet. In the interest of reviewable diffs, I therefore propose to replace the docs+release commit with a smaller one that does another non-user-facing patch, and then do a follow-up PR later this week with tests and the public release of type annotations. Sound good? |
5c021f3
to
f03a034
Compare
Updated for another @DRMacIver review 馃槃 |
@@ -27,5 +27,14 @@ def __repr__(self): | |||
return self.identifier | |||
|
|||
|
|||
infer = UniqueIdentifier(u'infer') | |||
class DefaultValueType(UniqueIdentifier): | |||
# Using subclasses so they can be distinguished by e.g. Mypy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This comment should probably go at the top level as it applies to two classes, not just this one.
(so Mypy can tell you're using the wrong one)
Does not quite close #200 (next time though! 馃帀)
I won't recite the whole motivation here - suffice to say that at least some people like static typing, and so I'd like to let the type-checker find some of their obvious misuses of Hypothesis.
Things not obvious from review:
tuples
.disallow_untyped_decorators
option is indispensable if you don't want a a decorator to erase the type hints on a function.I would also like to write some tests using
reveal_type
to check that Mypy does in fact infer the expected type for various expressions. This may go in a later PR, to keep things reviewable - I've confirmed most of this manually, so automated tests would really be for tooling or code regressions.