OLD | NEW |
1 """ | 1 """ |
2 TestCmd.py: a testing framework for commands and scripts. | 2 TestCmd.py: a testing framework for commands and scripts. |
3 | 3 |
4 The TestCmd module provides a framework for portable automated testing | 4 The TestCmd module provides a framework for portable automated testing |
5 of executable commands and scripts (in any language, not just Python), | 5 of executable commands and scripts (in any language, not just Python), |
6 especially commands and scripts that require file system interaction. | 6 especially commands and scripts that require file system interaction. |
7 | 7 |
8 In addition to running tests and evaluating conditions, the TestCmd | 8 In addition to running tests and evaluating conditions, the TestCmd |
9 module manages and cleans up one or more temporary workspace | 9 module manages and cleans up one or more temporary workspace |
10 directories, and provides methods for creating files and directories in | 10 directories, and provides methods for creating files and directories in |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 # SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF | 207 # SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF |
208 # THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 208 # THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
209 # DAMAGE. | 209 # DAMAGE. |
210 # | 210 # |
211 # THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT | 211 # THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
212 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | 212 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
213 # PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, | 213 # PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, |
214 # AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | 214 # AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |
215 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 215 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
216 | 216 |
| 217 from __future__ import print_function |
| 218 |
217 __author__ = "Steven Knight <knight at baldmt dot com>" | 219 __author__ = "Steven Knight <knight at baldmt dot com>" |
218 __revision__ = "TestCmd.py 0.37.D001 2010/01/11 16:55:50 knight" | 220 __revision__ = "TestCmd.py 0.37.D001 2010/01/11 16:55:50 knight" |
219 __version__ = "0.37" | 221 __version__ = "0.37" |
220 | 222 |
221 import errno | 223 import errno |
222 import os | 224 import os |
223 import os.path | 225 import os.path |
224 import re | 226 import re |
225 import shutil | 227 import shutil |
226 import stat | 228 import stat |
227 import string | |
228 import sys | 229 import sys |
229 import tempfile | 230 import tempfile |
230 import time | 231 import time |
231 import traceback | 232 import traceback |
232 import types | 233 try: |
233 import UserList | 234 from UserList import UserList |
| 235 except ImportError: |
| 236 from collections import UserList |
234 | 237 |
235 __all__ = [ | 238 __all__ = [ |
236 'diff_re', | 239 'diff_re', |
237 'fail_test', | 240 'fail_test', |
238 'no_result', | 241 'no_result', |
239 'pass_test', | 242 'pass_test', |
240 'match_exact', | 243 'match_exact', |
241 'match_re', | 244 'match_re', |
242 'match_re_dotall', | 245 'match_re_dotall', |
243 'python_executable', | 246 'python_executable', |
244 'TestCmd' | 247 'TestCmd' |
245 ] | 248 ] |
246 | 249 |
247 try: | 250 try: |
248 import difflib | 251 import difflib |
249 except ImportError: | 252 except ImportError: |
250 __all__.append('simple_diff') | 253 __all__.append('simple_diff') |
251 | 254 |
252 def is_List(e): | 255 def is_List(e): |
253 return type(e) is types.ListType \ | 256 return type(e) is list \ |
254 or isinstance(e, UserList.UserList) | 257 or isinstance(e, UserList) |
255 | 258 |
256 try: | 259 try: |
257 from UserString import UserString | 260 from UserString import UserString |
258 except ImportError: | 261 except ImportError: |
259 class UserString: | 262 try: |
260 pass | 263 from collections import UserString |
| 264 except ImportError: |
| 265 class UserString: |
| 266 pass |
261 | 267 |
262 if hasattr(types, 'UnicodeType'): | 268 try: |
263 def is_String(e): | 269 basestring = basestring |
264 return type(e) is types.StringType \ | 270 except NameError: |
265 or type(e) is types.UnicodeType \ | 271 basestring = str |
266 or isinstance(e, UserString) | 272 |
267 else: | 273 def is_String(e): |
268 def is_String(e): | 274 return isinstance(e, basestring) \ |
269 return type(e) is types.StringType or isinstance(e, UserString) | 275 or isinstance(e, UserString) |
270 | 276 |
271 tempfile.template = 'testcmd.' | 277 tempfile.template = 'testcmd.' |
272 if os.name in ('posix', 'nt'): | 278 if os.name in ('posix', 'nt'): |
273 tempfile.template = 'testcmd.' + str(os.getpid()) + '.' | 279 tempfile.template = 'testcmd.' + str(os.getpid()) + '.' |
274 else: | 280 else: |
275 tempfile.template = 'testcmd.' | 281 tempfile.template = 'testcmd.' |
276 | 282 |
277 re_space = re.compile('\s') | 283 re_space = re.compile('\s') |
278 | 284 |
279 _Cleanup = [] | 285 _Cleanup = [] |
280 | 286 |
281 _chain_to_exitfunc = None | 287 _chain_to_exitfunc = None |
282 | 288 |
283 def _clean(): | 289 def _clean(): |
284 global _Cleanup | 290 global _Cleanup |
285 cleanlist = filter(None, _Cleanup) | 291 for test in reversed(_Cleanup): |
| 292 if test: |
| 293 test.cleanup() |
286 del _Cleanup[:] | 294 del _Cleanup[:] |
287 cleanlist.reverse() | |
288 for test in cleanlist: | |
289 test.cleanup() | |
290 if _chain_to_exitfunc: | 295 if _chain_to_exitfunc: |
291 _chain_to_exitfunc() | 296 _chain_to_exitfunc() |
292 | 297 |
293 try: | 298 try: |
294 import atexit | 299 import atexit |
295 except ImportError: | 300 except ImportError: |
296 # TODO(1.5): atexit requires python 2.0, so chain sys.exitfunc | 301 # TODO(1.5): atexit requires python 2.0, so chain sys.exitfunc |
297 try: | 302 try: |
298 _chain_to_exitfunc = sys.exitfunc | 303 _chain_to_exitfunc = sys.exitfunc |
299 except AttributeError: | 304 except AttributeError: |
300 pass | 305 pass |
301 sys.exitfunc = _clean | 306 sys.exitfunc = _clean |
302 else: | 307 else: |
303 atexit.register(_clean) | 308 atexit.register(_clean) |
304 | 309 |
305 try: | 310 try: |
306 zip | 311 zip |
307 except NameError: | 312 except NameError: |
308 def zip(*lists): | 313 def zip(*lists): |
309 result = [] | 314 result = [] |
310 for i in xrange(min(map(len, lists))): | 315 for i in range(min(map(len, lists))): |
311 result.append(tuple(map(lambda l, i=i: l[i], lists))) | 316 result.append(tuple(map(lambda l, i=i: l[i], lists))) |
312 return result | 317 return result |
313 | 318 |
314 class Collector: | |
315 def __init__(self, top): | |
316 self.entries = [top] | |
317 def __call__(self, arg, dirname, names): | |
318 pathjoin = lambda n, d=dirname: os.path.join(d, n) | |
319 self.entries.extend(map(pathjoin, names)) | |
320 | |
321 def _caller(tblist, skip): | 319 def _caller(tblist, skip): |
322 string = "" | 320 string = "" |
323 arr = [] | 321 arr = [] |
324 for file, line, name, text in tblist: | 322 for file, line, name, text in tblist: |
325 if file[-10:] == "TestCmd.py": | 323 if file[-10:] == "TestCmd.py": |
326 break | 324 break |
327 arr = [(file, line, name, text)] + arr | 325 arr = [(file, line, name, text)] + arr |
328 atfrom = "at" | 326 atfrom = "at" |
329 for file, line, name, text in arr[skip:]: | 327 for file, line, name, text in arr[skip:]: |
330 if name in ("?", "<module>"): | 328 if name in ("?", "<module>"): |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 return | 401 return |
404 if not function is None: | 402 if not function is None: |
405 function() | 403 function() |
406 sys.stderr.write("PASSED\n") | 404 sys.stderr.write("PASSED\n") |
407 sys.exit(0) | 405 sys.exit(0) |
408 | 406 |
409 def match_exact(lines = None, matches = None): | 407 def match_exact(lines = None, matches = None): |
410 """ | 408 """ |
411 """ | 409 """ |
412 if not is_List(lines): | 410 if not is_List(lines): |
413 lines = string.split(lines, "\n") | 411 lines = lines.split("\n") |
414 if not is_List(matches): | 412 if not is_List(matches): |
415 matches = string.split(matches, "\n") | 413 matches = matches.split("\n") |
416 if len(lines) != len(matches): | 414 if len(lines) != len(matches): |
417 return | 415 return |
418 for i in range(len(lines)): | 416 for i in range(len(lines)): |
419 if lines[i] != matches[i]: | 417 if lines[i] != matches[i]: |
420 return | 418 return |
421 return 1 | 419 return 1 |
422 | 420 |
423 def match_re(lines = None, res = None): | 421 def match_re(lines = None, res = None): |
424 """ | 422 """ |
425 """ | 423 """ |
426 if not is_List(lines): | 424 if not is_List(lines): |
427 lines = string.split(lines, "\n") | 425 lines = lines.split("\n") |
428 if not is_List(res): | 426 if not is_List(res): |
429 res = string.split(res, "\n") | 427 res = res.split("\n") |
430 if len(lines) != len(res): | 428 if len(lines) != len(res): |
431 return | 429 return |
432 for i in range(len(lines)): | 430 for i in range(len(lines)): |
433 s = "^" + res[i] + "$" | 431 s = "^" + res[i] + "$" |
434 try: | 432 try: |
435 expr = re.compile(s) | 433 expr = re.compile(s) |
436 except re.error, e: | 434 except re.error as e: |
437 msg = "Regular expression error in %s: %s" | 435 msg = "Regular expression error in %s: %s" |
438 raise re.error, msg % (repr(s), e[0]) | 436 raise re.error(msg % (repr(s), e[0])) |
439 if not expr.search(lines[i]): | 437 if not expr.search(lines[i]): |
440 return | 438 return |
441 return 1 | 439 return 1 |
442 | 440 |
443 def match_re_dotall(lines = None, res = None): | 441 def match_re_dotall(lines = None, res = None): |
444 """ | 442 """ |
445 """ | 443 """ |
446 if not type(lines) is type(""): | 444 if not type(lines) is type(""): |
447 lines = string.join(lines, "\n") | 445 lines = "\n".join(lines) |
448 if not type(res) is type(""): | 446 if not type(res) is type(""): |
449 res = string.join(res, "\n") | 447 res = "\n".join(res) |
450 s = "^" + res + "$" | 448 s = "^" + res + "$" |
451 try: | 449 try: |
452 expr = re.compile(s, re.DOTALL) | 450 expr = re.compile(s, re.DOTALL) |
453 except re.error, e: | 451 except re.error as e: |
454 msg = "Regular expression error in %s: %s" | 452 msg = "Regular expression error in %s: %s" |
455 raise re.error, msg % (repr(s), e[0]) | 453 raise re.error(msg % (repr(s), e[0])) |
456 if expr.match(lines): | 454 if expr.match(lines): |
457 return 1 | 455 return 1 |
458 | 456 |
459 try: | 457 try: |
460 import difflib | 458 import difflib |
461 except ImportError: | 459 except ImportError: |
462 pass | 460 pass |
463 else: | 461 else: |
464 def simple_diff(a, b, fromfile='', tofile='', | 462 def simple_diff(a, b, fromfile='', tofile='', |
465 fromfiledate='', tofiledate='', n=3, lineterm='\n'): | 463 fromfiledate='', tofiledate='', n=3, lineterm='\n'): |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 diff = len(a) - len(b) | 497 diff = len(a) - len(b) |
500 if diff < 0: | 498 if diff < 0: |
501 a = a + ['']*(-diff) | 499 a = a + ['']*(-diff) |
502 elif diff > 0: | 500 elif diff > 0: |
503 b = b + ['']*diff | 501 b = b + ['']*diff |
504 i = 0 | 502 i = 0 |
505 for aline, bline in zip(a, b): | 503 for aline, bline in zip(a, b): |
506 s = "^" + aline + "$" | 504 s = "^" + aline + "$" |
507 try: | 505 try: |
508 expr = re.compile(s) | 506 expr = re.compile(s) |
509 except re.error, e: | 507 except re.error as e: |
510 msg = "Regular expression error in %s: %s" | 508 msg = "Regular expression error in %s: %s" |
511 raise re.error, msg % (repr(s), e[0]) | 509 raise re.error(msg % (repr(s), e[0])) |
512 if not expr.search(bline): | 510 if not expr.search(bline): |
513 result.append("%sc%s" % (i+1, i+1)) | 511 result.append("%sc%s" % (i+1, i+1)) |
514 result.append('< ' + repr(a[i])) | 512 result.append('< ' + repr(a[i])) |
515 result.append('---') | 513 result.append('---') |
516 result.append('> ' + repr(b[i])) | 514 result.append('> ' + repr(b[i])) |
517 i = i+1 | 515 i = i+1 |
518 return result | 516 return result |
519 | 517 |
520 if os.name == 'java': | 518 if os.name == 'java': |
521 | 519 |
522 python_executable = os.path.join(sys.prefix, 'jython') | 520 python_executable = os.path.join(sys.prefix, 'jython') |
523 | 521 |
524 else: | 522 else: |
525 | 523 |
526 python_executable = sys.executable | 524 python_executable = sys.executable |
527 | 525 |
528 if sys.platform == 'win32': | 526 if sys.platform == 'win32': |
529 | 527 |
530 default_sleep_seconds = 2 | 528 default_sleep_seconds = 2 |
531 | 529 |
532 def where_is(file, path=None, pathext=None): | 530 def where_is(file, path=None, pathext=None): |
533 if path is None: | 531 if path is None: |
534 path = os.environ['PATH'] | 532 path = os.environ['PATH'] |
535 if is_String(path): | 533 if is_String(path): |
536 path = string.split(path, os.pathsep) | 534 path = path.split(os.pathsep) |
537 if pathext is None: | 535 if pathext is None: |
538 pathext = os.environ['PATHEXT'] | 536 pathext = os.environ['PATHEXT'] |
539 if is_String(pathext): | 537 if is_String(pathext): |
540 pathext = string.split(pathext, os.pathsep) | 538 pathext = pathext.split(os.pathsep) |
541 for ext in pathext: | 539 for ext in pathext: |
542 if string.lower(ext) == string.lower(file[-len(ext):]): | 540 if ext.lower() == file[-len(ext):].lower(): |
543 pathext = [''] | 541 pathext = [''] |
544 break | 542 break |
545 for dir in path: | 543 for dir in path: |
546 f = os.path.join(dir, file) | 544 f = os.path.join(dir, file) |
547 for ext in pathext: | 545 for ext in pathext: |
548 fext = f + ext | 546 fext = f + ext |
549 if os.path.isfile(fext): | 547 if os.path.isfile(fext): |
550 return fext | 548 return fext |
551 return None | 549 return None |
552 | 550 |
553 else: | 551 else: |
554 | 552 |
555 def where_is(file, path=None, pathext=None): | 553 def where_is(file, path=None, pathext=None): |
556 if path is None: | 554 if path is None: |
557 path = os.environ['PATH'] | 555 path = os.environ['PATH'] |
558 if is_String(path): | 556 if is_String(path): |
559 path = string.split(path, os.pathsep) | 557 path = path.split(os.pathsep) |
560 for dir in path: | 558 for dir in path: |
561 f = os.path.join(dir, file) | 559 f = os.path.join(dir, file) |
562 if os.path.isfile(f): | 560 if os.path.isfile(f): |
563 try: | 561 try: |
564 st = os.stat(f) | 562 st = os.stat(f) |
565 except OSError: | 563 except OSError: |
566 continue | 564 continue |
567 if stat.S_IMODE(st[stat.ST_MODE]) & 0111: | 565 if stat.S_IMODE(st[stat.ST_MODE]) & 0o111: |
568 return f | 566 return f |
569 return None | 567 return None |
570 | 568 |
571 default_sleep_seconds = 1 | 569 default_sleep_seconds = 1 |
572 | 570 |
573 | 571 |
574 | 572 |
575 try: | 573 try: |
576 import subprocess | 574 import subprocess |
577 except ImportError: | 575 except ImportError: |
578 # The subprocess module doesn't exist in this version of Python, | 576 # The subprocess module doesn't exist in this version of Python, |
579 # so we're going to cobble up something that looks just enough | 577 # so we're going to cobble up something that looks just enough |
580 # like its API for our purposes below. | 578 # like its API for our purposes below. |
581 import new | 579 import new |
582 | 580 |
583 subprocess = new.module('subprocess') | 581 subprocess = new.module('subprocess') |
584 | 582 |
585 subprocess.PIPE = 'PIPE' | 583 subprocess.PIPE = 'PIPE' |
586 subprocess.STDOUT = 'STDOUT' | 584 subprocess.STDOUT = 'STDOUT' |
587 subprocess.mswindows = (sys.platform == 'win32') | |
588 | 585 |
589 try: | 586 try: |
590 import popen2 | 587 import popen2 |
591 popen2.Popen3 | 588 popen2.Popen3 |
592 except AttributeError: | 589 except AttributeError: |
593 class Popen3: | 590 class Popen3(object): |
594 universal_newlines = 1 | 591 universal_newlines = 1 |
595 def __init__(self, command, **kw): | 592 def __init__(self, command, **kw): |
596 if sys.platform == 'win32' and command[0] == '"': | 593 if sys.platform == 'win32' and command[0] == '"': |
597 command = '"' + command + '"' | 594 command = '"' + command + '"' |
598 (stdin, stdout, stderr) = os.popen3(' ' + command) | 595 (stdin, stdout, stderr) = os.popen3(' ' + command) |
599 self.stdin = stdin | 596 self.stdin = stdin |
600 self.stdout = stdout | 597 self.stdout = stdout |
601 self.stderr = stderr | 598 self.stderr = stderr |
602 def close_output(self): | 599 def close_output(self): |
603 self.stdout.close() | 600 self.stdout.close() |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 os.close(c2pwrite) | 642 os.close(c2pwrite) |
646 self.fromchild = os.fdopen(c2pread, 'r', bufsize) | 643 self.fromchild = os.fdopen(c2pread, 'r', bufsize) |
647 popen2._active.append(self) | 644 popen2._active.append(self) |
648 | 645 |
649 popen2.Popen4 = Popen4 | 646 popen2.Popen4 = Popen4 |
650 | 647 |
651 class Popen3(popen2.Popen3, popen2.Popen4): | 648 class Popen3(popen2.Popen3, popen2.Popen4): |
652 universal_newlines = 1 | 649 universal_newlines = 1 |
653 def __init__(self, command, **kw): | 650 def __init__(self, command, **kw): |
654 if kw.get('stderr') == 'STDOUT': | 651 if kw.get('stderr') == 'STDOUT': |
655 apply(popen2.Popen4.__init__, (self, command, 1)) | 652 popen2.Popen4.__init__(self, command, 1) |
656 else: | 653 else: |
657 apply(popen2.Popen3.__init__, (self, command, 1)) | 654 popen2.Popen3.__init__(self, command, 1) |
658 self.stdin = self.tochild | 655 self.stdin = self.tochild |
659 self.stdout = self.fromchild | 656 self.stdout = self.fromchild |
660 self.stderr = self.childerr | 657 self.stderr = self.childerr |
661 def wait(self, *args, **kw): | 658 def wait(self, *args, **kw): |
662 resultcode = apply(popen2.Popen3.wait, (self,)+args, kw) | 659 resultcode = popen2.Popen3.wait(self, *args, **kw) |
663 if os.WIFEXITED(resultcode): | 660 if os.WIFEXITED(resultcode): |
664 return os.WEXITSTATUS(resultcode) | 661 return os.WEXITSTATUS(resultcode) |
665 elif os.WIFSIGNALED(resultcode): | 662 elif os.WIFSIGNALED(resultcode): |
666 return os.WTERMSIG(resultcode) | 663 return os.WTERMSIG(resultcode) |
667 else: | 664 else: |
668 return None | 665 return None |
669 | 666 |
670 subprocess.Popen = Popen3 | 667 subprocess.Popen = Popen3 |
671 | 668 |
672 | 669 |
673 | 670 |
674 # From Josiah Carlson, | 671 # From Josiah Carlson, |
675 # ASPN : Python Cookbook : Module to allow Asynchronous subprocess use on Window
s and Posix platforms | 672 # ASPN : Python Cookbook : Module to allow Asynchronous subprocess use on Window
s and Posix platforms |
676 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554 | 673 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554 |
677 | 674 |
678 PIPE = subprocess.PIPE | 675 PIPE = subprocess.PIPE |
679 | 676 |
680 if subprocess.mswindows: | 677 if sys.platform == 'win32': |
681 from win32file import ReadFile, WriteFile | 678 from win32file import ReadFile, WriteFile |
682 from win32pipe import PeekNamedPipe | 679 from win32pipe import PeekNamedPipe |
683 import msvcrt | 680 import msvcrt |
684 else: | 681 else: |
685 import select | 682 import select |
686 import fcntl | 683 import fcntl |
687 | 684 |
688 try: fcntl.F_GETFL | 685 try: fcntl.F_GETFL |
689 except AttributeError: fcntl.F_GETFL = 3 | 686 except AttributeError: fcntl.F_GETFL = 3 |
690 | 687 |
(...skipping 14 matching lines...) Expand all Loading... |
705 if maxsize is None: | 702 if maxsize is None: |
706 maxsize = 1024 | 703 maxsize = 1024 |
707 elif maxsize < 1: | 704 elif maxsize < 1: |
708 maxsize = 1 | 705 maxsize = 1 |
709 return getattr(self, which), maxsize | 706 return getattr(self, which), maxsize |
710 | 707 |
711 def _close(self, which): | 708 def _close(self, which): |
712 getattr(self, which).close() | 709 getattr(self, which).close() |
713 setattr(self, which, None) | 710 setattr(self, which, None) |
714 | 711 |
715 if subprocess.mswindows: | 712 if sys.platform == 'win32': |
716 def send(self, input): | 713 def send(self, input): |
717 if not self.stdin: | 714 if not self.stdin: |
718 return None | 715 return None |
719 | 716 |
720 try: | 717 try: |
721 x = msvcrt.get_osfhandle(self.stdin.fileno()) | 718 x = msvcrt.get_osfhandle(self.stdin.fileno()) |
722 (errCode, written) = WriteFile(x, input) | 719 (errCode, written) = WriteFile(x, input) |
723 except ValueError: | 720 except ValueError: |
724 return self._close('stdin') | 721 return self._close('stdin') |
725 except (subprocess.pywintypes.error, Exception), why: | 722 except (subprocess.pywintypes.error, Exception) as why: |
726 if why[0] in (109, errno.ESHUTDOWN): | 723 if why[0] in (109, errno.ESHUTDOWN): |
727 return self._close('stdin') | 724 return self._close('stdin') |
728 raise | 725 raise |
729 | 726 |
730 return written | 727 return written |
731 | 728 |
732 def _recv(self, which, maxsize): | 729 def _recv(self, which, maxsize): |
733 conn, maxsize = self.get_conn_maxsize(which, maxsize) | 730 conn, maxsize = self.get_conn_maxsize(which, maxsize) |
734 if conn is None: | 731 if conn is None: |
735 return None | 732 return None |
736 | 733 |
737 try: | 734 try: |
738 x = msvcrt.get_osfhandle(conn.fileno()) | 735 x = msvcrt.get_osfhandle(conn.fileno()) |
739 (read, nAvail, nMessage) = PeekNamedPipe(x, 0) | 736 (read, nAvail, nMessage) = PeekNamedPipe(x, 0) |
740 if maxsize < nAvail: | 737 if maxsize < nAvail: |
741 nAvail = maxsize | 738 nAvail = maxsize |
742 if nAvail > 0: | 739 if nAvail > 0: |
743 (errCode, read) = ReadFile(x, nAvail, None) | 740 (errCode, read) = ReadFile(x, nAvail, None) |
744 except ValueError: | 741 except ValueError: |
745 return self._close(which) | 742 return self._close(which) |
746 except (subprocess.pywintypes.error, Exception), why: | 743 except (subprocess.pywintypes.error, Exception) as why: |
747 if why[0] in (109, errno.ESHUTDOWN): | 744 if why[0] in (109, errno.ESHUTDOWN): |
748 return self._close(which) | 745 return self._close(which) |
749 raise | 746 raise |
750 | 747 |
751 #if self.universal_newlines: | 748 #if self.universal_newlines: |
752 # read = self._translate_newlines(read) | 749 # read = self._translate_newlines(read) |
753 return read | 750 return read |
754 | 751 |
755 else: | 752 else: |
756 def send(self, input): | 753 def send(self, input): |
757 if not self.stdin: | 754 if not self.stdin: |
758 return None | 755 return None |
759 | 756 |
760 if not select.select([], [self.stdin], [], 0)[1]: | 757 if not select.select([], [self.stdin], [], 0)[1]: |
761 return 0 | 758 return 0 |
762 | 759 |
763 try: | 760 try: |
764 written = os.write(self.stdin.fileno(), input) | 761 written = os.write(self.stdin.fileno(), input) |
765 except OSError, why: | 762 except OSError as why: |
766 if why[0] == errno.EPIPE: #broken pipe | 763 if why[0] == errno.EPIPE: #broken pipe |
767 return self._close('stdin') | 764 return self._close('stdin') |
768 raise | 765 raise |
769 | 766 |
770 return written | 767 return written |
771 | 768 |
772 def _recv(self, which, maxsize): | 769 def _recv(self, which, maxsize): |
773 conn, maxsize = self.get_conn_maxsize(which, maxsize) | 770 conn, maxsize = self.get_conn_maxsize(which, maxsize) |
774 if conn is None: | 771 if conn is None: |
775 return None | 772 return None |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
824 # TODO(3.0: rewrite to use memoryview() | 821 # TODO(3.0: rewrite to use memoryview() |
825 def send_all(p, data): | 822 def send_all(p, data): |
826 while len(data): | 823 while len(data): |
827 sent = p.send(data) | 824 sent = p.send(data) |
828 if sent is None: | 825 if sent is None: |
829 raise Exception(disconnect_message) | 826 raise Exception(disconnect_message) |
830 data = buffer(data, sent) | 827 data = buffer(data, sent) |
831 | 828 |
832 | 829 |
833 | 830 |
834 try: | |
835 object | |
836 except NameError: | |
837 class object: | |
838 pass | |
839 | |
840 | |
841 | |
842 class TestCmd(object): | 831 class TestCmd(object): |
843 """Class TestCmd | 832 """Class TestCmd |
844 """ | 833 """ |
845 | 834 |
846 def __init__(self, description = None, | 835 def __init__(self, description = None, |
847 program = None, | 836 program = None, |
848 interpreter = None, | 837 interpreter = None, |
849 workdir = None, | 838 workdir = None, |
850 subdir = None, | 839 subdir = None, |
851 verbose = None, | 840 verbose = None, |
(...skipping 23 matching lines...) Expand all Loading... |
875 try: | 864 try: |
876 difflib | 865 difflib |
877 except NameError: | 866 except NameError: |
878 pass | 867 pass |
879 else: | 868 else: |
880 self.diff_function = simple_diff | 869 self.diff_function = simple_diff |
881 #self.diff_function = difflib.context_diff | 870 #self.diff_function = difflib.context_diff |
882 #self.diff_function = difflib.unified_diff | 871 #self.diff_function = difflib.unified_diff |
883 self._dirlist = [] | 872 self._dirlist = [] |
884 self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0} | 873 self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0} |
885 if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '': | 874 if 'PRESERVE' in os.environ and os.environ['PRESERVE'] is not '': |
886 self._preserve['pass_test'] = os.environ['PRESERVE'] | 875 self._preserve['pass_test'] = os.environ['PRESERVE'] |
887 self._preserve['fail_test'] = os.environ['PRESERVE'] | 876 self._preserve['fail_test'] = os.environ['PRESERVE'] |
888 self._preserve['no_result'] = os.environ['PRESERVE'] | 877 self._preserve['no_result'] = os.environ['PRESERVE'] |
889 else: | 878 else: |
890 try: | 879 try: |
891 self._preserve['pass_test'] = os.environ['PRESERVE_PASS'] | 880 self._preserve['pass_test'] = os.environ['PRESERVE_PASS'] |
892 except KeyError: | 881 except KeyError: |
893 pass | 882 pass |
894 try: | 883 try: |
895 self._preserve['fail_test'] = os.environ['PRESERVE_FAIL'] | 884 self._preserve['fail_test'] = os.environ['PRESERVE_FAIL'] |
(...skipping 24 matching lines...) Expand all Loading... |
920 width = self.banner_width | 909 width = self.banner_width |
921 return s + self.banner_char * (width - len(s)) | 910 return s + self.banner_char * (width - len(s)) |
922 | 911 |
923 if os.name == 'posix': | 912 if os.name == 'posix': |
924 | 913 |
925 def escape(self, arg): | 914 def escape(self, arg): |
926 "escape shell special characters" | 915 "escape shell special characters" |
927 slash = '\\' | 916 slash = '\\' |
928 special = '"$' | 917 special = '"$' |
929 | 918 |
930 arg = string.replace(arg, slash, slash+slash) | 919 arg = arg.replace(slash, slash+slash) |
931 for c in special: | 920 for c in special: |
932 arg = string.replace(arg, c, slash+c) | 921 arg = arg.replace(c, slash+c) |
933 | 922 |
934 if re_space.search(arg): | 923 if re_space.search(arg): |
935 arg = '"' + arg + '"' | 924 arg = '"' + arg + '"' |
936 return arg | 925 return arg |
937 | 926 |
938 else: | 927 else: |
939 | 928 |
940 # Windows does not allow special characters in file names | 929 # Windows does not allow special characters in file names |
941 # anyway, so no need for an escape function, we will just quote | 930 # anyway, so no need for an escape function, we will just quote |
942 # the arg. | 931 # the arg. |
943 def escape(self, arg): | 932 def escape(self, arg): |
944 if re_space.search(arg): | 933 if re_space.search(arg): |
945 arg = '"' + arg + '"' | 934 arg = '"' + arg + '"' |
946 return arg | 935 return arg |
947 | 936 |
948 def canonicalize(self, path): | 937 def canonicalize(self, path): |
949 if is_List(path): | 938 if is_List(path): |
950 path = apply(os.path.join, tuple(path)) | 939 path = os.path.join(*path) |
951 if not os.path.isabs(path): | 940 if not os.path.isabs(path): |
952 path = os.path.join(self.workdir, path) | 941 path = os.path.join(self.workdir, path) |
953 return path | 942 return path |
954 | 943 |
955 def chmod(self, path, mode): | 944 def chmod(self, path, mode): |
956 """Changes permissions on the specified file or directory | 945 """Changes permissions on the specified file or directory |
957 path name.""" | 946 path name.""" |
958 path = self.canonicalize(path) | 947 path = self.canonicalize(path) |
959 os.chmod(path, mode) | 948 os.chmod(path, mode) |
960 | 949 |
(...skipping 13 matching lines...) Expand all Loading... |
974 appropriate for the exit status. | 963 appropriate for the exit status. |
975 """ | 964 """ |
976 if not self._dirlist: | 965 if not self._dirlist: |
977 return | 966 return |
978 os.chdir(self._cwd) | 967 os.chdir(self._cwd) |
979 self.workdir = None | 968 self.workdir = None |
980 if condition is None: | 969 if condition is None: |
981 condition = self.condition | 970 condition = self.condition |
982 if self._preserve[condition]: | 971 if self._preserve[condition]: |
983 for dir in self._dirlist: | 972 for dir in self._dirlist: |
984 print "Preserved directory", dir | 973 print("Preserved directory", dir) |
985 else: | 974 else: |
986 list = self._dirlist[:] | 975 list = self._dirlist[:] |
987 list.reverse() | 976 list.reverse() |
988 for dir in list: | 977 for dir in list: |
989 self.writable(dir, 1) | 978 self.writable(dir, 1) |
990 shutil.rmtree(dir, ignore_errors = 1) | 979 shutil.rmtree(dir, ignore_errors = 1) |
991 self._dirlist = [] | 980 self._dirlist = [] |
992 | 981 |
993 try: | 982 try: |
994 global _Cleanup | 983 global _Cleanup |
(...skipping 13 matching lines...) Expand all Loading... |
1008 interpreter = self.interpreter | 997 interpreter = self.interpreter |
1009 if not type(program) in [type([]), type(())]: | 998 if not type(program) in [type([]), type(())]: |
1010 program = [program] | 999 program = [program] |
1011 cmd = list(program) | 1000 cmd = list(program) |
1012 if interpreter: | 1001 if interpreter: |
1013 if not type(interpreter) in [type([]), type(())]: | 1002 if not type(interpreter) in [type([]), type(())]: |
1014 interpreter = [interpreter] | 1003 interpreter = [interpreter] |
1015 cmd = list(interpreter) + cmd | 1004 cmd = list(interpreter) + cmd |
1016 if arguments: | 1005 if arguments: |
1017 if type(arguments) == type(''): | 1006 if type(arguments) == type(''): |
1018 arguments = string.split(arguments) | 1007 arguments = arguments.split() |
1019 cmd.extend(arguments) | 1008 cmd.extend(arguments) |
1020 return cmd | 1009 return cmd |
1021 | 1010 |
1022 def description_set(self, description): | 1011 def description_set(self, description): |
1023 """Set the description of the functionality being tested. | 1012 """Set the description of the functionality being tested. |
1024 """ | 1013 """ |
1025 self.description = description | 1014 self.description = description |
1026 | 1015 |
1027 try: | 1016 try: |
1028 difflib | 1017 difflib |
1029 except NameError: | 1018 except NameError: |
1030 def diff(self, a, b, name, *args, **kw): | 1019 def diff(self, a, b, name, *args, **kw): |
1031 print self.banner('Expected %s' % name) | 1020 print(self.banner('Expected %s' % name)) |
1032 print a | 1021 print(a) |
1033 print self.banner('Actual %s' % name) | 1022 print(self.banner('Actual %s' % name)) |
1034 print b | 1023 print(b) |
1035 else: | 1024 else: |
1036 def diff(self, a, b, name, *args, **kw): | 1025 def diff(self, a, b, name, *args, **kw): |
1037 print self.banner(name) | 1026 print(self.banner(name)) |
1038 args = (a.splitlines(), b.splitlines()) + args | 1027 args = (a.splitlines(), b.splitlines()) + args |
1039 lines = apply(self.diff_function, args, kw) | 1028 lines = self.diff_function(*args, **kw) |
1040 for l in lines: | 1029 for l in lines: |
1041 print l | 1030 print(l) |
1042 | 1031 |
1043 def fail_test(self, condition = 1, function = None, skip = 0): | 1032 def fail_test(self, condition = 1, function = None, skip = 0): |
1044 """Cause the test to fail. | 1033 """Cause the test to fail. |
1045 """ | 1034 """ |
1046 if not condition: | 1035 if not condition: |
1047 return | 1036 return |
1048 self.condition = 'fail_test' | 1037 self.condition = 'fail_test' |
1049 fail_test(self = self, | 1038 fail_test(self = self, |
1050 condition = condition, | 1039 condition = condition, |
1051 function = function, | 1040 function = function, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1108 for cond in conditions: | 1097 for cond in conditions: |
1109 self._preserve[cond] = 1 | 1098 self._preserve[cond] = 1 |
1110 | 1099 |
1111 def program_set(self, program): | 1100 def program_set(self, program): |
1112 """Set the executable program or script to be tested. | 1101 """Set the executable program or script to be tested. |
1113 """ | 1102 """ |
1114 if program and not os.path.isabs(program): | 1103 if program and not os.path.isabs(program): |
1115 program = os.path.join(self._cwd, program) | 1104 program = os.path.join(self._cwd, program) |
1116 self.program = program | 1105 self.program = program |
1117 | 1106 |
1118 def read(self, file, mode = 'rb'): | 1107 def read(self, file, mode = 'r'): |
1119 """Reads and returns the contents of the specified file name. | 1108 """Reads and returns the contents of the specified file name. |
1120 The file name may be a list, in which case the elements are | 1109 The file name may be a list, in which case the elements are |
1121 concatenated with the os.path.join() method. The file is | 1110 concatenated with the os.path.join() method. The file is |
1122 assumed to be under the temporary working directory unless it | 1111 assumed to be under the temporary working directory unless it |
1123 is an absolute path name. The I/O mode for the file may | 1112 is an absolute path name. The I/O mode for the file may |
1124 be specified; it must begin with an 'r'. The default is | 1113 be specified; it must begin with an 'r'. The default is |
1125 'rb' (binary read). | 1114 'r' (string read). |
1126 """ | 1115 """ |
1127 file = self.canonicalize(file) | 1116 file = self.canonicalize(file) |
1128 if mode[0] != 'r': | 1117 if mode[0] != 'r': |
1129 raise ValueError, "mode must begin with 'r'" | 1118 raise ValueError("mode must begin with 'r'") |
1130 with open(file, mode) as f: | 1119 with open(file, mode) as f: |
1131 result = f.read() | 1120 result = f.read() |
1132 return result | 1121 return result |
1133 | 1122 |
1134 def rmdir(self, dir): | 1123 def rmdir(self, dir): |
1135 """Removes the specified dir name. | 1124 """Removes the specified dir name. |
1136 The dir name may be a list, in which case the elements are | 1125 The dir name may be a list, in which case the elements are |
1137 concatenated with the os.path.join() method. The dir is | 1126 concatenated with the os.path.join() method. The dir is |
1138 assumed to be under the temporary working directory unless it | 1127 assumed to be under the temporary working directory unless it |
1139 is an absolute path name. | 1128 is an absolute path name. |
1140 The dir must be empty. | 1129 The dir must be empty. |
1141 """ | 1130 """ |
1142 dir = self.canonicalize(dir) | 1131 dir = self.canonicalize(dir) |
1143 os.rmdir(dir) | 1132 os.rmdir(dir) |
1144 | 1133 |
1145 def start(self, program = None, | 1134 def start(self, program = None, |
1146 interpreter = None, | 1135 interpreter = None, |
1147 arguments = None, | 1136 arguments = None, |
1148 universal_newlines = None, | 1137 universal_newlines = None, |
1149 **kw): | 1138 **kw): |
1150 """ | 1139 """ |
1151 Starts a program or script for the test environment. | 1140 Starts a program or script for the test environment. |
1152 | 1141 |
1153 The specified program will have the original directory | 1142 The specified program will have the original directory |
1154 prepended unless it is enclosed in a [list]. | 1143 prepended unless it is enclosed in a [list]. |
1155 """ | 1144 """ |
1156 cmd = self.command_args(program, interpreter, arguments) | 1145 cmd = self.command_args(program, interpreter, arguments) |
1157 cmd_string = string.join(map(self.escape, cmd), ' ') | 1146 cmd_string = ' '.join(map(self.escape, cmd)) |
1158 if self.verbose: | 1147 if self.verbose: |
1159 sys.stderr.write(cmd_string + "\n") | 1148 sys.stderr.write(cmd_string + "\n") |
1160 if universal_newlines is None: | 1149 if universal_newlines is None: |
1161 universal_newlines = self.universal_newlines | 1150 universal_newlines = self.universal_newlines |
1162 | 1151 |
1163 # On Windows, if we make stdin a pipe when we plan to send | 1152 # On Windows, if we make stdin a pipe when we plan to send |
1164 # no input, and the test program exits before | 1153 # no input, and the test program exits before |
1165 # Popen calls msvcrt.open_osfhandle, that call will fail. | 1154 # Popen calls msvcrt.open_osfhandle, that call will fail. |
1166 # So don't use a pipe for stdin if we don't need one. | 1155 # So don't use a pipe for stdin if we don't need one. |
1167 stdin = kw.get('stdin', None) | 1156 stdin = kw.get('stdin', None) |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1312 | 1301 |
1313 test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory']) | 1302 test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory']) |
1314 | 1303 |
1315 Returns the number of subdirectories actually created. | 1304 Returns the number of subdirectories actually created. |
1316 """ | 1305 """ |
1317 count = 0 | 1306 count = 0 |
1318 for sub in subdirs: | 1307 for sub in subdirs: |
1319 if sub is None: | 1308 if sub is None: |
1320 continue | 1309 continue |
1321 if is_List(sub): | 1310 if is_List(sub): |
1322 sub = apply(os.path.join, tuple(sub)) | 1311 sub = os.path.join(*sub) |
1323 new = os.path.join(self.workdir, sub) | 1312 new = os.path.join(self.workdir, sub) |
1324 try: | 1313 try: |
1325 os.mkdir(new) | 1314 os.mkdir(new) |
1326 except OSError: | 1315 except OSError: |
1327 pass | 1316 pass |
1328 else: | 1317 else: |
1329 count = count + 1 | 1318 count = count + 1 |
1330 return count | 1319 return count |
1331 | 1320 |
1332 def symlink(self, target, link): | 1321 def symlink(self, target, link): |
(...skipping 27 matching lines...) Expand all Loading... |
1360 try: | 1349 try: |
1361 os.chdir(path) | 1350 os.chdir(path) |
1362 path = os.getcwd() | 1351 path = os.getcwd() |
1363 finally: | 1352 finally: |
1364 os.chdir(cwd) | 1353 os.chdir(cwd) |
1365 | 1354 |
1366 # Uppercase the drive letter since the case of drive | 1355 # Uppercase the drive letter since the case of drive |
1367 # letters is pretty much random on win32: | 1356 # letters is pretty much random on win32: |
1368 drive,rest = os.path.splitdrive(path) | 1357 drive,rest = os.path.splitdrive(path) |
1369 if drive: | 1358 if drive: |
1370 path = string.upper(drive) + rest | 1359 path = drive.upper() + rest |
1371 | 1360 |
1372 # | 1361 # |
1373 self._dirlist.append(path) | 1362 self._dirlist.append(path) |
1374 global _Cleanup | 1363 global _Cleanup |
1375 try: | 1364 try: |
1376 _Cleanup.index(self) | 1365 _Cleanup.index(self) |
1377 except ValueError: | 1366 except ValueError: |
1378 _Cleanup.append(self) | 1367 _Cleanup.append(self) |
1379 | 1368 |
1380 return path | 1369 return path |
(...skipping 21 matching lines...) Expand all Loading... |
1402 | 1391 |
1403 def verbose_set(self, verbose): | 1392 def verbose_set(self, verbose): |
1404 """Set the verbose level. | 1393 """Set the verbose level. |
1405 """ | 1394 """ |
1406 self.verbose = verbose | 1395 self.verbose = verbose |
1407 | 1396 |
1408 def where_is(self, file, path=None, pathext=None): | 1397 def where_is(self, file, path=None, pathext=None): |
1409 """Find an executable file. | 1398 """Find an executable file. |
1410 """ | 1399 """ |
1411 if is_List(file): | 1400 if is_List(file): |
1412 file = apply(os.path.join, tuple(file)) | 1401 file = os.path.join(*file) |
1413 if not os.path.isabs(file): | 1402 if not os.path.isabs(file): |
1414 file = where_is(file, path, pathext) | 1403 file = where_is(file, path, pathext) |
1415 return file | 1404 return file |
1416 | 1405 |
1417 def workdir_set(self, path): | 1406 def workdir_set(self, path): |
1418 """Creates a temporary working directory with the specified | 1407 """Creates a temporary working directory with the specified |
1419 path name. If the path is a null string (''), a unique | 1408 path name. If the path is a null string (''), a unique |
1420 directory name is created. | 1409 directory name is created. |
1421 """ | 1410 """ |
1422 if (path != None): | 1411 if (path != None): |
1423 if path == '': | 1412 if path == '': |
1424 path = None | 1413 path = None |
1425 path = self.tempdir(path) | 1414 path = self.tempdir(path) |
1426 self.workdir = path | 1415 self.workdir = path |
1427 | 1416 |
1428 def workpath(self, *args): | 1417 def workpath(self, *args): |
1429 """Returns the absolute path name to a subdirectory or file | 1418 """Returns the absolute path name to a subdirectory or file |
1430 within the current temporary working directory. Concatenates | 1419 within the current temporary working directory. Concatenates |
1431 the temporary working directory name with the specified | 1420 the temporary working directory name with the specified |
1432 arguments using the os.path.join() method. | 1421 arguments using the os.path.join() method. |
1433 """ | 1422 """ |
1434 return apply(os.path.join, (self.workdir,) + tuple(args)) | 1423 return os.path.join(self.workdir, *args) |
1435 | 1424 |
1436 def readable(self, top, read=1): | 1425 def readable(self, top, read=1): |
1437 """Make the specified directory tree readable (read == 1) | 1426 """Make the specified directory tree readable (read == 1) |
1438 or not (read == None). | 1427 or not (read == None). |
1439 | 1428 |
1440 This method has no effect on Windows systems, which use a | 1429 This method has no effect on Windows systems, which use a |
1441 completely different mechanism to control file readability. | 1430 completely different mechanism to control file readability. |
1442 """ | 1431 """ |
1443 | 1432 |
1444 if sys.platform == 'win32': | 1433 if sys.platform == 'win32': |
(...skipping 10 matching lines...) Expand all Loading... |
1455 except OSError: pass | 1444 except OSError: pass |
1456 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IREA
D)) | 1445 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IREA
D)) |
1457 | 1446 |
1458 if os.path.isfile(top): | 1447 if os.path.isfile(top): |
1459 # If it's a file, that's easy, just chmod it. | 1448 # If it's a file, that's easy, just chmod it. |
1460 do_chmod(top) | 1449 do_chmod(top) |
1461 elif read: | 1450 elif read: |
1462 # It's a directory and we're trying to turn on read | 1451 # It's a directory and we're trying to turn on read |
1463 # permission, so it's also pretty easy, just chmod the | 1452 # permission, so it's also pretty easy, just chmod the |
1464 # directory and then chmod every entry on our walk down the | 1453 # directory and then chmod every entry on our walk down the |
1465 # tree. Because os.path.walk() is top-down, we'll enable | 1454 # tree. Because os.walk() is top-down, we'll enable |
1466 # read permission on any directories that have it disabled | 1455 # read permission on any directories that have it disabled |
1467 # before os.path.walk() tries to list their contents. | 1456 # before os.walk() tries to list their contents. |
1468 do_chmod(top) | 1457 do_chmod(top) |
1469 | 1458 |
1470 def chmod_entries(arg, dirname, names, do_chmod=do_chmod): | 1459 for dirname, dirnames, filenames in os.walk(top): |
1471 for n in names: | 1460 for n in dirnames: |
1472 do_chmod(os.path.join(dirname, n)) | 1461 do_chmod(os.path.join(dirname, n)) |
1473 | 1462 for n in filenames: |
1474 os.path.walk(top, chmod_entries, None) | 1463 do_chmod(os.path.join(dirname, n)) |
1475 else: | 1464 else: |
1476 # It's a directory and we're trying to turn off read | 1465 # It's a directory and we're trying to turn off read |
1477 # permission, which means we have to chmod the directoreis | 1466 # permission, which means we have to chmod the directoreis |
1478 # in the tree bottom-up, lest disabling read permission from | 1467 # in the tree bottom-up, lest disabling read permission from |
1479 # the top down get in the way of being able to get at lower | 1468 # the top down get in the way of being able to get at lower |
1480 # parts of the tree. But os.path.walk() visits things top | 1469 # parts of the tree. |
1481 # down, so we just use an object to collect a list of all | 1470 for dirname, dirnames, filenames in os.walk(top, topdown=False): |
1482 # of the entries in the tree, reverse the list, and then | 1471 for n in dirnames: |
1483 # chmod the reversed (bottom-up) list. | 1472 do_chmod(os.path.join(dirname, n)) |
1484 col = Collector(top) | 1473 for n in filenames: |
1485 os.path.walk(top, col, None) | 1474 do_chmod(os.path.join(dirname, n)) |
1486 col.entries.reverse() | 1475 |
1487 for d in col.entries: do_chmod(d) | 1476 do_chmod(top) |
1488 | 1477 |
1489 def writable(self, top, write=1): | 1478 def writable(self, top, write=1): |
1490 """Make the specified directory tree writable (write == 1) | 1479 """Make the specified directory tree writable (write == 1) |
1491 or not (write == None). | 1480 or not (write == None). |
1492 """ | 1481 """ |
1493 | 1482 |
1494 if sys.platform == 'win32': | 1483 if sys.platform == 'win32': |
1495 | 1484 |
1496 if write: | 1485 if write: |
1497 def do_chmod(fname): | 1486 def do_chmod(fname): |
1498 try: os.chmod(fname, stat.S_IWRITE) | 1487 try: os.chmod(fname, stat.S_IWRITE) |
1499 except OSError: pass | 1488 except OSError: pass |
1500 else: | 1489 else: |
1501 def do_chmod(fname): | 1490 def do_chmod(fname): |
1502 try: os.chmod(fname, stat.S_IREAD) | 1491 try: os.chmod(fname, stat.S_IREAD) |
1503 except OSError: pass | 1492 except OSError: pass |
1504 | 1493 |
1505 else: | 1494 else: |
1506 | 1495 |
1507 if write: | 1496 if write: |
1508 def do_chmod(fname): | 1497 def do_chmod(fname): |
1509 try: st = os.stat(fname) | 1498 try: st = os.stat(fname) |
1510 except OSError: pass | 1499 except OSError: pass |
1511 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200)) | 1500 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0o200)) |
1512 else: | 1501 else: |
1513 def do_chmod(fname): | 1502 def do_chmod(fname): |
1514 try: st = os.stat(fname) | 1503 try: st = os.stat(fname) |
1515 except OSError: pass | 1504 except OSError: pass |
1516 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200)) | 1505 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0o200)) |
1517 | 1506 |
1518 if os.path.isfile(top): | 1507 if os.path.isfile(top): |
1519 do_chmod(top) | 1508 do_chmod(top) |
1520 else: | 1509 else: |
1521 col = Collector(top) | 1510 do_chmod(top) |
1522 os.path.walk(top, col, None) | 1511 for dirname, dirnames, filenames in os.walk(top): |
1523 for d in col.entries: do_chmod(d) | 1512 for n in dirnames: |
| 1513 do_chmod(os.path.join(dirname, n)) |
| 1514 for n in filenames: |
| 1515 do_chmod(os.path.join(dirname, n)) |
1524 | 1516 |
1525 def executable(self, top, execute=1): | 1517 def executable(self, top, execute=1): |
1526 """Make the specified directory tree executable (execute == 1) | 1518 """Make the specified directory tree executable (execute == 1) |
1527 or not (execute == None). | 1519 or not (execute == None). |
1528 | 1520 |
1529 This method has no effect on Windows systems, which use a | 1521 This method has no effect on Windows systems, which use a |
1530 completely different mechanism to control file executability. | 1522 completely different mechanism to control file executability. |
1531 """ | 1523 """ |
1532 | 1524 |
1533 if sys.platform == 'win32': | 1525 if sys.platform == 'win32': |
(...skipping 10 matching lines...) Expand all Loading... |
1544 except OSError: pass | 1536 except OSError: pass |
1545 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IEXE
C)) | 1537 else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IEXE
C)) |
1546 | 1538 |
1547 if os.path.isfile(top): | 1539 if os.path.isfile(top): |
1548 # If it's a file, that's easy, just chmod it. | 1540 # If it's a file, that's easy, just chmod it. |
1549 do_chmod(top) | 1541 do_chmod(top) |
1550 elif execute: | 1542 elif execute: |
1551 # It's a directory and we're trying to turn on execute | 1543 # It's a directory and we're trying to turn on execute |
1552 # permission, so it's also pretty easy, just chmod the | 1544 # permission, so it's also pretty easy, just chmod the |
1553 # directory and then chmod every entry on our walk down the | 1545 # directory and then chmod every entry on our walk down the |
1554 # tree. Because os.path.walk() is top-down, we'll enable | 1546 # tree. Because os.walk() is top-down, we'll enable |
1555 # execute permission on any directories that have it disabled | 1547 # execute permission on any directories that have it disabled |
1556 # before os.path.walk() tries to list their contents. | 1548 # before os.walk() tries to list their contents. |
1557 do_chmod(top) | 1549 do_chmod(top) |
1558 | 1550 |
1559 def chmod_entries(arg, dirname, names, do_chmod=do_chmod): | 1551 for dirname, dirnames, filenames in os.walk(top): |
1560 for n in names: | 1552 for n in dirnames: |
1561 do_chmod(os.path.join(dirname, n)) | 1553 do_chmod(os.path.join(dirname, n)) |
1562 | 1554 for n in filenames: |
1563 os.path.walk(top, chmod_entries, None) | 1555 do_chmod(os.path.join(dirname, n)) |
1564 else: | 1556 else: |
1565 # It's a directory and we're trying to turn off execute | 1557 # It's a directory and we're trying to turn off execute |
1566 # permission, which means we have to chmod the directories | 1558 # permission, which means we have to chmod the directories |
1567 # in the tree bottom-up, lest disabling execute permission from | 1559 # in the tree bottom-up, lest disabling execute permission from |
1568 # the top down get in the way of being able to get at lower | 1560 # the top down get in the way of being able to get at lower |
1569 # parts of the tree. But os.path.walk() visits things top | 1561 # parts of the tree. |
1570 # down, so we just use an object to collect a list of all | 1562 for dirname, dirnames, filenames in os.walk(top, topdown=False): |
1571 # of the entries in the tree, reverse the list, and then | 1563 for n in dirnames: |
1572 # chmod the reversed (bottom-up) list. | 1564 do_chmod(os.path.join(dirname, n)) |
1573 col = Collector(top) | 1565 for n in filenames: |
1574 os.path.walk(top, col, None) | 1566 do_chmod(os.path.join(dirname, n)) |
1575 col.entries.reverse() | |
1576 for d in col.entries: do_chmod(d) | |
1577 | 1567 |
1578 def write(self, file, content, mode = 'wb'): | 1568 do_chmod(top) |
| 1569 |
| 1570 def write(self, file, content, mode = 'w'): |
1579 """Writes the specified content text (second argument) to the | 1571 """Writes the specified content text (second argument) to the |
1580 specified file name (first argument). The file name may be | 1572 specified file name (first argument). The file name may be |
1581 a list, in which case the elements are concatenated with the | 1573 a list, in which case the elements are concatenated with the |
1582 os.path.join() method. The file is created under the temporary | 1574 os.path.join() method. The file is created under the temporary |
1583 working directory. Any subdirectories in the path must already | 1575 working directory. Any subdirectories in the path must already |
1584 exist. The I/O mode for the file may be specified; it must | 1576 exist. The I/O mode for the file may be specified; it must |
1585 begin with a 'w'. The default is 'wb' (binary write). | 1577 begin with a 'w'. The default is 'w' (string write). |
1586 """ | 1578 """ |
1587 file = self.canonicalize(file) | 1579 file = self.canonicalize(file) |
1588 if mode[0] != 'w': | 1580 if mode[0] != 'w': |
1589 raise ValueError, "mode must begin with 'w'" | 1581 raise ValueError("mode must begin with 'w'") |
1590 with open(file, mode) as f: | 1582 with open(file, mode) as f: |
1591 f.write(content) | 1583 f.write(content) |
1592 | 1584 |
1593 # Local Variables: | 1585 # Local Variables: |
1594 # tab-width:4 | 1586 # tab-width:4 |
1595 # indent-tabs-mode:nil | 1587 # indent-tabs-mode:nil |
1596 # End: | 1588 # End: |
1597 # vim: set expandtab tabstop=4 shiftwidth=4: | 1589 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |