diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 57c9bc255b2a9a..91947575f8a472 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1167,6 +1167,13 @@ New deprecations (Contributed by Bénédikt Tran in :gh:`134978`.) +* :mod:`tempfile`: + + * The ``prefix`` and ``suffix`` parameters of the tempfile functions, + :func:`tempfile.mkdtemp`, :func:`tempfile.mkstemp` and + :func:`tempfile.NamedTemporaryFile`, will be sanitized to use only the + basename of the provided values if they contain a directory separator. + * ``__version__`` * The ``__version__``, ``version`` and ``VERSION`` attributes have been diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 2bc61662459992..68cfc26d7e7a44 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -116,11 +116,15 @@ def _sanitize_params(prefix, suffix, dir): output_type = _infer_return_type(prefix, suffix, dir) if suffix is None: suffix = output_type() + elif _os.path.dirname(suffix): + suffix = _os.path.basename(suffix) if prefix is None: if output_type is str: prefix = template else: prefix = _os.fsencode(template) + elif _os.path.dirname(prefix): + prefix = _os.path.basename(prefix) if dir is None: if output_type is str: dir = gettempdir() diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 7eec34f2f294ad..f9e397d0087a84 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -625,8 +625,10 @@ def do_create(self, dir=None, pre=None, suf=None): dir = tempfile.gettempdirb() if pre is None: pre = output_type() + pre = os.path.basename(pre) if suf is None: suf = output_type() + suf = os.path.basename(suf) (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf) (ndir, nbase) = os.path.split(name) adir = os.path.abspath(dir) @@ -647,6 +649,8 @@ def test_basic(self): self.do_create(pre="a", suf="b") self.do_create(pre="aa", suf=".txt") self.do_create(dir=".") + self.do_create(pre=f"{os.sep}myhome") + self.do_create(suf=f"{os.sep}home") def test_basic_with_bytes_names(self): # mkstemp can create files when given name parts all @@ -657,6 +661,8 @@ def test_basic_with_bytes_names(self): self.do_create(dir=d, suf=b"b") self.do_create(dir=d, pre=b"a", suf=b"b") self.do_create(dir=d, pre=b"aa", suf=b".txt") + self.do_create(dir=d, pre=os.fsencode(f"{os.sep}home")) + self.do_create(dir=d, suf=os.fsencode(f"{os.sep}home")) self.do_create(dir=b".") with self.assertRaises(TypeError): self.do_create(dir=".", pre=b"aa", suf=b".txt") @@ -724,6 +730,8 @@ def do_create(self, dir=None, pre=None, suf=None): pre = output_type() if suf is None: suf = output_type() + pre = os.path.basename(pre) + suf = os.path.basename(suf) name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf) try: @@ -740,6 +748,8 @@ def test_basic(self): os.rmdir(self.do_create(suf="b")) os.rmdir(self.do_create(pre="a", suf="b")) os.rmdir(self.do_create(pre="aa", suf=".txt")) + os.rmdir(self.do_create(pre=f"{os.sep}home")) + os.rmdir(self.do_create(suf=f"{os.sep}home")) def test_basic_with_bytes_names(self): # mkdtemp can create directories when given all binary parts @@ -749,6 +759,8 @@ def test_basic_with_bytes_names(self): os.rmdir(self.do_create(dir=d, suf=b"b")) os.rmdir(self.do_create(dir=d, pre=b"a", suf=b"b")) os.rmdir(self.do_create(dir=d, pre=b"aa", suf=b".txt")) + os.rmdir(self.do_create(dir=d, pre=os.fsencode(f"{os.sep}home"))) + os.rmdir(self.do_create(dir=d, suf=os.fsencode(f"{os.sep}home"))) with self.assertRaises(TypeError): os.rmdir(self.do_create(dir=d, pre="aa", suf=b".txt")) with self.assertRaises(TypeError): @@ -943,9 +955,19 @@ def test_many(self): class TestNamedTemporaryFile(BaseTestCase): """Test NamedTemporaryFile().""" - def do_create(self, dir=None, pre="", suf="", delete=True): + def do_create(self, dir=None, pre=None, suf=None, delete=True): + output_type = tempfile._infer_return_type(dir, pre, suf) if dir is None: - dir = tempfile.gettempdir() + if output_type is str: + dir = tempfile.gettempdir() + else: + dir = tempfile.gettempdirb() + if pre is None: + pre = output_type() + if suf is None: + suf = output_type() + pre = os.path.basename(pre) + suf = os.path.basename(suf) file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf, delete=delete) @@ -960,6 +982,10 @@ def test_basic(self): self.do_create(suf="b") self.do_create(pre="a", suf="b") self.do_create(pre="aa", suf=".txt") + self.do_create(pre=f"{os.sep}home") + self.do_create(pre=os.fsencode(f"{os.sep}home")) + self.do_create(suf=f"{os.sep}home") + self.do_create(suf=os.fsencode(f"{os.sep}home")) def test_method_lookup(self): # Issue #18879: Looking up a temporary file method should keep it diff --git a/Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst b/Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst new file mode 100644 index 00000000000000..06ae5cf4f16213 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst @@ -0,0 +1,2 @@ +Sanitize the ``prefix`` and ``suffix`` arguments to the functions: :func:`tempfile.mkdtemp`, :func:`tempfile.mkstemp` and :func:`tempfile.NamedTemporaryFile`. +If the value of ``prefix`` or ``suffix`` contain a directory separator then the basename of the value is used.