如何在更改入口点 (sys.path) 的 Python 中导入文件?
How to import file in Python with changed entry point (sys.path)?
我有这样的结构:
web/
api/
app.py
sets.json
tests/
test.py
app.py:
def func():
with open('sets.json', 'r') as file:
...
test.py:
import sys
import os
sys.path.append(os.getcwd()+'/api/')
from app import func
...
我想 运行 从根目录 (web/) 进行测试。导入成功。但是当调用 func 时,出现错误:FileNotFoundError: [Errno 2] No such file or directory: 'sets.json'
.
为什么? Sys.path 已更改,并且可以导入。为什么我无法导入 sets.json?
因为你当前的工作目录和你的路径不一样,而且你用的是相对路径(open("sets.json")
== open("./sets.json")
)所以python正在寻找sets.json
在您的顶级目录中,而不是在 api
.
中
乱用 sys.path
无论如何都不是导入的可靠解决方案。我不太确定你的 test.py
中有什么,但你最好使用合适的测试运行器(这取决于你如何设置它可能会解决问题),或者你可能想将你的应用程序变成一个 包 并将其安装在 'development mode' 中,这样就可以通过杂耍路径找到 app
。
在任何情况下,您都需要一个更强大的解决方案来查找您的数据,例如使用包路径(如果您将使用包分发数据),或者像 ~/.cache/my-app/my-data
.[=18 这样的特定路径=]
一些流行的网络框架支持解析到内置包中已部署资源的路径,这可能是您正在寻找的(但您没有说您是否正在使用)。
将 /api/
添加到您的 sys.path
不会更改您当前的工作目录,因此为了访问 sets.json
您必须修改您的代码:
def func():
with open('/api/sets.json', 'r') as file:
...
或者,更强大的解决方案涉及使用 pathlib 通过检查路径的最后一部分并更新 .json 相应的文件:
from pathlib import Path
def func():
if Path.cwd().parts[-1] == 'api':
set_location = 'sets.json'
elif Path.cwd().parts[-1] == 'web':
set_location = 'api/sets.json'
with open(set_location, 'r') as file:
...
因此,我得到了这样的解决方案:
我使用代码创建 tests/conftest.py
(对于 Pytest,它允许对所有文件应用我的更改):
import sys
import os
os.chdir(os.getcwd()+'/api/')
sys.path.append(os.getcwd())
使用此解决方案,我可以从 web/api/
(在 Docker 中)和从 web/
(在 PyTest 中)进行导入,并在 [= 中访问 sets.json
12=].
运行测试的正确方法是 运行 从 web 目录(希望不直接包含 python 文件)作为:
$ python -m tests.test # note no py
您应该删除所有 sys.path hack 并重写相对路径 - 切勿使用 chdir,这可能会导致导入系统中出现非常细微的错误,包括但不限于在不同命名空间中双重导入模块 - 下面将做:
sets_json = os.path.join(os.path.dirnname(__file__), 'sets.json')
def func():
with open(sets_json, 'r') as ins:
... # do not name your variable 'file', shadows a builtin
我有这样的结构:
web/
api/
app.py
sets.json
tests/
test.py
app.py:
def func():
with open('sets.json', 'r') as file:
...
test.py:
import sys
import os
sys.path.append(os.getcwd()+'/api/')
from app import func
...
我想 运行 从根目录 (web/) 进行测试。导入成功。但是当调用 func 时,出现错误:FileNotFoundError: [Errno 2] No such file or directory: 'sets.json'
.
为什么? Sys.path 已更改,并且可以导入。为什么我无法导入 sets.json?
因为你当前的工作目录和你的路径不一样,而且你用的是相对路径(open("sets.json")
== open("./sets.json")
)所以python正在寻找sets.json
在您的顶级目录中,而不是在 api
.
乱用 sys.path
无论如何都不是导入的可靠解决方案。我不太确定你的 test.py
中有什么,但你最好使用合适的测试运行器(这取决于你如何设置它可能会解决问题),或者你可能想将你的应用程序变成一个 包 并将其安装在 'development mode' 中,这样就可以通过杂耍路径找到 app
。
在任何情况下,您都需要一个更强大的解决方案来查找您的数据,例如使用包路径(如果您将使用包分发数据),或者像 ~/.cache/my-app/my-data
.[=18 这样的特定路径=]
一些流行的网络框架支持解析到内置包中已部署资源的路径,这可能是您正在寻找的(但您没有说您是否正在使用)。
将 /api/
添加到您的 sys.path
不会更改您当前的工作目录,因此为了访问 sets.json
您必须修改您的代码:
def func():
with open('/api/sets.json', 'r') as file:
...
或者,更强大的解决方案涉及使用 pathlib 通过检查路径的最后一部分并更新 .json 相应的文件:
from pathlib import Path
def func():
if Path.cwd().parts[-1] == 'api':
set_location = 'sets.json'
elif Path.cwd().parts[-1] == 'web':
set_location = 'api/sets.json'
with open(set_location, 'r') as file:
...
因此,我得到了这样的解决方案:
我使用代码创建 tests/conftest.py
(对于 Pytest,它允许对所有文件应用我的更改):
import sys
import os
os.chdir(os.getcwd()+'/api/')
sys.path.append(os.getcwd())
使用此解决方案,我可以从 web/api/
(在 Docker 中)和从 web/
(在 PyTest 中)进行导入,并在 [= 中访问 sets.json
12=].
运行测试的正确方法是 运行 从 web 目录(希望不直接包含 python 文件)作为:
$ python -m tests.test # note no py
您应该删除所有 sys.path hack 并重写相对路径 - 切勿使用 chdir,这可能会导致导入系统中出现非常细微的错误,包括但不限于在不同命名空间中双重导入模块 - 下面将做:
sets_json = os.path.join(os.path.dirnname(__file__), 'sets.json')
def func():
with open(sets_json, 'r') as ins:
... # do not name your variable 'file', shadows a builtin