Coverage for /pythoncovmergedfiles/medio/medio/usr/lib/python3.9/os.py: 1%

571 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 07:00 +0000

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 "popen", "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 if not isinstance(top, int) or not hasattr(top, '__index__'): 

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 

537def 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 

544def 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 

552def 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 

559def 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 

568def 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 

576def 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 

587def _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 

619def 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() 

664from _collections_abc import MutableMapping, Mapping 

665 

666class _Environ(MutableMapping): 

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 return 'environ({{{}}})'.format(', '.join( 

708 ('{!r}: {!r}'.format(self.decodekey(key), self.decodevalue(value)) 

709 for key, value in self._data.items()))) 

710 

711 def copy(self): 

712 return dict(self) 

713 

714 def setdefault(self, key, value): 

715 if key not in self: 

716 self[key] = value 

717 return self[key] 

718 

719 def __ior__(self, other): 

720 self.update(other) 

721 return self 

722 

723 def __or__(self, other): 

724 if not isinstance(other, Mapping): 

725 return NotImplemented 

726 new = dict(self) 

727 new.update(other) 

728 return new 

729 

730 def __ror__(self, other): 

731 if not isinstance(other, Mapping): 

732 return NotImplemented 

733 new = dict(other) 

734 new.update(self) 

735 return new 

736 

737def _createenviron(): 

738 if name == 'nt': 

739 # Where Env Var Names Must Be UPPERCASE 

740 def check_str(value): 

741 if not isinstance(value, str): 

742 raise TypeError("str expected, not %s" % type(value).__name__) 

743 return value 

744 encode = check_str 

745 decode = str 

746 def encodekey(key): 

747 return encode(key).upper() 

748 data = {} 

749 for key, value in environ.items(): 

750 data[encodekey(key)] = value 

751 else: 

752 # Where Env Var Names Can Be Mixed Case 

753 encoding = sys.getfilesystemencoding() 

754 def encode(value): 

755 if not isinstance(value, str): 

756 raise TypeError("str expected, not %s" % type(value).__name__) 

757 return value.encode(encoding, 'surrogateescape') 

758 def decode(value): 

759 return value.decode(encoding, 'surrogateescape') 

760 encodekey = encode 

761 data = environ 

762 return _Environ(data, 

763 encodekey, decode, 

764 encode, decode) 

765 

766# unicode environ 

767environ = _createenviron() 

768del _createenviron 

769 

770 

771def getenv(key, default=None): 

772 """Get an environment variable, return None if it doesn't exist. 

773 The optional second argument can specify an alternate default. 

774 key, default and the result are str.""" 

775 return environ.get(key, default) 

776 

777supports_bytes_environ = (name != 'nt') 

778__all__.extend(("getenv", "supports_bytes_environ")) 

779 

780if supports_bytes_environ: 

781 def _check_bytes(value): 

782 if not isinstance(value, bytes): 

783 raise TypeError("bytes expected, not %s" % type(value).__name__) 

784 return value 

785 

786 # bytes environ 

787 environb = _Environ(environ._data, 

788 _check_bytes, bytes, 

789 _check_bytes, bytes) 

790 del _check_bytes 

791 

792 def getenvb(key, default=None): 

793 """Get an environment variable, return None if it doesn't exist. 

794 The optional second argument can specify an alternate default. 

795 key, default and the result are bytes.""" 

796 return environb.get(key, default) 

797 

798 __all__.extend(("environb", "getenvb")) 

799 

800def _fscodec(): 

801 encoding = sys.getfilesystemencoding() 

802 errors = sys.getfilesystemencodeerrors() 

803 

804 def fsencode(filename): 

805 """Encode filename (an os.PathLike, bytes, or str) to the filesystem 

806 encoding with 'surrogateescape' error handler, return bytes unchanged. 

807 On Windows, use 'strict' error handler if the file system encoding is 

808 'mbcs' (which is the default encoding). 

809 """ 

810 filename = fspath(filename) # Does type-checking of `filename`. 

811 if isinstance(filename, str): 

812 return filename.encode(encoding, errors) 

813 else: 

814 return filename 

815 

816 def fsdecode(filename): 

817 """Decode filename (an os.PathLike, bytes, or str) from the filesystem 

818 encoding with 'surrogateescape' error handler, return str unchanged. On 

819 Windows, use 'strict' error handler if the file system encoding is 

820 'mbcs' (which is the default encoding). 

821 """ 

822 filename = fspath(filename) # Does type-checking of `filename`. 

823 if isinstance(filename, bytes): 

824 return filename.decode(encoding, errors) 

825 else: 

826 return filename 

827 

828 return fsencode, fsdecode 

829 

830fsencode, fsdecode = _fscodec() 

831del _fscodec 

832 

833# Supply spawn*() (probably only for Unix) 

834if _exists("fork") and not _exists("spawnv") and _exists("execv"): 

835 

836 P_WAIT = 0 

837 P_NOWAIT = P_NOWAITO = 1 

838 

839 __all__.extend(["P_WAIT", "P_NOWAIT", "P_NOWAITO"]) 

840 

841 # XXX Should we support P_DETACH? I suppose it could fork()**2 

842 # and close the std I/O streams. Also, P_OVERLAY is the same 

843 # as execv*()? 

844 

845 def _spawnvef(mode, file, args, env, func): 

846 # Internal helper; func is the exec*() function to use 

847 if not isinstance(args, (tuple, list)): 

848 raise TypeError('argv must be a tuple or a list') 

849 if not args or not args[0]: 

850 raise ValueError('argv first element cannot be empty') 

851 pid = fork() 

852 if not pid: 

853 # Child 

854 try: 

855 if env is None: 

856 func(file, args) 

857 else: 

858 func(file, args, env) 

859 except: 

860 _exit(127) 

861 else: 

862 # Parent 

863 if mode == P_NOWAIT: 

864 return pid # Caller is responsible for waiting! 

865 while 1: 

866 wpid, sts = waitpid(pid, 0) 

867 if WIFSTOPPED(sts): 

868 continue 

869 

870 return waitstatus_to_exitcode(sts) 

871 

872 def spawnv(mode, file, args): 

873 """spawnv(mode, file, args) -> integer 

874 

875Execute file with arguments from args in a subprocess. 

876If mode == P_NOWAIT return the pid of the process. 

877If mode == P_WAIT return the process's exit code if it exits normally; 

878otherwise return -SIG, where SIG is the signal that killed it. """ 

879 return _spawnvef(mode, file, args, None, execv) 

880 

881 def spawnve(mode, file, args, env): 

882 """spawnve(mode, file, args, env) -> integer 

883 

884Execute file with arguments from args in a subprocess with the 

885specified environment. 

886If mode == P_NOWAIT return the pid of the process. 

887If mode == P_WAIT return the process's exit code if it exits normally; 

888otherwise return -SIG, where SIG is the signal that killed it. """ 

889 return _spawnvef(mode, file, args, env, execve) 

890 

891 # Note: spawnvp[e] isn't currently supported on Windows 

892 

893 def spawnvp(mode, file, args): 

894 """spawnvp(mode, file, args) -> integer 

895 

896Execute file (which is looked for along $PATH) with arguments from 

897args in a subprocess. 

898If mode == P_NOWAIT return the pid of the process. 

899If mode == P_WAIT return the process's exit code if it exits normally; 

900otherwise return -SIG, where SIG is the signal that killed it. """ 

901 return _spawnvef(mode, file, args, None, execvp) 

902 

903 def spawnvpe(mode, file, args, env): 

904 """spawnvpe(mode, file, args, env) -> integer 

905 

906Execute file (which is looked for along $PATH) with arguments from 

907args in a subprocess with the supplied environment. 

908If mode == P_NOWAIT return the pid of the process. 

909If mode == P_WAIT return the process's exit code if it exits normally; 

910otherwise return -SIG, where SIG is the signal that killed it. """ 

