我如何为一个与setuptools, distribute等一起工作的twistd/twisted插件编写setup.p



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

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

我看到一些人试图添加"扭曲"。在distutils安装命令的'packages'键中添加plugins',但是因为它不是一个真正的包,所以会发生不好的事情(例如,__init__.py是由一些工具添加的)。

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

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

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

通过防止pip将行"twisted"写入.egg-info/top_level.txt,您可以继续使用packages=[..., 'twisted.plugins']并拥有一个不删除所有twisted/的工作pip uninstall。这涉及到在setup.py顶部附近的monkeypatching setuptools/distribution。以下是示例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 install, pip install --usereasy_install测试了这一点。使用任何安装方法,上面的monkeypatch和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来修复它。

这是一个博客条目,描述了如何使用'package_data':

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

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

也许您可以将package_data的想法改为使用data_files:它不需要您列出twisted。插件作为包,因为它使用绝对路径。但它仍然是一个拼凑。

我对纯distutils的测试告诉我,可以覆盖来自另一个发行版的文件。我想用pkgutil测试poor man的命名空间包。我可以用spam.ham/setup.py安装spam/ham/__init__.py,用spam.eggs/setup.py安装spam/eggs/__init__.py。目录不是问题,但文件将很高兴被覆盖。我认为这实际上是distutils中未定义的行为,它会渗透到setuptools和pip中,所以pip可以在IMO中关闭为wontfix。

通常安装Twisted插件的方法是什么?亲手放在这里吗?

我使用这种方法:

  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
    )
    

相关内容

  • 没有找到相关文章

最新更新