From c53f03107880d1c3fafd96d63cd24eee9a84c4e7 Mon Sep 17 00:00:00 2001 From: barneygale Date: Thu, 27 Jan 2022 23:16:32 +0000 Subject: [PATCH 1/6] bpo-46556: emit `DeprecationWarning` from `pathlib.Path.__enter__()` In Python 3.9 / bpo-39682 we made `Path.__exit__()` a no-op, and added a comment in the code mentioning that it should be deprecated in future. The future is here, so let's deprecate it. --- Lib/pathlib.py | 20 +++++++++++-------- .../2022-01-27-23-20-30.bpo-46556.tlpAgS.rst | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-01-27-23-20-30.bpo-46556.tlpAgS.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index d42ee4dc90b431..a7ed5b3f778fb9 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -968,17 +968,21 @@ def _make_child_relpath(self, part): return self._from_parsed_parts(self._drv, self._root, parts) def __enter__(self): + # In previous versions of pathlib, __exit__() marked this path as + # closed; subsequent attempts to perform I/O would raise an IOError. + # This functionality was never documented, and had the effect of + # making Path objects mutable, contrary to PEP 428. + # In Python 3.9 the _closed attribute was removed, and __exit__() + # was made a no-op. + # In Python 3.11 this method began emitting DeprecationWarning + # In Python 3.13 this method and __exit__() should be removed. + warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " + "for removal in Python 3.13. Path objects should not " + "be used as context managers.", + DeprecationWarning, stacklevel=2) return self def __exit__(self, t, v, tb): - # https://bugs.python.org/issue39682 - # In previous versions of pathlib, this method marked this path as - # closed; subsequent attempts to perform I/O would raise an IOError. - # This functionality was never documented, and had the effect of - # making Path objects mutable, contrary to PEP 428. In Python 3.9 the - # _closed attribute was removed, and this method made a no-op. - # This method and __enter__()/__exit__() should be deprecated and - # removed in the future. pass # Public API diff --git a/Misc/NEWS.d/next/Library/2022-01-27-23-20-30.bpo-46556.tlpAgS.rst b/Misc/NEWS.d/next/Library/2022-01-27-23-20-30.bpo-46556.tlpAgS.rst new file mode 100644 index 00000000000000..1209e0e2bd8b0e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-27-23-20-30.bpo-46556.tlpAgS.rst @@ -0,0 +1,2 @@ +Deprecate undocumented support for using a :class:`pathlib.Path` object as a +context manager. From 6bf4483d00366cff24bb7906f5a77e947c1620ca Mon Sep 17 00:00:00 2001 From: barneygale Date: Fri, 28 Jan 2022 13:15:33 +0000 Subject: [PATCH 2/6] Test that using a path as a context manager raises `DeprecationWarning` --- Lib/test/test_pathlib.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 1bf21120a36ca1..e49e605953a9dd 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1445,6 +1445,12 @@ def assertFileNotFound(self, func, *args, **kwargs): def assertEqualNormCase(self, path_a, path_b): self.assertEqual(os.path.normcase(path_a), os.path.normcase(path_b)) + def test_context_manager(self): + # bpo-46556: path context managers are deprecated in Python 3.11. + with self.assertWarns(DeprecationWarning): + with self.cls(): + pass + def _test_cwd(self, p): q = self.cls(os.getcwd()) self.assertEqual(p, q) From 6e086f88b194e6e00fdb0df1e2e6f3893998ec19 Mon Sep 17 00:00:00 2001 From: barneygale Date: Sat, 29 Jan 2022 19:01:11 +0000 Subject: [PATCH 3/6] Tweak comment in `__enter__()` --- Lib/pathlib.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py index a7ed5b3f778fb9..22c4e5198c8d5b 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -972,10 +972,9 @@ def __enter__(self): # closed; subsequent attempts to perform I/O would raise an IOError. # This functionality was never documented, and had the effect of # making Path objects mutable, contrary to PEP 428. - # In Python 3.9 the _closed attribute was removed, and __exit__() - # was made a no-op. - # In Python 3.11 this method began emitting DeprecationWarning - # In Python 3.13 this method and __exit__() should be removed. + # In Python 3.9 __exit__() was made a no-op. + # In Python 3.11 __enter__() began emitting DeprecationWarning. + # In Python 3.13 __enter__() and __exit__() should be removed. warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " "for removal in Python 3.13. Path objects should not " "be used as context managers.", From 8ae345917a2b40ddc5500c368c8919f432a6a5f4 Mon Sep 17 00:00:00 2001 From: barneygale Date: Sun, 30 Jan 2022 10:43:16 +0000 Subject: [PATCH 4/6] Fix up warning from test. --- Lib/test/test_pathlib.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index e49e605953a9dd..a8626f0f2371ad 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1445,12 +1445,6 @@ def assertFileNotFound(self, func, *args, **kwargs): def assertEqualNormCase(self, path_a, path_b): self.assertEqual(os.path.normcase(path_a), os.path.normcase(path_b)) - def test_context_manager(self): - # bpo-46556: path context managers are deprecated in Python 3.11. - with self.assertWarns(DeprecationWarning): - with self.cls(): - pass - def _test_cwd(self, p): q = self.cls(os.getcwd()) self.assertEqual(p, q) @@ -1836,8 +1830,10 @@ def test_with(self): it = p.iterdir() it2 = p.iterdir() next(it2) - with p: - pass + # bpo-46556: path context managers are deprecated in Python 3.11. + with self.assertWarns(DeprecationWarning): + with p: + pass # Using a path as a context manager is a no-op, thus the following # operations should still succeed after the context manage exits. next(it) @@ -1845,8 +1841,9 @@ def test_with(self): p.exists() p.resolve() p.absolute() - with p: - pass + with self.assertWarns(DeprecationWarning): + with p: + pass def test_chmod(self): p = self.cls(BASE) / 'fileA' From 87c9067c3761e74025d275570284b14954ff133f Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 4 Feb 2022 15:57:16 -0800 Subject: [PATCH 5/6] Tweak warning message --- Lib/pathlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 22c4e5198c8d5b..16bdebfb67a3cb 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -976,8 +976,8 @@ def __enter__(self): # In Python 3.11 __enter__() began emitting DeprecationWarning. # In Python 3.13 __enter__() and __exit__() should be removed. warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " - "for removal in Python 3.13. Path objects should not " - "be used as context managers.", + "for removal in Python 3.13; Path objects as context " + "managers is a no-op", DeprecationWarning, stacklevel=2) return self From e150f96fc3cd65ca92dc6d3d5d115827e6bf973d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 4 Feb 2022 15:58:14 -0800 Subject: [PATCH 6/6] Tweak warning message --- Lib/pathlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 16bdebfb67a3cb..5d1b78c500b690 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -976,8 +976,8 @@ def __enter__(self): # In Python 3.11 __enter__() began emitting DeprecationWarning. # In Python 3.13 __enter__() and __exit__() should be removed. warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " - "for removal in Python 3.13; Path objects as context " - "managers is a no-op", + "for removal in Python 3.13; Path objects as a context " + "manager is a no-op", DeprecationWarning, stacklevel=2) return self