26

Twisted Plugin System是编写可扩展的twisted 应用程序的 首选方式。

然而,由于插件系统的结构方式(插件进入一个应该是 Python 包的 twisted/plugins 目录),编写一个合适的 setup.py 来安装这些插件似乎并不简单。

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

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

问题是:是否有人成功编写了 setup.py 来安装适用于所有情况的扭曲插件?

4

4 回答 4

17

我在下面记录了一个 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. 这是一个示例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="jdoe@example.com",
    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 --user测试easy_install。使用任何安装方法,上面的猴子补丁都pip uninstall可以正常工作。

您可能想知道:我是否需要清除monkeypatch 以避免弄乱下一次安装?(例如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.

于 2011-09-23T06:34:42.507 回答
3

这是一个博客条目,描述了使用“package_data”进行操作:

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

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

于 2011-09-01T21:15:50.603 回答
2

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

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

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

于 2011-09-21T15:43:15.913 回答
1

我使用这种方法:

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

    # 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
    )
    
于 2013-11-28T13:06:10.643 回答