Python3中的Python命名空间包

鲍比

命名空间包的主题对于初学者来说似乎有些混乱,并且它不能帮助以前的Python版本以几种不同的方式实现它,或者对StackOverflow上的许多问与答都过时了。我要寻找一个解决方案Python 3.5或更高版本

场景:

我正在将一堆Python代码重构为模块和子模块,并努力将每个项目设置为在相同的名称空间中彼此独立地运行。

我们最终将使用内部PyPi服务器,将这些程序包提供给我们的内部网络,并且不希望将它们与外部(公共)PyPi程序包混淆。

示例:我有2个模块,我希望能够执行以下操作:

from org.client.client1 import mod1
from org.common import config

反映的模块将这样分开:

仓库1:

org_client_client1_mod1/
  setup.py
  mod1/
    __init__.py
    somefile.py

仓库2:

org_common_config/
  setup.py
  config/
    __init__.py
    someotherfile.py

我的Git储存库已经按照org_client_client1_mod1org_common_config进行了设置,因此__init__.py,我相信我只需要对包装和文件进行设置即可

问题:

#1

使用__init__.py,我应该使用其中的哪一个(如果有的话)?:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

或者:

import pkg_resources
pkg_resources.declare_namespace(__name__)

#2

使用setup.py,我是否仍需要添加namespace_modules参数,如果是,我会使用namespace_modules=['org.common']还是namespace_modules=['org', 'common']

#3

我可以通过以不同的方式实现上述方法来放弃上述所有方法吗?也许更简单或更“ pythonic”的东西?

rite2hhh

聚会晚了,但是从不帮助同行旅行者沿着Python的命名空间前进!

#1:

使用__init__.py,我应该使用其中的哪一个(如果有的话)?:

它取决于,有三种方法可以做到的命名空间的包作为上市在这里

  1. 使用本机名称空间包。这种类型的名称空间包在PEP 420中定义,并且在Python 3.3和更高版本中可用。如果命名空间中的软件包仅需要支持Python 3和通过pip安装,则建议使用此方法。

  2. 使用pkgutil样式的名称空间包。对于需要支持Python 2和3以及需要通过pip和python setup.py install进行安装的新软件包,建议使用此选项。

  3. 使用pkg_resources样式的名称空间包。如果您需要与已经使用该方法的软件包兼容,或者您​​的软件包需要使用zip安全,则建议使用此方法。

如果您使用的是#2(pkgutil-style)或#3(pkg_resources-style),则必须为__init__.py文件使用相应的样式如果使用本机名称空间,则__init__.py名称空间目录中的

#2:

使用setup.py,我是否仍需要添加namespace_modules参数,如果是,我将使用namespace_modules = ['org.common']还是namespace_modules = ['org','common']?

如果您选择的命名空间包不是本机样式,则可以,您需要namespace_packages在中setup()

#3:

我可以通过以不同的方式实现上述方法来放弃上述所有方法吗?也许更简单或更“ pythonic”的东西?

由于您最终遇到了python中的一个复杂主题,因此您似乎知道自己在做什么,想要什么,并确定了创建Python命名空间包的方法。这将被认为是解决问题的一种Python方法。


除了发现您的问题外,以下是我发现的一些内容:

我阅读了《Python打包指南》PEP420并花了很多时间来了解命名空间包,而且我通常也了解它是如何工作的。在这里这里这里以及这个关于SO的线程都读了几个答案-这里的示例以及Rob共享的Git链接

但是,我的问题是在创建程序包之后。由于所有说明和示例代码都明确列出了该setuptools.setup(package=[])函数中的程序包,因此我的代码失败了。我的子软件包/目录未包括在内。深入研究,我发现setuptools也具有find_namespace_package()有助于添加子软件包功能

编辑

链接到find_namespace_packages()setuptools版本大于40.1.0):https : //setuptools.readthedocs.io/en/latest/setuptools.html#find-namespace-packages

编辑(08/09/2019):

为了完成答案,让我也通过示例进行重组。

以下解决方案假定Python 3.3+支持隐式名称空间包

由于您正在寻找适用于Python版本3.5或更高版本的解决方案,因此让我们采用提供的代码示例并进一步进行详细说明。

让我们假设以下内容:

命名空间/ Python包名称: org

分发包:org_clientorg_common

Python: 3.3+

setuptools: 40.1.0

为您执行以下操作

from org.client.client1 import mod1
from org.common import config

并保持您的顶级目录相同,即。org_client_client1_mod1org_common_config,您可以将结构更改为以下内容

仓库1:

org_client_client1_mod1/
  setup.py
  org/
    client/
      client1/
        __init__.py
        submod1/
          __init__.py
        mod1/
          __init__.py
          somefile.py
        file1.py

更新 setup.py

from setuptools import find_namespace_packages, setup
setup(
    name="org_client",
    ...
    packages=find_namespace_packages(), # Follows similar lookup as find_packages()
    ...
)

仓库2:

org_common_config/
  setup.py
  org/
    common/
      __init__.py
      config/
        __init__.py
        someotherfile.py

更新时间setup.py

from setuptools import find_namespace_packages, setup
setup(
    name="org_common",
    ...
    packages=find_namespace_packages(), # Follows similar lookup as find_packages()
    ...
)

要安装(使用pip):

(venv) $ pip3 install org_common_config/
(venv) $ pip3 install org_client_client1_mod1/

更新的点列表将显示以下内容:

(venv) $ pip3 list
...
org_client
org_common
...

但是它们将不可导入,因为导入时必须遵循org.clientorg.common注明。

要了解原因,您可以在此处浏览(假设在venv中):

(venv) $ cd venv/lib/python3.5/site-packages/
(venv) $ ls -l | grep org

您会看到没有目录org_clientorg_common目录,它们被解释为名称空间包。

(venv) $ cd venv/lib/python3.5/site-packages/org/
(venv) $ ls -l
client/
common/
...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章