Как мне написать setup.py для плагина twistd / twisted, который работает с setuptools, распространяет и т. Д.? - PullRequest
26 голосов
/ 01 сентября 2011

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *.

Однако, из-за структуры системы плагинов (плагины помещаются в каталог витых / плагинов, который должен не быть пакетом Python), написав надлежащий setup.py для установки этих плагинов.Плагины, кажется, нетривиальны.

Я видел несколько попыток добавить 'twisted.plugins' к ключу 'packages' команды установки distutils, но так как это не совсем пакет, плохие вещислучается (например, __init__.py услужливо добавляется некоторыми инструментами).

Другие попытки, кажется, вместо этого используют 'package_data' (например, http://bazaar.launchpad.net/~glyph/divmod.org/trunk/view/head:/Epsilon/epsilon/setuphelper.py),, но это также может привести к неудаче странным образом.

Вопрос: кто-нибудь успешно написал setup.py для установки витых плагинов, который работает во всех случаях?

Ответы [ 4 ]

17 голосов
/ 23 сентября 2011

Я описываю ниже файл setup.py, который необходим, только если у вас есть пользователи с pip <1.2 (например, в Ubuntu 12.04).Если у всех есть пип 1.2 или новее, вам нужно только <code>packages=[..., 'twisted.plugins'].

. Запретив пункту написать строку "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 install, pip install --user и easy_install.При любом способе установки вышеприведенные monkeypatch и pip uninstall работают нормально.

Вы можете спросить: нужно ли мне очищать monkeypatch, чтобы не испортить следующую установку?(например, pip install --no-deps MyPackage Twisted; вы не хотели бы влиять на top_level.txt Twisted.) Ответ - нет;monkeypatch не влияет на другую установку, потому что pip порождает новый python для каждой установки.

Связанный: имейте в виду, что в вашем проекте вы должны не иметьфайл twisted/plugins/__init__.py.Если вы видите это предупреждение во время установки:

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

, оно совершенно нормально, и вы должны не попытаться исправить его, добавив __init__.py.

3 голосов
/ 02 сентября 2011

Вот запись в блоге, в которой описывается, как делать это с 'package_data':

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

Каким странным образом это может потерпеть неудачу? Может произойти сбой, если установка пакета не поместит данные пакета в каталог, который находится в sys.path. В этом случае загрузчик плагинов Twisted не найдет его. Однако все установки пакетов Python, о которых я знаю, помещают его в тот же каталог, в который устанавливаются модули или пакеты Python, так что это не составит проблемы.

2 голосов
/ 21 сентября 2011

Возможно, вы могли бы адаптировать идею package_data для использования data_files: для этого вам не потребуется перечислять twisted.plugins в качестве пакета, поскольку он использует абсолютные пути.Однако это все равно было бы клуджем.

Мои тесты с чистым distutils показали, что возможно перезаписать файлы из другого дистрибутива.Я хотел протестировать пакеты пространства имен бедного человека, используя pkgutil.extend_path и distutils, и оказалось, что я могу установить spam/ham/__init__.py с spam.ham / setup.py и spam/eggs/__init__.py с spam.eggs / setup.py.Каталоги не проблема, но файлы будут успешно перезаписаны.Я думаю, что это на самом деле неопределенное поведение в distutils, которое накапливается до setuptools и pip, поэтому pip может закрывать IMO как wontfix.

Каков обычный способ установки Twisted плагинов?Брось сюда вручную?

1 голос
/ 28 ноября 2013

Я использую этот подход:

  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
    )
    
...