diff -r 7a68a850a579 Lib/pathlib.py --- a/Lib/pathlib.py Thu Jun 02 16:09:49 2016 -0700 +++ b/Lib/pathlib.py Thu Jun 02 17:21:59 2016 -0700 @@ -634,13 +634,17 @@ for a in args: if isinstance(a, PurePath): parts += a._parts - elif isinstance(a, str): - # Force-cast str subclasses to str (issue #21127) - parts.append(str(a)) else: - raise TypeError( - "argument should be a path or str object, not %r" - % type(a)) + if hasattr(a, '__fspath__'): + a = os.fspath(a) + + if isinstance(a, str): + # Force-cast str subclasses to str (issue #21127) + parts.append(str(a)) + else: + raise TypeError( + "argument should be an os.PathLike or str object, not %r" + % type(a)) return cls._flavour.parse_parts(parts) @classmethod @@ -693,6 +697,9 @@ self._parts) or '.' return self._str + def __fspath__(self): + return str(self) + def as_posix(self): """Return the string representation of the path with forward (/) slashes.""" diff -r 7a68a850a579 Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py Thu Jun 02 16:09:49 2016 -0700 +++ b/Lib/test/test_pathlib.py Thu Jun 02 17:21:59 2016 -0700 @@ -190,13 +190,18 @@ P = self.cls p = P('a') self.assertIsInstance(p, P) + class PathLike: + def __fspath__(self): + return "a/b/c" P('a', 'b', 'c') P('/a', 'b', 'c') P('a/b/c') P('/a/b/c') + P(PathLike()) self.assertEqual(P(P('a')), P('a')) self.assertEqual(P(P('a'), 'b'), P('a/b')) self.assertEqual(P(P('a'), P('b')), P('a/b')) + self.assertEqual(P(P('a'), P('b'), P('c')), P(PathLike())) def _check_str_subclass(self, *args): # Issue #21127: it should be possible to construct a PurePath object @@ -384,6 +389,11 @@ parts = p.parts self.assertEqual(parts, (sep, 'a', 'b')) + def test_fspath_common(self): + P = self.cls + p = P('a/b') + self._check_str(p.__fspath__(), ('a/b',)) + def test_equivalences(self): for k, tuples in self.equivalences.items(): canon = k.replace('/', self.sep)