summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Levkivskyi <levkivskyi@gmail.com>2019-11-05 02:32:36 +0000
committerBenjamin Peterson <benjamin@python.org>2019-11-04 18:32:36 -0800
commitebb0db59f8cc221209876307d069c7c204fbb69a (patch)
tree56896eda30a7233feb96e374c2ee88ceac3975a1
parentaa4e90bcd7b7bc13a71dfaebcb2021f4caaa8432 (diff)
downloadsix-git-ebb0db59f8cc221209876307d069c7c204fbb69a.tar.gz
Add support for PEP 560. (#305)
-rw-r--r--.travis.yml2
-rw-r--r--six.py10
-rw-r--r--test_six.py48
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
diff --git a/six.py b/six.py
index 4c303ff..c09609b 100644
--- a/six.py
+++ b/six.py
@@ -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."""