@@ -275,93 +275,6 @@ def make_uri(self, path):
275
275
_posix_flavour = _PosixFlavour ()
276
276
277
277
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
-
365
278
#
366
279
# Globbing helpers
367
280
#
@@ -402,7 +315,7 @@ def select_from(self, parent_path):
402
315
path_cls = type (parent_path )
403
316
is_dir = path_cls .is_dir
404
317
exists = path_cls .exists
405
- scandir = parent_path . _accessor . scandir
318
+ scandir = path_cls . _scandir
406
319
if not is_dir (parent_path ):
407
320
return iter ([])
408
321
return self ._select_from (parent_path , is_dir , exists , scandir )
@@ -949,7 +862,6 @@ class Path(PurePath):
949
862
object. You can also instantiate a PosixPath or WindowsPath directly,
950
863
but cannot instantiate a WindowsPath on a POSIX system or vice versa.
951
864
"""
952
- _accessor = _normal_accessor
953
865
__slots__ = ()
954
866
955
867
def __new__ (cls , * args , ** kwargs ):
@@ -988,7 +900,7 @@ def cwd(cls):
988
900
"""Return a new path pointing to the current working directory
989
901
(as returned by os.getcwd()).
990
902
"""
991
- return cls (cls . _accessor .getcwd ())
903
+ return cls (os .getcwd ())
992
904
993
905
@classmethod
994
906
def home (cls ):
@@ -1005,16 +917,22 @@ def samefile(self, other_path):
1005
917
try :
1006
918
other_st = other_path .stat ()
1007
919
except AttributeError :
1008
- other_st = self ._accessor .stat (other_path )
920
+ other_st = self .__class__ ( other_path ) .stat ()
1009
921
return os .path .samestat (st , other_st )
1010
922
1011
923
def iterdir (self ):
1012
924
"""Iterate over the files in this directory. Does not yield any
1013
925
result for the special paths '.' and '..'.
1014
926
"""
1015
- for name in self . _accessor .listdir (self ):
927
+ for name in os .listdir (self ):
1016
928
yield self ._make_child_relpath (name )
1017
929
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
+
1018
936
def glob (self , pattern ):
1019
937
"""Iterate over this subtree and yield all existing files (of any
1020
938
kind, including directories) matching the given relative pattern.
@@ -1050,7 +968,7 @@ def absolute(self):
1050
968
"""
1051
969
if self .is_absolute ():
1052
970
return self
1053
- return self ._from_parts ([self ._accessor . getcwd ()] + self ._parts )
971
+ return self ._from_parts ([self .cwd ()] + self ._parts )
1054
972
1055
973
def resolve (self , strict = False ):
1056
974
"""
@@ -1064,7 +982,7 @@ def check_eloop(e):
1064
982
raise RuntimeError ("Symlink loop from %r" % e .filename )
1065
983
1066
984
try :
1067
- s = self . _accessor .realpath (self , strict = strict )
985
+ s = os . path .realpath (self , strict = strict )
1068
986
except OSError as e :
1069
987
check_eloop (e )
1070
988
raise
@@ -1084,19 +1002,28 @@ def stat(self, *, follow_symlinks=True):
1084
1002
Return the result of the stat() system call on this path, like
1085
1003
os.stat() does.
1086
1004
"""
1087
- return self . _accessor .stat (self , follow_symlinks = follow_symlinks )
1005
+ return os .stat (self , follow_symlinks = follow_symlinks )
1088
1006
1089
1007
def owner (self ):
1090
1008
"""
1091
1009
Return the login name of the file owner.
1092
1010
"""
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" )
1094
1016
1095
1017
def group (self ):
1096
1018
"""
1097
1019
Return the group name of the file gid.
1098
1020
"""
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" )
1100
1027
1101
1028
def open (self , mode = 'r' , buffering = - 1 , encoding = None ,
1102
1029
errors = None , newline = None ):
@@ -1106,8 +1033,7 @@ def open(self, mode='r', buffering=-1, encoding=None,
1106
1033
"""
1107
1034
if "b" not in mode :
1108
1035
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 )
1111
1037
1112
1038
def read_bytes (self ):
1113
1039
"""
@@ -1148,21 +1074,38 @@ def readlink(self):
1148
1074
"""
1149
1075
Return the path to which the symbolic link points.
1150
1076
"""
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 ),))
1153
1080
1154
1081
def touch (self , mode = 0o666 , exist_ok = True ):
1155
1082
"""
1156
1083
Create this file with the given access mode, if it doesn't exist.
1157
1084
"""
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 )
1159
1102
1160
1103
def mkdir (self , mode = 0o777 , parents = False , exist_ok = False ):
1161
1104
"""
1162
1105
Create a new directory at this given path.
1163
1106
"""
1164
1107
try :
1165
- self . _accessor .mkdir (self , mode )
1108
+ os .mkdir (self , mode )
1166
1109
except FileNotFoundError :
1167
1110
if not parents or self .parent == self :
1168
1111
raise
@@ -1178,7 +1121,7 @@ def chmod(self, mode, *, follow_symlinks=True):
1178
1121
"""
1179
1122
Change the permissions of the path, like os.chmod().
1180
1123
"""
1181
- self . _accessor .chmod (self , mode , follow_symlinks = follow_symlinks )
1124
+ os .chmod (self , mode , follow_symlinks = follow_symlinks )
1182
1125
1183
1126
def lchmod (self , mode ):
1184
1127
"""
@@ -1193,7 +1136,7 @@ def unlink(self, missing_ok=False):
1193
1136
If the path is a directory, use rmdir() instead.
1194
1137
"""
1195
1138
try :
1196
- self . _accessor .unlink (self )
1139
+ os .unlink (self )
1197
1140
except FileNotFoundError :
1198
1141
if not missing_ok :
1199
1142
raise
@@ -1202,7 +1145,7 @@ def rmdir(self):
1202
1145
"""
1203
1146
Remove this directory. The directory must be empty.
1204
1147
"""
1205
- self . _accessor .rmdir (self )
1148
+ os .rmdir (self )
1206
1149
1207
1150
def lstat (self ):
1208
1151
"""
@@ -1221,7 +1164,7 @@ def rename(self, target):
1221
1164
1222
1165
Returns the new Path instance pointing to the target path.
1223
1166
"""
1224
- self . _accessor .rename (self , target )
1167
+ os .rename (self , target )
1225
1168
return self .__class__ (target )
1226
1169
1227
1170
def replace (self , target ):
@@ -1234,23 +1177,27 @@ def replace(self, target):
1234
1177
1235
1178
Returns the new Path instance pointing to the target path.
1236
1179
"""
1237
- self . _accessor .replace (self , target )
1180
+ os .replace (self , target )
1238
1181
return self .__class__ (target )
1239
1182
1240
1183
def symlink_to (self , target , target_is_directory = False ):
1241
1184
"""
1242
1185
Make this path a symlink pointing to the target path.
1243
1186
Note the order of arguments (link, target) is the reverse of os.symlink.
1244
1187
"""
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 )
1246
1191
1247
1192
def hardlink_to (self , target ):
1248
1193
"""
1249
1194
Make this path a hard link pointing to the same file as *target*.
1250
1195
1251
1196
Note the order of arguments (self, target) is the reverse of os.link's.
1252
1197
"""
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 )
1254
1201
1255
1202
def link_to (self , target ):
1256
1203
"""
@@ -1268,7 +1215,7 @@ def link_to(self, target):
1268
1215
"for removal in Python 3.12. "
1269
1216
"Use pathlib.Path.hardlink_to() instead." ,
1270
1217
DeprecationWarning , stacklevel = 2 )
1271
- self ._accessor . link (self , target )
1218
+ self .__class__ ( target ). hardlink_to (self )
1272
1219
1273
1220
# Convenience functions for querying the stat results
1274
1221
@@ -1425,7 +1372,7 @@ def expanduser(self):
1425
1372
"""
1426
1373
if (not (self ._drv or self ._root ) and
1427
1374
self ._parts and self ._parts [0 ][:1 ] == '~' ):
1428
- homedir = self . _accessor .expanduser (self ._parts [0 ])
1375
+ homedir = os . path .expanduser (self ._parts [0 ])
1429
1376
if homedir [:1 ] == "~" :
1430
1377
raise RuntimeError ("Could not determine home directory." )
1431
1378
return self ._from_parts ([homedir ] + self ._parts [1 :])
0 commit comments