[pypy-commit] pypy default: A first version of import_from_mixin(), which really copies the
arigo
noreply at buildbot.pypy.org
Tue Aug 20 13:49:21 CEST 2013
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r66252:51c5cb0ddc92
Date: 2013-08-20 13:48 +0200
http://bitbucket.org/pypy/pypy/changeset/51c5cb0ddc92/
Log: A first version of import_from_mixin(), which really copies the
content of the source class into the target, completely before
translation.
diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -2539,6 +2539,27 @@
s = a.build_types(f, [])
assert s.const == 2
+ def test_import_from_mixin(self):
+ class M(object):
+ def f(self):
+ return self.a
+ class I(object):
+ objectmodel.import_from_mixin(M)
+ def __init__(self, i):
+ self.a = i
+ class S(object):
+ objectmodel.import_from_mixin(M)
+ def __init__(self, s):
+ self.a = s
+ def f(n):
+ return (I(n).f(), S("a" * n).f())
+
+ assert f(3) == (3, "aaa")
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert isinstance(s.items[0], annmodel.SomeInteger)
+ assert isinstance(s.items[1], annmodel.SomeString)
+
def test___class___attribute(self):
class Base(object): pass
class A(Base): pass
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -9,7 +9,7 @@
import types
import math
import inspect
-from rpython.tool.sourcetools import rpython_wrapper
+from rpython.tool.sourcetools import rpython_wrapper, func_with_new_name
# specialize is a decorator factory for attaching _annspecialcase_
# attributes to functions: for example
@@ -720,3 +720,32 @@
self.dic = dic
self.key = key
self.hash = hash
+
+# ____________________________________________________________
+
+def import_from_mixin(M):
+ flatten = {}
+ for base in inspect.getmro(M):
+ for key, value in base.__dict__.items():
+ if key in ('__module__', '__name__', '__dict__',
+ '__doc__', '__weakref__'):
+ continue
+ if key in flatten:
+ continue
+ if isinstance(value, types.FunctionType):
+ value = func_with_new_name(value, value.__name__)
+ elif isinstance(value, staticmethod):
+ func = value.__get__(42)
+ func = func_with_new_name(func, func.__name__)
+ value = staticmethod(func)
+ elif isinstance(value, classmethod):
+ raise AssertionError("classmethods not supported "
+ "in 'import_from_mixin'")
+ flatten[key] = value
+ #
+ target = sys._getframe(1).f_locals
+ for key, value in flatten.items():
+ if key in target:
+ raise Exception("import_from_mixin: would overwrite the value "
+ "already defined locally for %r" % (key,))
+ target[key] = value
diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py
--- a/rpython/rlib/test/test_objectmodel.py
+++ b/rpython/rlib/test/test_objectmodel.py
@@ -548,3 +548,57 @@
r = interpret(f, [29])
assert r == 1
+
+def test_import_from_mixin():
+ class M: # old-style
+ def f(self): pass
+ class A: # old-style
+ import_from_mixin(M)
+ assert A.f.im_func is not M.f.im_func
+
+ class M(object):
+ def f(self): pass
+ class A: # old-style
+ import_from_mixin(M)
+ assert A.f.im_func is not M.f.im_func
+
+ class M: # old-style
+ def f(self): pass
+ class A(object):
+ import_from_mixin(M)
+ assert A.f.im_func is not M.f.im_func
+
+ class M(object):
+ def f(self): pass
+ class A(object):
+ import_from_mixin(M)
+ assert A.f.im_func is not M.f.im_func
+
+ class MBase(object):
+ a = 42; b = 43; c = 1000
+ def f(self): return "hi"
+ def g(self): return self.c - 1
+ class M(MBase):
+ a = 84
+ def f(self): return "there"
+ class A(object):
+ import_from_mixin(M)
+ c = 88
+ assert A.f.im_func is not M.f.im_func
+ assert A.f.im_func is not MBase.f.im_func
+ assert A.g.im_func is not MBase.g.im_func
+ assert A().f() == "there"
+ assert A.a == 84
+ assert A.b == 43
+ assert A.c == 88
+ assert A().g() == 87
+
+ try:
+ class B(object):
+ a = 63
+ import_from_mixin(M)
+ except Exception, e:
+ assert ("would overwrite the value already defined locally for 'a'"
+ in str(e))
+ else:
+ raise AssertionError("failed to detect overwritten attribute")
More information about the pypy-commit
mailing list