【问题标题】:How to disable uploading a package to PyPi unless --public is passed to the upload command除非将 --public 传递给上传命令,否则如何禁用将包上传到 PyPi
【发布时间】:2017-01-24 01:30:42
【问题描述】:

我正在开发包并将我的包的开发/测试/等版本上传到本地 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 :: 不要上传”,但这似乎并不比我的 hack 更专业。

喜欢要做的是创建一个名为SafeUpload 的上传命令的适当子类,并让它检查--public cmd-line 选项。也许,由于上传之前可能存在构建,SafeBuild 可能是更好的选择。

很遗憾,我无法理解有关创建自定义命令的 setuptools 文档。

有人知道如何实现吗?我不清楚自定义命令是否可以访问传递给setup() 的参数,即它是否可以直接操纵传递给setup()classifiers,或者如果它要求命令的用户遵循以下约定将 CLASSIFIERS 定义为全局变量 yuck?

【问题讨论】:

    标签: python setuptools pypi devpi


    【解决方案1】:

    回溯你的问题;虽然它确实很广泛,但主题仍然足够有限。

    我可以告诉你,分类器不是被操纵的,而是通过egg_info 命令从PKG-INFO 文件中读取然后写入egg_info 命令,该命令依次查找setuptools.command.egg_info:write_pkg_info 函数的所有egg_info.writers entry_points会做实际的写作。据我所知,尝试在外部利用该分类器并不是一个好方法,但是您可以通过setuptools 覆盖您想要的 everythinganything,这样您就可以制作自己的write_pkg_info 函数,弄清楚如何使用read the metadata(您可以在主要的distutils.command.upload:upload.upload_file 方法中看到)并在upload_file 最终读取它之前对其进行进一步操作。在这一点上,您可能会认为操纵和使用这个系统会很烦人。

    正如我所提到的,一切都可以被覆盖。您可以制作一个带有公共标志的上传命令,如下所示:

    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
    

    用公共标志再试一次

    $ python setup.py upload --public
    running upload
    error: No dist file created in earlier command
    

    这很好,因为我根本没有创建任何 dist 文件。您当然可以通过重写 upload_file 方法(在您的代码中制作副本)进一步扩展该命令,并更改部分以在您的子类中执行您想要的操作(例如在那里注入私有分类器),由您决定。

    您可能还想知道为什么类名是小写的(违反 pep8),这是由于遗留问题以及如何生成给定命令的帮助。

    $ python setup.py upload --help
    ...
    Options for 'upload' command:
    

    使用“正确”命名的类(例如SafeUpload;记得同时更新setup.py 中的entry_point 以指向这个新的类名)

    $ python setup.py upload --help
    ...
    Options for 'SafeUpload' command:
    

    当然,如果此输出是意图,则可以使用标准类命名约定。

    老实说,您根本不应该在生产中指定上传,而是在构建服务器上执行此操作作为 post-push 挂钩的一部分,因此当项目被推送(或标记)时,构建完成并且文件被加载到您的私人服务器上,然后只有进一步的手动干预(或者如果推送特定标签,则自动)才能将包上传到 pypi。然而,上面的例子应该让你开始你最初打算做的事情。

    最后一件事:如果未设置 --public 标志,您可以只需将 self.repository 更改为您的私有 devpi 位置。您可以在调用orig.upload_file 方法之前覆盖它(通过您的自定义版本),或者在run 中执行它;因此,您的代码可以验证存储库 url 不是公共 PyPI 实例,而不是退出。或者,通过self.distribution.metadataselfupload 实例)操作分发元数据(即分类器)。你当然可以创建一个全新的命令来玩这个你的心的内容(通过创建一个新的Command 子类,并为此添加一个新的入口点)。

    【讨论】:

    • 只是想确保我清楚地理解这一点。将包 my_pypi_uploader 安装到我的环境中是否会覆盖我可能在该环境中开发的所有包的默认 setuptools 上传命令?我想我必须导入它或其他东西。我注意到这是酷还是可怕......
    • 这正是entry_point 系统的工作方式,所以如果包在环境中(即sys.path),它的入口点将被拾取,setuptools 将利用它(事实上,在setuptools 的最新版本中,upload 命令实际上是distutils 的覆盖版本,因此我在评论中有替代导入)。当然,这意味着安装提供格式错误的 distutils entry_points 的软件包可能会导致坏事发生。
    猜你喜欢
    • 2018-05-06
    • 2020-05-03
    • 2012-08-06
    • 2017-11-14
    • 2018-07-26
    • 2013-04-09
    • 1970-01-01
    • 2010-10-21
    • 2014-01-30
    相关资源
    最近更新 更多