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