1 r"""OS routines for NT or Posix depending on what system we're on.2 #NT或Posix的操作系统例程取决于我们所使用的系统。3 This exports:4 - all functions from posix or nt, e.g. unlink, stat, etc.5 #posix或nt的所有功能,例如unlink、stat等。6 - os.path is either posixpath or ntpath7 #操作系统。路径是posixpath或ntpath8 - os.name is either 'posix' or 'nt'9 #os.name要么是posix,要么是nt10 - os.curdir is a string representing the current directory (always '.')11 #os.curdir是一个字符串,表示当前目录(总是'.')。12 - os.pardir is a string representing the parent directory (always '..')13 #os.pardir是一个字符串,表示父目录(总是'..')14 - os.sep is the (or a most common) pathname separator ('/' or '\\')15 #os.sep是(或最常见的)路径名分隔符('/'或'\\')16 - os.extsep is the extension separator (always '.')17 #os.extsep是扩展分隔符(总是'.')。18 - os.altsep is the alternate pathname separator (None or '/')19 #os.altsep是替代路径名分隔符(None或'/')20 - os.pathsep is the component separator used in $PATH etc21 #os.pathsep是用于$PATH等的组件分隔符22 - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')23 #os.linesep是文本文件中的行分隔符('\r'或'\n'或'\r\n')24 - os.defpath is the default search path for executables25 #os.defpath是可执行文件的默认搜索路径26 - os.devnull is the file path of the null device ('/dev/null', etc.)27 #os.devnull是空设备('/dev/null'等)的文件路径28 Programs that import and use 'os' stand a better chance of being29 portable between different platforms. Of course, they must then30 only use functions that are defined by all platforms (e.g., unlink31 and opendir), and leave all pathname manipulation to os.path32 (e.g., split and join).33 #导入和使用“os”的程序更有可能存在在不同平台之间可移植。当然,他们必须这样做只使用34 所有平台定义的函数(例如,unlink),并将所有路径名操作留给操作系统.path(例如,分开并加入)。35 """
36
37 #'
38 importabc39 importsys40 importstat as st41
42 _names =sys.builtin_module_names43
44 #Note: more names are added to __all__ later.
45 __all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep",46 "defpath", "name", "path", "devnull", "SEEK_SET", "SEEK_CUR",47 "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen",48 "popen", "extsep"]49
50 def_exists(name):51 return name inglobals()52
53 def_get_exports_list(module):54 try:55 return list(module.__all__)56 exceptAttributeError:57 return [n for n in dir(module) if n[0] != '_']58
59 #Any new dependencies of the os module and/or changes in path separator
60 #requires updating importlib as well.
61 if 'posix' in_names:62 name = 'posix'
63 linesep = '\n'
64 from posix import *
65 try:66 from posix import_exit67 __all__.append('_exit')68 exceptImportError:69 pass
70 importposixpath as path71
72 try:73 from posix import_have_functions74 exceptImportError:75 pass
76
77 importposix78 __all__.extend(_get_exports_list(posix))79 delposix80
81 elif 'nt' in_names:82 name = 'nt'
83 linesep = '\r\n'
84 from nt import *
85 try:86 from nt import_exit87 __all__.append('_exit')88 exceptImportError:89 pass
90 importntpath as path91
92 importnt93 __all__.extend(_get_exports_list(nt))94 delnt95
96 try:97 from nt import_have_functions98 exceptImportError:99 pass
100
101 else:102 raise ImportError('no os specific module found')103
104 sys.modules['os.path'] =path105 from os.path import(curdir, pardir, sep, pathsep, defpath, extsep, altsep,106 devnull)107
108 del_names109
110
111 if _exists("_have_functions"):112 _globals =globals()113 def_add(str, fn):114 if (fn in _globals) and (str in_have_functions):115 _set.add(_globals[fn])116
117 _set =set()118 _add("HAVE_FACCESSAT", "access")119 _add("HAVE_FCHMODAT", "chmod")120 _add("HAVE_FCHOWNAT", "chown")121 _add("HAVE_FSTATAT", "stat")122 _add("HAVE_FUTIMESAT", "utime")123 _add("HAVE_LINKAT", "link")124 _add("HAVE_MKDIRAT", "mkdir")125 _add("HAVE_MKFIFOAT", "mkfifo")126 _add("HAVE_MKNODAT", "mknod")127 _add("HAVE_OPENAT", "open")128 _add("HAVE_READLINKAT", "readlink")129 _add("HAVE_RENAMEAT", "rename")130 _add("HAVE_SYMLINKAT", "symlink")131 _add("HAVE_UNLINKAT", "unlink")132 _add("HAVE_UNLINKAT", "rmdir")133 _add("HAVE_UTIMENSAT", "utime")134 supports_dir_fd =_set135
136 _set =set()137 _add("HAVE_FACCESSAT", "access")138 supports_effective_ids =_set139
140 _set =set()141 _add("HAVE_FCHDIR", "chdir")142 _add("HAVE_FCHMOD", "chmod")143 _add("HAVE_FCHOWN", "chown")144 _add("HAVE_FDOPENDIR", "listdir")145 _add("HAVE_FDOPENDIR", "scandir")146 _add("HAVE_FEXECVE", "execve")147 _set.add(stat) #fstat always works
148 _add("HAVE_FTRUNCATE", "truncate")149 _add("HAVE_FUTIMENS", "utime")150 _add("HAVE_FUTIMES", "utime")151 _add("HAVE_FPATHCONF", "pathconf")152 if _exists("statvfs") and _exists("fstatvfs"): #mac os x10.3
153 _add("HAVE_FSTATVFS", "statvfs")154 supports_fd =_set155
156 _set =set()157 _add("HAVE_FACCESSAT", "access")158 #Some platforms don't support lchmod(). Often the function exists
159 #anyway, as a stub that always returns ENOSUP or perhaps EOPNOTSUPP.
160 #(No, I don't know why that's a good design.) ./configure will detect
161 #this and reject it--so HAVE_LCHMOD still won't be defined on such
162 #platforms. This is Very Helpful.
163 #164 #However, sometimes platforms without a working lchmod() *do* have
165 #fchmodat(). (Examples: Linux kernel 3.2 with glibc 2.15,
166 #OpenIndiana 3.x.) And fchmodat() has a flag that theoretically makes
167 #it behave like lchmod(). So in theory it would be a suitable
168 #replacement for lchmod(). But when lchmod() doesn't work, fchmodat()'s
169 #flag doesn't work *either*. Sadly ./configure isn't sophisticated
170 #enough to detect this condition--it only determines whether or not
171 #fchmodat() minimally works.
172 #173 #Therefore we simply ignore fchmodat() when deciding whether or not
174 #os.chmod supports follow_symlinks. Just checking lchmod() is
175 #sufficient. After all--if you have a working fchmodat(), your
176 #lchmod() almost certainly works too.
177 #178 #_add("HAVE_FCHMODAT", "chmod")
179 _add("HAVE_FCHOWNAT", "chown")180 _add("HAVE_FSTATAT", "stat")181 _add("HAVE_LCHFLAGS", "chflags")182 _add("HAVE_LCHMOD", "chmod")183 if _exists("lchown"): #mac os x10.3
184 _add("HAVE_LCHOWN", "chown")185 _add("HAVE_LINKAT", "link")186 _add("HAVE_LUTIMES", "utime")187 _add("HAVE_LSTAT", "stat")188 _add("HAVE_FSTATAT", "stat")189 _add("HAVE_UTIMENSAT", "utime")190 _add("MS_WINDOWS", "stat")191 supports_follow_symlinks =_set192
193 del_set194 del_have_functions195 del_globals196 del_add197
198
199 #Python uses fixed values for the SEEK_ constants; they are mapped
200 #to native constants if necessary in posixmodule.c
201 #Other possible SEEK values are directly imported from posixmodule.c
202 SEEK_SET =0203 SEEK_CUR = 1
204 SEEK_END = 2
205
206 #Super directory utilities.
207 #(Inspired by Eric Raymond; the doc strings are mostly his)
208
209 def makedirs(name, mode=0o777, exist_ok=False):210 """makedirs(name [, mode=0o777][, exist_ok=False])211
212 Super-mkdir; create a leaf directory and all intermediate ones. Works like213 mkdir, except that any intermediate path segment (not just the rightmost)214 will be created if it does not exist. If the target directory already215 exists, raise an OSError if exist_ok is False. Otherwise no exception is216 raised. This is recursive.217 """
218 #makedirs(名称[,mode=0o777]][, exist_ok=False])Super-mkdir;
219 #创建一个叶子目录和所有中间目录。就像mkdir,除了任何中间路径段(不仅仅是最右边)
220 #将创建如果它不存在。如果目标目录已经存在,如果exist_ok为假,
221 #就启动一个OSError。否则没有例外提高。这是递归的。
222 head, tail =path.split(name)223 if nottail:224 head, tail =path.split(head)225 if head and tail and notpath.exists(head):226 try:227 makedirs(head, exist_ok=exist_ok)228 exceptFileExistsError:229 #Defeats race condition when another thread created the path
230 #在另一个线程创建路径时击败竞争条件
231 pass
232 cdir =curdir233 ifisinstance(tail, bytes):234 cdir = bytes(curdir, 'ASCII')235 if tail == cdir: #xxx/newdir/. exists if xxx/newdir exists
236 return
237 try:238 mkdir(name, mode)239 exceptOSError:240 #Cannot rely on checking for EEXIST, since the operating system
241 #could give priority to other errors like EACCES or EROFS
242 #不能依赖检查EEXIST,因为操作系统优先考虑其他错误,比如EACCES或EROFS
243 if not exist_ok or notpath.isdir(name):244 raise
245
246 defremovedirs(name):247 """removedirs(name)248
249 Super-rmdir; remove a leaf directory and all empty intermediate250 ones. Works like rmdir except that, if the leaf directory is251 successfully removed, directories corresponding to rightmost path252 segments will be pruned away until either the whole path is253 consumed or an error occurs. Errors during this latter phase are254 ignored -- they generally mean that a directory was not empty.255 """
256 #removedirs(名字)Super-rmdir;删除一个叶子目录和所有空的中间的人。与rmdir类似,
257 #但叶目录除外成功删除,对应于最右边路径的目录部分将被修剪掉,直到整个路径使用或
258 #发生错误。后一阶段的错误是忽略——它们通常意味着目录不是空的。
259 rmdir(name)260 head, tail =path.split(name)261 if nottail:262 head, tail =path.split(head)263 while head andtail:264 try:265 rmdir(head)266 exceptOSError:267 break
268 head, tail =path.split(head)269
270 defrenames(old, new):271 """renames(old, new)272
273 Super-rename; create directories as necessary and delete any left274 empty. Works like rename, except creation of any intermediate275 directories needed to make the new pathname good is attempted276 first. After the rename, directories corresponding to rightmost277 path segments of the old name will be pruned until either the278 whole path is consumed or a nonempty directory is found.279
280 Note: this function can fail with the new directory structure made281 if you lack permissions needed to unlink the leaf directory or282 file.283 """
284 #重命名(旧的,新的)Super-rename;根据需要创建目录并删除所有剩余的空目录。类似于
285 #rename的工作,但是首先尝试创建任何使新路径名良好所需的中间目录。在重命名之后,
286 #对应于旧名称最右边路径段的目录将被删除,直到使用整个路径或找到一个非空目录为止。
287 #注意:如果您缺少解除叶子目录或文件链接所需的权限,那么这个函数可能会失败。
288
289 head, tail =path.split(new)290 if head and tail and notpath.exists(head):291 makedirs(head)292 rename(old, new)293 head, tail =path.split(old)294 if head andtail:295 try:296 removedirs(head)297 exceptOSError:298 pass
299
300 __all__.extend(["makedirs", "removedirs", "renames"])301
302 def walk(top, topdown=True, οnerrοr=None, followlinks=False):303 """Directory tree generator.304
305 For each directory in the directory tree rooted at top (including top306 itself, but excluding '.' and '..'), yields a 3-tuple307
308 dirpath, dirnames, filenames309
310 dirpath is a string, the path to the directory. dirnames is a list of311 the names of the subdirectories in dirpath (excluding '.' and '..').312 filenames is a list of the names of the non-directory files in dirpath.313 Note that the names in the lists are just names, with no path components.314 To get a full path (which begins with top) to a file or directory in315 dirpath, do os.path.join(dirpath, name).316
317 If optional arg 'topdown' is true or not specified, the triple for a318 directory is generated before the triples for any of its subdirectories319 (directories are generated top down). If topdown is false, the triple320 for a directory is generated after the triples for all of its321 subdirectories (directories are generated bottom up).322
323 When topdown is true, the caller can modify the dirnames list in-place324 (e.g., via del or slice assignment), and walk will only recurse into the325 subdirectories whose names remain in dirnames; this can be used to prune the326 search, or to impose a specific order of visiting. Modifying dirnames when327 topdown is false is ineffective, since the directories in dirnames have328 already been generated by the time dirnames itself is generated. No matter329 the value of topdown, the list of subdirectories is retrieved before the330 tuples for the directory and its subdirectories are generated.331
332 By default errors from the os.scandir() call are ignored. If333 optional arg 'onerror' is specified, it should be a function; it334 will be called with one argument, an OSError instance. It can335 report the error to continue with the walk, or raise the exception336 to abort the walk. Note that the filename is available as the337 filename attribute of the exception object.338
339 By default, os.walk does not follow symbolic links to subdirectories on340 systems that support them. In order to get this functionality, set the341 optional argument 'followlinks' to true.342
343 Caution: if you pass a relative pathname for top, don't change the344 current working directory between resumptions of walk. walk never345 changes the current directory, and assumes that the client doesn't346 either.347
348 Example:349
350 import os351 from os.path import join, getsize352 for root, dirs, files in os.walk('python/Lib/email'):353 print(root, "consumes", end="")354 print(sum([getsize(join(root, name)) for name in files]), end="")355 print("bytes in", len(files), "non-directory files")356 if 'CVS' in dirs:357 dirs.remove('CVS') # don't visit CVS directories358 """
359 #目录树生成器。对于根在顶部的目录树中的每个目录(包括顶部本身,但不包括')。,
360 #生成一个3元组dirpath, dirnames, filenames dirpath是一个字符串,目录路径。
361 #dirnames是dirpath(不包括')中子目录的名称列表。”和“…”)。filenames文件名是
362 #dirpath中非目录文件的名称列表。注意,列表中的名称只是名称,没有路径组件。
363 #要获得指向dirpath文件或目录的完整路径(从顶部开始),请使用os.path。加入
364 #(dirpath、名称)。如果可选的arg '自顶向下'为真或未指定,则目录的三元组在其任何
365 #子目录的三元组之前生成(目录自顶向下生成)。如果自顶向下为false,目录的三元组将
366 #在所有子目录的三元组之后生成(从下往上生成目录)。当topdown为真时,调用者可以就
367 #地修改dirnames列表(例如,通过del或slice赋值),walk只会递归到名称仍然为
368 #dirnames的子目录中;这可以用于删除搜索,或强制执行特定的访问顺序。当自顶向下为
369 #false时修改dirnames是无效的,因为在生成dirnames本身时,dirnames中的目录已经
370 #生成了。无论自顶向下的值是多少,子目录列表都会在生成目录及其子目录的元组之前被
371 #检索。默认情况下,os.scandir()调用的错误将被忽略。如果指定了可选的arg
372 #'onerror',它应该是一个函数;它将使用一个参数调用,一个OSError实例。它可以报
373 #告错误以继续遍历,或者引发异常以中止遍历。注意,文件名作为异常对象的filename
374 #属性可用。默认情况下,操作系统。walk不会跟随支持它的系统上子目录的符号链接。
375 #为了获得这个功能,将可选参数“followlinks”设置为true。注意:如果您为top传递了
376 #一个相对路径名,那么不要在walk的恢复之间更改当前的工作目录。walk从不更改当前
377 #目录,并且假设客户机也不更改。
378
379 top =fspath(top)380 dirs =[]381 nondirs =[]382 walk_dirs =[]383
384 #We may not have read permission for top, in which case we can't
385 #get a list of the files the directory contains. os.walk
386 #always suppressed the exception then, rather than blow up for a
387 #minor reason when (say) a thousand readable directories are still
388 #left to visit. That logic is copied here.
389 #我们可能没有top的读权限,在这种情况下,我们无法获得目录包含的文件列表。操作系统。
390 #那时,walk总是会抑制异常,而不是因为一个小原因(比如)当仍有1000个可读目录要访
391 #问时就会崩溃。这里复制了这个逻辑。
392
393 try:394 #Note that scandir is global in this module due
395 #to earlier import-*.
396 #注意,由于前面的import-*, scandir在这个模块中是全局的。
397 scandir_it =scandir(top)398 exceptOSError as error:399 if onerror is notNone:400 onerror(error)401 return
402
403 with scandir_it:404 whileTrue:405 try:406 try:407 entry =next(scandir_it)408 exceptStopIteration:409 break
410 exceptOSError as error:411 if onerror is notNone:412 onerror(error)413 return
414
415 try:416 is_dir =entry.is_dir()417 exceptOSError:418 #If is_dir() raises an OSError, consider that the entry is not
419 #a directory, same behaviour than os.path.isdir().
420 #如果is_dir()引发一个OSError,则考虑该条目不是一个目录,其行为与os.path.isdir()相同
421 is_dir =False422
423 ifis_dir:424 dirs.append(entry.name)425 else:426 nondirs.append(entry.name)427
428 if not topdown andis_dir:429 #Bottom-up: recurse into sub-directory, but exclude symlinks to
430 #directories if followlinks is False
431 #自底向上:递归到子目录中,但如果followlinks为False,则排除到目录的符号链接
432 iffollowlinks:433 walk_into =True434 else:435 try:436 is_symlink =entry.is_symlink()437 exceptOSError:438 #If is_symlink() raises an OSError, consider that the
439 #entry is not a symbolic link, same behaviour than
440 #os.path.islink().
441 #如果is_symlink()引发一个OSError,请考虑该条目不是一个符号链接,其行为
442 #与os.path.islink()相同。
443
444 is_symlink =False445 walk_into = notis_symlink446
447 ifwalk_into:448 walk_dirs.append(entry.path)449
450 #Yield before recursion if going top down 如果从上到下递归,在递归之前要先屈服
451 iftopdown:452 yieldtop, dirs, nondirs453
454 #Recurse into sub-directories 递归到子目录
455 islink, join =path.islink, path.join456 for dirname indirs:457 new_path =join(top, dirname)458 #Issue #23605: os.path.islink() is used instead of caching
459 #entry.is_symlink() result during the loop on os.scandir() because
460 #the caller can replace the directory entry during the "yield"
461 #above.
462 #问题#23605:使用os.path.islink()来替代cache .is_symlink()结果,因为调用者
463 #可以在“yield”中替换目录条目。
464
465 if followlinks or notislink(new_path):466 yield fromwalk(new_path, topdown, onerror, followlinks)467 else:468 #Recurse into sub-directories
469 for new_path inwalk_dirs:470 yield fromwalk(new_path, topdown, onerror, followlinks)471 #Yield after recursion if going bottom up 如果从下往上递归,则在递归后屈服
472 yieldtop, dirs, nondirs473
474 __all__.append("walk")475
476 if {open, stat} <= supports_dir_fd and {scandir, stat} <=supports_fd:477
478 def fwalk(top=".", topdown=True, οnerrοr=None, *, follow_symlinks=False, dir_fd=None):479 """Directory tree generator.480
481 This behaves exactly like walk(), except that it yields a 4-tuple482
483 dirpath, dirnames, filenames, dirfd484
485 `dirpath`, `dirnames` and `filenames` are identical to walk() output,486 and `dirfd` is a file descriptor referring to the directory `dirpath`.487
488 The advantage of fwalk() over walk() is that it's safe against symlink489 races (when follow_symlinks is False).490
491 If dir_fd is not None, it should be a file descriptor open to a directory,492 and top should be relative; top will then be relative to that directory.493 (dir_fd is always supported for fwalk.)494
495 Caution:496 Since fwalk() yields file descriptors, those are only valid until the497 next iteration step, so you should dup() them if you want to keep them498 for a longer period.499
500 Example:501
502 import os503 for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):504 print(root, "consumes", end="")505 print(sum([os.stat(name, dir_fd=rootfd).st_size for name in files]),506 end="")507 print("bytes in", len(files), "non-directory files")508 if 'CVS' in dirs:509 dirs.remove('CVS') # don't visit CVS directories510 """
511 #目录树生成器。它的行为与walk()完全相同,只是它产生了一个4元组dirpath、
512 #dirnames、filenames、dirfd ' dirpath '、' dirnames '和' filenames
513 #'与walk()输出相同,而' dirfd '是一个指向目录' dirpath '的文件描述符。
514 #与walk()相比,fwalk()的优点是它对于symlink race(当follow_symlinks为False时)
515 #是安全的。如果dir_fd不是None,它应该是打开到目录的文件描述符,top应该是相对的;
516 #然后top将相对于那个目录。(fwalk始终支持dir_fd。)注意:因为fwalk()产生了文件描述符,
517 #所以这些描述符只在下一个迭代步骤之前有效,所以如果您想长时间保存它们,您应该使用dup()。
518
519 if not isinstance(top, int) or not hasattr(top, '__index__'):520 top =fspath(top)521 #Note: To guard against symlink races, we use the standard
522 #lstat()/open()/fstat() trick.
523 #注意:为了防止符号链接竞争,我们使用标准的lstat()/open()/fstat()技巧。
524 if notfollow_symlinks:525 orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)526 topfd = open(top, O_RDONLY, dir_fd=dir_fd)527 try:528 if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
529 path.samestat(orig_st, stat(topfd)))):530 yield from_fwalk(topfd, top, isinstance(top, bytes),531 topdown, onerror, follow_symlinks)532 finally:533 close(topfd)534
535 def_fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):536 #Note: This uses O(depth of the directory tree) file descriptors: if
537 #necessary, it can be adapted to only require O(1) FDs, see issue
538 ##13734.
539 #注意:这使用了O(目录树的深度)文件描述符:如果需要,它可以被修改为只需要O(1) FDs,请参阅issue13734
540
541 scandir_it =scandir(topfd)542 dirs =[]543 nondirs =[]544 entries = None if topdown or follow_symlinks else[]545 for entry inscandir_it:546 name =entry.name547 ifisbytes:548 name =fsencode(name)549 try:550 ifentry.is_dir():551 dirs.append(name)552 if entries is notNone:553 entries.append(entry)554 else:555 nondirs.append(name)556 exceptOSError:557 try:558 #Add dangling symlinks, ignore disappeared files
559 #添加悬空符号链接,忽略消失的文件
560 ifentry.is_symlink():561 nondirs.append(name)562 exceptOSError:563 pass
564
565 iftopdown:566 yieldtoppath, dirs, nondirs, topfd567
568 for name in dirs if entries is None elsezip(dirs, entries):569 try:570 if notfollow_symlinks:571 iftopdown:572 orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)573 else:574 assert entries is notNone575 name, entry =name576 orig_st = entry.stat(follow_symlinks=False)577 dirfd = open(name, O_RDONLY, dir_fd=topfd)578 exceptOSError as err:579 if onerror is notNone:580 onerror(err)581 continue
582 try:583 if follow_symlinks orpath.samestat(orig_st, stat(dirfd)):584 dirpath =path.join(toppath, name)585 yield from_fwalk(dirfd, dirpath, isbytes,586 topdown, onerror, follow_symlinks)587 finally:588 close(dirfd)589
590 if nottopdown:591 yieldtoppath, dirs, nondirs, topfd592
593 __all__.append("fwalk")594
595 #Make sure os.environ exists, at least
596 #确os.environ至少是存在的
597 try:598 environ599 exceptNameError:600 environ ={}601
602 def execl(file, *args):603 """execl(file, *args)604
605 Execute the executable file with argument list args, replacing the606 current process."""
607 #execl(文件,*args)用参数列表args执行可执行文件,替换当前进程。
608 execv(file, args)609
610 def execle(file, *args):611 """execle(file, *args, env)612
613 Execute the executable file with argument list args and614 environment env, replacing the current process."""
615 #execle(文件,*args, env)用参数列表args和环境env执行可执行文件,替换当前进程。
616 env = args[-1]617 execve(file, args[:-1], env)618
619 def execlp(file, *args):620 """execlp(file, *args)621
622 Execute the executable file (which is searched for along $PATH)623 with argument list args, replacing the current process."""
624 #execlp(文件,*args)用参数列表args执行可执行文件(沿着$PATH搜索),替换当前进程。
625 execvp(file, args)626
627 def execlpe(file, *args):628 """execlpe(file, *args, env)629
630 Execute the executable file (which is searched for along $PATH)631 with argument list args and environment env, replacing the current632 process."""
633 #execlpe(文件,*args, env)用参数列表arg和环境env执行可执行文件(沿着$PATH搜索),
634 #替换当前进程。
635
636 env = args[-1]637 execvpe(file, args[:-1], env)638
639 defexecvp(file, args):640 """execvp(file, args)641
642 Execute the executable file (which is searched for along $PATH)643 with argument list args, replacing the current process.644 args may be a list or tuple of strings."""
645 #execvp(文件,args)用参数列表args执行可执行文件(沿着$PATH搜索),替换当前进程。
646 #args可以是字符串的列表或元组。
647 _execvpe(file, args)648
649 defexecvpe(file, args, env):650 """execvpe(file, args, env)651
652 Execute the executable file (which is searched for along $PATH)653 with argument list args and environment env , replacing the654 current process.655 args may be a list or tuple of strings."""
656 #execvpe(文件,args, env)用参数列表arg和环境env执行可执行文件(沿着$PATH搜索),
657 #替换当前进程。args可以是字符串的列表或元组。
658 _execvpe(file, args, env)659
660 __all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])661
662 def _execvpe(file, args, env=None):663 if env is notNone:664 exec_func =execve665 argrest =(args, env)666 else:667 exec_func =execv668 argrest =(args,)669 env =environ670
671 ifpath.dirname(file):672 exec_func(file, *argrest)673 return
674 saved_exc =None675 path_list =get_exec_path(env)676 if name != 'nt':677 file =fsencode(file)678 path_list =map(fsencode, path_list)679 for dir inpath_list:680 fullname =path.join(dir, file)681 try:682 exec_func(fullname, *argrest)683 except(FileNotFoundError, NotADirectoryError) as e:684 last_exc =e685 exceptOSError as e:686 last_exc =e687 if saved_exc isNone:688 saved_exc =e689 if saved_exc is notNone:690 raisesaved_exc691 raiselast_exc692
693
694 def get_exec_path(env=None):695 """Returns the sequence of directories that will be searched for the696 named executable (similar to a shell) when launching a process.697
698 *env* must be an environment variable dict or None. If *env* is None,699 os.environ will be used.700 """
701 #返回在启动进程时将搜索命名可执行文件(类似于shell)的目录序列。*env*必须是环境变量dict或无。
702 #如果*env*为空,操作系统。将使用环境。
703
704 #Use a local import instead of a global import to limit the number of
705 #modules loaded at startup: the os module is always loaded at startup by
706 #Python. It may also avoid a bootstrap issue.
707 #使用本地导入而不是全局导入来限制在启动时加载的模块数量:os模块总是在启动时
708 #由Python加载。它还可以避免引导问题。
709 importwarnings710
711 if env isNone:712 env =environ713
714 #{b'PATH': ...}.get('PATH') and {'PATH': ...}.get(b'PATH') emit a
715 #BytesWarning when using python -b or python -bb: ignore the warning
716 with warnings.catch_warnings():717 warnings.simplefilter("ignore", BytesWarning)718
719 try:720 path_list = env.get('PATH')721 exceptTypeError:722 path_list =None723
724 ifsupports_bytes_environ:725 try:726 path_listb = env[b'PATH']727 except(KeyError, TypeError):728 pass
729 else:730 if path_list is notNone:731 raiseValueError(732 "env cannot contain 'PATH' and b'PATH' keys")733 path_list =path_listb734
735 if path_list is not None andisinstance(path_list, bytes):736 path_list =fsdecode(path_list)737
738 if path_list isNone:739 path_list =defpath740 returnpath_list.split(pathsep)741
742
743 #Change environ to automatically call putenv(), unsetenv if they exist.
744 #改变环境自动调用putenv(), unsetenv如果它们存在。
745 from _collections_abc importMutableMapping746
747 class_Environ(MutableMapping):748 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, putenv, unsetenv):749 self.encodekey =encodekey750 self.decodekey =decodekey751 self.encodevalue =encodevalue752 self.decodevalue =decodevalue753 self.putenv =putenv754 self.unsetenv =unsetenv755 self._data =data756
757 def __getitem__(self, key):758 try:759 value =self._data[self.encodekey(key)]760 exceptKeyError:761 #raise KeyError with the original key value
762 raise KeyError(key) fromNone763 returnself.decodevalue(value)764
765 def __setitem__(self, key, value):766 key =self.encodekey(key)767 value =self.encodevalue(value)768 self.putenv(key, value)769 self._data[key] =value770
771 def __delitem__(self, key):772 encodedkey =self.encodekey(key)773 self.unsetenv(encodedkey)774 try:775 delself._data[encodedkey]776 exceptKeyError:777 #raise KeyError with the original key value 使用原始键值引发KeyError
778 raise KeyError(key) fromNone779
780 def __iter__(self):781 #list() from dict object is an atomic operation
782 #dict对象的list()是一个原子操作
783 keys =list(self._data)784 for key inkeys:785 yieldself.decodekey(key)786
787 def __len__(self):788 returnlen(self._data)789
790 def __repr__(self):791 return 'environ({{{}}})'.format(','.join(792 ('{!r}: {!r}'.format(self.decodekey(key), self.decodevalue(value))793 for key, value inself._data.items())))794
795 defcopy(self):796 returndict(self)797
798 defsetdefault(self, key, value):799 if key not inself:800 self[key] =value801 returnself[key]802
803 try:804 _putenv =putenv805 exceptNameError:806 _putenv = lambdakey, value: None807 else:808 if "putenv" not in __all__:809 __all__.append("putenv")810
811 try:812 _unsetenv =unsetenv813 exceptNameError:814 _unsetenv = lambda key: _putenv(key, "")815 else:816 if "unsetenv" not in __all__:817 __all__.append("unsetenv")818
819 def_createenviron():820 if name == 'nt':821 #Where Env Var Names Must Be UPPERCASE 在哪里Env Var名称必须是大写的
822 defcheck_str(value):823 if notisinstance(value, str):824 raise TypeError("str expected, not %s" % type(value).__name__)825 returnvalue826 encode =check_str827 decode =str828 defencodekey(key):829 returnencode(key).upper()830 data ={}831 for key, value inenviron.items():832 data[encodekey(key)] =value833 else:834 #Where Env Var Names Can Be Mixed Case
835 encoding =sys.getfilesystemencoding()836 defencode(value):837 if notisinstance(value, str):838 raise TypeError("str expected, not %s" % type(value).__name__)839 return value.encode(encoding, 'surrogateescape')840 defdecode(value):841 return value.decode(encoding, 'surrogateescape')842 encodekey =encode843 data =environ844 return_Environ(data,845 encodekey, decode,846 encode, decode,847 _putenv, _unsetenv)848
849 #unicode environ
850 environ =_createenviron()851 del_createenviron852
853
854 def getenv(key, default=None):855 """Get an environment variable, return None if it doesn't exist.856 The optional second argument can specify an alternate default.857 key, default and the result are str."""
858 #获取一个环境变量,如果它不存在,返回None。可选的第二个参数可以指定另一个默认值。
859 #键、默认值和结果都是str。
860
861 returnenviron.get(key, default)862
863 supports_bytes_environ = (name != 'nt')864 __all__.extend(("getenv", "supports_bytes_environ"))865
866 ifsupports_bytes_environ:867 def_check_bytes(value):868 if notisinstance(value, bytes):869 raise TypeError("bytes expected, not %s" % type(value).__name__)870 returnvalue871
872 #bytes environ
873 environb =_Environ(environ._data,874 _check_bytes, bytes,875 _check_bytes, bytes,876 _putenv, _unsetenv)877 del_check_bytes878
879 def getenvb(key, default=None):880 """Get an environment variable, return None if it doesn't exist.881 The optional second argument can specify an alternate default.882 key, default and the result are bytes."""
883 #获取一个环境变量,如果它不存在,返回None。可选的第二个参数可以指定另一个默认值。
884 #键、默认值和结果都是字节。
885
886 returnenvironb.get(key, default)887
888 __all__.extend(("environb", "getenvb"))889
890 def_fscodec():891 encoding =sys.getfilesystemencoding()892 errors =sys.getfilesystemencodeerrors()893
894 deffsencode(filename):895 """Encode filename (an os.PathLike, bytes, or str) to the filesystem896 encoding with 'surrogateescape' error handler, return bytes unchanged.897 On Windows, use 'strict' error handler if the file system encoding is898 'mbcs' (which is the default encoding).899 """
900 #编码文件名(一个操作系统)。使用“surrogateescape”错误处理程序对文件系统进行
901 #编码,返回字节不变。在Windows上,如果文件系统编码是“mbcs”(这是默认编码),
902 #则使用“严格”错误处理程序。
903
904 filename = fspath(filename) #Does type-checking of `filename`.
905 ifisinstance(filename, str):906 returnfilename.encode(encoding, errors)907 else:908 returnfilename909
910 deffsdecode(filename):911 """Decode filename (an os.PathLike, bytes, or str) from the filesystem912 encoding with 'surrogateescape' error handler, return str unchanged. On913 Windows, use 'strict' error handler if the file system encoding is914 'mbcs' (which is the default encoding).915 """
916 #解码文件名(一个操作系统)。从带有“surrogateescape”错误处理程序的文件系统编码中,
917 #返回str不变。在Windows上,如果文件系统编码是“mbcs”(这是默认编码),则使用
918 #“严格”错误处理程序。
919
920 filename = fspath(filename) #Does type-checking of `filename`.
921 ifisinstance(filename, bytes):922 returnfilename.decode(encoding, errors)923 else:924 returnfilename925
926 returnfsencode, fsdecode927
928 fsencode, fsdecode =_fscodec()929 del_fscodec930
931 #Supply spawn*() (probably only for Unix) 提供spawn*()(可能只适用于Unix)
932 if _exists("fork") and not _exists("spawnv") and _exists("execv"):933
934 P_WAIT =0935 P_NOWAIT = P_NOWAITO = 1
936
937 __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"])938
939 #XXX Should we support P_DETACH? I suppose it could fork()**2
940 #and close the std I/O streams. Also, P_OVERLAY is the same
941 #as execv*()?
942 #我们应该支持P_DETACH吗?我想它可以分叉()**2并关闭std I/O流。另外,P_OVERLAY和execv*()一样?
943
944 def_spawnvef(mode, file, args, env, func):945 #Internal helper; func is the exec*() function to use
946 #内部辅助;func是要使用的exec*()函数
947 if notisinstance(args, (tuple, list)):948 raise TypeError('argv must be a tuple or a list')949 if not args or notargs[0]:950 raise ValueError('argv first element cannot be empty')951 pid =fork()952 if notpid:953 #Child
954 try:955 if env isNone:956 func(file, args)957 else:958 func(file, args, env)959 except:960 _exit(127)961 else:962 #Parent
963 if mode ==P_NOWAIT:964 return pid #Caller is responsible for waiting!
965 while 1:966 wpid, sts =waitpid(pid, 0)967 ifWIFSTOPPED(sts):968 continue
969 elifWIFSIGNALED(sts):970 return -WTERMSIG(sts)971 elifWIFEXITED(sts):972 returnWEXITSTATUS(sts)973 else:974 raise OSError("Not stopped, signaled or exited???")975
976 defspawnv(mode, file, args):977 """spawnv(mode, file, args) -> integer978
979 Execute file with arguments from args in a subprocess.980 If mode == P_NOWAIT return the pid of the process.981 If mode == P_WAIT return the process's exit code if it exits normally;982 otherwise return -SIG, where SIG is the signal that killed it."""
983 #在子进程中使用args参数执行文件。If mode == P_NOWAIT返回进程的pid。
984 #如果mode == P_WAIT返回进程正常退出的退出代码;否则返回-SIG,其中SIG是终止
985 #进程的信号。
986
987 return_spawnvef(mode, file, args, None, execv)988
989 defspawnve(mode, file, args, env):990 """spawnve(mode, file, args, env) -> integer991
992 Execute file with arguments from args in a subprocess with the993 specified environment.994 If mode == P_NOWAIT return the pid of the process.995 If mode == P_WAIT return the process's exit code if it exits normally;996 otherwise return -SIG, where SIG is the signal that killed it."""
997 #使用指定环境的子进程中的args参数执行文件。If mode == P_NOWAIT返回进程的pid。
998 #如果mode == P_WAIT返回进程正常退出的退出代码;否则返回-SIG,其中SIG是终止进程
999 #的信号。
1000
1001 return_spawnvef(mode, file, args, env, execve)1002
1003 #Note: spawnvp[e] isn't currently supported on Windows
1004
1005 defspawnvp(mode, file, args):1006 """spawnvp(mode, file, args) -> integer1007
1008 Execute file (which is looked for along $PATH) with arguments from1009 args in a subprocess.1010 If mode == P_NOWAIT return the pid of the process.1011 If mode == P_WAIT return the process's exit code if it exits normally;1012 otherwise return -SIG, where SIG is the signal that killed it."""
1013 return_spawnvef(mode, file, args, None, execvp)1014
1015 defspawnvpe(mode, file, args, env):1016 """spawnvpe(mode, file, args, env) -> integer1017
1018 Execute file (which is looked for along $PATH) with arguments from1019 args in a subprocess with the supplied environment.1020 If mode == P_NOWAIT return the pid of the process.1021 If mode == P_WAIT return the process's exit code if it exits normally;1022 otherwise return -SIG, where SIG is the signal that killed it."""
1023 return_spawnvef(mode, file, args, env, execvpe)1024
1025
1026 __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"])1027
1028
1029 if _exists("spawnv"):1030 #These aren't supplied by the basic Windows code
1031 #but can be easily implemented in Python
1032
1033 def spawnl(mode, file, *args):1034 """spawnl(mode, file, *args) -> integer1035
1036 Execute file with arguments from args in a subprocess.1037 If mode == P_NOWAIT return the pid of the process.1038 If mode == P_WAIT return the process's exit code if it exits normally;1039 otherwise return -SIG, where SIG is the signal that killed it."""
1040 returnspawnv(mode, file, args)1041
1042 def spawnle(mode, file, *args):1043 """spawnle(mode, file, *args, env) -> integer1044
1045 Execute file with arguments from args in a subprocess with the1046 supplied environment.1047 If mode == P_NOWAIT return the pid of the process.1048 If mode == P_WAIT return the process's exit code if it exits normally;1049 otherwise return -SIG, where SIG is the signal that killed it."""
1050 env = args[-1]1051 return spawnve(mode, file, args[:-1], env)1052
1053
1054 __all__.extend(["spawnl", "spawnle"])1055
1056
1057 if _exists("spawnvp"):1058 #At the moment, Windows doesn't implement spawnvp[e],
1059 #so it won't have spawnlp[e] either.
1060 def spawnlp(mode, file, *args):1061 """spawnlp(mode, file, *args) -> integer1062
1063 Execute file (which is looked for along $PATH) with arguments from1064 args in a subprocess with the supplied environment.1065 If mode == P_NOWAIT return the pid of the process.1066 If mode == P_WAIT return the process's exit code if it exits normally;1067 otherwise return -SIG, where SIG is the signal that killed it."""
1068 returnspawnvp(mode, file, args)1069
1070 def spawnlpe(mode, file, *args):1071 """spawnlpe(mode, file, *args, env) -> integer1072
1073 Execute file (which is looked for along $PATH) with arguments from1074 args in a subprocess with the supplied environment.1075 If mode == P_NOWAIT return the pid of the process.1076 If mode == P_WAIT return the process's exit code if it exits normally;1077 otherwise return -SIG, where SIG is the signal that killed it."""
1078 env = args[-1]1079 return spawnvpe(mode, file, args[:-1], env)1080
1081
1082 __all__.extend(["spawnlp", "spawnlpe"])1083
1084
1085 #Supply os.popen()
1086 def popen(cmd, mode="r", buffering=-1):1087 if notisinstance(cmd, str):1088 raise TypeError("invalid cmd type (%s, expected string)" %type(cmd))1089 if mode not in ("r", "w"):1090 raise ValueError("invalid mode %r" %mode)1091 if buffering == 0 or buffering isNone:1092 raise ValueError("popen() does not support unbuffered streams")1093 importsubprocess, io1094 if mode == "r":1095 proc =subprocess.Popen(cmd,1096 shell=True,1097 stdout=subprocess.PIPE,1098 bufsize=buffering)1099 return_wrap_close(io.TextIOWrapper(proc.stdout), proc)1100 else:1101 proc =subprocess.Popen(cmd,1102 shell=True,1103 stdin=subprocess.PIPE,1104 bufsize=buffering)1105 return_wrap_close(io.TextIOWrapper(proc.stdin), proc)1106
1107 #Helper for popen() -- a proxy for a file whose close waits for the process
1108 class_wrap_close:1109 def __init__(self, stream, proc):1110 self._stream =stream1111 self._proc =proc1112 defclose(self):1113 self._stream.close()1114 returncode =self._proc.wait()1115 if returncode ==0:1116 returnNone1117 if name == 'nt':1118 returnreturncode1119 else:1120 return returncode << 8 #Shift left to match old behavior
1121 def __enter__(self):1122 returnself1123 def __exit__(self, *args):1124 self.close()1125 def __getattr__(self, name):1126 returngetattr(self._stream, name)1127 def __iter__(self):1128 returniter(self._stream)1129
1130 #Supply os.fdopen()
1131 def fdopen(fd, *args, **kwargs):1132 if notisinstance(fd, int):1133 raise TypeError("invalid fd type (%s, expected integer)" %type(fd))1134 importio1135 return io.open(fd, *args, **kwargs)1136
1137
1138 #For testing purposes, make sure the function is available when the C
1139 #implementation exists.
1140 def_fspath(path):1141 """Return the path representation of a path-like object.1142
1143 If str or bytes is passed in, it is returned unchanged. Otherwise the1144 os.PathLike interface is used to get the path representation. If the1145 path representation is not str or bytes, TypeError is raised. If the1146 provided path is not str, bytes, or os.PathLike, TypeError is raised.1147 """
1148 #返回类路径对象的路径表示。如果传入str或字节,则返回时不会改变。否则,操作系统。
1149 #类路径接口用于获取路径表示。如果路径表示不是str或字节,则会引发类型错误。如果
1150 #提供的路径不是str、字节或os。类路径,类型错误。
1151
1152 ifisinstance(path, (str, bytes)):1153 returnpath1154
1155 #Work from the object's type to match method resolution of other magic
1156 #methods.
1157 #从对象的类型开始工作,以匹配其他魔术方法的方法解析。
1158 path_type =type(path)1159 try:1160 path_repr = path_type.__fspath__(path)1161 exceptAttributeError:1162 if hasattr(path_type, '__fspath__'):1163 raise
1164 else:1165 raise TypeError("expected str, bytes or os.PathLike object,"
1166 "not" + path_type.__name__)1167 ifisinstance(path_repr, (str, bytes)):1168 returnpath_repr1169 else:1170 raise TypeError("expected {}.__fspath__() to return str or bytes,"
1171 "not {}".format(path_type.__name__,1172 type(path_repr).__name__))1173
1174 #If there is no C implementation, make the pure Python version the
1175 #implementation as transparently as possible.
1176 #如果没有C实现,请尽可能使纯Python版本的实现透明。
1177 if not _exists('fspath'):1178 fspath =_fspath1179 fspath.__name__ = "fspath"
1180
1181
1182 classPathLike(abc.ABC):1183
1184 """Abstract base class for implementing the file system path protocol."""
1185 #用于实现文件系统路径协议的抽象基类。
1186
1187 @abc.abstractmethod1188 def __fspath__(self):1189 """Return the file system path representation of the object."""
1190 #返回对象的文件系统路径表示。
1191 raiseNotImplementedError1192
1193 @classmethod1194 def __subclasshook__(cls, subclass):1195 return hasattr(subclass, '__fspath__')