diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-03-01 18:01:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-01 18:01:27 (GMT) |
commit | 90f75e1069f2d692480bcd305fc35b4fe7847e18 (patch) | |
tree | 7699f462cf551869091f80c8a2e5a7c26516607b /Lib/typing.py | |
parent | 16be4a3b93ca315d6d95a5e5dd17c81d03ed578a (diff) | |
download | cpython-90f75e1069f2d692480bcd305fc35b4fe7847e18.zip cpython-90f75e1069f2d692480bcd305fc35b4fe7847e18.tar.gz cpython-90f75e1069f2d692480bcd305fc35b4fe7847e18.tar.bz2 |
[3.12] gh-112281: Allow `Union` with unhashable `Annotated` metadata (GH-112283) (#116213)
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Diffstat (limited to 'Lib/typing.py')
-rw-r--r-- | Lib/typing.py | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/Lib/typing.py b/Lib/typing.py index 1e4c725..7581c16 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -314,19 +314,33 @@ def _unpack_args(args): newargs.append(arg) return newargs -def _deduplicate(params): +def _deduplicate(params, *, unhashable_fallback=False): # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - return params - + try: + return dict.fromkeys(params) + except TypeError: + if not unhashable_fallback: + raise + # Happens for cases like `Annotated[dict, {'x': IntValidator()}]` + return _deduplicate_unhashable(params) + +def _deduplicate_unhashable(unhashable_params): + new_unhashable = [] + for t in unhashable_params: + if t not in new_unhashable: + new_unhashable.append(t) + return new_unhashable + +def _compare_args_orderless(first_args, second_args): + first_unhashable = _deduplicate_unhashable(first_args) + second_unhashable = _deduplicate_unhashable(second_args) + t = list(second_unhashable) + try: + for elem in first_unhashable: + t.remove(elem) + except ValueError: + return False + return not t def _remove_dups_flatten(parameters): """Internal helper for Union creation and substitution. @@ -341,7 +355,7 @@ def _remove_dups_flatten(parameters): else: params.append(p) - return tuple(_deduplicate(params)) + return tuple(_deduplicate(params, unhashable_fallback=True)) def _flatten_literal_params(parameters): @@ -1548,7 +1562,10 @@ class _UnionGenericAlias(_NotIterable, _GenericAlias, _root=True): def __eq__(self, other): if not isinstance(other, (_UnionGenericAlias, types.UnionType)): return NotImplemented - return set(self.__args__) == set(other.__args__) + try: # fast path + return set(self.__args__) == set(other.__args__) + except TypeError: # not hashable, slow path + return _compare_args_orderless(self.__args__, other.__args__) def __hash__(self): return hash(frozenset(self.__args__)) |