pathlib.py 49 KB

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