pathlib.py 51 KB

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