pathlib.py 49 KB

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