diff options
author | Jordan Moldow <jmoldow@alum.mit.edu> | 2017-09-17 11:13:15 -0700 |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2017-09-17 11:13:15 -0700 |
commit | 96b93280fc4c70d65be0af5949f80f46f5c679ca (patch) | |
tree | 47543ef125bcf7f7b0bd3669b21e6cd9ed4ccac5 /six.py | |
parent | 024fcbb9c6f18a79b1e65f7bb9233c49cdd7fe88 (diff) | |
download | six-git-96b93280fc4c70d65be0af5949f80f46f5c679ca.tar.gz |
Define __prepare__() in with_metaclass() (#178)
Define `__prepare__()` in `with_metaclass()`'s temporary
metaclass, and make sure that it passes the correct bases to the
real metaclass's `__prepare__()`.
The temporary metaclass previously didn't extend the
`__prepare__()` method, which meant that if the real metaclass
had a `__prepare__()`, it wouldn't get called correctly. This
could lead to bugs in Python 3 code.
The temporary metaclass's `__prepare__()` gets called with
```bases=(temporary_class,)```. Since there was no proxy in the
middle, that was getting passed directly to the real metaclass's
`__prepare__()`. But then, if the real class's `__prepare__()`
method depended on the bases, the logic would be incorrect.
This was a problem in projects that use `enum` / `enum34` and
try to use `with_metaclass(EnumMeta)`. `enum34.EnumMeta` doesn't
define `__prepare__()`, since it is a Python 2 backport. Python
3's `enum.EnumMeta` does define `__prepare__()`, but originally
didn't depend at all on the bases. But starting in Python 3.6,
`enum.EnumMeta.__prepare__()` will raise `TypeError` if the
bases aren't valid for an enum subclass. Thus, a codebase that
was successfully using `enum` / `enum34` and
`with_metaclass(EnumMeta)` could break on Python 3.6.
Diffstat (limited to 'six.py')
-rw-r--r-- | six.py | 4 |
1 files changed, 4 insertions, 0 deletions
@@ -825,6 +825,10 @@ def with_metaclass(meta, *bases): def __new__(cls, name, this_bases, d): return meta(name, bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) return type.__new__(metaclass, 'temporary_class', (), {}) |