Commit 4b93b8eb authored by Scott Talbert's avatar Scott Talbert

New upstream version 1.5

parent 1ceb707f
src/apipkg/version.py
__pycache__
*.egg-info
.cache/
.eggs/
\ No newline at end of file
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.5-dev" # 3.5 development branch
- "3.6"
- "3.6-dev" # 3.6 development branch
- "3.7-dev" # 3.7 development branch
- "nightly" # currently points to 3.7-dev
# command to install dependencies
env:
- EDITABLE=-e
- EDITABLE=
install:
- pip install -U setuptools pip setuptools_scm pytest
- pip install $EDITABLE .
# command to run tests
script: pytest
1.5
----
- switch to setuptools_scm
- move to github
- fix up python compat matrix
- avoid dict iteration (fixes issue on python3)
- preserve __package__ - ths gets us better pep 302 compliance
1.4
-----------------
......
Metadata-Version: 1.1
Metadata-Version: 1.2
Name: apipkg
Version: 1.4
Version: 1.5
Summary: apipkg: namespace control and lazy-import mechanism
Home-page: http://bitbucket.org/hpk42/apipkg
Home-page: https://github.com/pytest-dev/apipkg
Author: holger krekel
Author-email: holger at merlinux.eu
Maintainer: Ronny Pfannschmidt
Maintainer-email: opensource@ronnypfannschmidt.de
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.
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 CPython 2.7 and 3.4+,
Jython and PyPy. It cooperates 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 <200 Lines of code into your project.
can copy paste the ~200 lines of code into your project.
Tutorial example
......@@ -40,7 +40,7 @@ Description: Welcome to apipkg!
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.
regular Python package.
Namespace dictionaries contain ``name: value`` mappings
where the value may be another namespace dictionary or
......@@ -61,7 +61,7 @@ Description: Welcome to apipkg!
* 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.
access to the complete functionality
* the underlying modules are also accessible, for example::
......@@ -77,8 +77,8 @@ Description: Welcome to apipkg!
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
.. _`small pure Python module`:
.. _`apipkg.py`: https://github.com/pytest-dev/apipkg/blob/master/src/apipkg/__init__.py
Feedback?
-----------------------
......@@ -86,8 +86,7 @@ Description: Welcome to apipkg!
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
* create an issue on https://github.com/pytest-dev/apipkg/issues
have fun,
holger krekel
......@@ -105,3 +104,10 @@ Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Topic :: Software Development :: Libraries
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
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.
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 CPython 2.7 and 3.4+,
Jython and PyPy. It cooperates 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 <200 Lines of code into your project.
can copy paste the ~200 lines of code into your project.
Tutorial example
......@@ -32,7 +31,7 @@ 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.
regular Python package.
Namespace dictionaries contain ``name: value`` mappings
where the value may be another namespace dictionary or
......@@ -53,7 +52,7 @@ 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.
access to the complete functionality
* the underlying modules are also accessible, for example::
......@@ -69,8 +68,8 @@ 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
.. _`small pure Python module`:
.. _`apipkg.py`: https://github.com/pytest-dev/apipkg/blob/master/src/apipkg/__init__.py
Feedback?
-----------------------
......@@ -78,8 +77,7 @@ 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
* create an issue on https://github.com/pytest-dev/apipkg/issues
have fun,
holger krekel
import py
import apipkg
LOCAL_APIPKG = py.path.local(__file__).dirpath().join('src/apipkg/__init__.py')
INSTALL_TYPE = 'editable' if apipkg.__file__ == LOCAL_APIPKG else 'full'
def pytest_report_header(startdir):
return "apipkg {install_type} install version={version}".format(
install_type=INSTALL_TYPE, version=apipkg.__version__)
......@@ -4,5 +4,4 @@ universal = true
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
import re
from setuptools import setup
from setuptools import setup, find_packages
def get_version():
VERSION_RE = re.compile("__version__ = \'(.*)\'", re.M)
with open('apipkg.py') as fp:
return VERSION_RE.search(fp.read()).group(1)
def readme():
with open('README.rst') as fp:
return fp.read()
def main():
setup(
name='apipkg',
description='apipkg: namespace control and lazy-import mechanism',
long_description=open('README.txt').read(),
version=get_version(),
url='http://bitbucket.org/hpk42/apipkg',
long_description=readme(),
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
setup_requires=[
'setuptools_scm',
'setuptools>=30.3.0', # introduced setup.cfg metadata
],
use_scm_version={
'write_to': 'src/apipkg/version.py'
},
url='https://github.com/pytest-dev/apipkg',
license='MIT License',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
author='holger krekel',
author_email='holger at merlinux.eu',
maintainer="Ronny Pfannschmidt",
maintainer_email="opensource@ronnypfannschmidt.de",
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
......@@ -27,9 +33,21 @@ def main():
'Operating System :: Microsoft :: Windows',
'Operating System :: MacOS :: MacOS X',
'Topic :: Software Development :: Libraries',
'Programming Language :: Python'],
py_modules=['apipkg'],
# Specify the Python versions you support here.
# In particular, ensure that you indicate whether
# you support Python 2, Python 3 or both.
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
packages=find_packages('src'),
package_dir={'': 'src'},
)
if __name__ == '__main__':
main()
Metadata-Version: 1.2
Name: apipkg
Version: 1.5
Summary: apipkg: namespace control and lazy-import mechanism
Home-page: https://github.com/pytest-dev/apipkg
Author: holger krekel
Maintainer: Ronny Pfannschmidt
Maintainer-email: opensource@ronnypfannschmidt.de
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 CPython 2.7 and 3.4+,
Jython and PyPy. It cooperates 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 ~200 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
<ApiModule 'mypkg.path'>
>>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now
<class _mypkg.somemodule.Class1 at 0xb7d428fc>
>>> 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`: https://github.com/pytest-dev/apipkg/blob/master/src/apipkg/__init__.py
Feedback?
-----------------------
If you have questions you are welcome to
* join the #pylib channel on irc.freenode.net
* create an issue on https://github.com/pytest-dev/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
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
.gitignore
.travis.yml
CHANGELOG
LICENSE
MANIFEST.in
README.rst
conftest.py
setup.cfg
setup.py
test_apipkg.py
tox.ini
./.gitignore
./.travis.yml
./CHANGELOG
./LICENSE
./MANIFEST.in
./README.rst
./conftest.py
./setup.cfg
./setup.py
./test_apipkg.py
./tox.ini
./example/_mypkg/__init__.py
./example/_mypkg/othermodule.py
./example/_mypkg/somemodule.py
./example/mypkg/__init__.py
./example/mypkg/othermodule.py
./example/mypkg/somemodule.py
./src/apipkg/__init__.py
example/_mypkg/__init__.py
example/_mypkg/othermodule.py
example/_mypkg/somemodule.py
example/mypkg/__init__.py
example/mypkg/othermodule.py
example/mypkg/somemodule.py
src/apipkg/__init__.py
src/apipkg/version.py
src/apipkg.egg-info/PKG-INFO
src/apipkg.egg-info/SOURCES.txt
src/apipkg.egg-info/dependency_links.txt
src/apipkg.egg-info/top_level.txt
\ No newline at end of file
"""
apipkg: control the exported namespace of a python package.
apipkg: control the exported namespace of a Python package.
see http://pypi.python.org/pypi/apipkg
see https://pypi.python.org/pypi/apipkg
(c) holger krekel, 2009 - MIT license
"""
......@@ -9,8 +9,7 @@ import os
import sys
from types import ModuleType
__version__ = '1.4'
from .version import version as __version__
def _py_abspath(path):
......@@ -37,8 +36,9 @@ def distribution_version(name):
return dist.version
def initpkg(pkgname, exportdefs, attr=dict(), eager=False):
def initpkg(pkgname, exportdefs, attr=None, eager=False):
""" initialize given package from the export definitions. """
attr = attr or {}
oldmod = sys.modules.get(pkgname)
d = {}
f = getattr(oldmod, '__file__', None)
......@@ -51,6 +51,8 @@ def initpkg(pkgname, exportdefs, attr=dict(), eager=False):
d['__loader__'] = oldmod.__loader__
if hasattr(oldmod, '__path__'):
d['__path__'] = [_py_abspath(p) for p in oldmod.__path__]
if hasattr(oldmod, '__package__'):
d['__package__'] = oldmod.__package__
if '__doc__' not in exportdefs and getattr(oldmod, '__doc__', None):
d['__doc__'] = oldmod.__doc__
d.update(attr)
......@@ -60,12 +62,13 @@ def initpkg(pkgname, exportdefs, attr=dict(), eager=False):
sys.modules[pkgname] = mod
# eagerload in bypthon to avoid their monkeypatching breaking packages
if 'bpython' in sys.modules or eager:
for module in sys.modules.values():
for module in list(sys.modules.values()):
if isinstance(module, ApiModule):
module.__dict__
def importobj(modpath, attrname):
"""imports a module, then resolves the attrname on it"""
module = __import__(modpath, None, None, ['__doc__'])
if not attrname:
return module
......@@ -78,6 +81,7 @@ def importobj(modpath, attrname):
class ApiModule(ModuleType):
"""the magical lazy-loading module standing"""
def __docget(self):
try:
return self.__doc
......@@ -121,13 +125,13 @@ class ApiModule(ModuleType):
self.__map__[name] = (modpath, attrname)
def __repr__(self):
l = []
repr_list = []
if hasattr(self, '__version__'):
l.append("version=" + repr(self.__version__))
repr_list.append("version=" + repr(self.__version__))
if hasattr(self, '__file__'):
l.append('from ' + repr(self.__file__))
if l:
return '<ApiModule %r %s>' % (self.__name__, " ".join(l))
repr_list.append('from ' + repr(self.__file__))
if repr_list:
return '<ApiModule %r %s>' % (self.__name__, " ".join(repr_list))
return '<ApiModule %r>' % (self.__name__,)
def __makeattr(self, name):
......
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
version = '1.5'
......@@ -85,7 +85,7 @@ class TestRealModule:
def test_realmodule___doc__(self):
"""test whether the __doc__ attribute is set properly from initpkg"""
import realtest.x.module
print (realtest.x.module.__map__)
print(realtest.x.module.__map__)
assert realtest.x.module.__doc__ == 'test module'
......@@ -121,7 +121,7 @@ class TestScenarios:
pkgdir.join('submod.py').write(py.code.Source("""
import recmodule
class someclass: pass
print (recmodule.__dict__)
print(recmodule.__dict__)
"""))
monkeypatch.syspath_prepend(tmpdir)
import recmodule
......@@ -174,7 +174,7 @@ def test_parsenamespace():
test.raises __.test.outcome::raises
"""
d = parsenamespace(spec)
print (d)
print(d)
assert d == {
'test': {'raises': '__.test.outcome::raises'},
'path': {
......@@ -227,6 +227,7 @@ def test_initpkg_transfers_attrs(monkeypatch):
mod.__version__ = 10
mod.__file__ = "hello.py"
mod.__loader__ = "loader"
mod.__package__ = "package"
mod.__doc__ = "this is the documentation"
monkeypatch.setitem(sys.modules, 'hello', mod)
apipkg.initpkg('hello', {})
......@@ -235,6 +236,7 @@ def test_initpkg_transfers_attrs(monkeypatch):
assert newmod.__file__ == py.path.local(mod.__file__)
assert newmod.__version__ == mod.__version__
assert newmod.__loader__ == mod.__loader__
assert newmod.__package__ == mod.__package__
assert newmod.__doc__ == mod.__doc__
......@@ -261,12 +263,14 @@ def test_initpkg_not_transfers_not_existing_attrs(monkeypatch):
mod = ModuleType('hello')
mod.__file__ = "hello.py"
assert not hasattr(mod, '__path__')
assert not hasattr(mod, '__package__') or mod.__package__ is None
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, '__path__')
assert not hasattr(newmod, '__package__') or mod.__package__ is None
def test_initpkg_not_changing_jython_paths(monkeypatch):
......@@ -364,7 +368,7 @@ def test_onfirstaccess_setsnewattr(tmpdir, monkeypatch, mode):
if mode == 'attr':
assert mod.newattr == 42
elif mode == "dict":
print (list(mod.__dict__.keys()))
print(list(mod.__dict__.keys()))
assert 'newattr' in mod.__dict__
elif mode == "onfirst":
assert not hasattr(mod, '__onfirstaccess__')
......@@ -383,8 +387,8 @@ def test_bpython_getattr_override(tmpdir, monkeypatch):
assert 'abspath' in d
def test_chdir_with_relative_imports_shouldnt_break_lazy_loading(tmpdir):
tmpdir.join('apipkg.py').write(py.code.Source(apipkg))
def test_chdir_with_relative_imports_support_lazy_loading(tmpdir, monkeypatch):
monkeypatch.syspath_prepend(py.path.local('src'))
pkg = tmpdir.mkdir('pkg')
tmpdir.mkdir('messy')
pkg.join('__init__.py').write(py.code.Source("""
......
[tox]
envlist=py27,py26,py33,py34,jython,flakes
envlist=py27,py34,py35,py36,jython,flakes
[tox:hudson]
sdistsrc={distshare}/apipkg-*
......@@ -16,7 +16,6 @@ commands=py.test-jython []
deps=flake8
commands=flake8
[flake8]
exclude=.tox/,.env/,dist/,build/,example/
max_complexity=11
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment