From d635b1d724e79a1d2dce416b29a95c389fdfab30 Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Tue, 26 Sep 2000 17:32:27 +0000 Subject: The Usual --- Lib/dos-8x3/cgihttps.py | 254 +++++++++++++++++++++++++++++++++--------------- Lib/dos-8x3/configpa.py | 2 +- Lib/dos-8x3/posixfil.py | 3 - Lib/dos-8x3/py_compi.py | 5 + Lib/dos-8x3/sre_pars.py | 2 +- Lib/dos-8x3/stringio.py | 6 +- Lib/dos-8x3/test_arr.py | 14 ++- Lib/dos-8x3/test_cpi.py | 106 +------------------- Lib/dos-8x3/test_exc.py | 49 ++++++++++ Lib/dos-8x3/test_fcn.py | 2 +- Lib/dos-8x3/test_gra.py | 7 ++ Lib/dos-8x3/test_min.py | 125 +++++++++++++++--------- Lib/dos-8x3/test_pic.py | 82 ++++++++++++++-- Lib/dos-8x3/test_pye.py | 74 +++++++------- Lib/dos-8x3/test_rfc.py | 4 + Lib/dos-8x3/test_str.py | 143 +++------------------------ Lib/dos-8x3/test_url.py | 32 ++++++ Lib/dos-8x3/test_win.py | 150 +++++++++++++++++++++++++++- Lib/dos-8x3/userlist.py | 1 + Lib/dos-8x3/webbrows.py | 2 +- 20 files changed, 642 insertions(+), 421 deletions(-) diff --git a/Lib/dos-8x3/cgihttps.py b/Lib/dos-8x3/cgihttps.py index 6a259a3..ba1e76b 100755 --- a/Lib/dos-8x3/cgihttps.py +++ b/Lib/dos-8x3/cgihttps.py @@ -3,28 +3,31 @@ This module builds on SimpleHTTPServer by implementing GET and POST requests to cgi-bin scripts. -If the os.fork() function is not present, this module will not work; -SystemError will be raised instead. +If the os.fork() function is not present (e.g. on Windows), +os.popen2() is used as a fallback, with slightly altered semantics; if +that function is not present either (e.g. on Macintosh), only Python +scripts are supported, and they are executed by the current process. + +In all cases, the implementation is intentionally naive -- all +requests are executed sychronously. + +SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL +-- it may execute arbitrary Python code or external programs. """ -__version__ = "0.3" +__version__ = "0.4" import os +import sys import string import urllib import BaseHTTPServer import SimpleHTTPServer -try: - os.fork -except AttributeError: - raise SystemError, __name__ + " requires os.fork()" - - class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): """Complete HTTP server with GET, HEAD and POST commands. @@ -35,6 +38,10 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): """ + # Determine platform specifics + have_fork = hasattr(os, 'fork') + have_popen2 = hasattr(os, 'popen2') + # Make rfile unbuffered -- we need to read one line and then pass # the rest to a subprocess, so we can't use buffered input. rbufsize = 0 @@ -59,9 +66,9 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self) def is_cgi(self): - """test whether PATH corresponds to a CGI script. + """Test whether self.path corresponds to a CGI script. - Return a tuple (dir, rest) if PATH requires running a + Return a tuple (dir, rest) if self.path requires running a CGI script, None if not. Note that rest begins with a slash if it is not empty. @@ -83,6 +90,15 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): cgi_directories = ['/cgi-bin', '/htbin'] + def is_executable(self, path): + """Test whether argument path is an executable file.""" + return executable(path) + + def is_python(self, path): + """Test whether argument path is a Python script.""" + head, tail = os.path.splitext(path) + return tail.lower() in (".py", ".pyw") + def run_cgi(self): """Execute a CGI script.""" dir, rest = self.cgi_info @@ -105,79 +121,152 @@ class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): self.send_error(403, "CGI script is not a plain file (%s)" % `scriptname`) return - if not executable(scriptfile): - self.send_error(403, "CGI script is not executable (%s)" % - `scriptname`) - return - nobody = nobody_uid() + ispy = self.is_python(scriptname) + if not ispy: + if not (self.have_fork or self.have_popen2): + self.send_error(403, "CGI script is not a Python script (%s)" % + `scriptname`) + return + if not self.is_executable(scriptfile): + self.send_error(403, "CGI script is not executable (%s)" % + `scriptname`) + return + + # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html + # XXX Much of the following could be prepared ahead of time! + env = {} + env['SERVER_SOFTWARE'] = self.version_string() + env['SERVER_NAME'] = self.server.server_name + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + env['SERVER_PROTOCOL'] = self.protocol_version + env['SERVER_PORT'] = str(self.server.server_port) + env['REQUEST_METHOD'] = self.command + uqrest = urllib.unquote(rest) + env['PATH_INFO'] = uqrest + env['PATH_TRANSLATED'] = self.translate_path(uqrest) + env['SCRIPT_NAME'] = scriptname + if query: + env['QUERY_STRING'] = query + host = self.address_string() + if host != self.client_address[0]: + env['REMOTE_HOST'] = host + env['REMOTE_ADDR'] = self.client_address[0] + # XXX AUTH_TYPE + # XXX REMOTE_USER + # XXX REMOTE_IDENT + if self.headers.typeheader is None: + env['CONTENT_TYPE'] = self.headers.type + else: + env['CONTENT_TYPE'] = self.headers.typeheader + length = self.headers.getheader('content-length') + if length: + env['CONTENT_LENGTH'] = length + accept = [] + for line in self.headers.getallmatchingheaders('accept'): + if line[:1] in string.whitespace: + accept.append(string.strip(line)) + else: + accept = accept + string.split(line[7:], ',') + env['HTTP_ACCEPT'] = string.joinfields(accept, ',') + ua = self.headers.getheader('user-agent') + if ua: + env['HTTP_USER_AGENT'] = ua + co = filter(None, self.headers.getheaders('cookie')) + if co: + env['HTTP_COOKIE'] = string.join(co, ', ') + # XXX Other HTTP_* headers + if not self.have_fork: + # Since we're setting the env in the parent, provide empty + # values to override previously set values + for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', + 'HTTP_USER_AGENT', 'HTTP_COOKIE'): + env.setdefault(k, "") + self.send_response(200, "Script output follows") - self.wfile.flush() # Always flush before forking - pid = os.fork() - if pid != 0: - # Parent - pid, sts = os.waitpid(pid, 0) + + decoded_query = string.replace(query, '+', ' ') + + if self.have_fork: + # Unix -- fork as we should + args = [script] + if '=' not in decoded_query: + args.append(decoded_query) + nobody = nobody_uid() + self.wfile.flush() # Always flush before forking + pid = os.fork() + if pid != 0: + # Parent + pid, sts = os.waitpid(pid, 0) + if sts: + self.log_error("CGI script exit status %#x", sts) + return + # Child + try: + try: + os.setuid(nobody) + except os.error: + pass + os.dup2(self.rfile.fileno(), 0) + os.dup2(self.wfile.fileno(), 1) + os.execve(scriptfile, args, env) + except: + self.server.handle_error(self.request, self.client_address) + os._exit(127) + + elif self.have_popen2: + # Windows -- use popen2 to create a subprocess + import shutil + os.environ.update(env) + cmdline = scriptfile + if self.is_python(scriptfile): + interp = sys.executable + if interp.lower().endswith("w.exe"): + # On Windows, use python.exe, not python.exe + interp = interp[:-5] = interp[-4:] + cmdline = "%s %s" % (interp, cmdline) + if '=' not in query and '"' not in query: + cmdline = '%s "%s"' % (cmdline, query) + self.log_error("command: %s", cmdline) + try: + nbytes = int(length) + except: + nbytes = 0 + fi, fo = os.popen2(cmdline) + if self.command.lower() == "post" and nbytes > 0: + data = self.rfile.read(nbytes) + fi.write(data) + fi.close() + shutil.copyfileobj(fo, self.wfile) + sts = fo.close() if sts: - self.log_error("CGI script exit status x%x" % sts) - return - # Child - try: - # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html - # XXX Much of the following could be prepared ahead of time! - env = {} - env['SERVER_SOFTWARE'] = self.version_string() - env['SERVER_NAME'] = self.server.server_name - env['GATEWAY_INTERFACE'] = 'CGI/1.1' - env['SERVER_PROTOCOL'] = self.protocol_version - env['SERVER_PORT'] = str(self.server.server_port) - env['REQUEST_METHOD'] = self.command - uqrest = urllib.unquote(rest) - env['PATH_INFO'] = uqrest - env['PATH_TRANSLATED'] = self.translate_path(uqrest) - env['SCRIPT_NAME'] = scriptname - if query: - env['QUERY_STRING'] = query - host = self.address_string() - if host != self.client_address[0]: - env['REMOTE_HOST'] = host - env['REMOTE_ADDR'] = self.client_address[0] - # AUTH_TYPE - # REMOTE_USER - # REMOTE_IDENT - if self.headers.typeheader is None: - env['CONTENT_TYPE'] = self.headers.type + self.log_error("CGI script exit status %#x", sts) else: - env['CONTENT_TYPE'] = self.headers.typeheader - length = self.headers.getheader('content-length') - if length: - env['CONTENT_LENGTH'] = length - accept = [] - for line in self.headers.getallmatchingheaders('accept'): - if line[:1] in string.whitespace: - accept.append(string.strip(line)) - else: - accept = accept + string.split(line[7:], ',') - env['HTTP_ACCEPT'] = string.joinfields(accept, ',') - ua = self.headers.getheader('user-agent') - if ua: - env['HTTP_USER_AGENT'] = ua - co = filter(None, self.headers.getheaders('cookie')) - if co: - env['HTTP_COOKIE'] = string.join(co, ', ') - # XXX Other HTTP_* headers - decoded_query = string.replace(query, '+', ' ') + self.log_error("CGI script exited OK") + + else: + # Other O.S. -- execute script in this process + os.environ.update(env) + save_argv = sys.argv + save_stdin = sys.stdin + save_stdout = sys.stdout + save_stderr = sys.stderr try: - os.setuid(nobody) - except os.error: - pass - os.dup2(self.rfile.fileno(), 0) - os.dup2(self.wfile.fileno(), 1) - print scriptfile, script, decoded_query - os.execve(scriptfile, - [script, decoded_query], - env) - except: - self.server.handle_error(self.request, self.client_address) - os._exit(127) + try: + sys.argv = [scriptfile] + if '=' not in decoded_query: + sys.argv.append(decoded_query) + sys.stdout = self.wfile + sys.stdin = self.rfile + execfile(scriptfile, {"__name__": "__main__"}) + finally: + sys.argv = save_argv + sys.stdin = save_stdin + sys.stdout = save_stdout + sys.stderr = save_stderr + except SystemExit, sts: + self.log_error("CGI script exit status %s", str(sts)) + else: + self.log_error("CGI script exited OK") nobody = None @@ -187,7 +276,10 @@ def nobody_uid(): global nobody if nobody: return nobody - import pwd + try: + import pwd + except ImportError: + return -1 try: nobody = pwd.getpwnam('nobody')[2] except KeyError: diff --git a/Lib/dos-8x3/configpa.py b/Lib/dos-8x3/configpa.py index e7636b9..16d18d2 100644 --- a/Lib/dos-8x3/configpa.py +++ b/Lib/dos-8x3/configpa.py @@ -440,7 +440,7 @@ class ConfigParser: # allow empty values if optval == '""': optval = '' - cursect[optname] = optval + cursect[self.optionxform(optname)] = optval else: # a non-fatal parsing error occurred. set up the # exception but keep going. the exception will be diff --git a/Lib/dos-8x3/posixfil.py b/Lib/dos-8x3/posixfil.py index d358dc4..23f2c85 100755 --- a/Lib/dos-8x3/posixfil.py +++ b/Lib/dos-8x3/posixfil.py @@ -67,9 +67,6 @@ class _posixfile_: (self.states[file.closed], file.name, file.mode, \ hex(id(self))[2:]) - def __del__(self): - self._file_.close() - # # Initialization routines # diff --git a/Lib/dos-8x3/py_compi.py b/Lib/dos-8x3/py_compi.py index c54d61b..b453109 100755 --- a/Lib/dos-8x3/py_compi.py +++ b/Lib/dos-8x3/py_compi.py @@ -48,6 +48,11 @@ def compile(file, cfile=None, dfile=None): except AttributeError: timestamp = long(os.stat(file)[8]) codestring = f.read() + # If parsing from a string, line breaks are \n (see parsetok.c:tok_nextc) + # Replace will return original string if pattern is not found, so + # we don't need to check whether it is found first. + codestring = codestring.replace("\r\n","\n") + codestring = codestring.replace("\r","\n") f.close() if codestring and codestring[-1] != '\n': codestring = codestring + '\n' diff --git a/Lib/dos-8x3/sre_pars.py b/Lib/dos-8x3/sre_pars.py index 55de24c..f4741c9 100644 --- a/Lib/dos-8x3/sre_pars.py +++ b/Lib/dos-8x3/sre_pars.py @@ -634,7 +634,7 @@ def parse_template(source, pattern): while 1: group = _group(this, pattern.groups+1) if group: - if (not s.next or + if (s.next not in DIGITS or not _group(this + s.next, pattern.groups+1)): code = MARK, int(group) break diff --git a/Lib/dos-8x3/stringio.py b/Lib/dos-8x3/stringio.py index 8efd7d8..02eb7c8 100755 --- a/Lib/dos-8x3/stringio.py +++ b/Lib/dos-8x3/stringio.py @@ -91,11 +91,15 @@ class StringIO: r = self.buf[self.pos:newpos] self.pos = newpos return r - def readlines(self): + def readlines(self, sizehint = 0): + total = 0 lines = [] line = self.readline() while line: lines.append(line) + total += len(line) + if 0 < sizehint <= total: + break line = self.readline() return lines def write(self, s): diff --git a/Lib/dos-8x3/test_arr.py b/Lib/dos-8x3/test_arr.py index d3fe7e9..fb451a9 100644 --- a/Lib/dos-8x3/test_arr.py +++ b/Lib/dos-8x3/test_arr.py @@ -122,9 +122,14 @@ def testtype(type, example): a.pop() a.pop() a.pop() - a.pop() + x = a.pop() + if x != 'e': + raise TestFailed, "array(%s) pop-test" % `type` if a != array.array(type, "acd"): raise TestFailed, "array(%s) pop-test" % `type` + a.reverse() + if a != array.array(type, "dca"): + raise TestFailed, "array(%s) reverse-test" % `type` else: a = array.array(type, [1, 2, 3, 4, 5]) a[:-1] = a @@ -155,9 +160,14 @@ def testtype(type, example): a.pop() a.pop() a.pop() - a.pop() + x = a.pop() + if x != 5: + raise TestFailed, "array(%s) pop-test" % `type` if a != array.array(type, [1, 3, 4]): raise TestFailed, "array(%s) pop-test" % `type` + a.reverse() + if a != array.array(type, [4, 3, 1]): + raise TestFailed, "array(%s) reverse-test" % `type` # test that overflow exceptions are raised as expected for assignment # to array of specific integral types diff --git a/Lib/dos-8x3/test_cpi.py b/Lib/dos-8x3/test_cpi.py index f5e920f..f2aa0fe 100644 --- a/Lib/dos-8x3/test_cpi.py +++ b/Lib/dos-8x3/test_cpi.py @@ -1,107 +1,5 @@ # Test the cPickle module -DATA = """(lp0 -I0 -aL1L -aF2.0 -ac__builtin__ -complex -p1 -(F3.0 -F0.0 -tp2 -Rp3 -a(S'abc' -p4 -g4 -(i__main__ -C -p5 -(dp6 -S'foo' -p7 -I1 -sS'bar' -p8 -I2 -sbg5 -tp9 -ag9 -aI5 -a. -""" - -BINDATA = ']q\000(K\000L1L\012G@\000\000\000\000\000\000\000c__builtin__\012complex\012q\001(G@\010\000\000\000\000\000\000G\000\000\000\000\000\000\000\000tq\002Rq\003(U\003abcq\004h\004(c__main__\012C\012q\005oq\006}q\007(U\003fooq\010K\001U\003barq\011K\002ubh\006tq\012h\012K\005e.' - import cPickle - -class C: - def __cmp__(self, other): - return cmp(self.__dict__, other.__dict__) - -import __main__ -__main__.C = C - -def dotest(): - c = C() - c.foo = 1 - c.bar = 2 - x = [0, 1L, 2.0, 3.0+0j] - y = ('abc', 'abc', c, c) - x.append(y) - x.append(y) - x.append(5) - print "dumps()" - s = cPickle.dumps(x) - print "loads()" - x2 = cPickle.loads(s) - if x2 == x: print "ok" - else: print "bad" - print "loads() DATA" - x2 = cPickle.loads(DATA) - if x2 == x: print "ok" - else: print "bad" - print "dumps() binary" - s = cPickle.dumps(x, 1) - print "loads() binary" - x2 = cPickle.loads(s) - if x2 == x: print "ok" - else: print "bad" - print "loads() BINDATA" - x2 = cPickle.loads(BINDATA) - if x2 == x: print "ok" - else: print "bad" - - # Test protection against closed files - import tempfile, os - fn = tempfile.mktemp() - f = open(fn, "w") - f.close() - try: - cPickle.dump(123, f) - except ValueError: - pass - else: - print "dump to closed file should raise ValueError" - f = open(fn, "r") - f.close() - try: - cPickle.load(f) - except ValueError: - pass - else: - print "load from closed file should raise ValueError" - os.remove(fn) - - # Test specific bad cases - for i in range(10): - try: - x = cPickle.loads('garyp') - except cPickle.BadPickleGet, y: - del y - else: - print "unexpected success!" - break - - -dotest() +import test_pickle +test_pickle.dotest(cPickle) diff --git a/Lib/dos-8x3/test_exc.py b/Lib/dos-8x3/test_exc.py index 7ee203c..076f470 100755 --- a/Lib/dos-8x3/test_exc.py +++ b/Lib/dos-8x3/test_exc.py @@ -86,6 +86,55 @@ r(SyntaxError) try: exec '/\n' except SyntaxError: pass +# make sure the right exception message is raised for each of these +# code fragments: + +def ckmsg(src, msg): + try: + compile(src, '', 'exec') + except SyntaxError, e: + print e.msg + if e.msg == msg: + print "ok" + else: + print "expected:", msg + else: + print "failed to get expected SyntaxError" + +s = '''\ +while 1: + try: + continue + except: + pass +''' +ckmsg(s, "'continue' not supported inside 'try' clause") +s = '''\ +while 1: + try: + continue + finally: + pass +''' +ckmsg(s, "'continue' not supported inside 'try' clause") +s = '''\ +while 1: + try: + if 1: + continue + finally: + pass +''' +ckmsg(s, "'continue' not supported inside 'try' clause") +s = '''\ +try: + continue +except: + pass +''' +ckmsg(s, "'continue' not properly in loop") +ckmsg("continue\n", "'continue' not properly in loop") + r(IndentationError) r(TabError) diff --git a/Lib/dos-8x3/test_fcn.py b/Lib/dos-8x3/test_fcn.py index 3c1be88..e1ed88b 100644 --- a/Lib/dos-8x3/test_fcn.py +++ b/Lib/dos-8x3/test_fcn.py @@ -21,7 +21,7 @@ if sys.platform in ('netbsd1', 'bsdos2', 'bsdos3', 'bsdos4', 'openbsd', 'openbsd2'): lockdata = struct.pack('lxxxxlxxxxlhh', 0, 0, 0, FCNTL.F_WRLCK, 0) -elif sys.platform in ['aix3', 'aix4']: +elif sys.platform in ['aix3', 'aix4', 'hp-uxB']: lockdata = struct.pack('hhlllii', FCNTL.F_WRLCK, 0, 0, 0, 0, 0, 0) else: lockdata = struct.pack('hhllhh', FCNTL.F_WRLCK, 0, 0, 0, 0, 0) diff --git a/Lib/dos-8x3/test_gra.py b/Lib/dos-8x3/test_gra.py index ef7c09b..68cae81 100755 --- a/Lib/dos-8x3/test_gra.py +++ b/Lib/dos-8x3/test_gra.py @@ -355,6 +355,13 @@ def f(): del z exec 'z=1+1' if z <> 2: raise TestFailed, 'exec \'z=1+1\'' + z = None + del z + exec u'z=1+1\n' + if z <> 2: raise TestFailed, 'exec u\'z=1+1\'\\n' + del z + exec u'z=1+1' + if z <> 2: raise TestFailed, 'exec u\'z=1+1\'' f() g = {} exec 'z = 1' in g diff --git a/Lib/dos-8x3/test_min.py b/Lib/dos-8x3/test_min.py index 73c8ac4..8a63535 100644 --- a/Lib/dos-8x3/test_min.py +++ b/Lib/dos-8x3/test_min.py @@ -5,6 +5,7 @@ from xml.dom.minidom import parse, Node, Document, parseString import os.path import sys import traceback +from test_support import verbose if __name__ == "__main__": base = sys.argv[0] @@ -13,15 +14,28 @@ else: tstfile = os.path.join(os.path.dirname(base), "test.xml") del base +def confirm( test, testname="Test" ): + if test: + print "Passed " + testname + else: + print "Failed " + testname + raise Exception + Node._debug=1 +def testParseFromFile(): + from StringIO import StringIO + dom=parse( StringIO( open( tstfile ).read() ) ) + dom.unlink() + confirm(isinstance(dom,Document)) + def testGetElementsByTagName( ): dom=parse( tstfile ) - assert dom.getElementsByTagName( "LI" )==\ - dom.documentElement.getElementsByTagName( "LI" ) + confirm( dom.getElementsByTagName( "LI" )==\ + dom.documentElement.getElementsByTagName( "LI" ) ) dom.unlink() dom=None - assert( len( Node.allnodes ))==0 + confirm (len( Node.allnodes )==0) def testInsertBefore( ): dom=parse( tstfile ) @@ -32,44 +46,44 @@ def testInsertBefore( ): #docel.insertBefore( dom.createProcessingInstruction("a", "b"), # docel.childNodes[0]) - #assert docel.childNodes[0].target=="a" - #assert docel.childNodes[2].target=="a" + #confirm( docel.childNodes[0].tet=="a" ) + #confirm( docel.childNodes[2].tet=="a" ) dom.unlink() del dom del docel - assert( len( Node.allnodes ))==0 + confirm( len( Node.allnodes )==0) def testAppendChild(): dom=parse( tstfile ) dom.documentElement.appendChild( dom.createComment( u"Hello" )) - assert dom.documentElement.childNodes[-1].nodeName=="#comment" - assert dom.documentElement.childNodes[-1].data=="Hello" + confirm( dom.documentElement.childNodes[-1].nodeName=="#comment" ) + confirm( dom.documentElement.childNodes[-1].data=="Hello" ) dom.unlink() dom=None - assert( len( Node.allnodes ))==0 + confirm( len( Node.allnodes )==0 ) def testNonZero(): dom=parse( tstfile ) - assert dom # should not be zero + confirm( dom )# should not be zero dom.appendChild( dom.createComment( "foo" ) ) - assert not dom.childNodes[-1].childNodes + confirm( not dom.childNodes[-1].childNodes ) dom.unlink() dom=None - assert( len( Node.allnodes ))==0 + confirm( len( Node.allnodes )==0 ) def testUnlink(): dom=parse( tstfile ) dom.unlink() dom=None - assert( len( Node.allnodes ))==0 + confirm( len( Node.allnodes )==0 ) def testElement(): dom=Document() dom.appendChild( dom.createElement( "abc" ) ) - assert dom.documentElement + confirm( dom.documentElement ) dom.unlink() dom=None - assert( len( Node.allnodes ))==0 + confirm( len( Node.allnodes )==0 ) def testAAA(): dom=parseString( "" ) @@ -91,20 +105,20 @@ def testAddAttr(): child=dom.appendChild( dom.createElement( "abc" ) ) child.setAttribute( "def", "ghi" ) - assert child.getAttribute( "def" )=="ghi" - assert child.attributes["def"].value=="ghi" + confirm( child.getAttribute( "def" )=="ghi" ) + confirm( child.attributes["def"].value=="ghi" ) child.setAttribute( "jkl", "mno" ) - assert child.getAttribute( "jkl" )=="mno" - assert child.attributes["jkl"].value=="mno" + confirm( child.getAttribute( "jkl" )=="mno" ) + confirm( child.attributes["jkl"].value=="mno" ) - assert len( child.attributes )==2 + confirm( len( child.attributes )==2 ) child.setAttribute( "def", "newval" ) - assert child.getAttribute( "def" )=="newval" - assert child.attributes["def"].value=="newval" + confirm( child.getAttribute( "def" )=="newval" ) + confirm( child.attributes["def"].value=="newval" ) - assert len( child.attributes )==2 + confirm( len( child.attributes )==2 ) dom.unlink() dom=None @@ -114,22 +128,22 @@ def testDeleteAttr(): dom=Document() child=dom.appendChild( dom.createElement( "abc" ) ) - assert len( child.attributes)==0 + confirm( len( child.attributes)==0 ) child.setAttribute( "def", "ghi" ) - assert len( child.attributes)==1 + confirm( len( child.attributes)==1 ) del child.attributes["def"] - assert len( child.attributes)==0 + confirm( len( child.attributes)==0 ) dom.unlink() - assert( len( Node.allnodes ))==0 + confirm( len( Node.allnodes )==0 ) def testRemoveAttr(): dom=Document() child=dom.appendChild( dom.createElement( "abc" ) ) child.setAttribute( "def", "ghi" ) - assert len( child.attributes)==1 + confirm( len( child.attributes)==1 ) child.removeAttribute("def" ) - assert len( child.attributes)==0 + confirm( len( child.attributes)==0 ) dom.unlink() @@ -140,9 +154,9 @@ def testRemoveAttrNS(): child.setAttributeNS( "http://www.w3.org", "xmlns:python", "http://www.python.org" ) child.setAttributeNS( "http://www.python.org", "python:abcattr", "foo" ) - assert len( child.attributes )==2 + confirm( len( child.attributes )==2 ) child.removeAttributeNS( "http://www.python.org", "abcattr" ) - assert len( child.attributes )==1 + confirm( len( child.attributes )==1 ) dom.unlink() dom=None @@ -151,31 +165,31 @@ def testRemoveAttributeNode(): dom=Document() child=dom.appendChild( dom.createElement( "foo" ) ) child.setAttribute( "spam", "jam" ) - assert len( child.attributes )==1 + confirm( len( child.attributes )==1 ) node=child.getAttributeNode( "spam" ) child.removeAttributeNode( node ) - assert len( child.attributes )==0 + confirm( len( child.attributes )==0 ) dom.unlink() dom=None - assert len( Node.allnodes )==0 + confirm( len( Node.allnodes )==0 ) def testChangeAttr(): dom=parseString( "" ) el=dom.documentElement el.setAttribute( "spam", "jam" ) - assert len( el.attributes )==1 + confirm( len( el.attributes )==1 ) el.setAttribute( "spam", "bam" ) - assert len( el.attributes )==1 + confirm( len( el.attributes )==1 ) el.attributes["spam"]="ham" - assert len( el.attributes )==1 + confirm( len( el.attributes )==1 ) el.setAttribute( "spam2", "bam" ) - assert len( el.attributes )==2 + confirm( len( el.attributes )==2 ) el.attributes[ "spam2"]= "bam2" - assert len( el.attributes )==2 + confirm( len( el.attributes )==2 ) dom.unlink() dom=None - assert len( Node.allnodes )==0 + confirm( len( Node.allnodes )==0 ) def testGetAttrList(): pass @@ -199,7 +213,7 @@ def testElementReprAndStr(): el=dom.appendChild( dom.createElement( "abc" ) ) string1=repr( el ) string2=str( el ) - assert string1==string2 + confirm( string1==string2 ) dom.unlink() # commented out until Fredrick's fix is checked in @@ -208,25 +222,25 @@ def _testElementReprAndStrUnicode(): el=dom.appendChild( dom.createElement( u"abc" ) ) string1=repr( el ) string2=str( el ) - assert string1==string2 + confirm( string1==string2 ) dom.unlink() # commented out until Fredrick's fix is checked in def _testElementReprAndStrUnicodeNS(): dom=Document() el=dom.appendChild( - dom.createElementNS( u"http://www.slashdot.org", u"slash:abc" )) + dom.createElementNS( u"http://www.slashdot.org", u"slash:abc" )) string1=repr( el ) string2=str( el ) - assert string1==string2 - assert string1.find("slash:abc" )!=-1 + confirm( string1==string2 ) + confirm( string1.find("slash:abc" )!=-1 ) dom.unlink() def testAttributeRepr(): dom=Document() el=dom.appendChild( dom.createElement( u"abc" ) ) node=el.setAttribute( "abc", "def" ) - assert str( node ) == repr( node ) + confirm( str( node ) == repr( node ) ) dom.unlink() def testTextNodeRepr(): pass @@ -312,6 +326,9 @@ def testClonePIDeep(): pass names=globals().keys() names.sort() + +works=1 + for name in names: if name.startswith( "test" ): func=globals()[name] @@ -320,12 +337,24 @@ for name in names: print "Test Succeeded", name if len( Node.allnodes ): print "Garbage left over:" - print Node.allnodes.items()[0:10] + if verbose: + print Node.allnodes.items()[0:10] + else: + # Don't print specific nodes if repeatable results + # are needed + print len(Node.allnodes) Node.allnodes={} except Exception, e : + works=0 print "Test Failed: ", name apply( traceback.print_exception, sys.exc_info() ) print `e` Node.allnodes={} - raise +if works: + print "All tests succeeded" +else: + print "\n\n\n\n************ Check for failures!" + +Node.debug = None # Delete debug output collected in a StringIO object +Node._debug = 0 # And reset debug mode diff --git a/Lib/dos-8x3/test_pic.py b/Lib/dos-8x3/test_pic.py index 8fb534d..3c81fdd 100644 --- a/Lib/dos-8x3/test_pic.py +++ b/Lib/dos-8x3/test_pic.py @@ -1,5 +1,6 @@ # Test the pickle module +# break into multiple strings to please font-lock-mode DATA = """(lp0 I0 aL1L @@ -7,17 +8,20 @@ aF2.0 ac__builtin__ complex p1 -(F3.0 +""" \ +"""(F3.0 F0.0 tp2 Rp3 a(S'abc' p4 g4 -(i__main__ +""" \ +"""(i__main__ C p5 -(dp6 +""" \ +"""(dp6 S'foo' p7 I1 @@ -33,8 +37,6 @@ a. BINDATA = ']q\000(K\000L1L\012G@\000\000\000\000\000\000\000c__builtin__\012complex\012q\001(G@\010\000\000\000\000\000\000G\000\000\000\000\000\000\000\000tq\002Rq\003(U\003abcq\004h\004(c__main__\012C\012q\005oq\006}q\007(U\003fooq\010K\001U\003barq\011K\002ubh\006tq\012h\012K\005e.' -import pickle - class C: def __cmp__(self, other): return cmp(self.__dict__, other.__dict__) @@ -42,7 +44,7 @@ class C: import __main__ __main__.C = C -def dotest(): +def dotest(pickle): c = C() c.foo = 1 c.bar = 2 @@ -51,6 +53,8 @@ def dotest(): x.append(y) x.append(y) x.append(5) + r = [] + r.append(r) print "dumps()" s = pickle.dumps(x) print "loads()" @@ -71,5 +75,69 @@ def dotest(): x2 = pickle.loads(BINDATA) if x2 == x: print "ok" else: print "bad" + s = pickle.dumps(r) + print "dumps() RECURSIVE" + x2 = pickle.loads(s) + if x2 == r: print "ok" + else: print "bad" + # don't create cyclic garbage + del x2[0] + del r[0] -dotest() + # Test protection against closed files + import tempfile, os + fn = tempfile.mktemp() + f = open(fn, "w") + f.close() + try: + pickle.dump(123, f) + except ValueError: + pass + else: + print "dump to closed file should raise ValueError" + f = open(fn, "r") + f.close() + try: + pickle.load(f) + except ValueError: + pass + else: + print "load from closed file should raise ValueError" + os.remove(fn) + + # Test specific bad cases + for i in range(10): + try: + x = pickle.loads('garyp') + except KeyError, y: + # pickle + del y + except pickle.BadPickleGet, y: + # cPickle + del y + else: + print "unexpected success!" + break + + # Test insecure strings + insecure = ["abc", "2 + 2", # not quoted + "'abc' + 'def'", # not a single quoted string + "'abc", # quote is not closed + "'abc\"", # open quote and close quote don't match + "'abc' ?", # junk after close quote + # some tests of the quoting rules + "'abc\"\''", + "'\\\\a\'\'\'\\\'\\\\\''", + ] + for s in insecure: + buf = "S" + s + "\012p0\012." + try: + x = pickle.loads(buf) + except ValueError: + pass + else: + print "accepted insecure string: %s" % repr(buf) + + +import pickle +dotest(pickle) diff --git a/Lib/dos-8x3/test_pye.py b/Lib/dos-8x3/test_pye.py index d6bd84b..a119987 100644 --- a/Lib/dos-8x3/test_pye.py +++ b/Lib/dos-8x3/test_pye.py @@ -3,10 +3,7 @@ # XXX TypeErrors on calling handlers, or on bad return values from a # handler, are obscure and unhelpful. -import sys, string -import os - -import pyexpat +from xml.parsers import expat class Outputter: def StartElementHandler(self, name, attrs): @@ -16,7 +13,7 @@ class Outputter: print 'End element:\n\t', repr(name) def CharacterDataHandler(self, data): - data = string.strip(data) + data = data.strip() if data: print 'Character data:' print '\t', repr(data) @@ -63,29 +60,37 @@ class Outputter: pass +def confirm(ok): + if ok: + print "OK." + else: + print "Not OK." + out = Outputter() -parser = pyexpat.ParserCreate(namespace_separator='!') +parser = expat.ParserCreate(namespace_separator='!') # Test getting/setting returns_unicode -parser.returns_unicode = 0 ; assert parser.returns_unicode == 0 -parser.returns_unicode = 1 ; assert parser.returns_unicode == 1 -parser.returns_unicode = 2 ; assert parser.returns_unicode == 1 -parser.returns_unicode = 0 ; assert parser.returns_unicode == 0 - -HANDLER_NAMES = ['StartElementHandler', 'EndElementHandler', - 'CharacterDataHandler', 'ProcessingInstructionHandler', - 'UnparsedEntityDeclHandler', 'NotationDeclHandler', - 'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler', - 'CommentHandler', 'StartCdataSectionHandler', - 'EndCdataSectionHandler', - 'DefaultHandler', 'DefaultHandlerExpand', - #'NotStandaloneHandler', - 'ExternalEntityRefHandler' - ] +parser.returns_unicode = 0; confirm(parser.returns_unicode == 0) +parser.returns_unicode = 1; confirm(parser.returns_unicode == 1) +parser.returns_unicode = 2; confirm(parser.returns_unicode == 1) +parser.returns_unicode = 0; confirm(parser.returns_unicode == 0) + +HANDLER_NAMES = [ + 'StartElementHandler', 'EndElementHandler', + 'CharacterDataHandler', 'ProcessingInstructionHandler', + 'UnparsedEntityDeclHandler', 'NotationDeclHandler', + 'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler', + 'CommentHandler', 'StartCdataSectionHandler', + 'EndCdataSectionHandler', + 'DefaultHandler', 'DefaultHandlerExpand', + #'NotStandaloneHandler', + 'ExternalEntityRefHandler' + ] for name in HANDLER_NAMES: - setattr(parser, name, getattr(out, name) ) + setattr(parser, name, getattr(out, name)) -data = """ +data = '''\ + &external_entity; -""" +''' # Produce UTF-8 output parser.returns_unicode = 0 try: parser.Parse(data, 1) -except pyexpat.error: - print '** Error', parser.ErrorCode, pyexpat.ErrorString( parser.ErrorCode) +except expat.error: + print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode) print '** Line', parser.ErrorLineNumber print '** Column', parser.ErrorColumnNumber print '** Byte', parser.ErrorByteIndex # Try the parse again, this time producing Unicode output -parser = pyexpat.ParserCreate(namespace_separator='!') +parser = expat.ParserCreate(namespace_separator='!') parser.returns_unicode = 1 for name in HANDLER_NAMES: - setattr(parser, name, getattr(out, name) ) + setattr(parser, name, getattr(out, name)) try: parser.Parse(data, 1) -except pyexpat.error: - print '** Error', parser.ErrorCode, pyexpat.ErrorString( parser.ErrorCode) +except expat.error: + print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode) print '** Line', parser.ErrorLineNumber print '** Column', parser.ErrorColumnNumber print '** Byte', parser.ErrorByteIndex # Try parsing a file -parser = pyexpat.ParserCreate(namespace_separator='!') +parser = expat.ParserCreate(namespace_separator='!') parser.returns_unicode = 1 for name in HANDLER_NAMES: - setattr(parser, name, getattr(out, name) ) + setattr(parser, name, getattr(out, name)) import StringIO file = StringIO.StringIO(data) try: parser.ParseFile(file) -except pyexpat.error: - print '** Error', parser.ErrorCode, pyexpat.ErrorString( parser.ErrorCode) +except expat.error: + print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode) print '** Line', parser.ErrorLineNumber print '** Column', parser.ErrorColumnNumber print '** Byte', parser.ErrorByteIndex - diff --git a/Lib/dos-8x3/test_rfc.py b/Lib/dos-8x3/test_rfc.py index 0d4c66f..36e7a51 100644 --- a/Lib/dos-8x3/test_rfc.py +++ b/Lib/dos-8x3/test_rfc.py @@ -120,3 +120,7 @@ Date: Wed, 13 Jan 1999 23:57:35 -0500 test''', [('', 'goit@lip.com')]) + +test('''To: guido@[132.151.1.21] + +foo''', [('', 'guido@[132.151.1.21]')]) diff --git a/Lib/dos-8x3/test_str.py b/Lib/dos-8x3/test_str.py index c713d05..6e321e9 100644 --- a/Lib/dos-8x3/test_str.py +++ b/Lib/dos-8x3/test_str.py @@ -1,134 +1,15 @@ -#! /usr/bin/env python +# Tests StringIO and cStringIO -# Sanity checker for time.strftime +import string -import time, calendar, sys, string, os, re -from test_support import verbose +def do_test(module): + s = (string.letters+'\n')*5 + f = module.StringIO(s) + print f.read(10) + print f.readline() + print len(f.readlines(60)) -def main(): - global verbose - now = time.time() - strftest(now) - verbose = 0 - # Try a bunch of dates and times, chosen to vary through time of - # day and daylight saving time - for j in range(-5, 5): - for i in range(25): - strftest(now + (i + j*100)*23*3603) - -def strftest(now): - if verbose: - print "strftime test for", time.ctime(now) - nowsecs = str(long(now))[:-1] - gmt = time.gmtime(now) - now = time.localtime(now) - - if now[3] < 12: ampm='AM' - else: ampm='PM' - - jan1 = time.localtime(time.mktime((now[0], 1, 1) + (0,)*6)) - - try: - if now[8]: tz = time.tzname[1] - else: tz = time.tzname[0] - except AttributeError: - tz = '' - - if now[3] > 12: clock12 = now[3] - 12 - elif now[3] > 0: clock12 = now[3] - else: clock12 = 12 - - expectations = ( - ('%a', calendar.day_abbr[now[6]], 'abbreviated weekday name'), - ('%A', calendar.day_name[now[6]], 'full weekday name'), - ('%b', calendar.month_abbr[now[1]], 'abbreviated month name'), - ('%B', calendar.month_name[now[1]], 'full month name'), - # %c see below - ('%d', '%02d' % now[2], 'day of month as number (00-31)'), - ('%H', '%02d' % now[3], 'hour (00-23)'), - ('%I', '%02d' % clock12, 'hour (01-12)'), - ('%j', '%03d' % now[7], 'julian day (001-366)'), - ('%m', '%02d' % now[1], 'month as number (01-12)'), - ('%M', '%02d' % now[4], 'minute, (00-59)'), - ('%p', ampm, 'AM or PM as appropriate'), - ('%S', '%02d' % now[5], 'seconds of current time (00-60)'), - ('%U', '%02d' % ((now[7] + jan1[6])/7), - 'week number of the year (Sun 1st)'), - ('%w', '0?%d' % ((1+now[6]) % 7), 'weekday as a number (Sun 1st)'), - ('%W', '%02d' % ((now[7] + (jan1[6] - 1)%7)/7), - 'week number of the year (Mon 1st)'), - # %x see below - ('%X', '%02d:%02d:%02d' % (now[3], now[4], now[5]), '%H:%M:%S'), - ('%y', '%02d' % (now[0]%100), 'year without century'), - ('%Y', '%d' % now[0], 'year with century'), - # %Z see below - ('%%', '%', 'single percent sign'), - ) - - nonstandard_expectations = ( - # These are standard but don't have predictable output - ('%c', fixasctime(time.asctime(now)), 'near-asctime() format'), - ('%x', '%02d/%02d/%02d' % (now[1], now[2], (now[0]%100)), - '%m/%d/%y %H:%M:%S'), - ('%Z', '%s' % tz, 'time zone name'), - - # These are some platform specific extensions - ('%D', '%02d/%02d/%02d' % (now[1], now[2], (now[0]%100)), 'mm/dd/yy'), - ('%e', '%2d' % now[2], 'day of month as number, blank padded ( 0-31)'), - ('%h', calendar.month_abbr[now[1]], 'abbreviated month name'), - ('%k', '%2d' % now[3], 'hour, blank padded ( 0-23)'), - ('%n', '\n', 'newline character'), - ('%r', '%02d:%02d:%02d %s' % (clock12, now[4], now[5], ampm), - '%I:%M:%S %p'), - ('%R', '%02d:%02d' % (now[3], now[4]), '%H:%M'), - ('%s', nowsecs, 'seconds since the Epoch in UCT'), - ('%t', '\t', 'tab character'), - ('%T', '%02d:%02d:%02d' % (now[3], now[4], now[5]), '%H:%M:%S'), - ('%3y', '%03d' % (now[0]%100), - 'year without century rendered using fieldwidth'), - ) - - if verbose: - print "Strftime test, platform: %s, Python version: %s" % \ - (sys.platform, string.split(sys.version)[0]) - - for e in expectations: - try: - result = time.strftime(e[0], now) - except ValueError, error: - print "Standard '%s' format gave error:" % e[0], error - continue - if re.match(e[1], result): continue - if not result or result[0] == '%': - print "Does not support standard '%s' format (%s)" % (e[0], e[2]) - else: - print "Conflict for %s (%s):" % (e[0], e[2]) - print " Expected %s, but got %s" % (e[1], result) - - for e in nonstandard_expectations: - try: - result = time.strftime(e[0], now) - except ValueError, result: - if verbose: - print "Error for nonstandard '%s' format (%s): %s" % \ - (e[0], e[2], str(result)) - continue - if re.match(e[1], result): - if verbose: - print "Supports nonstandard '%s' format (%s)" % (e[0], e[2]) - elif not result or result[0] == '%': - if verbose: - print "Does not appear to support '%s' format (%s)" % (e[0], - e[2]) - else: - if verbose: - print "Conflict for nonstandard '%s' format (%s):" % (e[0], - e[2]) - print " Expected %s, but got %s" % (e[1], result) - -def fixasctime(s): - if s[8] == ' ': - s = s[:8] + '0' + s[9:] - return s - -main() +# Don't bother testing cStringIO without +import StringIO, cStringIO +do_test(StringIO) +do_test(cStringIO) diff --git a/Lib/dos-8x3/test_url.py b/Lib/dos-8x3/test_url.py index e69de29..484acea 100644 --- a/Lib/dos-8x3/test_url.py +++ b/Lib/dos-8x3/test_url.py @@ -0,0 +1,32 @@ +# Minimal test of the quote function +import urllib + +chars = 'abcdefghijklmnopqrstuvwxyz'\ + '\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356' \ + '\357\360\361\362\363\364\365\366\370\371\372\373\374\375\376\377' \ + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' \ + '\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317' \ + '\320\321\322\323\324\325\326\330\331\332\333\334\335\336' + +expected = 'abcdefghijklmnopqrstuvwxyz%df%e0%e1%e2%e3%e4%e5%e6%e7%e8%e9%ea%eb%ec%ed%ee%ef%f0%f1%f2%f3%f4%f5%f6%f8%f9%fa%fb%fc%fd%fe%ffABCDEFGHIJKLMNOPQRSTUVWXYZ%c0%c1%c2%c3%c4%c5%c6%c7%c8%c9%ca%cb%cc%cd%ce%cf%d0%d1%d2%d3%d4%d5%d6%d8%d9%da%db%dc%dd%de' + +test = urllib.quote(chars) +assert test == expected, "urllib.quote problem" +test2 = urllib.unquote(expected) +assert test2 == chars + +in1 = "abc/def" +out1_1 = "abc/def" +out1_2 = "abc%2fdef" + +assert urllib.quote(in1) == out1_1, "urllib.quote problem" +assert urllib.quote(in1, '') == out1_2, "urllib.quote problem" + +in2 = "abc?def" +out2_1 = "abc%3fdef" +out2_2 = "abc?def" + +assert urllib.quote(in2) == out2_1, "urllib.quote problem" +assert urllib.quote(in2, '?') == out2_2, "urllib.quote problem" + + diff --git a/Lib/dos-8x3/test_win.py b/Lib/dos-8x3/test_win.py index 7b4fa15..18ce7a7 100644 --- a/Lib/dos-8x3/test_win.py +++ b/Lib/dos-8x3/test_win.py @@ -1,7 +1,147 @@ -# Ridiculously simple test of the winsound module for Windows. +# Test the windows specific win32reg module. +# Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey -import winsound -for i in range(100, 2000, 100): - winsound.Beep(i, 75) -print "Hopefully you heard some sounds increasing in frequency!" +from _winreg import * +import os, sys + +test_key_name = "SOFTWARE\\Python Registry Test Key - Delete Me" + +test_data = [ + ("Int Value", 45, REG_DWORD), + ("String Val", "A string value", REG_SZ,), + (u"Unicode Val", u"A Unicode value", REG_SZ,), + ("StringExpand", "The path is %path%", REG_EXPAND_SZ), + ("UnicodeExpand", u"The path is %path%", REG_EXPAND_SZ), + ("Multi-string", ["Lots", "of", "string", "values"], REG_MULTI_SZ), + ("Multi-unicode", [u"Lots", u"of", u"unicode", u"values"], REG_MULTI_SZ), + ("Multi-mixed", [u"Unicode", u"and", "string", "values"],REG_MULTI_SZ), + ("Raw Data", ("binary"+chr(0)+"data"), REG_BINARY), +] + +def WriteTestData(root_key): + # Set the default value for this key. + SetValue(root_key, test_key_name, REG_SZ, "Default value") + key = CreateKey(root_key, test_key_name) + # Create a sub-key + sub_key = CreateKey(key, "sub_key") + # Give the sub-key some named values + + for value_name, value_data, value_type in test_data: + SetValueEx(sub_key, value_name, 0, value_type, value_data) + + # Check we wrote as many items as we thought. + nkeys, nvalues, since_mod = QueryInfoKey(key) + assert nkeys==1, "Not the correct number of sub keys" + assert nvalues==1, "Not the correct number of values" + nkeys, nvalues, since_mod = QueryInfoKey(sub_key) + assert nkeys==0, "Not the correct number of sub keys" + assert nvalues==len(test_data), "Not the correct number of values" + # Close this key this way... + # (but before we do, copy the key as an integer - this allows + # us to test that the key really gets closed). + int_sub_key = int(sub_key) + CloseKey(sub_key) + try: + QueryInfoKey(int_sub_key) + raise RuntimeError, "It appears the CloseKey() function does not close the actual key!" + except EnvironmentError: + pass + # ... and close that key that way :-) + int_key = int(key) + key.Close() + try: + QueryInfoKey(int_key) + raise RuntimeError, "It appears the key.Close() function does not close the actual key!" + except EnvironmentError: + pass + +def ReadTestData(root_key): + # Check we can get default value for this key. + val = QueryValue(root_key, test_key_name) + assert val=="Default value", "Registry didn't give back the correct value" + + key = OpenKey(root_key, test_key_name) + # Read the sub-keys + sub_key = OpenKey(key, "sub_key") + # Check I can enumerate over the values. + index = 0 + while 1: + try: + data = EnumValue(sub_key, index) + except EnvironmentError: + break + assert data in test_data, "Didn't read back the correct test data" + index = index + 1 + assert index==len(test_data), "Didn't read the correct number of items" + # Check I can directly access each item + for value_name, value_data, value_type in test_data: + read_val, read_typ = QueryValueEx(sub_key, value_name) + assert read_val==value_data and read_typ == value_type, \ + "Could not directly read the value" + sub_key.Close() + # Enumerate our main key. + read_val = EnumKey(key, 0) + assert read_val == "sub_key", "Read subkey value wrong" + try: + EnumKey(key, 1) + assert 0, "Was able to get a second key when I only have one!" + except EnvironmentError: + pass + + key.Close() + +def DeleteTestData(root_key): + key = OpenKey(root_key, test_key_name, 0, KEY_ALL_ACCESS) + sub_key = OpenKey(key, "sub_key", 0, KEY_ALL_ACCESS) + # It is not necessary to delete the values before deleting + # the key (although subkeys must not exist). We delete them + # manually just to prove we can :-) + for value_name, value_data, value_type in test_data: + DeleteValue(sub_key, value_name) + + nkeys, nvalues, since_mod = QueryInfoKey(sub_key) + assert nkeys==0 and nvalues==0, "subkey not empty before delete" + sub_key.Close() + DeleteKey(key, "sub_key") + + try: + # Shouldnt be able to delete it twice! + DeleteKey(key, "sub_key") + assert 0, "Deleting the key twice succeeded" + except EnvironmentError: + pass + key.Close() + DeleteKey(root_key, test_key_name) + # Opening should now fail! + try: + key = OpenKey(root_key, test_key_name) + assert 0, "Could open the non-existent key" + except WindowsError: # Use this error name this time + pass + +def TestAll(root_key): + WriteTestData(root_key) + ReadTestData(root_key) + DeleteTestData(root_key) + +# Test on my local machine. +TestAll(HKEY_CURRENT_USER) +print "Local registry tests worked" +try: + remote_name = sys.argv[sys.argv.index("--remote")+1] +except (IndexError, ValueError): + remote_name = None + +if remote_name is not None: + try: + remote_key = ConnectRegistry(remote_name, HKEY_CURRENT_USER) + except EnvironmentError, exc: + print "Could not connect to the remote machine -", exc.strerror + remote_key = None + if remote_key is not None: + TestAll(remote_key) + print "Remote registry tests worked" +else: + print "Remote registry calls can be tested using", + print "'test_winreg.py --remote \\\\machine_name'" diff --git a/Lib/dos-8x3/userlist.py b/Lib/dos-8x3/userlist.py index 1146060..aab5119 100755 --- a/Lib/dos-8x3/userlist.py +++ b/Lib/dos-8x3/userlist.py @@ -17,6 +17,7 @@ class UserList: return cmp(self.data, other.data) else: return cmp(self.data, other) + def __contains__(self, item): return item in self.data def __len__(self): return len(self.data) def __getitem__(self, i): return self.data[i] def __setitem__(self, i, item): self.data[i] = item diff --git a/Lib/dos-8x3/webbrows.py b/Lib/dos-8x3/webbrows.py index 66cdbff..a8b0e8b 100644 --- a/Lib/dos-8x3/webbrows.py +++ b/Lib/dos-8x3/webbrows.py @@ -183,7 +183,7 @@ register("grail", Grail) class WindowsDefault: def open(self, url, new=0): - self.junk = os.popen("start " + url) + os.startfile(url) def open_new(self, url): self.open(url) -- cgit v0.12