找到Python包中的非Python文件。

huangapple go评论66阅读模式
英文:

Package and find non Python Files in a python package

问题

我相对于Python包装技术还比较新,我正在尝试创建一个命令行工具,以便可以将其发送给客户与我的AWS服务进行交互。

我的目标是创建一个命令行工具,用于上传位于resources文件夹中的文件到S3,以供其他服务稍后使用。

这是我第一次使用setuptools,但我似乎在某个地方迷失了方向。

我的项目结构如下:

ProjectRoot
├── MANIFEST.in
├── Pipfile
├── Pipfile.lock
├── dist
│   ├── myscript-0.0.1.whl
│   └── myscript-0.0.1.tar.gz
├── pyproject.toml
├── resources
│   ├── artifacts
│   │   ├── code1.jar
│   │   ├── code2.jar
│   │   ├── api.keys
│   │   ├── package1.tar.gz
│   │   ├── install-linux.sh
│   │   └── confs.yaml
│   ├── recipe.template.yaml
└── src
    └── code
        ├── __init__.py
        └── myscript.py

我尝试使用pyproject.toml使setuptools将这些文件添加到.tar包中,如下所示:

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "myscript"
version = "0.0.1"
dependencies = [
    'Click',
    'boto3',
    'botocore',
]

[project.scripts]
myscript = "code.main:run"

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["src","resources"]
include = ["code*"]
exclude = [] 

[tool.setuptools.package-data]
"resources.artifacts" = ["*"]
recipe = ["*.yaml"]

之后,我尝试使用pip install dist/generated_file.whl安装生成的wheel文件,但在安装过程中找不到resources/文件夹。

附注:我也有点困惑是否需要同时使用whl和tar包。

我尝试使用相对路径来查找资源,但我发现它们未安装在site-packages中。

我最近尝试使用from importlib_resources import files,但它似乎也找不到资源。

我找不到resources文件夹中的文件。

英文:

I'm fairly new to python packaging and I'm trying to create a command line tool so that I can send to client to interact with my service in AWS.

My goal is to have a command line tool to upload files that are in the folder resources to s3 that will later be used by other services.

It's my first time using setuptools for that but I'm seem to be lost at some point.

My project structure is something like:

ProjectRoot
├── MANIFEST.in
├── Pipfile
├── Pipfile.lock
├── dist
│   ├── myscript-0.0.1.whl
│   └── myscript-0.0.1.tar.gz
├── pyproject.toml
├── resources
│   ├── artifacts
│   │   ├── code1.jar
│   │   ├── code2.jar
│   │   ├── api.keys
│   │   ├── package1.tar.gz
│   │   ├── install-linux.sh
│   │   └── confs.yaml
│   ├── recipe.template.yaml
└── src
    └── code
        ├── __init__.py
        └── myscript.py

I've tried to make setuptools add the files to the .tar package with the pyproject.toml with this:

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "myscript"
version = "0.0.1"
dependencies = [
    'Click',
    'boto3',
    'botocore',
]

[project.scripts]
myscript = "code.main:run"

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["src","resources"] 
include = ["code*"]
exclude = [] 

[tool.setuptools.package-data]
"resources.artifacts" = ["*"]
recipe = ["*.yaml"]

After that I try to install the wheel generated file with pip install dist/generated_file.whl, but I can't find the resources/ folder anywhere during installation.

ps.: I also got a little lost if I need the whl and the tar package together.

I tried using relative paths to find the resources, but I saw they weren't installed in the sites_packages.

My latest try was using from importlib_resources import files but it also can't seem to find the resources.

I can't find the resources folder files.

答案1

得分: 3

起始点

使用给定的项目结构

🌱 <项目根目录>/
├─🔖 pyproject.toml
├─🌱 src/
│ └─🌱 code/
│   ├─🔖 __init__.py
│   └─🔖 myscript.py
├─🌱 resources/
  └─🌱 artifacts/
    └─🔖 code1.jar

并通过指定以下内容

[tool.setuptools.packages.find]
where = ["src","resources"]
include = ["code*"]
exclude = []

[tool.setuptools.package-data]
"resources.artifacts" = ["*"]
recipe = ["*.yaml"]

您将得到一个包含以下内容的轮子

🌱 myscript-0.0.1-py3-none-any/
└─🌱 code/
  ├─🔖 __init__.py
  └─🔖 myscript.py

这是因为唯一找到的code。包是一个包含Python(.py)文件的文件夹,通常包含一个__init__.py文件(如果不涉及命名空间包的话,这是一个特殊情况)。

