@@ -275,93 +275,6 @@ def make_uri(self, path):
275275_posix_flavour = _PosixFlavour ()
276276
277277
278- class _Accessor :
279- """An accessor implements a particular (system-specific or not) way of
280- accessing paths on the filesystem."""
281-
282-
283- class _NormalAccessor (_Accessor ):
284-
285- stat = os .stat
286-
287- open = io .open
288-
289- listdir = os .listdir
290-
291- scandir = os .scandir
292-
293- chmod = os .chmod
294-
295- mkdir = os .mkdir
296-
297- unlink = os .unlink
298-
299- if hasattr (os , "link" ):
300- link = os .link
301- else :
302- def link (self , src , dst ):
303- raise NotImplementedError ("os.link() not available on this system" )
304-
305- rmdir = os .rmdir
306-
307- rename = os .rename
308-
309- replace = os .replace
310-
311- if hasattr (os , "symlink" ):
312- symlink = os .symlink
313- else :
314- def symlink (self , src , dst , target_is_directory = False ):
315- raise NotImplementedError ("os.symlink() not available on this system" )
316-
317- def touch (self , path , mode = 0o666 , exist_ok = True ):
318- if exist_ok :
319- # First try to bump modification time
320- # Implementation note: GNU touch uses the UTIME_NOW option of
321- # the utimensat() / futimens() functions.
322- try :
323- os .utime (path , None )
324- except OSError :
325- # Avoid exception chaining
326- pass
327- else :
328- return
329- flags = os .O_CREAT | os .O_WRONLY
330- if not exist_ok :
331- flags |= os .O_EXCL
332- fd = os .open (path , flags , mode )
333- os .close (fd )
334-
335- if hasattr (os , "readlink" ):
336- readlink = os .readlink
337- else :
338- def readlink (self , path ):
339- raise NotImplementedError ("os.readlink() not available on this system" )
340-
341- def owner (self , path ):
342- try :
343- import pwd
344- return pwd .getpwuid (self .stat (path ).st_uid ).pw_name
345- except ImportError :
346- raise NotImplementedError ("Path.owner() is unsupported on this system" )
347-
348- def group (self , path ):
349- try :
350- import grp
351- return grp .getgrgid (self .stat (path ).st_gid ).gr_name
352- except ImportError :
353- raise NotImplementedError ("Path.group() is unsupported on this system" )
354-
355- getcwd = os .getcwd
356-
357- expanduser = staticmethod (os .path .expanduser )
358-
359- realpath = staticmethod (os .path .realpath )
360-
361-
362- _normal_accessor = _NormalAccessor ()
363-
364-
365278#
366279# Globbing helpers
367280#
@@ -402,7 +315,7 @@ def select_from(self, parent_path):
402315 path_cls = type (parent_path )
403316 is_dir = path_cls .is_dir
404317 exists = path_cls .exists
405- scandir = parent_path . _accessor . scandir
318+ scandir = path_cls . _scandir
406319 if not is_dir (parent_path ):
407320 return iter ([])
408321 return self ._select_from (parent_path , is_dir , exists , scandir )
@@ -949,7 +862,6 @@ class Path(PurePath):
949862 object. You can also instantiate a PosixPath or WindowsPath directly,
950863 but cannot instantiate a WindowsPath on a POSIX system or vice versa.
951864 """
952- _accessor = _normal_accessor
953865 __slots__ = ()
954866
955867 def __new__ (cls , * args , ** kwargs ):
@@ -988,7 +900,7 @@ def cwd(cls):
988900 """Return a new path pointing to the current working directory
989901 (as returned by os.getcwd()).
990902 """
991- return cls (cls . _accessor .getcwd ())
903+ return cls (os .getcwd ())
992904
993905 @classmethod
994906 def home (cls ):
@@ -1005,16 +917,22 @@ def samefile(self, other_path):
1005917 try :
1006918 other_st = other_path .stat ()
1007919 except AttributeError :
1008- other_st = self ._accessor .stat (other_path )
920+ other_st = self .__class__ ( other_path ) .stat ()
1009921 return os .path .samestat (st , other_st )
1010922
1011923 def iterdir (self ):
1012924 """Iterate over the files in this directory. Does not yield any
1013925 result for the special paths '.' and '..'.
1014926 """
1015- for name in self . _accessor .listdir (self ):
927+ for name in os .listdir (self ):
1016928 yield self ._make_child_relpath (name )
1017929
930+ def _scandir (self ):
931+ # bpo-24132: a future version of pathlib will support subclassing of
932+ # pathlib.Path to customize how the filesystem is accessed. This
933+ # includes scandir(), which is used to implement glob().
934+ return os .scandir (self )
935+
1018936 def glob (self , pattern ):
1019937 """Iterate over this subtree and yield all existing files (of any
1020938 kind, including directories) matching the given relative pattern.
@@ -1050,7 +968,7 @@ def absolute(self):
1050968 """
1051969 if self .is_absolute ():
1052970 return self
1053- return self ._from_parts ([self ._accessor . getcwd ()] + self ._parts )
971+ return self ._from_parts ([self .cwd ()] + self ._parts )
1054972
1055973 def resolve (self , strict = False ):
1056974 """
@@ -1064,7 +982,7 @@ def check_eloop(e):
1064982 raise RuntimeError ("Symlink loop from %r" % e .filename )
1065983
1066984 try :
1067- s = self . _accessor .realpath (self , strict = strict )
985+ s = os . path .realpath (self , strict = strict )
1068986 except OSError as e :
1069987 check_eloop (e )
1070988 raise
@@ -1084,19 +1002,28 @@ def stat(self, *, follow_symlinks=True):
10841002 Return the result of the stat() system call on this path, like
10851003 os.stat() does.
10861004 """
1087- return self . _accessor .stat (self , follow_symlinks = follow_symlinks )
1005+ return os .stat (self , follow_symlinks = follow_symlinks )
10881006
10891007 def owner (self ):
10901008 """
10911009 Return the login name of the file owner.
10921010 """
1093- return self ._accessor .owner (self )
1011+ try :
1012+ import pwd
1013+ return pwd .getpwuid (self .stat ().st_uid ).pw_name
1014+ except ImportError :
1015+ raise NotImplementedError ("Path.owner() is unsupported on this system" )
10941016
10951017 def group (self ):
10961018 """
10971019 Return the group name of the file gid.
10981020 """
1099- return self ._accessor .group (self )
1021+
1022+ try :
1023+ import grp
1024+ return grp .getgrgid (self .stat ().st_gid ).gr_name
1025+ except ImportError :
1026+ raise NotImplementedError ("Path.group() is unsupported on this system" )
11001027
11011028 def open (self , mode = 'r' , buffering = - 1 , encoding = None ,
11021029 errors = None , newline = None ):
@@ -1106,8 +1033,7 @@ def open(self, mode='r', buffering=-1, encoding=None,
11061033 """
11071034 if "b" not in mode :
11081035 encoding = io .text_encoding (encoding )
1109- return self ._accessor .open (self , mode , buffering , encoding , errors ,
1110- newline )
1036+ return io .open (self , mode , buffering , encoding , errors , newline )
11111037
11121038 def read_bytes (self ):
11131039 """
@@ -1148,21 +1074,38 @@ def readlink(self):
11481074 """
11491075 Return the path to which the symbolic link points.
11501076 """
1151- path = self ._accessor .readlink (self )
1152- return self ._from_parts ((path ,))
1077+ if not hasattr (os , "readlink" ):
1078+ raise NotImplementedError ("os.readlink() not available on this system" )
1079+ return self ._from_parts ((os .readlink (self ),))
11531080
11541081 def touch (self , mode = 0o666 , exist_ok = True ):
11551082 """
11561083 Create this file with the given access mode, if it doesn't exist.
11571084 """
1158- self ._accessor .touch (self , mode , exist_ok )
1085+
1086+ if exist_ok :
1087+ # First try to bump modification time
1088+ # Implementation note: GNU touch uses the UTIME_NOW option of
1089+ # the utimensat() / futimens() functions.
1090+ try :
1091+ os .utime (self , None )
1092+ except OSError :
1093+ # Avoid exception chaining
1094+ pass
1095+ else :
1096+ return
1097+ flags = os .O_CREAT | os .O_WRONLY
1098+ if not exist_ok :
1099+ flags |= os .O_EXCL
1100+ fd = os .open (self , flags , mode )
1101+ os .close (fd )
11591102
11601103 def mkdir (self , mode = 0o777 , parents = False , exist_ok = False ):
11611104 """
11621105 Create a new directory at this given path.
11631106 """
11641107 try :
1165- self . _accessor .mkdir (self , mode )
1108+ os .mkdir (self , mode )
11661109 except FileNotFoundError :
11671110 if not parents or self .parent == self :
11681111 raise
@@ -1178,7 +1121,7 @@ def chmod(self, mode, *, follow_symlinks=True):
11781121 """
11791122 Change the permissions of the path, like os.chmod().
11801123 """
1181- self . _accessor .chmod (self , mode , follow_symlinks = follow_symlinks )
1124+ os .chmod (self , mode , follow_symlinks = follow_symlinks )
11821125
11831126 def lchmod (self , mode ):
11841127 """
@@ -1193,7 +1136,7 @@ def unlink(self, missing_ok=False):
11931136 If the path is a directory, use rmdir() instead.
11941137 """
11951138 try :
1196- self . _accessor .unlink (self )
1139+ os .unlink (self )
11971140 except FileNotFoundError :
11981141 if not missing_ok :
11991142 raise
@@ -1202,7 +1145,7 @@ def rmdir(self):
12021145 """
12031146 Remove this directory. The directory must be empty.
12041147 """
1205- self . _accessor .rmdir (self )
1148+ os .rmdir (self )
12061149
12071150 def lstat (self ):
12081151 """
@@ -1221,7 +1164,7 @@ def rename(self, target):
12211164
12221165 Returns the new Path instance pointing to the target path.
12231166 """
1224- self . _accessor .rename (self , target )
1167+ os .rename (self , target )
12251168 return self .__class__ (target )
12261169
12271170 def replace (self , target ):
@@ -1234,23 +1177,27 @@ def replace(self, target):
12341177
12351178 Returns the new Path instance pointing to the target path.
12361179 """
1237- self . _accessor .replace (self , target )
1180+ os .replace (self , target )
12381181 return self .__class__ (target )
12391182
12401183 def symlink_to (self , target , target_is_directory = False ):
12411184 """
12421185 Make this path a symlink pointing to the target path.
12431186 Note the order of arguments (link, target) is the reverse of os.symlink.
12441187 """
1245- self ._accessor .symlink (target , self , target_is_directory )
1188+ if not hasattr (os , "symlink" ):
1189+ raise NotImplementedError ("os.symlink() not available on this system" )
1190+ os .symlink (target , self , target_is_directory )
12461191
12471192 def hardlink_to (self , target ):
12481193 """
12491194 Make this path a hard link pointing to the same file as *target*.
12501195
12511196 Note the order of arguments (self, target) is the reverse of os.link's.
12521197 """
1253- self ._accessor .link (target , self )
1198+ if not hasattr (os , "link" ):
1199+ raise NotImplementedError ("os.link() not available on this system" )
1200+ os .link (target , self )
12541201
12551202 def link_to (self , target ):
12561203 """
@@ -1268,7 +1215,7 @@ def link_to(self, target):
12681215 "for removal in Python 3.12. "
12691216 "Use pathlib.Path.hardlink_to() instead." ,
12701217 DeprecationWarning , stacklevel = 2 )
1271- self ._accessor . link (self , target )
1218+ self .__class__ ( target ). hardlink_to (self )
12721219
12731220 # Convenience functions for querying the stat results
12741221
@@ -1425,7 +1372,7 @@ def expanduser(self):
14251372 """
14261373 if (not (self ._drv or self ._root ) and
14271374 self ._parts and self ._parts [0 ][:1 ] == '~' ):
1428- homedir = self . _accessor .expanduser (self ._parts [0 ])
1375+ homedir = os . path .expanduser (self ._parts [0 ])
14291376 if homedir [:1 ] == "~" :
14301377 raise RuntimeError ("Could not determine home directory." )
14311378 return self ._from_parts ([homedir ] + self ._parts [1 :])
0 commit comments