除非 --public 传递给上传命令,否则如何禁止将包上传到 PyPi
How to disable uploading a package to PyPi unless --public is passed to the upload command
我正在开发包并将我的包的 development/testing/etc 版本上传到本地 devpi 服务器。
为了防止意外上传到PyPi,我采用了以下常见做法:
setup(...,
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Private :: Do not Upload"
],
...)
效果很好,但是当我终于准备好将包上传到 PyPi 时呢?
我想出了一个非常丑陋但简单的 hack,它要求我将分类器定义为 setup() 调用之外的全局变量,如下所示:
CLASSIFIERS = [
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7"
]
if "--public" not in sys.argv:
CLASSIFIERS.append("Private :: Do Not Upload")
else:
sys.argv.remove("--public")
setup(...
classifiers=CLASSIFIERS,
...)
另一个可能更简单的选择是仅注释掉 "Private :: Do not Upload",但这似乎并不比我的 hack 更专业。
我 喜欢 做的是创建一个名为 SafeUpload
的上传命令的适当子类,并让它检查 --public
cmd-行选项。也许,由于在上传之前可能存在构建,SafeBuild
可能是更好的选择。
不幸的是,我无法理解关于创建自定义命令的 setuptools 文档。
有人知道如何实现吗?我不清楚自定义命令是否可以访问传递给 setup()
的参数,即它是否可以直接操作传递给 setup()
的 classifiers
,或者如果它需要用户该命令遵循将 CLASSIFIERS 定义为全局变量的约定 yuck?
回溯你的问题;虽然它确实很广泛,但主题仍然足够局限。
我可以告诉你 classifier 不是被操纵的,而是从 PKG-INFO
文件中读取然后通过 egg_info
命令写入到 PKG-INFO
文件中,该命令依次查找所有 egg_info.writers
entry_points setuptools.command.egg_info:write_pkg_info
function will do the actual writing. As far as I can tell, trying to leverage that Classifier outside will not be a great way, however you can override everything and anything you want through setuptools
so you can make your own write_pkg_info
function, figure out how to read the metadata (which you can see in the main distutils.command.upload:upload.upload_file
方法)并在 upload_file 最终读取它之前进一步操作它。在这一点上,您可能认为操纵和使用这个系统会很烦人。
正如我提到的,一切都可以被覆盖。您可以制作一个带有 public 标志的上传命令,如下所示:
from distutils.log import warn
from distutils.command.upload import upload as orig
# alternatively, for later versions of setuptools:
# from setuptools.command.upload import upload as orig
class upload(orig):
description = "customized upload command"
user_options = orig.user_options + [
('public', None,
'make package public on pypi'),
]
def initialize_options(self):
orig.initialize_options(self)
self.public = False
def run(self):
if not self.public:
warn('not public, not uploading')
return
return orig.run(self)
附带的 setup.py
可能看起来像这样。
from setuptools import setup
setup(
name='my_pypi_uploader',
version='0.0',
description='"safer" pypi uploader',
py_modules=['my_pypi_uploader'], # assuming above file is my_py_uploader.py
entry_points={
'distutils.commands': [
'upload = my_pypi_uploader:upload',
],
},
)
将其作为一个包安装到您的环境中,上传命令将被您的版本替换。例子 运行:
$ python setup.py upload
running upload
not public, not uploading
使用 public 标志重试
$ python setup.py upload --public
running upload
error: No dist file created in earlier command
这很好,因为我根本没有创建任何 dist 文件。您当然可以通过重写 upload_file
方法(在您的代码中复制)并更改部分以在您的 subclass 中执行您想要的操作来进一步扩展该命令(例如注入私有 classifier 那里),由你决定。
您可能还想知道为什么 class 名称是小写的(违反 pep8),这是由于遗留问题以及给定命令的帮助是如何生成的。
$ python setup.py upload --help
...
Options for 'upload' command:
使用名为 class 的 "properly"(例如 SafeUpload
;记得还要更新 setup.py
中的 entry_point
以指向这个新的 class名字)
$ python setup.py upload --help
...
Options for 'SafeUpload' command:
当然,如果此输出是意图,则可以改用标准 class 命名约定。
老实说,您根本不应该在生产环境中指定上传,而是在您的构建服务器上作为 post-push 挂钩的一部分执行此操作,因此当项目被推送(或tagged),构建完成并将文件加载到您的私人服务器上,然后只有进一步的手动干预(或者如果推送特定标签则自动干预)才能将包上传到 pypi。然而,上面的例子应该让你开始你最初打算做的事情。
最后一件事:如果未设置 --public
标志,您 可以 将 self.repository
更改为您的私有 devpi 位置。您可以在调用 orig.upload_file
方法(通过您的自定义版本)之前覆盖它,或者在 run
中进行;因此,与其退出,您的代码还可以验证存储库 url 不是 public PyPI 实例。或者,通过 self.distribution.metadata
(self
是 upload
实例)操纵分发元数据(即 classifier)。您当然可以创建一个全新的命令来尽情发挥它(通过创建一个新的 Command
subclass,并为此添加一个新的 entry_point)。
我正在开发包并将我的包的 development/testing/etc 版本上传到本地 devpi 服务器。
为了防止意外上传到PyPi,我采用了以下常见做法:
setup(...,
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Private :: Do not Upload"
],
...)
效果很好,但是当我终于准备好将包上传到 PyPi 时呢?
我想出了一个非常丑陋但简单的 hack,它要求我将分类器定义为 setup() 调用之外的全局变量,如下所示:
CLASSIFIERS = [
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7"
]
if "--public" not in sys.argv:
CLASSIFIERS.append("Private :: Do Not Upload")
else:
sys.argv.remove("--public")
setup(...
classifiers=CLASSIFIERS,
...)
另一个可能更简单的选择是仅注释掉 "Private :: Do not Upload",但这似乎并不比我的 hack 更专业。
我 喜欢 做的是创建一个名为 SafeUpload
的上传命令的适当子类,并让它检查 --public
cmd-行选项。也许,由于在上传之前可能存在构建,SafeBuild
可能是更好的选择。
不幸的是,我无法理解关于创建自定义命令的 setuptools 文档。
有人知道如何实现吗?我不清楚自定义命令是否可以访问传递给 setup()
的参数,即它是否可以直接操作传递给 setup()
的 classifiers
,或者如果它需要用户该命令遵循将 CLASSIFIERS 定义为全局变量的约定 yuck?
回溯你的问题;虽然它确实很广泛,但主题仍然足够局限。
我可以告诉你 classifier 不是被操纵的,而是从 PKG-INFO
文件中读取然后通过 egg_info
命令写入到 PKG-INFO
文件中,该命令依次查找所有 egg_info.writers
entry_points setuptools.command.egg_info:write_pkg_info
function will do the actual writing. As far as I can tell, trying to leverage that Classifier outside will not be a great way, however you can override everything and anything you want through setuptools
so you can make your own write_pkg_info
function, figure out how to read the metadata (which you can see in the main distutils.command.upload:upload.upload_file
方法)并在 upload_file 最终读取它之前进一步操作它。在这一点上,您可能认为操纵和使用这个系统会很烦人。
正如我提到的,一切都可以被覆盖。您可以制作一个带有 public 标志的上传命令,如下所示:
from distutils.log import warn
from distutils.command.upload import upload as orig
# alternatively, for later versions of setuptools:
# from setuptools.command.upload import upload as orig
class upload(orig):
description = "customized upload command"
user_options = orig.user_options + [
('public', None,
'make package public on pypi'),
]
def initialize_options(self):
orig.initialize_options(self)
self.public = False
def run(self):
if not self.public:
warn('not public, not uploading')
return
return orig.run(self)
附带的 setup.py
可能看起来像这样。
from setuptools import setup
setup(
name='my_pypi_uploader',
version='0.0',
description='"safer" pypi uploader',
py_modules=['my_pypi_uploader'], # assuming above file is my_py_uploader.py
entry_points={
'distutils.commands': [
'upload = my_pypi_uploader:upload',
],
},
)
将其作为一个包安装到您的环境中,上传命令将被您的版本替换。例子 运行:
$ python setup.py upload
running upload
not public, not uploading
使用 public 标志重试
$ python setup.py upload --public
running upload
error: No dist file created in earlier command
这很好,因为我根本没有创建任何 dist 文件。您当然可以通过重写 upload_file
方法(在您的代码中复制)并更改部分以在您的 subclass 中执行您想要的操作来进一步扩展该命令(例如注入私有 classifier 那里),由你决定。
您可能还想知道为什么 class 名称是小写的(违反 pep8),这是由于遗留问题以及给定命令的帮助是如何生成的。
$ python setup.py upload --help
...
Options for 'upload' command:
使用名为 class 的 "properly"(例如 SafeUpload
;记得还要更新 setup.py
中的 entry_point
以指向这个新的 class名字)
$ python setup.py upload --help
...
Options for 'SafeUpload' command:
当然,如果此输出是意图,则可以改用标准 class 命名约定。
老实说,您根本不应该在生产环境中指定上传,而是在您的构建服务器上作为 post-push 挂钩的一部分执行此操作,因此当项目被推送(或tagged),构建完成并将文件加载到您的私人服务器上,然后只有进一步的手动干预(或者如果推送特定标签则自动干预)才能将包上传到 pypi。然而,上面的例子应该让你开始你最初打算做的事情。
最后一件事:如果未设置 --public
标志,您 可以 将 self.repository
更改为您的私有 devpi 位置。您可以在调用 orig.upload_file
方法(通过您的自定义版本)之前覆盖它,或者在 run
中进行;因此,与其退出,您的代码还可以验证存储库 url 不是 public PyPI 实例。或者,通过 self.distribution.metadata
(self
是 upload
实例)操纵分发元数据(即 classifier)。您当然可以创建一个全新的命令来尽情发挥它(通过创建一个新的 Command
subclass,并为此添加一个新的 entry_point)。