Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3)

Delta Between Two Patch Sets: Lib/os.py

Issue 16353: add function to os module for getting path to default shell
Left Patch Set: Created 5 years, 8 months ago
Right Patch Set: Created 3 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | Modules/posixmodule.c » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 r"""OS routines for NT or Posix depending on what system we're on. 1 r"""OS routines for NT or Posix depending on what system we're on.
2 2
3 This exports: 3 This exports:
4 - all functions from posix, nt or ce, e.g. unlink, stat, etc. 4 - all functions from posix, nt or ce, e.g. unlink, stat, etc.
5 - os.path is either posixpath or ntpath 5 - os.path is either posixpath or ntpath
6 - os.name is either 'posix', 'nt' or 'ce'. 6 - os.name is either 'posix', 'nt' or 'ce'.
7 - os.curdir is a string representing the current directory ('.' or ':') 7 - os.curdir is a string representing the current directory ('.' or ':')
8 - os.pardir is a string representing the parent directory ('..' or '::') 8 - os.pardir is a string representing the parent directory ('..' or '::')
9 - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\') 9 - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\')
10 - os.extsep is the extension separator (always '.') 10 - os.extsep is the extension separator (always '.')
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 from posix import _exit 53 from posix import _exit
54 __all__.append('_exit') 54 __all__.append('_exit')
55 except ImportError: 55 except ImportError:
56 pass 56 pass
57 import posixpath as path 57 import posixpath as path
58 58
59 try: 59 try:
60 from posix import _have_functions 60 from posix import _have_functions
61 except ImportError: 61 except ImportError:
62 pass 62 pass
63
64 import posix
65 __all__.extend(_get_exports_list(posix))
66 del posix
63 67
64 elif 'nt' in _names: 68 elif 'nt' in _names:
65 name = 'nt' 69 name = 'nt'
66 linesep = '\r\n' 70 linesep = '\r\n'
67 from nt import * 71 from nt import *
68 try: 72 try:
69 from nt import _exit 73 from nt import _exit
70 __all__.append('_exit') 74 __all__.append('_exit')
71 except ImportError: 75 except ImportError:
72 pass 76 pass
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 _add("HAVE_UTIMENSAT", "utime") 196 _add("HAVE_UTIMENSAT", "utime")
193 _add("MS_WINDOWS", "stat") 197 _add("MS_WINDOWS", "stat")
194 supports_follow_symlinks = _set 198 supports_follow_symlinks = _set
195 199
196 del _set 200 del _set
197 del _have_functions 201 del _have_functions
198 del _globals 202 del _globals
199 del _add 203 del _add
200 204
201 205
206 if sys.platform == 'win32':
207 default_shell = 'cmd.exe'
Michael.Felt 2016/07/29 14:40:15 Has cmd.exe moved around too much to not specify a
eryksun 2016/07/29 15:03:28 It should be environ['ComSpec'], for which the def
208 elif _exists('is_android') and is_android:
209 default_shell = '/system/bin/sh'
210 else:
211 default_shell = '/bin/sh'
212
202 # Python uses fixed values for the SEEK_ constants; they are mapped 213 # Python uses fixed values for the SEEK_ constants; they are mapped
203 # to native constants if necessary in posixmodule.c 214 # to native constants if necessary in posixmodule.c
204 # Other possible SEEK values are directly imported from posixmodule.c 215 # Other possible SEEK values are directly imported from posixmodule.c
205 SEEK_SET = 0 216 SEEK_SET = 0
206 SEEK_CUR = 1 217 SEEK_CUR = 1
207 SEEK_END = 2 218 SEEK_END = 2
208 219
209 # Super directory utilities. 220 # Super directory utilities.
210 # (Inspired by Eric Raymond; the doc strings are mostly his) 221 # (Inspired by Eric Raymond; the doc strings are mostly his)
211 222
212 def makedirs(name, mode=0o777, exist_ok=False): 223 def makedirs(name, mode=0o777, exist_ok=False):
213 """makedirs(name [, mode=0o777][, exist_ok=False]) 224 """makedirs(name [, mode=0o777][, exist_ok=False])
214 225
215 Super-mkdir; create a leaf directory and all intermediate ones. Works like 226 Super-mkdir; create a leaf directory and all intermediate ones. Works like
216 mkdir, except that any intermediate path segment (not just the rightmost) 227 mkdir, except that any intermediate path segment (not just the rightmost)
217 will be created if it does not exist. If the target directory already 228 will be created if it does not exist. If the target directory already
218 exists, raise an OSError if exist_ok is False. Otherwise no exception is 229 exists, raise an OSError if exist_ok is False. Otherwise no exception is
219 raised. This is recursive. 230 raised. This is recursive.
220 231
221 """ 232 """
222 head, tail = path.split(name) 233 head, tail = path.split(name)
223 if not tail: 234 if not tail:
224 head, tail = path.split(head) 235 head, tail = path.split(head)
225 if head and tail and not path.exists(head): 236 if head and tail and not path.exists(head):
226 try: 237 try:
227 makedirs(head, mode, exist_ok) 238 makedirs(head, mode, exist_ok)
228 except FileExistsError: 239 except FileExistsError:
229 # be happy if someone already created the path 240 # Defeats race condition when another thread created the path
230 pass 241 pass
231 cdir = curdir 242 cdir = curdir
232 if isinstance(tail, bytes): 243 if isinstance(tail, bytes):
233 cdir = bytes(curdir, 'ASCII') 244 cdir = bytes(curdir, 'ASCII')
234 if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists 245 if tail == cdir: # xxx/newdir/. exists if xxx/newdir exists
235 return 246 return
236 try: 247 try:
237 mkdir(name, mode) 248 mkdir(name, mode)
238 except OSError as e: 249 except OSError:
239 if not exist_ok or e.errno != errno.EEXIST or not path.isdir(name): 250 # Cannot rely on checking for EEXIST, since the operating system
251 # could give priority to other errors like EACCES or EROFS
252 if not exist_ok or not path.isdir(name):
240 raise 253 raise
241 254
242 def removedirs(name): 255 def removedirs(name):
243 """removedirs(name) 256 """removedirs(name)
244 257
245 Super-rmdir; remove a leaf directory and all empty intermediate 258 Super-rmdir; remove a leaf directory and all empty intermediate
246 ones. Works like rmdir except that, if the leaf directory is 259 ones. Works like rmdir except that, if the leaf directory is
247 successfully removed, directories corresponding to rightmost path 260 successfully removed, directories corresponding to rightmost path
248 segments will be pruned away until either the whole path is 261 segments will be pruned away until either the whole path is
249 consumed or an error occurs. Errors during this latter phase are 262 consumed or an error occurs. Errors during this latter phase are
(...skipping 11 matching lines...) Expand all
261 break 274 break
262 head, tail = path.split(head) 275 head, tail = path.split(head)
263 276
264 def renames(old, new): 277 def renames(old, new):
265 """renames(old, new) 278 """renames(old, new)
266 279
267 Super-rename; create directories as necessary and delete any left 280 Super-rename; create directories as necessary and delete any left
268 empty. Works like rename, except creation of any intermediate 281 empty. Works like rename, except creation of any intermediate
269 directories needed to make the new pathname good is attempted 282 directories needed to make the new pathname good is attempted
270 first. After the rename, directories corresponding to rightmost 283 first. After the rename, directories corresponding to rightmost
271 path segments of the old name will be pruned way until either the 284 path segments of the old name will be pruned until either the
272 whole path is consumed or a nonempty directory is found. 285 whole path is consumed or a nonempty directory is found.
273 286
274 Note: this function can fail with the new directory structure made 287 Note: this function can fail with the new directory structure made
275 if you lack permissions needed to unlink the leaf directory or 288 if you lack permissions needed to unlink the leaf directory or
276 file. 289 file.
277 290
278 """ 291 """
279 head, tail = path.split(new) 292 head, tail = path.split(new)
280 if head and tail and not path.exists(head): 293 if head and tail and not path.exists(head):
281 makedirs(head) 294 makedirs(head)
(...skipping 30 matching lines...) Expand all
312 325
313 When topdown is true, the caller can modify the dirnames list in-place 326 When topdown is true, the caller can modify the dirnames list in-place
314 (e.g., via del or slice assignment), and walk will only recurse into the 327 (e.g., via del or slice assignment), and walk will only recurse into the
315 subdirectories whose names remain in dirnames; this can be used to prune the 328 subdirectories whose names remain in dirnames; this can be used to prune the
316 search, or to impose a specific order of visiting. Modifying dirnames when 329 search, or to impose a specific order of visiting. Modifying dirnames when
317 topdown is false is ineffective, since the directories in dirnames have 330 topdown is false is ineffective, since the directories in dirnames have
318 already been generated by the time dirnames itself is generated. No matter 331 already been generated by the time dirnames itself is generated. No matter
319 the value of topdown, the list of subdirectories is retrieved before the 332 the value of topdown, the list of subdirectories is retrieved before the
320 tuples for the directory and its subdirectories are generated. 333 tuples for the directory and its subdirectories are generated.
321 334
322 By default errors from the os.listdir() call are ignored. If 335 By default errors from the os.scandir() call are ignored. If
323 optional arg 'onerror' is specified, it should be a function; it 336 optional arg 'onerror' is specified, it should be a function; it
324 will be called with one argument, an OSError instance. It can 337 will be called with one argument, an OSError instance. It can
325 report the error to continue with the walk, or raise the exception 338 report the error to continue with the walk, or raise the exception
326 to abort the walk. Note that the filename is available as the 339 to abort the walk. Note that the filename is available as the
327 filename attribute of the exception object. 340 filename attribute of the exception object.
328 341
329 By default, os.walk does not follow symbolic links to subdirectories on 342 By default, os.walk does not follow symbolic links to subdirectories on
330 systems that support them. In order to get this functionality, set the 343 systems that support them. In order to get this functionality, set the
331 optional argument 'followlinks' to true. 344 optional argument 'followlinks' to true.
332 345
333 Caution: if you pass a relative pathname for top, don't change the 346 Caution: if you pass a relative pathname for top, don't change the
334 current working directory between resumptions of walk. walk never 347 current working directory between resumptions of walk. walk never
335 changes the current directory, and assumes that the client doesn't 348 changes the current directory, and assumes that the client doesn't
336 either. 349 either.
337 350
338 Example: 351 Example:
339 352
340 import os 353 import os
341 from os.path import join, getsize 354 from os.path import join, getsize
342 for root, dirs, files in os.walk('python/Lib/email'): 355 for root, dirs, files in os.walk('python/Lib/email'):
343 print(root, "consumes", end="") 356 print(root, "consumes", end="")
344 print(sum([getsize(join(root, name)) for name in files]), end="") 357 print(sum([getsize(join(root, name)) for name in files]), end="")
345 print("bytes in", len(files), "non-directory files") 358 print("bytes in", len(files), "non-directory files")
346 if 'CVS' in dirs: 359 if 'CVS' in dirs:
347 dirs.remove('CVS') # don't visit CVS directories 360 dirs.remove('CVS') # don't visit CVS directories
348 361
349 """ 362 """
350 363
351 islink, join, isdir = path.islink, path.join, path.isdir 364 dirs = []
365 nondirs = []
366 walk_dirs = []
352 367
353 # We may not have read permission for top, in which case we can't 368 # We may not have read permission for top, in which case we can't
354 # get a list of the files the directory contains. os.walk 369 # get a list of the files the directory contains. os.walk
355 # always suppressed the exception then, rather than blow up for a 370 # always suppressed the exception then, rather than blow up for a
356 # minor reason when (say) a thousand readable directories are still 371 # minor reason when (say) a thousand readable directories are still
357 # left to visit. That logic is copied here. 372 # left to visit. That logic is copied here.
358 try: 373 try:
359 # Note that listdir is global in this module due 374 if name == 'nt' and isinstance(top, bytes):
360 # to earlier import-*. 375 scandir_it = _dummy_scandir(top)
361 names = listdir(top) 376 else:
362 except OSError as err: 377 # Note that scandir is global in this module due
378 # to earlier import-*.
379 scandir_it = scandir(top)
380 except OSError as error:
363 if onerror is not None: 381 if onerror is not None:
364 onerror(err) 382 onerror(error)
365 return 383 return
366 384
367 dirs, nondirs = [], [] 385 with scandir_it:
368 for name in names: 386 while True:
369 if isdir(join(top, name)): 387 try:
370 dirs.append(name) 388 try:
371 else: 389 entry = next(scandir_it)
372 nondirs.append(name) 390 except StopIteration:
373 391 break
392 except OSError as error:
393 if onerror is not None:
394 onerror(error)
395 return
396
397 try:
398 is_dir = entry.is_dir()
399 except OSError:
400 # If is_dir() raises an OSError, consider that the entry is not
401 # a directory, same behaviour than os.path.isdir().
402 is_dir = False
403
404 if is_dir:
405 dirs.append(entry.name)
406 else:
407 nondirs.append(entry.name)
408
409 if not topdown and is_dir:
410 # Bottom-up: recurse into sub-directory, but exclude symlinks to
411 # directories if followlinks is False
412 if followlinks:
413 walk_into = True
414 else:
415 try:
416 is_symlink = entry.is_symlink()
417 except OSError:
418 # If is_symlink() raises an OSError, consider that the
419 # entry is not a symbolic link, same behaviour than
420 # os.path.islink().
421 is_symlink = False
422 walk_into = not is_symlink
423
424 if walk_into:
425 walk_dirs.append(entry.path)
426
427 # Yield before recursion if going top down
374 if topdown: 428 if topdown:
375 yield top, dirs, nondirs 429 yield top, dirs, nondirs
376 for name in dirs: 430
377 new_path = join(top, name) 431 # Recurse into sub-directories
378 if followlinks or not islink(new_path): 432 islink, join = path.islink, path.join
433 for dirname in dirs:
434 new_path = join(top, dirname)
435 # Issue #23605: os.path.islink() is used instead of caching
436 # entry.is_symlink() result during the loop on os.scandir() because
437 # the caller can replace the directory entry during the "yield"
438 # above.
439 if followlinks or not islink(new_path):
440 yield from walk(new_path, topdown, onerror, followlinks)
441 else:
442 # Recurse into sub-directories
443 for new_path in walk_dirs:
379 yield from walk(new_path, topdown, onerror, followlinks) 444 yield from walk(new_path, topdown, onerror, followlinks)
380 if not topdown: 445 # Yield after recursion if going bottom up
381 yield top, dirs, nondirs 446 yield top, dirs, nondirs
447
448 class _DummyDirEntry:
449 """Dummy implementation of DirEntry
450
451 Only used internally by os.walk(bytes). Since os.walk() doesn't need the
452 follow_symlinks parameter: don't implement it, always follow symbolic
453 links.
454 """
455
456 def __init__(self, dir, name):
457 self.name = name
458 self.path = path.join(dir, name)
459 # Mimick FindFirstFile/FindNextFile: we should get file attributes
460 # while iterating on a directory
461 self._stat = None
462 self._lstat = None
463 try:
464 self.stat(follow_symlinks=False)
465 except OSError:
466 pass
467
468 def stat(self, *, follow_symlinks=True):
469 if follow_symlinks:
470 if self._stat is None:
471 self._stat = stat(self.path)
472 return self._stat
473 else:
474 if self._lstat is None:
475 self._lstat = stat(self.path, follow_symlinks=False)
476 return self._lstat
477
478 def is_dir(self):
479 if self._lstat is not None and not self.is_symlink():
480 # use the cache lstat
481 stat = self.stat(follow_symlinks=False)
482 return st.S_ISDIR(stat.st_mode)
483
484 stat = self.stat()
485 return st.S_ISDIR(stat.st_mode)
486
487 def is_symlink(self):
488 stat = self.stat(follow_symlinks=False)
489 return st.S_ISLNK(stat.st_mode)
490
491 class _dummy_scandir:
492 # listdir-based implementation for bytes patches on Windows
493 def __init__(self, dir):
494 self.dir = dir
495 self.it = iter(listdir(dir))
496
497 def __iter__(self):
498 return self
499
500 def __next__(self):
501 return _DummyDirEntry(self.dir, next(self.it))
502
503 def __enter__(self):
504 return self
505
506 def __exit__(self, *args):
507 self.it = iter(())
382 508
383 __all__.append("walk") 509 __all__.append("walk")
384 510
385 if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd: 511 if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:
386 512
387 def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir _fd=None): 513 def fwalk(top=".", topdown=True, onerror=None, *, follow_symlinks=False, dir _fd=None):
388 """Directory tree generator. 514 """Directory tree generator.
389 515
390 This behaves exactly like walk(), except that it yields a 4-tuple 516 This behaves exactly like walk(), except that it yields a 4-tuple
391 517
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 if topdown: 583 if topdown:
458 yield toppath, dirs, nondirs, topfd 584 yield toppath, dirs, nondirs, topfd
459 585
460 for name in dirs: 586 for name in dirs:
461 try: 587 try:
462 orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlin ks) 588 orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlin ks)
463 dirfd = open(name, O_RDONLY, dir_fd=topfd) 589 dirfd = open(name, O_RDONLY, dir_fd=topfd)
464 except OSError as err: 590 except OSError as err:
465 if onerror is not None: 591 if onerror is not None:
466 onerror(err) 592 onerror(err)
467 return 593 continue
468 try: 594 try:
469 if follow_symlinks or path.samestat(orig_st, stat(dirfd)): 595 if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
470 dirpath = path.join(toppath, name) 596 dirpath = path.join(toppath, name)
471 yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_s ymlinks) 597 yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_s ymlinks)
472 finally: 598 finally:
473 close(dirfd) 599 close(dirfd)
474 600
475 if not topdown: 601 if not topdown:
476 yield toppath, dirs, nondirs, topfd 602 yield toppath, dirs, nondirs, topfd
477 603
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 raise ValueError( 729 raise ValueError(
604 "env cannot contain 'PATH' and b'PATH' keys") 730 "env cannot contain 'PATH' and b'PATH' keys")
605 path_list = path_listb 731 path_list = path_listb
606 732
607 if path_list is not None and isinstance(path_list, bytes): 733 if path_list is not None and isinstance(path_list, bytes):
608 path_list = fsdecode(path_list) 734 path_list = fsdecode(path_list)
609 735
610 if path_list is None: 736 if path_list is None:
611 path_list = defpath 737 path_list = defpath
612 return path_list.split(pathsep) 738 return path_list.split(pathsep)
613
614
615 if sys.platform == "win32": # use sys.platform to accommodate java
616 def get_shell_executable():
617 """Return path to the command processor specified by %ComSpec%.
618
619 Default: %SystemRoot%\system32\cmd.exe
620 """
621 return (environ.get('ComSpec') or
622 path.join(environ.get('SystemRoot', r'C:\Windows'),
623 r'system32\cmd.exe'))
624 else: # POSIX
625 def get_shell_executable():
626 """Return path to the standard system shell executable.
627
628 Default: '/bin/sh'
629 """
630 for dirpath in defpath.split(pathsep):
631 sh = dirpath + sep + 'sh' #NOTE: interpret '' as '/'
632 if access(sh, F_OK | X_OK) and path.isfile(sh):
633 #NOTE: allow symlinks e.g., /bin/sh on Ubuntu may be dash
634 return sh
635 return '/bin/sh' #XXX either OS or python are broken if we got here
636 739
637 740
638 # Change environ to automatically call putenv(), unsetenv if they exist. 741 # Change environ to automatically call putenv(), unsetenv if they exist.
639 from _collections_abc import MutableMapping 742 from _collections_abc import MutableMapping
640 743
641 class _Environ(MutableMapping): 744 class _Environ(MutableMapping):
642 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, put env, unsetenv): 745 def __init__(self, data, encodekey, decodekey, encodevalue, decodevalue, put env, unsetenv):
643 self.encodekey = encodekey 746 self.encodekey = encodekey
644 self.decodekey = decodekey 747 self.decodekey = decodekey
645 self.encodevalue = encodevalue 748 self.encodevalue = encodevalue
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
994 return getattr(self._stream, name) 1097 return getattr(self._stream, name)
995 def __iter__(self): 1098 def __iter__(self):
996 return iter(self._stream) 1099 return iter(self._stream)
997 1100
998 # Supply os.fdopen() 1101 # Supply os.fdopen()
999 def fdopen(fd, *args, **kwargs): 1102 def fdopen(fd, *args, **kwargs):
1000 if not isinstance(fd, int): 1103 if not isinstance(fd, int):
1001 raise TypeError("invalid fd type (%s, expected integer)" % type(fd)) 1104 raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
1002 import io 1105 import io
1003 return io.open(fd, *args, **kwargs) 1106 return io.open(fd, *args, **kwargs)
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+