1 r"""OS routines for NT or Posix depending on what system we're on.
2
3 This 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
17 Programs that import and use 'os' stand a better chance of being
18 portable between different platforms. Of course, they must then
19 only use functions that are defined by all platforms (e.g., unlink
20 and opendir), and leave all pathname manipulation to os.path
21 (e.g., split and join).
22 """
23
24 #'
25 import abc
26 import sys
27 import stat as st
28
29 from _collections_abc import _check_methods
30
31 GenericAlias = 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
41 def _exists(name):
42 return name in globals()
43
44 def _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.
52 if '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
72 elif '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
92 else:
93 raise ImportError('no os specific module found')
94
95 sys.modules['os.path'] = path
96 from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep,
97 devnull)
98
99 del _names
100
101
102 if _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
193 SEEK_SET = 0
194 SEEK_CUR = 1
195 SEEK_END = 2
196
197 # Super directory utilities.
198 # (Inspired by Eric Raymond; the doc strings are mostly his)
199
200 def 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
232 def 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
254 def 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
282 def 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 (including symlinks to directories,
292 and excluding '.' and '..').
293 filenames is a list of the names of the non-directory files in dirpath.
294 Note that the names in the lists are just names, with no path components.
295 To get a full path (which begins with top) to a file or directory in
296 dirpath, do os.path.join(dirpath, name).
297
298 If optional arg 'topdown' is true or not specified, the triple for a
299 directory is generated before the triples for any of its subdirectories
300 (directories are generated top down). If topdown is false, the triple
301 for a directory is generated after the triples for all of its
302 subdirectories (directories are generated bottom up).
303
304 When topdown is true, the caller can modify the dirnames list in-place
305 (e.g., via del or slice assignment), and walk will only recurse into the
306 subdirectories whose names remain in dirnames; this can be used to prune the
307 search, or to impose a specific order of visiting. Modifying dirnames when
308 topdown is false has no effect on the behavior of os.walk(), since the
309 directories in dirnames have already been generated by the time dirnames
310 itself is generated. No matter the value of topdown, the list of
311 subdirectories is retrieved before the tuples for the directory and its
312 subdirectories are generated.
313
314 By default errors from the os.scandir() call are ignored. If
315 optional arg 'onerror' is specified, it should be a function; it
316 will be called with one argument, an OSError instance. It can
317 report the error to continue with the walk, or raise the exception
318 to abort the walk. Note that the filename is available as the
319 filename attribute of the exception object.
320
321 By default, os.walk does not follow symbolic links to subdirectories on
322 systems that support them. In order to get this functionality, set the
323 optional argument 'followlinks' to true.
324
325 Caution: if you pass a relative pathname for top, don't change the
326 current working directory between resumptions of walk. walk never
327 changes the current directory, and assumes that the client doesn't
328 either.
329
330 Example:
331
332 import os
333 from os.path import join, getsize
334 for root, dirs, files in os.walk('python/Lib/email'):
335 print(root, "consumes ")
336 print(sum(getsize(join(root, name)) for name in files), end=" ")
337 print("bytes in", len(files), "non-directory files")
338 if 'CVS' in dirs:
339 dirs.remove('CVS') # don't visit CVS directories
340
341 """
342 sys.audit("os.walk", top, topdown, onerror, followlinks)
343 return _walk(fspath(top), topdown, onerror, followlinks)
344
345 def _walk(top, topdown, onerror, followlinks):
346 dirs = []
347 nondirs = []
348 walk_dirs = []
349
350 # We may not have read permission for top, in which case we can't
351 # get a list of the files the directory contains. os.walk
352 # always suppressed the exception then, rather than blow up for a
353 # minor reason when (say) a thousand readable directories are still
354 # left to visit. That logic is copied here.
355 try:
356 # Note that scandir is global in this module due
357 # to earlier import-*.
358 scandir_it = scandir(top)
359 except OSError as error:
360 if onerror is not None:
361 onerror(error)
362 return
363
364 with scandir_it:
365 while True:
366 try:
367 try:
368 entry = next(scandir_it)
369 except StopIteration:
370 break
371 except OSError as error:
372 if onerror is not None:
373 onerror(error)
374 return
375
376 try:
377 is_dir = entry.is_dir()
378 except OSError:
379 # If is_dir() raises an OSError, consider that the entry is not
380 # a directory, same behaviour than os.path.isdir().
381 is_dir = False
382
383 if is_dir:
384 dirs.append(entry.name)
385 else:
386 nondirs.append(entry.name)
387
388 if not topdown and is_dir:
389 # Bottom-up: recurse into sub-directory, but exclude symlinks to
390 # directories if followlinks is False
391 if followlinks:
392 walk_into = True
393 else:
394 try:
395 is_symlink = entry.is_symlink()
396 except OSError:
397 # If is_symlink() raises an OSError, consider that the
398 # entry is not a symbolic link, same behaviour than
399 # os.path.islink().
400 is_symlink = False
401 walk_into = not is_symlink
402
403 if walk_into:
404 walk_dirs.append(entry.path)
405
406 # Yield before recursion if going top down
407 if topdown:
408 yield top, dirs, nondirs
409
410 # Recurse into sub-directories
411 islink, join = path.islink, path.join
412 for dirname in dirs:
413 new_path = join(top, dirname)
414 # Issue #23605: os.path.islink() is used instead of caching
415 # entry.is_symlink() result during the loop on os.scandir() because
416 # the caller can replace the directory entry during the "yield"
417 # above.
418 if followlinks or not islink(new_path):
419 yield from _walk(new_path, topdown, onerror, followlinks)
420 else:
421 # Recurse into sub-directories
422 for new_path in walk_dirs:
423 yield from _walk(new_path, topdown, onerror, followlinks)
424 # Yield after recursion if going bottom up
425 yield top, dirs, nondirs
426
427 __all__.append("walk")
428
429 if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
430
431 def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir_fd=None):
432 """Directory tree generator.
433
434 This behaves exactly like walk(), except that it yields a 4-tuple
435
436 dirpath, dirnames, filenames, dirfd
437
438 `dirpath`, `dirnames` and `filenames` are identical to walk() output,
439 and `dirfd` is a file descriptor referring to the directory `dirpath`.
440
441 The advantage of fwalk() over walk() is that it's safe against symlink
442 races (when follow_symlinks is False).
443
444 If dir_fd is not None, it should be a file descriptor open to a directory,
445 and top should be relative; top will then be relative to that directory.
446 (dir_fd is always supported for fwalk.)
447
448 Caution:
449 Since fwalk() yields file descriptors, those are only valid until the
450 next iteration step, so you should dup() them if you want to keep them
451 for a longer period.
452
453 Example:
454
455 import os
456 for root, dirs, files, rootfd in os.fwalk('python/Lib/email'):
457 print(root, "consumes", end="")
458 print(sum(os.stat(name, dir_fd=rootfd).st_size for name in files),
459 end="")
460 print("bytes in", len(files), "non-directory files")
461 if 'CVS' in dirs:
462 dirs.remove('CVS') # don't visit CVS directories
463 """
464 sys.audit("os.fwalk", top, topdown, onerror, follow_symlinks, dir_fd)
465 top = fspath(top)
466 # Note: To guard against symlink races, we use the standard
467 # lstat()/open()/fstat() trick.
468 if not follow_symlinks:
469 orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
470 topfd = open(top, O_RDONLY, dir_fd=dir_fd)
471 try:
472 if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
473 path.samestat(orig_st, stat(topfd)))):
474 yield from _fwalk(topfd, top, isinstance(top, bytes),
475 topdown, onerror, follow_symlinks)
476 finally:
477 close(topfd)
478
479 def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
480 # Note: This uses O(depth of the directory tree) file descriptors: if
481 # necessary, it can be adapted to only require O(1) FDs, see issue
482 # #13734.
483
484 scandir_it = scandir(topfd)
485 dirs = []
486 nondirs = []
487 entries = None if topdown or follow_symlinks else []
488 for entry in scandir_it:
489 name = entry.name
490 if isbytes:
491 name = fsencode(name)
492 try:
493 if entry.is_dir():
494 dirs.append(name)
495 if entries is not None:
496 entries.append(entry)
497 else:
498 nondirs.append(name)
499 except OSError:
500 try:
501 # Add dangling symlinks, ignore disappeared files
502 if entry.is_symlink():
503 nondirs.append(name)
504 except OSError:
505 pass
506
507 if topdown:
508 yield toppath, dirs, nondirs, topfd
509
510 for name in dirs if entries is None else zip(dirs, entries):
511 try:
512 if not follow_symlinks:
513 if topdown:
514 orig_st = stat(name, dir_fd=topfd, follow_symlinks=False)
515 else:
516 assert entries is not None
517 name, entry = name
518 orig_st = entry.stat(follow_symlinks=False)
519 dirfd = open(name, O_RDONLY, dir_fd=topfd)
520 except OSError as err:
521 if onerror is not None:
522 onerror(err)
523 continue
524 try:
525 if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
526 dirpath = path.join(toppath, name)
527 yield from _fwalk(dirfd, dirpath, isbytes,
528 topdown, onerror, follow_symlinks)
529 finally:
530 close(dirfd)
531
532 if not topdown:
533 yield toppath, dirs, nondirs, topfd
534
535 __all__.append("fwalk")
536
537 def execl(file, *args):
538 """execl(file, *args)
539
540 Execute the executable file with argument list args, replacing the
541 current process. """
542 execv(file, args)
543
544 def execle(file, *args):
545 """execle(file, *args, env)
546
547 Execute the executable file with argument list args and
548 environment env, replacing the current process. """
549 env = args[-1]
550 execve(file, args[:-1], env)
551
552 def execlp(file, *args):
553 """execlp(file, *args)
554
555 Execute the executable file (which is searched for along $PATH)
556 with argument list args, replacing the current process. """
557 execvp(file, args)
558
559 def execlpe(file, *args):
560 """execlpe(file, *args, env)
561
562 Execute the executable file (which is searched for along $PATH)
563 with argument list args and environment env, replacing the current
564 process. """
565 env = args[-1]
566 execvpe(file, args[:-1], env)
567
568 def execvp(file, args):
569 """execvp(file, args)
570
571 Execute the executable file (which is searched for along $PATH)
572 with argument list args, replacing the current process.
573 args may be a list or tuple of strings. """
574 _execvpe(file, args)
575
576 def execvpe(file, args, env):
577 """execvpe(file, args, env)
578
579 Execute the executable file (which is searched for along $PATH)
580 with argument list args and environment env, replacing the
581 current process.
582 args may be a list or tuple of strings. """
583 _execvpe(file, args, env)
584
585 __all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
586
587 def _execvpe(file, args, env=None):
588 if env is not None:
589 exec_func = execve
590 argrest = (args, env)
591 else:
592 exec_func = execv
593 argrest = (args,)
594 env = environ
595
596 if path.dirname(file):
597 exec_func(file, *argrest)
598 return
599 saved_exc = None
600 path_list = get_exec_path(env)
601 if name != 'nt':
602 file = fsencode(file)
603 path_list = map(fsencode, path_list)
604 for dir in path_list:
605 fullname = path.join(dir, file)
606 try:
607 exec_func(fullname, *argrest)
608 except (FileNotFoundError, NotADirectoryError) as e:
609 last_exc = e
610 except OSError as e:
611 last_exc = e
612 if saved_exc is None:
613 saved_exc = e
614 if saved_exc is not None:
615 raise saved_exc
616 raise last_exc
617
618
619 def get_exec_path(env=None):
620 """Returns the sequence of directories that will be searched for the
621 named executable (similar to a shell) when launching a process.
622
623 *env* must be an environment variable dict or None. If *env* is None,
624 os.environ will be used.
625 """
626 # Use a local import instead of a global import to limit the number of
627 # modules loaded at startup: the os module is always loaded at startup by
628 # Python. It may also avoid a bootstrap issue.
629 import warnings
630
631 if env is None:
632 env = environ
633
634 # {b'PATH': ...}.get('PATH') and {'PATH': ...}.get(b'PATH') emit a
635 # BytesWarning when using python -b or python -bb: ignore the warning
636 with warnings.catch_warnings():
637 warnings.simplefilter("ignore", BytesWarning)
638
639 try:
640 path_list = env.get('PATH')
641 except TypeError:
642 path_list = None
643
644 if supports_bytes_environ:
645 try:
646 path_listb = env[b'PATH']
647 except (KeyError, TypeError):
648 pass
649 else:
650 if path_list is not None:
651 raise ValueError(
652 "env cannot contain 'PATH' and b'PATH' keys")
653 path_list = path_listb
654
655 if path_list is not None and isinstance(path_list, bytes):
656 path_list = fsdecode(path_list)
657
658 if path_list is None:
659 path_list = defpath
660 return path_list.split(pathsep)
661
662
663 # Change environ to automatically call putenv() and unsetenv()
664 from _collections_abc import MutableMapping, Mapping
665
666 class ESC[4;38;5;81m_Environ(ESC[4;38;5;149mMutableMapping):
667 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue):
668 self.encodekey = encodekey
669 self.decodekey = decodekey
670 self.encodevalue = encodevalue
671 self.decodevalue = decodevalue
672 self._data = data
673
674 def __getitem__(self, key):
675 try:
676 value = self._data[self.encodekey(key)]
677 except KeyError:
678 # raise KeyError with the original key value
679 raise KeyError(key) from None
680 return self.decodevalue(value)
681
682 def __setitem__(self, key, value):
683 key = self.encodekey(key)
684 value = self.encodevalue(value)
685 putenv(key, value)
686 self._data[key] = value
687
688 def __delitem__(self, key):
689 encodedkey = self.encodekey(key)
690 unsetenv(encodedkey)
691 try:
692 del self._data[encodedkey]
693 except KeyError:
694 # raise KeyError with the original key value
695 raise KeyError(key) from None
696
697 def __iter__(self):
698 # list() from dict object is an atomic operation
699 keys = list(self._data)
700 for key in keys:
701 yield self.decodekey(key)
702
703 def __len__(self):
704 return len(self._data)
705
706 def __repr__(self):
707 formatted_items = ", ".join(
708 f"{self.decodekey(key)!r}: {self.decodevalue(value)!r}"
709 for key, value in self._data.items()
710 )
711 return f"environ({{{formatted_items}}})"
712
713 def copy(self):
714 return dict(self)
715
716 def setdefault(self, key, value):
717 if key not in self:
718 self[key] = value
719 return self[key]
720
721 def __ior__(self, other):
722 self.update(other)
723 return self
724
725 def __or__(self, other):
726 if not isinstance(other, Mapping):
727 return NotImplemented
728 new = dict(self)
729 new.update(other)
730 return new
731
732 def __ror__(self, other):
733 if not isinstance(other, Mapping):
734 return NotImplemented
735 new = dict(other)
736 new.update(self)
737 return new
738
739 def _createenviron():
740 if name == 'nt':
741 # Where Env Var Names Must Be UPPERCASE
742 def check_str(value):
743 if not isinstance(value, str):
744 raise TypeError("str expected, not %s" % type(value).__name__)
745 return value
746 encode = check_str
747 decode = str
748 def encodekey(key):
749 return encode(key).upper()
750 data = {}
751 for key, value in environ.items():
752 data[encodekey(key)] = value
753 else:
754 # Where Env Var Names Can Be Mixed Case
755 encoding = sys.getfilesystemencoding()
756 def encode(value):
757 if not isinstance(value, str):
758 raise TypeError("str expected, not %s" % type(value).__name__)
759 return value.encode(encoding, 'surrogateescape')
760 def decode(value):
761 return value.decode(encoding, 'surrogateescape')
762 encodekey = encode
763 data = environ
764 return _Environ(data,
765 encodekey, decode,
766 encode, decode)
767
768 # unicode environ
769 environ = _createenviron()
770 del _createenviron
771
772
773 def getenv(key, default=None):
774 """Get an environment variable, return None if it doesn't exist.
775 The optional second argument can specify an alternate default.
776 key, default and the result are str."""
777 return environ.get(key, default)
778
779 supports_bytes_environ = (name != 'nt')
780 __all__.extend(("getenv", "supports_bytes_environ"))
781
782 if supports_bytes_environ:
783 def _check_bytes(value):
784 if not isinstance(value, bytes):
785 raise TypeError("bytes expected, not %s" % type(value).__name__)
786 return value
787
788 # bytes environ
789 environb = _Environ(environ._data,
790 _check_bytes, bytes,
791 _check_bytes, bytes)
792 del _check_bytes
793
794 def getenvb(key, default=None):
795 """Get an environment variable, return None if it doesn't exist.
796 The optional second argument can specify an alternate default.
797 key, default and the result are bytes."""
798 return environb.get(key, default)
799
800 __all__.extend(("environb", "getenvb"))
801
802 def _fscodec():
803 encoding = sys.getfilesystemencoding()
804 errors = sys.getfilesystemencodeerrors()
805
806 def fsencode(filename):
807 """Encode filename (an os.PathLike, bytes, or str) to the filesystem
808 encoding with 'surrogateescape' error handler, return bytes unchanged.
809 On Windows, use 'strict' error handler if the file system encoding is
810 'mbcs' (which is the default encoding).
811 """
812 filename = fspath(filename) # Does type-checking of `filename`.
813 if isinstance(filename, str):
814 return filename.encode(encoding, errors)
815 else:
816 return filename
817
818 def fsdecode(filename):
819 """Decode filename (an os.PathLike, bytes, or str) from the filesystem
820 encoding with 'surrogateescape' error handler, return str unchanged. On
821 Windows, use 'strict' error handler if the file system encoding is
822 'mbcs' (which is the default encoding).
823 """
824 filename = fspath(filename) # Does type-checking of `filename`.
825 if isinstance(filename, bytes):
826 return filename.decode(encoding, errors)
827 else:
828 return filename
829
830 return fsencode, fsdecode
831
832 fsencode, fsdecode = _fscodec()
833 del _fscodec
834
835 # Supply spawn*() (probably only for Unix)
836 if _exists("fork") and not _exists("spawnv") and _exists("execv"):
837
838 P_WAIT = 0
839 P_NOWAIT = P_NOWAITO = 1
840
841 __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"])
842
843 # XXX Should we support P_DETACH? I suppose it could fork()**2
844 # and close the std I/O streams. Also, P_OVERLAY is the same
845 # as execv*()?
846
847 def _spawnvef(mode, file, args, env, func):
848 # Internal helper; func is the exec*() function to use
849 if not isinstance(args, (tuple, list)):
850 raise TypeError('argv must be a tuple or a list')
851 if not args or not args[0]:
852 raise ValueError('argv first element cannot be empty')
853 pid = fork()
854 if not pid:
855 # Child
856 try:
857 if env is None:
858 func(file, args)
859 else:
860 func(file, args, env)
861 except:
862 _exit(127)
863 else:
864 # Parent
865 if mode == P_NOWAIT:
866 return pid # Caller is responsible for waiting!
867 while 1:
868 wpid, sts = waitpid(pid, 0)
869 if WIFSTOPPED(sts):
870 continue
871
872 return waitstatus_to_exitcode(sts)
873
874 def spawnv(mode, file, args):
875 """spawnv(mode, file, args) -> integer
876
877 Execute file with arguments from args in a subprocess.
878 If mode == P_NOWAIT return the pid of the process.
879 If mode == P_WAIT return the process's exit code if it exits normally;
880 otherwise return -SIG, where SIG is the signal that killed it. """
881 return _spawnvef(mode, file, args, None, execv)
882
883 def spawnve(mode, file, args, env):
884 """spawnve(mode, file, args, env) -> integer
885
886 Execute file with arguments from args in a subprocess with the
887 specified environment.
888 If mode == P_NOWAIT return the pid of the process.
889 If mode == P_WAIT return the process's exit code if it exits normally;
890 otherwise return -SIG, where SIG is the signal that killed it. """
891 return _spawnvef(mode, file, args, env, execve)
892
893 # Note: spawnvp[e] isn't currently supported on Windows
894
895 def spawnvp(mode, file, args):
896 """spawnvp(mode, file, args) -> integer
897
898 Execute file (which is looked for along $PATH) with arguments from
899 args in a subprocess.
900 If mode == P_NOWAIT return the pid of the process.
901 If mode == P_WAIT return the process's exit code if it exits normally;
902 otherwise return -SIG, where SIG is the signal that killed it. """
903 return _spawnvef(mode, file, args, None, execvp)
904
905 def spawnvpe(mode, file, args, env):
906 """spawnvpe(mode, file, args, env) -> integer
907
908 Execute file (which is looked for along $PATH) with arguments from
909 args in a subprocess with the supplied environment.
910 If mode == P_NOWAIT return the pid of the process.
911 If mode == P_WAIT return the process's exit code if it exits normally;
912 otherwise return -SIG, where SIG is the signal that killed it. """
913 return _spawnvef(mode, file, args, env, execvpe)
914
915
916 __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"])
917
918
919 if _exists("spawnv"):
920 # These aren't supplied by the basic Windows code
921 # but can be easily implemented in Python
922
923 def spawnl(mode, file, *args):
924 """spawnl(mode, file, *args) -> integer
925
926 Execute file with arguments from args in a subprocess.
927 If mode == P_NOWAIT return the pid of the process.
928 If mode == P_WAIT return the process's exit code if it exits normally;
929 otherwise return -SIG, where SIG is the signal that killed it. """
930 return spawnv(mode, file, args)
931
932 def spawnle(mode, file, *args):
933 """spawnle(mode, file, *args, env) -> integer
934
935 Execute file with arguments from args in a subprocess with the
936 supplied environment.
937 If mode == P_NOWAIT return the pid of the process.
938 If mode == P_WAIT return the process's exit code if it exits normally;
939 otherwise return -SIG, where SIG is the signal that killed it. """
940 env = args[-1]
941 return spawnve(mode, file, args[:-1], env)
942
943
944 __all__.extend(["spawnl", "spawnle"])
945
946
947 if _exists("spawnvp"):
948 # At the moment, Windows doesn't implement spawnvp[e],
949 # so it won't have spawnlp[e] either.
950 def spawnlp(mode, file, *args):
951 """spawnlp(mode, file, *args) -> integer
952
953 Execute file (which is looked for along $PATH) with arguments from
954 args in a subprocess with the supplied environment.
955 If mode == P_NOWAIT return the pid of the process.
956 If mode == P_WAIT return the process's exit code if it exits normally;
957 otherwise return -SIG, where SIG is the signal that killed it. """
958 return spawnvp(mode, file, args)
959
960 def spawnlpe(mode, file, *args):
961 """spawnlpe(mode, file, *args, env) -> integer
962
963 Execute file (which is looked for along $PATH) with arguments from
964 args in a subprocess with the supplied environment.
965 If mode == P_NOWAIT return the pid of the process.
966 If mode == P_WAIT return the process's exit code if it exits normally;
967 otherwise return -SIG, where SIG is the signal that killed it. """
968 env = args[-1]
969 return spawnvpe(mode, file, args[:-1], env)
970
971
972 __all__.extend(["spawnlp", "spawnlpe"])
973
974 # VxWorks has no user space shell provided. As a result, running
975 # command in a shell can't be supported.
976 if sys.platform != 'vxworks':
977 # Supply os.popen()
978 def popen(cmd, mode="r", buffering=-1):
979 if not isinstance(cmd, str):
980 raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
981 if mode not in ("r", "w"):
982 raise ValueError("invalid mode %r" % mode)
983 if buffering == 0 or buffering is None:
984 raise ValueError("popen() does not support unbuffered streams")
985 import subprocess
986 if mode == "r":
987 proc = subprocess.Popen(cmd,
988 shell=True, text=True,
989 stdout=subprocess.PIPE,
990 bufsize=buffering)
991 return _wrap_close(proc.stdout, proc)
992 else:
993 proc = subprocess.Popen(cmd,
994 shell=True, text=True,
995 stdin=subprocess.PIPE,
996 bufsize=buffering)
997 return _wrap_close(proc.stdin, proc)
998
999 # Helper for popen() -- a proxy for a file whose close waits for the process
1000 class ESC[4;38;5;81m_wrap_close:
1001 def __init__(self, stream, proc):
1002 self._stream = stream
1003 self._proc = proc
1004 def close(self):
1005 self._stream.close()
1006 returncode = self._proc.wait()
1007 if returncode == 0:
1008 return None
1009 if name == 'nt':
1010 return returncode
1011 else:
1012 return returncode << 8 # Shift left to match old behavior
1013 def __enter__(self):
1014 return self
1015 def __exit__(self, *args):
1016 self.close()
1017 def __getattr__(self, name):
1018 return getattr(self._stream, name)
1019 def __iter__(self):
1020 return iter(self._stream)
1021
1022 __all__.append("popen")
1023
1024 # Supply os.fdopen()
1025 def fdopen(fd, mode="r", buffering=-1, encoding=None, *args, **kwargs):
1026 if not isinstance(fd, int):
1027 raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
1028 import io
1029 if "b" not in mode:
1030 encoding = io.text_encoding(encoding)
1031 return io.open(fd, mode, buffering, encoding, *args, **kwargs)
1032
1033
1034 # For testing purposes, make sure the function is available when the C
1035 # implementation exists.
1036 def _fspath(path):
1037 """Return the path representation of a path-like object.
1038
1039 If str or bytes is passed in, it is returned unchanged. Otherwise the
1040 os.PathLike interface is used to get the path representation. If the
1041 path representation is not str or bytes, TypeError is raised. If the
1042 provided path is not str, bytes, or os.PathLike, TypeError is raised.
1043 """
1044 if isinstance(path, (str, bytes)):
1045 return path
1046
1047 # Work from the object's type to match method resolution of other magic
1048 # methods.
1049 path_type = type(path)
1050 try:
1051 path_repr = path_type.__fspath__(path)
1052 except AttributeError:
1053 if hasattr(path_type, '__fspath__'):
1054 raise
1055 else:
1056 raise TypeError("expected str, bytes or os.PathLike object, "
1057 "not " + path_type.__name__)
1058 if isinstance(path_repr, (str, bytes)):
1059 return path_repr
1060 else:
1061 raise TypeError("expected {}.__fspath__() to return str or bytes, "
1062 "not {}".format(path_type.__name__,
1063 type(path_repr).__name__))
1064
1065 # If there is no C implementation, make the pure Python version the
1066 # implementation as transparently as possible.
1067 if not _exists('fspath'):
1068 fspath = _fspath
1069 fspath.__name__ = "fspath"
1070
1071
1072 class ESC[4;38;5;81mPathLike(ESC[4;38;5;149mabcESC[4;38;5;149m.ESC[4;38;5;149mABC):
1073
1074 """Abstract base class for implementing the file system path protocol."""
1075
1076 @abc.abstractmethod
1077 def __fspath__(self):
1078 """Return the file system path representation of the object."""
1079 raise NotImplementedError
1080
1081 @classmethod
1082 def __subclasshook__(cls, subclass):
1083 if cls is PathLike:
1084 return _check_methods(subclass, '__fspath__')
1085 return NotImplemented
1086
1087 __class_getitem__ = classmethod(GenericAlias)
1088
1089
1090 if name == 'nt':
1091 class ESC[4;38;5;81m_AddedDllDirectory:
1092 def __init__(self, path, cookie, remove_dll_directory):
1093 self.path = path
1094 self._cookie = cookie
1095 self._remove_dll_directory = remove_dll_directory
1096 def close(self):
1097 self._remove_dll_directory(self._cookie)
1098 self.path = None
1099 def __enter__(self):
1100 return self
1101 def __exit__(self, *args):
1102 self.close()
1103 def __repr__(self):
1104 if self.path:
1105 return "<AddedDllDirectory({!r})>".format(self.path)
1106 return "<AddedDllDirectory()>"
1107
1108 def add_dll_directory(path):
1109 """Add a path to the DLL search path.
1110
1111 This search path is used when resolving dependencies for imported
1112 extension modules (the module itself is resolved through sys.path),
1113 and also by ctypes.
1114
1115 Remove the directory by calling close() on the returned object or
1116 using it in a with statement.
1117 """
1118 import nt
1119 cookie = nt._add_dll_directory(path)
1120 return _AddedDllDirectory(
1121 path,
1122 cookie,
1123 nt._remove_dll_directory
1124 )