-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-89263: Add typing.get_overloads #31716
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
Changes from 30 commits
2ee377d
831b565
f03f8a9
404668a
7a5b0d1
6998255
26bb908
f52b757
fc6a925
b524244
e95558e
31fd72d
7041ad3
e26b0db
1bf89fb
83ac432
dfdbdc7
e16c8d0
b3d2227
9727eee
2e374b8
ff03b12
17f0710
2346970
f2053a0
b6131ad
506bd66
e9a2100
2b1a5cc
103bfd4
d453f7f
450afeb
ea62287
905253c
debbf8a
754c134
1ad8224
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 |
---|---|---|
@@ -1,15 +1,18 @@ | ||
import contextlib | ||
import collections | ||
from collections import defaultdict | ||
from functools import lru_cache | ||
import inspect | ||
import pickle | ||
import re | ||
import sys | ||
import warnings | ||
from unittest import TestCase, main, skipUnless, skip | ||
from unittest.mock import patch | ||
from copy import copy, deepcopy | ||
|
||
from typing import Any, NoReturn, Never, assert_never | ||
from typing import overload, get_overloads, clear_overloads | ||
from typing import TypeVar, TypeVarTuple, Unpack, AnyStr | ||
from typing import T, KT, VT # Not in __all__. | ||
from typing import Union, Optional, Literal | ||
|
@@ -3850,11 +3853,22 @@ def test_or(self): | |
self.assertEqual("x" | X, Union["x", X]) | ||
|
||
|
||
@lru_cache() | ||
def cached_func(x, y): | ||
return 3 * x + y | ||
|
||
|
||
class MethodHolder: | ||
@classmethod | ||
def clsmethod(cls): ... | ||
@staticmethod | ||
def stmethod(): ... | ||
def method(self): ... | ||
|
||
|
||
class OverloadTests(BaseTestCase): | ||
|
||
def test_overload_fails(self): | ||
from typing import overload | ||
|
||
with self.assertRaises(RuntimeError): | ||
|
||
@overload | ||
|
@@ -3864,8 +3878,6 @@ def blah(): | |
blah() | ||
|
||
def test_overload_succeeds(self): | ||
from typing import overload | ||
|
||
@overload | ||
def blah(): | ||
pass | ||
|
@@ -3875,6 +3887,52 @@ def blah(): | |
|
||
blah() | ||
|
||
def set_up_overloads(self): | ||
def blah(): | ||
pass | ||
|
||
overload1 = blah | ||
overload(blah) | ||
|
||
def blah(): | ||
pass | ||
|
||
overload2 = blah | ||
overload(blah) | ||
|
||
def blah(): | ||
pass | ||
|
||
return blah, [overload1, overload2] | ||
|
||
# Make sure we don't clear the global overload registry | ||
@patch("typing._overload_registry", | ||
defaultdict(lambda: defaultdict(dict))) | ||
def test_overload_registry(self): | ||
JelleZijlstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertEqual(len(typing._overload_registry), 0) | ||
|
||
impl, overloads = self.set_up_overloads() | ||
self.assertNotEqual(typing._overload_registry, {}) | ||
self.assertEqual(list(get_overloads(impl)), overloads) | ||
|
||
clear_overloads(impl) | ||
self.assertEqual(typing._overload_registry, {}) | ||
self.assertEqual(get_overloads(impl), []) | ||
|
||
impl, overloads = self.set_up_overloads() | ||
self.assertNotEqual(typing._overload_registry, {}) | ||
self.assertEqual(list(get_overloads(impl)), overloads) | ||
|
||
clear_overloads() | ||
self.assertEqual(typing._overload_registry, {}) | ||
self.assertEqual(get_overloads(impl), []) | ||
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. Can you add a comment explaining why this sequence is repeated? 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. Done. Also added a test case to make sure that clearing one function's overloads doesn't clear another. Thinking out loud, clear_overloads() is becoming the most complicated part of this. Perhaps we don't need to support clearing overloads per function, which would simplify it greatly. Use cases I can think of are:
So maybe we should only support clearing the whole overload registry at once. Can you think of other realistic reasons people may want to use clear_overloads()? 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. Hm. Given the reload(module) use case, maybe the only options should be clear all or clear a specific module? The new data structure makes that easy. The question would then be whether the argument should be the (full) module name or the module object? (Or either?) The sequence of events would be something like typing.clear_overload(mod)
importlib.reload(mod) I can't really think of a use case for clearing a specific function. Did you have one in mind originally? Or was it just convenient for testing? 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 for now we should allow only clearing the whole registry. I see the use case for wanting to repeatedly reload modules while wanting to introspect overloads, but it seems unlikely to be common. We can always add an argument later to clear overloads by module if someone asks for it, but once we add it we're stuck with it. |
||
|
||
def test_overload_registry_repeated(self): | ||
for _ in range(2): | ||
impl, overloads = self.set_up_overloads() | ||
|
||
self.assertEqual(list(get_overloads(impl)), overloads) | ||
|
||
|
||
# Definitions needed for features introduced in Python 3.6 | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Add :func:`typing.get_overloads` and :func:`typing.clear_overloads`. | ||
Patch by Jelle Zijlstra. |
Uh oh!
There was an error while loading. Please reload this page.