-
-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
bpo-46998: Allow subclassing Any at runtime #31841
Changes from 13 commits
bc71456
abea39a
771f492
900f2c7
6e76441
b00ab17
4d913ad
1c1ab38
4927e78
68ea3a8
f94b7e0
05db029
e11f405
63b00e4
ac7b4a8
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 |
---|---|---|
|
@@ -2802,8 +2802,6 @@ def f(arg): | |
f.register(list[int] | str, lambda arg: "types.UnionTypes(types.GenericAlias)") | ||
with self.assertRaisesRegex(TypeError, "Invalid first argument to "): | ||
f.register(typing.List[float] | bytes, lambda arg: "typing.Union[typing.GenericAlias]") | ||
with self.assertRaisesRegex(TypeError, "Invalid first argument to "): | ||
f.register(typing.Any, lambda arg: "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. This might be worth forbidding explicitly because the behavior could be quite unintuitive. Happy to leave that decision to the functools maintainer though. 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. @ambv, do you have any thoughts on the bits of this PR that touch |
||
|
||
self.assertEqual(f([1]), "default") | ||
self.assertEqual(f([1.0]), "default") | ||
|
@@ -2823,8 +2821,6 @@ def f(arg): | |
f.register(list[int] | str) | ||
with self.assertRaisesRegex(TypeError, "Invalid first argument to "): | ||
f.register(typing.List[int] | str) | ||
with self.assertRaisesRegex(TypeError, "Invalid first argument to "): | ||
f.register(typing.Any) | ||
|
||
def test_register_genericalias_annotation(self): | ||
@functools.singledispatch | ||
|
@@ -2847,10 +2843,6 @@ def _(arg: list[int] | str): | |
@f.register | ||
def _(arg: typing.List[float] | bytes): | ||
return "typing.Union[typing.GenericAlias]" | ||
with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"): | ||
@f.register | ||
def _(arg: typing.Any): | ||
return "typing.Any" | ||
|
||
self.assertEqual(f([1]), "default") | ||
self.assertEqual(f([1.0]), "default") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -429,8 +429,17 @@ def __getitem__(self, parameters): | |
return self._getitem(self, *parameters) | ||
|
||
|
||
@_SpecialForm | ||
def Any(self, parameters): | ||
class _AnyMeta(type): | ||
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 metaclass is unfortunate because it restricts what classes can double-inherit from Any (due to metaclass conflicts). Seems unavoidable though. 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. Not entirely unavoidable, if we were willing to give up on instancecheck (and repr), I'd say we could just remove the metaclass entirely |
||
def __instancecheck__(self, obj): | ||
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. Should we even have this? 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 fine with removing it (as this PR currently does for My reasoning for keeping it is that |
||
if self is Any: | ||
raise TypeError("typing.Any cannot be used with isinstance()") | ||
return super().__instancecheck__(obj) | ||
|
||
def __repr__(self): | ||
JelleZijlstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return "typing.Any" | ||
|
||
|
||
class Any(metaclass=_AnyMeta): | ||
"""Special type indicating an unconstrained type. | ||
|
||
- Any is compatible with every type. | ||
|
@@ -439,9 +448,13 @@ def Any(self, parameters): | |
|
||
Note that all the above statements are true from the point of view of | ||
static type checkers. At runtime, Any should not be used with instance | ||
or class checks. | ||
checks. | ||
""" | ||
raise TypeError(f"{self} is not subscriptable") | ||
def __new__(cls, *args, **kwargs): | ||
if cls is Any: | ||
raise TypeError("Any cannot be instantiated") | ||
return super().__new__(cls, *args, **kwargs) | ||
|
||
|
||
@_SpecialForm | ||
def NoReturn(self, parameters): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Allow subclassing of :class:`typing.Any`. Patch by Shantanu Jain. |
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.
Can you add some explanation about the use cases?
This doesn’t say why someone could want that, nor does the ticket, one has to hunt for the last message in the mailing list thread!
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 added a sentence here. Let me know if I should make it longer; I tried to keep it short because this is a lot more niche than other things covered in typing.rst
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 adding one short example might be nice
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.
Not sure about this. On the one hand an example would be useful; on the other hand it risks putting too much emphasis on a pretty obscure use case.
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.
Let's omit the example then (devguide says "err on the side of being succinct" for docs). I'm hoping to do some work on typing docs sometime soon, which might be a better home for such details.
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.
Alrighty!