-
-
Notifications
You must be signed in to change notification settings - Fork 582
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
Harmonize annotations with python/typeshed#8608 #1027
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
""" | ||
Type aliases and utilities to help manage `typing` usage and type annotations. | ||
""" | ||
|
||
from collections.abc import Mapping, Sequence | ||
import typing | ||
|
||
Schema = Mapping[str, typing.Any] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Schema is tricky to nail down for multiple reasons. Its precise type depends on the specific dialect of JSON Schema involved, and (speaking off the top of my head without double checking, which counts for lots of the comments I'm about to make --)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm definitely going to have to circle back to try to better grasp what's sensible here. In line with my other comment about maybe accepting some technical inaccuracy in the annotations as a pragmatic approach, I'm instinctively inclined towards |
||
|
||
JsonObject = Mapping[str, typing.Any] | ||
|
||
JsonValue = typing.Union[ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is incomplete -- someone can come along and invent validator callbacks which only work if someone deserialized into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we might have a tension here between annotations which are useful vs ones which are completely accurate. If we annotate things as Is it okay to suggest that anyone using type checking needs to use The type really is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to think about what I think honestly. To me, all I am "convinced" is useful of at the minute (and I'm quite convinced it's very useful indeed) is that typing forces documentation to have correctly documented types. That's the reason I'm quite picky about making sure that things which work "accidentally" because we abuse some type internally do not in fact get represented as the type -- because later down the line I will not support those internal abuses if we need to change them for whatever reason. They're not part of the public API, they don't have stability guarantees. Here, the opposite is true -- not documenting the type here actually means "regressing" something that is indeed public API, and which I very much do intend folks to rely on (by which I don't mean I have no reservations that it will bite me in the ass, but I do mean it's something I think people should consider public API at this point, type annotation or not, and I don't intend to break it). And I know we don't actually regress, since I'm pretty sure there are tests covering the (So... "I don't know yet" :D) |
||
JsonObject, Sequence[typing.Any], str, int, float, bool, None | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,13 +23,19 @@ | |
_format, | ||
_legacy_validators, | ||
_types, | ||
_typing, | ||
_utils, | ||
_validators, | ||
exceptions, | ||
) | ||
|
||
_UNSET = _utils.Unset() | ||
|
||
_ValidatorCallback = typing.Callable[ | ||
[typing.Any, typing.Any, _typing.JsonValue, _typing.JsonObject], | ||
typing.Iterator[exceptions.ValidationError], | ||
] | ||
|
||
_VALIDATORS: dict[str, typing.Any] = {} | ||
_META_SCHEMAS = _utils.URIDict() | ||
_VOCABULARIES: list[tuple[str, typing.Any]] = [] | ||
|
@@ -114,13 +120,15 @@ def _store_schema_list(): | |
|
||
|
||
def create( | ||
meta_schema, | ||
validators=(), | ||
meta_schema: _typing.Schema, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to double check (which I will be lazy and not do here) but Unlike There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, that makes sense. I need to think harder about what to do with schemas more broadly, but we now have a clean place where we can define |
||
validators: Mapping[str, _ValidatorCallback] | tuple[()] = (), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The public API is just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I'm cool with that way of handling these! I had some other ideas which I like less, but another option just occured to me. With # in the definition
validators: Mapping[str, _ValidatorCallback] = _typing.EmptySequence
# in _typing
EmptySequence = typing.cast(typing.Any, ()) Because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That seems also fine with me (although I think the fact that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it help that I also considered
? I just know that this pattern occurs several times in the code, with |
||
version=None, | ||
type_checker=_types.draft202012_type_checker, | ||
format_checker=_format.draft202012_format_checker, | ||
id_of=_id_of, | ||
applicable_validators=methodcaller("items"), | ||
type_checker: _types.TypeChecker = _types.draft202012_type_checker, | ||
format_checker: _format.FormatChecker = _format.draft202012_format_checker, | ||
id_of: typing.Callable[[_typing.Schema], str] = _id_of, | ||
applicable_validators: typing.Callable[ | ||
[_typing.Schema], typing.Iterable[tuple[str, _ValidatorCallback]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (This has to do with the above, the type for |
||
] = methodcaller("items"), | ||
): | ||
""" | ||
Create a new validator class. | ||
|
@@ -186,7 +194,7 @@ def create( | |
@attr.s | ||
class Validator: | ||
|
||
VALIDATORS = dict(validators) | ||
VALIDATORS: dict[str, _ValidatorCallback] = dict(validators) | ||
META_SCHEMA = dict(meta_schema) | ||
TYPE_CHECKER = type_checker | ||
FORMAT_CHECKER = format_checker_arg | ||
|
@@ -339,7 +347,7 @@ def is_valid(self, instance, _schema=None): | |
if version is not None: | ||
safe = version.title().replace(" ", "").replace("-", "") | ||
Validator.__name__ = Validator.__qualname__ = f"{safe}Validator" | ||
Validator = validates(version)(Validator) | ||
Validator = validates(version)(Validator) # type: ignore[misc] | ||
|
||
return Validator | ||
|
||
|
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.
(Definitely support adding this, thanks!)