我有一个具有以下结构的Python项目(为简单起见省略了无关的源文件):
myproject/
mysubmodule/
setup.py
setup.py
文件myproject/setup.py
使用distutils.core.setup
来安装模块myproject
和相关来源。但是,myproject
需要安装mysubmodule
(这是一个git子模块)。所以我现在正在做的是:
myproject/$ cd mysubmodule
myproject/mysubmodule/$ python setup.py install
myproject/mysubmodule/$ cd ..
myproject/$ python setup.py install
这对客户来说太单调乏味了,特别是如果将来通过进一步的子模块扩展项目。
调用mysubmodule
时,有没有办法自动安装myproject/setup.py
?
答案 0 :(得分:3)
使用自己的mysubmodule
为setup.py
创建一个包,并让顶级包依赖于setup.py
中的该包。这意味着您只需要使包/依赖项可用并在顶级包上运行python setup.py install
。
接下来的问题是如何将依赖项/包发送给客户,但这可以通过将它们放在一个目录中并在搜索依赖项时配置setup.py
以包含该目录来解决。
另一种选择是“供应商”mysubmodule
,这意味着将其全部包含在一个包中(不再提出问题)并让一个python setup.py install
安装主包。例如,pip
个供应商(包括)requests
因此可以使用它而无需依赖requests
个包。
答案 1 :(得分:2)
setuptools.find_packages()
能够发现子模块
您的setup.py
应该看起来像
from setuptools import setup, find_packages
setup(
packages=find_packages(),
# ...
)
答案 2 :(得分:0)
当我需要包含几个尚未被部署到PiPy软件包索引中的,作为子模块克隆的第三方软件包时,我可以使用以下方法之一:
# Find git submodules
sub_mod_bash_command = "git config --file " + \
os.getcwd()+"/.gitmodules --get-regexp path | awk '{ print $2 }'"
bash_output = subprocess.check_output(['bash', '-c', sub_mod_bash_command])
sub_mods = [x for x in bash_output.decode("utf-8").split("\n") if x != '']
# Install submodule and it's requirements
for sub_mod in sub_mods:
submod_setup_path = os.getcwd()+"/"+sub_mod+"/setup.py"
if os.path.exists(submod_setup_path):
# Run submodule setup.py file
subprocess.call([sys.executable, "-m", "pip", "install", os.getcwd()+"/"+sub_mod+"/"])
# Find git submodules
sub_mod_bash_command = "git config --file " + \
os.getcwd()+"/.gitmodules --get-regexp path | awk '{ print $2 }'"
bash_output = subprocess.check_output(['bash', '-c', sub_mod_bash_command])
sub_mods = [x for x in bash_output.decode("utf-8").split("\n") if x != '']
# Extend requirements list with submodule requirements
for sub_mod in sub_mods:
submod_setup_path = os.getcwd()+"/"+sub_mod+"/setup.py"
if os.path.exists(submod_setup_path):
# Generate requires.txt file for the submodule using the setuptools.egg_info module
try:
subprocess.call([sys.executable, submod_setup_path,"egg_info"])
# Open egg_info generated requires.txt file
with open(os.getcwd()+"/gqcnn.egg-info/requires.txt") as file:
# Read requires file up till empty line
for line in file:
if line.strip() == "":
## Try to remove tree; if failed show an error using try...except on screen
try:
shutil.rmtree(os.getcwd()+"/gqcnn.egg-info")
except OSError as e:
print ("Error: %s - %s." % (e.filename, e.strerror))
break
requirements.append(line.strip()) # Append submodule requirement to package requirements
except Exception as e:
logger.warning("Submodule dependencies could not be imported. "+str(e))
不确定这是否是实现此目的的最干净的方法,但是在我测试过的所有情况下,它似乎都有效。