Skip to main content
 首页 » 编程设计

python之如何在 python 安装包中包含文本文件

2025年05月04日12bhlsheji

我创建了一个如下所示的 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' 

如何查看和使用属于已安装包的文件,但我要在运行该程序的环境中使用它?

编辑:

This a simplification of the problem you can download and test:

https://github.com/mctrjalloh/project_initializer

请您参考如下方法:

经过大量研究,我找到了解决这个问题的方法以及它的工作原理。这有点令人困惑,其他 stackoverflow 答案都没有真正的解释。我想在这里试试:

我制作了一个示例项目,仅用于演示和测试解决方案。我想出了两种解决方案:一种使用 setup() 函数的 data_files 参数,另一种使用我最喜欢的 package_data 参数。

Here is the link to the github repo you can download and test

安装运行后使用

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

使用 package_data= ARGUMENT METHOD(我更喜欢)

项目结构:

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

在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' 
        ] 
    } 
) 

在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 文档

Using data_files= argument

Using package_data= argument