diff options
author | Ivan Levkivskyi <levkivskyi@gmail.com> | 2019-11-05 02:32:36 +0000 |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2019-11-04 18:32:36 -0800 |
commit | ebb0db59f8cc221209876307d069c7c204fbb69a (patch) | |
tree | 56896eda30a7233feb96e374c2ee88ceac3975a1 | |
parent | aa4e90bcd7b7bc13a71dfaebcb2021f4caaa8432 (diff) | |
download | six-git-ebb0db59f8cc221209876307d069c7c204fbb69a.tar.gz |
Add support for PEP 560. (#305)
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | six.py | 10 | ||||
-rw-r--r-- | test_six.py | 48 |
3 files changed, 58 insertions, 2 deletions
diff --git a/.travis.yml b/.travis.yml index 53803b1..3425ecc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ install: - pip install --upgrade --force-reinstall "setuptools; python_version != '3.2' and python_version != '3.3'" "setuptools < 30; python_version == '3.2'" "setuptools < 40; python_version == '3.3'" - pip uninstall --yes six || true - pip install --upgrade --force-reinstall --ignore-installed -e . -- pip install pytest +- pip install pytest typing - &py_pkg_list pip list --format=columns || pip list script: - py.test @@ -825,7 +825,15 @@ def with_metaclass(meta, *bases): class metaclass(type): def __new__(cls, name, this_bases, d): - return meta(name, bases, d) + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d['__orig_bases__'] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) @classmethod def __prepare__(cls, name, this_bases): diff --git a/test_six.py b/test_six.py index 4808399..d175683 100644 --- a/test_six.py +++ b/test_six.py @@ -22,6 +22,7 @@ import operator import sys import types import unittest +import abc import py @@ -744,6 +745,53 @@ def test_with_metaclass(): assert Y.__mro__ == (Y, X, object) +@py.test.mark.skipif("sys.version_info[:2] < (2, 7)") +def test_with_metaclass_typing(): + try: + import typing + except ImportError: + py.test.skip("typing module required") + class Meta(type): + pass + if sys.version_info[:2] < (3, 7): + # Generics with custom metaclasses were broken on older versions. + class Meta(Meta, typing.GenericMeta): + pass + T = typing.TypeVar('T') + class G(six.with_metaclass(Meta, typing.Generic[T])): + pass + class GA(six.with_metaclass(abc.ABCMeta, typing.Generic[T])): + pass + assert isinstance(G, Meta) + assert isinstance(GA, abc.ABCMeta) + assert G[int] is not G[G[int]] + assert GA[int] is not GA[GA[int]] + assert G.__bases__ == (typing.Generic,) + assert G.__orig_bases__ == (typing.Generic[T],) + + +@py.test.mark.skipif("sys.version_info[:2] < (3, 7)") +def test_with_metaclass_pep_560(): + class Meta(type): + pass + class A: + pass + class B: + pass + class Fake: + def __mro_entries__(self, bases): + return (A, B) + fake = Fake() + class G(six.with_metaclass(Meta, fake)): + pass + class GA(six.with_metaclass(abc.ABCMeta, fake)): + pass + assert isinstance(G, Meta) + assert isinstance(GA, abc.ABCMeta) + assert G.__bases__ == (A, B) + assert G.__orig_bases__ == (fake,) + + @py.test.mark.skipif("sys.version_info[:2] < (3, 0)") def test_with_metaclass_prepare(): """Test that with_metaclass causes Meta.__prepare__ to be called with the correct arguments.""" |