pathlib.py 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  1. import fnmatch
  2. import functools
  3. import io
  4. import ntpath
  5. import os
  6. import posixpath
  7. import re
  8. import sys
  9. import time
  10. from collections import Sequence
  11. from contextlib import contextmanager
  12. from errno import EINVAL, ENOENT
  13. from operator import attrgetter
  14. from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
  15. try:
  16. from urllib import quote as urlquote, quote as urlquote_from_bytes
  17. except ImportError:
  18. from urllib.parse import quote as urlquote, quote_from_bytes as urlquote_from_bytes
  19. try:
  20. intern = intern
  21. except NameError:
  22. intern = sys.intern
  23. try:
  24. basestring = basestring
  25. except NameError:
  26. basestring = str
  27. supports_symlinks = True
  28. try:
  29. import nt
  30. except ImportError:
  31. nt = None
  32. else:
  33. if sys.getwindowsversion()[:2] >= (6, 0) and sys.version_info >= (3, 2):
  34. from nt import _getfinalpathname
  35. else:
  36. supports_symlinks = False
  37. _getfinalpathname = None
  38. __all__ = [
  39. "PurePath", "PurePosixPath", "PureWindowsPath",
  40. "Path", "PosixPath", "WindowsPath",
  41. ]
  42. #
  43. # Internals
  44. #
  45. _py2 = sys.version_info < (3,)
  46. _py2_fs_encoding = 'ascii'
  47. def _py2_fsencode(parts):
  48. # py2 => minimal unicode support
  49. return [part.encode(_py2_fs_encoding) if isinstance(part, unicode)
  50. else part for part in parts]
  51. def _is_wildcard_pattern(pat):
  52. # Whether this pattern needs actual matching using fnmatch, or can
  53. # be looked up directly as a file.
  54. return "*" in pat or "?" in pat or "[" in pat
  55. class _Flavour(object):
  56. """A flavour implements a particular (platform-specific) set of path
  57. semantics."""
  58. def __init__(self):
  59. self.join = self.sep.join
  60. def parse_parts(self, parts):
  61. if _py2:
  62. parts = _py2_fsencode(parts)
  63. parsed = []
  64. sep = self.sep
  65. altsep = self.altsep
  66. drv = root = ''
  67. it = reversed(parts)
  68. for part in it:
  69. if not part:
  70. continue
  71. if altsep:
  72. part = part.replace(altsep, sep)
  73. drv, root, rel = self.splitroot(part)
  74. if sep in rel:
  75. for x in reversed(rel.split(sep)):
  76. if x and x != '.':
  77. parsed.append(intern(x))
  78. else:
  79. if rel and rel != '.':
  80. parsed.append(intern(rel))
  81. if drv or root:
  82. if not drv:
  83. # If no drive is present, try to find one in the previous
  84. # parts. This makes the result of parsing e.g.
  85. # ("C:", "/", "a") reasonably intuitive.
  86. for part in it:
  87. drv = self.splitroot(part)[0]
  88. if drv:
  89. break
  90. break
  91. if drv or root:
  92. parsed.append(drv + root)
  93. parsed.reverse()
  94. return drv, root, parsed
  95. def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
  96. """
  97. Join the two paths represented by the respective
  98. (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
  99. """
  100. if root2:
  101. if not drv2 and drv:
  102. return drv, root2, [drv + root2] + parts2[1:]
  103. elif drv2:
  104. if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
  105. # Same drive => second path is relative to the first
  106. return drv, root, parts + parts2[1:]
  107. else:
  108. # Second path is non-anchored (common case)
  109. return drv, root, parts + parts2
  110. return drv2, root2, parts2
  111. class _WindowsFlavour(_Flavour):
  112. # Reference for Windows paths can be found at
  113. # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
  114. sep = '\\'
  115. altsep = '/'
  116. has_drv = True
  117. pathmod = ntpath
  118. is_supported = (nt is not None)
  119. drive_letters = (
  120. set(chr(x) for x in range(ord('a'), ord('z') + 1)) |
  121. set(chr(x) for x in range(ord('A'), ord('Z') + 1))
  122. )
  123. ext_namespace_prefix = '\\\\?\\'
  124. reserved_names = (
  125. set(['CON', 'PRN', 'AUX', 'NUL']) |
  126. set(['COM%d' % i for i in range(1, 10)]) |
  127. set(['LPT%d' % i for i in range(1, 10)])
  128. )
  129. # Interesting findings about extended paths:
  130. # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
  131. # but '\\?\c:/a' is not
  132. # - extended paths are always absolute; "relative" extended paths will
  133. # fail.
  134. def splitroot(self, part, sep=sep):
  135. first = part[0:1]
  136. second = part[1:2]
  137. if (second == sep and first == sep):
  138. # XXX extended paths should also disable the collapsing of "."
  139. # components (according to MSDN docs).
  140. prefix, part = self._split_extended_path(part)
  141. first = part[0:1]
  142. second = part[1:2]
  143. else:
  144. prefix = ''
  145. third = part[2:3]
  146. if (second == sep and first == sep and third != sep):
  147. # is a UNC path:
  148. # vvvvvvvvvvvvvvvvvvvvv root
  149. # \\machine\mountpoint\directory\etc\...
  150. # directory ^^^^^^^^^^^^^^
  151. index = part.find(sep, 2)
  152. if index != -1:
  153. index2 = part.find(sep, index + 1)
  154. # a UNC path can't have two slashes in a row
  155. # (after the initial two)
  156. if index2 != index + 1:
  157. if index2 == -1:
  158. index2 = len(part)
  159. if prefix:
  160. return prefix + part[1:index2], sep, part[index2+1:]
  161. else:
  162. return part[:index2], sep, part[index2+1:]
  163. drv = root = ''
  164. if second == ':' and first in self.drive_letters:
  165. drv = part[:2]
  166. part = part[2:]
  167. first = third
  168. if first == sep:
  169. root = first
  170. part = part.lstrip(sep)
  171. return prefix + drv, root, part
  172. def casefold(self, s):
  173. return s.lower()
  174. def casefold_parts(self, parts):
  175. return [p.lower() for p in parts]
  176. def resolve(self, path):
  177. s = str(path)
  178. if not s:
  179. return os.getcwd()
  180. if _getfinalpathname is not None:
  181. return self._ext_to_normal(_getfinalpathname(s))
  182. # Means fallback on absolute
  183. return None
  184. def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
  185. prefix = ''
  186. if s.startswith(ext_prefix):
  187. prefix = s[:4]
  188. s = s[4:]
  189. if s.startswith('UNC\\'):
  190. prefix += s[:3]
  191. s = '\\' + s[3:]
  192. return prefix, s
  193. def _ext_to_normal(self, s):
  194. # Turn back an extended path into a normal DOS-like path
  195. return self._split_extended_path(s)[1]
  196. def is_reserved(self, parts):
  197. # NOTE: the rules for reserved names seem somewhat complicated
  198. # (e.g. r"..\NUL" is reserved but not r"foo\NUL").
  199. # We err on the side of caution and return True for paths which are
  200. # not considered reserved by Windows.
  201. if not parts:
  202. return False
  203. if parts[0].startswith('\\\\'):
  204. # UNC paths are never reserved
  205. return False
  206. return parts[-1].partition('.')[0].upper() in self.reserved_names
  207. def make_uri(self, path):
  208. # Under Windows, file URIs use the UTF-8 encoding.
  209. drive = path.drive
  210. if len(drive) == 2 and drive[1] == ':':
  211. # It's a path on a local drive => 'file:///c:/a/b'
  212. rest = path.as_posix()[2:].lstrip('/')
  213. return 'file:///%s/%s' % (
  214. drive, urlquote_from_bytes(rest.encode('utf-8')))
  215. else:
  216. # It's a path on a network drive => 'file://host/share/a/b'
  217. return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
  218. class _PosixFlavour(_Flavour):
  219. sep = '/'
  220. altsep = ''
  221. has_drv = False
  222. pathmod = posixpath
  223. is_supported = (os.name != 'nt')
  224. def splitroot(self, part, sep=sep):
  225. if part and part[0] == sep:
  226. stripped_part = part.lstrip(sep)
  227. # According to POSIX path resolution:
  228. # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
  229. # "A pathname that begins with two successive slashes may be
  230. # interpreted in an implementation-defined manner, although more
  231. # than two leading slashes shall be treated as a single slash".
  232. if len(part) - len(stripped_part) == 2:
  233. return '', sep * 2, stripped_part
  234. else:
  235. return '', sep, stripped_part
  236. else:
  237. return '', '', part
  238. def casefold(self, s):
  239. return s
  240. def casefold_parts(self, parts):
  241. return parts
  242. def resolve(self, path):
  243. sep = self.sep
  244. accessor = path._accessor
  245. seen = {}
  246. def _resolve(path, rest):
  247. if rest.startswith(sep):
  248. path = ''
  249. for name in rest.split(sep):
  250. if not name or name == '.':
  251. # current dir
  252. continue
  253. if name == '..':
  254. # parent dir
  255. path, _, _ = path.rpartition(sep)
  256. continue
  257. newpath = path + sep + name
  258. if newpath in seen:
  259. # Already seen this path
  260. path = seen[newpath]
  261. if path is not None:
  262. # use cached value
  263. continue
  264. # The symlink is not resolved, so we must have a symlink loop.
  265. raise RuntimeError("Symlink loop from %r" % newpath)
  266. # Resolve the symbolic link
  267. try:
  268. target = accessor.readlink(newpath)
  269. except OSError as e:
  270. if e.errno != EINVAL:
  271. raise
  272. # Not a symlink
  273. path = newpath
  274. else:
  275. seen[newpath] = None # not resolved symlink
  276. path = _resolve(path, target)
  277. seen[newpath] = path # resolved symlink
  278. return path
  279. # NOTE: according to POSIX, getcwd() cannot contain path components
  280. # which are symlinks.
  281. base = '' if path.is_absolute() else os.getcwd()
  282. return _resolve(base, str(path)) or sep
  283. def is_reserved(self, parts):
  284. return False
  285. def make_uri(self, path):
  286. # We represent the path using the local filesystem encoding,
  287. # for portability to other applications.
  288. bpath = bytes(path)
  289. return 'file://' + urlquote_from_bytes(bpath)
  290. _windows_flavour = _WindowsFlavour()
  291. _posix_flavour = _PosixFlavour()
  292. class _Accessor:
  293. """An accessor implements a particular (system-specific or not) way of
  294. accessing paths on the filesystem."""
  295. class _NormalAccessor(_Accessor):
  296. def _wrap_strfunc(strfunc):
  297. @functools.wraps(strfunc)
  298. def wrapped(pathobj, *args):
  299. return strfunc(str(pathobj), *args)
  300. return staticmethod(wrapped)
  301. def _wrap_binary_strfunc(strfunc):
  302. @functools.wraps(strfunc)
  303. def wrapped(pathobjA, pathobjB, *args):
  304. return strfunc(str(pathobjA), str(pathobjB), *args)
  305. return staticmethod(wrapped)
  306. stat = _wrap_strfunc(os.stat)
  307. lstat = _wrap_strfunc(os.lstat)
  308. open = _wrap_strfunc(os.open)
  309. listdir = _wrap_strfunc(os.listdir)
  310. chmod = _wrap_strfunc(os.chmod)
  311. if hasattr(os, "lchmod"):
  312. lchmod = _wrap_strfunc(os.lchmod)
  313. else:
  314. def lchmod(self, pathobj, mode):
  315. raise NotImplementedError("lchmod() not available on this system")
  316. mkdir = _wrap_strfunc(os.mkdir)
  317. unlink = _wrap_strfunc(os.unlink)
  318. rmdir = _wrap_strfunc(os.rmdir)
  319. rename = _wrap_binary_strfunc(os.rename)
  320. if sys.version_info >= (3, 3):
  321. replace = _wrap_binary_strfunc(os.replace)
  322. if nt:
  323. if supports_symlinks:
  324. symlink = _wrap_binary_strfunc(os.symlink)
  325. else:
  326. def symlink(a, b, target_is_directory):
  327. raise NotImplementedError("symlink() not available on this system")
  328. else:
  329. # Under POSIX, os.symlink() takes two args
  330. @staticmethod
  331. def symlink(a, b, target_is_directory):
  332. return os.symlink(str(a), str(b))
  333. utime = _wrap_strfunc(os.utime)
  334. # Helper for resolve()
  335. def readlink(self, path):
  336. return os.readlink(path)
  337. _normal_accessor = _NormalAccessor()
  338. #
  339. # Globbing helpers
  340. #
  341. @contextmanager
  342. def _cached(func):
  343. try:
  344. func.__cached__
  345. yield func
  346. except AttributeError:
  347. cache = {}
  348. def wrapper(*args):
  349. try:
  350. return cache[args]
  351. except KeyError:
  352. value = cache[args] = func(*args)
  353. return value
  354. wrapper.__cached__ = True
  355. try:
  356. yield wrapper
  357. finally:
  358. cache.clear()
  359. def _make_selector(pattern_parts):
  360. pat = pattern_parts[0]
  361. child_parts = pattern_parts[1:]
  362. if pat == '**':
  363. cls = _RecursiveWildcardSelector
  364. elif '**' in pat:
  365. raise ValueError("Invalid pattern: '**' can only be an entire path component")
  366. elif _is_wildcard_pattern(pat):
  367. cls = _WildcardSelector
  368. else:
  369. cls = _PreciseSelector
  370. return cls(pat, child_parts)
  371. if hasattr(functools, "lru_cache"):
  372. _make_selector = functools.lru_cache()(_make_selector)
  373. class _Selector:
  374. """A selector matches a specific glob pattern part against the children
  375. of a given path."""
  376. def __init__(self, child_parts):
  377. self.child_parts = child_parts
  378. if child_parts:
  379. self.successor = _make_selector(child_parts)
  380. else:
  381. self.successor = _TerminatingSelector()
  382. def select_from(self, parent_path):
  383. """Iterate over all child paths of `parent_path` matched by this
  384. selector. This can contain parent_path itself."""
  385. path_cls = type(parent_path)
  386. is_dir = path_cls.is_dir
  387. exists = path_cls.exists
  388. listdir = parent_path._accessor.listdir
  389. return self._select_from(parent_path, is_dir, exists, listdir)
  390. class _TerminatingSelector:
  391. def _select_from(self, parent_path, is_dir, exists, listdir):
  392. yield parent_path
  393. class _PreciseSelector(_Selector):
  394. def __init__(self, name, child_parts):
  395. self.name = name
  396. _Selector.__init__(self, child_parts)
  397. def _select_from(self, parent_path, is_dir, exists, listdir):
  398. if not is_dir(parent_path):
  399. return
  400. path = parent_path._make_child_relpath(self.name)
  401. if exists(path):
  402. for p in self.successor._select_from(path, is_dir, exists, listdir):
  403. yield p
  404. class _WildcardSelector(_Selector):
  405. def __init__(self, pat, child_parts):
  406. self.pat = re.compile(fnmatch.translate(pat))
  407. _Selector.__init__(self, child_parts)
  408. def _select_from(self, parent_path, is_dir, exists, listdir):
  409. if not is_dir(parent_path):
  410. return
  411. cf = parent_path._flavour.casefold
  412. for name in listdir(parent_path):
  413. casefolded = cf(name)
  414. if self.pat.match(casefolded):
  415. path = parent_path._make_child_relpath(name)
  416. for p in self.successor._select_from(path, is_dir, exists, listdir):
  417. yield p
  418. class _RecursiveWildcardSelector(_Selector):
  419. def __init__(self, pat, child_parts):
  420. _Selector.__init__(self, child_parts)
  421. def _iterate_directories(self, parent_path, is_dir, listdir):
  422. yield parent_path
  423. for name in listdir(parent_path):
  424. path = parent_path._make_child_relpath(name)
  425. if is_dir(path):
  426. for p in self._iterate_directories(path, is_dir, listdir):
  427. yield p
  428. def _select_from(self, parent_path, is_dir, exists, listdir):
  429. if not is_dir(parent_path):
  430. return
  431. with _cached(listdir) as listdir:
  432. yielded = set()
  433. try:
  434. successor_select = self.successor._select_from
  435. for starting_point in self._iterate_directories(parent_path, is_dir, listdir):
  436. for p in successor_select(starting_point, is_dir, exists, listdir):
  437. if p not in yielded:
  438. yield p
  439. yielded.add(p)
  440. finally:
  441. yielded.clear()
  442. #
  443. # Public API
  444. #
  445. class _PathParents(Sequence):
  446. """This object provides sequence-like access to the logical ancestors
  447. of a path. Don't try to construct it yourself."""
  448. __slots__ = ('_pathcls', '_drv', '_root', '_parts')
  449. def __init__(self, path):
  450. # We don't store the instance to avoid reference cycles
  451. self._pathcls = type(path)
  452. self._drv = path._drv
  453. self._root = path._root
  454. self._parts = path._parts
  455. def __len__(self):
  456. if self._drv or self._root:
  457. return len(self._parts) - 1
  458. else:
  459. return len(self._parts)
  460. def __getitem__(self, idx):
  461. if idx < 0 or idx >= len(self):
  462. raise IndexError(idx)
  463. return self._pathcls._from_parsed_parts(self._drv, self._root,
  464. self._parts[:-idx - 1])
  465. def __repr__(self):
  466. return "<{0}.parents>".format(self._pathcls.__name__)
  467. class PurePath(object):
  468. """PurePath represents a filesystem path and offers operations which
  469. don't imply any actual filesystem I/O. Depending on your system,
  470. instantiating a PurePath will return either a PurePosixPath or a
  471. PureWindowsPath object. You can also instantiate either of these classes
  472. directly, regardless of your system.
  473. """
  474. __slots__ = (
  475. '_drv', '_root', '_parts',
  476. '_str', '_hash', '_pparts', '_cached_cparts',
  477. )
  478. def __new__(cls, *args):
  479. """Construct a PurePath from one or several strings and or existing
  480. PurePath objects. The strings and path objects are combined so as
  481. to yield a canonicalized path, which is incorporated into the
  482. new PurePath object.
  483. """
  484. if cls is PurePath:
  485. cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
  486. return cls._from_parts(args)
  487. def __reduce__(self):
  488. # Using the parts tuple helps share interned path parts
  489. # when pickling related paths.
  490. return (self.__class__, tuple(self._parts))
  491. @classmethod
  492. def _parse_args(cls, args):
  493. # This is useful when you don't want to create an instance, just
  494. # canonicalize some constructor arguments.
  495. parts = []
  496. for a in args:
  497. if isinstance(a, PurePath):
  498. parts += a._parts
  499. elif isinstance(a, basestring):
  500. parts.append(a)
  501. else:
  502. raise TypeError(
  503. "argument should be a path or str object, not %r"
  504. % type(a))
  505. return cls._flavour.parse_parts(parts)
  506. @classmethod
  507. def _from_parts(cls, args, init=True):
  508. # We need to call _parse_args on the instance, so as to get the
  509. # right flavour.
  510. self = object.__new__(cls)
  511. drv, root, parts = self._parse_args(args)
  512. self._drv = drv
  513. self._root = root
  514. self._parts = parts
  515. if init:
  516. self._init()
  517. return self
  518. @classmethod
  519. def _from_parsed_parts(cls, drv, root, parts, init=True):
  520. self = object.__new__(cls)
  521. self._drv = drv
  522. self._root = root
  523. self._parts = parts
  524. if init:
  525. self._init()
  526. return self
  527. @classmethod
  528. def _format_parsed_parts(cls, drv, root, parts):
  529. if drv or root:
  530. return drv + root + cls._flavour.join(parts[1:])
  531. else:
  532. return cls._flavour.join(parts)
  533. def _init(self):
  534. # Overriden in concrete Path
  535. pass
  536. def _make_child(self, args):
  537. drv, root, parts = self._parse_args(args)
  538. drv, root, parts = self._flavour.join_parsed_parts(
  539. self._drv, self._root, self._parts, drv, root, parts)
  540. return self._from_parsed_parts(drv, root, parts)
  541. def __str__(self):
  542. """Return the string representation of the path, suitable for
  543. passing to system calls."""
  544. try:
  545. return self._str
  546. except AttributeError:
  547. self._str = self._format_parsed_parts(self._drv, self._root,
  548. self._parts) or '.'
  549. return self._str
  550. def as_posix(self):
  551. """Return the string representation of the path with forward (/)
  552. slashes."""
  553. f = self._flavour
  554. return str(self).replace(f.sep, '/')
  555. def __bytes__(self):
  556. """Return the bytes representation of the path. This is only
  557. recommended to use under Unix."""
  558. if sys.version_info < (3, 2):
  559. raise NotImplementedError("needs Python 3.2 or later")
  560. return os.fsencode(str(self))
  561. def __repr__(self):
  562. return "{0}({1!r})".format(self.__class__.__name__, self.as_posix())
  563. def as_uri(self):
  564. """Return the path as a 'file' URI."""
  565. if not self.is_absolute():
  566. raise ValueError("relative path can't be expressed as a file URI")
  567. return self._flavour.make_uri(self)
  568. @property
  569. def _cparts(self):
  570. # Cached casefolded parts, for hashing and comparison
  571. try:
  572. return self._cached_cparts
  573. except AttributeError:
  574. self._cached_cparts = self._flavour.casefold_parts(self._parts)
  575. return self._cached_cparts
  576. def __eq__(self, other):
  577. if not isinstance(other, PurePath):
  578. return NotImplemented
  579. return self._cparts == other._cparts and self._flavour is other._flavour
  580. def __ne__(self, other):
  581. return not self == other
  582. def __hash__(self):
  583. try:
  584. return self._hash
  585. except AttributeError:
  586. self._hash = hash(tuple(self._cparts))
  587. return self._hash
  588. def __lt__(self, other):
  589. if not isinstance(other, PurePath) or self._flavour is not other._flavour:
  590. return NotImplemented
  591. return self._cparts < other._cparts
  592. def __le__(self, other):
  593. if not isinstance(other, PurePath) or self._flavour is not other._flavour:
  594. return NotImplemented
  595. return self._cparts <= other._cparts
  596. def __gt__(self, other):
  597. if not isinstance(other, PurePath) or self._flavour is not other._flavour:
  598. return NotImplemented
  599. return self._cparts > other._cparts
  600. def __ge__(self, other):
  601. if not isinstance(other, PurePath) or self._flavour is not other._flavour:
  602. return NotImplemented
  603. return self._cparts >= other._cparts
  604. drive = property(attrgetter('_drv'),
  605. doc="""The drive prefix (letter or UNC path), if any.""")
  606. root = property(attrgetter('_root'),
  607. doc="""The root of the path, if any.""")
  608. @property
  609. def anchor(self):
  610. """The concatenation of the drive and root, or ''."""
  611. anchor = self._drv + self._root
  612. return anchor
  613. @property
  614. def name(self):
  615. """The final path component, if any."""
  616. parts = self._parts
  617. if len(parts) == (1 if (self._drv or self._root) else 0):
  618. return ''
  619. return parts[-1]
  620. @property
  621. def suffix(self):
  622. """The final component's last suffix, if any."""
  623. name = self.name
  624. i = name.rfind('.')
  625. if 0 < i < len(name) - 1:
  626. return name[i:]
  627. else:
  628. return ''
  629. @property
  630. def suffixes(self):
  631. """A list of the final component's suffixes, if any."""
  632. name = self.name
  633. if name.endswith('.'):
  634. return []
  635. name = name.lstrip('.')
  636. return ['.' + suffix for suffix in name.split('.')[1:]]
  637. @property
  638. def stem(self):
  639. """The final path component, minus its last suffix."""
  640. name = self.name
  641. i = name.rfind('.')
  642. if 0 < i < len(name) - 1:
  643. return name[:i]
  644. else:
  645. return name
  646. def with_name(self, name):
  647. """Return a new path with the file name changed."""
  648. if not self.name:
  649. raise ValueError("%r has an empty name" % (self,))
  650. return self._from_parsed_parts(self._drv, self._root,
  651. self._parts[:-1] + [name])
  652. def with_suffix(self, suffix):
  653. """Return a new path with the file suffix changed (or added, if none)."""
  654. # XXX if suffix is None, should the current suffix be removed?
  655. drv, root, parts = self._flavour.parse_parts((suffix,))
  656. if drv or root or len(parts) != 1:
  657. raise ValueError("Invalid suffix %r" % (suffix))
  658. suffix = parts[0]
  659. if not suffix.startswith('.'):
  660. raise ValueError("Invalid suffix %r" % (suffix))
  661. name = self.name
  662. if not name:
  663. raise ValueError("%r has an empty name" % (self,))
  664. old_suffix = self.suffix
  665. if not old_suffix:
  666. name = name + suffix
  667. else:
  668. name = name[:-len(old_suffix)] + suffix
  669. return self._from_parsed_parts(self._drv, self._root,
  670. self._parts[:-1] + [name])
  671. def relative_to(self, *other):
  672. """Return the relative path to another path identified by the passed
  673. arguments. If the operation is not possible (because this is not
  674. a subpath of the other path), raise ValueError.
  675. """
  676. # For the purpose of this method, drive and root are considered
  677. # separate parts, i.e.:
  678. # Path('c:/').relative_to('c:') gives Path('/')
  679. # Path('c:/').relative_to('/') raise ValueError
  680. if not other:
  681. raise TypeError("need at least one argument")
  682. parts = self._parts
  683. drv = self._drv
  684. root = self._root
  685. if root:
  686. abs_parts = [drv, root] + parts[1:]
  687. else:
  688. abs_parts = parts
  689. to_drv, to_root, to_parts = self._parse_args(other)
  690. if to_root:
  691. to_abs_parts = [to_drv, to_root] + to_parts[1:]
  692. else:
  693. to_abs_parts = to_parts
  694. n = len(to_abs_parts)
  695. cf = self._flavour.casefold_parts
  696. if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
  697. formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
  698. raise ValueError("{!r} does not start with {!r}"
  699. .format(str(self), str(formatted)))
  700. return self._from_parsed_parts('', root if n == 1 else '',
  701. abs_parts[n:])
  702. @property
  703. def parts(self):
  704. """An object providing sequence-like access to the
  705. components in the filesystem path."""
  706. # We cache the tuple to avoid building a new one each time .parts
  707. # is accessed. XXX is this necessary?
  708. try:
  709. return self._pparts
  710. except AttributeError:
  711. self._pparts = tuple(self._parts)
  712. return self._pparts
  713. def joinpath(self, *args):
  714. """Combine this path with one or several arguments, and return a
  715. new path representing either a subpath (if all arguments are relative
  716. paths) or a totally different path (if one of the arguments is
  717. anchored).
  718. """
  719. return self._make_child(args)
  720. def __truediv__(self, key):
  721. return self._make_child((key,))
  722. def __rtruediv__(self, key):
  723. return self._from_parts([key] + self._parts)
  724. if sys.version_info < (3,):
  725. __div__ = __truediv__
  726. __rdiv__ = __rtruediv__
  727. @property
  728. def parent(self):
  729. """The logical parent of the path."""
  730. drv = self._drv
  731. root = self._root
  732. parts = self._parts
  733. if len(parts) == 1 and (drv or root):
  734. return self
  735. return self._from_parsed_parts(drv, root, parts[:-1])
  736. @property
  737. def parents(self):
  738. """A sequence of this path's logical parents."""
  739. return _PathParents(self)
  740. def is_absolute(self):
  741. """True if the path is absolute (has both a root and, if applicable,
  742. a drive)."""
  743. if not self._root:
  744. return False
  745. return not self._flavour.has_drv or bool(self._drv)
  746. def is_reserved(self):
  747. """Return True if the path contains one of the special names reserved
  748. by the system, if any."""
  749. return self._flavour.is_reserved(self._parts)
  750. def match(self, path_pattern):
  751. """
  752. Return True if this path matches the given pattern.
  753. """
  754. cf = self._flavour.casefold
  755. path_pattern = cf(path_pattern)
  756. drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
  757. if not pat_parts:
  758. raise ValueError("empty pattern")
  759. if drv and drv != cf(self._drv):
  760. return False
  761. if root and root != cf(self._root):
  762. return False
  763. parts = self._cparts
  764. if drv or root:
  765. if len(pat_parts) != len(parts):
  766. return False
  767. pat_parts = pat_parts[1:]
  768. elif len(pat_parts) > len(parts):
  769. return False
  770. for part, pat in zip(reversed(parts), reversed(pat_parts)):
  771. if not fnmatch.fnmatchcase(part, pat):
  772. return False
  773. return True
  774. class PurePosixPath(PurePath):
  775. _flavour = _posix_flavour
  776. __slots__ = ()
  777. class PureWindowsPath(PurePath):
  778. _flavour = _windows_flavour
  779. __slots__ = ()
  780. # Filesystem-accessing classes
  781. class Path(PurePath):
  782. __slots__ = (
  783. '_accessor',
  784. )
  785. def __new__(cls, *args, **kwargs):
  786. if cls is Path:
  787. cls = WindowsPath if os.name == 'nt' else PosixPath
  788. self = cls._from_parts(args, init=False)
  789. if not self._flavour.is_supported:
  790. raise NotImplementedError("cannot instantiate %r on your system"
  791. % (cls.__name__,))
  792. self._init()
  793. return self
  794. def _init(self,
  795. # Private non-constructor arguments
  796. template=None,
  797. ):
  798. if template is not None:
  799. self._accessor = template._accessor
  800. else:
  801. self._accessor = _normal_accessor
  802. def _make_child_relpath(self, part):
  803. # This is an optimization used for dir walking. `part` must be
  804. # a single part relative to this path.
  805. parts = self._parts + [part]
  806. return self._from_parsed_parts(self._drv, self._root, parts)
  807. def _opener(self, name, flags, mode=0o666):
  808. # A stub for the opener argument to built-in open()
  809. return self._accessor.open(self, flags, mode)
  810. def _raw_open(self, flags, mode=0o777):
  811. """
  812. Open the file pointed by this path and return a file descriptor,
  813. as os.open() does.
  814. """
  815. return self._accessor.open(self, flags, mode)
  816. # Public API
  817. @classmethod
  818. def cwd(cls):
  819. """Return a new path pointing to the current working directory
  820. (as returned by os.getcwd()).
  821. """
  822. return cls(os.getcwd())
  823. def iterdir(self):
  824. """Iterate over the files in this directory. Does not yield any
  825. result for the special paths '.' and '..'.
  826. """
  827. for name in self._accessor.listdir(self):
  828. if name in ('.', '..'):
  829. # Yielding a path object for these makes little sense
  830. continue
  831. yield self._make_child_relpath(name)
  832. def glob(self, pattern):
  833. """Iterate over this subtree and yield all existing files (of any
  834. kind, including directories) matching the given pattern.
  835. """
  836. pattern = self._flavour.casefold(pattern)
  837. drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
  838. if drv or root:
  839. raise NotImplementedError("Non-relative patterns are unsupported")
  840. selector = _make_selector(tuple(pattern_parts))
  841. for p in selector.select_from(self):
  842. yield p
  843. def rglob(self, pattern):
  844. """Recursively yield all existing files (of any kind, including
  845. directories) matching the given pattern, anywhere in this subtree.
  846. """
  847. pattern = self._flavour.casefold(pattern)
  848. drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
  849. if drv or root:
  850. raise NotImplementedError("Non-relative patterns are unsupported")
  851. selector = _make_selector(("**",) + tuple(pattern_parts))
  852. for p in selector.select_from(self):
  853. yield p
  854. def absolute(self):
  855. """Return an absolute version of this path. This function works
  856. even if the path doesn't point to anything.
  857. No normalization is done, i.e. all '.' and '..' will be kept along.
  858. Use resolve() to get the canonical path to a file.
  859. """
  860. # XXX untested yet!
  861. if self.is_absolute():
  862. return self
  863. # FIXME this must defer to the specific flavour (and, under Windows,
  864. # use nt._getfullpathname())
  865. obj = self._from_parts([os.getcwd()] + self._parts, init=False)
  866. obj._init(template=self)
  867. return obj
  868. def resolve(self):
  869. """
  870. Make the path absolute, resolving all symlinks on the way and also
  871. normalizing it (for example turning slashes into backslashes under
  872. Windows).
  873. """
  874. s = self._flavour.resolve(self)
  875. if s is None:
  876. # No symlink resolution => for consistency, raise an error if
  877. # the path doesn't exist or is forbidden
  878. self.stat()
  879. s = str(self.absolute())
  880. # Now we have no symlinks in the path, it's safe to normalize it.
  881. normed = self._flavour.pathmod.normpath(s)
  882. obj = self._from_parts((normed,), init=False)
  883. obj._init(template=self)
  884. return obj
  885. def stat(self):
  886. """
  887. Return the result of the stat() system call on this path, like
  888. os.stat() does.
  889. """
  890. return self._accessor.stat(self)
  891. def owner(self):
  892. """
  893. Return the login name of the file owner.
  894. """
  895. import pwd
  896. return pwd.getpwuid(self.stat().st_uid).pw_name
  897. def group(self):
  898. """
  899. Return the group name of the file gid.
  900. """
  901. import grp
  902. return grp.getgrgid(self.stat().st_gid).gr_name
  903. def open(self, mode='r', buffering=-1, encoding=None,
  904. errors=None, newline=None):
  905. """
  906. Open the file pointed by this path and return a file object, as
  907. the built-in open() function does.
  908. """
  909. if sys.version_info >= (3, 3):
  910. return io.open(str(self), mode, buffering, encoding, errors, newline,
  911. opener=self._opener)
  912. else:
  913. return io.open(str(self), mode, buffering, encoding, errors, newline)
  914. def touch(self, mode=0o666, exist_ok=True):
  915. """
  916. Create this file with the given access mode, if it doesn't exist.
  917. """
  918. if exist_ok:
  919. # First try to bump modification time
  920. # Implementation note: GNU touch uses the UTIME_NOW option of
  921. # the utimensat() / futimens() functions.
  922. t = time.time()
  923. try:
  924. self._accessor.utime(self, (t, t))
  925. except OSError:
  926. # Avoid exception chaining
  927. pass
  928. else:
  929. return
  930. flags = os.O_CREAT | os.O_WRONLY
  931. if not exist_ok:
  932. flags |= os.O_EXCL
  933. fd = self._raw_open(flags, mode)
  934. os.close(fd)
  935. def mkdir(self, mode=0o777, parents=False):
  936. if not parents:
  937. self._accessor.mkdir(self, mode)
  938. else:
  939. try:
  940. self._accessor.mkdir(self, mode)
  941. except OSError as e:
  942. if e.errno != ENOENT:
  943. raise
  944. self.parent.mkdir(parents=True)
  945. self._accessor.mkdir(self, mode)
  946. def chmod(self, mode):
  947. """
  948. Change the permissions of the path, like os.chmod().
  949. """
  950. self._accessor.chmod(self, mode)
  951. def lchmod(self, mode):
  952. """
  953. Like chmod(), except if the path points to a symlink, the symlink's
  954. permissions are changed, rather than its target's.
  955. """
  956. self._accessor.lchmod(self, mode)
  957. def unlink(self):
  958. """
  959. Remove this file or link.
  960. If the path is a directory, use rmdir() instead.
  961. """
  962. self._accessor.unlink(self)
  963. def rmdir(self):
  964. """
  965. Remove this directory. The directory must be empty.
  966. """
  967. self._accessor.rmdir(self)
  968. def lstat(self):
  969. """
  970. Like stat(), except if the path points to a symlink, the symlink's
  971. status information is returned, rather than its target's.
  972. """
  973. return self._accessor.lstat(self)
  974. def rename(self, target):
  975. """
  976. Rename this path to the given path.
  977. """
  978. self._accessor.rename(self, target)
  979. def replace(self, target):
  980. """
  981. Rename this path to the given path, clobbering the existing
  982. destination if it exists.
  983. """
  984. if sys.version_info < (3, 3):
  985. raise NotImplementedError("replace() is only available "
  986. "with Python 3.3 and later")
  987. self._accessor.replace(self, target)
  988. def symlink_to(self, target, target_is_directory=False):
  989. """
  990. Make this path a symlink pointing to the given path.
  991. Note the order of arguments (self, target) is the reverse of os.symlink's.
  992. """
  993. self._accessor.symlink(target, self, target_is_directory)
  994. # Convenience functions for querying the stat results
  995. def exists(self):
  996. """
  997. Whether this path exists.
  998. """
  999. try:
  1000. self.stat()
  1001. except OSError as e:
  1002. if e.errno != ENOENT:
  1003. raise
  1004. return False
  1005. return True
  1006. def is_dir(self):
  1007. """
  1008. Whether this path is a directory.
  1009. """
  1010. try:
  1011. return S_ISDIR(self.stat().st_mode)
  1012. except OSError as e:
  1013. if e.errno != ENOENT:
  1014. raise
  1015. # Path doesn't exist or is a broken symlink
  1016. # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
  1017. return False
  1018. def is_file(self):
  1019. """
  1020. Whether this path is a regular file (also True for symlinks pointing
  1021. to regular files).
  1022. """
  1023. try:
  1024. return S_ISREG(self.stat().st_mode)
  1025. except OSError as e:
  1026. if e.errno != ENOENT:
  1027. raise
  1028. # Path doesn't exist or is a broken symlink
  1029. # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
  1030. return False
  1031. def is_symlink(self):
  1032. """
  1033. Whether this path is a symbolic link.
  1034. """
  1035. try:
  1036. return S_ISLNK(self.lstat().st_mode)
  1037. except OSError as e:
  1038. if e.errno != ENOENT:
  1039. raise
  1040. # Path doesn't exist
  1041. return False
  1042. def is_block_device(self):
  1043. """
  1044. Whether this path is a block device.
  1045. """
  1046. try:
  1047. return S_ISBLK(self.stat().st_mode)
  1048. except OSError as e:
  1049. if e.errno != ENOENT:
  1050. raise
  1051. # Path doesn't exist or is a broken symlink
  1052. # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
  1053. return False
  1054. def is_char_device(self):
  1055. """
  1056. Whether this path is a character device.
  1057. """
  1058. try:
  1059. return S_ISCHR(self.stat().st_mode)
  1060. except OSError as e:
  1061. if e.errno != ENOENT:
  1062. raise
  1063. # Path doesn't exist or is a broken symlink
  1064. # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
  1065. return False
  1066. def is_fifo(self):
  1067. """
  1068. Whether this path is a FIFO.
  1069. """
  1070. try:
  1071. return S_ISFIFO(self.stat().st_mode)
  1072. except OSError as e:
  1073. if e.errno != ENOENT:
  1074. raise
  1075. # Path doesn't exist or is a broken symlink
  1076. # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
  1077. return False
  1078. def is_socket(self):
  1079. """
  1080. Whether this path is a socket.
  1081. """
  1082. try:
  1083. return S_ISSOCK(self.stat().st_mode)
  1084. except OSError as e:
  1085. if e.errno != ENOENT:
  1086. raise
  1087. # Path doesn't exist or is a broken symlink
  1088. # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
  1089. return False
  1090. class PosixPath(Path, PurePosixPath):
  1091. __slots__ = ()
  1092. class WindowsPath(Path, PureWindowsPath):
  1093. __slots__ = ()