[py-svn] apipkg commit e630694050b2: refine and better test onfirstaccess handling

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Tue Dec 29 14:51:15 CET 2009


# HG changeset patch -- Bitbucket.org
# Project apipkg
# URL http://bitbucket.org/hpk42/apipkg/overview/
# User holger krekel <holger at merlinux.eu>
# Date 1262094649 -3600
# Node ID e630694050b26b2db57b46b2c68774af4c3b9e08
# Parent 47756aba150f1bd68aebc04364a9a44fe78ef524
refine and better test onfirstaccess handling

--- /dev/null
+++ b/conftest.py
@@ -0,0 +1,9 @@
+
+def pytest_generate_tests(metafunc):
+    multi = getattr(metafunc.function, 'multi', None)
+    if multi is None:
+        return
+    assert len(multi.kwargs) == 1
+    for name, l in multi.kwargs.items():
+        for val in l:
+            metafunc.addcall(funcargs={name: val})

--- a/apipkg.py
+++ b/apipkg.py
@@ -35,8 +35,6 @@ class ApiModule(ModuleType):
                 apimod = ApiModule(subname, importspec, implprefix)
                 sys.modules[subname] = apimod
                 setattr(self, name, apimod)
-            elif name == '__onfirstaccess__':
-                self.__map__[name] = importspec
             else:
                 modpath, attrname = importspec.split(':')
                 if modpath[0] == '.':
@@ -57,16 +55,17 @@ class ApiModule(ModuleType):
         return '<ApiModule %r>' % (self.__name__,)
 
     def __getattr__(self, name):
-        try:
-            func = self.__map__.pop('__onfirstaccess__')
-        except KeyError:
-            pass
-        else:
-            if func:
-                func()
+        target = None
+        if '__onfirstaccess__' in self.__map__:
+            target = self.__map__.pop('__onfirstaccess__')
+            importobj(*target)()
+            if name == "__onfirstaccess__":
+                return target
         try:
             modpath, attrname = self.__map__[name]
         except KeyError:
+            if target is not None: # retry, onfirstaccess might have set attrs
+                return getattr(self, name)
             raise AttributeError(name)
         else:
             result = importobj(modpath, attrname)

--- a/test_apipkg.py
+++ b/test_apipkg.py
@@ -209,30 +209,49 @@ def test_error_loading_one_element(monke
     py.test.raises(ImportError, 'errorloading1.x')
     py.test.raises(ImportError, 'errorloading1.x')
 
-def test_onfirstaccess(monkeypatch):
-    mod = type(sys)('hello')
-    monkeypatch.setitem(sys.modules, 'hello', mod)
-    l = []
-    apipkg.initpkg('hello', {
-        '__onfirstaccess__': lambda: l.append(1),
-        'world': 'sys:executable',
-        'world2': 'sys:executable',
-    })
-    hello = sys.modules['hello']
-    assert hello.world  == sys.executable
-    assert len(l) == 1
-    assert hello.world == sys.executable
-    assert len(l) == 1
+def test_onfirstaccess(tmpdir, monkeypatch):
+    pkgdir = tmpdir.mkdir("firstaccess")
+    pkgdir.join('__init__.py').write(py.code.Source("""
+        import apipkg
+        apipkg.initpkg(__name__, exportdefs={
+            '__onfirstaccess__': '.submod:init',
+            'l': '.submod:l',
+            },
+        )
+    """))
+    pkgdir.join('submod.py').write(py.code.Source("""
+        l = []
+        def init(): 
+            l.append(1)
+    """))
+    monkeypatch.syspath_prepend(tmpdir)
+    import firstaccess
+    assert isinstance(firstaccess, apipkg.ApiModule)
+    assert len(firstaccess.l) == 1
+    assert len(firstaccess.l) == 1
 
-def test_onfirstaccess__dict__(monkeypatch):
-    mod = type(sys)('hello')
-    monkeypatch.setitem(sys.modules, 'hello', mod)
-    l = []
-    apipkg.initpkg('hello', {
-        '__onfirstaccess__': lambda: l.append(1),
-    })
-    hello = sys.modules['hello']
-    hello.__dict__
-    assert len(l) == 1
-    hello.__dict__
-    assert len(l) == 1
+ at py.test.mark.multi(mode=['attr', 'dict'])
+def test_onfirstaccess_setsnewattr(tmpdir, monkeypatch, mode):
+    pkgname = tmpdir.basename.replace("-", "")
+    pkgdir = tmpdir.mkdir(pkgname)
+    pkgdir.join('__init__.py').write(py.code.Source("""
+        import apipkg
+        apipkg.initpkg(__name__, exportdefs={
+            '__onfirstaccess__': '.submod:init',
+            },
+        )
+    """))
+    pkgdir.join('submod.py').write(py.code.Source("""
+        def init(): 
+            import %s as pkg
+            pkg.newattr = 42 
+    """ % pkgname))
+    monkeypatch.syspath_prepend(tmpdir)
+    mod = __import__(pkgname)
+    assert isinstance(mod, apipkg.ApiModule)
+    if mode == 'attr':
+        assert mod.newattr == 42
+    elif mode == "dict":
+        print mod.__dict__.keys()
+        assert 'newattr' in mod.__dict__
+    assert '__onfirstaccess__' not in vars(mod)

--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,5 @@
 1.0.0b3 (compared to 1.0.0b2)
 ------------------------------------
 
-- added special attribute __onfirstaccess__ whose value will 
-  be called on the first attribute access to the apimodule
+- added special __onfirstaccess__ attribute whose value will 
+  be called on the first attribute access of an apimodule.



More information about the pytest-commit mailing list