__init__.py 61 KB

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