我会做什么?

  • 首先,重新命名您的主包文件夹。您在pyproject中称项目为myscript(因此您将使用pip install myscript安装它),但文件结构暗示导入名称code;因此,您需要执行import code.myscript(code是主包)。我将在此示例中更改项目名称为myproj,通过在pyproject.toml和./code文件夹中更改名称为./myproj

  • 其次,"package-data"的名称对我来说表明它是内的数据。./resources不是一个包,因为它不包含任何Python文件。如果您在那里添加一个空的__init__.py,它将变成一个包。但是pyproject.toml中还存在另一个问题:您的包应该在名为./resources的文件夹下找到,但实际上它在根文件夹(.)下。因此,您应该要么更改where = ['src', '.'](这将引入新问题),要么将./resources移动到./resources/resources,但您也可以更简单地执行(第三点)

  • 第三,您可以通过将数据文件放置在您的包内(./myproj)来简化事情。这是更常见的做法,也使pip安装资源与您的代码一起,放在site-packages/myproj中,这很好(尽管还有其他可能性)。因此,我建议对pyproject.toml进行以下更改:

[project]
name = "myproj" # <-- 这个改变了
version = "0.0.1"

[tool.setuptools.packages.find]
where = ["src"] # <-- 这个改变了

[tool.setuptools.package-data]
"*" = ["*.*"] # <-- 这个改变了

然后文件夹结构如下:

🌱 <项目根目录>/
├─🔖 pyproject.toml
└─🌱 src/
  └─🌱 myproj/
    ├─🔖 __init__.py
    ├─🌱 __assets__/ # 非代码文件放在这里
    │ └─🔖 code1.jar     
    └─🔖 myscript.py

然后将创建具有以下文件夹结构的轮子:

└─🌱 myproj-0.0.1-py3-none-any/
  └─🌱 myproj/
    ├─🔖 __init__.py
    ├─🌱 __assets__/
    │ └─🔖 code1.jar
    └─🔖 myscript.py
英文:

Starting point

With the given project structure

&#128193; &lt;project root&gt;/
├─&#128196; pyproject.toml
├─&#128193; src/
│ └─&#128193; code/
│   ├─&#128196; __init__.py
│   └─&#128196; myscript.py
├─&#128193; resources/
  └─&#128193; artifacts/
    └─&#128196; code1.jar

and by specifying

[tool.setuptools.packages.find]
where = [&quot;src&quot;,&quot;resources&quot;]
include = [&quot;code*&quot;]
exclude = []

[tool.setuptools.package-data]
&quot;resources.artifacts&quot; = [&quot;*&quot;]
recipe = [&quot;*.yaml&quot;]

you'll get a wheel with following contents

&#128193; myscript-0.0.1-py3-none-any/
└─&#128193; code/
  ├─&#128196; __init__.py
  └─&#128196; myscript.py

The reason for this is that the only package found is code. A package is a folder with python (.py) files, and usually with __init__.py file (if not talking about namespace packages which are a bit of a special thing).

What I would do?

  • First, renaming your main package folder. You've called your project myscript in pyproject (so you would install it with pip install myscript), but then the file structure would imply that the import name is code; so you would need to do import code.myscript (code being the main package). I'll change the project name to be in this example myproj, by changing the name in pyproject.toml and ./code folder to ./myproj

  • Second, the name of the "package-data" to me says that it is data inside a package. The ./resources is not a package as it does not contain any python files. If you add there an empty __init__.py, it will become a package. But there is another problem in pyproject.toml: your package should be found under a folder called ./resources, but that is actually in root folder (.). Therefore, you should either change where = [&#39;src&#39;, &#39;.&#39;] (which creates new problems) or move ./resources to ./resources/resources, but you could also do it easier (third point)

  • Third, you could simplify things by putting the data files inside you package (./myproj). That's fair more common practice, and also makes pip install the resources with your code, inside site-packages/myproj, which is nice (although, there are other possibilities). So, I propose these changes to pyproject.toml:

[project]
name = &quot;myproj&quot; # &lt;-- this changed
version = &quot;0.0.1&quot;

[tool.setuptools.packages.find]
where = [&quot;src&quot;] # &lt;-- this changed

[tool.setuptools.package-data]
&quot;*&quot; = [&quot;*.*&quot;] # &lt;-- this changed

and then the folder structure to

&#128193; &lt;project root&gt;/
├─&#128196; pyproject.toml
└─&#128193; src/
  └─&#128193; myproj/
    ├─&#128196; __init__.py
    ├─&#128193; __assets__/ # non-code files here
    │ └─&#128196; code1.jar     
    └─&#128196; myscript.py

That will then create a wheel with following folder structure:

└─&#128193; myproj-0.0.1-py3-none-any/
  └─&#128193; myproj/
    ├─&#128196; __init__.py
    ├─&#128193; __assets__/
    │ └─&#128196; code1.jar
    └─&#128196; myscript.py

答案2

得分: 1

你想要使用 data_files 来实现这个。 (https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#data-files)

序列中的每个 (目录, 文件) 对都指定了安装目录以及要在那里安装的文件。目录必须是相对路径 [...]

这将会安装 files 到与 site-packages 或用户安装位置相关的 directory 中。

英文:

You want to use data_files for this. (https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#data-files)

> Each (directory, files) pair in the sequence specifies the installation directory and the files to install there. The directory must be a relative path [...]

This will install the files in the directory relative to site-packages or user install location.

huangapple
  • 本文由 发表于 2023年6月16日 03:48:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76485082.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定