From 05e9cab32267c86fbe03be2b154a85eb302ba944 Mon Sep 17 00:00:00 2001 From: Bar Harel Date: Sun, 22 Dec 2019 11:57:27 +0200 Subject: [PATCH 1/3] backport --- Lib/os.py | 6 +++++- Lib/test/test_os.py | 11 +++++++++++ .../Library/2019-11-22-12-08-52.bpo-38878.EJ0cFf.rst | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2019-11-22-12-08-52.bpo-38878.EJ0cFf.rst diff --git a/Lib/os.py b/Lib/os.py index 52d3f1d7415854e..253cad1a59f35ad 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -26,6 +26,8 @@ import sys import stat as st +from _collections_abc import _check_methods + _names = sys.builtin_module_names # Note: more names are added to __all__ later. @@ -1070,7 +1072,9 @@ def __fspath__(self): @classmethod def __subclasshook__(cls, subclass): - return hasattr(subclass, '__fspath__') + if cls is PathLike: + return _check_methods(subclass, '__fspath__') + return NotImplemented if name == 'nt': diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 4a076e3bbf5426b..ba32f096788ac33 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -4017,6 +4017,17 @@ def test_bad_pathlike(self): self.assertRaises(ZeroDivisionError, self.fspath, FakePath(ZeroDivisionError())) + def test_pathlike_subclasshook(self): + # bpo-38878: subclasshook causes subclass checks + # true on abstract implementation. + class A(os.PathLike): + pass + self.assertFalse(issubclass(FakePath, A)) + self.assertTrue(issubclass(FakePath, os.PathLike)) + + def test_pathlike_class_getitem(self): + self.assertIs(os.PathLike[bytes], os.PathLike) + class TimesTests(unittest.TestCase): def test_times(self): diff --git a/Misc/NEWS.d/next/Library/2019-11-22-12-08-52.bpo-38878.EJ0cFf.rst b/Misc/NEWS.d/next/Library/2019-11-22-12-08-52.bpo-38878.EJ0cFf.rst new file mode 100644 index 000000000000000..9cbdf08dd53e318 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-11-22-12-08-52.bpo-38878.EJ0cFf.rst @@ -0,0 +1,2 @@ +Fixed __subclasshook__ of :class:`os.PathLike` to return a correct result +upon inheritence. Patch by Bar Harel. From 7c28111e5bbb8baa52145fb4521bcbb7c477bf20 Mon Sep 17 00:00:00 2001 From: Bar Harel Date: Mon, 23 Dec 2019 15:13:02 +0200 Subject: [PATCH 2/3] [3.8] bpo-38878: Fix os.PathLike __subclasshook__ (GH-17336) Quick subclasshook fix using the same method is being used in collections.abc (up to a certain degree).. (cherry picked from commit eae87e3e4e0cb9a0ce10c2e101acb6995d79e09c) Co-authored-by: Bar Harel From 0c9507062d73f29d1b22fa0d288d69c5ade984f7 Mon Sep 17 00:00:00 2001 From: Bar Harel Date: Mon, 23 Dec 2019 15:20:01 +0200 Subject: [PATCH 3/3] backported an extra test by mistake --- Lib/test/test_os.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index ba32f096788ac33..11454b2e88ff65a 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -4025,9 +4025,6 @@ class A(os.PathLike): self.assertFalse(issubclass(FakePath, A)) self.assertTrue(issubclass(FakePath, os.PathLike)) - def test_pathlike_class_getitem(self): - self.assertIs(os.PathLike[bytes], os.PathLike) - class TimesTests(unittest.TestCase): def test_times(self):