Как включить текстовый файл в установленный пакет Python? - PullRequest
0 голосов
/ 24 ноября 2018

Я создал пакет Python, который выглядит следующим образом:

/command
    /command
        module.py
        __main__.py
    README.md
    setup.py
    file.txt

Для установки я запускаю:

sudo python setup.py install

Теперь, когда я звоню

$ command

он показывает эту ошибку:

FileNotFoundError: [Errno 2] No such file or directory: '../file.txt'

Примерно содержимое модулей setup.py , __ main __. py и module.py

setup.py

import setuptools

setuptools.setup(
    name='command',
    ...
    entry_points={
        'console_scripts': [
            'command = command.__main__:main'
        ]
    }
)

__ main __. Py

from . import module

def main():
    module.run('arg')

module.py

import shutil

# copy file.txt from command project into the directory where it is running
def run(arg):
    shutil.copyfile('../file.txt', './file.txt')

После ввода этого пакета с помощью:

sudo python setup.py install

И вызова программы из командной строки

$ command

Я получаю ошибку ниже

FileNotFoundError: [Errno 2] No such file or directory: '../file.txt'

Как можно увидеть и использовать такой файл, который принадлежит установленному пакету, но я хочу использовать его в среде, где я запускаю эту программу?

Изменить:

Это упрощение проблемы, которую вы можете загрузить и проверить:

https://github.com/mctrjalloh/project_initializer

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Итак, после долгих исследований я нашел решение этой проблемы и то, как она работает.Это немного сбивает с толку, ни один из других ответов на стеке не был настолько объяснительным.Я хочу попробовать это здесь:

Я сделал пример проекта для этой единственной цели, чтобы продемонстрировать и протестировать решение.Я предложил два решения: одно с использованием аргумента data_files функции setup (), а другое с использованием аргумента package_data , который я предпочел больше всего.

Вот ссылка на репозиторий github, который вы можете загрузить и протестировать

Чтобы использовать его после установки, запустите

proj init <some-name>

Но, если кратко, есть самые важные модулидля каждого метода.

ИСПОЛЬЗОВАНИЕ data_files = МЕТОД АРГУМЕНТА:

Структура проекта:

project_initializer
    project_initializer
        __init__.py
        __main__.py
        init.py
    README.md
    setup.py

в setup.py

import setuptools
import os
import sys


PROJECT_NAME = "project_initializer"
DATA_DIR = os.path.join(
    sys.prefix, "local/lib/python3.6/dist-packages", PROJECT_NAME)


setuptools.setup(
    name='project_initializer',
    version='0.1.0',
    packages=setuptools.find_packages(),
    install_requires=[
        'docopt'
    ],
    data_files=[         # is the important part
        (DATA_DIR, [
            "README.md",
            ".gitignore"
        ])               
    ],
    entry_points={
        'console_scripts': [
            'proj = project_initializer.__main__:main'
        ]
    }
)

в init.py

import subprocess
import os
import shutil
import sys

"""Create a new project and initialize it with a .gitignore file
@params project: name of a project to be initialized
effects:
    /project
        README.md
    README.md in the created project directory must be the same as the README.md in THIS directory 
"""

PROJECT_NAME = "project_initializer"
DATA_DIR = os.path.join(
    sys.prefix, "local/lib/python3.6/dist-packages", PROJECT_NAME)


def run(project):
    os.mkdir(project)
    shutil.copyfile(os.path.join(DATA_DIR, "README.md"),
                    f"{project}/README.md")  # problem solved


if __name__ == '__main__':
    run("hello-world")

USING package_data = МЕТОД АРГУМЕНТА (что я предпочел)

Структура проекта:

project_initializer
    project_initializer
        data/
            README.md  # the file we want to copy
        __init__.py
        __main__.py
        init.py
    README.md
    setup.py

in setup.py

import setuptools


setuptools.setup(
    name='project_initializer',
    version='0.1.0',
    packages=setuptools.find_packages(),
    package_dir={'project_initializer': 'project_initializer'}, # are the ... 
    package_data={'project_initializer': [ # ... important parameters
        'data/README.md', 'data/.gitignore']},
    install_requires=[
        'docopt'
    ],
    entry_points={
        'console_scripts': [
            'proj = project_initializer.__main__:main'
        ]
    }
)

in init.py

import subprocess
import os
import shutil
import sys

PROJECT_DIR = os.path.dirname(__file__)

"""Create a new project and initialize it with a .gitignore file
@params project: name of a project to be initialized
effects:
    /project
        .gitignore
    .gitignore in the created project directory must be the same as the gitignore in THIS directory 
"""


def run(project):
    os.mkdir(project)
    shutil.copyfile(os.path.join(PROJECT_DIR, 'data/README.md'),
                    f"{project}/README.md")  # problem solved


if __name__ == '__main__':
    run("hello-world")

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

Для более подробного объяснения различий между этими двумя аргументами обратитесь к документации по python

Использование data_files = аргумент

Использование package_data = аргумент

0 голосов
/ 24 ноября 2018

По умолчанию в пакет включены только файлы python.

Чтобы добавить больше, добавьте MANIFEST.in и перечислите файл. Например .

Это всеобъемлющее руководство

...