Python 分发命名空间包子模块

Python 分发命名空间包子模块,python,setuptools,namespace-package,Python,Setuptools,Namespace Package,我已经重新组织了我的Python项目,使之成为一个同名的保护伞。我的项目现在可以看作是相互依赖的多个子系统。这意味着每个子模块现在都可以单独分发,这样就只能安装所需的依赖项 旧结构: / ├─ myproj/ │ ├─ __init__.py │ ├─ mod1.py │ ├─ subpackage1/ │ └─ subpackage2/ └─ setup.py / ├─ myproj/ │ ├─ common/ │ │ └─ mod1.py │ ├─ subpackage1

我已经重新组织了我的Python项目,使之成为一个同名的保护伞。我的项目现在可以看作是相互依赖的多个子系统。这意味着每个子模块现在都可以单独分发,这样就只能安装所需的依赖项

旧结构:

/
├─ myproj/
│  ├─ __init__.py
│  ├─ mod1.py
│  ├─ subpackage1/
│  └─ subpackage2/
└─ setup.py
/
├─ myproj/
│  ├─ common/ 
│  │  └─ mod1.py
│  ├─ subpackage1/
│  └─ subpackage2/
└─ setup.py
新结构:

/
├─ myproj/
│  ├─ __init__.py
│  ├─ mod1.py
│  ├─ subpackage1/
│  └─ subpackage2/
└─ setup.py
/
├─ myproj/
│  ├─ common/ 
│  │  └─ mod1.py
│  ├─ subpackage1/
│  └─ subpackage2/
└─ setup.py
正如您所看到的,除了
myproj
现在是一个独立的应用程序,并且子包
common
子包1
子包2
现在可以独立分发之外,没有什么变化

是否可以保留一个唯一的
setup.py
文件来创建3个独立的包

  • myproj.common
  • myproj.子包1
  • myproj.子包2

另外,我想指定在安装
myproj.subpackage1
时,需要
myproj.common
,或者
myproj.subpackage2
将同时需要
myproj.common
myproj.subpackage1
,正如Martijn Pieters所说,这只是python代码,所以您可以这样做。我甚至认为这也不会那么困难

基本上,您只需要操作setup.py中的命令行参数

import sys

if sys.argv[1] == "subpackage1":
    # Remove the first command line argument so the setup function works normally.
    sys.argv.pop(1)

    # Run setup code for subpackage1 or 
    # Use a separate setup file and call "import setup_subpackage1"
    ...
elif sys.argv[1] == "subpackage2":
    # Remove the first command line argument so the setup function works normally.
    sys.argv.pop(1)

    # Run setup code for subpackage2 or
    # Use a separate setup file and call "import setup_subpackage2"
    ...
else:
    # Check if they gave common as an argument or just left if blank
    if sys.argv[1] == "common":
        # Remove the first command line argument so the setup function works normally.
        sys.argv.pop(1)

    # Run setup code for both packages.
    ...
再一次,正如Martijn Pieters所说,这可能不值得付出努力。Python的主要理念是简单优于复杂。如果您的两个子包完全不同,那么它们可能应该是不同的项目

示例:Scipy

我试图想出一个为什么不这样做的例子,但显然
scipy
就是这样做的。所以我试图劝阻你可能是错的。仍然可能不值得这么做,因为大多数人只是
pip安装scipy

很有趣。Scipy的结构是经过深思熟虑的。Scipy将每个子包作为Python包(带有_init__.py文件的目录)。每个包的内部都有一个setup.py文件。他们还使用
numpy.distutils.misc_util.Configuration
添加子包

如果您仔细查看他们的源代码,scipy的主setup.py文件如下所示

from __future__ import division, print_function, absolute_import

import sys


def configuration(parent_package='',top_path=None):
    from numpy.distutils.misc_util import Configuration
    config = Configuration('scipy',parent_package,top_path)
    config.add_subpackage('cluster')
    config.add_subpackage('constants')
    config.add_subpackage('fftpack')
    config.add_subpackage('integrate')
    config.add_subpackage('interpolate')
    config.add_subpackage('io')
    config.add_subpackage('linalg')
    config.add_data_files('*.pxd')
    config.add_subpackage('misc')
    config.add_subpackage('odr')
    config.add_subpackage('optimize')
    config.add_subpackage('signal')
    config.add_subpackage('sparse')
    config.add_subpackage('spatial')
    config.add_subpackage('special')
    config.add_subpackage('stats')
    config.add_subpackage('ndimage')
    config.add_subpackage('_build_utils')
    config.add_subpackage('_lib')
    config.make_config_py()
    return config

if __name__ == '__main__':
    from numpy.distutils.core import setup
    setup(**configuration(top_path='').todict())

因此,似乎已经为您找到了一个很好的解决方案。

是的,这是可能的,但可能不值得为维护它付出努力或痛苦
setup.py
只是Python代码,但它用于创建源代码和二进制发行版,在下载源代码发行版后处理安装,此外,对于各种额外任务,如运行测试或上载您创建的分发版,您必须为您的子包维护单独的元数据,a)决定在创建分发版时应用哪个元数据,b)确保在您创建的分发版中记录该决定,以便在安装时,您不会意外地获得其他选项的元数据,否则会完全崩溃。