Skip to content

Commit 04ec450

Browse files
committed
Merge pull request jaraco#9
2 parents 996a3fa + d36450e commit 04ec450

File tree

2 files changed

+75
-47
lines changed

2 files changed

+75
-47
lines changed

path.py

+61-47
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,27 @@ class path(unicode):
7777
counterparts in os.path.
7878
"""
7979

80+
# Use an alternate path module (e.g. posixpath)
81+
module = os.path
82+
_subclass_for_module = {}
83+
@classmethod
84+
def using_module(cls, module, value=None):
85+
if module in cls._subclass_for_module:
86+
subclass = cls._subclass_for_module[module]
87+
else:
88+
subclass_name = cls.__name__ + '_' + module.__name__
89+
bases = (cls,)
90+
ns = {'module': module}
91+
subclass = type(subclass_name, bases, ns)
92+
cls._subclass_for_module[module] = subclass
93+
if value is None:
94+
return subclass
95+
return subclass(value)
96+
8097
# --- Special Python methods.
8198

8299
def __repr__(self):
83-
return 'path(%s)' % super(path, self).__repr__()
100+
return '%s(%s)' % (type(self).__name__, super(path, self).__repr__())
84101

85102
# Adding a path and a string yields a path.
86103
def __add__(self, more):
@@ -101,7 +118,7 @@ def __div__(self, rel):
101118
Join two path components, adding a separator character if
102119
needed.
103120
"""
104-
return self.__class__(os.path.join(self, rel))
121+
return self.__class__(self.module.join(self, rel))
105122

106123
# Make the / operator work even when true division is enabled.
107124
__truediv__ = __div__
@@ -121,14 +138,14 @@ def getcwd(cls):
121138
#
122139
# --- Operations on path strings.
123140

124-
def abspath(self): return self.__class__(os.path.abspath(self))
125-
def normcase(self): return self.__class__(os.path.normcase(self))
126-
def normpath(self): return self.__class__(os.path.normpath(self))
127-
def realpath(self): return self.__class__(os.path.realpath(self))
128-
def expanduser(self): return self.__class__(os.path.expanduser(self))
129-
def expandvars(self): return self.__class__(os.path.expandvars(self))
130-
def dirname(self): return self.__class__(os.path.dirname(self))
131-
def basename(self): return self.__class__(os.path.basename(self))
141+
def abspath(self): return self.__class__(self.module.abspath(self))
142+
def normcase(self): return self.__class__(self.module.normcase(self))
143+
def normpath(self): return self.__class__(self.module.normpath(self))
144+
def realpath(self): return self.__class__(self.module.realpath(self))
145+
def expanduser(self): return self.__class__(self.module.expanduser(self))
146+
def expandvars(self): return self.__class__(self.module.expandvars(self))
147+
def dirname(self): return self.__class__(self.module.dirname(self))
148+
def basename(self): return self.__class__(self.module.basename(self))
132149

133150
def expand(self):
134151
""" Clean up a filename by calling expandvars(),
@@ -140,15 +157,15 @@ def expand(self):
140157
return self.expandvars().expanduser().normpath()
141158

142159
def _get_namebase(self):
143-
base, ext = os.path.splitext(self.name)
160+
base, ext = self.module.splitext(self.name)
144161
return base
145162

146163
def _get_ext(self):
147-
f, ext = os.path.splitext(self)
164+
f, ext = self.module.splitext(self)
148165
return ext
149166

150167
def _get_drive(self):
151-
drive, r = os.path.splitdrive(self)
168+
drive, r = self.module.splitdrive(self)
152169
return self.__class__(drive)
153170

154171
parent = property(
@@ -185,7 +202,7 @@ def _get_drive(self):
185202

186203
def splitpath(self):
187204
""" p.splitpath() -> Return (p.parent, p.name). """
188-
parent, child = os.path.split(self)
205+
parent, child = self.module.split(self)
189206
return self.__class__(parent), child
190207

191208
def splitdrive(self):
@@ -195,7 +212,7 @@ def splitdrive(self):
195212
no drive specifier, p.drive is empty, so the return value
196213
is simply (path(''), p). This is always the case on Unix.
197214
"""
198-
drive, rel = os.path.splitdrive(self)
215+
drive, rel = self.module.splitdrive(self)
199216
return self.__class__(drive), rel
200217

201218
def splitext(self):
@@ -208,7 +225,7 @@ def splitext(self):
208225
last path segment. This has the property that if
209226
(a, b) == p.splitext(), then a + b == p.
210227
"""
211-
filename, ext = os.path.splitext(self)
228+
filename, ext = self.module.splitext(self)
212229
return self.__class__(filename), ext
213230

214231
def stripext(self):
@@ -219,26 +236,25 @@ def stripext(self):
219236
"""
220237
return self.splitext()[0]
221238

222-
if hasattr(os.path, 'splitunc'):
223-
def splitunc(self):
224-
unc, rest = os.path.splitunc(self)
225-
return self.__class__(unc), rest
239+
def splitunc(self):
240+
unc, rest = self.module.splitunc(self)
241+
return self.__class__(unc), rest
226242