911 return _spawnvef(mode, file, args, env, execvpe) 

912 

913 

914 __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"]) 

915 

916 

917if _exists("spawnv"): 

918 # These aren't supplied by the basic Windows code 

919 # but can be easily implemented in Python 

920 

921 def spawnl(mode, file, *args): 

922 """spawnl(mode, file, *args) -> integer 

923 

924Execute file with arguments from args in a subprocess. 

925If mode == P_NOWAIT return the pid of the process. 

926If mode == P_WAIT return the process's exit code if it exits normally; 

927otherwise return -SIG, where SIG is the signal that killed it. """ 

928 return spawnv(mode, file, args) 

929 

930 def spawnle(mode, file, *args): 

931 """spawnle(mode, file, *args, env) -> integer 

932 

933Execute file with arguments from args in a subprocess with the 

934supplied environment. 

935If mode == P_NOWAIT return the pid of the process. 

936If mode == P_WAIT return the process's exit code if it exits normally; 

937otherwise return -SIG, where SIG is the signal that killed it. """ 

938 env = args[-1] 

939 return spawnve(mode, file, args[:-1], env) 

940 

941 

942 __all__.extend(["spawnl", "spawnle"]) 

943 

944 

945if _exists("spawnvp"): 

946 # At the moment, Windows doesn't implement spawnvp[e], 

947 # so it won't have spawnlp[e] either. 

948 def spawnlp(mode, file, *args): 

949 """spawnlp(mode, file, *args) -> integer 

950 

951Execute file (which is looked for along $PATH) with arguments from 

952args in a subprocess with the supplied environment. 

953If mode == P_NOWAIT return the pid of the process. 

954If mode == P_WAIT return the process's exit code if it exits normally; 

955otherwise return -SIG, where SIG is the signal that killed it. """ 

956 return spawnvp(mode, file, args) 

957 

958 def spawnlpe(mode, file, *args): 

959 """spawnlpe(mode, file, *args, env) -> integer 

960 

961Execute file (which is looked for along $PATH) with arguments from 

962args in a subprocess with the supplied environment. 

963If mode == P_NOWAIT return the pid of the process. 

964If mode == P_WAIT return the process's exit code if it exits normally; 

965otherwise return -SIG, where SIG is the signal that killed it. """ 

966 env = args[-1] 

967 return spawnvpe(mode, file, args[:-1], env) 

968 

969 

970 __all__.extend(["spawnlp", "spawnlpe"]) 

971 

972 

973# Supply os.popen() 

974def popen(cmd, mode="r", buffering=-1): 

975 if not isinstance(cmd, str): 

976 raise TypeError("invalid cmd type (%s, expected string)" % type(cmd)) 

977 if mode not in ("r", "w"): 

978 raise ValueError("invalid mode %r" % mode) 

979 if buffering == 0 or buffering is None: 

980 raise ValueError("popen() does not support unbuffered streams") 

981 import subprocess, io 

982 if mode == "r": 

983 proc = subprocess.Popen(cmd, 

984 shell=True, 

985 stdout=subprocess.PIPE, 

986 bufsize=buffering) 

987 return _wrap_close(io.TextIOWrapper(proc.stdout), proc) 

988 else: 

989 proc = subprocess.Popen(cmd, 

990 shell=True, 

991 stdin=subprocess.PIPE, 

992 bufsize=buffering) 

993 return _wrap_close(io.TextIOWrapper(proc.stdin), proc) 

994 

995# Helper for popen() -- a proxy for a file whose close waits for the process 

996class _wrap_close: 

997 def __init__(self, stream, proc): 

998 self._stream = stream 

999 self._proc = proc 

1000 def close(self): 

1001 self._stream.close() 

1002 returncode = self._proc.wait() 

1003 if returncode == 0: 

1004 return None 

1005 if name == 'nt': 

1006 return returncode 

1007 else: 

1008 return returncode << 8 # Shift left to match old behavior 

