在 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() 使用 / 连接 fdirfname.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 图像的。在此类系统中,路径分隔符是 /。 要构建可在容器内外运行的环境独立路径,您需要执行以下步骤:

  1. 正在将主机文件夹挂载到容器目录。
  2. 容器内外环境变量。

我可以举例说明如何通过 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')