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