Skip to content

Commit

Permalink
Add support for PEP 560. (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
ilevkivskyi authored and benjaminp committed Nov 5, 2019
1 parent aa4e90b commit ebb0db5
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion six.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
48 changes: 48 additions & 0 deletions test_six.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import sys
import types
import unittest
import abc

import py

Expand Down Expand Up @@ -744,6 +745,53 @@ class Y(six.with_metaclass(MetaSub, X)):
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."""
Expand Down

0 comments on commit ebb0db5

Please sign in to comment.