pathlib.py 51 KB

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