Правильный способ копирования файлов конфигурации во время установки?

Я пытаюсь распространять mplstyle, которое я написал, так, чтобы я мог легко поделиться им. Он сводится к копированию текстового файла в правильном направлении конфигурации (известном для любой архитектуры) во время установки. Я хочу установить с помощью python setup.py install или pip install .... В настоящее время мне кажется, что ни один из двух способов не является надежным (см. Текущий подход ниже).

  • Установка с помощью pip install ..., похоже, вообще не вызывает копирование.
  • Установка с помощью python setup.py install работает на моей машине хорошо, но ReadTheDocs выдает следующую ошибку:

    python setup.py install --force
    
    running install
    error: [Errno 2] No such file or directory: u'/home/docs/.config/matplotlib/stylelib/goose.mplsty
    

Как правильно копировать файлы конфигурации во время установки надежным способом?

Текущий подход

Структура файла

setup.py
goosempl/
| __init__.py
| stylelib/
  | goose.mplstyle
  | ...

setup.py

from setuptools                 import setup
from setuptools.command.install import install

class PostInstallCommand(install):

  def run(self):

    import goosempl
    goosempl.copy_style()

    install.run(self)

setup(
  name              = 'goosempl',
  ...,
  install_requires  = ['matplotlib>=2.0.0'],
  packages          = ['goosempl'],
  cmdclass          = {'install': PostInstallCommand},
  package_data      = {'goosempl/stylelib':['goosempl/stylelib/goose.mplstyle']},
)

goosempl/__init__.py

def copy_style():

  import os
  import matplotlib

  from pkg_resources import resource_string

  files = [
    'stylelib/goose.mplstyle',
  ]

  for fname in files:
    path = os.path.join(matplotlib.get_configdir(),fname)
    text = resource_string(__name__,fname).decode()

    print(path, text)

    open(path,'w').write(text)

Загрузить в PyPi

python setup.py bdist_wheel --universal
twine upload dist/*

person Tom de Geus    schedule 03.03.2018    source источник


Ответы (1)


Прежде всего, исходя из предоставленной вами структуры проекта, вы неправильно указываете package_data. Если goosempl — это пакет, а stylelib — каталог внутри него, содержащий файлы mplstyle (что я предполагаю из вашего кода), то ваша строка конфигурации package_data должна быть:

package_data = {'goosempl': ['stylelib/goose.mplstyle']},

Как описано в Сборка и распространение пакетов с помощью Setuptools:

Аргумент package_data — это словарь, который отображает имена пакетов в списки шаблонов глобусов. Подстановочные знаки могут включать имена подкаталогов, если файлы данных содержатся в подкаталоге пакета.

Итак, ваш пакет — goosempl, а stylelib/goose.mplstyle — это файл, который нужно включить в данные пакета для goosempl.

Ваша вторая проблема (No such file or directory) проста: в функции copy_style() вы никогда не проверяете, существует ли родительский каталог файла перед записью файла. Вы сможете воспроизвести это локально, удалив каталог /home/<user>/.config/matplotlib/stylelib/ (или временно переместив его).

Исправить тоже довольно просто, на самом деле их много. Используйте все, что вы хотите, чтобы создать недостающие каталоги.

  • distutils.dir_util.mkpath подходит как для python2, так и для python3:

    for fname in files:
        path = os.path.join(matplotlib.get_configdir(), fname)
        distutils.dir_util.mkpath(os.dirname(path))
    
  • Я предпочитаю использовать pathlib, но он доступен только с версии Python 3.4:

    for fname in files:
        path = pathlib.Path(matplotlib.get_configdir(), fname)
        path.parent.mkdir(parents=True, exist_ok=True)
    
person hoefling    schedule 04.03.2018
comment
Спасибо, это решает большинство моих проблем. Я использовал os в конце: if not os.path.isdir(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) (обратите внимание на небольшую ошибку на моей стороне). Однако это не решает проблему с pip. Установка из PyPi с помощью pip, похоже, не вызывает команду PostInstallCommand. (Он вызывается только на моей машине перед загрузкой в ​​PyPi). - person Tom de Geus; 05.03.2018
comment
Команда install не будет вызываться pip. Он не устанавливается из исходного кода по дизайну. Вместо этого строит колесо и с него устанавливает - но формат wheel не использует скрипт установки - даже не включает его. Так что ваш PostInstallCommand не будет называться. - person hoefling; 05.03.2018
comment
Хорошо я понял. Есть ли способ скопировать эти файлы конфигурации при установке с помощью pip? Я понимаю, что можно просто включить команду копирования, чтобы она всегда вызывалась при включении библиотеки, но это действительно не то, что я ищу, поскольку (i) это приводит к ненужным проверкам, которые выполняются снова и снова, и (ii ) в моем конкретном случае я хочу, чтобы пользователи загружали стиль без необходимости включать библиотеку. - person Tom de Geus; 05.03.2018
comment
К сожалению, в вашем случае нет - вы хотите разместить файл за пределами каталога site-packages, а wheel этого не позволяет. См. мой другой ответ на аналогичный вопрос - OP хотел поместить файл конфигурации в домашний каталог пользователя при установке. Единственный обходной путь для этого — не создавать колеса в первую очередь, вместо этого создавать исходный tar/zip/bz2, а при установке указать pip не создавать колесо из исходного дистрибутива с флагом --no-binary. - person hoefling; 05.03.2018