test_pathlib.py 115 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849
  1. import contextlib
  2. import collections.abc
  3. import io
  4. import os
  5. import sys
  6. import errno
  7. import pathlib
  8. import pickle
  9. import socket
  10. import stat
  11. import tempfile
  12. import unittest
  13. from unittest import mock
  14. from test.support import import_helper
  15. from test.support import is_emscripten, is_wasi
  16. from test.support import os_helper
  17. from test.support.os_helper import TESTFN, FakePath
  18. try:
  19. import grp, pwd
  20. except ImportError:
  21. grp = pwd = None
  22. class _BaseFlavourTest(object):
  23. def _check_parse_parts(self, arg, expected):
  24. f = self.flavour.parse_parts
  25. sep = self.flavour.sep
  26. altsep = self.flavour.altsep
  27. actual = f([x.replace('/', sep) for x in arg])
  28. self.assertEqual(actual, expected)
  29. if altsep:
  30. actual = f([x.replace('/', altsep) for x in arg])
  31. self.assertEqual(actual, expected)
  32. def test_parse_parts_common(self):
  33. check = self._check_parse_parts
  34. sep = self.flavour.sep
  35. # Unanchored parts.
  36. check([], ('', '', []))
  37. check(['a'], ('', '', ['a']))
  38. check(['a/'], ('', '', ['a']))
  39. check(['a', 'b'], ('', '', ['a', 'b']))
  40. # Expansion.
  41. check(['a/b'], ('', '', ['a', 'b']))
  42. check(['a/b/'], ('', '', ['a', 'b']))
  43. check(['a', 'b/c', 'd'], ('', '', ['a', 'b', 'c', 'd']))
  44. # Collapsing and stripping excess slashes.
  45. check(['a', 'b//c', 'd'], ('', '', ['a', 'b', 'c', 'd']))
  46. check(['a', 'b/c/', 'd'], ('', '', ['a', 'b', 'c', 'd']))
  47. # Eliminating standalone dots.
  48. check(['.'], ('', '', []))
  49. check(['.', '.', 'b'], ('', '', ['b']))
  50. check(['a', '.', 'b'], ('', '', ['a', 'b']))
  51. check(['a', '.', '.'], ('', '', ['a']))
  52. # The first part is anchored.
  53. check(['/a/b'], ('', sep, [sep, 'a', 'b']))
  54. check(['/a', 'b'], ('', sep, [sep, 'a', 'b']))
  55. check(['/a/', 'b'], ('', sep, [sep, 'a', 'b']))
  56. # Ignoring parts before an anchored part.
  57. check(['a', '/b', 'c'], ('', sep, [sep, 'b', 'c']))
  58. check(['a', '/b', '/c'], ('', sep, [sep, 'c']))
  59. class PosixFlavourTest(_BaseFlavourTest, unittest.TestCase):
  60. flavour = pathlib._posix_flavour
  61. def test_parse_parts(self):
  62. check = self._check_parse_parts
  63. # Collapsing of excess leading slashes, except for the double-slash
  64. # special case.
  65. check(['//a', 'b'], ('', '//', ['//', 'a', 'b']))
  66. check(['///a', 'b'], ('', '/', ['/', 'a', 'b']))
  67. check(['////a', 'b'], ('', '/', ['/', 'a', 'b']))
  68. # Paths which look like NT paths aren't treated specially.
  69. check(['c:a'], ('', '', ['c:a']))
  70. check(['c:\\a'], ('', '', ['c:\\a']))
  71. check(['\\a'], ('', '', ['\\a']))
  72. def test_splitroot(self):
  73. f = self.flavour.splitroot
  74. self.assertEqual(f(''), ('', '', ''))
  75. self.assertEqual(f('a'), ('', '', 'a'))
  76. self.assertEqual(f('a/b'), ('', '', 'a/b'))
  77. self.assertEqual(f('a/b/'), ('', '', 'a/b/'))
  78. self.assertEqual(f('/a'), ('', '/', 'a'))
  79. self.assertEqual(f('/a/b'), ('', '/', 'a/b'))
  80. self.assertEqual(f('/a/b/'), ('', '/', 'a/b/'))
  81. # The root is collapsed when there are redundant slashes
  82. # except when there are exactly two leading slashes, which
  83. # is a special case in POSIX.
  84. self.assertEqual(f('//a'), ('', '//', 'a'))
  85. self.assertEqual(f('///a'), ('', '/', 'a'))
  86. self.assertEqual(f('///a/b'), ('', '/', 'a/b'))
  87. # Paths which look like NT paths aren't treated specially.
  88. self.assertEqual(f('c:/a/b'), ('', '', 'c:/a/b'))
  89. self.assertEqual(f('\\/a/b'), ('', '', '\\/a/b'))
  90. self.assertEqual(f('\\a\\b'), ('', '', '\\a\\b'))
  91. class NTFlavourTest(_BaseFlavourTest, unittest.TestCase):
  92. flavour = pathlib._windows_flavour
  93. def test_parse_parts(self):
  94. check = self._check_parse_parts
  95. # First part is anchored.
  96. check(['c:'], ('c:', '', ['c:']))
  97. check(['c:/'], ('c:', '\\', ['c:\\']))
  98. check(['/'], ('', '\\', ['\\']))
  99. check(['c:a'], ('c:', '', ['c:', 'a']))
  100. check(['c:/a'], ('c:', '\\', ['c:\\', 'a']))
  101. check(['/a'], ('', '\\', ['\\', 'a']))
  102. # UNC paths.
  103. check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
  104. check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
  105. check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c']))
  106. # Second part is anchored, so that the first part is ignored.
  107. check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c']))
  108. check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
  109. # UNC paths.
  110. check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
  111. # Collapsing and stripping excess slashes.
  112. check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd']))
  113. # UNC paths.
  114. check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
  115. # Extended paths.
  116. check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\']))
  117. check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a']))
  118. check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b']))
  119. # Extended UNC paths (format is "\\?\UNC\server\share").
  120. check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\']))
  121. check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd']))
  122. # Second part has a root but not drive.
  123. check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c']))
  124. check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
  125. check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c']))
  126. def test_splitroot(self):
  127. f = self.flavour.splitroot
  128. self.assertEqual(f(''), ('', '', ''))
  129. self.assertEqual(f('a'), ('', '', 'a'))
  130. self.assertEqual(f('a\\b'), ('', '', 'a\\b'))
  131. self.assertEqual(f('\\a'), ('', '\\', 'a'))
  132. self.assertEqual(f('\\a\\b'), ('', '\\', 'a\\b'))
  133. self.assertEqual(f('c:a\\b'), ('c:', '', 'a\\b'))
  134. self.assertEqual(f('c:\\a\\b'), ('c:', '\\', 'a\\b'))
  135. # Redundant slashes in the root are collapsed.
  136. self.assertEqual(f('\\\\a'), ('', '\\', 'a'))
  137. self.assertEqual(f('\\\\\\a/b'), ('', '\\', 'a/b'))
  138. self.assertEqual(f('c:\\\\a'), ('c:', '\\', 'a'))
  139. self.assertEqual(f('c:\\\\\\a/b'), ('c:', '\\', 'a/b'))
  140. # Valid UNC paths.
  141. self.assertEqual(f('\\\\a\\b'), ('\\\\a\\b', '\\', ''))
  142. self.assertEqual(f('\\\\a\\b\\'), ('\\\\a\\b', '\\', ''))
  143. self.assertEqual(f('\\\\a\\b\\c\\d'), ('\\\\a\\b', '\\', 'c\\d'))
  144. # These are non-UNC paths (according to ntpath.py and test_ntpath).
  145. # However, command.com says such paths are invalid, so it's
  146. # difficult to know what the right semantics are.
  147. self.assertEqual(f('\\\\\\a\\b'), ('', '\\', 'a\\b'))
  148. self.assertEqual(f('\\\\a'), ('', '\\', 'a'))
  149. #
  150. # Tests for the pure classes.
  151. #
  152. class _BasePurePathTest(object):
  153. # Keys are canonical paths, values are list of tuples of arguments
  154. # supposed to produce equal paths.
  155. equivalences = {
  156. 'a/b': [
  157. ('a', 'b'), ('a/', 'b'), ('a', 'b/'), ('a/', 'b/'),
  158. ('a/b/',), ('a//b',), ('a//b//',),
  159. # Empty components get removed.
  160. ('', 'a', 'b'), ('a', '', 'b'), ('a', 'b', ''),
  161. ],
  162. '/b/c/d': [
  163. ('a', '/b/c', 'd'), ('a', '///b//c', 'd/'),
  164. ('/a', '/b/c', 'd'),
  165. # Empty components get removed.
  166. ('/', 'b', '', 'c/d'), ('/', '', 'b/c/d'), ('', '/b/c/d'),
  167. ],
  168. }
  169. def setUp(self):
  170. p = self.cls('a')
  171. self.flavour = p._flavour
  172. self.sep = self.flavour.sep
  173. self.altsep = self.flavour.altsep
  174. def test_constructor_common(self):
  175. P = self.cls
  176. p = P('a')
  177. self.assertIsInstance(p, P)
  178. P('a', 'b', 'c')
  179. P('/a', 'b', 'c')
  180. P('a/b/c')
  181. P('/a/b/c')
  182. P(FakePath("a/b/c"))
  183. self.assertEqual(P(P('a')), P('a'))
  184. self.assertEqual(P(P('a'), 'b'), P('a/b'))
  185. self.assertEqual(P(P('a'), P('b')), P('a/b'))
  186. self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c")))
  187. def _check_str_subclass(self, *args):
  188. # Issue #21127: it should be possible to construct a PurePath object
  189. # from a str subclass instance, and it then gets converted to
  190. # a pure str object.
  191. class StrSubclass(str):
  192. pass
  193. P = self.cls
  194. p = P(*(StrSubclass(x) for x in args))
  195. self.assertEqual(p, P(*args))
  196. for part in p.parts:
  197. self.assertIs(type(part), str)
  198. def test_str_subclass_common(self):
  199. self._check_str_subclass('')
  200. self._check_str_subclass('.')
  201. self._check_str_subclass('a')
  202. self._check_str_subclass('a/b.txt')
  203. self._check_str_subclass('/a/b.txt')
  204. def test_join_common(self):
  205. P = self.cls
  206. p = P('a/b')
  207. pp = p.joinpath('c')
  208. self.assertEqual(pp, P('a/b/c'))
  209. self.assertIs(type(pp), type(p))
  210. pp = p.joinpath('c', 'd')
  211. self.assertEqual(pp, P('a/b/c/d'))
  212. pp = p.joinpath(P('c'))
  213. self.assertEqual(pp, P('a/b/c'))
  214. pp = p.joinpath('/c')
  215. self.assertEqual(pp, P('/c'))
  216. def test_div_common(self):
  217. # Basically the same as joinpath().
  218. P = self.cls
  219. p = P('a/b')
  220. pp = p / 'c'
  221. self.assertEqual(pp, P('a/b/c'))
  222. self.assertIs(type(pp), type(p))
  223. pp = p / 'c/d'
  224. self.assertEqual(pp, P('a/b/c/d'))
  225. pp = p / 'c' / 'd'
  226. self.assertEqual(pp, P('a/b/c/d'))
  227. pp = 'c' / p / 'd'
  228. self.assertEqual(pp, P('c/a/b/d'))
  229. pp = p / P('c')
  230. self.assertEqual(pp, P('a/b/c'))
  231. pp = p/ '/c'
  232. self.assertEqual(pp, P('/c'))
  233. def _check_str(self, expected, args):
  234. p = self.cls(*args)
  235. self.assertEqual(str(p), expected.replace('/', self.sep))
  236. def test_str_common(self):
  237. # Canonicalized paths roundtrip.
  238. for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
  239. self._check_str(pathstr, (pathstr,))
  240. # Special case for the empty path.
  241. self._check_str('.', ('',))
  242. # Other tests for str() are in test_equivalences().
  243. def test_as_posix_common(self):
  244. P = self.cls
  245. for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
  246. self.assertEqual(P(pathstr).as_posix(), pathstr)
  247. # Other tests for as_posix() are in test_equivalences().
  248. def test_as_bytes_common(self):
  249. sep = os.fsencode(self.sep)
  250. P = self.cls
  251. self.assertEqual(bytes(P('a/b')), b'a' + sep + b'b')
  252. def test_as_uri_common(self):
  253. P = self.cls
  254. with self.assertRaises(ValueError):
  255. P('a').as_uri()
  256. with self.assertRaises(ValueError):
  257. P().as_uri()
  258. def test_repr_common(self):
  259. for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
  260. p = self.cls(pathstr)
  261. clsname = p.__class__.__name__
  262. r = repr(p)
  263. # The repr() is in the form ClassName("forward-slashes path").
  264. self.assertTrue(r.startswith(clsname + '('), r)
  265. self.assertTrue(r.endswith(')'), r)
  266. inner = r[len(clsname) + 1 : -1]
  267. self.assertEqual(eval(inner), p.as_posix())
  268. # The repr() roundtrips.
  269. q = eval(r, pathlib.__dict__)
  270. self.assertIs(q.__class__, p.__class__)
  271. self.assertEqual(q, p)
  272. self.assertEqual(repr(q), r)
  273. def test_eq_common(self):
  274. P = self.cls
  275. self.assertEqual(P('a/b'), P('a/b'))
  276. self.assertEqual(P('a/b'), P('a', 'b'))
  277. self.assertNotEqual(P('a/b'), P('a'))
  278. self.assertNotEqual(P('a/b'), P('/a/b'))
  279. self.assertNotEqual(P('a/b'), P())
  280. self.assertNotEqual(P('/a/b'), P('/'))
  281. self.assertNotEqual(P(), P('/'))
  282. self.assertNotEqual(P(), "")
  283. self.assertNotEqual(P(), {})
  284. self.assertNotEqual(P(), int)
  285. def test_match_common(self):
  286. P = self.cls
  287. self.assertRaises(ValueError, P('a').match, '')
  288. self.assertRaises(ValueError, P('a').match, '.')
  289. # Simple relative pattern.
  290. self.assertTrue(P('b.py').match('b.py'))
  291. self.assertTrue(P('a/b.py').match('b.py'))
  292. self.assertTrue(P('/a/b.py').match('b.py'))
  293. self.assertFalse(P('a.py').match('b.py'))
  294. self.assertFalse(P('b/py').match('b.py'))
  295. self.assertFalse(P('/a.py').match('b.py'))
  296. self.assertFalse(P('b.py/c').match('b.py'))
  297. # Wildcard relative pattern.
  298. self.assertTrue(P('b.py').match('*.py'))
  299. self.assertTrue(P('a/b.py').match('*.py'))
  300. self.assertTrue(P('/a/b.py').match('*.py'))
  301. self.assertFalse(P('b.pyc').match('*.py'))
  302. self.assertFalse(P('b./py').match('*.py'))
  303. self.assertFalse(P('b.py/c').match('*.py'))
  304. # Multi-part relative pattern.
  305. self.assertTrue(P('ab/c.py').match('a*/*.py'))
  306. self.assertTrue(P('/d/ab/c.py').match('a*/*.py'))
  307. self.assertFalse(P('a.py').match('a*/*.py'))
  308. self.assertFalse(P('/dab/c.py').match('a*/*.py'))
  309. self.assertFalse(P('ab/c.py/d').match('a*/*.py'))
  310. # Absolute pattern.
  311. self.assertTrue(P('/b.py').match('/*.py'))
  312. self.assertFalse(P('b.py').match('/*.py'))
  313. self.assertFalse(P('a/b.py').match('/*.py'))
  314. self.assertFalse(P('/a/b.py').match('/*.py'))
  315. # Multi-part absolute pattern.
  316. self.assertTrue(P('/a/b.py').match('/a/*.py'))
  317. self.assertFalse(P('/ab.py').match('/a/*.py'))
  318. self.assertFalse(P('/a/b/c.py').match('/a/*.py'))
  319. # Multi-part glob-style pattern.
  320. self.assertFalse(P('/a/b/c.py').match('/**/*.py'))
  321. self.assertTrue(P('/a/b/c.py').match('/a/**/*.py'))
  322. def test_ordering_common(self):
  323. # Ordering is tuple-alike.
  324. def assertLess(a, b):
  325. self.assertLess(a, b)
  326. self.assertGreater(b, a)
  327. P = self.cls
  328. a = P('a')
  329. b = P('a/b')
  330. c = P('abc')
  331. d = P('b')
  332. assertLess(a, b)
  333. assertLess(a, c)
  334. assertLess(a, d)
  335. assertLess(b, c)
  336. assertLess(c, d)
  337. P = self.cls
  338. a = P('/a')
  339. b = P('/a/b')
  340. c = P('/abc')
  341. d = P('/b')
  342. assertLess(a, b)
  343. assertLess(a, c)
  344. assertLess(a, d)
  345. assertLess(b, c)
  346. assertLess(c, d)
  347. with self.assertRaises(TypeError):
  348. P() < {}
  349. def test_parts_common(self):
  350. # `parts` returns a tuple.
  351. sep = self.sep
  352. P = self.cls
  353. p = P('a/b')
  354. parts = p.parts
  355. self.assertEqual(parts, ('a', 'b'))
  356. # The object gets reused.
  357. self.assertIs(parts, p.parts)
  358. # When the path is absolute, the anchor is a separate part.
  359. p = P('/a/b')
  360. parts = p.parts
  361. self.assertEqual(parts, (sep, 'a', 'b'))
  362. def test_fspath_common(self):
  363. P = self.cls
  364. p = P('a/b')
  365. self._check_str(p.__fspath__(), ('a/b',))
  366. self._check_str(os.fspath(p), ('a/b',))
  367. def test_equivalences(self):
  368. for k, tuples in self.equivalences.items():
  369. canon = k.replace('/', self.sep)
  370. posix = k.replace(self.sep, '/')
  371. if canon != posix:
  372. tuples = tuples + [
  373. tuple(part.replace('/', self.sep) for part in t)
  374. for t in tuples
  375. ]
  376. tuples.append((posix, ))
  377. pcanon = self.cls(canon)
  378. for t in tuples:
  379. p = self.cls(*t)
  380. self.assertEqual(p, pcanon, "failed with args {}".format(t))
  381. self.assertEqual(hash(p), hash(pcanon))
  382. self.assertEqual(str(p), canon)
  383. self.assertEqual(p.as_posix(), posix)
  384. def test_parent_common(self):
  385. # Relative
  386. P = self.cls
  387. p = P('a/b/c')
  388. self.assertEqual(p.parent, P('a/b'))
  389. self.assertEqual(p.parent.parent, P('a'))
  390. self.assertEqual(p.parent.parent.parent, P())
  391. self.assertEqual(p.parent.parent.parent.parent, P())
  392. # Anchored
  393. p = P('/a/b/c')
  394. self.assertEqual(p.parent, P('/a/b'))
  395. self.assertEqual(p.parent.parent, P('/a'))
  396. self.assertEqual(p.parent.parent.parent, P('/'))
  397. self.assertEqual(p.parent.parent.parent.parent, P('/'))
  398. def test_parents_common(self):
  399. # Relative
  400. P = self.cls
  401. p = P('a/b/c')
  402. par = p.parents
  403. self.assertEqual(len(par), 3)
  404. self.assertEqual(par[0], P('a/b'))
  405. self.assertEqual(par[1], P('a'))
  406. self.assertEqual(par[2], P('.'))
  407. self.assertEqual(par[-1], P('.'))
  408. self.assertEqual(par[-2], P('a'))
  409. self.assertEqual(par[-3], P('a/b'))
  410. self.assertEqual(par[0:1], (P('a/b'),))
  411. self.assertEqual(par[:2], (P('a/b'), P('a')))
  412. self.assertEqual(par[:-1], (P('a/b'), P('a')))
  413. self.assertEqual(par[1:], (P('a'), P('.')))
  414. self.assertEqual(par[::2], (P('a/b'), P('.')))
  415. self.assertEqual(par[::-1], (P('.'), P('a'), P('a/b')))
  416. self.assertEqual(list(par), [P('a/b'), P('a'), P('.')])
  417. with self.assertRaises(IndexError):
  418. par[-4]
  419. with self.assertRaises(IndexError):
  420. par[3]
  421. with self.assertRaises(TypeError):
  422. par[0] = p
  423. # Anchored
  424. p = P('/a/b/c')
  425. par = p.parents
  426. self.assertEqual(len(par), 3)
  427. self.assertEqual(par[0], P('/a/b'))
  428. self.assertEqual(par[1], P('/a'))
  429. self.assertEqual(par[2], P('/'))
  430. self.assertEqual(par[-1], P('/'))
  431. self.assertEqual(par[-2], P('/a'))
  432. self.assertEqual(par[-3], P('/a/b'))
  433. self.assertEqual(par[0:1], (P('/a/b'),))
  434. self.assertEqual(par[:2], (P('/a/b'), P('/a')))
  435. self.assertEqual(par[:-1], (P('/a/b'), P('/a')))
  436. self.assertEqual(par[1:], (P('/a'), P('/')))
  437. self.assertEqual(par[::2], (P('/a/b'), P('/')))
  438. self.assertEqual(par[::-1], (P('/'), P('/a'), P('/a/b')))
  439. self.assertEqual(list(par), [P('/a/b'), P('/a'), P('/')])
  440. with self.assertRaises(IndexError):
  441. par[-4]
  442. with self.assertRaises(IndexError):
  443. par[3]
  444. def test_drive_common(self):
  445. P = self.cls
  446. self.assertEqual(P('a/b').drive, '')
  447. self.assertEqual(P('/a/b').drive, '')
  448. self.assertEqual(P('').drive, '')
  449. def test_root_common(self):
  450. P = self.cls
  451. sep = self.sep
  452. self.assertEqual(P('').root, '')
  453. self.assertEqual(P('a/b').root, '')
  454. self.assertEqual(P('/').root, sep)
  455. self.assertEqual(P('/a/b').root, sep)
  456. def test_anchor_common(self):
  457. P = self.cls
  458. sep = self.sep
  459. self.assertEqual(P('').anchor, '')
  460. self.assertEqual(P('a/b').anchor, '')
  461. self.assertEqual(P('/').anchor, sep)
  462. self.assertEqual(P('/a/b').anchor, sep)
  463. def test_name_common(self):
  464. P = self.cls
  465. self.assertEqual(P('').name, '')
  466. self.assertEqual(P('.').name, '')
  467. self.assertEqual(P('/').name, '')
  468. self.assertEqual(P('a/b').name, 'b')
  469. self.assertEqual(P('/a/b').name, 'b')
  470. self.assertEqual(P('/a/b/.').name, 'b')
  471. self.assertEqual(P('a/b.py').name, 'b.py')
  472. self.assertEqual(P('/a/b.py').name, 'b.py')
  473. def test_suffix_common(self):
  474. P = self.cls
  475. self.assertEqual(P('').suffix, '')
  476. self.assertEqual(P('.').suffix, '')
  477. self.assertEqual(P('..').suffix, '')
  478. self.assertEqual(P('/').suffix, '')
  479. self.assertEqual(P('a/b').suffix, '')
  480. self.assertEqual(P('/a/b').suffix, '')
  481. self.assertEqual(P('/a/b/.').suffix, '')
  482. self.assertEqual(P('a/b.py').suffix, '.py')
  483. self.assertEqual(P('/a/b.py').suffix, '.py')
  484. self.assertEqual(P('a/.hgrc').suffix, '')
  485. self.assertEqual(P('/a/.hgrc').suffix, '')
  486. self.assertEqual(P('a/.hg.rc').suffix, '.rc')
  487. self.assertEqual(P('/a/.hg.rc').suffix, '.rc')
  488. self.assertEqual(P('a/b.tar.gz').suffix, '.gz')
  489. self.assertEqual(P('/a/b.tar.gz').suffix, '.gz')
  490. self.assertEqual(P('a/Some name. Ending with a dot.').suffix, '')
  491. self.assertEqual(P('/a/Some name. Ending with a dot.').suffix, '')
  492. def test_suffixes_common(self):
  493. P = self.cls
  494. self.assertEqual(P('').suffixes, [])
  495. self.assertEqual(P('.').suffixes, [])
  496. self.assertEqual(P('/').suffixes, [])
  497. self.assertEqual(P('a/b').suffixes, [])
  498. self.assertEqual(P('/a/b').suffixes, [])
  499. self.assertEqual(P('/a/b/.').suffixes, [])
  500. self.assertEqual(P('a/b.py').suffixes, ['.py'])
  501. self.assertEqual(P('/a/b.py').suffixes, ['.py'])
  502. self.assertEqual(P('a/.hgrc').suffixes, [])
  503. self.assertEqual(P('/a/.hgrc').suffixes, [])
  504. self.assertEqual(P('a/.hg.rc').suffixes, ['.rc'])
  505. self.assertEqual(P('/a/.hg.rc').suffixes, ['.rc'])
  506. self.assertEqual(P('a/b.tar.gz').suffixes, ['.tar', '.gz'])
  507. self.assertEqual(P('/a/b.tar.gz').suffixes, ['.tar', '.gz'])
  508. self.assertEqual(P('a/Some name. Ending with a dot.').suffixes, [])
  509. self.assertEqual(P('/a/Some name. Ending with a dot.').suffixes, [])
  510. def test_stem_common(self):
  511. P = self.cls
  512. self.assertEqual(P('').stem, '')
  513. self.assertEqual(P('.').stem, '')
  514. self.assertEqual(P('..').stem, '..')
  515. self.assertEqual(P('/').stem, '')
  516. self.assertEqual(P('a/b').stem, 'b')
  517. self.assertEqual(P('a/b.py').stem, 'b')
  518. self.assertEqual(P('a/.hgrc').stem, '.hgrc')
  519. self.assertEqual(P('a/.hg.rc').stem, '.hg')
  520. self.assertEqual(P('a/b.tar.gz').stem, 'b.tar')
  521. self.assertEqual(P('a/Some name. Ending with a dot.').stem,
  522. 'Some name. Ending with a dot.')
  523. def test_with_name_common(self):
  524. P = self.cls
  525. self.assertEqual(P('a/b').with_name('d.xml'), P('a/d.xml'))
  526. self.assertEqual(P('/a/b').with_name('d.xml'), P('/a/d.xml'))
  527. self.assertEqual(P('a/b.py').with_name('d.xml'), P('a/d.xml'))
  528. self.assertEqual(P('/a/b.py').with_name('d.xml'), P('/a/d.xml'))
  529. self.assertEqual(P('a/Dot ending.').with_name('d.xml'), P('a/d.xml'))
  530. self.assertEqual(P('/a/Dot ending.').with_name('d.xml'), P('/a/d.xml'))
  531. self.assertRaises(ValueError, P('').with_name, 'd.xml')
  532. self.assertRaises(ValueError, P('.').with_name, 'd.xml')
  533. self.assertRaises(ValueError, P('/').with_name, 'd.xml')
  534. self.assertRaises(ValueError, P('a/b').with_name, '')
  535. self.assertRaises(ValueError, P('a/b').with_name, '/c')
  536. self.assertRaises(ValueError, P('a/b').with_name, 'c/')
  537. self.assertRaises(ValueError, P('a/b').with_name, 'c/d')
  538. def test_with_stem_common(self):
  539. P = self.cls
  540. self.assertEqual(P('a/b').with_stem('d'), P('a/d'))
  541. self.assertEqual(P('/a/b').with_stem('d'), P('/a/d'))
  542. self.assertEqual(P('a/b.py').with_stem('d'), P('a/d.py'))
  543. self.assertEqual(P('/a/b.py').with_stem('d'), P('/a/d.py'))
  544. self.assertEqual(P('/a/b.tar.gz').with_stem('d'), P('/a/d.gz'))
  545. self.assertEqual(P('a/Dot ending.').with_stem('d'), P('a/d'))
  546. self.assertEqual(P('/a/Dot ending.').with_stem('d'), P('/a/d'))
  547. self.assertRaises(ValueError, P('').with_stem, 'd')
  548. self.assertRaises(ValueError, P('.').with_stem, 'd')
  549. self.assertRaises(ValueError, P('/').with_stem, 'd')
  550. self.assertRaises(ValueError, P('a/b').with_stem, '')
  551. self.assertRaises(ValueError, P('a/b').with_stem, '/c')
  552. self.assertRaises(ValueError, P('a/b').with_stem, 'c/')
  553. self.assertRaises(ValueError, P('a/b').with_stem, 'c/d')
  554. def test_with_suffix_common(self):
  555. P = self.cls
  556. self.assertEqual(P('a/b').with_suffix('.gz'), P('a/b.gz'))
  557. self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz'))
  558. self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz'))
  559. self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz'))
  560. # Stripping suffix.
  561. self.assertEqual(P('a/b.py').with_suffix(''), P('a/b'))
  562. self.assertEqual(P('/a/b').with_suffix(''), P('/a/b'))
  563. # Path doesn't have a "filename" component.
  564. self.assertRaises(ValueError, P('').with_suffix, '.gz')
  565. self.assertRaises(ValueError, P('.').with_suffix, '.gz')
  566. self.assertRaises(ValueError, P('/').with_suffix, '.gz')
  567. # Invalid suffix.
  568. self.assertRaises(ValueError, P('a/b').with_suffix, 'gz')
  569. self.assertRaises(ValueError, P('a/b').with_suffix, '/')
  570. self.assertRaises(ValueError, P('a/b').with_suffix, '.')
  571. self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz')
  572. self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d')
  573. self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d')
  574. self.assertRaises(ValueError, P('a/b').with_suffix, './.d')
  575. self.assertRaises(ValueError, P('a/b').with_suffix, '.d/.')
  576. self.assertRaises(ValueError, P('a/b').with_suffix,
  577. (self.flavour.sep, 'd'))
  578. def test_relative_to_common(self):
  579. P = self.cls
  580. p = P('a/b')
  581. self.assertRaises(TypeError, p.relative_to)
  582. self.assertRaises(TypeError, p.relative_to, b'a')
  583. self.assertEqual(p.relative_to(P()), P('a/b'))
  584. self.assertEqual(p.relative_to(''), P('a/b'))
  585. self.assertEqual(p.relative_to(P('a')), P('b'))
  586. self.assertEqual(p.relative_to('a'), P('b'))
  587. self.assertEqual(p.relative_to('a/'), P('b'))
  588. self.assertEqual(p.relative_to(P('a/b')), P())
  589. self.assertEqual(p.relative_to('a/b'), P())
  590. # With several args.
  591. self.assertEqual(p.relative_to('a', 'b'), P())
  592. # Unrelated paths.
  593. self.assertRaises(ValueError, p.relative_to, P('c'))
  594. self.assertRaises(ValueError, p.relative_to, P('a/b/c'))
  595. self.assertRaises(ValueError, p.relative_to, P('a/c'))
  596. self.assertRaises(ValueError, p.relative_to, P('/a'))
  597. p = P('/a/b')
  598. self.assertEqual(p.relative_to(P('/')), P('a/b'))
  599. self.assertEqual(p.relative_to('/'), P('a/b'))
  600. self.assertEqual(p.relative_to(P('/a')), P('b'))
  601. self.assertEqual(p.relative_to('/a'), P('b'))
  602. self.assertEqual(p.relative_to('/a/'), P('b'))
  603. self.assertEqual(p.relative_to(P('/a/b')), P())
  604. self.assertEqual(p.relative_to('/a/b'), P())
  605. # Unrelated paths.
  606. self.assertRaises(ValueError, p.relative_to, P('/c'))
  607. self.assertRaises(ValueError, p.relative_to, P('/a/b/c'))
  608. self.assertRaises(ValueError, p.relative_to, P('/a/c'))
  609. self.assertRaises(ValueError, p.relative_to, P())
  610. self.assertRaises(ValueError, p.relative_to, '')
  611. self.assertRaises(ValueError, p.relative_to, P('a'))
  612. def test_is_relative_to_common(self):
  613. P = self.cls
  614. p = P('a/b')
  615. self.assertRaises(TypeError, p.is_relative_to)
  616. self.assertRaises(TypeError, p.is_relative_to, b'a')
  617. self.assertTrue(p.is_relative_to(P()))
  618. self.assertTrue(p.is_relative_to(''))
  619. self.assertTrue(p.is_relative_to(P('a')))
  620. self.assertTrue(p.is_relative_to('a/'))
  621. self.assertTrue(p.is_relative_to(P('a/b')))
  622. self.assertTrue(p.is_relative_to('a/b'))
  623. # With several args.
  624. self.assertTrue(p.is_relative_to('a', 'b'))
  625. # Unrelated paths.
  626. self.assertFalse(p.is_relative_to(P('c')))
  627. self.assertFalse(p.is_relative_to(P('a/b/c')))
  628. self.assertFalse(p.is_relative_to(P('a/c')))
  629. self.assertFalse(p.is_relative_to(P('/a')))
  630. p = P('/a/b')
  631. self.assertTrue(p.is_relative_to(P('/')))
  632. self.assertTrue(p.is_relative_to('/'))
  633. self.assertTrue(p.is_relative_to(P('/a')))
  634. self.assertTrue(p.is_relative_to('/a'))
  635. self.assertTrue(p.is_relative_to('/a/'))
  636. self.assertTrue(p.is_relative_to(P('/a/b')))
  637. self.assertTrue(p.is_relative_to('/a/b'))
  638. # Unrelated paths.
  639. self.assertFalse(p.is_relative_to(P('/c')))
  640. self.assertFalse(p.is_relative_to(P('/a/b/c')))
  641. self.assertFalse(p.is_relative_to(P('/a/c')))
  642. self.assertFalse(p.is_relative_to(P()))
  643. self.assertFalse(p.is_relative_to(''))
  644. self.assertFalse(p.is_relative_to(P('a')))
  645. def test_pickling_common(self):
  646. P = self.cls
  647. p = P('/a/b')
  648. for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
  649. dumped = pickle.dumps(p, proto)
  650. pp = pickle.loads(dumped)
  651. self.assertIs(pp.__class__, p.__class__)
  652. self.assertEqual(pp, p)
  653. self.assertEqual(hash(pp), hash(p))
  654. self.assertEqual(str(pp), str(p))
  655. class PurePosixPathTest(_BasePurePathTest, unittest.TestCase):
  656. cls = pathlib.PurePosixPath
  657. def test_root(self):
  658. P = self.cls
  659. self.assertEqual(P('/a/b').root, '/')
  660. self.assertEqual(P('///a/b').root, '/')
  661. # POSIX special case for two leading slashes.
  662. self.assertEqual(P('//a/b').root, '//')
  663. def test_eq(self):
  664. P = self.cls
  665. self.assertNotEqual(P('a/b'), P('A/b'))
  666. self.assertEqual(P('/a'), P('///a'))
  667. self.assertNotEqual(P('/a'), P('//a'))
  668. def test_as_uri(self):
  669. P = self.cls
  670. self.assertEqual(P('/').as_uri(), 'file:///')
  671. self.assertEqual(P('/a/b.c').as_uri(), 'file:///a/b.c')
  672. self.assertEqual(P('/a/b%#c').as_uri(), 'file:///a/b%25%23c')
  673. def test_as_uri_non_ascii(self):
  674. from urllib.parse import quote_from_bytes
  675. P = self.cls
  676. try:
  677. os.fsencode('\xe9')
  678. except UnicodeEncodeError:
  679. self.skipTest("\\xe9 cannot be encoded to the filesystem encoding")
  680. self.assertEqual(P('/a/b\xe9').as_uri(),
  681. 'file:///a/b' + quote_from_bytes(os.fsencode('\xe9')))
  682. def test_match(self):
  683. P = self.cls
  684. self.assertFalse(P('A.py').match('a.PY'))
  685. def test_is_absolute(self):
  686. P = self.cls
  687. self.assertFalse(P().is_absolute())
  688. self.assertFalse(P('a').is_absolute())
  689. self.assertFalse(P('a/b/').is_absolute())
  690. self.assertTrue(P('/').is_absolute())
  691. self.assertTrue(P('/a').is_absolute())
  692. self.assertTrue(P('/a/b/').is_absolute())
  693. self.assertTrue(P('//a').is_absolute())
  694. self.assertTrue(P('//a/b').is_absolute())
  695. def test_is_reserved(self):
  696. P = self.cls
  697. self.assertIs(False, P('').is_reserved())
  698. self.assertIs(False, P('/').is_reserved())
  699. self.assertIs(False, P('/foo/bar').is_reserved())
  700. self.assertIs(False, P('/dev/con/PRN/NUL').is_reserved())
  701. def test_join(self):
  702. P = self.cls
  703. p = P('//a')
  704. pp = p.joinpath('b')
  705. self.assertEqual(pp, P('//a/b'))
  706. pp = P('/a').joinpath('//c')
  707. self.assertEqual(pp, P('//c'))
  708. pp = P('//a').joinpath('/c')
  709. self.assertEqual(pp, P('/c'))
  710. def test_div(self):
  711. # Basically the same as joinpath().
  712. P = self.cls
  713. p = P('//a')
  714. pp = p / 'b'
  715. self.assertEqual(pp, P('//a/b'))
  716. pp = P('/a') / '//c'
  717. self.assertEqual(pp, P('//c'))
  718. pp = P('//a') / '/c'
  719. self.assertEqual(pp, P('/c'))
  720. class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
  721. cls = pathlib.PureWindowsPath
  722. equivalences = _BasePurePathTest.equivalences.copy()
  723. equivalences.update({
  724. 'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('/', 'c:', 'a') ],
  725. 'c:/a': [
  726. ('c:/', 'a'), ('c:', '/', 'a'), ('c:', '/a'),
  727. ('/z', 'c:/', 'a'), ('//x/y', 'c:/', 'a'),
  728. ],
  729. '//a/b/': [ ('//a/b',) ],
  730. '//a/b/c': [
  731. ('//a/b', 'c'), ('//a/b/', 'c'),
  732. ],
  733. })
  734. def test_str(self):
  735. p = self.cls('a/b/c')
  736. self.assertEqual(str(p), 'a\\b\\c')
  737. p = self.cls('c:/a/b/c')
  738. self.assertEqual(str(p), 'c:\\a\\b\\c')
  739. p = self.cls('//a/b')
  740. self.assertEqual(str(p), '\\\\a\\b\\')
  741. p = self.cls('//a/b/c')
  742. self.assertEqual(str(p), '\\\\a\\b\\c')
  743. p = self.cls('//a/b/c/d')
  744. self.assertEqual(str(p), '\\\\a\\b\\c\\d')
  745. def test_str_subclass(self):
  746. self._check_str_subclass('c:')
  747. self._check_str_subclass('c:a')
  748. self._check_str_subclass('c:a\\b.txt')
  749. self._check_str_subclass('c:\\')
  750. self._check_str_subclass('c:\\a')
  751. self._check_str_subclass('c:\\a\\b.txt')
  752. self._check_str_subclass('\\\\some\\share')
  753. self._check_str_subclass('\\\\some\\share\\a')
  754. self._check_str_subclass('\\\\some\\share\\a\\b.txt')
  755. def test_eq(self):
  756. P = self.cls
  757. self.assertEqual(P('c:a/b'), P('c:a/b'))
  758. self.assertEqual(P('c:a/b'), P('c:', 'a', 'b'))
  759. self.assertNotEqual(P('c:a/b'), P('d:a/b'))
  760. self.assertNotEqual(P('c:a/b'), P('c:/a/b'))
  761. self.assertNotEqual(P('/a/b'), P('c:/a/b'))
  762. # Case-insensitivity.
  763. self.assertEqual(P('a/B'), P('A/b'))
  764. self.assertEqual(P('C:a/B'), P('c:A/b'))
  765. self.assertEqual(P('//Some/SHARE/a/B'), P('//somE/share/A/b'))
  766. def test_as_uri(self):
  767. P = self.cls
  768. with self.assertRaises(ValueError):
  769. P('/a/b').as_uri()
  770. with self.assertRaises(ValueError):
  771. P('c:a/b').as_uri()
  772. self.assertEqual(P('c:/').as_uri(), 'file:///c:/')
  773. self.assertEqual(P('c:/a/b.c').as_uri(), 'file:///c:/a/b.c')
  774. self.assertEqual(P('c:/a/b%#c').as_uri(), 'file:///c:/a/b%25%23c')
  775. self.assertEqual(P('c:/a/b\xe9').as_uri(), 'file:///c:/a/b%C3%A9')
  776. self.assertEqual(P('//some/share/').as_uri(), 'file://some/share/')
  777. self.assertEqual(P('//some/share/a/b.c').as_uri(),
  778. 'file://some/share/a/b.c')
  779. self.assertEqual(P('//some/share/a/b%#c\xe9').as_uri(),
  780. 'file://some/share/a/b%25%23c%C3%A9')
  781. def test_match_common(self):
  782. P = self.cls
  783. # Absolute patterns.
  784. self.assertTrue(P('c:/b.py').match('/*.py'))
  785. self.assertTrue(P('c:/b.py').match('c:*.py'))
  786. self.assertTrue(P('c:/b.py').match('c:/*.py'))
  787. self.assertFalse(P('d:/b.py').match('c:/*.py')) # wrong drive
  788. self.assertFalse(P('b.py').match('/*.py'))
  789. self.assertFalse(P('b.py').match('c:*.py'))
  790. self.assertFalse(P('b.py').match('c:/*.py'))
  791. self.assertFalse(P('c:b.py').match('/*.py'))
  792. self.assertFalse(P('c:b.py').match('c:/*.py'))
  793. self.assertFalse(P('/b.py').match('c:*.py'))
  794. self.assertFalse(P('/b.py').match('c:/*.py'))
  795. # UNC patterns.
  796. self.assertTrue(P('//some/share/a.py').match('/*.py'))
  797. self.assertTrue(P('//some/share/a.py').match('//some/share/*.py'))
  798. self.assertFalse(P('//other/share/a.py').match('//some/share/*.py'))
  799. self.assertFalse(P('//some/share/a/b.py').match('//some/share/*.py'))
  800. # Case-insensitivity.
  801. self.assertTrue(P('B.py').match('b.PY'))
  802. self.assertTrue(P('c:/a/B.Py').match('C:/A/*.pY'))
  803. self.assertTrue(P('//Some/Share/B.Py').match('//somE/sharE/*.pY'))
  804. def test_ordering_common(self):
  805. # Case-insensitivity.
  806. def assertOrderedEqual(a, b):
  807. self.assertLessEqual(a, b)
  808. self.assertGreaterEqual(b, a)
  809. P = self.cls
  810. p = P('c:A/b')
  811. q = P('C:a/B')
  812. assertOrderedEqual(p, q)
  813. self.assertFalse(p < q)
  814. self.assertFalse(p > q)
  815. p = P('//some/Share/A/b')
  816. q = P('//Some/SHARE/a/B')
  817. assertOrderedEqual(p, q)
  818. self.assertFalse(p < q)
  819. self.assertFalse(p > q)
  820. def test_parts(self):
  821. P = self.cls
  822. p = P('c:a/b')
  823. parts = p.parts
  824. self.assertEqual(parts, ('c:', 'a', 'b'))
  825. p = P('c:/a/b')
  826. parts = p.parts
  827. self.assertEqual(parts, ('c:\\', 'a', 'b'))
  828. p = P('//a/b/c/d')
  829. parts = p.parts
  830. self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd'))
  831. def test_parent(self):
  832. # Anchored
  833. P = self.cls
  834. p = P('z:a/b/c')
  835. self.assertEqual(p.parent, P('z:a/b'))
  836. self.assertEqual(p.parent.parent, P('z:a'))
  837. self.assertEqual(p.parent.parent.parent, P('z:'))
  838. self.assertEqual(p.parent.parent.parent.parent, P('z:'))
  839. p = P('z:/a/b/c')
  840. self.assertEqual(p.parent, P('z:/a/b'))
  841. self.assertEqual(p.parent.parent, P('z:/a'))
  842. self.assertEqual(p.parent.parent.parent, P('z:/'))
  843. self.assertEqual(p.parent.parent.parent.parent, P('z:/'))
  844. p = P('//a/b/c/d')
  845. self.assertEqual(p.parent, P('//a/b/c'))
  846. self.assertEqual(p.parent.parent, P('//a/b'))
  847. self.assertEqual(p.parent.parent.parent, P('//a/b'))
  848. def test_parents(self):
  849. # Anchored
  850. P = self.cls
  851. p = P('z:a/b/')
  852. par = p.parents
  853. self.assertEqual(len(par), 2)
  854. self.assertEqual(par[0], P('z:a'))
  855. self.assertEqual(par[1], P('z:'))
  856. self.assertEqual(par[0:1], (P('z:a'),))
  857. self.assertEqual(par[:-1], (P('z:a'),))
  858. self.assertEqual(par[:2], (P('z:a'), P('z:')))
  859. self.assertEqual(par[1:], (P('z:'),))
  860. self.assertEqual(par[::2], (P('z:a'),))
  861. self.assertEqual(par[::-1], (P('z:'), P('z:a')))
  862. self.assertEqual(list(par), [P('z:a'), P('z:')])
  863. with self.assertRaises(IndexError):
  864. par[2]
  865. p = P('z:/a/b/')
  866. par = p.parents
  867. self.assertEqual(len(par), 2)
  868. self.assertEqual(par[0], P('z:/a'))
  869. self.assertEqual(par[1], P('z:/'))
  870. self.assertEqual(par[0:1], (P('z:/a'),))
  871. self.assertEqual(par[0:-1], (P('z:/a'),))
  872. self.assertEqual(par[:2], (P('z:/a'), P('z:/')))
  873. self.assertEqual(par[1:], (P('z:/'),))
  874. self.assertEqual(par[::2], (P('z:/a'),))
  875. self.assertEqual(par[::-1], (P('z:/'), P('z:/a'),))
  876. self.assertEqual(list(par), [P('z:/a'), P('z:/')])
  877. with self.assertRaises(IndexError):
  878. par[2]
  879. p = P('//a/b/c/d')
  880. par = p.parents
  881. self.assertEqual(len(par), 2)
  882. self.assertEqual(par[0], P('//a/b/c'))
  883. self.assertEqual(par[1], P('//a/b'))
  884. self.assertEqual(par[0:1], (P('//a/b/c'),))
  885. self.assertEqual(par[0:-1], (P('//a/b/c'),))
  886. self.assertEqual(par[:2], (P('//a/b/c'), P('//a/b')))
  887. self.assertEqual(par[1:], (P('//a/b'),))
  888. self.assertEqual(par[::2], (P('//a/b/c'),))
  889. self.assertEqual(par[::-1], (P('//a/b'), P('//a/b/c')))
  890. self.assertEqual(list(par), [P('//a/b/c'), P('//a/b')])
  891. with self.assertRaises(IndexError):
  892. par[2]
  893. def test_drive(self):
  894. P = self.cls
  895. self.assertEqual(P('c:').drive, 'c:')
  896. self.assertEqual(P('c:a/b').drive, 'c:')
  897. self.assertEqual(P('c:/').drive, 'c:')
  898. self.assertEqual(P('c:/a/b/').drive, 'c:')
  899. self.assertEqual(P('//a/b').drive, '\\\\a\\b')
  900. self.assertEqual(P('//a/b/').drive, '\\\\a\\b')
  901. self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b')
  902. def test_root(self):
  903. P = self.cls
  904. self.assertEqual(P('c:').root, '')
  905. self.assertEqual(P('c:a/b').root, '')
  906. self.assertEqual(P('c:/').root, '\\')
  907. self.assertEqual(P('c:/a/b/').root, '\\')
  908. self.assertEqual(P('//a/b').root, '\\')
  909. self.assertEqual(P('//a/b/').root, '\\')
  910. self.assertEqual(P('//a/b/c/d').root, '\\')
  911. def test_anchor(self):
  912. P = self.cls
  913. self.assertEqual(P('c:').anchor, 'c:')
  914. self.assertEqual(P('c:a/b').anchor, 'c:')
  915. self.assertEqual(P('c:/').anchor, 'c:\\')
  916. self.assertEqual(P('c:/a/b/').anchor, 'c:\\')
  917. self.assertEqual(P('//a/b').anchor, '\\\\a\\b\\')
  918. self.assertEqual(P('//a/b/').anchor, '\\\\a\\b\\')
  919. self.assertEqual(P('//a/b/c/d').anchor, '\\\\a\\b\\')
  920. def test_name(self):
  921. P = self.cls
  922. self.assertEqual(P('c:').name, '')
  923. self.assertEqual(P('c:/').name, '')
  924. self.assertEqual(P('c:a/b').name, 'b')
  925. self.assertEqual(P('c:/a/b').name, 'b')
  926. self.assertEqual(P('c:a/b.py').name, 'b.py')
  927. self.assertEqual(P('c:/a/b.py').name, 'b.py')
  928. self.assertEqual(P('//My.py/Share.php').name, '')
  929. self.assertEqual(P('//My.py/Share.php/a/b').name, 'b')
  930. def test_suffix(self):
  931. P = self.cls
  932. self.assertEqual(P('c:').suffix, '')
  933. self.assertEqual(P('c:/').suffix, '')
  934. self.assertEqual(P('c:a/b').suffix, '')
  935. self.assertEqual(P('c:/a/b').suffix, '')
  936. self.assertEqual(P('c:a/b.py').suffix, '.py')
  937. self.assertEqual(P('c:/a/b.py').suffix, '.py')
  938. self.assertEqual(P('c:a/.hgrc').suffix, '')
  939. self.assertEqual(P('c:/a/.hgrc').suffix, '')
  940. self.assertEqual(P('c:a/.hg.rc').suffix, '.rc')
  941. self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc')
  942. self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz')
  943. self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz')
  944. self.assertEqual(P('c:a/Some name. Ending with a dot.').suffix, '')
  945. self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffix, '')
  946. self.assertEqual(P('//My.py/Share.php').suffix, '')
  947. self.assertEqual(P('//My.py/Share.php/a/b').suffix, '')
  948. def test_suffixes(self):
  949. P = self.cls
  950. self.assertEqual(P('c:').suffixes, [])
  951. self.assertEqual(P('c:/').suffixes, [])
  952. self.assertEqual(P('c:a/b').suffixes, [])
  953. self.assertEqual(P('c:/a/b').suffixes, [])
  954. self.assertEqual(P('c:a/b.py').suffixes, ['.py'])
  955. self.assertEqual(P('c:/a/b.py').suffixes, ['.py'])
  956. self.assertEqual(P('c:a/.hgrc').suffixes, [])
  957. self.assertEqual(P('c:/a/.hgrc').suffixes, [])
  958. self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc'])
  959. self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc'])
  960. self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz'])
  961. self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz'])
  962. self.assertEqual(P('//My.py/Share.php').suffixes, [])
  963. self.assertEqual(P('//My.py/Share.php/a/b').suffixes, [])
  964. self.assertEqual(P('c:a/Some name. Ending with a dot.').suffixes, [])
  965. self.assertEqual(P('c:/a/Some name. Ending with a dot.').suffixes, [])
  966. def test_stem(self):
  967. P = self.cls
  968. self.assertEqual(P('c:').stem, '')
  969. self.assertEqual(P('c:.').stem, '')
  970. self.assertEqual(P('c:..').stem, '..')
  971. self.assertEqual(P('c:/').stem, '')
  972. self.assertEqual(P('c:a/b').stem, 'b')
  973. self.assertEqual(P('c:a/b.py').stem, 'b')
  974. self.assertEqual(P('c:a/.hgrc').stem, '.hgrc')
  975. self.assertEqual(P('c:a/.hg.rc').stem, '.hg')
  976. self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar')
  977. self.assertEqual(P('c:a/Some name. Ending with a dot.').stem,
  978. 'Some name. Ending with a dot.')
  979. def test_with_name(self):
  980. P = self.cls
  981. self.assertEqual(P('c:a/b').with_name('d.xml'), P('c:a/d.xml'))
  982. self.assertEqual(P('c:/a/b').with_name('d.xml'), P('c:/a/d.xml'))
  983. self.assertEqual(P('c:a/Dot ending.').with_name('d.xml'), P('c:a/d.xml'))
  984. self.assertEqual(P('c:/a/Dot ending.').with_name('d.xml'), P('c:/a/d.xml'))
  985. self.assertRaises(ValueError, P('c:').with_name, 'd.xml')
  986. self.assertRaises(ValueError, P('c:/').with_name, 'd.xml')
  987. self.assertRaises(ValueError, P('//My/Share').with_name, 'd.xml')
  988. self.assertRaises(ValueError, P('c:a/b').with_name, 'd:')
  989. self.assertRaises(ValueError, P('c:a/b').with_name, 'd:e')
  990. self.assertRaises(ValueError, P('c:a/b').with_name, 'd:/e')
  991. self.assertRaises(ValueError, P('c:a/b').with_name, '//My/Share')
  992. def test_with_stem(self):
  993. P = self.cls
  994. self.assertEqual(P('c:a/b').with_stem('d'), P('c:a/d'))
  995. self.assertEqual(P('c:/a/b').with_stem('d'), P('c:/a/d'))
  996. self.assertEqual(P('c:a/Dot ending.').with_stem('d'), P('c:a/d'))
  997. self.assertEqual(P('c:/a/Dot ending.').with_stem('d'), P('c:/a/d'))
  998. self.assertRaises(ValueError, P('c:').with_stem, 'd')
  999. self.assertRaises(ValueError, P('c:/').with_stem, 'd')
  1000. self.assertRaises(ValueError, P('//My/Share').with_stem, 'd')
  1001. self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:')
  1002. self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:e')
  1003. self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:/e')
  1004. self.assertRaises(ValueError, P('c:a/b').with_stem, '//My/Share')
  1005. def test_with_suffix(self):
  1006. P = self.cls
  1007. self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz'))
  1008. self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz'))
  1009. self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz'))
  1010. self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz'))
  1011. # Path doesn't have a "filename" component.
  1012. self.assertRaises(ValueError, P('').with_suffix, '.gz')
  1013. self.assertRaises(ValueError, P('.').with_suffix, '.gz')
  1014. self.assertRaises(ValueError, P('/').with_suffix, '.gz')
  1015. self.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz')
  1016. # Invalid suffix.
  1017. self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz')
  1018. self.assertRaises(ValueError, P('c:a/b').with_suffix, '/')
  1019. self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\')
  1020. self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:')
  1021. self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz')
  1022. self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz')
  1023. self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz')
  1024. self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d')
  1025. self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d')
  1026. self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d')
  1027. self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d')
  1028. def test_relative_to(self):
  1029. P = self.cls
  1030. p = P('C:Foo/Bar')
  1031. self.assertEqual(p.relative_to(P('c:')), P('Foo/Bar'))
  1032. self.assertEqual(p.relative_to('c:'), P('Foo/Bar'))
  1033. self.assertEqual(p.relative_to(P('c:foO')), P('Bar'))
  1034. self.assertEqual(p.relative_to('c:foO'), P('Bar'))
  1035. self.assertEqual(p.relative_to('c:foO/'), P('Bar'))
  1036. self.assertEqual(p.relative_to(P('c:foO/baR')), P())
  1037. self.assertEqual(p.relative_to('c:foO/baR'), P())
  1038. # Unrelated paths.
  1039. self.assertRaises(ValueError, p.relative_to, P())
  1040. self.assertRaises(ValueError, p.relative_to, '')
  1041. self.assertRaises(ValueError, p.relative_to, P('d:'))
  1042. self.assertRaises(ValueError, p.relative_to, P('/'))
  1043. self.assertRaises(ValueError, p.relative_to, P('Foo'))
  1044. self.assertRaises(ValueError, p.relative_to, P('/Foo'))
  1045. self.assertRaises(ValueError, p.relative_to, P('C:/Foo'))
  1046. self.assertRaises(ValueError, p.relative_to, P('C:Foo/Bar/Baz'))
  1047. self.assertRaises(ValueError, p.relative_to, P('C:Foo/Baz'))
  1048. p = P('C:/Foo/Bar')
  1049. self.assertEqual(p.relative_to(P('c:')), P('/Foo/Bar'))
  1050. self.assertEqual(p.relative_to('c:'), P('/Foo/Bar'))
  1051. self.assertEqual(str(p.relative_to(P('c:'))), '\\Foo\\Bar')
  1052. self.assertEqual(str(p.relative_to('c:')), '\\Foo\\Bar')
  1053. self.assertEqual(p.relative_to(P('c:/')), P('Foo/Bar'))
  1054. self.assertEqual(p.relative_to('c:/'), P('Foo/Bar'))
  1055. self.assertEqual(p.relative_to(P('c:/foO')), P('Bar'))
  1056. self.assertEqual(p.relative_to('c:/foO'), P('Bar'))
  1057. self.assertEqual(p.relative_to('c:/foO/'), P('Bar'))
  1058. self.assertEqual(p.relative_to(P('c:/foO/baR')), P())
  1059. self.assertEqual(p.relative_to('c:/foO/baR'), P())
  1060. # Unrelated paths.
  1061. self.assertRaises(ValueError, p.relative_to, P('C:/Baz'))
  1062. self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Bar/Baz'))
  1063. self.assertRaises(ValueError, p.relative_to, P('C:/Foo/Baz'))
  1064. self.assertRaises(ValueError, p.relative_to, P('C:Foo'))
  1065. self.assertRaises(ValueError, p.relative_to, P('d:'))
  1066. self.assertRaises(ValueError, p.relative_to, P('d:/'))
  1067. self.assertRaises(ValueError, p.relative_to, P('/'))
  1068. self.assertRaises(ValueError, p.relative_to, P('/Foo'))
  1069. self.assertRaises(ValueError, p.relative_to, P('//C/Foo'))
  1070. # UNC paths.
  1071. p = P('//Server/Share/Foo/Bar')
  1072. self.assertEqual(p.relative_to(P('//sErver/sHare')), P('Foo/Bar'))
  1073. self.assertEqual(p.relative_to('//sErver/sHare'), P('Foo/Bar'))
  1074. self.assertEqual(p.relative_to('//sErver/sHare/'), P('Foo/Bar'))
  1075. self.assertEqual(p.relative_to(P('//sErver/sHare/Foo')), P('Bar'))
  1076. self.assertEqual(p.relative_to('//sErver/sHare/Foo'), P('Bar'))
  1077. self.assertEqual(p.relative_to('//sErver/sHare/Foo/'), P('Bar'))
  1078. self.assertEqual(p.relative_to(P('//sErver/sHare/Foo/Bar')), P())
  1079. self.assertEqual(p.relative_to('//sErver/sHare/Foo/Bar'), P())
  1080. # Unrelated paths.
  1081. self.assertRaises(ValueError, p.relative_to, P('/Server/Share/Foo'))
  1082. self.assertRaises(ValueError, p.relative_to, P('c:/Server/Share/Foo'))
  1083. self.assertRaises(ValueError, p.relative_to, P('//z/Share/Foo'))
  1084. self.assertRaises(ValueError, p.relative_to, P('//Server/z/Foo'))
  1085. def test_is_relative_to(self):
  1086. P = self.cls
  1087. p = P('C:Foo/Bar')
  1088. self.assertTrue(p.is_relative_to(P('c:')))
  1089. self.assertTrue(p.is_relative_to('c:'))
  1090. self.assertTrue(p.is_relative_to(P('c:foO')))
  1091. self.assertTrue(p.is_relative_to('c:foO'))
  1092. self.assertTrue(p.is_relative_to('c:foO/'))
  1093. self.assertTrue(p.is_relative_to(P('c:foO/baR')))
  1094. self.assertTrue(p.is_relative_to('c:foO/baR'))
  1095. # Unrelated paths.
  1096. self.assertFalse(p.is_relative_to(P()))
  1097. self.assertFalse(p.is_relative_to(''))
  1098. self.assertFalse(p.is_relative_to(P('d:')))
  1099. self.assertFalse(p.is_relative_to(P('/')))
  1100. self.assertFalse(p.is_relative_to(P('Foo')))
  1101. self.assertFalse(p.is_relative_to(P('/Foo')))
  1102. self.assertFalse(p.is_relative_to(P('C:/Foo')))
  1103. self.assertFalse(p.is_relative_to(P('C:Foo/Bar/Baz')))
  1104. self.assertFalse(p.is_relative_to(P('C:Foo/Baz')))
  1105. p = P('C:/Foo/Bar')
  1106. self.assertTrue(p.is_relative_to('c:'))
  1107. self.assertTrue(p.is_relative_to(P('c:/')))
  1108. self.assertTrue(p.is_relative_to(P('c:/foO')))
  1109. self.assertTrue(p.is_relative_to('c:/foO/'))
  1110. self.assertTrue(p.is_relative_to(P('c:/foO/baR')))
  1111. self.assertTrue(p.is_relative_to('c:/foO/baR'))
  1112. # Unrelated paths.
  1113. self.assertFalse(p.is_relative_to(P('C:/Baz')))
  1114. self.assertFalse(p.is_relative_to(P('C:/Foo/Bar/Baz')))
  1115. self.assertFalse(p.is_relative_to(P('C:/Foo/Baz')))
  1116. self.assertFalse(p.is_relative_to(P('C:Foo')))
  1117. self.assertFalse(p.is_relative_to(P('d:')))
  1118. self.assertFalse(p.is_relative_to(P('d:/')))
  1119. self.assertFalse(p.is_relative_to(P('/')))
  1120. self.assertFalse(p.is_relative_to(P('/Foo')))
  1121. self.assertFalse(p.is_relative_to(P('//C/Foo')))
  1122. # UNC paths.
  1123. p = P('//Server/Share/Foo/Bar')
  1124. self.assertTrue(p.is_relative_to(P('//sErver/sHare')))
  1125. self.assertTrue(p.is_relative_to('//sErver/sHare'))
  1126. self.assertTrue(p.is_relative_to('//sErver/sHare/'))
  1127. self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo')))
  1128. self.assertTrue(p.is_relative_to('//sErver/sHare/Foo'))
  1129. self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/'))
  1130. self.assertTrue(p.is_relative_to(P('//sErver/sHare/Foo/Bar')))
  1131. self.assertTrue(p.is_relative_to('//sErver/sHare/Foo/Bar'))
  1132. # Unrelated paths.
  1133. self.assertFalse(p.is_relative_to(P('/Server/Share/Foo')))
  1134. self.assertFalse(p.is_relative_to(P('c:/Server/Share/Foo')))
  1135. self.assertFalse(p.is_relative_to(P('//z/Share/Foo')))
  1136. self.assertFalse(p.is_relative_to(P('//Server/z/Foo')))
  1137. def test_is_absolute(self):
  1138. P = self.cls
  1139. # Under NT, only paths with both a drive and a root are absolute.
  1140. self.assertFalse(P().is_absolute())
  1141. self.assertFalse(P('a').is_absolute())
  1142. self.assertFalse(P('a/b/').is_absolute())
  1143. self.assertFalse(P('/').is_absolute())
  1144. self.assertFalse(P('/a').is_absolute())
  1145. self.assertFalse(P('/a/b/').is_absolute())
  1146. self.assertFalse(P('c:').is_absolute())
  1147. self.assertFalse(P('c:a').is_absolute())
  1148. self.assertFalse(P('c:a/b/').is_absolute())
  1149. self.assertTrue(P('c:/').is_absolute())
  1150. self.assertTrue(P('c:/a').is_absolute())
  1151. self.assertTrue(P('c:/a/b/').is_absolute())
  1152. # UNC paths are absolute by definition.
  1153. self.assertTrue(P('//a/b').is_absolute())
  1154. self.assertTrue(P('//a/b/').is_absolute())
  1155. self.assertTrue(P('//a/b/c').is_absolute())
  1156. self.assertTrue(P('//a/b/c/d').is_absolute())
  1157. def test_join(self):
  1158. P = self.cls
  1159. p = P('C:/a/b')
  1160. pp = p.joinpath('x/y')
  1161. self.assertEqual(pp, P('C:/a/b/x/y'))
  1162. pp = p.joinpath('/x/y')
  1163. self.assertEqual(pp, P('C:/x/y'))
  1164. # Joining with a different drive => the first path is ignored, even
  1165. # if the second path is relative.
  1166. pp = p.joinpath('D:x/y')
  1167. self.assertEqual(pp, P('D:x/y'))
  1168. pp = p.joinpath('D:/x/y')
  1169. self.assertEqual(pp, P('D:/x/y'))
  1170. pp = p.joinpath('//host/share/x/y')
  1171. self.assertEqual(pp, P('//host/share/x/y'))
  1172. # Joining with the same drive => the first path is appended to if
  1173. # the second path is relative.
  1174. pp = p.joinpath('c:x/y')
  1175. self.assertEqual(pp, P('C:/a/b/x/y'))
  1176. pp = p.joinpath('c:/x/y')
  1177. self.assertEqual(pp, P('C:/x/y'))
  1178. def test_div(self):
  1179. # Basically the same as joinpath().
  1180. P = self.cls
  1181. p = P('C:/a/b')
  1182. self.assertEqual(p / 'x/y', P('C:/a/b/x/y'))
  1183. self.assertEqual(p / 'x' / 'y', P('C:/a/b/x/y'))
  1184. self.assertEqual(p / '/x/y', P('C:/x/y'))
  1185. self.assertEqual(p / '/x' / 'y', P('C:/x/y'))
  1186. # Joining with a different drive => the first path is ignored, even
  1187. # if the second path is relative.
  1188. self.assertEqual(p / 'D:x/y', P('D:x/y'))
  1189. self.assertEqual(p / 'D:' / 'x/y', P('D:x/y'))
  1190. self.assertEqual(p / 'D:/x/y', P('D:/x/y'))
  1191. self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y'))
  1192. self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y'))
  1193. # Joining with the same drive => the first path is appended to if
  1194. # the second path is relative.
  1195. self.assertEqual(p / 'c:x/y', P('C:/a/b/x/y'))
  1196. self.assertEqual(p / 'c:/x/y', P('C:/x/y'))
  1197. def test_is_reserved(self):
  1198. P = self.cls
  1199. self.assertIs(False, P('').is_reserved())
  1200. self.assertIs(False, P('/').is_reserved())
  1201. self.assertIs(False, P('/foo/bar').is_reserved())
  1202. # UNC paths are never reserved.
  1203. self.assertIs(False, P('//my/share/nul/con/aux').is_reserved())
  1204. # Case-insensitive DOS-device names are reserved.
  1205. self.assertIs(True, P('nul').is_reserved())
  1206. self.assertIs(True, P('aux').is_reserved())
  1207. self.assertIs(True, P('prn').is_reserved())
  1208. self.assertIs(True, P('con').is_reserved())
  1209. self.assertIs(True, P('conin$').is_reserved())
  1210. self.assertIs(True, P('conout$').is_reserved())
  1211. # COM/LPT + 1-9 or + superscript 1-3 are reserved.
  1212. self.assertIs(True, P('COM1').is_reserved())
  1213. self.assertIs(True, P('LPT9').is_reserved())
  1214. self.assertIs(True, P('com\xb9').is_reserved())
  1215. self.assertIs(True, P('com\xb2').is_reserved())
  1216. self.assertIs(True, P('lpt\xb3').is_reserved())
  1217. # DOS-device name mataching ignores characters after a dot or
  1218. # a colon and also ignores trailing spaces.
  1219. self.assertIs(True, P('NUL.txt').is_reserved())
  1220. self.assertIs(True, P('PRN ').is_reserved())
  1221. self.assertIs(True, P('AUX .txt').is_reserved())
  1222. self.assertIs(True, P('COM1:bar').is_reserved())
  1223. self.assertIs(True, P('LPT9 :bar').is_reserved())
  1224. # DOS-device names are only matched at the beginning
  1225. # of a path component.
  1226. self.assertIs(False, P('bar.com9').is_reserved())
  1227. self.assertIs(False, P('bar.lpt9').is_reserved())
  1228. # Only the last path component matters.
  1229. self.assertIs(True, P('c:/baz/con/NUL').is_reserved())
  1230. self.assertIs(False, P('c:/NUL/con/baz').is_reserved())
  1231. class PurePathTest(_BasePurePathTest, unittest.TestCase):
  1232. cls = pathlib.PurePath
  1233. def test_concrete_class(self):
  1234. p = self.cls('a')
  1235. self.assertIs(type(p),
  1236. pathlib.PureWindowsPath if os.name == 'nt' else pathlib.PurePosixPath)
  1237. def test_different_flavours_unequal(self):
  1238. p = pathlib.PurePosixPath('a')
  1239. q = pathlib.PureWindowsPath('a')
  1240. self.assertNotEqual(p, q)
  1241. def test_different_flavours_unordered(self):
  1242. p = pathlib.PurePosixPath('a')
  1243. q = pathlib.PureWindowsPath('a')
  1244. with self.assertRaises(TypeError):
  1245. p < q
  1246. with self.assertRaises(TypeError):
  1247. p <= q
  1248. with self.assertRaises(TypeError):
  1249. p > q
  1250. with self.assertRaises(TypeError):
  1251. p >= q
  1252. #
  1253. # Tests for the concrete classes.
  1254. #
  1255. # Make sure any symbolic links in the base test path are resolved.
  1256. BASE = os.path.realpath(TESTFN)
  1257. join = lambda *x: os.path.join(BASE, *x)
  1258. rel_join = lambda *x: os.path.join(TESTFN, *x)
  1259. only_nt = unittest.skipIf(os.name != 'nt',
  1260. 'test requires a Windows-compatible system')
  1261. only_posix = unittest.skipIf(os.name == 'nt',
  1262. 'test requires a POSIX-compatible system')
  1263. @only_posix
  1264. class PosixPathAsPureTest(PurePosixPathTest):
  1265. cls = pathlib.PosixPath
  1266. @only_nt
  1267. class WindowsPathAsPureTest(PureWindowsPathTest):
  1268. cls = pathlib.WindowsPath
  1269. def test_owner(self):
  1270. P = self.cls
  1271. with self.assertRaises(NotImplementedError):
  1272. P('c:/').owner()
  1273. def test_group(self):
  1274. P = self.cls
  1275. with self.assertRaises(NotImplementedError):
  1276. P('c:/').group()
  1277. class _BasePathTest(object):
  1278. """Tests for the FS-accessing functionalities of the Path classes."""
  1279. # (BASE)
  1280. # |
  1281. # |-- brokenLink -> non-existing
  1282. # |-- dirA
  1283. # | `-- linkC -> ../dirB
  1284. # |-- dirB
  1285. # | |-- fileB
  1286. # | `-- linkD -> ../dirB
  1287. # |-- dirC
  1288. # | |-- dirD
  1289. # | | `-- fileD
  1290. # | `-- fileC
  1291. # | `-- novel.txt
  1292. # |-- dirE # No permissions
  1293. # |-- fileA
  1294. # |-- linkA -> fileA
  1295. # |-- linkB -> dirB
  1296. # `-- brokenLinkLoop -> brokenLinkLoop
  1297. #
  1298. def setUp(self):
  1299. def cleanup():
  1300. os.chmod(join('dirE'), 0o777)
  1301. os_helper.rmtree(BASE)
  1302. self.addCleanup(cleanup)
  1303. os.mkdir(BASE)
  1304. os.mkdir(join('dirA'))
  1305. os.mkdir(join('dirB'))
  1306. os.mkdir(join('dirC'))
  1307. os.mkdir(join('dirC', 'dirD'))
  1308. os.mkdir(join('dirE'))
  1309. with open(join('fileA'), 'wb') as f:
  1310. f.write(b"this is file A\n")
  1311. with open(join('dirB', 'fileB'), 'wb') as f:
  1312. f.write(b"this is file B\n")
  1313. with open(join('dirC', 'fileC'), 'wb') as f:
  1314. f.write(b"this is file C\n")
  1315. with open(join('dirC', 'novel.txt'), 'wb') as f:
  1316. f.write(b"this is a novel\n")
  1317. with open(join('dirC', 'dirD', 'fileD'), 'wb') as f:
  1318. f.write(b"this is file D\n")
  1319. os.chmod(join('dirE'), 0)
  1320. if os_helper.can_symlink():
  1321. # Relative symlinks.
  1322. os.symlink('fileA', join('linkA'))
  1323. os.symlink('non-existing', join('brokenLink'))
  1324. self.dirlink('dirB', join('linkB'))
  1325. self.dirlink(os.path.join('..', 'dirB'), join('dirA', 'linkC'))
  1326. # This one goes upwards, creating a loop.
  1327. self.dirlink(os.path.join('..', 'dirB'), join('dirB', 'linkD'))
  1328. # Broken symlink (pointing to itself).
  1329. os.symlink('brokenLinkLoop', join('brokenLinkLoop'))
  1330. if os.name == 'nt':
  1331. # Workaround for http://bugs.python.org/issue13772.
  1332. def dirlink(self, src, dest):
  1333. os.symlink(src, dest, target_is_directory=True)
  1334. else:
  1335. def dirlink(self, src, dest):
  1336. os.symlink(src, dest)
  1337. def assertSame(self, path_a, path_b):
  1338. self.assertTrue(os.path.samefile(str(path_a), str(path_b)),
  1339. "%r and %r don't point to the same file" %
  1340. (path_a, path_b))
  1341. def assertFileNotFound(self, func, *args, **kwargs):
  1342. with self.assertRaises(FileNotFoundError) as cm:
  1343. func(*args, **kwargs)
  1344. self.assertEqual(cm.exception.errno, errno.ENOENT)
  1345. def assertEqualNormCase(self, path_a, path_b):
  1346. self.assertEqual(os.path.normcase(path_a), os.path.normcase(path_b))
  1347. def _test_cwd(self, p):
  1348. q = self.cls(os.getcwd())
  1349. self.assertEqual(p, q)
  1350. self.assertEqualNormCase(str(p), str(q))
  1351. self.assertIs(type(p), type(q))
  1352. self.assertTrue(p.is_absolute())
  1353. def test_cwd(self):
  1354. p = self.cls.cwd()
  1355. self._test_cwd(p)
  1356. def test_absolute_common(self):
  1357. P = self.cls
  1358. with mock.patch("os.getcwd") as getcwd:
  1359. getcwd.return_value = BASE
  1360. # Simple relative paths.
  1361. self.assertEqual(str(P().absolute()), BASE)
  1362. self.assertEqual(str(P('.').absolute()), BASE)
  1363. self.assertEqual(str(P('a').absolute()), os.path.join(BASE, 'a'))
  1364. self.assertEqual(str(P('a', 'b', 'c').absolute()), os.path.join(BASE, 'a', 'b', 'c'))
  1365. # Symlinks should not be resolved.
  1366. self.assertEqual(str(P('linkB', 'fileB').absolute()), os.path.join(BASE, 'linkB', 'fileB'))
  1367. self.assertEqual(str(P('brokenLink').absolute()), os.path.join(BASE, 'brokenLink'))
  1368. self.assertEqual(str(P('brokenLinkLoop').absolute()), os.path.join(BASE, 'brokenLinkLoop'))
  1369. # '..' entries should be preserved and not normalised.
  1370. self.assertEqual(str(P('..').absolute()), os.path.join(BASE, '..'))
  1371. self.assertEqual(str(P('a', '..').absolute()), os.path.join(BASE, 'a', '..'))
  1372. self.assertEqual(str(P('..', 'b').absolute()), os.path.join(BASE, '..', 'b'))
  1373. def _test_home(self, p):
  1374. q = self.cls(os.path.expanduser('~'))
  1375. self.assertEqual(p, q)
  1376. self.assertEqualNormCase(str(p), str(q))
  1377. self.assertIs(type(p), type(q))
  1378. self.assertTrue(p.is_absolute())
  1379. @unittest.skipIf(
  1380. pwd is None, reason="Test requires pwd module to get homedir."
  1381. )
  1382. def test_home(self):
  1383. with os_helper.EnvironmentVarGuard() as env:
  1384. self._test_home(self.cls.home())
  1385. env.clear()
  1386. env['USERPROFILE'] = os.path.join(BASE, 'userprofile')
  1387. self._test_home(self.cls.home())
  1388. # bpo-38883: ignore `HOME` when set on windows
  1389. env['HOME'] = os.path.join(BASE, 'home')
  1390. self._test_home(self.cls.home())
  1391. def test_samefile(self):
  1392. fileA_path = os.path.join(BASE, 'fileA')
  1393. fileB_path = os.path.join(BASE, 'dirB', 'fileB')
  1394. p = self.cls(fileA_path)
  1395. pp = self.cls(fileA_path)
  1396. q = self.cls(fileB_path)
  1397. self.assertTrue(p.samefile(fileA_path))
  1398. self.assertTrue(p.samefile(pp))
  1399. self.assertFalse(p.samefile(fileB_path))
  1400. self.assertFalse(p.samefile(q))
  1401. # Test the non-existent file case
  1402. non_existent = os.path.join(BASE, 'foo')
  1403. r = self.cls(non_existent)
  1404. self.assertRaises(FileNotFoundError, p.samefile, r)
  1405. self.assertRaises(FileNotFoundError, p.samefile, non_existent)
  1406. self.assertRaises(FileNotFoundError, r.samefile, p)
  1407. self.assertRaises(FileNotFoundError, r.samefile, non_existent)
  1408. self.assertRaises(FileNotFoundError, r.samefile, r)
  1409. self.assertRaises(FileNotFoundError, r.samefile, non_existent)
  1410. def test_empty_path(self):
  1411. # The empty path points to '.'
  1412. p = self.cls('')
  1413. self.assertEqual(p.stat(), os.stat('.'))
  1414. @unittest.skipIf(is_wasi, "WASI has no user accounts.")
  1415. def test_expanduser_common(self):
  1416. P = self.cls
  1417. p = P('~')
  1418. self.assertEqual(p.expanduser(), P(os.path.expanduser('~')))
  1419. p = P('foo')
  1420. self.assertEqual(p.expanduser(), p)
  1421. p = P('/~')
  1422. self.assertEqual(p.expanduser(), p)
  1423. p = P('../~')
  1424. self.assertEqual(p.expanduser(), p)
  1425. p = P(P('').absolute().anchor) / '~'
  1426. self.assertEqual(p.expanduser(), p)
  1427. def test_exists(self):
  1428. P = self.cls
  1429. p = P(BASE)
  1430. self.assertIs(True, p.exists())
  1431. self.assertIs(True, (p / 'dirA').exists())
  1432. self.assertIs(True, (p / 'fileA').exists())
  1433. self.assertIs(False, (p / 'fileA' / 'bah').exists())
  1434. if os_helper.can_symlink():
  1435. self.assertIs(True, (p / 'linkA').exists())
  1436. self.assertIs(True, (p / 'linkB').exists())
  1437. self.assertIs(True, (p / 'linkB' / 'fileB').exists())
  1438. self.assertIs(False, (p / 'linkA' / 'bah').exists())
  1439. self.assertIs(False, (p / 'foo').exists())
  1440. self.assertIs(False, P('/xyzzy').exists())
  1441. self.assertIs(False, P(BASE + '\udfff').exists())
  1442. self.assertIs(False, P(BASE + '\x00').exists())
  1443. def test_open_common(self):
  1444. p = self.cls(BASE)
  1445. with (p / 'fileA').open('r') as f:
  1446. self.assertIsInstance(f, io.TextIOBase)
  1447. self.assertEqual(f.read(), "this is file A\n")
  1448. with (p / 'fileA').open('rb') as f:
  1449. self.assertIsInstance(f, io.BufferedIOBase)
  1450. self.assertEqual(f.read().strip(), b"this is file A")
  1451. with (p / 'fileA').open('rb', buffering=0) as f:
  1452. self.assertIsInstance(f, io.RawIOBase)
  1453. self.assertEqual(f.read().strip(), b"this is file A")
  1454. def test_read_write_bytes(self):
  1455. p = self.cls(BASE)
  1456. (p / 'fileA').write_bytes(b'abcdefg')
  1457. self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
  1458. # Check that trying to write str does not truncate the file.
  1459. self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr')
  1460. self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
  1461. def test_read_write_text(self):
  1462. p = self.cls(BASE)
  1463. (p / 'fileA').write_text('äbcdefg', encoding='latin-1')
  1464. self.assertEqual((p / 'fileA').read_text(
  1465. encoding='utf-8', errors='ignore'), 'bcdefg')
  1466. # Check that trying to write bytes does not truncate the file.
  1467. self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes')
  1468. self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg')
  1469. def test_write_text_with_newlines(self):
  1470. p = self.cls(BASE)
  1471. # Check that `\n` character change nothing
  1472. (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n')
  1473. self.assertEqual((p / 'fileA').read_bytes(),
  1474. b'abcde\r\nfghlk\n\rmnopq')
  1475. # Check that `\r` character replaces `\n`
  1476. (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r')
  1477. self.assertEqual((p / 'fileA').read_bytes(),
  1478. b'abcde\r\rfghlk\r\rmnopq')
  1479. # Check that `\r\n` character replaces `\n`
  1480. (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n')
  1481. self.assertEqual((p / 'fileA').read_bytes(),
  1482. b'abcde\r\r\nfghlk\r\n\rmnopq')
  1483. # Check that no argument passed will change `\n` to `os.linesep`
  1484. os_linesep_byte = bytes(os.linesep, encoding='ascii')
  1485. (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq')
  1486. self.assertEqual((p / 'fileA').read_bytes(),
  1487. b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq')
  1488. def test_iterdir(self):
  1489. P = self.cls
  1490. p = P(BASE)
  1491. it = p.iterdir()
  1492. paths = set(it)
  1493. expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA']
  1494. if os_helper.can_symlink():
  1495. expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop']
  1496. self.assertEqual(paths, { P(BASE, q) for q in expected })
  1497. @os_helper.skip_unless_symlink
  1498. def test_iterdir_symlink(self):
  1499. # __iter__ on a symlink to a directory.
  1500. P = self.cls
  1501. p = P(BASE, 'linkB')
  1502. paths = set(p.iterdir())
  1503. expected = { P(BASE, 'linkB', q) for q in ['fileB', 'linkD'] }
  1504. self.assertEqual(paths, expected)
  1505. def test_iterdir_nodir(self):
  1506. # __iter__ on something that is not a directory.
  1507. p = self.cls(BASE, 'fileA')
  1508. with self.assertRaises(OSError) as cm:
  1509. next(p.iterdir())
  1510. # ENOENT or EINVAL under Windows, ENOTDIR otherwise
  1511. # (see issue #12802).
  1512. self.assertIn(cm.exception.errno, (errno.ENOTDIR,
  1513. errno.ENOENT, errno.EINVAL))
  1514. def test_glob_common(self):
  1515. def _check(glob, expected):
  1516. self.assertEqual(set(glob), { P(BASE, q) for q in expected })
  1517. P = self.cls
  1518. p = P(BASE)
  1519. it = p.glob("fileA")
  1520. self.assertIsInstance(it, collections.abc.Iterator)
  1521. _check(it, ["fileA"])
  1522. _check(p.glob("fileB"), [])
  1523. _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"])
  1524. if not os_helper.can_symlink():
  1525. _check(p.glob("*A"), ['dirA', 'fileA'])
  1526. else:
  1527. _check(p.glob("*A"), ['dirA', 'fileA', 'linkA'])
  1528. if not os_helper.can_symlink():
  1529. _check(p.glob("*B/*"), ['dirB/fileB'])
  1530. else:
  1531. _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD',
  1532. 'linkB/fileB', 'linkB/linkD'])
  1533. if not os_helper.can_symlink():
  1534. _check(p.glob("*/fileB"), ['dirB/fileB'])
  1535. else:
  1536. _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB'])
  1537. if not os_helper.can_symlink():
  1538. _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"])
  1539. else:
  1540. _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"])
  1541. def test_rglob_common(self):
  1542. def _check(glob, expected):
  1543. self.assertEqual(set(glob), { P(BASE, q) for q in expected })
  1544. P = self.cls
  1545. p = P(BASE)
  1546. it = p.rglob("fileA")
  1547. self.assertIsInstance(it, collections.abc.Iterator)
  1548. _check(it, ["fileA"])
  1549. _check(p.rglob("fileB"), ["dirB/fileB"])
  1550. _check(p.rglob("*/fileA"), [])
  1551. if not os_helper.can_symlink():
  1552. _check(p.rglob("*/fileB"), ["dirB/fileB"])
  1553. else:
  1554. _check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB",
  1555. "linkB/fileB", "dirA/linkC/fileB"])
  1556. _check(p.rglob("file*"), ["fileA", "dirB/fileB",
  1557. "dirC/fileC", "dirC/dirD/fileD"])
  1558. if not os_helper.can_symlink():
  1559. _check(p.rglob("*/"), [
  1560. "dirA", "dirB", "dirC", "dirC/dirD", "dirE",
  1561. ])
  1562. else:
  1563. _check(p.rglob("*/"), [
  1564. "dirA", "dirA/linkC", "dirB", "dirB/linkD", "dirC",
  1565. "dirC/dirD", "dirE", "linkB",
  1566. ])
  1567. _check(p.rglob(""), ["", "dirA", "dirB", "dirC", "dirE", "dirC/dirD"])
  1568. p = P(BASE, "dirC")
  1569. _check(p.rglob("*"), ["dirC/fileC", "dirC/novel.txt",
  1570. "dirC/dirD", "dirC/dirD/fileD"])
  1571. _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
  1572. _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
  1573. _check(p.rglob("*/"), ["dirC/dirD"])
  1574. _check(p.rglob(""), ["dirC", "dirC/dirD"])
  1575. # gh-91616, a re module regression
  1576. _check(p.rglob("*.txt"), ["dirC/novel.txt"])
  1577. _check(p.rglob("*.*"), ["dirC/novel.txt"])
  1578. @os_helper.skip_unless_symlink
  1579. def test_rglob_symlink_loop(self):
  1580. # Don't get fooled by symlink loops (Issue #26012).
  1581. P = self.cls
  1582. p = P(BASE)
  1583. given = set(p.rglob('*'))
  1584. expect = {'brokenLink',
  1585. 'dirA', 'dirA/linkC',
  1586. 'dirB', 'dirB/fileB', 'dirB/linkD',
  1587. 'dirC', 'dirC/dirD', 'dirC/dirD/fileD',
  1588. 'dirC/fileC', 'dirC/novel.txt',
  1589. 'dirE',
  1590. 'fileA',
  1591. 'linkA',
  1592. 'linkB',
  1593. 'brokenLinkLoop',
  1594. }
  1595. self.assertEqual(given, {p / x for x in expect})
  1596. def test_glob_many_open_files(self):
  1597. depth = 30
  1598. P = self.cls
  1599. base = P(BASE) / 'deep'
  1600. p = P(base, *(['d']*depth))
  1601. p.mkdir(parents=True)
  1602. pattern = '/'.join(['*'] * depth)
  1603. iters = [base.glob(pattern) for j in range(100)]
  1604. for it in iters:
  1605. self.assertEqual(next(it), p)
  1606. iters = [base.rglob('d') for j in range(100)]
  1607. p = base
  1608. for i in range(depth):
  1609. p = p / 'd'
  1610. for it in iters:
  1611. self.assertEqual(next(it), p)
  1612. def test_glob_dotdot(self):
  1613. # ".." is not special in globs.
  1614. P = self.cls
  1615. p = P(BASE)
  1616. self.assertEqual(set(p.glob("..")), { P(BASE, "..") })
  1617. self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
  1618. self.assertEqual(set(p.glob("../xyzzy")), set())
  1619. @os_helper.skip_unless_symlink
  1620. def test_glob_permissions(self):
  1621. # See bpo-38894
  1622. P = self.cls
  1623. base = P(BASE) / 'permissions'
  1624. base.mkdir()
  1625. file1 = base / "file1"
  1626. file1.touch()
  1627. file2 = base / "file2"
  1628. file2.touch()
  1629. subdir = base / "subdir"
  1630. file3 = base / "file3"
  1631. file3.symlink_to(subdir / "other")
  1632. # Patching is needed to avoid relying on the filesystem
  1633. # to return the order of the files as the error will not
  1634. # happen if the symlink is the last item.
  1635. real_scandir = os.scandir
  1636. def my_scandir(path):
  1637. with real_scandir(path) as scandir_it:
  1638. entries = list(scandir_it)
  1639. entries.sort(key=lambda entry: entry.name)
  1640. return contextlib.nullcontext(entries)
  1641. with mock.patch("os.scandir", my_scandir):
  1642. self.assertEqual(len(set(base.glob("*"))), 3)
  1643. subdir.mkdir()
  1644. self.assertEqual(len(set(base.glob("*"))), 4)
  1645. subdir.chmod(000)
  1646. self.assertEqual(len(set(base.glob("*"))), 4)
  1647. def _check_resolve(self, p, expected, strict=True):
  1648. q = p.resolve(strict)
  1649. self.assertEqual(q, expected)
  1650. # This can be used to check both relative and absolute resolutions.
  1651. _check_resolve_relative = _check_resolve_absolute = _check_resolve
  1652. @os_helper.skip_unless_symlink
  1653. def test_resolve_common(self):
  1654. P = self.cls
  1655. p = P(BASE, 'foo')
  1656. with self.assertRaises(OSError) as cm:
  1657. p.resolve(strict=True)
  1658. self.assertEqual(cm.exception.errno, errno.ENOENT)
  1659. # Non-strict
  1660. self.assertEqualNormCase(str(p.resolve(strict=False)),
  1661. os.path.join(BASE, 'foo'))
  1662. p = P(BASE, 'foo', 'in', 'spam')
  1663. self.assertEqualNormCase(str(p.resolve(strict=False)),
  1664. os.path.join(BASE, 'foo', 'in', 'spam'))
  1665. p = P(BASE, '..', 'foo', 'in', 'spam')
  1666. self.assertEqualNormCase(str(p.resolve(strict=False)),
  1667. os.path.abspath(os.path.join('foo', 'in', 'spam')))
  1668. # These are all relative symlinks.
  1669. p = P(BASE, 'dirB', 'fileB')
  1670. self._check_resolve_relative(p, p)
  1671. p = P(BASE, 'linkA')
  1672. self._check_resolve_relative(p, P(BASE, 'fileA'))
  1673. p = P(BASE, 'dirA', 'linkC', 'fileB')
  1674. self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
  1675. p = P(BASE, 'dirB', 'linkD', 'fileB')
  1676. self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB'))
  1677. # Non-strict
  1678. p = P(BASE, 'dirA', 'linkC', 'fileB', 'foo', 'in', 'spam')
  1679. self._check_resolve_relative(p, P(BASE, 'dirB', 'fileB', 'foo', 'in',
  1680. 'spam'), False)
  1681. p = P(BASE, 'dirA', 'linkC', '..', 'foo', 'in', 'spam')
  1682. if os.name == 'nt':
  1683. # In Windows, if linkY points to dirB, 'dirA\linkY\..'
  1684. # resolves to 'dirA' without resolving linkY first.
  1685. self._check_resolve_relative(p, P(BASE, 'dirA', 'foo', 'in',
  1686. 'spam'), False)
  1687. else:
  1688. # In Posix, if linkY points to dirB, 'dirA/linkY/..'
  1689. # resolves to 'dirB/..' first before resolving to parent of dirB.
  1690. self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
  1691. # Now create absolute symlinks.
  1692. d = os_helper._longpath(tempfile.mkdtemp(suffix='-dirD',
  1693. dir=os.getcwd()))
  1694. self.addCleanup(os_helper.rmtree, d)
  1695. os.symlink(os.path.join(d), join('dirA', 'linkX'))
  1696. os.symlink(join('dirB'), os.path.join(d, 'linkY'))
  1697. p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB')
  1698. self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB'))
  1699. # Non-strict
  1700. p = P(BASE, 'dirA', 'linkX', 'linkY', 'foo', 'in', 'spam')
  1701. self._check_resolve_relative(p, P(BASE, 'dirB', 'foo', 'in', 'spam'),
  1702. False)
  1703. p = P(BASE, 'dirA', 'linkX', 'linkY', '..', 'foo', 'in', 'spam')
  1704. if os.name == 'nt':
  1705. # In Windows, if linkY points to dirB, 'dirA\linkY\..'
  1706. # resolves to 'dirA' without resolving linkY first.
  1707. self._check_resolve_relative(p, P(d, 'foo', 'in', 'spam'), False)
  1708. else:
  1709. # In Posix, if linkY points to dirB, 'dirA/linkY/..'
  1710. # resolves to 'dirB/..' first before resolving to parent of dirB.
  1711. self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
  1712. @os_helper.skip_unless_symlink
  1713. def test_resolve_dot(self):
  1714. # See https://bitbucket.org/pitrou/pathlib/issue/9/pathresolve-fails-on-complex-symlinks
  1715. p = self.cls(BASE)
  1716. self.dirlink('.', join('0'))
  1717. self.dirlink(os.path.join('0', '0'), join('1'))
  1718. self.dirlink(os.path.join('1', '1'), join('2'))
  1719. q = p / '2'
  1720. self.assertEqual(q.resolve(strict=True), p)
  1721. r = q / '3' / '4'
  1722. self.assertRaises(FileNotFoundError, r.resolve, strict=True)
  1723. # Non-strict
  1724. self.assertEqual(r.resolve(strict=False), p / '3' / '4')
  1725. def test_resolve_nonexist_relative_issue38671(self):
  1726. p = self.cls('non', 'exist')
  1727. old_cwd = os.getcwd()
  1728. os.chdir(BASE)
  1729. try:
  1730. self.assertEqual(p.resolve(), self.cls(BASE, p))
  1731. finally:
  1732. os.chdir(old_cwd)
  1733. def test_with(self):
  1734. p = self.cls(BASE)
  1735. it = p.iterdir()
  1736. it2 = p.iterdir()
  1737. next(it2)
  1738. # bpo-46556: path context managers are deprecated in Python 3.11.
  1739. with self.assertWarns(DeprecationWarning):
  1740. with p:
  1741. pass
  1742. # Using a path as a context manager is a no-op, thus the following
  1743. # operations should still succeed after the context manage exits.
  1744. next(it)
  1745. next(it2)
  1746. p.exists()
  1747. p.resolve()
  1748. p.absolute()
  1749. with self.assertWarns(DeprecationWarning):
  1750. with p:
  1751. pass
  1752. @os_helper.skip_unless_working_chmod
  1753. def test_chmod(self):
  1754. p = self.cls(BASE) / 'fileA'
  1755. mode = p.stat().st_mode
  1756. # Clear writable bit.
  1757. new_mode = mode & ~0o222
  1758. p.chmod(new_mode)
  1759. self.assertEqual(p.stat().st_mode, new_mode)
  1760. # Set writable bit.
  1761. new_mode = mode | 0o222
  1762. p.chmod(new_mode)
  1763. self.assertEqual(p.stat().st_mode, new_mode)
  1764. # On Windows, os.chmod does not follow symlinks (issue #15411)
  1765. @only_posix
  1766. @os_helper.skip_unless_working_chmod
  1767. def test_chmod_follow_symlinks_true(self):
  1768. p = self.cls(BASE) / 'linkA'
  1769. q = p.resolve()
  1770. mode = q.stat().st_mode
  1771. # Clear writable bit.
  1772. new_mode = mode & ~0o222
  1773. p.chmod(new_mode, follow_symlinks=True)
  1774. self.assertEqual(q.stat().st_mode, new_mode)
  1775. # Set writable bit
  1776. new_mode = mode | 0o222
  1777. p.chmod(new_mode, follow_symlinks=True)
  1778. self.assertEqual(q.stat().st_mode, new_mode)
  1779. # XXX also need a test for lchmod.
  1780. @os_helper.skip_unless_working_chmod
  1781. def test_stat(self):
  1782. p = self.cls(BASE) / 'fileA'
  1783. st = p.stat()
  1784. self.assertEqual(p.stat(), st)
  1785. # Change file mode by flipping write bit.
  1786. p.chmod(st.st_mode ^ 0o222)
  1787. self.addCleanup(p.chmod, st.st_mode)
  1788. self.assertNotEqual(p.stat(), st)
  1789. @os_helper.skip_unless_symlink
  1790. def test_stat_no_follow_symlinks(self):
  1791. p = self.cls(BASE) / 'linkA'
  1792. st = p.stat()
  1793. self.assertNotEqual(st, p.stat(follow_symlinks=False))
  1794. def test_stat_no_follow_symlinks_nosymlink(self):
  1795. p = self.cls(BASE) / 'fileA'
  1796. st = p.stat()
  1797. self.assertEqual(st, p.stat(follow_symlinks=False))
  1798. @os_helper.skip_unless_symlink
  1799. def test_lstat(self):
  1800. p = self.cls(BASE)/ 'linkA'
  1801. st = p.stat()
  1802. self.assertNotEqual(st, p.lstat())
  1803. def test_lstat_nosymlink(self):
  1804. p = self.cls(BASE) / 'fileA'
  1805. st = p.stat()
  1806. self.assertEqual(st, p.lstat())
  1807. @unittest.skipUnless(pwd, "the pwd module is needed for this test")
  1808. def test_owner(self):
  1809. p = self.cls(BASE) / 'fileA'
  1810. uid = p.stat().st_uid
  1811. try:
  1812. name = pwd.getpwuid(uid).pw_name
  1813. except KeyError:
  1814. self.skipTest(
  1815. "user %d doesn't have an entry in the system database" % uid)
  1816. self.assertEqual(name, p.owner())
  1817. @unittest.skipUnless(grp, "the grp module is needed for this test")
  1818. def test_group(self):
  1819. p = self.cls(BASE) / 'fileA'
  1820. gid = p.stat().st_gid
  1821. try:
  1822. name = grp.getgrgid(gid).gr_name
  1823. except KeyError:
  1824. self.skipTest(
  1825. "group %d doesn't have an entry in the system database" % gid)
  1826. self.assertEqual(name, p.group())
  1827. def test_unlink(self):
  1828. p = self.cls(BASE) / 'fileA'
  1829. p.unlink()
  1830. self.assertFileNotFound(p.stat)
  1831. self.assertFileNotFound(p.unlink)
  1832. def test_unlink_missing_ok(self):
  1833. p = self.cls(BASE) / 'fileAAA'
  1834. self.assertFileNotFound(p.unlink)
  1835. p.unlink(missing_ok=True)
  1836. def test_rmdir(self):
  1837. p = self.cls(BASE) / 'dirA'
  1838. for q in p.iterdir():
  1839. q.unlink()
  1840. p.rmdir()
  1841. self.assertFileNotFound(p.stat)
  1842. self.assertFileNotFound(p.unlink)
  1843. @unittest.skipUnless(hasattr(os, "link"), "os.link() is not present")
  1844. def test_link_to(self):
  1845. P = self.cls(BASE)
  1846. p = P / 'fileA'
  1847. size = p.stat().st_size
  1848. # linking to another path.
  1849. q = P / 'dirA' / 'fileAA'
  1850. try:
  1851. with self.assertWarns(DeprecationWarning):
  1852. p.link_to(q)
  1853. except PermissionError as e:
  1854. self.skipTest('os.link(): %s' % e)
  1855. self.assertEqual(q.stat().st_size, size)
  1856. self.assertEqual(os.path.samefile(p, q), True)
  1857. self.assertTrue(p.stat)
  1858. # Linking to a str of a relative path.
  1859. r = rel_join('fileAAA')
  1860. with self.assertWarns(DeprecationWarning):
  1861. q.link_to(r)
  1862. self.assertEqual(os.stat(r).st_size, size)
  1863. self.assertTrue(q.stat)
  1864. @unittest.skipUnless(hasattr(os, "link"), "os.link() is not present")
  1865. def test_hardlink_to(self):
  1866. P = self.cls(BASE)
  1867. target = P / 'fileA'
  1868. size = target.stat().st_size
  1869. # linking to another path.
  1870. link = P / 'dirA' / 'fileAA'
  1871. link.hardlink_to(target)
  1872. self.assertEqual(link.stat().st_size, size)
  1873. self.assertTrue(os.path.samefile(target, link))
  1874. self.assertTrue(target.exists())
  1875. # Linking to a str of a relative path.
  1876. link2 = P / 'dirA' / 'fileAAA'
  1877. target2 = rel_join('fileA')
  1878. link2.hardlink_to(target2)
  1879. self.assertEqual(os.stat(target2).st_size, size)
  1880. self.assertTrue(link2.exists())
  1881. @unittest.skipIf(hasattr(os, "link"), "os.link() is present")
  1882. def test_link_to_not_implemented(self):
  1883. P = self.cls(BASE)
  1884. p = P / 'fileA'
  1885. # linking to another path.
  1886. q = P / 'dirA' / 'fileAA'
  1887. with self.assertRaises(NotImplementedError):
  1888. p.link_to(q)
  1889. def test_rename(self):
  1890. P = self.cls(BASE)
  1891. p = P / 'fileA'
  1892. size = p.stat().st_size
  1893. # Renaming to another path.
  1894. q = P / 'dirA' / 'fileAA'
  1895. renamed_p = p.rename(q)
  1896. self.assertEqual(renamed_p, q)
  1897. self.assertEqual(q.stat().st_size, size)
  1898. self.assertFileNotFound(p.stat)
  1899. # Renaming to a str of a relative path.
  1900. r = rel_join('fileAAA')
  1901. renamed_q = q.rename(r)
  1902. self.assertEqual(renamed_q, self.cls(r))
  1903. self.assertEqual(os.stat(r).st_size, size)
  1904. self.assertFileNotFound(q.stat)
  1905. def test_replace(self):
  1906. P = self.cls(BASE)
  1907. p = P / 'fileA'
  1908. size = p.stat().st_size
  1909. # Replacing a non-existing path.
  1910. q = P / 'dirA' / 'fileAA'
  1911. replaced_p = p.replace(q)
  1912. self.assertEqual(replaced_p, q)
  1913. self.assertEqual(q.stat().st_size, size)
  1914. self.assertFileNotFound(p.stat)
  1915. # Replacing another (existing) path.
  1916. r = rel_join('dirB', 'fileB')
  1917. replaced_q = q.replace(r)
  1918. self.assertEqual(replaced_q, self.cls(r))
  1919. self.assertEqual(os.stat(r).st_size, size)
  1920. self.assertFileNotFound(q.stat)
  1921. @os_helper.skip_unless_symlink
  1922. def test_readlink(self):
  1923. P = self.cls(BASE)
  1924. self.assertEqual((P / 'linkA').readlink(), self.cls('fileA'))
  1925. self.assertEqual((P / 'brokenLink').readlink(),
  1926. self.cls('non-existing'))
  1927. self.assertEqual((P / 'linkB').readlink(), self.cls('dirB'))
  1928. with self.assertRaises(OSError):
  1929. (P / 'fileA').readlink()
  1930. def test_touch_common(self):
  1931. P = self.cls(BASE)
  1932. p = P / 'newfileA'
  1933. self.assertFalse(p.exists())
  1934. p.touch()
  1935. self.assertTrue(p.exists())
  1936. st = p.stat()
  1937. old_mtime = st.st_mtime
  1938. old_mtime_ns = st.st_mtime_ns
  1939. # Rewind the mtime sufficiently far in the past to work around
  1940. # filesystem-specific timestamp granularity.
  1941. os.utime(str(p), (old_mtime - 10, old_mtime - 10))
  1942. # The file mtime should be refreshed by calling touch() again.
  1943. p.touch()
  1944. st = p.stat()
  1945. self.assertGreaterEqual(st.st_mtime_ns, old_mtime_ns)
  1946. self.assertGreaterEqual(st.st_mtime, old_mtime)
  1947. # Now with exist_ok=False.
  1948. p = P / 'newfileB'
  1949. self.assertFalse(p.exists())
  1950. p.touch(mode=0o700, exist_ok=False)
  1951. self.assertTrue(p.exists())
  1952. self.assertRaises(OSError, p.touch, exist_ok=False)
  1953. def test_touch_nochange(self):
  1954. P = self.cls(BASE)
  1955. p = P / 'fileA'
  1956. p.touch()
  1957. with p.open('rb') as f:
  1958. self.assertEqual(f.read().strip(), b"this is file A")
  1959. def test_mkdir(self):
  1960. P = self.cls(BASE)
  1961. p = P / 'newdirA'
  1962. self.assertFalse(p.exists())
  1963. p.mkdir()
  1964. self.assertTrue(p.exists())
  1965. self.assertTrue(p.is_dir())
  1966. with self.assertRaises(OSError) as cm:
  1967. p.mkdir()
  1968. self.assertEqual(cm.exception.errno, errno.EEXIST)
  1969. def test_mkdir_parents(self):
  1970. # Creating a chain of directories.
  1971. p = self.cls(BASE, 'newdirB', 'newdirC')
  1972. self.assertFalse(p.exists())
  1973. with self.assertRaises(OSError) as cm:
  1974. p.mkdir()
  1975. self.assertEqual(cm.exception.errno, errno.ENOENT)
  1976. p.mkdir(parents=True)
  1977. self.assertTrue(p.exists())
  1978. self.assertTrue(p.is_dir())
  1979. with self.assertRaises(OSError) as cm:
  1980. p.mkdir(parents=True)
  1981. self.assertEqual(cm.exception.errno, errno.EEXIST)
  1982. # Test `mode` arg.
  1983. mode = stat.S_IMODE(p.stat().st_mode) # Default mode.
  1984. p = self.cls(BASE, 'newdirD', 'newdirE')
  1985. p.mkdir(0o555, parents=True)
  1986. self.assertTrue(p.exists())
  1987. self.assertTrue(p.is_dir())
  1988. if os.name != 'nt':
  1989. # The directory's permissions follow the mode argument.
  1990. self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o7555 & mode)
  1991. # The parent's permissions follow the default process settings.
  1992. self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode)
  1993. def test_mkdir_exist_ok(self):
  1994. p = self.cls(BASE, 'dirB')
  1995. st_ctime_first = p.stat().st_ctime
  1996. self.assertTrue(p.exists())
  1997. self.assertTrue(p.is_dir())
  1998. with self.assertRaises(FileExistsError) as cm:
  1999. p.mkdir()
  2000. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2001. p.mkdir(exist_ok=True)
  2002. self.assertTrue(p.exists())
  2003. self.assertEqual(p.stat().st_ctime, st_ctime_first)
  2004. def test_mkdir_exist_ok_with_parent(self):
  2005. p = self.cls(BASE, 'dirC')
  2006. self.assertTrue(p.exists())
  2007. with self.assertRaises(FileExistsError) as cm:
  2008. p.mkdir()
  2009. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2010. p = p / 'newdirC'
  2011. p.mkdir(parents=True)
  2012. st_ctime_first = p.stat().st_ctime
  2013. self.assertTrue(p.exists())
  2014. with self.assertRaises(FileExistsError) as cm:
  2015. p.mkdir(parents=True)
  2016. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2017. p.mkdir(parents=True, exist_ok=True)
  2018. self.assertTrue(p.exists())
  2019. self.assertEqual(p.stat().st_ctime, st_ctime_first)
  2020. @unittest.skipIf(is_emscripten, "FS root cannot be modified on Emscripten.")
  2021. def test_mkdir_exist_ok_root(self):
  2022. # Issue #25803: A drive root could raise PermissionError on Windows.
  2023. self.cls('/').resolve().mkdir(exist_ok=True)
  2024. self.cls('/').resolve().mkdir(parents=True, exist_ok=True)
  2025. @only_nt # XXX: not sure how to test this on POSIX.
  2026. def test_mkdir_with_unknown_drive(self):
  2027. for d in 'ZYXWVUTSRQPONMLKJIHGFEDCBA':
  2028. p = self.cls(d + ':\\')
  2029. if not p.is_dir():
  2030. break
  2031. else:
  2032. self.skipTest("cannot find a drive that doesn't exist")
  2033. with self.assertRaises(OSError):
  2034. (p / 'child' / 'path').mkdir(parents=True)
  2035. def test_mkdir_with_child_file(self):
  2036. p = self.cls(BASE, 'dirB', 'fileB')
  2037. self.assertTrue(p.exists())
  2038. # An exception is raised when the last path component is an existing
  2039. # regular file, regardless of whether exist_ok is true or not.
  2040. with self.assertRaises(FileExistsError) as cm:
  2041. p.mkdir(parents=True)
  2042. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2043. with self.assertRaises(FileExistsError) as cm:
  2044. p.mkdir(parents=True, exist_ok=True)
  2045. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2046. def test_mkdir_no_parents_file(self):
  2047. p = self.cls(BASE, 'fileA')
  2048. self.assertTrue(p.exists())
  2049. # An exception is raised when the last path component is an existing
  2050. # regular file, regardless of whether exist_ok is true or not.
  2051. with self.assertRaises(FileExistsError) as cm:
  2052. p.mkdir()
  2053. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2054. with self.assertRaises(FileExistsError) as cm:
  2055. p.mkdir(exist_ok=True)
  2056. self.assertEqual(cm.exception.errno, errno.EEXIST)
  2057. def test_mkdir_concurrent_parent_creation(self):
  2058. for pattern_num in range(32):
  2059. p = self.cls(BASE, 'dirCPC%d' % pattern_num)
  2060. self.assertFalse(p.exists())
  2061. real_mkdir = os.mkdir
  2062. def my_mkdir(path, mode=0o777):
  2063. path = str(path)
  2064. # Emulate another process that would create the directory
  2065. # just before we try to create it ourselves. We do it
  2066. # in all possible pattern combinations, assuming that this
  2067. # function is called at most 5 times (dirCPC/dir1/dir2,
  2068. # dirCPC/dir1, dirCPC, dirCPC/dir1, dirCPC/dir1/dir2).
  2069. if pattern.pop():
  2070. real_mkdir(path, mode) # From another process.
  2071. concurrently_created.add(path)
  2072. real_mkdir(path, mode) # Our real call.
  2073. pattern = [bool(pattern_num & (1 << n)) for n in range(5)]
  2074. concurrently_created = set()
  2075. p12 = p / 'dir1' / 'dir2'
  2076. try:
  2077. with mock.patch("os.mkdir", my_mkdir):
  2078. p12.mkdir(parents=True, exist_ok=False)
  2079. except FileExistsError:
  2080. self.assertIn(str(p12), concurrently_created)
  2081. else:
  2082. self.assertNotIn(str(p12), concurrently_created)
  2083. self.assertTrue(p.exists())
  2084. @os_helper.skip_unless_symlink
  2085. def test_symlink_to(self):
  2086. P = self.cls(BASE)
  2087. target = P / 'fileA'
  2088. # Symlinking a path target.
  2089. link = P / 'dirA' / 'linkAA'
  2090. link.symlink_to(target)
  2091. self.assertEqual(link.stat(), target.stat())
  2092. self.assertNotEqual(link.lstat(), target.stat())
  2093. # Symlinking a str target.
  2094. link = P / 'dirA' / 'linkAAA'
  2095. link.symlink_to(str(target))
  2096. self.assertEqual(link.stat(), target.stat())
  2097. self.assertNotEqual(link.lstat(), target.stat())
  2098. self.assertFalse(link.is_dir())
  2099. # Symlinking to a directory.
  2100. target = P / 'dirB'
  2101. link = P / 'dirA' / 'linkAAAA'
  2102. link.symlink_to(target, target_is_directory=True)
  2103. self.assertEqual(link.stat(), target.stat())
  2104. self.assertNotEqual(link.lstat(), target.stat())
  2105. self.assertTrue(link.is_dir())
  2106. self.assertTrue(list(link.iterdir()))
  2107. def test_is_dir(self):
  2108. P = self.cls(BASE)
  2109. self.assertTrue((P / 'dirA').is_dir())
  2110. self.assertFalse((P / 'fileA').is_dir())
  2111. self.assertFalse((P / 'non-existing').is_dir())
  2112. self.assertFalse((P / 'fileA' / 'bah').is_dir())
  2113. if os_helper.can_symlink():
  2114. self.assertFalse((P / 'linkA').is_dir())
  2115. self.assertTrue((P / 'linkB').is_dir())
  2116. self.assertFalse((P/ 'brokenLink').is_dir(), False)
  2117. self.assertIs((P / 'dirA\udfff').is_dir(), False)
  2118. self.assertIs((P / 'dirA\x00').is_dir(), False)
  2119. def test_is_file(self):
  2120. P = self.cls(BASE)
  2121. self.assertTrue((P / 'fileA').is_file())
  2122. self.assertFalse((P / 'dirA').is_file())
  2123. self.assertFalse((P / 'non-existing').is_file())
  2124. self.assertFalse((P / 'fileA' / 'bah').is_file())
  2125. if os_helper.can_symlink():
  2126. self.assertTrue((P / 'linkA').is_file())
  2127. self.assertFalse((P / 'linkB').is_file())
  2128. self.assertFalse((P/ 'brokenLink').is_file())
  2129. self.assertIs((P / 'fileA\udfff').is_file(), False)
  2130. self.assertIs((P / 'fileA\x00').is_file(), False)
  2131. @only_posix
  2132. def test_is_mount(self):
  2133. P = self.cls(BASE)
  2134. R = self.cls('/') # TODO: Work out Windows.
  2135. self.assertFalse((P / 'fileA').is_mount())
  2136. self.assertFalse((P / 'dirA').is_mount())
  2137. self.assertFalse((P / 'non-existing').is_mount())
  2138. self.assertFalse((P / 'fileA' / 'bah').is_mount())
  2139. self.assertTrue(R.is_mount())
  2140. if os_helper.can_symlink():
  2141. self.assertFalse((P / 'linkA').is_mount())
  2142. self.assertIs(self.cls('/\udfff').is_mount(), False)
  2143. self.assertIs(self.cls('/\x00').is_mount(), False)
  2144. def test_is_symlink(self):
  2145. P = self.cls(BASE)
  2146. self.assertFalse((P / 'fileA').is_symlink())
  2147. self.assertFalse((P / 'dirA').is_symlink())
  2148. self.assertFalse((P / 'non-existing').is_symlink())
  2149. self.assertFalse((P / 'fileA' / 'bah').is_symlink())
  2150. if os_helper.can_symlink():
  2151. self.assertTrue((P / 'linkA').is_symlink())
  2152. self.assertTrue((P / 'linkB').is_symlink())
  2153. self.assertTrue((P/ 'brokenLink').is_symlink())
  2154. self.assertIs((P / 'fileA\udfff').is_file(), False)
  2155. self.assertIs((P / 'fileA\x00').is_file(), False)
  2156. if os_helper.can_symlink():
  2157. self.assertIs((P / 'linkA\udfff').is_file(), False)
  2158. self.assertIs((P / 'linkA\x00').is_file(), False)
  2159. def test_is_fifo_false(self):
  2160. P = self.cls(BASE)
  2161. self.assertFalse((P / 'fileA').is_fifo())
  2162. self.assertFalse((P / 'dirA').is_fifo())
  2163. self.assertFalse((P / 'non-existing').is_fifo())
  2164. self.assertFalse((P / 'fileA' / 'bah').is_fifo())
  2165. self.assertIs((P / 'fileA\udfff').is_fifo(), False)
  2166. self.assertIs((P / 'fileA\x00').is_fifo(), False)
  2167. @unittest.skipUnless(hasattr(os, "mkfifo"), "os.mkfifo() required")
  2168. @unittest.skipIf(sys.platform == "vxworks",
  2169. "fifo requires special path on VxWorks")
  2170. def test_is_fifo_true(self):
  2171. P = self.cls(BASE, 'myfifo')
  2172. try:
  2173. os.mkfifo(str(P))
  2174. except PermissionError as e:
  2175. self.skipTest('os.mkfifo(): %s' % e)
  2176. self.assertTrue(P.is_fifo())
  2177. self.assertFalse(P.is_socket())
  2178. self.assertFalse(P.is_file())
  2179. self.assertIs(self.cls(BASE, 'myfifo\udfff').is_fifo(), False)
  2180. self.assertIs(self.cls(BASE, 'myfifo\x00').is_fifo(), False)
  2181. def test_is_socket_false(self):
  2182. P = self.cls(BASE)
  2183. self.assertFalse((P / 'fileA').is_socket())
  2184. self.assertFalse((P / 'dirA').is_socket())
  2185. self.assertFalse((P / 'non-existing').is_socket())
  2186. self.assertFalse((P / 'fileA' / 'bah').is_socket())
  2187. self.assertIs((P / 'fileA\udfff').is_socket(), False)
  2188. self.assertIs((P / 'fileA\x00').is_socket(), False)
  2189. @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
  2190. @unittest.skipIf(
  2191. is_emscripten, "Unix sockets are not implemented on Emscripten."
  2192. )
  2193. @unittest.skipIf(
  2194. is_wasi, "Cannot create socket on WASI."
  2195. )
  2196. def test_is_socket_true(self):
  2197. P = self.cls(BASE, 'mysock')
  2198. sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  2199. self.addCleanup(sock.close)
  2200. try:
  2201. sock.bind(str(P))
  2202. except OSError as e:
  2203. if (isinstance(e, PermissionError) or
  2204. "AF_UNIX path too long" in str(e)):
  2205. self.skipTest("cannot bind Unix socket: " + str(e))
  2206. self.assertTrue(P.is_socket())
  2207. self.assertFalse(P.is_fifo())
  2208. self.assertFalse(P.is_file())
  2209. self.assertIs(self.cls(BASE, 'mysock\udfff').is_socket(), False)
  2210. self.assertIs(self.cls(BASE, 'mysock\x00').is_socket(), False)
  2211. def test_is_block_device_false(self):
  2212. P = self.cls(BASE)
  2213. self.assertFalse((P / 'fileA').is_block_device())
  2214. self.assertFalse((P / 'dirA').is_block_device())
  2215. self.assertFalse((P / 'non-existing').is_block_device())
  2216. self.assertFalse((P / 'fileA' / 'bah').is_block_device())
  2217. self.assertIs((P / 'fileA\udfff').is_block_device(), False)
  2218. self.assertIs((P / 'fileA\x00').is_block_device(), False)
  2219. def test_is_char_device_false(self):
  2220. P = self.cls(BASE)
  2221. self.assertFalse((P / 'fileA').is_char_device())
  2222. self.assertFalse((P / 'dirA').is_char_device())
  2223. self.assertFalse((P / 'non-existing').is_char_device())
  2224. self.assertFalse((P / 'fileA' / 'bah').is_char_device())
  2225. self.assertIs((P / 'fileA\udfff').is_char_device(), False)
  2226. self.assertIs((P / 'fileA\x00').is_char_device(), False)
  2227. def test_is_char_device_true(self):
  2228. # Under Unix, /dev/null should generally be a char device.
  2229. P = self.cls('/dev/null')
  2230. if not P.exists():
  2231. self.skipTest("/dev/null required")
  2232. self.assertTrue(P.is_char_device())
  2233. self.assertFalse(P.is_block_device())
  2234. self.assertFalse(P.is_file())
  2235. self.assertIs(self.cls('/dev/null\udfff').is_char_device(), False)
  2236. self.assertIs(self.cls('/dev/null\x00').is_char_device(), False)
  2237. def test_pickling_common(self):
  2238. p = self.cls(BASE, 'fileA')
  2239. for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
  2240. dumped = pickle.dumps(p, proto)
  2241. pp = pickle.loads(dumped)
  2242. self.assertEqual(pp.stat(), p.stat())
  2243. def test_parts_interning(self):
  2244. P = self.cls
  2245. p = P('/usr/bin/foo')
  2246. q = P('/usr/local/bin')
  2247. # 'usr'
  2248. self.assertIs(p.parts[1], q.parts[1])
  2249. # 'bin'
  2250. self.assertIs(p.parts[2], q.parts[3])
  2251. def _check_complex_symlinks(self, link0_target):
  2252. # Test solving a non-looping chain of symlinks (issue #19887).
  2253. P = self.cls(BASE)
  2254. self.dirlink(os.path.join('link0', 'link0'), join('link1'))
  2255. self.dirlink(os.path.join('link1', 'link1'), join('link2'))
  2256. self.dirlink(os.path.join('link2', 'link2'), join('link3'))
  2257. self.dirlink(link0_target, join('link0'))
  2258. # Resolve absolute paths.
  2259. p = (P / 'link0').resolve()
  2260. self.assertEqual(p, P)
  2261. self.assertEqualNormCase(str(p), BASE)
  2262. p = (P / 'link1').resolve()
  2263. self.assertEqual(p, P)
  2264. self.assertEqualNormCase(str(p), BASE)
  2265. p = (P / 'link2').resolve()
  2266. self.assertEqual(p, P)
  2267. self.assertEqualNormCase(str(p), BASE)
  2268. p = (P / 'link3').resolve()
  2269. self.assertEqual(p, P)
  2270. self.assertEqualNormCase(str(p), BASE)
  2271. # Resolve relative paths.
  2272. old_path = os.getcwd()
  2273. os.chdir(BASE)
  2274. try:
  2275. p = self.cls('link0').resolve()
  2276. self.assertEqual(p, P)
  2277. self.assertEqualNormCase(str(p), BASE)
  2278. p = self.cls('link1').resolve()
  2279. self.assertEqual(p, P)
  2280. self.assertEqualNormCase(str(p), BASE)
  2281. p = self.cls('link2').resolve()
  2282. self.assertEqual(p, P)
  2283. self.assertEqualNormCase(str(p), BASE)
  2284. p = self.cls('link3').resolve()
  2285. self.assertEqual(p, P)
  2286. self.assertEqualNormCase(str(p), BASE)
  2287. finally:
  2288. os.chdir(old_path)
  2289. @os_helper.skip_unless_symlink
  2290. def test_complex_symlinks_absolute(self):
  2291. self._check_complex_symlinks(BASE)
  2292. @os_helper.skip_unless_symlink
  2293. def test_complex_symlinks_relative(self):
  2294. self._check_complex_symlinks('.')
  2295. @os_helper.skip_unless_symlink
  2296. def test_complex_symlinks_relative_dot_dot(self):
  2297. self._check_complex_symlinks(os.path.join('dirA', '..'))
  2298. class PathTest(_BasePathTest, unittest.TestCase):
  2299. cls = pathlib.Path
  2300. def test_concrete_class(self):
  2301. p = self.cls('a')
  2302. self.assertIs(type(p),
  2303. pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath)
  2304. def test_unsupported_flavour(self):
  2305. if os.name == 'nt':
  2306. self.assertRaises(NotImplementedError, pathlib.PosixPath)
  2307. else:
  2308. self.assertRaises(NotImplementedError, pathlib.WindowsPath)
  2309. def test_glob_empty_pattern(self):
  2310. p = self.cls()
  2311. with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'):
  2312. list(p.glob(''))
  2313. @only_posix
  2314. class PosixPathTest(_BasePathTest, unittest.TestCase):
  2315. cls = pathlib.PosixPath
  2316. def test_absolute(self):
  2317. P = self.cls
  2318. self.assertEqual(str(P('/').absolute()), '/')
  2319. self.assertEqual(str(P('/a').absolute()), '/a')
  2320. self.assertEqual(str(P('/a/b').absolute()), '/a/b')
  2321. # '//'-prefixed absolute path (supported by POSIX).
  2322. self.assertEqual(str(P('//').absolute()), '//')
  2323. self.assertEqual(str(P('//a').absolute()), '//a')
  2324. self.assertEqual(str(P('//a/b').absolute()), '//a/b')
  2325. def _check_symlink_loop(self, *args, strict=True):
  2326. path = self.cls(*args)
  2327. with self.assertRaises(RuntimeError):
  2328. print(path.resolve(strict))
  2329. @unittest.skipIf(
  2330. is_emscripten or is_wasi,
  2331. "umask is not implemented on Emscripten/WASI."
  2332. )
  2333. def test_open_mode(self):
  2334. old_mask = os.umask(0)
  2335. self.addCleanup(os.umask, old_mask)
  2336. p = self.cls(BASE)
  2337. with (p / 'new_file').open('wb'):
  2338. pass
  2339. st = os.stat(join('new_file'))
  2340. self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
  2341. os.umask(0o022)
  2342. with (p / 'other_new_file').open('wb'):
  2343. pass
  2344. st = os.stat(join('other_new_file'))
  2345. self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
  2346. def test_resolve_root(self):
  2347. current_directory = os.getcwd()
  2348. try:
  2349. os.chdir('/')
  2350. p = self.cls('spam')
  2351. self.assertEqual(str(p.resolve()), '/spam')
  2352. finally:
  2353. os.chdir(current_directory)
  2354. @unittest.skipIf(
  2355. is_emscripten or is_wasi,
  2356. "umask is not implemented on Emscripten/WASI."
  2357. )
  2358. def test_touch_mode(self):
  2359. old_mask = os.umask(0)
  2360. self.addCleanup(os.umask, old_mask)
  2361. p = self.cls(BASE)
  2362. (p / 'new_file').touch()
  2363. st = os.stat(join('new_file'))
  2364. self.assertEqual(stat.S_IMODE(st.st_mode), 0o666)
  2365. os.umask(0o022)
  2366. (p / 'other_new_file').touch()
  2367. st = os.stat(join('other_new_file'))
  2368. self.assertEqual(stat.S_IMODE(st.st_mode), 0o644)
  2369. (p / 'masked_new_file').touch(mode=0o750)
  2370. st = os.stat(join('masked_new_file'))
  2371. self.assertEqual(stat.S_IMODE(st.st_mode), 0o750)
  2372. @os_helper.skip_unless_symlink
  2373. def test_resolve_loop(self):
  2374. # Loops with relative symlinks.
  2375. os.symlink('linkX/inside', join('linkX'))
  2376. self._check_symlink_loop(BASE, 'linkX')
  2377. os.symlink('linkY', join('linkY'))
  2378. self._check_symlink_loop(BASE, 'linkY')
  2379. os.symlink('linkZ/../linkZ', join('linkZ'))
  2380. self._check_symlink_loop(BASE, 'linkZ')
  2381. # Non-strict
  2382. self._check_symlink_loop(BASE, 'linkZ', 'foo', strict=False)
  2383. # Loops with absolute symlinks.
  2384. os.symlink(join('linkU/inside'), join('linkU'))
  2385. self._check_symlink_loop(BASE, 'linkU')
  2386. os.symlink(join('linkV'), join('linkV'))
  2387. self._check_symlink_loop(BASE, 'linkV')
  2388. os.symlink(join('linkW/../linkW'), join('linkW'))
  2389. self._check_symlink_loop(BASE, 'linkW')
  2390. # Non-strict
  2391. self._check_symlink_loop(BASE, 'linkW', 'foo', strict=False)
  2392. def test_glob(self):
  2393. P = self.cls
  2394. p = P(BASE)
  2395. given = set(p.glob("FILEa"))
  2396. expect = set() if not os_helper.fs_is_case_insensitive(BASE) else given
  2397. self.assertEqual(given, expect)
  2398. self.assertEqual(set(p.glob("FILEa*")), set())
  2399. def test_rglob(self):
  2400. P = self.cls
  2401. p = P(BASE, "dirC")
  2402. given = set(p.rglob("FILEd"))
  2403. expect = set() if not os_helper.fs_is_case_insensitive(BASE) else given
  2404. self.assertEqual(given, expect)
  2405. self.assertEqual(set(p.rglob("FILEd*")), set())
  2406. @unittest.skipUnless(hasattr(pwd, 'getpwall'),
  2407. 'pwd module does not expose getpwall()')
  2408. @unittest.skipIf(sys.platform == "vxworks",
  2409. "no home directory on VxWorks")
  2410. def test_expanduser(self):
  2411. P = self.cls
  2412. import_helper.import_module('pwd')
  2413. import pwd
  2414. pwdent = pwd.getpwuid(os.getuid())
  2415. username = pwdent.pw_name
  2416. userhome = pwdent.pw_dir.rstrip('/') or '/'
  2417. # Find arbitrary different user (if exists).
  2418. for pwdent in pwd.getpwall():
  2419. othername = pwdent.pw_name
  2420. otherhome = pwdent.pw_dir.rstrip('/')
  2421. if othername != username and otherhome:
  2422. break
  2423. else:
  2424. othername = username
  2425. otherhome = userhome
  2426. fakename = 'fakeuser'
  2427. # This user can theoretically exist on a test runner. Create unique name:
  2428. try:
  2429. while pwd.getpwnam(fakename):
  2430. fakename += '1'
  2431. except KeyError:
  2432. pass # Non-existent name found
  2433. p1 = P('~/Documents')
  2434. p2 = P(f'~{username}/Documents')
  2435. p3 = P(f'~{othername}/Documents')
  2436. p4 = P(f'../~{username}/Documents')
  2437. p5 = P(f'/~{username}/Documents')
  2438. p6 = P('')
  2439. p7 = P(f'~{fakename}/Documents')
  2440. with os_helper.EnvironmentVarGuard() as env:
  2441. env.pop('HOME', None)
  2442. self.assertEqual(p1.expanduser(), P(userhome) / 'Documents')
  2443. self.assertEqual(p2.expanduser(), P(userhome) / 'Documents')
  2444. self.assertEqual(p3.expanduser(), P(otherhome) / 'Documents')
  2445. self.assertEqual(p4.expanduser(), p4)
  2446. self.assertEqual(p5.expanduser(), p5)
  2447. self.assertEqual(p6.expanduser(), p6)
  2448. self.assertRaises(RuntimeError, p7.expanduser)
  2449. env['HOME'] = '/tmp'
  2450. self.assertEqual(p1.expanduser(), P('/tmp/Documents'))
  2451. self.assertEqual(p2.expanduser(), P(userhome) / 'Documents')
  2452. self.assertEqual(p3.expanduser(), P(otherhome) / 'Documents')
  2453. self.assertEqual(p4.expanduser(), p4)
  2454. self.assertEqual(p5.expanduser(), p5)
  2455. self.assertEqual(p6.expanduser(), p6)
  2456. self.assertRaises(RuntimeError, p7.expanduser)
  2457. @unittest.skipIf(sys.platform != "darwin",
  2458. "Bad file descriptor in /dev/fd affects only macOS")
  2459. def test_handling_bad_descriptor(self):
  2460. try:
  2461. file_descriptors = list(pathlib.Path('/dev/fd').rglob("*"))[3:]
  2462. if not file_descriptors:
  2463. self.skipTest("no file descriptors - issue was not reproduced")
  2464. # Checking all file descriptors because there is no guarantee
  2465. # which one will fail.
  2466. for f in file_descriptors:
  2467. f.exists()
  2468. f.is_dir()
  2469. f.is_file()
  2470. f.is_symlink()
  2471. f.is_block_device()
  2472. f.is_char_device()
  2473. f.is_fifo()
  2474. f.is_socket()
  2475. except OSError as e:
  2476. if e.errno == errno.EBADF:
  2477. self.fail("Bad file descriptor not handled.")
  2478. raise
  2479. @only_nt
  2480. class WindowsPathTest(_BasePathTest, unittest.TestCase):
  2481. cls = pathlib.WindowsPath
  2482. def test_absolute(self):
  2483. P = self.cls
  2484. # Simple absolute paths.
  2485. self.assertEqual(str(P('c:\\').absolute()), 'c:\\')
  2486. self.assertEqual(str(P('c:\\a').absolute()), 'c:\\a')
  2487. self.assertEqual(str(P('c:\\a\\b').absolute()), 'c:\\a\\b')
  2488. # UNC absolute paths.
  2489. share = '\\\\server\\share\\'
  2490. self.assertEqual(str(P(share).absolute()), share)
  2491. self.assertEqual(str(P(share + 'a').absolute()), share + 'a')
  2492. self.assertEqual(str(P(share + 'a\\b').absolute()), share + 'a\\b')
  2493. # UNC relative paths.
  2494. with mock.patch("os.getcwd") as getcwd:
  2495. getcwd.return_value = share
  2496. self.assertEqual(str(P().absolute()), share)
  2497. self.assertEqual(str(P('.').absolute()), share)
  2498. self.assertEqual(str(P('a').absolute()), os.path.join(share, 'a'))
  2499. self.assertEqual(str(P('a', 'b', 'c').absolute()),
  2500. os.path.join(share, 'a', 'b', 'c'))
  2501. def test_glob(self):
  2502. P = self.cls
  2503. p = P(BASE)
  2504. self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") })
  2505. self.assertEqual(set(p.glob("*a\\")), { P(BASE, "dirA") })
  2506. self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") })
  2507. self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\FILEa"})
  2508. self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"})
  2509. def test_rglob(self):
  2510. P = self.cls
  2511. p = P(BASE, "dirC")
  2512. self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") })
  2513. self.assertEqual(set(p.rglob("*\\")), { P(BASE, "dirC/dirD") })
  2514. self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\FILEd"})
  2515. def test_expanduser(self):
  2516. P = self.cls
  2517. with os_helper.EnvironmentVarGuard() as env:
  2518. env.pop('HOME', None)
  2519. env.pop('USERPROFILE', None)
  2520. env.pop('HOMEPATH', None)
  2521. env.pop('HOMEDRIVE', None)
  2522. env['USERNAME'] = 'alice'
  2523. # test that the path returns unchanged
  2524. p1 = P('~/My Documents')
  2525. p2 = P('~alice/My Documents')
  2526. p3 = P('~bob/My Documents')
  2527. p4 = P('/~/My Documents')
  2528. p5 = P('d:~/My Documents')
  2529. p6 = P('')
  2530. self.assertRaises(RuntimeError, p1.expanduser)
  2531. self.assertRaises(RuntimeError, p2.expanduser)
  2532. self.assertRaises(RuntimeError, p3.expanduser)
  2533. self.assertEqual(p4.expanduser(), p4)
  2534. self.assertEqual(p5.expanduser(), p5)
  2535. self.assertEqual(p6.expanduser(), p6)
  2536. def check():
  2537. env.pop('USERNAME', None)
  2538. self.assertEqual(p1.expanduser(),
  2539. P('C:/Users/alice/My Documents'))
  2540. self.assertRaises(RuntimeError, p2.expanduser)
  2541. env['USERNAME'] = 'alice'
  2542. self.assertEqual(p2.expanduser(),
  2543. P('C:/Users/alice/My Documents'))
  2544. self.assertEqual(p3.expanduser(),
  2545. P('C:/Users/bob/My Documents'))
  2546. self.assertEqual(p4.expanduser(), p4)
  2547. self.assertEqual(p5.expanduser(), p5)
  2548. self.assertEqual(p6.expanduser(), p6)
  2549. env['HOMEPATH'] = 'C:\\Users\\alice'
  2550. check()
  2551. env['HOMEDRIVE'] = 'C:\\'
  2552. env['HOMEPATH'] = 'Users\\alice'
  2553. check()
  2554. env.pop('HOMEDRIVE', None)
  2555. env.pop('HOMEPATH', None)
  2556. env['USERPROFILE'] = 'C:\\Users\\alice'
  2557. check()
  2558. # bpo-38883: ignore `HOME` when set on windows
  2559. env['HOME'] = 'C:\\Users\\eve'
  2560. check()
  2561. class CompatiblePathTest(unittest.TestCase):
  2562. """
  2563. Test that a type can be made compatible with PurePath
  2564. derivatives by implementing division operator overloads.
  2565. """
  2566. class CompatPath:
  2567. """
  2568. Minimum viable class to test PurePath compatibility.
  2569. Simply uses the division operator to join a given
  2570. string and the string value of another object with
  2571. a forward slash.
  2572. """
  2573. def __init__(self, string):
  2574. self.string = string
  2575. def __truediv__(self, other):
  2576. return type(self)(f"{self.string}/{other}")
  2577. def __rtruediv__(self, other):
  2578. return type(self)(f"{other}/{self.string}")
  2579. def test_truediv(self):
  2580. result = pathlib.PurePath("test") / self.CompatPath("right")
  2581. self.assertIsInstance(result, self.CompatPath)
  2582. self.assertEqual(result.string, "test/right")
  2583. with self.assertRaises(TypeError):
  2584. # Verify improper operations still raise a TypeError
  2585. pathlib.PurePath("test") / 10
  2586. def test_rtruediv(self):
  2587. result = self.CompatPath("left") / pathlib.PurePath("test")
  2588. self.assertIsInstance(result, self.CompatPath)
  2589. self.assertEqual(result.string, "left/test")
  2590. with self.assertRaises(TypeError):
  2591. # Verify improper operations still raise a TypeError
  2592. 10 / pathlib.PurePath("test")
  2593. if __name__ == "__main__":
  2594. unittest.main()