os.py revision 8e4997390ccb92f889ac709c9a45e589472bdee2
1r"""OS routines for Mac, NT, or Posix depending on what system we're on. 2 3This exports: 4 - all functions from posix, nt, os2, mac, or ce, e.g. unlink, stat, etc. 5 - os.path is one of the modules posixpath, ntpath, or macpath 6 - os.name is 'posix', 'nt', 'os2', 'mac', 'ce' or 'riscos' 7 - os.curdir is a string representing the current 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 '\\') 10 - os.extsep is the extension separator ('.' or '/') 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#' 25 26import sys, errno 27 28_names = sys.builtin_module_names 29 30# Note: more names are added to __all__ later. 31__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep", 32 "defpath", "name", "path", "devnull", 33 "SEEK_SET", "SEEK_CUR", "SEEK_END"] 34 35def _get_exports_list(module): 36 try: 37 return list(module.__all__) 38 except AttributeError: 39 return [n for n in dir(module) if n[0] != '_'] 40 41if 'posix' in _names: 42 name = 'posix' 43 linesep = '\n' 44 from posix import * 45 try: 46 from posix import _exit 47 except ImportError: 48 pass 49 import posixpath as path 50 51 import posix 52 __all__.extend(_get_exports_list(posix)) 53 del posix 54 55elif 'nt' in _names: 56 name = 'nt' 57 linesep = '\r\n' 58 from nt import * 59 try: 60 from nt import _exit 61 except ImportError: 62 pass 63 import ntpath as path 64 65 import nt 66 __all__.extend(_get_exports_list(nt)) 67 del nt 68 69elif 'os2' in _names: 70 name = 'os2' 71 linesep = '\r\n' 72 from os2 import * 73 try: 74 from os2 import _exit 75 except ImportError: 76 pass 77 if sys.version.find('EMX GCC') == -1: 78 import ntpath as path 79 else: 80 import os2emxpath as path 81 from _emx_link import link 82 83 import os2 84 __all__.extend(_get_exports_list(os2)) 85 del os2 86 87elif 'mac' in _names: 88 name = 'mac' 89 linesep = '\r' 90 from mac import * 91 try: 92 from mac import _exit 93 except ImportError: 94 pass 95 import macpath as path 96 97 import mac 98 __all__.extend(_get_exports_list(mac)) 99 del mac 100 101elif 'ce' in _names: 102 name = 'ce' 103 linesep = '\r\n' 104 from ce import * 105 try: 106 from ce import _exit 107 except ImportError: 108 pass 109 # We can use the standard Windows path. 110 import ntpath as path 111 112 import ce 113 __all__.extend(_get_exports_list(ce)) 114 del ce 115 116elif 'riscos' in _names: 117 name = 'riscos' 118 linesep = '\n' 119 from riscos import * 120 try: 121 from riscos import _exit 122 except ImportError: 123 pass 124 import riscospath as path 125 126 import riscos 127 __all__.extend(_get_exports_list(riscos)) 128 del riscos 129 130else: 131 raise ImportError, 'no os specific module found' 132 133sys.modules['os.path'] = path 134from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, 135 devnull) 136 137del _names 138 139# Python uses fixed values for the SEEK_ constants; they are mapped 140# to native constants if necessary in posixmodule.c 141SEEK_SET = 0 142SEEK_CUR = 1 143SEEK_END = 2 144 145#' 146 147# Super directory utilities. 148# (Inspired by Eric Raymond; the doc strings are mostly his) 149 150def makedirs(name, mode=0777): 151 """makedirs(path [, mode=0777]) 152 153 Super-mkdir; create a leaf directory and all intermediate ones. 154 Works like mkdir, except that any intermediate path segment (not 155 just the rightmost) will be created if it does not exist. This is 156 recursive. 157 158 """ 159 head, tail = path.split(name) 160 if not tail: 161 head, tail = path.split(head) 162 if head and tail and not path.exists(head): 163 try: 164 makedirs(head, mode) 165 except OSError, e: 166 # be happy if someone already created the path 167 if e.errno != errno.EEXIST: 168 raise 169 if tail == curdir: # xxx/newdir/. exists if xxx/newdir exists 170 return 171 mkdir(name, mode) 172 173def removedirs(name): 174 """removedirs(path) 175 176 Super-rmdir; remove a leaf directory and all empty intermediate 177 ones. Works like rmdir except that, if the leaf directory is 178 successfully removed, directories corresponding to rightmost path 179 segments will be pruned away until either the whole path is 180 consumed or an error occurs. Errors during this latter phase are 181 ignored -- they generally mean that a directory was not empty. 182 183 """ 184 rmdir(name) 185 head, tail = path.split(name) 186 if not tail: 187 head, tail = path.split(head) 188 while head and tail: 189 try: 190 rmdir(head) 191 except error: 192 break 193 head, tail = path.split(head) 194 195def renames(old, new): 196 """renames(old, new) 197 198 Super-rename; create directories as necessary and delete any left 199 empty. Works like rename, except creation of any intermediate 200 directories needed to make the new pathname good is attempted 201 first. After the rename, directories corresponding to rightmost 202 path segments of the old name will be pruned way until either the 203 whole path is consumed or a nonempty directory is found. 204 205 Note: this function can fail with the new directory structure made 206 if you lack permissions needed to unlink the leaf directory or 207 file. 208 209 """ 210 head, tail = path.split(new) 211 if head and tail and not path.exists(head): 212 makedirs(head) 213 rename(old, new) 214 head, tail = path.split(old) 215 if head and tail: 216 try: 217 removedirs(head) 218 except error: 219 pass 220 221__all__.extend(["makedirs", "removedirs", "renames"]) 222 223def walk(top, topdown=True, onerror=None, followlinks=False): 224 """Directory tree generator. 225 226 For each directory in the directory tree rooted at top (including top 227 itself, but excluding '.' and '..'), yields a 3-tuple 228 229 dirpath, dirnames, filenames 230 231 dirpath is a string, the path to the directory. dirnames is a list of 232 the names of the subdirectories in dirpath (excluding '.' and '..'). 233 filenames is a list of the names of the non-directory files in dirpath. 234 Note that the names in the lists are just names, with no path components. 235 To get a full path (which begins with top) to a file or directory in 236 dirpath, do os.path.join(dirpath, name). 237 238 If optional arg 'topdown' is true or not specified, the triple for a 239 directory is generated before the triples for any of its subdirectories 240 (directories are generated top down). If topdown is false, the triple 241 for a directory is generated after the triples for all of its 242 subdirectories (directories are generated bottom up). 243 244 When topdown is true, the caller can modify the dirnames list in-place 245 (e.g., via del or slice assignment), and walk will only recurse into the 246 subdirectories whose names remain in dirnames; this can be used to prune 247 the search, or to impose a specific order of visiting. Modifying 248 dirnames when topdown is false is ineffective, since the directories in 249 dirnames have already been generated by the time dirnames itself is 250 generated. 251 252 By default errors from the os.listdir() call are ignored. If 253 optional arg 'onerror' is specified, it should be a function; it 254 will be called with one argument, an os.error instance. It can 255 report the error to continue with the walk, or raise the exception 256 to abort the walk. Note that the filename is available as the 257 filename attribute of the exception object. 258 259 By default, os.walk does not follow symbolic links to subdirectories on 260 systems that support them. In order to get this functionality, set the 261 optional argument 'followlinks' to true. 262 263 Caution: if you pass a relative pathname for top, don't change the 264 current working directory between resumptions of walk. walk never 265 changes the current directory, and assumes that the client doesn't 266 either. 267 268 Example: 269 270 import os 271 from os.path import join, getsize 272 for root, dirs, files in os.walk('python/Lib/email'): 273 print root, "consumes", 274 print sum([getsize(join(root, name)) for name in files]), 275 print "bytes in", len(files), "non-directory files" 276 if 'CVS' in dirs: 277 dirs.remove('CVS') # don't visit CVS directories 278 """ 279 280 from os.path import join, isdir, islink 281 282 # We may not have read permission for top, in which case we can't 283 # get a list of the files the directory contains. os.path.walk 284 # always suppressed the exception then, rather than blow up for a 285 # minor reason when (say) a thousand readable directories are still 286 # left to visit. That logic is copied here. 287 try: 288 # Note that listdir and error are globals in this module due 289 # to earlier import-*. 290 names = listdir(top) 291 except error, err: 292 if onerror is not None: 293 onerror(err) 294 return 295 296 dirs, nondirs = [], [] 297 for name in names: 298 if isdir(join(top, name)): 299 dirs.append(name) 300 else: 301 nondirs.append(name) 302 303 if topdown: 304 yield top, dirs, nondirs 305 for name in dirs: 306 path = join(top, name) 307 if followlinks or not islink(path): 308 for x in walk(path, topdown, onerror, followlinks): 309 yield x 310 if not topdown: 311 yield top, dirs, nondirs 312 313__all__.append("walk") 314 315# Make sure os.environ exists, at least 316try: 317 environ 318except NameError: 319 environ = {} 320 321def execl(file, *args): 322 """execl(file, *args) 323 324 Execute the executable file with argument list args, replacing the 325 current process. """ 326 execv(file, args) 327 328def execle(file, *args): 329 """execle(file, *args, env) 330 331 Execute the executable file with argument list args and 332 environment env, replacing the current process. """ 333 env = args[-1] 334 execve(file, args[:-1], env) 335 336def execlp(file, *args): 337 """execlp(file, *args) 338 339 Execute the executable file (which is searched for along $PATH) 340 with argument list args, replacing the current process. """ 341 execvp(file, args) 342 343def execlpe(file, *args): 344 """execlpe(file, *args, env) 345 346 Execute the executable file (which is searched for along $PATH) 347 with argument list args and environment env, replacing the current 348 process. """ 349 env = args[-1] 350 execvpe(file, args[:-1], env) 351 352def execvp(file, args): 353 """execp(file, args) 354 355 Execute the executable file (which is searched for along $PATH) 356 with argument list args, replacing the current process. 357 args may be a list or tuple of strings. """ 358 _execvpe(file, args) 359 360def execvpe(file, args, env): 361 """execvpe(file, args, env) 362 363 Execute the executable file (which is searched for along $PATH) 364 with argument list args and environment env , replacing the 365 current process. 366 args may be a list or tuple of strings. """ 367 _execvpe(file, args, env) 368 369__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"]) 370 371def _execvpe(file, args, env=None): 372 if env is not None: 373 func = execve 374 argrest = (args, env) 375 else: 376 func = execv 377 argrest = (args,) 378 env = environ 379 380 head, tail = path.split(file) 381 if head: 382 func(file, *argrest) 383 return 384 if 'PATH' in env: 385 envpath = env['PATH'] 386 else: 387 envpath = defpath 388 PATH = envpath.split(pathsep) 389 saved_exc = None 390 saved_tb = None 391 for dir in PATH: 392 fullname = path.join(dir, file) 393 try: 394 func(fullname, *argrest) 395 except error, e: 396 tb = sys.exc_info()[2] 397 if (e.errno != errno.ENOENT and e.errno != errno.ENOTDIR 398 and saved_exc is None): 399 saved_exc = e 400 saved_tb = tb 401 if saved_exc: 402 raise error, saved_exc, saved_tb 403 raise error, e, tb 404 405# Change environ to automatically call putenv() if it exists 406try: 407 # This will fail if there's no putenv 408 putenv 409except NameError: 410 pass 411else: 412 import UserDict 413 414 # Fake unsetenv() for Windows 415 # not sure about os2 here but 416 # I'm guessing they are the same. 417 418 if name in ('os2', 'nt'): 419 def unsetenv(key): 420 putenv(key, "") 421 422 if name == "riscos": 423 # On RISC OS, all env access goes through getenv and putenv 424 from riscosenviron import _Environ 425 elif name in ('os2', 'nt'): # Where Env Var Names Must Be UPPERCASE 426 # But we store them as upper case 427 class _Environ(UserDict.IterableUserDict): 428 def __init__(self, environ): 429 UserDict.UserDict.__init__(self) 430 data = self.data 431 for k, v in environ.items(): 432 data[k.upper()] = v 433 def __setitem__(self, key, item): 434 putenv(key, item) 435 self.data[key.upper()] = item 436 def __getitem__(self, key): 437 return self.data[key.upper()] 438 try: 439 unsetenv 440 except NameError: 441 def __delitem__(self, key): 442 del self.data[key.upper()] 443 else: 444 def __delitem__(self, key): 445 unsetenv(key) 446 del self.data[key.upper()] 447 def clear(self): 448 for key in self.data.keys(): 449 unsetenv(key) 450 del self.data[key] 451 def pop(self, key, *args): 452 unsetenv(key) 453 return self.data.pop(key.upper(), *args) 454 def has_key(self, key): 455 return key.upper() in self.data 456 def __contains__(self, key): 457 return key.upper() in self.data 458 def get(self, key, failobj=None): 459 return self.data.get(key.upper(), failobj) 460 def update(self, dict=None, **kwargs): 461 if dict: 462 try: 463 keys = dict.keys() 464 except AttributeError: 465 # List of (key, value) 466 for k, v in dict: 467 self[k] = v 468 else: 469 # got keys 470 # cannot use items(), since mappings 471 # may not have them. 472 for k in keys: 473 self[k] = dict[k] 474 if kwargs: 475 self.update(kwargs) 476 def copy(self): 477 return dict(self) 478 479 else: # Where Env Var Names Can Be Mixed Case 480 class _Environ(UserDict.IterableUserDict): 481 def __init__(self, environ): 482 UserDict.UserDict.__init__(self) 483 self.data = environ 484 def __setitem__(self, key, item): 485 putenv(key, item) 486 self.data[key] = item 487 def update(self, dict=None, **kwargs): 488 if dict: 489 try: 490 keys = dict.keys() 491 except AttributeError: 492 # List of (key, value) 493 for k, v in dict: 494 self[k] = v 495 else: 496 # got keys 497 # cannot use items(), since mappings 498 # may not have them. 499 for k in keys: 500 self[k] = dict[k] 501 if kwargs: 502 self.update(kwargs) 503 try: 504 unsetenv 505 except NameError: 506 pass 507 else: 508 def __delitem__(self, key): 509 unsetenv(key) 510 del self.data[key] 511 def clear(self): 512 for key in self.data.keys(): 513 unsetenv(key) 514 del self.data[key] 515 def pop(self, key, *args): 516 unsetenv(key) 517 return self.data.pop(key, *args) 518 def copy(self): 519 return dict(self) 520 521 522 environ = _Environ(environ) 523 524def getenv(key, default=None): 525 """Get an environment variable, return None if it doesn't exist. 526 The optional second argument can specify an alternate default.""" 527 return environ.get(key, default) 528__all__.append("getenv") 529 530def _exists(name): 531 try: 532 eval(name) 533 return True 534 except NameError: 535 return False 536 537# Supply spawn*() (probably only for Unix) 538if _exists("fork") and not _exists("spawnv") and _exists("execv"): 539 540 P_WAIT = 0 541 P_NOWAIT = P_NOWAITO = 1 542 543 # XXX Should we support P_DETACH? I suppose it could fork()**2 544 # and close the std I/O streams. Also, P_OVERLAY is the same 545 # as execv*()? 546 547 def _spawnvef(mode, file, args, env, func): 548 # Internal helper; func is the exec*() function to use 549 pid = fork() 550 if not pid: 551 # Child 552 try: 553 if env is None: 554 func(file, args) 555 else: 556 func(file, args, env) 557 except: 558 _exit(127) 559 else: 560 # Parent 561 if mode == P_NOWAIT: 562 return pid # Caller is responsible for waiting! 563 while 1: 564 wpid, sts = waitpid(pid, 0) 565 if WIFSTOPPED(sts): 566 continue 567 elif WIFSIGNALED(sts): 568 return -WTERMSIG(sts) 569 elif WIFEXITED(sts): 570 return WEXITSTATUS(sts) 571 else: 572 raise error, "Not stopped, signaled or exited???" 573 574 def spawnv(mode, file, args): 575 """spawnv(mode, file, args) -> integer 576 577Execute file with arguments from args in a subprocess. 578If mode == P_NOWAIT return the pid of the process. 579If mode == P_WAIT return the process's exit code if it exits normally; 580otherwise return -SIG, where SIG is the signal that killed it. """ 581 return _spawnvef(mode, file, args, None, execv) 582 583 def spawnve(mode, file, args, env): 584 """spawnve(mode, file, args, env) -> integer 585 586Execute file with arguments from args in a subprocess with the 587specified environment. 588If mode == P_NOWAIT return the pid of the process. 589If mode == P_WAIT return the process's exit code if it exits normally; 590otherwise return -SIG, where SIG is the signal that killed it. """ 591 return _spawnvef(mode, file, args, env, execve) 592 593 # Note: spawnvp[e] is't currently supported on Windows 594 595 def spawnvp(mode, file, args): 596 """spawnvp(mode, file, args) -> integer 597 598Execute file (which is looked for along $PATH) with arguments from 599args in a subprocess. 600If mode == P_NOWAIT return the pid of the process. 601If mode == P_WAIT return the process's exit code if it exits normally; 602otherwise return -SIG, where SIG is the signal that killed it. """ 603 return _spawnvef(mode, file, args, None, execvp) 604 605 def spawnvpe(mode, file, args, env): 606 """spawnvpe(mode, file, args, env) -> integer 607 608Execute file (which is looked for along $PATH) with arguments from 609args in a subprocess with the supplied environment. 610If mode == P_NOWAIT return the pid of the process. 611If mode == P_WAIT return the process's exit code if it exits normally; 612otherwise return -SIG, where SIG is the signal that killed it. """ 613 return _spawnvef(mode, file, args, env, execvpe) 614 615if _exists("spawnv"): 616 # These aren't supplied by the basic Windows code 617 # but can be easily implemented in Python 618 619 def spawnl(mode, file, *args): 620 """spawnl(mode, file, *args) -> integer 621 622Execute file with arguments from args in a subprocess. 623If mode == P_NOWAIT return the pid of the process. 624If mode == P_WAIT return the process's exit code if it exits normally; 625otherwise return -SIG, where SIG is the signal that killed it. """ 626 return spawnv(mode, file, args) 627 628 def spawnle(mode, file, *args): 629 """spawnle(mode, file, *args, env) -> integer 630 631Execute file with arguments from args in a subprocess with the 632supplied environment. 633If mode == P_NOWAIT return the pid of the process. 634If mode == P_WAIT return the process's exit code if it exits normally; 635otherwise return -SIG, where SIG is the signal that killed it. """ 636 env = args[-1] 637 return spawnve(mode, file, args[:-1], env) 638 639 640 __all__.extend(["spawnv", "spawnve", "spawnl", "spawnle",]) 641 642 643if _exists("spawnvp"): 644 # At the moment, Windows doesn't implement spawnvp[e], 645 # so it won't have spawnlp[e] either. 646 def spawnlp(mode, file, *args): 647 """spawnlp(mode, file, *args) -> integer 648 649Execute file (which is looked for along $PATH) with arguments from 650args in a subprocess with the supplied environment. 651If mode == P_NOWAIT return the pid of the process. 652If mode == P_WAIT return the process's exit code if it exits normally; 653otherwise return -SIG, where SIG is the signal that killed it. """ 654 return spawnvp(mode, file, args) 655 656 def spawnlpe(mode, file, *args): 657 """spawnlpe(mode, file, *args, env) -> integer 658 659Execute file (which is looked for along $PATH) with arguments from 660args in a subprocess with the supplied environment. 661If mode == P_NOWAIT return the pid of the process. 662If mode == P_WAIT return the process's exit code if it exits normally; 663otherwise return -SIG, where SIG is the signal that killed it. """ 664 env = args[-1] 665 return spawnvpe(mode, file, args[:-1], env) 666 667 668 __all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe",]) 669 670 671# Supply popen2 etc. (for Unix) 672if _exists("fork"): 673 if not _exists("popen2"): 674 def popen2(cmd, mode="t", bufsize=-1): 675 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' 676 may be a sequence, in which case arguments will be passed directly to 677 the program without shell intervention (as with os.spawnv()). If 'cmd' 678 is a string it will be passed to the shell (as with os.system()). If 679 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 680 file objects (child_stdin, child_stdout) are returned.""" 681 import warnings 682 msg = "os.popen2 is deprecated. Use the subprocess module." 683 warnings.warn(msg, DeprecationWarning, stacklevel=2) 684 685 import subprocess 686 PIPE = subprocess.PIPE 687 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, 688 stdin=PIPE, stdout=PIPE, close_fds=True) 689 return p.stdin, p.stdout 690 __all__.append("popen2") 691 692 if not _exists("popen3"): 693 def popen3(cmd, mode="t", bufsize=-1): 694 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' 695 may be a sequence, in which case arguments will be passed directly to 696 the program without shell intervention (as with os.spawnv()). If 'cmd' 697 is a string it will be passed to the shell (as with os.system()). If 698 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 699 file objects (child_stdin, child_stdout, child_stderr) are returned.""" 700 import warnings 701 msg = "os.popen3 is deprecated. Use the subprocess module." 702 warnings.warn(msg, DeprecationWarning, stacklevel=2) 703 704 import subprocess 705 PIPE = subprocess.PIPE 706 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, 707 stdin=PIPE, stdout=PIPE, stderr=PIPE, 708 close_fds=True) 709 return p.stdin, p.stdout, p.stderr 710 __all__.append("popen3") 711 712 if not _exists("popen4"): 713 def popen4(cmd, mode="t", bufsize=-1): 714 """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' 715 may be a sequence, in which case arguments will be passed directly to 716 the program without shell intervention (as with os.spawnv()). If 'cmd' 717 is a string it will be passed to the shell (as with os.system()). If 718 'bufsize' is specified, it sets the buffer size for the I/O pipes. The 719 file objects (child_stdin, child_stdout_stderr) are returned.""" 720 import warnings 721 msg = "os.popen4 is deprecated. Use the subprocess module." 722 warnings.warn(msg, DeprecationWarning, stacklevel=2) 723 724 import subprocess 725 PIPE = subprocess.PIPE 726 p = subprocess.Popen(cmd, shell=True, bufsize=bufsize, 727 stdin=PIPE, stdout=PIPE, 728 stderr=subprocess.STDOUT, close_fds=True) 729 return p.stdin, p.stdout 730 __all__.append("popen4") 731 732import copy_reg as _copy_reg 733 734def _make_stat_result(tup, dict): 735 return stat_result(tup, dict) 736 737def _pickle_stat_result(sr): 738 (type, args) = sr.__reduce__() 739 return (_make_stat_result, args) 740 741try: 742 _copy_reg.pickle(stat_result, _pickle_stat_result, _make_stat_result) 743except NameError: # stat_result may not exist 744 pass 745 746def _make_statvfs_result(tup, dict): 747 return statvfs_result(tup, dict) 748 749def _pickle_statvfs_result(sr): 750 (type, args) = sr.__reduce__() 751 return (_make_statvfs_result, args) 752 753try: 754 _copy_reg.pickle(statvfs_result, _pickle_statvfs_result, 755 _make_statvfs_result) 756except NameError: # statvfs_result may not exist 757 pass 758 759if not _exists("urandom"): 760 def urandom(n): 761 """urandom(n) -> str 762 763 Return a string of n random bytes suitable for cryptographic use. 764 765 """ 766 try: 767 _urandomfd = open("/dev/urandom", O_RDONLY) 768 except (OSError, IOError): 769 raise NotImplementedError("/dev/urandom (or equivalent) not found") 770 bytes = "" 771 while len(bytes) < n: 772 bytes += read(_urandomfd, n - len(bytes)) 773 close(_urandomfd) 774 return bytes 775