1r"""OS routines for NT or Posix depending on what system we're on. 2 3This exports: 4 - all functions from posix or nt, e.g. unlink, stat, etc. 5 - os.path is either posixpath or ntpath 6 - os.name is either 'posix' or 'nt' 7 - os.curdir is a string representing the current directory (always '.') 8 - os.pardir is a string representing the parent directory (always '..') 9 - os.sep is the (or a most common) pathname separator ('/' or '\\') 10 - os.extsep is the extension separator (always '.') 11 - os.altsep is the alternate pathname separator (None or '/') 12 - os.pathsep is the component separator used in $PATH etc 13 - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n') 14 - os.defpath is the default search path for executables 15 - os.devnull is the file path of the null device ('/dev/null', etc.) 16 17Programs that import and use 'os' stand a better chance of being 18portable between different platforms. Of course, they must then 19only use functions that are defined by all platforms (e.g., unlink 20and opendir), and leave all pathname manipulation to os.path 21(e.g., split and join). 22""" 23 24#' 25import abc 26import sys 27import stat as st 28 29from _collections_abc import _check_methods 30 31GenericAlias = type(list[int]) 32 33_names = sys.builtin_module_names 34 35# Note: more names are added to __all__ later. 36__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep", 37 "defpath", "name", "path", "devnull", "SEEK_SET", "SEEK_CUR", 38 "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen", 39 "extsep"] 40 41def _exists(name): 42 return name in globals() 43 44def _get_exports_list(module): 45 try: 46 return list(module.__all__) 47 except AttributeError: 48 return [n for n in dir(module) if n[0] != '_'] 49 50# Any new dependencies of the os module and/or changes in path separator 51# requires updating importlib as well. 52if 'posix' in _names: 53 name = 'posix' 54 linesep = '\n' 55 from posix import * 56 try: 57 from posix import _exit 58 __all__.append('_exit') 59 except ImportError: 60 pass 61 import posixpath as path 62 63 try: 64 from posix import _have_functions 65 except ImportError: 66 pass 67 68 import posix 69 __all__.extend(_get_exports_list(posix)) 70 del posix 71 72elif 'nt' in _names: 73 name = 'nt' 74 linesep = '\r\n' 75 from nt import * 76 try: 77 from nt import _exit 78 __all__.append('_exit') 79 except ImportError: 80 pass 81 import ntpath as path 82 83 import nt 84 __all__.extend(_get_exports_list(nt)) 85 del nt 86 87 try: 88 from nt import _have_functions 89 except ImportError: 90 pass 91 92else: 93 raise ImportError('no os specific module found') 94 95sys.modules['os.path'] = path 96from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, 97 devnull) 98 99del _names 100 101 102if _exists("_have_functions"): 103 _globals = globals() 104 def _add(str, fn): 105 if (fn in _globals) and (str in _have_functions): 106 _set.add(_globals[fn]) 107 108 _set = set() 109 _add("HAVE_FACCESSAT", "access") 110 _add("HAVE_FCHMODAT", "chmod") 111 _add("HAVE_FCHOWNAT", "chown") 112 _add("HAVE_FSTATAT", "stat") 113 _add("HAVE_FUTIMESAT", "utime") 114 _add("HAVE_LINKAT", "link") 115 _add("HAVE_MKDIRAT", "mkdir") 116 _add("HAVE_MKFIFOAT", "mkfifo") 117 _add("HAVE_MKNODAT", "mknod") 118 _add("HAVE_OPENAT", "open") 119 _add("HAVE_READLINKAT", "readlink") 120 _add("HAVE_RENAMEAT", "rename") 121 _add("HAVE_SYMLINKAT", "symlink") 122 _add("HAVE_UNLINKAT", "unlink") 123 _add("HAVE_UNLINKAT", "rmdir") 124 _add("HAVE_UTIMENSAT", "utime") 125 supports_dir_fd = _set 126 127 _set = set() 128 _add("HAVE_FACCESSAT", "access") 129 supports_effective_ids = _set 130 131 _set = set() 132 _add("HAVE_FCHDIR", "chdir") 133 _add("HAVE_FCHMOD", "chmod") 134 _add("HAVE_FCHOWN", "chown") 135 _add("HAVE_FDOPENDIR", "listdir") 136 _add("HAVE_FDOPENDIR", "scandir") 137 _add("HAVE_FEXECVE", "execve") 138 _set.add(stat) # fstat always works 139 _add("HAVE_FTRUNCATE", "truncate") 140 _add("HAVE_FUTIMENS", "utime") 141 _add("HAVE_FUTIMES", "utime") 142 _add("HAVE_FPATHCONF", "pathconf") 143 if _exists("statvfs") and _exists("fstatvfs"): # mac os x10.3 144 _add("HAVE_FSTATVFS", "statvfs") 145 supports_fd = _set 146 147 _set = set() 148 _add("HAVE_FACCESSAT", "access") 149 # Some platforms don't support lchmod(). Often the function exists 150 # anyway, as a stub that always returns ENOSUP or perhaps EOPNOTSUPP. 151 # (No, I don't know why that's a good design.) ./configure will detect 152 # this and reject it--so HAVE_LCHMOD still won't be defined on such 153 # platforms. This is Very Helpful. 154 # 155 # However, sometimes platforms without a working lchmod() *do* have 156 # fchmodat(). (Examples: Linux kernel 3.2 with glibc 2.15, 157 # OpenIndiana 3.x.) And fchmodat() has a flag that theoretically makes 158 # it behave like lchmod(). So in theory it would be a suitable 159 # replacement for lchmod(). But when lchmod() doesn't work, fchmodat()'s 160 # flag doesn't work *either*. Sadly ./configure isn't sophisticated 161 # enough to detect this condition--it only determines whether or not 162 # fchmodat() minimally works. 163 # 164 # Therefore we simply ignore fchmodat() when deciding whether or not 165 # os.chmod supports follow_symlinks. Just checking lchmod() is 166 # sufficient. After all--if you have a working fchmodat(), your 167 # lchmod() almost certainly works too. 168 # 169 # _add("HAVE_FCHMODAT", "chmod") 170 _add("HAVE_FCHOWNAT", "chown") 171 _add("HAVE_FSTATAT", "stat") 172 _add("HAVE_LCHFLAGS", "chflags") 173 _add("HAVE_LCHMOD", "chmod") 174 if _exists("lchown"): # mac os x10.3 175 _add("HAVE_LCHOWN", "chown") 176 _add("HAVE_LINKAT", "link") 177 _add("HAVE_LUTIMES", "utime") 178 _add("HAVE_LSTAT", "stat") 179 _add("HAVE_FSTATAT", "stat") 180 _add("HAVE_UTIMENSAT", "utime") 181 _add("MS_WINDOWS", "stat") 182 supports_follow_symlinks = _set 183 184 del _set 185 del _have_functions 186 del _globals 187 del _add 188 189 190# Python uses fixed values for the SEEK_ constants; they are mapped 191# to native constants if necessary in posixmodule.c 192# Other possible SEEK values are directly imported from posixmodule.c 193SEEK_SET = 0 194SEEK_CUR = 1 195SEEK_END = 2 196 197# Super directory utilities. 198# (Inspired by Eric Raymond; the doc strings are mostly his) 199 200def makedirs(name, mode=0o777, exist_ok=False): 201 """makedirs(name [, mode=0o777][, exist_ok=False]) 202 203 Super-mkdir; create a leaf directory and all intermediate ones. Works like 204 mkdir, except that any intermediate path segment (not just the rightmost) 205 will be created if it does not exist. If the target directory already 206 exists, raise an OSError if exist_ok is False. Otherwise no exception is 207 raised. This is recursive. 208 209 """ 210 head, tail = path.split(name) 211 if not tail: 212 head, tail = path.split(head) 213 if head and tail and not path.exists(head): 214 try: 215 makedirs(head, exist_ok=exist_ok) 216 except FileExistsError: 217 # Defeats race condition when another thread created the path 218 pass 219 cdir = curdir 220 if isinstance(tail, bytes): 221 cdir = bytes(curdir, 'ASCII') 222 if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists 223 return 224 try: 225 mkdir(name, mode) 226 except OSError: 227 # Cannot rely on checking for EEXIST, since the operating system 228 # could give priority to other errors like EACCES or EROFS 229 if not exist_ok or not path.isdir(name): 230 raise 231 232def removedirs(name): 233 """removedirs(name) 234 235 Super-rmdir; remove a leaf directory and all empty intermediate 236 ones. Works like rmdir except that, if the leaf directory is 237 successfully removed, directories corresponding to rightmost path 238 segments will be pruned away until either the whole path is 239 consumed or an error occurs. Errors during this latter phase are 240 ignored -- they generally mean that a directory was not empty. 241 242 """ 243 rmdir(name) 244 head, tail = path.split(name) 245 if not tail: 246 head, tail = path.split(head) 247 while head and tail: 248 try: 249 rmdir(head) 250 except OSError: 251 break 252 head, tail = path.split(head) 253 254def renames(old, new): 255 """renames(old, new) 256 257 Super-rename; create directories as necessary and delete any left 258 empty. Works like rename, except creation of any intermediate 259 directories needed to make the new pathname good is attempted 260 first. After the rename, directories corresponding to rightmost 261 path segments of the old name will be pruned until either the 262 whole path is consumed or a nonempty directory is found. 263 264 Note: this function can fail with the new directory structure made 265 if you lack permissions needed to unlink the leaf directory or 266 file. 267 268 """ 269 head, tail = path.split(new) 270 if head and tail and not path.exists(head): 271 makedirs(head) 272 rename(old, new) 273 head, tail = path.split(old) 274 if head and tail: 275 try: 276 removedirs(head) 277 except OSError: 278 pass 279 280__all__.extend(["makedirs", "removedirs", "renames"]) 281 282def walk(top, topdown=True, onerror=None, followlinks=False): 283 """Directory tree generator. 284 285 For each directory in the directory tree rooted at top (including top 286 itself, but excluding '.' and '..'), yields a 3-tuple 287 288 dirpath, dirnames, filenames 289 290 dirpath is a string, the path to the directory. dirnames is a list of 291 the names of the subdirectories in dirpath (excluding '.' and '..'). 292 filenames is a list of the names of the non-directory files in dirpath. 293 Note that the names in the lists are just names, with no path components. 294 To get a full path (which begins with top) to a file or directory in 295 dirpath, do os.path.join(dirpath, name). 296 297 If optional arg 'topdown' is true or not specified, the triple for a 298 directory is generated before the triples for any of its subdirectories 299 (directories are generated top down). If topdown is false, the triple 300 for a directory is generated after the triples for all of its 301 subdirectories (directories are generated bottom up). 302 303 When topdown is true, the caller can modify the dirnames list in-place 304 (e.g., via del or slice assignment), and walk will only recurse into the 305 subdirectories whose names remain in dirnames; this can be used to prune the 306 search, or to impose a specific order of visiting. Modifying dirnames when 307 topdown is false has no effect on the behavior of os.walk(), since the 308 directories in dirnames have already been generated by the time dirnames 309 itself is generated. No matter the value of topdown, the list of 310 subdirectories is retrieved before the tuples for the directory and its 311 subdirectories are generated. 312 313 By default errors from the os.scandir() call are ignored. If 314 optional arg 'onerror' is specified, it should be a function; it 315 will be called with one argument, an OSError instance. It can 316 report the error to continue with the walk, or raise the exception 317 to abort the walk. Note that the filename is available as the 318 filename attribute of the exception object. 319 320 By default, os.walk does not follow symbolic links to subdirectories on 321 systems that support them. In order to get this functionality, set the 322 optional argument 'followlinks' to true. 323 324 Caution: if you pass a relative pathname for top, don't change the 325 current working directory between resumptions of walk. walk never 326 changes the current directory, and assumes that the client doesn't 327 either. 328 329 Example: 330 331 import os 332 from os.path import join, getsize 333 for root, dirs, files in os.walk('python/Lib/email'): 334 print(root, "consumes", end="") 335 print(sum(getsize(join(root, name)) for name in files), end="") 336 print("bytes in", len(files), "non-directory files") 337 if 'CVS' in dirs: 338 dirs.remove('CVS') # don't visit CVS directories 339 340 """ 341 sys.audit("os.walk", top, topdown, onerror, followlinks) 342 return _walk(fspath(top), topdown, onerror, followlinks) 343 344def _walk(top, topdown, onerror, followlinks): 345 dirs = [] 346 nondirs = [] 347 walk_dirs = [] 348 349 # We may not have read permission for top, in which case we can't 350 # get a list of the files the directory contains. os.walk 351 # always suppressed the exception then, rather than blow up for a 352 # minor reason when (say) a thousand readable directories are still 353 # left to visit. That logic is copied here. 354 try: 355 # Note that scandir is global in this module due 356 # to earlier import-*. 357 scandir_it = scandir(top) 358 except OSError as error: 359 if onerror is not None: 360 onerror(error) 361 return 362 363 with scandir_it: 364 while True: 365 try: 366 try: 367 entry = next(scandir_it) 368 except StopIteration: 369 break 370 except OSError as error: 371 if onerror is not None: 372 onerror(error) 373 return 374 375 try: 376 is_dir = entry.is_dir() 377 except OSError: 378 # If is_dir() raises an OSError, consider that the entry is not 379 # a directory, same behaviour than os.path.isdir(). 380 is_dir = False 381 382 if is_dir: 383 dirs.append(entry.name) 384 else: 385 nondirs.append(entry.name) 386 387 if not topdown and is_dir: 388 # Bottom-up: recurse into sub-directory, but exclude symlinks to 389 # directories if followlinks is False 390 if followlinks: 391 walk_into = True 392 else: 393 try: 394 is_symlink = entry.is_symlink() 395 except OSError: 396 # If is_symlink() raises an OSError, consider that the 397 # entry is not a symbolic link, same behaviour than 398 # os.path.islink(). 399 is_symlink = False 400 walk_into = not is_symlink 401 402 if walk_into: 403 walk_dirs.append(entry.path) 404 405 # Yield before recursion if going top down 406 if topdown: 407 yield top, dirs, nondirs 408 409 # Recurse into sub-directories 410 islink, join = path.islink, path.join 411 for dirname in dirs: 412 new_path = join(top, dirname) 413 # Issue #23605: os.path.islink() is used instead of caching 414 # entry.is_symlink() result during the loop on os.scandir() because 415 # the caller can replace the directory entry during the "yield" 416 # above. 417 if followlinks or not islink(new_path): 418 yield from _walk(new_path, topdown, onerror, followlinks) 419 else: 420 # Recurse into sub-directories 421 for new_path in walk_dirs: 422 yield from _walk(new_path, topdown, onerror, followlinks) 423 # Yield after recursion if going bottom up 424 yield top, dirs, nondirs 425 426__all__.append("walk") 427 428if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd: 429 430 def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None): 431 """Directory tree generator. 432 433 This behaves exactly like walk(), except that it yields a 4-tuple 434 435 dirpath, dirnames, filenames, dirfd 436 437 `dirpath`, `dirnames` and `filenames` are identical to walk() output, 438 and `dirfd` is a file descriptor referring to the directory `dirpath`. 439 440 The advantage of fwalk() over walk() is that it's safe against symlink 441 races (when follow_symlinks is False). 442 443 If dir_fd is not None, it should be a file descriptor open to a directory, 444 and top should be relative; top will then be relative to that directory. 445 (dir_fd is always supported for fwalk.) 446 447 Caution: 448 Since fwalk() yields file descriptors, those are only valid until the 449 next iteration step, so you should dup() them if you want to keep them 450 for a longer period. 451 452 Example: 453 454 import os 455 for root, dirs, files, rootfd in os.fwalk('python/Lib/email'): 456 print(root, "consumes", end="") 457 print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files), 458 end="") 459 print("bytes in", len(files), "non-directory files") 460 if 'CVS' in dirs: 461 dirs.remove('CVS') # don't visit CVS directories 462 """ 463 sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd) 464 top = fspath(top) 465 # Note: To guard against symlink races, we use the standard 466 # lstat()/open()/fstat() trick. 467 if not follow_symlinks: 468 orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd) 469 topfd = open(top, O_RDONLY, dir_fd=dir_fd) 470 try: 471 if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and 472 path.samestat(orig_st, stat(topfd)))): 473 yield from _fwalk(topfd, top, isinstance(top, bytes), 474 topdown, onerror, follow_symlinks) 475 finally: 476 close(topfd) 477 478 def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks): 479 # Note: This uses O(depth of the directory tree) file descriptors: if 480 # necessary, it can be adapted to only require O(1) FDs, see issue 481 # #13734. 482 483 scandir_it = scandir(topfd) 484 dirs = [] 485 nondirs = [] 486 entries = None if topdown or follow_symlinks else [] 487 for entry in scandir_it: 488 name = entry.name 489 if isbytes: 490 name = fsencode(name) 491 try: 492 if entry.is_dir(): 493 dirs.append(name) 494 if entries is not None: 495 entries.append(entry) 496 else: 497 nondirs.append(name) 498 except OSError: 499 try: 500 # Add dangling symlinks, ignore disappeared files 501 if entry.is_symlink(): 502 nondirs.append(name) 503 except OSError: 504 pass 505 506 if topdown: 507 yield toppath, dirs, nondirs, topfd 508 509 for name in dirs if entries is None else zip(dirs, entries): 510 try: 511 if not follow_symlinks: 512 if topdown: 513 orig_st = stat(name, dir_fd=topfd, follow_symlinks=False) 514 else: 515 assert entries is not None 516 name, entry = name 517 orig_st = entry.stat(follow_symlinks=False) 518 dirfd = open(name, O_RDONLY, dir_fd=topfd) 519 except OSError as err: 520 if onerror is not None: 521 onerror(err) 522 continue 523 try: 524 if follow_symlinks or path.samestat(orig_st, stat(dirfd)): 525 dirpath = path.join(toppath, name) 526 yield from _fwalk(dirfd, dirpath, isbytes, 527 topdown, onerror, follow_symlinks) 528 finally: 529 close(dirfd) 530 531 if not topdown: 532 yield toppath, dirs, nondirs, topfd 533 534 __all__.append("fwalk") 535 536def execl(file, *args): 537 """execl(file, *args) 538 539 Execute the executable file with argument list args, replacing the 540 current process. """ 541 execv(file, args) 542 543def execle(file, *args): 544 """execle(file, *args, env) 545 546 Execute the executable file with argument list args and 547 environment env, replacing the current process. """ 548 env = args[-1] 549 execve(file, args[:-1], env) 550 551def execlp(file, *args): 552 """execlp(file, *args) 553 554 Execute the executable file (which is searched for along $PATH) 555 with argument list args, replacing the current process. """ 556 execvp(file, args) 557 558def execlpe(file, *args): 559 """execlpe(file, *args, env) 560 561 Execute the executable file (which is searched for along $PATH) 562 with argument list args and environment env, replacing the current 563 process. """ 564 env = args[-1] 565 execvpe(file, args[:-1], env) 566 567def execvp(file, args): 568 """execvp(file, args) 569 570 Execute the executable file (which is searched for along $PATH) 571 with argument list args, replacing the current process. 572 args may be a list or tuple of strings. """ 573 _execvpe(file, args) 574 575def execvpe(file, args, env): 576 """execvpe(file, args, env) 577 578 Execute the executable file (which is searched for along $PATH) 579 with argument list args and environment env, replacing the 580 current process. 581 args may be a list or tuple of strings. """ 582 _execvpe(file, args, env) 583 584__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"]) 585 586def _execvpe(file, args, env=None): 587 if env is not None: 588 exec_func = execve 589 argrest = (args, env) 590 else: 591 exec_func = execv 592 argrest = (args,) 593 env = environ 594 595 if path.dirname(file): 596 exec_func(file, *argrest) 597 return 598 saved_exc = None 599 path_list = get_exec_path(env) 600 if name != 'nt': 601 file = fsencode(file) 602 path_list = map(fsencode, path_list) 603 for dir in path_list: 604 fullname = path.join(dir, file) 605 try: 606 exec_func(fullname, *argrest) 607 except (FileNotFoundError, NotADirectoryError) as e: 608 last_exc = e 609 except OSError as e: 610 last_exc = e 611 if saved_exc is None: 612 saved_exc = e 613 if saved_exc is not None: 614 raise saved_exc 615 raise last_exc 616 617 618def get_exec_path(env=None): 619 """Returns the sequence of directories that will be searched for the 620 named executable (similar to a shell) when launching a process. 621 622 *env* must be an environment variable dict or None. If *env* is None, 623 os.environ will be used. 624 """ 625 # Use a local import instead of a global import to limit the number of 626 # modules loaded at startup: the os module is always loaded at startup by 627 # Python. It may also avoid a bootstrap issue. 628 import warnings 629 630 if env is None: 631 env = environ 632 633 # {b'PATH': ...}.get('PATH') and {'PATH': ...}.get(b'PATH') emit a 634 # BytesWarning when using python -b or python -bb: ignore the warning 635 with warnings.catch_warnings(): 636 warnings.simplefilter("ignore", BytesWarning) 637 638 try: 639 path_list = env.get('PATH') 640 except TypeError: 641 path_list = None 642 643 if supports_bytes_environ: 644 try: 645 path_listb = env[b'PATH'] 646 except (KeyError, TypeError): 647 pass 648 else: 649 if path_list is not None: 650 raise ValueError( 651 "env cannot contain 'PATH' and b'PATH' keys") 652 path_list = path_listb 653 654 if path_list is not None and isinstance(path_list, bytes): 655 path_list = fsdecode(path_list) 656 657 if path_list is None: 658 path_list = defpath 659 return path_list.split(pathsep) 660 661 662# Change environ to automatically call putenv() and unsetenv() 663from _collections_abc import MutableMapping, Mapping 664 665class _Environ(MutableMapping): 666 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue): 667 self.encodekey = encodekey 668 self.decodekey = decodekey 669 self.encodevalue = encodevalue 670 self.decodevalue = decodevalue 671 self._data = data 672 673 def __getitem__(self, key): 674 try: 675 value = self._data[self.encodekey(key)] 676 except KeyError: 677 # raise KeyError with the original key value 678 raise KeyError(key) from None 679 return self.decodevalue(value) 680 681 def __setitem__(self, key, value): 682 key = self.encodekey(key) 683 value = self.encodevalue(value) 684 putenv(key, value) 685 self._data[key] = value 686 687 def __delitem__(self, key): 688 encodedkey = self.encodekey(key) 689 unsetenv(encodedkey) 690 try: 691 del self._data[encodedkey] 692 except KeyError: 693 # raise KeyError with the original key value 694 raise KeyError(key) from None 695 696 def __iter__(self): 697 # list() from dict object is an atomic operation 698 keys = list(self._data) 699 for key in keys: 700 yield self.decodekey(key) 701 702 def __len__(self): 703 return len(self._data) 704 705 def __repr__(self): 706 formatted_items = ", ".join( 707 f"{self.decodekey(key)!r}: {self.decodevalue(value)!r}" 708 for key, value in self._data.items() 709 ) 710 return f"environ({{{formatted_items}}})" 711 712 def copy(self): 713 return dict(self) 714 715 def setdefault(self, key, value): 716 if key not in self: 717 self[key] = value 718 return self[key] 719 720 def __ior__(self, other): 721 self.update(other) 722 return self 723 724 def __or__(self, other): 725 if not isinstance(other, Mapping): 726 return NotImplemented 727 new = dict(self) 728 new.update(other) 729 return new 730 731 def __ror__(self, other): 732 if not isinstance(other, Mapping): 733 return NotImplemented 734 new = dict(other) 735 new.update(self) 736 return new 737 738def _createenviron(): 739 if name == 'nt': 740 # Where Env Var Names Must Be UPPERCASE 741 def check_str(value): 742 if not isinstance(value, str): 743 raise TypeError("str expected, not %s" % type(value).__name__) 744 return value 745 encode = check_str 746 decode = str 747 def encodekey(key): 748 return encode(key).upper() 749 data = {} 750 for key, value in environ.items(): 751 data[encodekey(key)] = value 752 else: 753 # Where Env Var Names Can Be Mixed Case 754 encoding = sys.getfilesystemencoding() 755 def encode(value): 756 if not isinstance(value, str): 757 raise TypeError("str expected, not %s" % type(value).__name__) 758 return value.encode(encoding, 'surrogateescape') 759 def decode(value): 760 return value.decode(encoding, 'surrogateescape') 761 encodekey = encode 762 data = environ 763 return _Environ(data, 764 encodekey, decode, 765 encode, decode) 766 767# unicode environ 768environ = _createenviron() 769del _createenviron 770 771 772def getenv(key, default=None): 773 """Get an environment variable, return None if it doesn't exist. 774 The optional second argument can specify an alternate default. 775 key, default and the result are str.""" 776 return environ.get(key, default) 777 778supports_bytes_environ = (name != 'nt') 779__all__.extend(("getenv", "supports_bytes_environ")) 780 781if supports_bytes_environ: 782 def _check_bytes(value): 783 if not isinstance(value, bytes): 784 raise TypeError("bytes expected, not %s" % type(value).__name__) 785 return value 786 787 # bytes environ 788 environb = _Environ(environ._data, 789 _check_bytes, bytes, 790 _check_bytes, bytes) 791 del _check_bytes 792 793 def getenvb(key, default=None): 794 """Get an environment variable, return None if it doesn't exist. 795 The optional second argument can specify an alternate default. 796 key, default and the result are bytes.""" 797 return environb.get(key, default) 798 799 __all__.extend(("environb", "getenvb")) 800 801def _fscodec(): 802 encoding = sys.getfilesystemencoding() 803 errors = sys.getfilesystemencodeerrors() 804 805 def fsencode(filename): 806 """Encode filename (an os.PathLike, bytes, or str) to the filesystem 807 encoding with 'surrogateescape' error handler, return bytes unchanged. 808 On Windows, use 'strict' error handler if the file system encoding is 809 'mbcs' (which is the default encoding). 810 """ 811 filename = fspath(filename) # Does type-checking of `filename`. 812 if isinstance(filename, str): 813 return filename.encode(encoding, errors) 814 else: 815 return filename 816 817 def fsdecode(filename): 818 """Decode filename (an os.PathLike, bytes, or str) from the filesystem 819 encoding with 'surrogateescape' error handler, return str unchanged. On 820 Windows, use 'strict' error handler if the file system encoding is 821 'mbcs' (which is the default encoding). 822 """ 823 filename = fspath(filename) # Does type-checking of `filename`. 824 if isinstance(filename, bytes): 825 return filename.decode(encoding, errors) 826 else: 827 return filename 828 829 return fsencode, fsdecode 830 831fsencode, fsdecode = _fscodec() 832del _fscodec 833 834# Supply spawn*() (probably only for Unix) 835if _exists("fork") and not _exists("spawnv") and _exists("execv"): 836 837 P_WAIT = 0 838 P_NOWAIT = P_NOWAITO = 1 839 840 __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"]) 841 842 # XXX Should we support P_DETACH? I suppose it could fork()**2 843 # and close the std I/O streams. Also, P_OVERLAY is the same 844 # as execv*()? 845 846 def _spawnvef(mode, file, args, env, func): 847 # Internal helper; func is the exec*() function to use 848 if not isinstance(args, (tuple, list)): 849 raise TypeError('argv must be a tuple or a list') 850 if not args or not args[0]: 851 raise ValueError('argv first element cannot be empty') 852 pid = fork() 853 if not pid: 854 # Child 855 try: 856 if env is None: 857 func(file, args) 858 else: 859 func(file, args, env) 860 except: 861 _exit(127) 862 else: 863 # Parent 864 if mode == P_NOWAIT: 865 return pid # Caller is responsible for waiting! 866 while 1: 867 wpid, sts = waitpid(pid, 0) 868 if WIFSTOPPED(sts): 869 continue 870 871 return waitstatus_to_exitcode(sts) 872 873 def spawnv(mode, file, args): 874 """spawnv(mode, file, args) -> integer 875 876Execute file with arguments from args in a subprocess. 877If mode == P_NOWAIT return the pid of the process. 878If mode == P_WAIT return the process's exit code if it exits normally; 879otherwise return -SIG, where SIG is the signal that killed it. """ 880 return _spawnvef(mode, file, args, None, execv) 881 882 def spawnve(mode, file, args, env): 883 """spawnve(mode, file, args, env) -> integer 884 885Execute file with arguments from args in a subprocess with the 886specified environment. 887If mode == P_NOWAIT return the pid of the process. 888If mode == P_WAIT return the process's exit code if it exits normally; 889otherwise return -SIG, where SIG is the signal that killed it. """ 890 return _spawnvef(mode, file, args, env, execve) 891 892 # Note: spawnvp[e] isn't currently supported on Windows 893 894 def spawnvp(mode, file, args): 895 """spawnvp(mode, file, args) -> integer 896 897Execute file (which is looked for along $PATH) with arguments from 898args in a subprocess. 899If mode == P_NOWAIT return the pid of the process. 900If mode == P_WAIT return the process's exit code if it exits normally; 901otherwise return -SIG, where SIG is the signal that killed it. """ 902 return _spawnvef(mode, file, args, None, execvp) 903 904 def spawnvpe(mode, file, args, env): 905 """spawnvpe(mode, file, args, env) -> integer 906 907Execute file (which is looked for along $PATH) with arguments from 908args in a subprocess with the supplied environment. 909If mode == P_NOWAIT return the pid of the process. 910If mode == P_WAIT return the process's exit code if it exits normally; 911otherwise return -SIG, where SIG is the signal that killed it. """ 912 return _spawnvef(mode, file, args, env, execvpe) 913 914 915 __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"]) 916 917 918if _exists("spawnv"): 919 # These aren't supplied by the basic Windows code 920 # but can be easily implemented in Python 921 922 def spawnl(mode, file, *args): 923 """spawnl(mode, file, *args) -> integer 924 925Execute file with arguments from args in a subprocess. 926If mode == P_NOWAIT return the pid of the process. 927If mode == P_WAIT return the process's exit code if it exits normally; 928otherwise return -SIG, where SIG is the signal that killed it. """ 929 return spawnv(mode, file, args) 930 931 def spawnle(mode, file, *args): 932 """spawnle(mode, file, *args, env) -> integer 933 934Execute file with arguments from args in a subprocess with the 935supplied environment. 936If mode == P_NOWAIT return the pid of the process. 937If mode == P_WAIT return the process's exit code if it exits normally; 938otherwise return -SIG, where SIG is the signal that killed it. """ 939 env = args[-1] 940 return spawnve(mode, file, args[:-1], env) 941 942 943 __all__.extend(["spawnl", "spawnle"]) 944 945 946if _exists("spawnvp"): 947 # At the moment, Windows doesn't implement spawnvp[e], 948 # so it won't have spawnlp[e] either. 949 def spawnlp(mode, file, *args): 950 """spawnlp(mode, file, *args) -> integer 951 952Execute file (which is looked for along $PATH) with arguments from 953args in a subprocess with the supplied environment. 954If mode == P_NOWAIT return the pid of the process. 955If mode == P_WAIT return the process's exit code if it exits normally; 956otherwise return -SIG, where SIG is the signal that killed it. """ 957 return spawnvp(mode, file, args) 958 959 def spawnlpe(mode, file, *args): 960 """spawnlpe(mode, file, *args, env) -> integer 961 962Execute file (which is looked for along $PATH) with arguments from 963args in a subprocess with the supplied environment. 964If mode == P_NOWAIT return the pid of the process. 965If mode == P_WAIT return the process's exit code if it exits normally; 966otherwise return -SIG, where SIG is the signal that killed it. """ 967 env = args[-1] 968 return spawnvpe(mode, file, args[:-1], env) 969 970 971 __all__.extend(["spawnlp", "spawnlpe"]) 972 973# VxWorks has no user space shell provided. As a result, running 974# command in a shell can't be supported. 975if sys.platform != 'vxworks': 976 # Supply os.popen() 977 def popen(cmd, mode="r", buffering=-1): 978 if not isinstance(cmd, str): 979 raise TypeError("invalid cmd type (%s, expected string)" % type(cmd)) 980 if mode not in ("r", "w"): 981 raise ValueError("invalid mode %r" % mode) 982 if buffering == 0 or buffering is None: 983 raise ValueError("popen() does not support unbuffered streams") 984 import subprocess, io 985 if mode == "r": 986 proc = subprocess.Popen(cmd, 987 shell=True, text=True, 988 stdout=subprocess.PIPE, 989 bufsize=buffering) 990 return _wrap_close(proc.stdout, proc) 991 else: 992 proc = subprocess.Popen(cmd, 993 shell=True, text=True, 994 stdin=subprocess.PIPE, 995 bufsize=buffering) 996 return _wrap_close(proc.stdin, proc) 997 998 # Helper for popen() -- a proxy for a file whose close waits for the process 999 class _wrap_close: 1000 def __init__(self, stream, proc): 1001 self._stream = stream 1002 self._proc = proc 1003 def close(self): 1004 self._stream.close() 1005 returncode = self._proc.wait() 1006 if returncode == 0: 1007 return None 1008 if name == 'nt': 1009 return returncode 1010 else: 1011 return returncode << 8 # Shift left to match old behavior 1012 def __enter__(self): 1013 return self 1014 def __exit__(self, *args): 1015 self.close() 1016 def __getattr__(self, name): 1017 return getattr(self._stream, name) 1018 def __iter__(self): 1019 return iter(self._stream) 1020 1021 __all__.append("popen") 1022 1023# Supply os.fdopen() 1024def fdopen(fd, mode="r", buffering=-1, encoding=None, *args, **kwargs): 1025 if not isinstance(fd, int): 1026 raise TypeError("invalid fd type (%s, expected integer)" % type(fd)) 1027 import io 1028 if "b" not in mode: 1029 encoding = io.text_encoding(encoding) 1030 return io.open(fd, mode, buffering, encoding, *args, **kwargs) 1031 1032 1033# For testing purposes, make sure the function is available when the C 1034# implementation exists. 1035def _fspath(path): 1036 """Return the path representation of a path-like object. 1037 1038 If str or bytes is passed in, it is returned unchanged. Otherwise the 1039 os.PathLike interface is used to get the path representation. If the 1040 path representation is not str or bytes, TypeError is raised. If the 1041 provided path is not str, bytes, or os.PathLike, TypeError is raised. 1042 """ 1043 if isinstance(path, (str, bytes)): 1044 return path 1045 1046 # Work from the object's type to match method resolution of other magic 1047 # methods. 1048 path_type = type(path) 1049 try: 1050 path_repr = path_type.__fspath__(path) 1051 except AttributeError: 1052 if hasattr(path_type, '__fspath__'): 1053 raise 1054 else: 1055 raise TypeError("expected str, bytes or os.PathLike object, " 1056 "not " + path_type.__name__) 1057 if isinstance(path_repr, (str, bytes)): 1058 return path_repr 1059 else: 1060 raise TypeError("expected {}.__fspath__() to return str or bytes, " 1061 "not {}".format(path_type.__name__, 1062 type(path_repr).__name__)) 1063 1064# If there is no C implementation, make the pure Python version the 1065# implementation as transparently as possible. 1066if not _exists('fspath'): 1067 fspath = _fspath 1068 fspath.__name__ = "fspath" 1069 1070 1071class PathLike(abc.ABC): 1072 1073 """Abstract base class for implementing the file system path protocol.""" 1074 1075 @abc.abstractmethod 1076 def __fspath__(self): 1077 """Return the file system path representation of the object.""" 1078 raise NotImplementedError 1079 1080 @classmethod 1081 def __subclasshook__(cls, subclass): 1082 if cls is PathLike: 1083 return _check_methods(subclass, '__fspath__') 1084 return NotImplemented 1085 1086 __class_getitem__ = classmethod(GenericAlias) 1087 1088 1089if name == 'nt': 1090 class _AddedDllDirectory: 1091 def __init__(self, path, cookie, remove_dll_directory): 1092 self.path = path 1093 self._cookie = cookie 1094 self._remove_dll_directory = remove_dll_directory 1095 def close(self): 1096 self._remove_dll_directory(self._cookie) 1097 self.path = None 1098 def __enter__(self): 1099 return self 1100 def __exit__(self, *args): 1101 self.close() 1102 def __repr__(self): 1103 if self.path: 1104 return "<AddedDllDirectory({!r})>".format(self.path) 1105 return "<AddedDllDirectory()>" 1106 1107 def add_dll_directory(path): 1108 """Add a path to the DLL search path. 1109 1110 This search path is used when resolving dependencies for imported 1111 extension modules (the module itself is resolved through sys.path), 1112 and also by ctypes. 1113 1114 Remove the directory by calling close() on the returned object or 1115 using it in a with statement. 1116 """ 1117 import nt 1118 cookie = nt._add_dll_directory(path) 1119 return _AddedDllDirectory( 1120 path, 1121 cookie, 1122 nt._remove_dll_directory 1123 ) 1124