为 CLI 脚本构建 python 包
Build python package for CLI script
我正在尝试构建我的第一个 python 包并将其发布到 PyPi。我的目标是通过 CLI 提供某个功能,以便最终用户可以像 pip3 install my-package
这样通过 pip 安装它,并像 my-package -fa first_argument -sa second_argument
.
那样直接从终端使用它
假设我的包裹名为 fp-test-package
。我制作了我的项目文件夹结构模型,您可以在此处找到 https://github.com/fabiopipitone/fp-test-package.
在模型中,我还作为要求插入了真实项目 (tqdm) 中所需的包之一,并保持完全相同的约定(外部文件夹和 github 存储库上的连字符,内部包下划线,相同定位和导入助手和实用程序等)。这样,如果它在模型上工作,它必须在真实项目上工作。
这是项目的目录结构
fp-test-package
├── fp_test_package
│ ├── __init__.py
│ ├── fp_test_package.py
│ ├── helpers
│ │ ├── arguments_checkers.py
│ │ ├── csv_handlers.py
│ │ └── utility_functions.py
│ └── utils
│ ├── __init__.py
│ ├── CustomLogger.py
│ └── TqdmLoggingHandler.py
├── LICENSE
├── README.rst
├── requirements.txt
├── setup.py
├── docs
└── tests
这是setup.py
from setuptools import setup, find_packages
with open("README.rst", "r") as fh:
long_description = fh.read()
setup(
name ='fp-test-package',
version ='0.0.1',
description='Simple test building a CLI tool package',
long_description=long_description,
long_description_content_type='text/x-rst',
license ='GPLv2',
packages = find_packages(),
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package.py:main'
]
},
classifiers =(
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v2",
"Operating System :: Linux",
),
keywords ='test packaging fabiopipitone',
install_requires = ['tqdm>=4.49.0'],
zip_safe = False
)
我尝试了一些关于如何构建和发布 CLI python 包的方法,然后我尝试使用 fp-test-package
目录中的 sudo python3 setup.py install
(与 setup.py).它似乎安装了软件包(我可以在 pip3 freeze
中找到条目 fp-test-package==0.0.1
)但是如果我在终端中尝试 fp-test-package
它 returns fp-test-package: command not found
,如果我试试 fp_test_package
它 returns:
Traceback (most recent call last):
File "/usr/local/bin/fp_test_package", line 11, in <module>
load_entry_point('fp-test-package==0.0.1', 'console_scripts', 'fp_test_package')()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
return ep.load()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
return self.resolve()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'fp_test_package.py'
然后我使用 sudo pip3 uninstall fp_test_package
成功卸载了软件包。我删除了之前创建的 build
、dist
和 fp_test_package.egg-info
目录并尝试使用 pip3 install -e .
(再次从 fp-test-package
内部)。它创建了 fp_test_package.egg-info
目录,但又在控制台中 运行 fp_test_package
returns
Traceback (most recent call last):
File "/usr/local/bin/fp_test_package", line 11, in <module>
load_entry_point('fp-test-package==0.0.1', 'console_scripts', 'fp_test_package')()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
return ep.load()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
return self.resolve()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'fp_test_package.py'
现在,我错过了什么?我想简单地打包并安装它,以便当用户键入 fp-test-package
或 fp_test_package
时 returns 需要 --export_path
参数的错误(意味着脚本正确开始)就像我从控制台调用它时一样:
$ python3 fp_test_package/fp_test_package.py
usage: fp_test_package.py [-h] -ep EXPORT_PATH [-sa SECOND_ARGUMENT] [-ta THIRD_ARGUMENT]
fp_test_package.py: error: the following arguments are required: -ep/--export_path
我该怎么做?
编辑:
我注意到 @Dustin 然后指出了关于 setup.py 的内容。事实上,我的一位同事 PRed 更改了 console_scripts
部分的虚拟仓库。
现在,在我的同事机器上,一切似乎都按预期工作。在我的系统中,在拉取 repo 并重新运行 python3 setup.py install
后,当从控制台调用 fp_test_package
时,它 returns 如下:
Traceback (most recent call last):
File "/usr/local/bin/fp_test_package", line 11, in <module>
load_entry_point('fp-test-package==0.0.1', 'console_scripts', 'fp_test_package')()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
return ep.load()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
return self.resolve()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
File "/usr/local/bin/fp_test_package.py", line 4, in <module>
__import__('pkg_resources').run_script('fp-test-package==0.0.1', 'fp_test_package.py')
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 667, in run_script
self.require(requires)[0].run_script(script_name, ns)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 1452, in run_script
raise ResolutionError(
pkg_resources.ResolutionError: Script 'scripts/fp_test_package.py' not found in metadata at '/usr/local/lib/python3.8/dist-packages/fp_test_package-0.0.1-py3.8.egg/EGG-INFO'
有什么想法吗?
您的 setup.py
有:
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package.py:main'
]
},
这相当于以下导入:
from fp_test_package.py import main as fp_test_package
问题是您没有 fp_test_package.py
模块,您有一个包含 fp_test_package
的 fp_test_package
模块(包含 __init__.py
文件的目录)子模块(模块名称不包括扩展名)。
假设您的 fp_test_package.py
文件定义了一个 main
函数,您可以将其更改为:
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package.fp_test_package:main'
]
},
或者您可以将 main
函数移动到 fp_test_package/__init__.py
,这样它就可以是:
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package:main'
]
},
好的,我最终在我的具体案例中找到了问题。使用 python3 setup.py install
安装时导致神秘错误的原因
pkg_resources.ResolutionError: Script 'scripts/fp_test_package.py' not found in metadata at '/usr/local/lib/python3.8/dist-packages/fp_test_package-0.0.1-py3.8.egg/EGG-INFO'
或使用 pip3 install .
安装时的等效错误
pkg_resources.ResolutionError: Script 'scripts/fp_test_package.py' not found in metadata at '/home/fabio/Desktop/test_python_package/fp-test-package/fp_test_package-0.0.1-py3.8.egg/EGG-INFO'
$PATH 变量中缺少正确启动脚本所需的路径。
总结一下,我所做的是:
- 根据 Dustin 关于
console_scripts
的建议编辑 setup.py
文件
- 从
fp-test-package
文件夹中构建和安装包 运行 pip3 install .
(或 pip3 install -e .
,如果你想要可编辑的版本)。
- 检查脚本二进制文件的创建位置
which fp_test_package
(在我的例子中是/home/fabio/.local/bin/fp_test_package
)
- 将
path
添加到 $PATH 环境变量中(在我的 .bashrc
- 和 .zshrc
中,因为我使用 zsh
- 我添加了一行 export PATH="$HOME/.local/bin:$PATH"
)
现在一切正常。
我不会删除 correct version of the repo,所以如果有人想使用工作骨架来启动项目,可以在那里找到它。
我正在尝试构建我的第一个 python 包并将其发布到 PyPi。我的目标是通过 CLI 提供某个功能,以便最终用户可以像 pip3 install my-package
这样通过 pip 安装它,并像 my-package -fa first_argument -sa second_argument
.
假设我的包裹名为 fp-test-package
。我制作了我的项目文件夹结构模型,您可以在此处找到 https://github.com/fabiopipitone/fp-test-package.
在模型中,我还作为要求插入了真实项目 (tqdm) 中所需的包之一,并保持完全相同的约定(外部文件夹和 github 存储库上的连字符,内部包下划线,相同定位和导入助手和实用程序等)。这样,如果它在模型上工作,它必须在真实项目上工作。
这是项目的目录结构
fp-test-package
├── fp_test_package
│ ├── __init__.py
│ ├── fp_test_package.py
│ ├── helpers
│ │ ├── arguments_checkers.py
│ │ ├── csv_handlers.py
│ │ └── utility_functions.py
│ └── utils
│ ├── __init__.py
│ ├── CustomLogger.py
│ └── TqdmLoggingHandler.py
├── LICENSE
├── README.rst
├── requirements.txt
├── setup.py
├── docs
└── tests
这是setup.py
from setuptools import setup, find_packages
with open("README.rst", "r") as fh:
long_description = fh.read()
setup(
name ='fp-test-package',
version ='0.0.1',
description='Simple test building a CLI tool package',
long_description=long_description,
long_description_content_type='text/x-rst',
license ='GPLv2',
packages = find_packages(),
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package.py:main'
]
},
classifiers =(
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v2",
"Operating System :: Linux",
),
keywords ='test packaging fabiopipitone',
install_requires = ['tqdm>=4.49.0'],
zip_safe = False
)
我尝试了一些关于如何构建和发布 CLI python 包的方法,然后我尝试使用 fp-test-package
目录中的 sudo python3 setup.py install
(与 setup.py).它似乎安装了软件包(我可以在 pip3 freeze
中找到条目 fp-test-package==0.0.1
)但是如果我在终端中尝试 fp-test-package
它 returns fp-test-package: command not found
,如果我试试 fp_test_package
它 returns:
Traceback (most recent call last):
File "/usr/local/bin/fp_test_package", line 11, in <module>
load_entry_point('fp-test-package==0.0.1', 'console_scripts', 'fp_test_package')()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
return ep.load()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
return self.resolve()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'fp_test_package.py'
然后我使用 sudo pip3 uninstall fp_test_package
成功卸载了软件包。我删除了之前创建的 build
、dist
和 fp_test_package.egg-info
目录并尝试使用 pip3 install -e .
(再次从 fp-test-package
内部)。它创建了 fp_test_package.egg-info
目录,但又在控制台中 运行 fp_test_package
returns
Traceback (most recent call last):
File "/usr/local/bin/fp_test_package", line 11, in <module>
load_entry_point('fp-test-package==0.0.1', 'console_scripts', 'fp_test_package')()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
return ep.load()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
return self.resolve()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'fp_test_package.py'
现在,我错过了什么?我想简单地打包并安装它,以便当用户键入 fp-test-package
或 fp_test_package
时 returns 需要 --export_path
参数的错误(意味着脚本正确开始)就像我从控制台调用它时一样:
$ python3 fp_test_package/fp_test_package.py
usage: fp_test_package.py [-h] -ep EXPORT_PATH [-sa SECOND_ARGUMENT] [-ta THIRD_ARGUMENT]
fp_test_package.py: error: the following arguments are required: -ep/--export_path
我该怎么做?
编辑:
我注意到 @Dustin 然后指出了关于 setup.py 的内容。事实上,我的一位同事 PRed 更改了 console_scripts
部分的虚拟仓库。
现在,在我的同事机器上,一切似乎都按预期工作。在我的系统中,在拉取 repo 并重新运行 python3 setup.py install
后,当从控制台调用 fp_test_package
时,它 returns 如下:
Traceback (most recent call last):
File "/usr/local/bin/fp_test_package", line 11, in <module>
load_entry_point('fp-test-package==0.0.1', 'console_scripts', 'fp_test_package')()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 490, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2854, in load_entry_point
return ep.load()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2445, in load
return self.resolve()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2451, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
File "/usr/local/bin/fp_test_package.py", line 4, in <module>
__import__('pkg_resources').run_script('fp-test-package==0.0.1', 'fp_test_package.py')
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 667, in run_script
self.require(requires)[0].run_script(script_name, ns)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 1452, in run_script
raise ResolutionError(
pkg_resources.ResolutionError: Script 'scripts/fp_test_package.py' not found in metadata at '/usr/local/lib/python3.8/dist-packages/fp_test_package-0.0.1-py3.8.egg/EGG-INFO'
有什么想法吗?
您的 setup.py
有:
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package.py:main'
]
},
这相当于以下导入:
from fp_test_package.py import main as fp_test_package
问题是您没有 fp_test_package.py
模块,您有一个包含 fp_test_package
的 fp_test_package
模块(包含 __init__.py
文件的目录)子模块(模块名称不包括扩展名)。
假设您的 fp_test_package.py
文件定义了一个 main
函数,您可以将其更改为:
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package.fp_test_package:main'
]
},
或者您可以将 main
函数移动到 fp_test_package/__init__.py
,这样它就可以是:
entry_points ={
'console_scripts': [
'fp_test_package = fp_test_package:main'
]
},
好的,我最终在我的具体案例中找到了问题。使用 python3 setup.py install
pkg_resources.ResolutionError: Script 'scripts/fp_test_package.py' not found in metadata at '/usr/local/lib/python3.8/dist-packages/fp_test_package-0.0.1-py3.8.egg/EGG-INFO'
或使用 pip3 install .
pkg_resources.ResolutionError: Script 'scripts/fp_test_package.py' not found in metadata at '/home/fabio/Desktop/test_python_package/fp-test-package/fp_test_package-0.0.1-py3.8.egg/EGG-INFO'
$PATH 变量中缺少正确启动脚本所需的路径。
总结一下,我所做的是:
- 根据 Dustin 关于
console_scripts
的建议编辑 - 从
fp-test-package
文件夹中构建和安装包 运行pip3 install .
(或pip3 install -e .
,如果你想要可编辑的版本)。 - 检查脚本二进制文件的创建位置
which fp_test_package
(在我的例子中是/home/fabio/.local/bin/fp_test_package
) - 将
path
添加到 $PATH 环境变量中(在我的.bashrc
- 和.zshrc
中,因为我使用zsh
- 我添加了一行export PATH="$HOME/.local/bin:$PATH"
)
setup.py
文件
现在一切正常。 我不会删除 correct version of the repo,所以如果有人想使用工作骨架来启动项目,可以在那里找到它。