apipkg-1.0/0000755000175000017500000000000011455435255010764 5ustar hpkhpkapipkg-1.0/apipkg.egg-info/0000755000175000017500000000000011455435255013731 5ustar hpkhpkapipkg-1.0/apipkg.egg-info/SOURCES.txt0000644000175000017500000000027211455435255015616 0ustar hpkhpkCHANGELOG MANIFEST.in README.txt apipkg.py setup.py test_apipkg.py apipkg.egg-info/PKG-INFO apipkg.egg-info/SOURCES.txt apipkg.egg-info/dependency_links.txt apipkg.egg-info/top_level.txtapipkg-1.0/apipkg.egg-info/PKG-INFO0000644000175000017500000001013511455435255015026 0ustar hpkhpkMetadata-Version: 1.0 Name: apipkg Version: 1.0 Summary: apipkg: namespace control and lazy-import mechanism Home-page: http://bitbucket.org/hpk42/apipkg Author: holger krekel Author-email: holger at merlinux.eu License: MIT License Description: Welcome to apipkg! ------------------------ With apipkg you can control the exported namespace of a python package and greatly reduce the number of imports for your users. It is a `small pure python module`_ that works on virtually all Python versions, including CPython2.3 to Python3.1, Jython and PyPy. It co-operates well with Python's ``help()`` system, custom importers (PEP302) and common command line completion tools. Usage is very simple: you can require 'apipkg' as a dependency or you can copy paste the <100 Lines of code into your project. Tutorial example ------------------- Here is a simple ``mypkg`` package that specifies one namespace and exports two objects imported from different modules:: # mypkg/__init__.py import apipkg apipkg.initpkg(__name__, { 'path': { 'Class1': "_mypkg.somemodule:Class1", 'clsattr': "_mypkg.othermodule:Class2.attr", } } The package is initialized with a dictionary as namespace. You need to create a ``_mypkg`` package with a ``somemodule.py`` and ``othermodule.py`` containing the respective classes. The ``_mypkg`` is not special - it's a completely regular python package. Namespace dictionaries contain ``name: value`` mappings where the value may be another namespace dictionary or a string specifying an import location. On accessing an namespace attribute an import will be performed:: >>> import mypkg >>> mypkg.path >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now 4 # the value of _mypkg.othermodule.Class2.attr The ``mypkg.path`` namespace and its two entries are loaded when they are accessed. This means: * lazy loading - only what is actually needed is ever loaded * only the root "mypkg" ever needs to be imported to get access to the complete functionality. * the underlying modules are also accessible, for example:: from mypkg.sub import Class1 Including apipkg in your package -------------------------------------- If you don't want to add an ``apipkg`` dependency to your package you can copy the `apipkg.py`_ file somewhere to your own package, for example ``_mypkg/apipkg.py`` in the above example. You then import the ``initpkg`` function from that new place and are good to go. .. _`small pure python module`: .. _`apipkg.py`: http://bitbucket.org/hpk42/apipkg/src/tip/apipkg.py Feedback? ----------------------- If you have questions you are welcome to * join the #pylib channel on irc.freenode.net * subscribe to the http://codespeak.net/mailman/listinfo/py-dev list. * create an issue on http://bitbucket.org/hpk42/apipkg/issues have fun, holger krekel Platform: unix Platform: linux Platform: osx Platform: cygwin Platform: win32 Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: MacOS :: MacOS X Classifier: Topic :: Software Development :: Libraries Classifier: Programming Language :: Python apipkg-1.0/apipkg.egg-info/top_level.txt0000644000175000017500000000000711455435255016460 0ustar hpkhpkapipkg apipkg-1.0/apipkg.egg-info/dependency_links.txt0000644000175000017500000000000111455435255017777 0ustar hpkhpk apipkg-1.0/test_apipkg.py0000644000175000017500000002666311455435235013663 0ustar hpkhpkimport types import sys import py import apipkg import subprocess # # test support for importing modules # class TestRealModule: def setup_class(cls): cls.tmpdir = py.test.ensuretemp('test_apipkg') sys.path = [str(cls.tmpdir)] + sys.path pkgdir = cls.tmpdir.ensure('realtest', dir=1) tfile = pkgdir.join('__init__.py') tfile.write(py.code.Source(""" import apipkg apipkg.initpkg(__name__, { 'x': { 'module': { '__doc__': '_xyz.testmodule:__doc__', 'mytest0': '_xyz.testmodule:mytest0', 'mytest1': '_xyz.testmodule:mytest1', 'MyTest': '_xyz.testmodule:MyTest', } } } ) """)) ipkgdir = cls.tmpdir.ensure("_xyz", dir=1) tfile = ipkgdir.join('testmodule.py') ipkgdir.ensure("__init__.py") tfile.write(py.code.Source(""" 'test module' from _xyz.othermodule import MyTest #__all__ = ['mytest0', 'mytest1', 'MyTest'] def mytest0(): pass def mytest1(): pass """)) ipkgdir.join("othermodule.py").write("class MyTest: pass") def setup_method(self, *args): # Unload the test modules before each test. module_names = ['realtest', 'realtest.x', 'realtest.x.module'] for modname in module_names: if modname in sys.modules: del sys.modules[modname] def test_realmodule(self): import realtest.x assert 'realtest.x.module' in sys.modules assert getattr(realtest.x.module, 'mytest0') def test_realmodule_repr(self): import realtest.x assert "" == repr(realtest.x) def test_realmodule_from(self): from realtest.x import module assert getattr(module, 'mytest1') def test_realmodule__all__(self): import realtest.x.module assert realtest.x.__all__ == ['module'] assert len(realtest.x.module.__all__) == 4 def test_realmodule_dict_import(self): "Test verifying that accessing the __dict__ invokes the import" import realtest.x.module moddict = realtest.x.module.__dict__ assert 'mytest0' in moddict assert 'mytest1' in moddict assert 'MyTest' in moddict def test_realmodule___doc__(self): """test whether the __doc__ attribute is set properly from initpkg""" import realtest.x.module print (realtest.x.module.__map__) assert realtest.x.module.__doc__ == 'test module' class TestScenarios: def test_relative_import(self, monkeypatch, tmpdir): pkgdir = tmpdir.mkdir("mymodule") pkgdir.join('__init__.py').write(py.code.Source(""" import apipkg apipkg.initpkg(__name__, exportdefs={ '__doc__': '.submod:maindoc', 'x': '.submod:x', 'y': { 'z': '.submod:x' }, }) """)) pkgdir.join('submod.py').write("x=3\nmaindoc='hello'") monkeypatch.syspath_prepend(tmpdir) import mymodule assert isinstance(mymodule, apipkg.ApiModule) assert mymodule.x == 3 assert mymodule.__doc__ == 'hello' assert mymodule.y.z == 3 def test_recursive_import(self, monkeypatch, tmpdir): pkgdir = tmpdir.mkdir("recmodule") pkgdir.join('__init__.py').write(py.code.Source(""" import apipkg apipkg.initpkg(__name__, exportdefs={ 'some': '.submod:someclass', }) """)) pkgdir.join('submod.py').write(py.code.Source(""" import recmodule class someclass: pass print (recmodule.__dict__) """)) monkeypatch.syspath_prepend(tmpdir) 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(""" import apipkg apipkg.initpkg(__name__, exportdefs={ 'some': 'os.path', }) """)) monkeypatch.syspath_prepend(tmpdir) import aliasimport assert aliasimport.some is py.std.os.path def xtest_nested_absolute_imports(): import email api_email = apipkg.ApiModule('email',{ 'message2': { 'Message': 'email.message:Message', }, }) # nesting is supposed to put nested items into sys.modules assert 'email.message2' in sys.modules # alternate ideas for specifying package + preliminary code # def test_parsenamespace(): spec = """ path.local __.path.local::LocalPath path.svnwc __.path.svnwc::WCCommandPath test.raises __.test.outcome::raises """ d = parsenamespace(spec) print (d) assert d == {'test': {'raises': '__.test.outcome::raises'}, 'path': {'svnwc': '__.path.svnwc::WCCommandPath', 'local': '__.path.local::LocalPath'} } def xtest_parsenamespace_errors(): py.test.raises(ValueError, """ parsenamespace('path.local xyz') """) py.test.raises(ValueError, """ parsenamespace('x y z') """) def parsenamespace(spec): ns = {} for line in spec.split("\n"): line = line.strip() if not line or line[0] == "#": continue parts = [x.strip() for x in line.split()] if len(parts) != 2: raise ValueError("Wrong format: %r" %(line,)) apiname, spec = parts if not spec.startswith("__"): raise ValueError("%r does not start with __" %(spec,)) apinames = apiname.split(".") cur = ns for name in apinames[:-1]: cur.setdefault(name, {}) cur = cur[name] cur[apinames[-1]] = spec return ns def test_initpkg_replaces_sysmodules(monkeypatch): mod = type(sys)('hello') monkeypatch.setitem(sys.modules, 'hello', mod) apipkg.initpkg('hello', {'x': 'os.path:abspath'}) newmod = sys.modules['hello'] assert newmod != mod assert newmod.x == py.std.os.path.abspath def test_initpkg_transfers_attrs(monkeypatch): mod = type(sys)('hello') mod.__version__ = 10 mod.__file__ = "hello.py" mod.__loader__ = "loader" monkeypatch.setitem(sys.modules, 'hello', mod) apipkg.initpkg('hello', {}) newmod = sys.modules['hello'] assert newmod != mod assert newmod.__file__ == py.path.local(mod.__file__) assert newmod.__version__ == mod.__version__ assert newmod.__loader__ == mod.__loader__ def test_initpkg_not_transfers_not_existing_attrs(monkeypatch): mod = type(sys)('hello') mod.__file__ = "hello.py" monkeypatch.setitem(sys.modules, 'hello', mod) apipkg.initpkg('hello', {}) newmod = sys.modules['hello'] assert newmod != mod assert newmod.__file__ == py.path.local(mod.__file__) assert not hasattr(newmod, '__loader__') assert not hasattr(newmod, '__path__') def test_initpkg_defaults(monkeypatch): mod = type(sys)('hello') monkeypatch.setitem(sys.modules, 'hello', mod) apipkg.initpkg('hello', {}) newmod = sys.modules['hello'] assert newmod.__file__ == None assert newmod.__version__ == '0' def test_name_attribute(): api = apipkg.ApiModule('name_test', { 'subpkg': {}, }) assert api.__name__ == 'name_test' assert api.subpkg.__name__ == 'name_test.subpkg' def test_error_loading_one_element(monkeypatch, tmpdir): pkgdir = tmpdir.mkdir("errorloading1") pkgdir.join('__init__.py').write(py.code.Source(""" import apipkg apipkg.initpkg(__name__, exportdefs={ 'x': '.notexists:x', 'y': '.submod:y' }, ) """)) pkgdir.join('submod.py').write("y=0") monkeypatch.syspath_prepend(tmpdir) import errorloading1 assert isinstance(errorloading1, apipkg.ApiModule) assert errorloading1.y == 0 py.test.raises(ImportError, 'errorloading1.x') py.test.raises(ImportError, 'errorloading1.x') 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 assert '__onfirstaccess__' not in firstaccess.__all__ @py.test.mark.multi(mode=['attr', 'dict', 'onfirst']) 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 (list(mod.__dict__.keys())) assert 'newattr' in mod.__dict__ elif mode == "onfirst": assert not hasattr(mod, '__onfirstaccess__') assert not hasattr(mod, '__onfirstaccess__') assert '__onfirstaccess__' not in vars(mod) def test_bpython_getattr_override(tmpdir, monkeypatch): def patchgetattr(self, name): raise AttributeError(name) monkeypatch.setattr(apipkg.ApiModule, '__getattr__', patchgetattr) api = apipkg.ApiModule('bpy', { 'abspath': 'os.path:abspath', }) d = api.__dict__ assert 'abspath' in d def test_chdir_with_relative_imports_shouldnt_break_lazy_loading(tmpdir): pkg = tmpdir.mkdir('pkg') messy = tmpdir.mkdir('messy') pkg.join('__init__.py').write(py.code.Source(""" import apipkg apipkg.initpkg(__name__, { 'test': '.sub:test', }) """)) pkg.join('sub.py').write('def test(): pass') tmpdir.join('main.py').write(py.code.Source(""" import os import sys sys.path.insert(0, '') import pkg import py py.builtin.print_(pkg.__path__, file=sys.stderr) py.builtin.print_(pkg.__file__, file=sys.stderr) py.builtin.print_(pkg, file=sys.stderr) os.chdir('messy') pkg.test() """)) res = subprocess.call( ['python', 'main.py'], cwd=str(tmpdir), ) assert res == 0 def test_dotted_name_lookup(tmpdir, monkeypatch): pkgdir = tmpdir.mkdir("dotted_name_lookup") pkgdir.join('__init__.py').write(py.code.Source(""" import apipkg apipkg.initpkg(__name__, dict(abs='os:path.abspath')) """)) monkeypatch.syspath_prepend(tmpdir) import dotted_name_lookup assert dotted_name_lookup.abs == py.std.os.path.abspath apipkg-1.0/setup.py0000644000175000017500000000233211455435235012474 0ustar hpkhpk""" apipkg: namespace control and lazy-import mechanism. compatible to CPython 2.3 through to CPython 3.1, Jython, PyPy (c) 2009 holger krekel, Holger Krekel """ import os, sys try: from setuptools import setup except ImportError: from distutils.core import setup from apipkg import __version__ def main(): setup( name='apipkg', description= 'apipkg: namespace control and lazy-import mechanism', long_description = open('README.txt').read(), version= __version__, url='http://bitbucket.org/hpk42/apipkg', license='MIT License', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], author='holger krekel', author_email='holger at merlinux.eu', classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS :: MacOS X', 'Topic :: Software Development :: Libraries', 'Programming Language :: Python'], py_modules=['apipkg'] ) if __name__ == '__main__': main() apipkg-1.0/PKG-INFO0000644000175000017500000001013511455435255012061 0ustar hpkhpkMetadata-Version: 1.0 Name: apipkg Version: 1.0 Summary: apipkg: namespace control and lazy-import mechanism Home-page: http://bitbucket.org/hpk42/apipkg Author: holger krekel Author-email: holger at merlinux.eu License: MIT License Description: Welcome to apipkg! ------------------------ With apipkg you can control the exported namespace of a python package and greatly reduce the number of imports for your users. It is a `small pure python module`_ that works on virtually all Python versions, including CPython2.3 to Python3.1, Jython and PyPy. It co-operates well with Python's ``help()`` system, custom importers (PEP302) and common command line completion tools. Usage is very simple: you can require 'apipkg' as a dependency or you can copy paste the <100 Lines of code into your project. Tutorial example ------------------- Here is a simple ``mypkg`` package that specifies one namespace and exports two objects imported from different modules:: # mypkg/__init__.py import apipkg apipkg.initpkg(__name__, { 'path': { 'Class1': "_mypkg.somemodule:Class1", 'clsattr': "_mypkg.othermodule:Class2.attr", } } The package is initialized with a dictionary as namespace. You need to create a ``_mypkg`` package with a ``somemodule.py`` and ``othermodule.py`` containing the respective classes. The ``_mypkg`` is not special - it's a completely regular python package. Namespace dictionaries contain ``name: value`` mappings where the value may be another namespace dictionary or a string specifying an import location. On accessing an namespace attribute an import will be performed:: >>> import mypkg >>> mypkg.path >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now 4 # the value of _mypkg.othermodule.Class2.attr The ``mypkg.path`` namespace and its two entries are loaded when they are accessed. This means: * lazy loading - only what is actually needed is ever loaded * only the root "mypkg" ever needs to be imported to get access to the complete functionality. * the underlying modules are also accessible, for example:: from mypkg.sub import Class1 Including apipkg in your package -------------------------------------- If you don't want to add an ``apipkg`` dependency to your package you can copy the `apipkg.py`_ file somewhere to your own package, for example ``_mypkg/apipkg.py`` in the above example. You then import the ``initpkg`` function from that new place and are good to go. .. _`small pure python module`: .. _`apipkg.py`: http://bitbucket.org/hpk42/apipkg/src/tip/apipkg.py Feedback? ----------------------- If you have questions you are welcome to * join the #pylib channel on irc.freenode.net * subscribe to the http://codespeak.net/mailman/listinfo/py-dev list. * create an issue on http://bitbucket.org/hpk42/apipkg/issues have fun, holger krekel Platform: unix Platform: linux Platform: osx Platform: cygwin Platform: win32 Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: MacOS :: MacOS X Classifier: Topic :: Software Development :: Libraries Classifier: Programming Language :: Python apipkg-1.0/setup.cfg0000644000175000017500000000007311455435255012605 0ustar hpkhpk[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 apipkg-1.0/CHANGELOG0000644000175000017500000000153711455435235012202 0ustar hpkhpk1.0 ---------------------------------------- - make apipkg memorize the absolute path where a package starts importing so that subsequent chdir + imports won't break. - allow to alias modules - allow to use dotted names in alias specifications (thanks Ralf Schmitt). 1.0.0b6 ---------------------------------------- - fix recursive import issue resulting in a superflous KeyError - default to __version__ '0' and not set __loader__ or __path__ at all if it doesn't exist on the underlying init module 1.0.0b5 ---------------------------------------- - fixed MANIFEST.in - also transfer __loader__ attribute (thanks Ralf Schmitt) - compat fix for BPython 1.0.0b3 (compared to 1.0.0b2) ------------------------------------ - added special __onfirstaccess__ attribute whose value will be called on the first attribute access of an apimodule. apipkg-1.0/apipkg.py0000644000175000017500000000775411455435235012624 0ustar hpkhpk""" apipkg: control the exported namespace of a python package. see http://pypi.python.org/pypi/apipkg (c) holger krekel, 2009 - MIT license """ import os import sys from types import ModuleType __version__ = "1.0" def initpkg(pkgname, exportdefs): """ initialize given package from the export definitions. """ oldmod = sys.modules[pkgname] d = {} f = getattr(oldmod, '__file__', None) if f: f = os.path.abspath(f) d['__file__'] = f d['__version__'] = getattr(oldmod, '__version__', '0') if hasattr(oldmod, '__loader__'): d['__loader__'] = oldmod.__loader__ if hasattr(oldmod, '__path__'): d['__path__'] = [os.path.abspath(p) for p in oldmod.__path__] oldmod.__dict__.update(d) mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d) sys.modules[pkgname] = mod def importobj(modpath, attrname): module = __import__(modpath, None, None, ['__doc__']) if not attrname: return module retval = module names = attrname.split(".") for x in names: retval = getattr(retval, x) return retval class ApiModule(ModuleType): def __init__(self, name, importspec, implprefix=None, attr=None): self.__name__ = name self.__all__ = [x for x in importspec if x != '__onfirstaccess__'] self.__map__ = {} self.__implprefix__ = implprefix or name if attr: for name, val in attr.items(): #print "setting", self.__name__, name, val setattr(self, name, val) for name, importspec in importspec.items(): if isinstance(importspec, dict): subname = '%s.%s'%(self.__name__, name) apimod = ApiModule(subname, importspec, implprefix) sys.modules[subname] = apimod setattr(self, name, apimod) else: parts = importspec.split(':') modpath = parts.pop(0) attrname = parts and parts[0] or "" if modpath[0] == '.': modpath = implprefix + modpath if name == '__doc__': self.__doc__ = importobj(modpath, attrname) else: self.__map__[name] = (modpath, attrname) def __repr__(self): l = [] if hasattr(self, '__version__'): l.append("version=" + repr(self.__version__)) if hasattr(self, '__file__'): l.append('from ' + repr(self.__file__)) if l: return '' % (self.__name__, " ".join(l)) return '' % (self.__name__,) def __makeattr(self, name): """lazily compute value for name or raise AttributeError if unknown.""" #print "makeattr", self.__name__, name target = None if '__onfirstaccess__' in self.__map__: target = self.__map__.pop('__onfirstaccess__') importobj(*target)() try: modpath, attrname = self.__map__[name] except KeyError: if target is not None and name != '__onfirstaccess__': # retry, onfirstaccess might have set attrs return getattr(self, name) raise AttributeError(name) else: result = importobj(modpath, attrname) setattr(self, name, result) try: del self.__map__[name] except KeyError: pass # in a recursive-import situation a double-del can happen return result __getattr__ = __makeattr def __dict__(self): # force all the content of the module to be loaded when __dict__ is read dictdescr = ModuleType.__dict__['__dict__'] dict = dictdescr.__get__(self) if dict is not None: hasattr(self, 'some') for name in self.__all__: try: self.__makeattr(name) except AttributeError: pass return dict __dict__ = property(__dict__) apipkg-1.0/README.txt0000644000175000017500000000540011455435235012457 0ustar hpkhpkWelcome to apipkg! ------------------------ With apipkg you can control the exported namespace of a python package and greatly reduce the number of imports for your users. It is a `small pure python module`_ that works on virtually all Python versions, including CPython2.3 to Python3.1, Jython and PyPy. It co-operates well with Python's ``help()`` system, custom importers (PEP302) and common command line completion tools. Usage is very simple: you can require 'apipkg' as a dependency or you can copy paste the <100 Lines of code into your project. Tutorial example ------------------- Here is a simple ``mypkg`` package that specifies one namespace and exports two objects imported from different modules:: # mypkg/__init__.py import apipkg apipkg.initpkg(__name__, { 'path': { 'Class1': "_mypkg.somemodule:Class1", 'clsattr': "_mypkg.othermodule:Class2.attr", } } The package is initialized with a dictionary as namespace. You need to create a ``_mypkg`` package with a ``somemodule.py`` and ``othermodule.py`` containing the respective classes. The ``_mypkg`` is not special - it's a completely regular python package. Namespace dictionaries contain ``name: value`` mappings where the value may be another namespace dictionary or a string specifying an import location. On accessing an namespace attribute an import will be performed:: >>> import mypkg >>> mypkg.path >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now 4 # the value of _mypkg.othermodule.Class2.attr The ``mypkg.path`` namespace and its two entries are loaded when they are accessed. This means: * lazy loading - only what is actually needed is ever loaded * only the root "mypkg" ever needs to be imported to get access to the complete functionality. * the underlying modules are also accessible, for example:: from mypkg.sub import Class1 Including apipkg in your package -------------------------------------- If you don't want to add an ``apipkg`` dependency to your package you can copy the `apipkg.py`_ file somewhere to your own package, for example ``_mypkg/apipkg.py`` in the above example. You then import the ``initpkg`` function from that new place and are good to go. .. _`small pure python module`: .. _`apipkg.py`: http://bitbucket.org/hpk42/apipkg/src/tip/apipkg.py Feedback? ----------------------- If you have questions you are welcome to * join the #pylib channel on irc.freenode.net * subscribe to the http://codespeak.net/mailman/listinfo/py-dev list. * create an issue on http://bitbucket.org/hpk42/apipkg/issues have fun, holger krekel apipkg-1.0/MANIFEST.in0000644000175000017500000000014411455435235012517 0ustar hpkhpkinclude CHANGELOG include README.txt include setup.py include test_apipkg.py prune .svn prune .hg