setup python twisted setuptools distutils distribute

python - ¿Cómo escribo un setup.py para un plugin twistd/twisted que funciona con setuptools, distribuye, etc.?



setuptools windows 10 (4)

El Twisted Plugin System es la forma preferida de escribir aplicaciones retorcidas extensibles.

Sin embargo, debido a la forma en que está estructurado el sistema de complementos (los complementos entran en un directorio torcido / complementos que no debería ser un paquete de Python), escribir un setup.py apropiado para instalar esos complementos parece no ser trivial.

He visto algunos intentos que agregan ''twisted.plugins'' a la clave de ''paquetes'' del comando de configuración distutils, pero como no es realmente un paquete, suceden cosas malas (por ejemplo, algunos __init__.py son útiles para algunos herramientas).

Otros intentos parecen usar ''package_data'' en su lugar (por ejemplo, http://bazaar.launchpad.net/~glyph/divmod.org/trunk/view/head:/Epsilon/epsilon/setuphelper.py ), pero eso también puede fallar en formas extrañas

La pregunta es: ¿alguien ha escrito con éxito un setup.py para instalar complementos trenzados que funcione en todos los casos?


Aquí hay una entrada de blog que describe cómo hacerlo con ''package_data'':

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

¿De qué maneras extrañas puede fallar eso? Podría fallar si la instalación del paquete no coloca los datos del paquete en un directorio que se encuentra en sys.path. En ese caso, el cargador de plugins Twisted no lo encontraría. Sin embargo, todas las instalaciones de paquetes de Python que conozco lo colocarán en el mismo directorio donde están instalando los módulos o paquetes de Python, por lo que no será un problema.


Documento un setup.py a continuación que se necesita solo si tiene usuarios con pip <1.2 (por ejemplo, en Ubuntu 12.04). Si todo el mundo tiene pip 1.2 o más reciente, lo único que necesita es packages=[..., ''twisted.plugins''] .

Al evitar que pip escriba la línea " twisted " en .egg-info/top_level.txt , puede seguir usando packages=[..., ''twisted.plugins''] y tener una pip uninstall activa que no elimine todo twisted/ . Esto involucra la instalación de herramientas de instalación / distribución cerca de la parte superior de su setup.py . Aquí hay un ejemplo de 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))

He probado esto con pip install , pip install --user , y easy_install . Con cualquier método de instalación, la pip uninstall Monkeypatch y pip uninstall funciona bien.

Quizás se esté preguntando: ¿necesito borrar el Monkeypatch para evitar estropear la próxima instalación? (por ejemplo, pip install --no-deps MyPackage Twisted ; no querrás afectar el top_level.txt de Twisted). La respuesta es no; El monkeypatch no afecta a otra instalación porque pip genera un nuevo python para cada instalación.

Relacionado: tenga en cuenta que en su proyecto, no debe tener un archivo twisted/plugins/__init__.py . Si ve esta advertencia durante la instalación:

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

es completamente normal y no debe intentar arreglarlo agregando un __init__.py .


Tal vez podría adaptar la idea package_data para usar data_files en su lugar: no requeriría que enumere twisted.plugins como paquete, ya que usa rutas absolutas. Sin embargo, todavía sería un kludge.

Mis pruebas con distutils puros me han dicho que es posible sobrescribir archivos de otra distribución. Quería probar los paquetes de espacio de nombres de los pobres usando pkgutil.extend_path y distutils, y resulta que puedo instalar spam/ham/__init__.py con spam.ham / setup.py y spam/eggs/__init__.py with spam.eggs /setup.py. Los directorios no son un problema, pero los archivos se sobrescribirán felizmente. Creo que este es en realidad un comportamiento indefinido en distutils que se escurre hasta setuptools y pip, por lo que pip podría IMO cerrar como wontfix.

¿Cuál es la forma habitual de instalar complementos Twisted? Drop-it-here a mano?


Yo uso este enfoque:

  1. Coloque las versiones '' .py '' y '' .pyc '' de su archivo en la carpeta " twisted/plugins/ " dentro de su paquete. Tenga en cuenta que el archivo '' .pyc '' puede estar vacío, simplemente debería existir.
  2. En setup.py especifique copiar ambos archivos a una carpeta de la biblioteca (asegúrese de no sobrescribir los complementos existentes). Por ejemplo:

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