【问题标题】:Python Namespace package as extension to existing packagePython 命名空间包作为现有包的扩展
【发布时间】:2023-03-10 12:35:01
【问题描述】:

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

假设有一个名为 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 安装这两个软件包,而无需将猴子补丁添加到我想从packagepackage.extension 导入的project.py 中?


部分解决方案

我已经能够通过两种方式实现我所需要的:通过修改原始 package 和通过猴子修补 project.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 安装的软件包是否有可能不需要更改原始软件包或猴子补丁?

【问题讨论】:

    标签: python namespaces pip setuptools pypi


    【解决方案1】:

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

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

    【讨论】:

    【解决方案2】:

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

    • namespace_packagessetup()
    • __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,它从 ./ 加载。这仍然可以按预期工作,我将上面的示例换成了我正在使用其他工作目录的示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-24
      • 2014-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 2017-05-28
      • 1970-01-01
      相关资源
      最近更新 更多