Skip to content

Commit cb5ec77

Browse files
committed
Issue #21127: Path objects can now be instantiated from str subclass instances (such as numpy.str_).
Thanks to Antony Lee for the report and preliminary patch.
1 parent 9573638 commit cb5ec77

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

Lib/pathlib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,8 +574,8 @@ def _parse_args(cls, args):
574574
if isinstance(a, PurePath):
575575
parts += a._parts
576576
elif isinstance(a, str):
577-
# Assuming a str
578-
parts.append(a)
577+
# Force-cast str subclasses to str (issue #21127)
578+
parts.append(str(a))
579579
else:
580580
raise TypeError(
581581
"argument should be a path or str object, not %r"

Lib/test/test_pathlib.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,25 @@ def test_constructor_common(self):
197197
self.assertEqual(P(P('a'), 'b'), P('a/b'))
198198
self.assertEqual(P(P('a'), P('b')), P('a/b'))
199199

200+
def _check_str_subclass(self, *args):
201+
# Issue #21127: it should be possible to construct a PurePath object
202+
# from an str subclass instance, and it then gets converted to
203+
# a pure str object.
204+
class StrSubclass(str):
205+
pass
206+
P = self.cls
207+
p = P(*(StrSubclass(x) for x in args))
208+
self.assertEqual(p, P(*args))
209+
for part in p.parts:
210+
self.assertIs(type(part), str)
211+
212+
def test_str_subclass_common(self):
213+
self._check_str_subclass('')
214+
self._check_str_subclass('.')
215+
self._check_str_subclass('a')
216+
self._check_str_subclass('a/b.txt')
217+
self._check_str_subclass('/a/b.txt')
218+
200219
def test_join_common(self):
201220
P = self.cls
202221
p = P('a/b')
@@ -690,6 +709,17 @@ def test_str(self):
690709
p = self.cls('//a/b/c/d')
691710
self.assertEqual(str(p), '\\\\a\\b\\c\\d')
692711

712+
def test_str_subclass(self):
713+
self._check_str_subclass('c:')
714+
self._check_str_subclass('c:a')
715+
self._check_str_subclass('c:a\\b.txt')
716+
self._check_str_subclass('c:\\')
717+
self._check_str_subclass('c:\\a')
718+
self._check_str_subclass('c:\\a\\b.txt')
719+
self._check_str_subclass('\\\\some\\share')
720+
self._check_str_subclass('\\\\some\\share\\a')
721+
self._check_str_subclass('\\\\some\\share\\a\\b.txt')
722+
693723
def test_eq(self):
694724
P = self.cls
695725
self.assertEqual(P('c:a/b'), P('c:a/b'))

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ Julia Lawall
743743
Chris Lawrence
744744
Brian Leair
745745
Mathieu Leduc-Hamel
746+
Antony Lee
746747
Christopher Lee
747748
Inyeol Lee
748749
James Lee

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ Core and Builtins
3939
Library
4040
-------
4141

42+
- Issue #21127: Path objects can now be instantiated from str subclass
43+
instances (such as numpy.str_).
44+
4245
- Issue #15002: urllib.response object to use _TemporaryFileWrapper (and
4346
_TemporaryFileCloser) facility. Provides a better way to handle file
4447
descriptor close. Patch contributed by Christian Theune.

0 commit comments

Comments
 (0)