227-
def _get_uncshare(self):
228-
unc, r = os.path.splitunc(self)
229-
return self.__class__(unc)
243+
def _get_uncshare(self):
244+
unc, r = self.module.splitunc(self)
245+
return self.__class__(unc)
230246

231-
uncshare = property(
232-
_get_uncshare, None, None,
233-
""" The UNC mount point for this path.
234-
This is empty for paths on local drives. """)
247+
uncshare = property(
248+
_get_uncshare, None, None,
249+
""" The UNC mount point for this path.
250+
This is empty for paths on local drives. """)
235251

236252
def joinpath(self, *args):
237253
""" Join two or more path components, adding a separator
238254
character (os.sep) if needed. Returns a new path
239255
object.
240256
"""
241-
return self.__class__(os.path.join(self, *args))
257+
return self.__class__(self.module.join(self, *args))
242258

243259
def splitall(self):
244260
r""" Return a list of the path components in this path.
@@ -283,14 +299,14 @@ def relpathto(self, dest):
283299
# Don't normcase dest! We want to preserve the case.
284300
dest_list = dest.splitall()
285301

286-
if orig_list[0] != os.path.normcase(dest_list[0]):
302+
if orig_list[0] != self.module.normcase(dest_list[0]):
287303
# Can't get here from there.
288304
return dest
289305

290306
# Find the location where the two paths start to differ.
291307
i = 0
292308
for start_seg, dest_seg in zip(orig_list, dest_list):
293-
if start_seg != os.path.normcase(dest_seg):
309+
if start_seg != self.module.normcase(dest_seg):
294310
break
295311
i += 1
296312

@@ -304,7 +320,7 @@ def relpathto(self, dest):
304320
# If they happen to be identical, use os.curdir.
305321
relpath = os.curdir
306322
else:
307-
relpath = os.path.join(*segments)
323+
relpath = self.module.join(*segments)
308324
return self.__class__(relpath)
309325

310326
# --- Listing, searching, walking, and matching
@@ -796,33 +812,31 @@ def read_hexhash(self, hash_name):
796812
# (e.g. isdir on Windows, Python 3.2.2), and compiled functions don't get
797813
# bound. Playing it safe and wrapping them all in method calls.
798814

799-
def isabs(self): return os.path.isabs(self)
800-
def exists(self): return os.path.exists(self)
801-
def isdir(self): return os.path.isdir(self)
802-
def isfile(self): return os.path.isfile(self)
803-
def islink(self): return os.path.islink(self)
804-
def ismount(self): return os.path.ismount(self)
815+
def isabs(self): return self.module.isabs(self)
816+
def exists(self): return self.module.exists(self)
817+
def isdir(self): return self.module.isdir(self)
818+
def isfile(self): return self.module.isfile(self)
819+
def islink(self): return self.module.islink(self)
820+
def ismount(self): return self.module.ismount(self)
805821

806-
if hasattr(os.path, 'samefile'):
807-
def samefile(self): return os.path.samefile(self)
822+
def samefile(self): return self.module.samefile(self)
808823

809-
def getatime(self): return os.path.getatime(self)
824+
def getatime(self): return self.module.getatime(self)
810825
atime = property(
811826
getatime, None, None,
812827
""" Last access time of the file. """)
813828

814-
def getmtime(self): return os.path.getmtime(self)
829+
def getmtime(self): return self.module.getmtime(self)
815830
mtime = property(
816831
getmtime, None, None,
817832
""" Last-modified time of the file. """)
818833

819-
if hasattr(os.path, 'getctime'):
820-
def getctime(self): return os.path.getctime(self)
821-
ctime = property(
822-
getctime, None, None,
823-
""" Creation time of the file. """)
834+
def getctime(self): return self.module.getctime(self)
835+
ctime = property(
836+
getctime, None, None,
837+
""" Creation time of the file. """)
824838

825-
def getsize(self): return os.path.getsize(self)
839+
def getsize(self): return self.module.getsize(self)
826840
size = property(
827841
getsize, None, None,
828842
""" Size of the file, in bytes. """)

test_path.py

+14
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import shutil
2828
import tempfile
2929
import time
30+
import ntpath
31+
import posixpath
3032

3133
from path import path, __version__ as path_version
3234

@@ -127,6 +129,18 @@ def testUNC(self):
127129
self.assert_(p.uncshare == r'\\python1\share1')
128130
self.assert_(p.splitunc() == os.path.splitunc(str(p)))
129131

132+
def testExplicitModule(self):
133+
nt_ok = path.using_module(ntpath, r'foo\bar\baz')
134+
posix_ok = path.using_module(posixpath, r'foo/bar/baz')
135+
posix_wrong = path.using_module(posixpath, r'foo\bar\baz')
136+
137+
self.assertEqual(nt_ok.dirname(), r'foo\bar')
138+
self.assertEqual(posix_ok.dirname(), r'foo/bar')
139+
self.assertEqual(posix_wrong.dirname(), '')
140+
141+
self.assertEqual(nt_ok / 'quux', r'foo\bar\baz\quux')
142+
self.assertEqual(posix_ok / 'quux', r'foo/bar/baz/quux')
143+
130144
class ReturnSelfTestCase(unittest.TestCase):
131145
def setUp(self):
132146
# Create a temporary directory.

0 commit comments

Comments
 (0)