在 Docker 容器化 Python 代码中加入路径时如何避免在文件路径中混合使用 \ 和 /
how to avoid mixture of \ and / in file paths when joining paths in Docker containerized Python code
据我所知,我正在使用最佳实践来定义路径(使用原始字符串)以及我如何加入它们(使用 os.path.join()
),例如
import os
fdir = r'C:\Code\...\samples'
fpath = os.path.join(fdir, 'fname.ext')
当 运行 在 Python 或命令 shell 中使用我的代码时,这样做并没有给我带来任何问题。如果我将 fpath
打印到控制台,我会在路径中一致使用 \
s:
C:\Code...\samples\fname.ext
但是当我 运行 代码的 Docker 容器化版本和 运行 图像时,我得到错误:
FileNotFoundError: [Errno 2] No such file or directory:
'C:\Code\...\samples/fname.ext'
我不明白为什么 os.path.join()
使用 /
连接 fdir
和 fname.ext
而路径的其余部分包含 \
。当我 运行 容器外的代码时,它不会这样做。
我试过使用 os.path.normpath()
:
fpath = os.path.join(fdir, 'fname.ext')
fpath = os.path.normpath(fpath)
如讨论的那样 ,以及 os.sep.join()
:
fpath = os.sep.join([fdir, 'fname.ext'])
涵盖 here,并且 Path().joinpath()
:
from pathlib import Path
fpath = Path(fdir).joinpath('fname.ext')
以及Path() / 'path_to_add'
:
fpath = Path(fdir) / 'fname.ext'
正如所讨论的 ,但在每种情况下,我使用 os.path.join()
.
得到的结果都是一样的
有人可以帮助我了解正在发生的事情以及如何创建一致的路径,无论我是在 Windows 环境中 运行 Python 中的代码,还是在 Docker 容器中?
11 月 16 日更新:
为了让我的问题保持简短,我想我遗漏了重要的细节。对那些根据我对问题的不完整描述而花时间提出建议的人表示歉意。
我的代码需要 import/export 文件 from/to 在用户指定的配置文件中定义的目录。
所以配置文件中有一段代码是用户定义变量和路径的,例如
samplesDir = r"path-to-samples-directory"
变量存储在dictionaris的字典中,存储为.json.
在代码的开头,用户定义了选择感兴趣的字典的键,这样当我的代码的各个部分需要文件时 imported/exported,路径就在手边。
所以回到我的示例,samplesDir
存储在配置字典中,cfgDict
,所以我需要做的就是附加文件名:
sampleFpath = os.path.join(sampleDir, sampleFname)
和sampleFname
是根据其他变量确定的。
由于变量的动态特性(包括目录路径和文件路径),我认为它排除了在 .yml 中使用 Docker Compose 定义的静态路径的使用。
11 月 18 日更新:
包含更多详细信息和一些屏幕截图可能会有所帮助。
上面的屏幕截图显示了 src 目录的文件和文件夹结构,其中包含源代码、用于命令行使用的主要 app.py 脚本、Docker文件等
configs 文件夹包含 JSON 个文件,其中包括变量、目录路径和文件。用户可以通过复制现有文件并修改条目来创建配置文件,或者可以通过调用 config.py.
来生成配置文件
在config.py内我有预先设置的变量和路径,这样配置文件(configs)、示例文件(sample_DROs) 和其他(例如 fiducials)都在 src.
中
我不认为用户有任何理由想要将配置文件存储在其他任何地方,我也不希望他们想要使用不同的示例文件(或将它们移动到其他地方)。然而,他们无疑会创建自己的基准点,并可能决定不将它们存储在 fiducials 目录中(即不在 src 目录中的某个地方)。
同样,我已将下载目录(基于存储在配置文件中的参数,从服务器获取文件并下载)预设为默认的 Downloads 目录:
rootDownloadDir = os.path.join(Path.home(), "Downloads", "xnat_downloads")
这些文件随后被导入、处理,并且输出(默认情况下)导出到 rootDownloadDir.
中的子目录中
在 Dockerfile 中,我将容器的工作目录设置为源代码的工作目录,并复制 src 的所有内容(.dockerignore 中定义的一些目录除外):
WORKDIR C:/Code/WP1.3_multiple_modalities/src
...
COPY . .
以便容器的结构模仿 WORKDIR
:
因此我在 import/export 目录中允许了灵活性,默认情况下它们是 src 目录内外路径的组合。因此,在容器内执行的代码将需要访问 src.
内部和外部的文件
就是说,我不知道当 os.path.join(Path.home(), "Downloads", "xnat_downloads")
在容器中 运行 时 rootDownloadDir
会是什么样子。
这让我开始思考 - 将下载目录设置在 src 之外是一种不好的做法吗?
返回原错误:
示例文件在容器中:
从实际行为来看,我可以假设容器是基于类 Unix 图像的。在此类系统中,路径分隔符是 /
。
要构建可在容器内外运行的环境独立路径,您需要执行以下步骤:
- 正在将主机文件夹挂载到容器目录。
- 容器内外环境变量。
我可以举例说明如何通过 docker-compose
工具及其配置文件 docker-compose.yml
:
# docker-compose.yml file
version: '3'
services:
<service_name>: # your service name here
image: <image_name> # name of image your container is built on
environment:
- SAMPLES_PATH=/samples
volumes:
- C:\Code\somepath\samples:/samples
在您的 python 代码中,您可以使用以下结构:
import os
fdir = os.getenv('SAMPLES_PATH', r'C:\Code\...\samples')
fpath = os.path.join(fdir, 'fname.ext')
据我所知,我正在使用最佳实践来定义路径(使用原始字符串)以及我如何加入它们(使用 os.path.join()
),例如
import os
fdir = r'C:\Code\...\samples'
fpath = os.path.join(fdir, 'fname.ext')
当 运行 在 Python 或命令 shell 中使用我的代码时,这样做并没有给我带来任何问题。如果我将 fpath
打印到控制台,我会在路径中一致使用 \
s:
C:\Code...\samples\fname.ext
但是当我 运行 代码的 Docker 容器化版本和 运行 图像时,我得到错误:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\Code\...\samples/fname.ext'
我不明白为什么 os.path.join()
使用 /
连接 fdir
和 fname.ext
而路径的其余部分包含 \
。当我 运行 容器外的代码时,它不会这样做。
我试过使用 os.path.normpath()
:
fpath = os.path.join(fdir, 'fname.ext')
fpath = os.path.normpath(fpath)
如讨论的那样 os.sep.join()
:
fpath = os.sep.join([fdir, 'fname.ext'])
涵盖 here,并且 Path().joinpath()
:
from pathlib import Path
fpath = Path(fdir).joinpath('fname.ext')
以及Path() / 'path_to_add'
:
fpath = Path(fdir) / 'fname.ext'
正如所讨论的 os.path.join()
.
有人可以帮助我了解正在发生的事情以及如何创建一致的路径,无论我是在 Windows 环境中 运行 Python 中的代码,还是在 Docker 容器中?
11 月 16 日更新:
为了让我的问题保持简短,我想我遗漏了重要的细节。对那些根据我对问题的不完整描述而花时间提出建议的人表示歉意。
我的代码需要 import/export 文件 from/to 在用户指定的配置文件中定义的目录。
所以配置文件中有一段代码是用户定义变量和路径的,例如
samplesDir = r"path-to-samples-directory"
变量存储在dictionaris的字典中,存储为.json.
在代码的开头,用户定义了选择感兴趣的字典的键,这样当我的代码的各个部分需要文件时 imported/exported,路径就在手边。
所以回到我的示例,samplesDir
存储在配置字典中,cfgDict
,所以我需要做的就是附加文件名:
sampleFpath = os.path.join(sampleDir, sampleFname)
和sampleFname
是根据其他变量确定的。
由于变量的动态特性(包括目录路径和文件路径),我认为它排除了在 .yml 中使用 Docker Compose 定义的静态路径的使用。
11 月 18 日更新:
包含更多详细信息和一些屏幕截图可能会有所帮助。
上面的屏幕截图显示了 src 目录的文件和文件夹结构,其中包含源代码、用于命令行使用的主要 app.py 脚本、Docker文件等
configs 文件夹包含 JSON 个文件,其中包括变量、目录路径和文件。用户可以通过复制现有文件并修改条目来创建配置文件,或者可以通过调用 config.py.
来生成配置文件在config.py内我有预先设置的变量和路径,这样配置文件(configs)、示例文件(sample_DROs) 和其他(例如 fiducials)都在 src.
中我不认为用户有任何理由想要将配置文件存储在其他任何地方,我也不希望他们想要使用不同的示例文件(或将它们移动到其他地方)。然而,他们无疑会创建自己的基准点,并可能决定不将它们存储在 fiducials 目录中(即不在 src 目录中的某个地方)。
同样,我已将下载目录(基于存储在配置文件中的参数,从服务器获取文件并下载)预设为默认的 Downloads 目录:
rootDownloadDir = os.path.join(Path.home(), "Downloads", "xnat_downloads")
这些文件随后被导入、处理,并且输出(默认情况下)导出到 rootDownloadDir.
中的子目录中在 Dockerfile 中,我将容器的工作目录设置为源代码的工作目录,并复制 src 的所有内容(.dockerignore 中定义的一些目录除外):
WORKDIR C:/Code/WP1.3_multiple_modalities/src
...
COPY . .
以便容器的结构模仿 WORKDIR
:
因此我在 import/export 目录中允许了灵活性,默认情况下它们是 src 目录内外路径的组合。因此,在容器内执行的代码将需要访问 src.
内部和外部的文件就是说,我不知道当 os.path.join(Path.home(), "Downloads", "xnat_downloads")
在容器中 运行 时 rootDownloadDir
会是什么样子。
这让我开始思考 - 将下载目录设置在 src 之外是一种不好的做法吗?
返回原错误:
示例文件在容器中:
从实际行为来看,我可以假设容器是基于类 Unix 图像的。在此类系统中,路径分隔符是 /
。
要构建可在容器内外运行的环境独立路径,您需要执行以下步骤:
- 正在将主机文件夹挂载到容器目录。
- 容器内外环境变量。
我可以举例说明如何通过 docker-compose
工具及其配置文件 docker-compose.yml
:
# docker-compose.yml file
version: '3'
services:
<service_name>: # your service name here
image: <image_name> # name of image your container is built on
environment:
- SAMPLES_PATH=/samples
volumes:
- C:\Code\somepath\samples:/samples
在您的 python 代码中,您可以使用以下结构:
import os
fdir = os.getenv('SAMPLES_PATH', r'C:\Code\...\samples')
fpath = os.path.join(fdir, 'fname.ext')