# HG changeset patch -- Bitbucket.org
# Project pylib
# URL http://bitbucket.org/hpk42/pylib/overview
# User holger krekel <hol...@merlinux.eu>
# Date 1289635306 -3600
# Node ID 1371dfb06957338aef2066da0af04888f7e2af55
# Parent  4ce4019bb0a929796cacb251eb1505001cdaacee
use new apipkg with aliasmodule support

--- a/py/_apipkg.py
+++ b/py/_apipkg.py
@@ -9,11 +9,11 @@ import os
 import sys
 from types import ModuleType
 
-__version__ = "1.1"
+__version__ = '1.2.dev5'
 
 def initpkg(pkgname, exportdefs, attr=dict()):
     """ initialize given package from the export definitions. """
-    oldmod = sys.modules[pkgname]
+    oldmod = sys.modules.get(pkgname)
     d = {}
     f = getattr(oldmod, '__file__', None)
     if f:
@@ -25,10 +25,11 @@ def initpkg(pkgname, exportdefs, attr=di
         d['__loader__'] = oldmod.__loader__
     if hasattr(oldmod, '__path__'):
         d['__path__'] = [os.path.abspath(p) for p in oldmod.__path__]
-    if hasattr(oldmod, '__doc__'):
+    if '__doc__' not in exportdefs and getattr(oldmod, '__doc__', None):
         d['__doc__'] = oldmod.__doc__
     d.update(attr)
-    oldmod.__dict__.update(d)
+    if hasattr(oldmod, "__dict__"):
+        oldmod.__dict__.update(d)
     mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d)
     sys.modules[pkgname]  = mod
 
@@ -44,6 +45,16 @@ def importobj(modpath, attrname):
     return retval
 
 class ApiModule(ModuleType):
+    def __docget(self):
+        try:
+            return self.__doc
+        except AttributeError:
+            if '__doc__' in self.__map__:
+                return self.__makeattr('__doc__')
+    def __docset(self, value):
+        self.__doc = value
+    __doc__ = property(__docget, __docset)
+
     def __init__(self, name, importspec, implprefix=None, attr=None):
         self.__name__ = name
         self.__all__ = [x for x in importspec if x != '__onfirstaccess__']
@@ -65,8 +76,13 @@ class ApiModule(ModuleType):
                 attrname = parts and parts[0] or ""
                 if modpath[0] == '.':
                     modpath = implprefix + modpath
-                if name == '__doc__':
-                    self.__doc__ = importobj(modpath, attrname)
+
+                if not attrname:
+                    subname = '%s.%s'%(self.__name__, name)
+                    apimod = AliasModule(subname, modpath)
+                    sys.modules[subname] = apimod
+                    if '.' not in name:
+                        setattr(self, name, apimod)
                 else:
                     self.__map__[name] = (modpath, attrname)
 
@@ -118,3 +134,28 @@ class ApiModule(ModuleType):
                     pass
         return dict
     __dict__ = property(__dict__)
+
+
+def AliasModule(modname, modpath):
+    mod = []
+
+    def getmod():
+        if not mod:
+            mod.append(importobj(modpath, None))
+        return mod[0]
+
+    class AliasModule(ModuleType):
+
+        def __repr__(self):
+            return '<AliasModule %r for %r>' % (modname, modpath)
+
+        def __getattribute__(self, name):
+            return getattr(getmod(), name)
+
+        def __setattr__(self, name, value):
+            setattr(getmod(), name, value)
+
+        def __delattr__(self, name):
+            delattr(getmod(), name)
+
+    return AliasModule(modname)

--- a/setup.py
+++ b/setup.py
@@ -30,7 +30,7 @@ def main():
         long_description = long_description,
         install_requires=['py>=1.3.9', ], # force newer py version which 
removes 'py' namespace
         #                                  # so we can occupy it
-        version='2.0.0.dev6',
+        version='2.0.0.dev7',
         url='http://pylib.org',
         license='MIT license',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

--- a/testing/test_apipkg.py
+++ b/testing/test_apipkg.py
@@ -1,7 +1,7 @@
 import types
 import sys
 import py
-from py import apipkg
+import py._apipkg as apipkg
 import subprocess
 #
 # test support for importing modules
