как использовать distutils для создания исполняемого zip-файла?

#python #distutils #python-2.6

#питон #искажения #python-2.6 #python #distutils

Вопрос:

Python 2.6 и выше имеет возможность прямого выполнения zip-файла, если zip-файл содержит __main__.py файл в верхней части zip-архива. Я хочу использовать эту функцию для предоставления предварительных версий разрабатываемого мной инструмента, который не потребует от пользователей установки чего-либо, кроме копирования zip-файла на свой диск. Существует ли стандартный способ создания такого zip-файла? Я ищу решение, которое работает с python 2.6 и python 2.7.

В идеале я хотел бы использовать distutils, поскольку он у меня уже работает, когда я хочу выполнить обычную установку. Существует ли канонический способ использования (или расширения) distutils для создания такого zip-файла?

distutils предоставляет sdist команду, которая создает исходный дистрибутив, который почти правильный, но создает структуру, которая немного слишком глубока.

Например, мое дерево исходных текстов выглядит следующим образом:

 my_package/
  - setup.py
  - src/
      - __main__.py
      - module1/
      - module2/
      - module3/
  

Когда я это делаю python setup.py sdist , в итоге получается zip-файл со следующей структурой:

 my_package-0.1.zip
  - my_package-0.1/
      - README.txt
      - PKG_INFO
      - src/
          - __main__.py
          - module1/
          - module2/
          - module3/
  

Это не исполняемый файл, потому что __main__.py он не находится в верхней части дистрибутива. Фактически, то, что я хочу, — это дистрибутив src, который не включает src , а только файлы под src . Это, или именно то, что sdist дает мне, но с добавлением __main__.py в верхней части архива.

Ответ №1:

Обновлено: поскольку setup.cfg это глобальное, это влияет на настройку ‘install-lib’ для всех команд, что не является желательным. К сожалению, насколько мне известно, нет способа передать параметры подкоманде через командную строку, например, если вы укажете bdist --install-lib=/ , это вызовет ошибку вместо передачи ее подкомандам.

Чтобы настроить install-lib для install подкоманды только при bdist запуске, вы можете подклассировать bdist_dumb команду и задать путь вручную после того, как install подкоманда будет создана / повторно инициализирована:

setup.py

 from distutils.core import setup
from distutils.command.bdist_dumb import bdist_dumb

class custom_bdist_dumb(bdist_dumb):

    def reinitialize_command(self, name, **kw):
        cmd = bdist_dumb.reinitialize_command(self, name, **kw)
        if name == 'install':
            cmd.install_lib = '/'
        return cmd

if __name__ == '__main__':
    setup(
        # our custom class override
        cmdclass = {'bdist_dumb': custom_bdist_dumb},
        name='my_package',
        py_modules = ['__main__'],
        packages = ['module1', 'module2'],
        package_dir = {'': 'src'}
    )
  

Выполняется:

 % python setup.py bdist --format=zip
% unzip -l dist/my_package-0.0.0.linux-x86_64.zip
Archive:  dist/my_package-0.0.0.linux-x86_64.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
      184  2011-05-31 20:34   my_package-0.0.0.egg-info
       30  2011-05-31 20:34   __main__.py
      128  2011-05-31 20:34   __main__.pyc
      107  2011-05-31 20:34   module1/__init__.pyc
        0  2011-05-31 20:27   module1/__init__.py
      107  2011-05-31 20:34   module2/__init__.pyc
        0  2011-05-31 20:27   module2/__init__.py
---------                     -------
      556                     7 files

% python dist/my_package-0.0.0.linux-x86_64.zip
my_package working.
  

Комментарии:

1. Однако я обнаружил, что выполнение этого означает, что выполнение «setup.py установка «завершается с ошибкой, поскольку она пытается записать в «/». Мне нужна возможность как создать zip-файл, так и установить обычным способом.

2. @Bryan Я обновил ответ, чтобы исправить это, и вы можете удалить setup.cfg изменения. Надеюсь, решение сработает для вас.

3. Черт возьми, когда я запускал это в Windows в оболочке cygwin (не уверен, имеет ли это значение …) Я получил ‘ValueError: path’ / ‘не может быть абсолютным’. Изменение cmd.install_lib = '/' на cmd.install_lib = '\' устранило эту проблему.

Ответ №2:

Можно также создать sdist исполняемый файл, поместив следующий __main__.py файл в корень вашего .zip:

 import os
import sys

# add package .zip to python lookup path
__dir__ = os.path.dirname(__file__)
path = os.path.join(__dir__, 'my_package-0.1', 'src')
sys.path.insert(0, path)

import module1
module1.main()
  

Это добавляет вложенный каталог исходного кода из архива в, sys.path так что импорт из module1 становится возможным.

Я не могу сказать прямо сейчас, как исправить sdist команду distutils, чтобы автоматически вводить это __main__.py в .zip , но это определенно реально.