Python命名空间包作为现有包

时间:2015-07-22 14:23:42

标签: python namespaces pip setuptools pypi

是否可以在现有包的名称空间/路径中添加一些不是命名空间包的东西?

假设有一个名为package的外部包。

我在我的project.py中使用它:

from package.module import Class

是否可以将名为extension的程序包创建为package的名称空间,以便可以从package.extension导入?

from package.module import Class
from package.extension.module import ExtensionClass

是否可以使用pip / setuptools安装这两个软件包,而无需在我project.py package中添加猴子修补程序,我要从package.extension和{{} { 1}}?

部分解决方案

我已经能够通过两种方式实现我的需求:修改原始packageproject.py中的猴子修补

结构:

./test.py
./demo/test.py
./demo/__init__.py
./extension/demo/__init__.py
./extension/demo/extension/test.py
./extension/demo/extension/__init__.py
./extension/__init__.py

./test.py的内容:

import demo.test
demo.test.hello()

import demo.extension.test
demo.extension.test.hello()

部分解决方案1 ​​ - 修改原始包

我修改了demo/__init__.py,因此它包含:

import pkgutil

__path__ = pkgutil.extend_path(__path__, __name__)

执行示例:

$ export PYTHONPATH=extension
$ python test.py 
Hello! I'm demo.
Hello! I'm extension.

部分解决方案2 - 修改原始包

我修改了./test.py所以它包含了猴子补丁:

import pkgutil
import demo
demo.__path__ = pkgutil.extend_path(demo.__path__, demo.__name__)

import demo.test
demo.test.hello()

import demo.extension.test
demo.extension.test.hello()

执行示例:

$ export PYTHONPATH=extension
$ python test.py 
Hello! I'm demo.
Hello! I'm extension.

问题(再次)

其中一个解决方案要求原始软件包的所有者允许扩展,另一个解决方案需要猴子修补。是否有可能通过setup.py/pip安装的软件包不需要修改原始软件包或猴子修补?

2 个答案:

答案 0 :(得分:1)

这可能不太有用,但您可以查看Flask和部分its extensions来源。 Flask扩展的工作方式与您描述的完全相同,例如:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

答案 1 :(得分:1)

我认为命名空间包是setuptools的一个功能,the docs只说明两个条件:

    namespace_packages和中
  • setup()
  • __import__('pkg_resources').declare_namespace(__name__)在你的 __init__.py个文件。

有了这个,我在Windows 7上使用Python 3.3测试了以下配置:

│   setup.py
│
└───cherrypy
    │   __init__.py
    │
    └───extend
        │   test.py
        │
        └───__init__.py

我的setup.py:

from setuptools import setup, find_packages
setup(
    name = "HelloWorld",
    version = "0.1",
    packages = find_packages(),
    namespace_packages = ['cherrypy']
)

然后,在python setup.py develop之后,cherrypy.extend像模块一样工作,我可以从中加载类:

Python 3.3.5 (v3.3.5:62cf4e77f785, Mar  9 2014, 10:37:12) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cherrypy
>>> cherrypy
<module 'cherrypy' from 'C:\\Python33\\lib\\site-packages\\cherrypy\\__init__.py
'>
>>> from cherrypy.extend import Cls
>>> from cherrypy.extend import test
>>> test
<module 'cherrypy.extend.test' from 'c:\\users\\me\\desktop\\test\\cherrypy\
\extend\\test.py'>
>>> o = Cls()
>>> o
<cherrypy.extend.Cls object at 0x01AA0AB0>
>>>

我还没有用pip测试可安装性,但似乎没有任何东西可以让它变得不可能。如果这不适合您,和/或您处于不同的环境中,请告诉我们。

编辑:我注意到我从我的包的源文件夹运行Python,它从./加载。这仍然按预期工作,我将上面的示例换成了我正在使用其他工作目录的示例。