我使用 tempfile.TemporaryDirectory
类作为上下文管理器。它应该默认使用 /tmp
文件夹。我尝试使用默认值,也尝试强制使用 /tmp
文件夹。它会在调用者脚本所在的位置创建临时文件夹。
设置:
- 红帽 7 Linux
- python 3.6.6
- 脚本是从 Jenkins 调用的
代码:
import tempfile
import os
print(os.path.dirname(__file__))
TMP_DIR_PREFIX = "my_test_"
with tempfile.TemporaryDirectory(prefix=TMP_DIR_PREFIX, dir="/tmp") as tmp_dir:
print(tmp_dir)
输出:
>>> python3 /home/my_home/test.py
home/my_home
home/my_home/my_test_m1vljq2h
我的问题:
有人知道我该如何解决吗?
这怎么可能?我已经检查了
TemporaryDirectory
类的实现,但我看不出任何原因。如果有人能够解释其中的原因,我将非常高兴。
我已经阅读了相关的官方文档以及tempfile
模块的实现,但我没有找到任何相关的代码部分可以导致此类问题。
注意:如果可能的话,我不想继承和更改此模块的许多元素,但我愿意接受想法。
编辑:
完整回溯(来自 Jenkins 运行):
File "/my_path/python/3.6.0/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/my_path/python/3.6.0/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/home/my_home/copy_to_location.py", line 143, in upload_files
with tempfile.TemporaryDirectory(prefix=TMP_DIR_PREFIX, dir="/tmp") as tmp_dir:
File "/my_path/python/3.6.0/lib/python3.6/tempfile.py", line 790, in __init__
self.name = mkdtemp(suffix, prefix, dir)
File "/my_path/python/3.6.0/lib/python3.6/tempfile.py", line 368, in mkdtemp
_os.mkdir(file, 0o700)
PermissionError: [Errno 13] Permission denied: '/home/my_home/my_test_q1pldmf2'
编辑 2:
我无法在本地复制它。这个问题只在 Jenkins 中经常发生!
编辑 3:
添加行:
logging.info(tempfile._sanitize_params("my_test_", None, None))
Jenkins 中的输出:
2019-11-08 15:09:26 [Thread-1] [INFO] ('my_test_', '', '/tmp', <class 'str'>)
更改行:
logging.info(tempfile._sanitize_params("my_test_", None, "/tmp"))
在 Jenkins 中添加:
2019-11-08 15:13:46 [Thread-1] [INFO] ('my_test_', '', '/tmp', <class 'str'>)
最佳答案
tempfile.TemporaryDirectory()
对象使用 tempfile.mkdtemp()
从传入的参数创建临时目录。这反过来将使用 tempfile.gettempdir()
如果你不给它一个 dir
参数。
如果您传入 dir='/tmp'
并且仍然看不到在 /tmp
中创建的目录,那么有两种可能性:
- 您的
prefix
值不是您认为的那样,而是以/
开头 - 您系统上 的
tempfile
模块已更改,其行为方式不再与standard library version distributed with Python 3.6.0 相同。 .这些更改可以在磁盘上进行,也可以由其他动态更改行为的 Python 代码进行。
mkdtemp()
函数的正常行为是调用名为 _sanitize_params()
的内部函数, 如果设置了 dir
则返回不变,否则返回 gettempdir()
的值:
>>> import tempfile
>>> tempfile._sanitize_params('my_test_', None, '/tmp')
('my_test_', '', '/tmp', <class 'str'>)
>>> tempfile._sanitize_params('my_test_', None, None)
('my_test_', '', '/tmp', <class 'str'>)
>>> tempfile.gettempdir()
'/tmp'
mkdtemp()
然后使用该调用的结果(返回更新的 prefix
、suffix
、dir
和bytes
或 str
类型)和随机字符串,为您创建一个新目录。
这导致您可能没有正确排除 prefix
值确实是您认为的那样。 mkdtemp()
函数使用:
os.path.join(dir, prefix + name + suffix)
将 dir
路径与前缀、候选 name
(随机值)和后缀(在您的情况下为空字符串)串联起来。但请注意 os.path.join()
function将丢弃以/
斜杠开头的参数之前的所有路径元素:
>>> import os.path
>>> os.path.join("/foo", "bar")
'/foo/bar'
>>> os.path.join("/foo", "/bar")
'/bar'
因此,您看到的行为也可以通过以斜杠开头的前缀来解释,因此:
TMP_DIR_PREFIX = "/home/my_home/my_test_"
会立即产生相同的结果:
>>> TMP_DIR_PREFIX = "/home/my_home/my_test_"
>>> tempfile.mkdtemp(prefix=TMP_DIR_PREFIX, dir="/tmp")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/.../lib/python3.6/tempfile.py", line 368, in mkdtemp
_os.mkdir(file, 0o700)
PermissionError: [Errno 13] Permission denied: '/home/my_home/my_test_v4cqpamm'
这在之前以 issue #35278 的形式报告给 Python 项目.
您可以在 Jenkins 作业中简单地包含两个测试以排除这些选项。确保记录 TMP_DIR_PREFIX
值,以及 tempfile._sanitize_params(TMP_DIR_PREFIX, None, '/tmp')
返回的内容。
如果其中任何一个都没有在您的系统上产生预期的输出,那么您就知道您需要专注于寻找; tempfile
模块行为已更改,或者您假设 TMP_DIR_PREFIX
具有它所具有的值是不正确的。
您可以使用以下 shell 命令检查本地副本是否与发布版本不同:
$ diff -u \
> <(curl -s https://raw.githubusercontent.com/python/cpython/v3.6.0/Lib/tempfile.py) \
> /my_path/python/3.6.0/lib/python3.6/tempfile.py
或者您可以计算文件的校验和:
import hashlib
with open(tempfile.__file__, 'rb') as file_to_hash:
tempfile_checksum = hashlib.sha1(file_to_hash.read()).hexdigest()
并将该校验和值与已发布文件的校验和值进行比较:
$ curl -s https://raw.githubusercontent.com/python/cpython/v3.6.0/Lib/tempfile.py | \
> sha1sum
38ad01ccc5972e193e1b96a1de8b7ba1bd8d289d -
如果没有出现任何问题,您将使用调试器逐步完成调用,或者查看所涉及函数的 __module__
属性。例如。如果 _sanitize_params()
被动态更改(monkey patched),则 tempfile._sanitize_params.__module__
将不会设置为 'tempfile'
,例如。但是,请注意,您的回溯已经显示 TemporaryDirectory.__init__
和 mkdtemp
都取自正确的文件,并且可见的两行的行号与已发布的行号相匹配来源。
关于python - tempfile.TemporaryDirectory 上下文管理器不使用/tmp 文件夹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58767241/