如何为与 setuptools、distribute 等配合使用的 twind/twisted 插件编写 setup.py?

发布于 2024-12-02 16:17:41 字数 705 浏览 1 评论 0原文

Twisted 插件系统 是编写可扩展扭曲应用程序的首选方式。

然而,由于插件系统的结构方式(插件进入twisted/plugins目录,该目录不应该是Python包),编写适当的setup.py来安装这些插件似乎是不可行的。 -琐碎的。

我已经看到一些尝试将“twisted.plugins”添加到 distutils setup 命令的“packages”键中,但由于它不是真正的包,因此会发生不好的事情(例如, __init__.py 由某些工具添加很有帮助)。

其他尝试似乎使用“package_data”代替(例如,http://bazaar.launchpad.net/~glyph/divmod.org/trunk/view/head:/Epsilon/epsilon/setuphelper.py),但这也可能会以奇怪的方式失败方式。

问题是:有没有人成功编写了一个 setup.py 来安装在所有情况下都有效的扭曲插件?

The Twisted Plugin System is the preferred way to write extensible twisted applications.

However, due to the way the plugin system is structured (plugins go into a twisted/plugins directory which should not be a Python package), writing a proper setup.py for installing those plugins appears to be non-trivial.

I've seen some attempts that add 'twisted.plugins' to the 'packages' key of the distutils setup command, but since it is not really a package, bad things happen (for example, an __init__.py is helpfully added by some tools).

Other attempts seem to use 'package_data' instead (eg, http://bazaar.launchpad.net/~glyph/divmod.org/trunk/view/head:/Epsilon/epsilon/setuphelper.py), but that can also fail in weird ways.

The question is: has anyone successfully written a setup.py for installing twisted plugins which works in all cases?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

雪花飘飘的天空 2024-12-09 16:17:41

我在下面记录了一个 setup.py ,仅当您的用户使用 pip < 时才需要该文件。 1.2(例如在 Ubuntu 12.04 上)。如果每个人都有 pip 1.2 或更高版本,那么您唯一需要的是 packages=[..., 'twisted.plugins']

通过阻止 pip 将“twisted”行写入 .egg-info/top_level.txt,您可以继续使用 packages=[..., 'twisted .plugins'] 并有一个有效的 pip uninstall,但不会删除所有 twisted/。这涉及到 setup.py 顶部附近的 setuptools/distribute 进行猴子修补。这是一个示例 setup.py

from distutils.core import setup

# When pip installs anything from packages, py_modules, or ext_modules that
# includes a twistd plugin (which are installed to twisted/plugins/),
# setuptools/distribute writes a Package.egg-info/top_level.txt that includes
# "twisted".  If you later uninstall Package with `pip uninstall Package`,
# pip <1.2 removes all of twisted/ instead of just Package's twistd plugins.
# See https://github.com/pypa/pip/issues/355 (now fixed)
#
# To work around this problem, we monkeypatch
# setuptools.command.egg_info.write_toplevel_names to not write the line
# "twisted".  This fixes the behavior of `pip uninstall Package`.  Note that
# even with this workaround, `pip uninstall Package` still correctly uninstalls
# Package's twistd plugins from twisted/plugins/, since pip also uses
# Package.egg-info/installed-files.txt to determine what to uninstall,
# and the paths to the plugin files are indeed listed in installed-files.txt.
try:
    from setuptools.command import egg_info
    egg_info.write_toplevel_names
except (ImportError, AttributeError):
    pass
else:
    def _top_level_package(name):
        return name.split('.', 1)[0]

    def _hacked_write_toplevel_names(cmd, basename, filename):
        pkgs = dict.fromkeys(
            [_top_level_package(k)
                for k in cmd.distribution.iter_distribution_names()
                if _top_level_package(k) != "twisted"
            ]
        )
        cmd.write_file("top-level names", filename, '\n'.join(pkgs) + '\n')

    egg_info.write_toplevel_names = _hacked_write_toplevel_names

setup(
    name='MyPackage',
    version='1.0',
    description="You can do anything with MyPackage, anything at all.",
    url="http://example.com/",
    author="John Doe",
    author_email="[email protected]",
    packages=['mypackage', 'twisted.plugins'],
    # You may want more options here, including install_requires=,
    # package_data=, and classifiers=
)

# Make Twisted regenerate the dropin.cache, if possible.  This is necessary
# because in a site-wide install, dropin.cache cannot be rewritten by
# normal users.
try:
    from twisted.plugin import IPlugin, getPlugins
except ImportError:
    pass
else:
    list(getPlugins(IPlugin))

我已经使用 pip installpip install --usereasy_install< 对此进行了测试/代码>。使用任何安装方法,上面的 Monkeypatch 和 pip uninstall 都可以正常工作。

您可能想知道:我是否需要清除猴子补丁以避免搞乱下次安装? (例如pip install --no-deps MyPackage Twisted;您不想影响Twisted的top_level.txt。)答案是否定的; Monkeypatch 不会影响其他安装,因为 pip 会为每次安装生成一个新的 python

相关:请记住,在您的项目中,您必须 有一个文件 twisted/plugins/__init__.py。如果您在安装过程中看到此警告:

package init file 'twisted/plugins/__init__.py' not found (or not a regular file)

这是完全正常的,您不应该尝试通过添加 __init__.py 来修复它。

I document a setup.py below that is needed only if you have users with pip < 1.2 (e.g. on Ubuntu 12.04). If everyone has pip 1.2 or newer, the only thing you need is packages=[..., 'twisted.plugins'].

By preventing pip from writing the line "twisted" to .egg-info/top_level.txt, you can keep using packages=[..., 'twisted.plugins'] and have a working pip uninstall that doesn't remove all of twisted/. This involves monkeypatching setuptools/distribute near the top of your setup.py. Here is a sample setup.py:

from distutils.core import setup

# When pip installs anything from packages, py_modules, or ext_modules that
# includes a twistd plugin (which are installed to twisted/plugins/),
# setuptools/distribute writes a Package.egg-info/top_level.txt that includes
# "twisted".  If you later uninstall Package with `pip uninstall Package`,
# pip <1.2 removes all of twisted/ instead of just Package's twistd plugins.
# See https://github.com/pypa/pip/issues/355 (now fixed)
#
# To work around this problem, we monkeypatch
# setuptools.command.egg_info.write_toplevel_names to not write the line
# "twisted".  This fixes the behavior of `pip uninstall Package`.  Note that
# even with this workaround, `pip uninstall Package` still correctly uninstalls
# Package's twistd plugins from twisted/plugins/, since pip also uses
# Package.egg-info/installed-files.txt to determine what to uninstall,
# and the paths to the plugin files are indeed listed in installed-files.txt.
try:
    from setuptools.command import egg_info
    egg_info.write_toplevel_names
except (ImportError, AttributeError):
    pass
else:
    def _top_level_package(name):
        return name.split('.', 1)[0]

    def _hacked_write_toplevel_names(cmd, basename, filename):
        pkgs = dict.fromkeys(
            [_top_level_package(k)
                for k in cmd.distribution.iter_distribution_names()
                if _top_level_package(k) != "twisted"
            ]
        )
        cmd.write_file("top-level names", filename, '\n'.join(pkgs) + '\n')

    egg_info.write_toplevel_names = _hacked_write_toplevel_names

setup(
    name='MyPackage',
    version='1.0',
    description="You can do anything with MyPackage, anything at all.",
    url="http://example.com/",
    author="John Doe",
    author_email="[email protected]",
    packages=['mypackage', 'twisted.plugins'],
    # You may want more options here, including install_requires=,
    # package_data=, and classifiers=
)

# Make Twisted regenerate the dropin.cache, if possible.  This is necessary
# because in a site-wide install, dropin.cache cannot be rewritten by
# normal users.
try:
    from twisted.plugin import IPlugin, getPlugins
except ImportError:
    pass
else:
    list(getPlugins(IPlugin))

I've tested this with pip install, pip install --user, and easy_install. With any install method, the above monkeypatch and pip uninstall work fine.

You might be wondering: do I need to clear the monkeypatch to avoid messing up the next install? (e.g. pip install --no-deps MyPackage Twisted; you wouldn't want to affect Twisted's top_level.txt.) The answer is no; the monkeypatch does not affect another install because pip spawns a new python for each install.

Related: keep in mind that in your project, you must not have a file twisted/plugins/__init__.py. If you see this warning during installation:

package init file 'twisted/plugins/__init__.py' not found (or not a regular file)

it is completely normal and you should not try to fix it by adding an __init__.py.

手心的温暖 2024-12-09 16:17:41

以下是一篇博客文章,描述了如何使用“package_data”进行操作:

http://chrismiles.livejournal.com/23399 .html

会以什么奇怪的方式失败?如果包的安装未将包数据放入 sys.path 上的目录中,则可能会失败。在这种情况下,Twisted 插件加载器将找不到它。但是,据我所知,所有 Python 包的安装都会将其放入安装 Python 模块或包本身的同一目录中,因此这不会成为问题。

Here is a blog entry which describes doing it with 'package_data':

http://chrismiles.livejournal.com/23399.html

In what weird ways can that fail? It could fail if the installation of the package doesn't put the package data into a directory which is on the sys.path. In that case the Twisted plugin loader wouldn't find it. However, all installations of Python packages that I know of will put it into the same directory where they are installing the Python modules or packages themselves, so that won't be a problem.

二智少女 2024-12-09 16:17:41

也许您可以调整 package_data 的想法来使用 data_files :它不需要您将 twins.plugins 列为包,因为它使用绝对路径。不过,这仍然是一个杂凑。

我对纯 distutils 的测试告诉我,可以覆盖另一个发行版的文件。我想使用 pkgutil.extend_path 和 distutils 测试穷人的命名空间包,结果证明我可以使用 spam.ham/setup.py 和 spam 安装 spam/ham/__init__.py 。 /eggs/__init__.py 与 spam.eggs/setup.py。目录不是问题,但文件会被愉快地覆盖。我认为这实际上是 distutils 中未定义的行为,它会渗透到 setuptools 和 pip,因此在我看来,pip 可以像不会修复一样关闭。

安装 Twisted 插件的常用方法是什么?用手把它扔到这里?

Maybe you could adapt the package_data idea to use data_files instead: it wouldn’t require you to list twisted.plugins as package, as it uses absolute paths. It would still be a kludge, though.

My tests with pure distutils have told me that its is possible to overwrite files from another distribution. I wanted to test poor man’s namespace packages using pkgutil.extend_path and distutils, and it turns out that I can install spam/ham/__init__.py with spam.ham/setup.py and spam/eggs/__init__.py with spam.eggs/setup.py. Directories are not a problem, but files will be happily overwritten. I think this is actually undefined behavior in distutils which trickles up to setuptools and pip, so pip could IMO close as wontfix.

What is the usual way to install Twisted plugins? Drop-it-here by hand?

泛滥成性 2024-12-09 16:17:41

我使用这种方法:

  1. 将文件的“.py”和“.pyc”版本放入“twisted/plugins/”文件夹中包裹。
    请注意,“.pyc”文件可以为空,它应该存在。
  2. setup.py中指定将两个文件复制到库文件夹(确保不会覆盖现有插件!)。例如:

    <前><代码># setup.py

    从 distutils 导入 sysconfig

    LIB_PATH = sysconfig.get_python_lib()

    # ...

    plugin_name = '/twisted/plugins/'
    # '.pyc' 扩展名是正确删除插件所必需的
    数据文件 = [
    (os.path.join(LIB_PATH, '扭曲', '插件'),
    [''.join((plugin_name, extension)) 用于 ('.py', '.pyc') 中的扩展])
    ]

    设置(
    # ...
    数据文件=数据文件

I use this approach:

  1. Put '.py' and '.pyc' versions of your file to "twisted/plugins/" folder inside your package.
    Note that '.pyc' file can be empty, it just should exist.
  2. In setup.py specify copying both files to a library folder (make sure that you will not overwrite existing plugins!). For example:

    # setup.py
    
    from distutils import sysconfig
    
    LIB_PATH = sysconfig.get_python_lib()
    
    # ...
    
    plugin_name = '<your_package>/twisted/plugins/<plugin_name>'
    # '.pyc' extension is necessary for correct plugins removing
    data_files = [
      (os.path.join(LIB_PATH, 'twisted', 'plugins'),
       [''.join((plugin_name, extension)) for extension in ('.py', '.pyc')])
    ]
    
    setup(
          # ...
          data_files=data_files
    )
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文