Python打包时包含静态文件处理方法

Python打包时包含静态文件处理方法

使用场景

  1. 已搭建了PyPI私有库,上传公共库包含静态文件,如需要使用sql静态文件初始化数据库。
  2. 打包python包,给其他人使用,但项目中包含静态文件,如html。

解决步骤

  1. 解决静态文件读取问题
  2. 解决静态文件打包问题

环境

Python3.8
PyCharm 2020

demo项目为例

步骤

  1. 创建项目
  2. 展示静态文件读取问题
  3. 解决方案
  4. 展示静态文件打包问题
  5. 解决方案

1. 创建项目

创建一个demo项目(text-setup),目录如下


  • test-setup
    • demo
      • __init__.py
      • demo.py
      • demo.txt

/demo/demo.txt

The text is from demo.txt.

/demo/demo.py

import os


def get_txt():
    """使用原始打开io方式打开"""
    with open('demo.txt', 'r', encoding='utf-8') as f:
        return f.read()


def get_demo_txt():
    """修改获取路径方式,使用io打开"""
    current_dir = os.path.dirname(__file__)
    file_path = os.path.join(current_dir, 'demo.txt')
    with open(file_path, 'r', encoding='utf-8') as f:
        return f.read()


if __name__ == "__main__":
    """类内测试,均无异常"""
    print("get_demo_txt() :", get_demo_txt())
    # get_demo_txt() : The text is from demo.txt.

    print("get_txt() :", get_txt())
    # get_txt() : The text is from demo.txt.

在当前路径下执行demo.py文件没有异常(使用PyCharm直接右键run)

2. 展示静态文件读取问题

在根目录(或其他任意除demo.py文件路径)执行上面的demo.py文件就会报错

$ python demo/demo.py
get_demo_txt() : The text is from demo.txt.
Traceback (most recent call last):
  File "demo/demo.py", line 21, in <module>
    print("get_txt() :", get_txt())  # get_txt() : The text is from demo.txt.
  File "demo/demo.py", line 6, in get_txt
    with open('demo.txt', 'r', encoding='utf-8') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'demo.txt'

明显看出

  • 直接使用相对路径读取静态文件的方式报错
  • 使用os.path.dirname(__file__)获取当前python文件路径并拼接的方式不会报错

3. 解决方案

使用os.path.dirname(__file__)的方式去获取当前python文件路径,再去拼接静态文件的路径

demo中将get_txt()方法删除,继续进行以下打包demo

4. 展示静态文件打包问题

打包,创建打包配置文件
/setup.py

from setuptools import find_packages, setup

setup(
    name='demo',
    version='1.0.0',
    packages=find_packages(),
    zip_sage=False,
)

执行打包命令

$ python setup.py sdist

打开打包信息文件,内容如下
/demo.egg-info/SOURCES.txt

setup.py
demo/__init__.py
demo/demo.py
demo.egg-info/PKG-INFO
demo.egg-info/SOURCES.txt
demo.egg-info/dependency_links.txt
demo.egg-info/top_level.txt

可以看出,demo.txt并不在资源文件中,可以实际试一下,其他项目引用这个文件执行获取文件也将报错FileNotFoundError

5. 解决方案

修改打包配置文件
/setup.py

from setuptools import find_packages, setup

setup(
    name='demo',
    version='1.0.0',
    packages=find_packages(),
    zip_sage=False,
    include_package_data=True,  # 打包包含静态文件标识
)

增加配置文件
/MANIFEST.in

include demo/demo.txt

最终文件目录


  • test-setup
    • demo
      • __init__.py
      • demo.py
      • demo.txt
    • setup.py
    • MANIFEST.in

再次执行打包命令

$ python setup.py sdist

打开打包信息文件,内容如下
/demo.egg-info/SOURCES.txt

MANIFEST.in
setup.py
demo/__init__.py
demo/demo.py
demo/demo.txt
demo.egg-info/PKG-INFO
demo.egg-info/SOURCES.txt
demo.egg-info/dependency_links.txt
demo.egg-info/top_level.txt

可以看到demo.txt已经在打包信息当中,引用这个包也不会报错了

参考资料:

Creating a Source Distribution
Flask docs - Make the Project Installable

posted @ 2021-01-12 21:45  言午日尧耳总  阅读(457)  评论(0编辑  收藏  举报