@@ -16,7 +16,7 @@ class TestRealModule:
 
         tfile = pkgdir.join('__init__.py')
         tfile.write(py.code.Source("""
-            from py import apipkg
+            import py._apipkg as apipkg
             apipkg.initpkg(__name__, {
                 'x': {
                     'module': {
@@ -89,7 +89,7 @@ class TestScenarios:
     def test_relative_import(self, monkeypatch, tmpdir):
         pkgdir = tmpdir.mkdir("mymodule")
         pkgdir.join('__init__.py').write(py.code.Source("""
-            from py import apipkg
+            import py._apipkg as apipkg
             apipkg.initpkg(__name__, exportdefs={
                 '__doc__': '.submod:maindoc',
                 'x': '.submod:x',
@@ -109,32 +109,45 @@ class TestScenarios:
     def test_recursive_import(self, monkeypatch, tmpdir):
         pkgdir = tmpdir.mkdir("recmodule")
         pkgdir.join('__init__.py').write(py.code.Source("""
-            from py import apipkg
+            import py._apipkg as apipkg
             apipkg.initpkg(__name__, exportdefs={
                 'some': '.submod:someclass',
             })
         """))
         pkgdir.join('submod.py').write(py.code.Source("""
-            import recmodule 
+            import recmodule
             class someclass: pass
             print (recmodule.__dict__)
         """))
         monkeypatch.syspath_prepend(tmpdir)
-        import recmodule 
+        import recmodule
         assert isinstance(recmodule, apipkg.ApiModule)
         assert recmodule.some.__name__ == "someclass"
 
     def test_module_alias_import(self, monkeypatch, tmpdir):
         pkgdir = tmpdir.mkdir("aliasimport")
         pkgdir.join('__init__.py').write(py.code.Source("""
-            from py import apipkg
+            import py._apipkg as apipkg
             apipkg.initpkg(__name__, exportdefs={
                 'some': 'os.path',
             })
         """))
         monkeypatch.syspath_prepend(tmpdir)
         import aliasimport
-        assert aliasimport.some is py.std.os.path
+        for k, v in py.std.os.path.__dict__.items():
+            assert getattr(aliasimport.some, k) == v
+
+    def test_from_module_alias_import(self, monkeypatch, tmpdir):
+        pkgdir = tmpdir.mkdir("fromaliasimport")
+        pkgdir.join('__init__.py').write(py.code.Source("""
+            import py._apipkg as apipkg
+            apipkg.initpkg(__name__, exportdefs={
+                'some': 'os.path',
+            })
+        """))
+        monkeypatch.syspath_prepend(tmpdir)
+        from fromaliasimport.some import join
+        assert join is py.std.os.path.join
 
 def xtest_nested_absolute_imports():
     import email
@@ -211,14 +224,22 @@ def test_initpkg_transfers_attrs(monkeyp
     assert newmod.__loader__ == mod.__loader__
     assert newmod.__doc__ == mod.__doc__
 
-def test_initpkg_not_overwrite_exportdefs(monkeypatch):
+def test_initpkg_nodoc(monkeypatch):
     mod = type(sys)('hello')
-    mod.__doc__ = "this is the documentation"
+    mod.__file__ = "hello.py"
     monkeypatch.setitem(sys.modules, 'hello', mod)
+    apipkg.initpkg('hello', {})
+    newmod = sys.modules['hello']
+    assert not newmod.__doc__
+
+def test_initpkg_overwrite_doc(monkeypatch):
+    hello = type(sys)('hello')
+    hello.__doc__ = "this is the documentation"
+    monkeypatch.setitem(sys.modules, 'hello', hello)
     apipkg.initpkg('hello', {"__doc__": "sys:__doc__"})
-    newmod = sys.modules['hello']
-    assert newmod != mod
-    assert newmod.__doc__ == sys.__doc__
+    newhello = sys.modules['hello']
+    assert newhello != hello
+    assert newhello.__doc__ == sys.__doc__
 
 def test_initpkg_not_transfers_not_existing_attrs(monkeypatch):
     mod = type(sys)('hello')
@@ -249,7 +270,7 @@ def test_name_attribute():
 def test_error_loading_one_element(monkeypatch, tmpdir):
     pkgdir = tmpdir.mkdir("errorloading1")
     pkgdir.join('__init__.py').write(py.code.Source("""
-        from py import apipkg
+        import py._apipkg as apipkg
         apipkg.initpkg(__name__, exportdefs={
             'x': '.notexists:x',
             'y': '.submod:y'
@@ -267,7 +288,7 @@ def test_error_loading_one_element(monke
 def test_onfirstaccess(tmpdir, monkeypatch):
     pkgdir = tmpdir.mkdir("firstaccess")
     pkgdir.join('__init__.py').write(py.code.Source("""
-        from py import apipkg
+        import py._apipkg as apipkg
         apipkg.initpkg(__name__, exportdefs={
             '__onfirstaccess__': '.submod:init',
             'l': '.submod:l',
@@ -276,7 +297,7 @@ def test_onfirstaccess(tmpdir, monkeypat
     """))
     pkgdir.join('submod.py').write(py.code.Source("""
         l = []
-        def init(): 
+        def init():
             l.append(1)
     """))
     monkeypatch.syspath_prepend(tmpdir)
@@ -288,19 +309,19 @@ def test_onfirstaccess(tmpdir, monkeypat
 
 @py.test.mark.multi(mode=['attr', 'dict', 'onfirst'])
 def test_onfirstaccess_setsnewattr(tmpdir, monkeypatch, mode):
-    pkgname = 'mode_' + mode
+    pkgname = tmpdir.basename.replace("-", "")
     pkgdir = tmpdir.mkdir(pkgname)
     pkgdir.join('__init__.py').write(py.code.Source("""
-        from py import apipkg
+        import py._apipkg as apipkg
         apipkg.initpkg(__name__, exportdefs={
             '__onfirstaccess__': '.submod:init',
             },
         )
     """))
     pkgdir.join('submod.py').write(py.code.Source("""
-        def init(): 
+        def init():
             import %s as pkg
-            pkg.newattr = 42 
+            pkg.newattr = 42
     """ % pkgname))
     monkeypatch.syspath_prepend(tmpdir)
     mod = __import__(pkgname)
@@ -329,12 +350,11 @@ def test_bpython_getattr_override(tmpdir
 
 
 def test_chdir_with_relative_imports_shouldnt_break_lazy_loading(tmpdir):
-    from py import _apipkg  # cause py.apipkg is a apimodule
-    tmpdir.join('apipkg.py').write(py.code.Source(_apipkg))
+    tmpdir.join('apipkg.py').write(py.code.Source(apipkg))
     pkg = tmpdir.mkdir('pkg')
     messy = tmpdir.mkdir('messy')
     pkg.join('__init__.py').write(py.code.Source("""
-        import apipkg
+        import py._apipkg as apipkg
         apipkg.initpkg(__name__, {
             'test': '.sub:test',
         })
@@ -365,7 +385,7 @@ def test_chdir_with_relative_imports_sho
 def test_dotted_name_lookup(tmpdir, monkeypatch):
     pkgdir = tmpdir.mkdir("dotted_name_lookup")
     pkgdir.join('__init__.py').write(py.code.Source("""
-        from py import apipkg
+        import py._apipkg as apipkg
         apipkg.initpkg(__name__, dict(abs='os:path.abspath'))
     """))
     monkeypatch.syspath_prepend(tmpdir)
@@ -375,9 +395,76 @@ def test_dotted_name_lookup(tmpdir, monk
 def test_extra_attributes(tmpdir, monkeypatch):
     pkgdir = tmpdir.mkdir("extra_attributes")
     pkgdir.join('__init__.py').write(py.code.Source("""
-        from py import apipkg
+        import py._apipkg as apipkg
         apipkg.initpkg(__name__, dict(abs='os:path.abspath'), dict(foo='bar'))
     """))
     monkeypatch.syspath_prepend(tmpdir)
     import extra_attributes
     assert extra_attributes.foo == 'bar'
+
+def test_aliasmodule_repr():
+    am = apipkg.AliasModule("mymod", "sys")
+    r = repr(am)
+    assert "<AliasModule 'mymod' for 'sys'>" == r
+    am.version
+    assert repr(am) == r
+
+def test_aliasmodule_proxy_methods(tmpdir, monkeypatch):
+    pkgdir = tmpdir
+    pkgdir.join('aliasmodule_proxy.py').write(py.code.Source("""
+        def doit():
+            return 42
+    """))
+
+    pkgdir.join('my_aliasmodule_proxy.py').write(py.code.Source("""
+        import py._apipkg as apipkg
+        apipkg.initpkg(__name__, dict(proxy='aliasmodule_proxy'))
+
+        def doit():
+            return 42
+    """))
+
+    monkeypatch.syspath_prepend(tmpdir)
+    import aliasmodule_proxy as orig
+    from my_aliasmodule_proxy import proxy
+
+    doit = proxy.doit
+    assert doit is orig.doit
+
+    del proxy.doit
+    py.test.raises(AttributeError, "orig.doit")
+
+    proxy.doit = doit
+    assert orig.doit is doit
+
+def test_aliasmodule_nested_import_with_from(tmpdir, monkeypatch):
+    import os
+    pkgdir = tmpdir.mkdir("api1")
+    pkgdir.ensure("__init__.py").write(py.std.textwrap.dedent("""
+        import py._apipkg as apipkg
+        apipkg.initpkg(__name__, {
+            'os2': 'api2',
+            'os2.path': 'api2.path2',
+            })
+    """))
+    tmpdir.join("api2.py").write(py.std.textwrap.dedent("""
+        import os, sys
+        from os import path
+        sys.modules['api2.path2'] = path
+        x = 3
+    """))
+    monkeypatch.syspath_prepend(tmpdir)
+    from api1 import os2
+    from api1.os2.path import abspath
+    assert abspath == os.path.abspath
+    # check that api1.os2 mirrors os.*
+    assert os2.x == 3
+    import api1
+    assert 'os2.path' not in api1.__dict__
+
+
+def test_initpkg_without_old_module():
+    apipkg.initpkg("initpkg_without_old_module",
+                   dict(modules="sys:modules"))
+    from initpkg_without_old_module import modules
+    assert modules is sys.modules

--- a/py/__init__.py
+++ b/py/__init__.py
@@ -8,40 +8,44 @@ dictionary or an import path.
 
 (c) Holger Krekel and others, 2004-2010
 """
-__version__ = '2.0.0.dev6'
+__version__ = '2.0.0.dev7'
 
 from py import _apipkg
 
-_apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs=dict(
+_apipkg.initpkg(__name__, attr={'_apipkg': _apipkg}, exportdefs={
     # access to all standard lib modules
-    std = '._std:std',
+    'std': '._std:std',
     # access to all posix errno's as classes
-    error = '._error:error',
+    'error': '._error:error',
 
-    _pydir = '.__metainfo:pydir',
-    version = 'py:__version__', # backward compatibility
+    '_pydir' : '.__metainfo:pydir',
+    'version': 'py:__version__', # backward compatibility
 
-    test = 'pytest', # defer to pytest package
+    # pytest-2.0 has a flat namespace, we use alias modules
+    # to keep old references compatible
+    'test' : 'pytest',
+    'test.collect' : 'pytest',
+    'test.cmdline' : 'pytest',
 
     # hook into the top-level standard library
-    process = {
+    'process' : {
         '__doc__'        : '._process:__doc__',
         'cmdexec'        : '._process.cmdexec:cmdexec',
         'kill'           : '._process.killproc:kill',
         'ForkedFunc'     : '._process.forkedfunc:ForkedFunc',
     },
 
-    apipkg = {
+    'apipkg' : {
         'initpkg'   : '._apipkg:initpkg',
         'ApiModule' : '._apipkg:ApiModule',
     },
 
-    iniconfig = {
+    'iniconfig' : {
         'IniConfig'      : '._iniconfig:IniConfig',
         'ParseError'     : '._iniconfig:ParseError',
     },
 
-    path = {
+    'path' : {
         '__doc__'        : '._path:__doc__',
         'svnwc'          : '._path.svnwc:SvnWCCommandPath',
         'svnurl'         : '._path.svnurl:SvnCommandPath',
@@ -50,7 +54,7 @@ _apipkg.initpkg(__name__, attr={'_apipkg
     },
 
     # python inspection/code-generation API
-    code = {
+    'code' : {
         '__doc__'           : '._code:__doc__',
         'compile'           : '._code.source:compile_',
         'Source'            : '._code.source:Source',
@@ -69,7 +73,7 @@ _apipkg.initpkg(__name__, attr={'_apipkg
     },
 
     # backports and additions of builtins
-    builtin = {
+    'builtin' : {
         '__doc__'        : '._builtin:__doc__',
         'enumerate'      : '._builtin:enumerate',
         'reversed'       : '._builtin:reversed',
@@ -98,7 +102,7 @@ _apipkg.initpkg(__name__, attr={'_apipkg
     },
 
     # input-output helping
-    io = {
+    'io' : {
         '__doc__'             : '._io:__doc__',
         'dupfile'             : '._io.capture:dupfile',
         'TextIO'              : '._io.capture:TextIO',
@@ -113,7 +117,7 @@ _apipkg.initpkg(__name__, attr={'_apipkg
     },
 
     # small and mean xml/html generation
-    xml = {
+    'xml' : {
         '__doc__'            : '._xmlgen:__doc__',
         'html'               : '._xmlgen:html',
         'Tag'                : '._xmlgen:Tag',
@@ -122,7 +126,7 @@ _apipkg.initpkg(__name__, attr={'_apipkg
         'escape'             : '._xmlgen:escape',
     },
 
-    log = {
+    'log' : {
         # logging API ('producers' and 'consumers' connected via keywords)
         '__doc__'            : '._log:__doc__',
         '_apiwarn'           : '._log.warning:_apiwarn',
@@ -137,11 +141,11 @@ _apipkg.initpkg(__name__, attr={'_apipkg
     },
 
     # compatibility modules (deprecated)
-    compat = {
+    'compat' : {
         '__doc__'         : '._compat:__doc__',
         'doctest'         : '._compat.dep_doctest:doctest',
         'optparse'        : '._compat.dep_optparse:optparse',
         'textwrap'        : '._compat.dep_textwrap:textwrap',
         'subprocess'      : '._compat.dep_subprocess:subprocess',
     },
-))
+})
_______________________________________________
py-svn mailing list
py-svn@codespeak.net
http://codespeak.net/mailman/listinfo/py-svn

Reply via email to