1009 def __enter__(self): 

1010 return self 

1011 def __exit__(self, *args): 

1012 self.close() 

1013 def __getattr__(self, name): 

1014 return getattr(self._stream, name) 

1015 def __iter__(self): 

1016 return iter(self._stream) 

1017 

1018# Supply os.fdopen() 

1019def fdopen(fd, *args, **kwargs): 

1020 if not isinstance(fd, int): 

1021 raise TypeError("invalid fd type (%s, expected integer)" % type(fd)) 

1022 import io 

1023 return io.open(fd, *args, **kwargs) 

1024 

1025 

1026# For testing purposes, make sure the function is available when the C 

1027# implementation exists. 

1028def _fspath(path): 

1029 """Return the path representation of a path-like object. 

1030 

1031 If str or bytes is passed in, it is returned unchanged. Otherwise the 

1032 os.PathLike interface is used to get the path representation. If the 

1033 path representation is not str or bytes, TypeError is raised. If the 

1034 provided path is not str, bytes, or os.PathLike, TypeError is raised. 

1035 """ 

1036 if isinstance(path, (str, bytes)): 

1037 return path 

1038 

1039 # Work from the object's type to match method resolution of other magic 

1040 # methods. 

1041 path_type = type(path) 

1042 try: 

1043 path_repr = path_type.__fspath__(path) 

1044 except AttributeError: 

1045 if hasattr(path_type, '__fspath__'): 

1046 raise 

1047 else: 

1048 raise TypeError("expected str, bytes or os.PathLike object, " 

1049 "not " + path_type.__name__) 

1050 if isinstance(path_repr, (str, bytes)): 

1051 return path_repr 

1052 else: 

1053 raise TypeError("expected {}.__fspath__() to return str or bytes, " 

1054 "not {}".format(path_type.__name__, 

1055 type(path_repr).__name__)) 

1056 

1057# If there is no C implementation, make the pure Python version the 

1058# implementation as transparently as possible. 

1059if not _exists('fspath'): 

1060 fspath = _fspath 

1061 fspath.__name__ = "fspath" 

1062 

1063 

1064class PathLike(abc.ABC): 

1065 

1066 """Abstract base class for implementing the file system path protocol.""" 

1067 

1068 @abc.abstractmethod 

1069 def __fspath__(self): 

1070 """Return the file system path representation of the object.""" 

1071 raise NotImplementedError 

1072 

1073 @classmethod 

1074 def __subclasshook__(cls, subclass): 

1075 if cls is PathLike: 

1076 return _check_methods(subclass, '__fspath__') 

1077 return NotImplemented 

1078 

1079 __class_getitem__ = classmethod(GenericAlias) 

1080 

1081 

1082if name == 'nt': 

1083 class _AddedDllDirectory: 

1084 def __init__(self, path, cookie, remove_dll_directory): 

1085 self.path = path 

1086 self._cookie = cookie 

1087 self._remove_dll_directory = remove_dll_directory 

1088 def close(self): 

1089 self._remove_dll_directory(self._cookie) 

1090 self.path = None 

1091 def __enter__(self): 

1092 return self 

1093 def __exit__(self, *args): 

1094 self.close() 

1095 def __repr__(self): 

1096 if self.path: 

1097 return "<AddedDllDirectory({!r})>".format(self.path) 

1098 return "<AddedDllDirectory()>" 

1099 

1100 def add_dll_directory(path): 

1101 """Add a path to the DLL search path. 

1102 

1103 This search path is used when resolving dependencies for imported 

1104 extension modules (the module itself is resolved through sys.path), 

1105 and also by ctypes. 

1106 

1107 Remove the directory by calling close() on the returned object or 

1108 using it in a with statement. 

1109 """ 

1110 import nt 

1111 cookie = nt._add_dll_directory(path) 

1112 return _AddedDllDirectory( 

1113 path, 

1114 cookie, 

1115 nt._remove_dll_directory 

1116 )