Changeset 2068
- Timestamp:
- 11/08/08 12:22:41
- Files:
-
- branches/cherrypy-3.1.x/cherrypy/_cpconfig.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/_cpdispatch.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/_cplogging.py (modified) (3 diffs)
- branches/cherrypy-3.1.x/cherrypy/_cprequest.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/_cpserver.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/_cptree.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/_cpwsgi_server.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/cherryd (modified) (4 diffs)
- branches/cherrypy-3.1.x/cherrypy/lib/__init__.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/lib/cptools.py (modified) (3 diffs)
- branches/cherrypy-3.1.x/cherrypy/lib/http.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/lib/httpauth.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/lib/profiler.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/lib/sessions.py (modified) (3 diffs)
- branches/cherrypy-3.1.x/cherrypy/lib/static.py (modified) (4 diffs)
- branches/cherrypy-3.1.x/cherrypy/lib/xmlrpc.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/process/plugins.py (modified) (4 diffs)
- branches/cherrypy-3.1.x/cherrypy/process/servers.py (modified) (3 diffs)
- branches/cherrypy-3.1.x/cherrypy/process/win32.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/process/wspbus.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/test/fcgi.conf (copied) (copied from trunk/cherrypy/test/fcgi.conf)
- branches/cherrypy-3.1.x/cherrypy/test/helper.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/test/modfcgid.py (copied) (copied from trunk/cherrypy/test/modfcgid.py)
- branches/cherrypy-3.1.x/cherrypy/test/modwsgi.py (modified) (5 diffs)
- branches/cherrypy-3.1.x/cherrypy/test/test.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/test/test_core.py (modified) (4 diffs)
- branches/cherrypy-3.1.x/cherrypy/test/test_http.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/test/test_objectmapping.py (modified) (3 diffs)
- branches/cherrypy-3.1.x/cherrypy/test/test_sessionauthenticate.py (modified) (2 diffs)
- branches/cherrypy-3.1.x/cherrypy/test/test_xmlrpc.py (modified) (1 diff)
- branches/cherrypy-3.1.x/cherrypy/wsgiserver/__init__.py (modified) (7 diffs)
- branches/cherrypy-3.1.x/ez_setup.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/cherrypy-3.1.x/cherrypy/_cpconfig.py
r1989 r2068 304 304 engine.autoreload.match = v 305 305 elif k == 'reload_files': 306 engine.autoreload.files = v306 engine.autoreload.files = set(v) 307 307 elif k == 'deadlock_poll_freq': 308 308 engine.timeout_monitor.frequency = v … … 311 311 elif k == 'SIGTERM': 312 312 engine.listeners['SIGTERM'] = set([v]) 313 elif "." in k: 314 plugin, attrname = k.split(".", 1) 315 plugin = getattr(engine, plugin) 316 if attrname == 'on': 317 if v and callable(getattr(plugin, 'subscribe', None)): 318 plugin.subscribe() 319 return 320 elif (not v) and callable(getattr(plugin, 'unsubscribe', None)): 321 plugin.unsubscribe() 322 return 323 setattr(plugin, attrname, v) 324 else: 325 setattr(engine, k, v) 313 326 Config.namespaces["engine"] = _engine_namespace_handler 314 327 branches/cherrypy-3.1.x/cherrypy/_cpdispatch.py
r1893 r2068 22 22 23 23 def __call__(self): 24 return self.callable(*self.args, **self.kwargs) 24 try: 25 return self.callable(*self.args, **self.kwargs) 26 except TypeError, x: 27 test_callable_spec(self.callable, self.args, self.kwargs) 28 raise 29 30 def test_callable_spec(callable, callable_args, callable_kwargs): 31 """ 32 Inspect callable and test to see if the given args are suitable for it. 33 34 When an error occurs during the handler's invoking stage there are 2 35 erroneous cases: 36 1. Too many parameters passed to a function which doesn't define 37 one of *args or **kwargs. 38 2. Too little parameters are passed to the function. 39 40 There are 3 sources of parameters to a cherrypy handler. 41 1. query string parameters are passed as keyword parameters to the handler. 42 2. body parameters are also passed as keyword parameters. 43 3. when partial matching occurs, the final path atoms are passed as 44 positional args. 45 Both the query string and path atoms are part of the URI. If they are 46 incorrect, then a 404 Not Found should be raised. Conversely the body 47 parameters are part of the request; if they are invalid a 400 Bad Request. 48 """ 49 (args, varargs, varkw, defaults) = inspect.getargspec(callable) 50 51 if args and args[0] == 'self': 52 args = args[1:] 53 54 arg_usage = dict([(arg, 0,) for arg in args]) 55 vararg_usage = 0 56 varkw_usage = 0 57 extra_kwargs = set() 58 59 for i, value in enumerate(callable_args): 60 try: 61 arg_usage[args[i]] += 1 62 except IndexError: 63 vararg_usage += 1 64 65 for key in callable_kwargs.keys(): 66 try: 67 arg_usage[key] += 1 68 except KeyError: 69 varkw_usage += 1 70 extra_kwargs.add(key) 71 72 for i, val in enumerate(defaults or []): 73 # Defaults take effect only when the arg hasn't been used yet. 74 if arg_usage[args[i]] == 0: 75 arg_usage[args[i]] += 1 76 77 missing_args = [] 78 multiple_args = [] 79 for key, usage in arg_usage.iteritems(): 80 if usage == 0: 81 missing_args.append(key) 82 elif usage > 1: 83 multiple_args.append(key) 84 85 if missing_args: 86 # In the case where the method allows body arguments 87 # there are 3 potential errors: 88 # 1. not enough query string parameters -> 404 89 # 2. not enough body parameters -> 400 90 # 3. not enough path parts (partial matches) -> 404 91 # 92 # We can't actually tell which case it is, 93 # so I'm raising a 404 because that covers 2/3 of the 94 # possibilities 95 # 96 # In the case where the method does not allow body 97 # arguments it's definitely a 404. 98 raise cherrypy.HTTPError(404, 99 message="Missing parameters: %s" % ",".join(missing_args)) 100 101 # the extra positional arguments come from the path - 404 Not Found 102 if not varargs and vararg_usage > 0: 103 raise cherrypy.HTTPError(404) 104 105 body_params = cherrypy.request.body_params or {} 106 body_params = set(body_params.keys()) 107 qs_params = set(callable_kwargs.keys()) - body_params 108 109 if multiple_args: 110 111 if qs_params.intersection(set(multiple_args)): 112 # If any of the multiple parameters came from the query string then 113 # it's a 404 Not Found 114 error = 404 115 else: 116 # Otherwise it's a 400 Bad Request 117 error = 400 118 119 raise cherrypy.HTTPError(error, 120 message="Multiple values for parameters: "\ 121 "%s" % ",".join(multiple_args)) 122 123 if not varkw and varkw_usage > 0: 124 125 # If there were extra query string parameters, it's a 404 Not Found 126 extra_qs_params = set(qs_params).intersection(extra_kwargs) 127 if extra_qs_params: 128 raise cherrypy.HTTPError(404, 129 message="Unexpected query string "\ 130 "parameters: %s" % ", ".join(extra_qs_params)) 131 132 # If there were any extra body parameters, it's a 400 Not Found 133 extra_body_params = set(body_params).intersection(extra_kwargs) 134 if extra_body_params: 135 raise cherrypy.HTTPError(400, 136 message="Unexpected body parameters: "\ 137 "%s" % ", ".join(extra_body_params)) 138 139 140 try: 141 import inspect 142 except ImportError: 143 test_callable_spec = lambda callable, args, kwargs: None 144 25 145 26 146 branches/cherrypy-3.1.x/cherrypy/_cplogging.py
r1984 r2068 127 127 stream=sys.stderr 128 128 h = logging.StreamHandler(stream) 129 h.setLevel(logging.DEBUG)130 129 h.setFormatter(logfmt) 131 130 h._cpbuiltin = "screen" … … 150 149 def _add_builtin_file_handler(self, log, fname): 151 150 h = logging.FileHandler(fname) 152 h.setLevel(logging.DEBUG)153 151 h.setFormatter(logfmt) 154 152 h._cpbuiltin = "file" … … 198 196 if not h: 199 197 h = WSGIErrorHandler() 200 h.setLevel(logging.DEBUG)201 198 h.setFormatter(logfmt) 202 199 h._cpbuiltin = "wsgi" branches/cherrypy-3.1.x/cherrypy/_cprequest.py
r1994 r2068 9 9 from cherrypy import _cpcgifs, _cpconfig 10 10 from cherrypy._cperror import format_exc, bare_error 11 from cherrypy.lib import http 11 from cherrypy.lib import http, file_generator 12 12 13 13 … … 748 748 749 749 750 def file_generator(input, chunkSize=65536):751 """Yield the given input (a file object) in chunks (default 64k). (Core)"""752 chunk = input.read(chunkSize)753 while chunk:754 yield chunk755 chunk = input.read(chunkSize)756 input.close()757 758 759 750 class Body(object): 760 751 """The body of the HTTP response (the response entity).""" branches/cherrypy-3.1.x/cherrypy/_cpserver.py
r1994 r2068 50 50 reverse_dns = False 51 51 thread_pool = 10 52 thread_pool_max = -1 52 53 max_request_header_size = 500 * 1024 53 54 max_request_body_size = 100 * 1024 * 1024 branches/cherrypy-3.1.x/cherrypy/_cptree.py
r1989 r2068 154 154 root: an instance of a "controller class" (a collection of page 155 155 handler methods) which represents the root of the application. 156 This may also be an Application instance, or None if using 157 a dispatcher other than the default. 156 158 script_name: a string containing the "mount point" of the application. 157 159 This should start with a slash, and be the path portion of the … … 169 171 if isinstance(root, Application): 170 172 app = root 173 if script_name != "" and script_name != app.script_name: 174 raise ValueError, "Cannot specify a different script name and pass an Application instance to cherrypy.mount" 175 script_name = app.script_name 171 176 else: 172 177 app = Application(root, script_name) 173 178 174 179 # If mounted at "", add favicon.ico 175 if script_name == "" and root and not hasattr(root, "favicon_ico"): 180 if (script_name == "" and root is not None 181 and not hasattr(root, "favicon_ico")): 176 182 favicon = os.path.join(os.getcwd(), os.path.dirname(__file__), 177 183 "favicon.ico") branches/cherrypy-3.1.x/cherrypy/_cpwsgi_server.py
r1994 r2068 44 44 server.thread_pool, 45 45 server.socket_host, 46 max = server.thread_pool_max, 46 47 request_queue_size = server.socket_queue_size, 47 48 timeout = server.socket_timeout, branches/cherrypy-3.1.x/cherrypy/cherryd
r2067 r2068 9 9 10 10 def start(configfiles=None, daemonize=False, environment=None, 11 fastcgi=False, pidfile=None, imports=None):11 fastcgi=False, scgi=False, pidfile=None, imports=None): 12 12 """Subscribe all engine plugins and start the engine.""" 13 sys.path = [''] + sys.path 13 14 for i in imports or []: 14 15 exec "import %s" % i … … 36 37 engine.console_control_handler.subscribe() 37 38 38 if fastcgi: 39 # turn off autoreload when using fastcgi 40 cherrypy.config.update({'autoreload.on': False}) 41 39 if fastcgi and scgi: 40 # fastcgi and scgi aren't allowed together. 41 cherrypy.log.error("fastcgi and scgi aren't allowed together.", 'ENGINE') 42 sys.exit(1) 43 elif fastcgi or scgi: 44 # Turn off autoreload when using fastcgi or scgi. 45 cherrypy.config.update({'engine.autoreload_on': False}) 46 # Turn off the default HTTP server (which is subscribed by default). 42 47 cherrypy.server.unsubscribe() 43 48 44 fastcgi_port = cherrypy.config.get('server.socket_port', 4000) 45 fastcgi_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0') 46 bindAddress = (fastcgi_bindaddr, fastcgi_port) 47 f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=bindAddress) 49 sock_file = cherrypy.config.get('server.socket_file', None) 50 if sock_file: 51 bindAddress = sock_file 52 else: 53 flup_port = cherrypy.config.get('server.socket_port', 4000) 54 flup_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0') 55 bindAddress = (flup_bindaddr, flup_port) 56 if fastcgi: 57 f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=bindAddress) 58 else: 59 f = servers.FlupSCGIServer(application=cherrypy.tree, bindAddress=bindAddress) 48 60 s = servers.ServerAdapter(engine, httpserver=f, bind_addr=bindAddress) 49 61 s.subscribe() … … 71 83 p.add_option('-f', action="store_true", dest='fastcgi', 72 84 help="start a fastcgi server instead of the default HTTP server") 85 p.add_option('-s', action="store_true", dest='scgi', 86 help="start a scgi server instead of the default HTTP server") 73 87 p.add_option('-i', '--import', action="append", dest='imports', 74 88 help="specify modules to import") … … 78 92 79 93 start(options.config, options.daemonize, 80 options.environment, options.fastcgi, options. pidfile,94 options.environment, options.fastcgi, options.scgi, options.pidfile, 81 95 options.imports) 82 96 branches/cherrypy-3.1.x/cherrypy/lib/__init__.py
r1794 r2068 134 134 return _Builder().build(obj) 135 135 136 137 def file_generator(input, chunkSize=65536): 138 """Yield the given input (a file object) in chunks (default 64k). (Core)""" 139 chunk = input.read(chunkSize) 140 while chunk: 141 yield chunk 142 chunk = input.read(chunkSize) 143 input.close() 144 145 146 def file_generator_limited(fileobj, count, chunk_size=65536): 147 """Yield the given file object in chunks, stopping after `count` 148 bytes has been emitted. Default chunk size is 64kB. (Core) 149 """ 150 remaining = count 151 while remaining > 0: 152 chunk = fileobj.read(min(chunk_size, remaining)) 153 chunklen = len(chunk) 154 if chunklen == 0: 155 return 156 remaining -= chunklen 157 yield chunk 158 branches/cherrypy-3.1.x/cherrypy/lib/cptools.py
r1980 r2068 213 213 pass 214 214 215 def login_screen(self, from_page='..', username='', error_msg='' ):215 def login_screen(self, from_page='..', username='', error_msg='', **kwargs): 216 216 return """<html><body> 217 217 Message: %(error_msg)s … … 225 225 'error_msg': error_msg} 226 226 227 def do_login(self, username, password, from_page='..' ):227 def do_login(self, username, password, from_page='..', **kwargs): 228 228 """Login. May raise redirect, or return True if request handled.""" 229 229 error_msg = self.check_username_and_password(username, password) … … 240 240 raise cherrypy.HTTPRedirect(from_page or "/") 241 241 242 def do_logout(self, from_page='..' ):242 def do_logout(self, from_page='..', **kwargs): 243 243 """Logout. May raise redirect, or return True if request handled.""" 244 244 sess = cherrypy.session branches/cherrypy-3.1.x/cherrypy/lib/http.py
r1994 r2068 252 252 253 253 def parse_query_string(query_string, keep_blank_values=True): 254 """Build a params dictionary from a query_string.""" 254 """Build a params dictionary from a query_string. 255 256 Duplicate key/value pairs in the provided query_string will be 257 returned as {'key': [val1, val2, ...]}. Single key/values will 258 be returned as strings: {'key': 'value'}. 259 """ 255 260 if image_map_pattern.match(query_string): 256 261 # Server-side image map. Map the coords to 'x' and 'y' branches/cherrypy-3.1.x/cherrypy/lib/httpauth.py
r1891 r2068 276 276 H_A1 = H(_A1(params, password)) 277 277 278 if qop == "auth" or aop == "auth-int":278 if qop in ("auth", "auth-int"): 279 279 # If the "qop" value is "auth" or "auth-int": 280 280 # request-digest = <"> < KD ( H(A1), unq(nonce-value) … … 291 291 H_A2, 292 292 ) 293 294 293 elif qop is None: 295 294 # If the "qop" directive is not present (this construction is branches/cherrypy-3.1.x/cherrypy/lib/profiler.py
r1985 r2068 161 161 class make_app: 162 162 def __init__(self, nextapp, path=None, aggregate=False): 163 """Make a WSGI middleware app which wraps 'nextapp' with profiling.""" 163 """Make a WSGI middleware app which wraps 'nextapp' with profiling. 164 165 nextapp: the WSGI application to wrap, usually an instance of 166 cherrypy.Application. 167 path: where to dump the profiling output. 168 aggregate: if True, profile data for all HTTP requests will go in 169 a single file. If False (the default), each HTTP request will 170 dump its profile data into a separate file. 171 """ 164 172 self.nextapp = nextapp 165 173 self.aggregate = aggregate branches/cherrypy-3.1.x/cherrypy/lib/sessions.py
r1932 r2068 144 144 # The instances are created and destroyed per-request. 145 145 cls = self.__class__ 146 if not cls.clean_thread:146 if self.clean_freq and not cls.clean_thread: 147 147 # clean_up is in instancemethod and not a classmethod, 148 148 # so that tool config can be accessed inside the method. … … 283 283 LOCK_SUFFIX = '.lock' 284 284 285 def __init__(self, id=None, **kwargs): 286 # The 'storage_path' arg is required for file-based sessions. 287 kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) 288 Session.__init__(self, id=id, **kwargs) 289 285 290 def setup(cls, **kwargs): 286 291 """Set up the storage system for file-based sessions. … … 289 294 automatically when using sessions.init (as the built-in Tool does). 290 295 """ 291 if 'storage_path' in kwargs:292 kwargs['storage_path'] = os.path.abspath(kwargs['storage_path'])296 # The 'storage_path' arg is required for file-based sessions. 297 kwargs['storage_path'] = os.path.abspath(kwargs['storage_path']) 293 298 294 299 for k, v in kwargs.iteritems(): branches/cherrypy-3.1.x/cherrypy/lib/static.py
r1975 r2068 11 11 12 12 import cherrypy 13 from cherrypy.lib import cptools, http 13 from cherrypy.lib import cptools, http, file_generator_limited 14 14 15 15 … … 84 84 # Return a single-part response. 85 85 start, stop = r[0] 86 if stop > c_len: 87 stop = c_len 86 88 r_len = stop - start 87 89 response.status = "206 Partial Content" … … 90 92 response.headers['Content-Length'] = r_len 91 93 bodyfile.seek(start) 92 response.body = bodyfile.read(r_len)94 response.body = file_generator_limited(bodyfile, r_len) 93 95 else: 94 96 # Return a multipart/byteranges response. … … 112 114 % (start, stop - 1, c_len)) 113 115 bodyfile.seek(start) 114 yield bodyfile.read(stop - start) 116 for chunk in file_generator_limited(bodyfile, stop-start): 117 yield chunk 115 118 yield "\r\n" 116 119 # Final boundary branches/cherrypy-3.1.x/cherrypy/lib/xmlrpc.py
r1955 r2068 43 43 allow_none=allow_none)) 44 44 45 def on_error( ):45 def on_error(*args, **kwargs): 46 46 body = str(sys.exc_info()[1]) 47 47 import xmlrpclib branches/cherrypy-3.1.x/cherrypy/process/plugins.py
r2006 r2068 22 22 """Register this object as a (multi-channel) listener on the bus.""" 23 23 for channel in self.bus.listeners: 24 # Subscribe self.start, self.exit, etc. if present. 24 25 method = getattr(self, channel, None) 25 26 if method is not None: … … 29 30 """Unregister this object as a listener on the bus.""" 30 31 for channel in self.bus.listeners: 32 # Unsubscribe self.start, self.exit, etc. if present. 31 33 method = getattr(self, channel, None) 32 34 if method is not None: … … 214 216 self.bus.log('Started as uid: %r gid: %r' % current_ids()) 215 217 if self.gid is not None: 216 os.setgid( gid)218 os.setgid(self.gid) 217 219 if self.uid is not None: 218 os.setuid( uid)220 os.setuid(self.uid) 219 221 self.bus.log('Running as uid: %r gid: %r' % current_ids()) 220 222 … … 232 234 233 235 self.finalized = True 234 start.priority = 75 236 # This is slightly higher than the priority for server.start 237 # in order to facilitate the most common use: starting on a low 238 # port (which requires root) and then dropping to another user. 239 start.priority = 77 235 240 236 241 branches/cherrypy-3.1.x/cherrypy/process/servers.py
r1974 r2068 125 125 126 126 def __init__(self, *args, **kwargs): 127 self.args = args 128 self.kwargs = kwargs 129 self.ready = False 130 131 def start(self): 132 """Start the FCGI server.""" 133 # We have to instantiate the server class here because its __init__ 134 # starts a threadpool. If we do it too early, daemonize won't work. 127 135 from flup.server.fcgi import WSGIServer 128 self.fcgiserver = WSGIServer(* args, **kwargs)136 self.fcgiserver = WSGIServer(*self.args, **self.kwargs) 129 137 # TODO: report this bug upstream to flup. 130 138 # If we don't set _oldSIGs on Windows, we get: … … 136 144 # for signum,handler in self._oldSIGs: 137 145 # AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' 146 self.fcgiserver._installSignalHandlers = lambda: None 138 147 self.fcgiserver._oldSIGs = [] 139 self.ready = False140 141 def start(self):142 """Start the FCGI server."""143 148 self.ready = True 144 149 self.fcgiserver.run() … … 151 156 # Force all worker threads to die off. 152 157 self.fcgiserver._threadPool.maxSpare = 0 158 159 160 class FlupSCGIServer(object): 161 """Adapter for a flup.server.scgi.WSGIServer.""" 162 163 def __init__(self, *args, **kwargs): 164 self.args = args 165 self.kwargs = kwargs 166 self.ready = False 167 168 def start(self): 169 """Start the SCGI server.""" 170 # We have to instantiate the server class here because its __init__ 171 # starts a threadpool. If we do it too early, daemonize won't work. 172 from flup.server.scgi import WSGIServer 173 self.scgiserver = WSGIServer(*self.args, **self.kwargs) 174 # TODO: report this bug upstream to flup. 175 # If we don't set _oldSIGs on Windows, we get: 176 # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", 177 # line 108, in run 178 # self._restoreSignalHandlers() 179 # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", 180 # line 156, in _restoreSignalHandlers 181 # for signum,handler in self._oldSIGs: 182 # AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' 183 self.scgiserver._installSignalHandlers = lambda: None 184 self.scgiserver._oldSIGs = [] 185 self.ready = True 186 self.scgiserver.run() 187 188 def stop(self): 189 """Stop the HTTP server.""" 190 self.ready = False 191 # Forcibly stop the scgi server main event loop. 192 self.scgiserver._keepGoing = False 193 # Force all worker threads to die off. 194 self.scgiserver._threadPool.maxSpare = 0 153 195 154 196 branches/cherrypy-3.1.x/cherrypy/process/win32.py
r1989 r2068 72 72 """A Web Site Process Bus implementation for Win32. 73 73 74 Instead of using time.sleep for blocking, this bus uses native 75 win32event objects. It also responds to console events. 74 Instead of time.sleep, this bus blocks using native win32event objects. 76 75 """ 77 76 … … 100 99 101 100 def wait(self, state, interval=0.1): 102 """Wait for the given state , KeyboardInterrupt or SystemExit.101 """Wait for the given state(s), KeyboardInterrupt or SystemExit. 103 102 104 103 Since this class uses native win32event objects, the interval 105 104 argument is ignored. 106 105 """ 107 # Don't wait for an event that beat us to the punch ;) 108 if self.state != state: 109 event = self._get_state_event(state) 110 win32event.WaitForSingleObject(event, win32event.INFINITE) 106 if isinstance(state, (tuple, list)): 107 # Don't wait for an event that beat us to the punch ;) 108 if self.state not in state: 109 events = tuple([self._get_state_event(s) for s in state]) 110 win32event.WaitForMultipleObjects(events, 0, win32event.INFINITE) 111 else: 112 # Don't wait for an event that beat us to the punch ;) 113 if self.state != state: 114 event = self._get_state_event(state) 115 win32event.WaitForSingleObject(event, win32event.INFINITE) 111 116 112 117 branches/cherrypy-3.1.x/cherrypy/process/wspbus.py
r1989 r2068 154 154 raise 155 155 except: 156 self.log("Error in %r listener %r" % (channel, listener),157 level=40, traceback=True)158 156 exc = sys.exc_info()[1] 157 if channel == 'log': 158 # Assume any further messages to 'log' will fail. 159 pass 160 else: 161 self.log("Error in %r listener %r" % (channel, listener), 162 level=40, traceback=True) 159 163 if exc: 160 164 raise … … 249 253 250 254 def wait(self, state, interval=0.1): 251 """Wait for the given state.""" 255 """Wait for the given state(s).""" 256 if isinstance(state, (tuple, list)): 257 states = state 258 else: 259 states = [state] 260 252 261 def _wait(): 253 while self.state != state:262 while self.state not in states: 254 263 time.sleep(interval) 255 264 branches/cherrypy-3.1.x/cherrypy/test/helper.py
r2004 r2068 148 148 else: 149 149 app = validate.validator(app) 150 cherrypy.server.httpserver.wsgi_app = app 150 151 h = cherrypy.server.httpserver 152 if hasattr(h, 'wsgi_app'): 153 # CherryPy's wsgiserver 154 h.wsgi_app = app 155 elif hasattr(h, 'fcgiserver'): 156 # flup's WSGIServer 157 h.fcgiserver.application = app 158 elif hasattr(h, 'scgiserver'): 159 # flup's WSGIServer 160 h.scgiserver.application = app 151 161 152 162 def _run_test_suite_thread(moduleNames, conf): branches/cherrypy-3.1.x/cherrypy/test/modwsgi.py
r1824 r2068 34 34 35 35 import os 36 curdir = os.path. join(os.getcwd(),os.path.dirname(__file__))36 curdir = os.path.abspath(os.path.dirname(__file__)) 37 37 import re 38 import sys 38 39 import time 39 40 40 from cherrypy.test import test 41 import cherrypy 42 from cherrypy.test import test, webtest 41 43 42 44 … … 54 56 55 57 56 APACHE_PATH = "apache" 58 if sys.platform == 'win32': 59 APACHE_PATH = "httpd" 60 else: 61 APACHE_PATH = "apache" 62 57 63 CONF_PATH = "test_mw.conf" 58 64 59 conf_modwsgi = """65 conf_modwsgi = r""" 60 66 # Apache2 server conf file for testing CherryPy with modpython_gateway. 61 67 68 ServerName 127.0.0.1 62 69 DocumentRoot "/" 63 Listen %%s 70 Listen %(port)s 71 72 AllowEncodedSlashes On 73 LoadModule rewrite_module modules/mod_rewrite.so 74 RewriteEngine on 75 RewriteMap escaping int:escape 76 77 LoadModule log_config_module modules/mod_log_config.so 78 LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-agent}i\"" combined 79 CustomLog "%(curdir)s/apache.access.log" combined 80 ErrorLog "%(curdir)s/apache.error.log" 81 LogLevel debug 82 64 83 LoadModule wsgi_module modules/mod_wsgi.so 65 84 LoadModule env_module modules/mod_env.so 66 85 67 WSGIScriptAlias / %s68 SetEnv testmod % %s69 """ % os.path.join(curdir, 'modwsgi.py')86 WSGIScriptAlias / "%(curdir)s/modwsgi.py" 87 SetEnv testmod %(testmod)s 88 """ 70 89 71 90 … … 77 96 f = open(mpconf, 'wb') 78 97 try: 79 f.write(conf_template % (port, testmod)) 98 output = (conf_template % 99 {'port': port, 'testmod': testmod, 'curdir': curdir}) 100 f.write(output) 80 101 finally: 81 102 f.close() … … 114 135 try: 115 136 start(testmod, self.port, conf_template) 137 cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port) 116 138 suite = webtest.ReloadingTestLoader().loadTestsFromName(testmod) 139 # Make a request so mod_wsgi starts up our app. 140 # If we don't, concurrent initial requests will 404. 141 webtest.openURL('/ihopetheresnodefault', port=self.port) 142 time.sleep(1) 117 143 result = webtest.TerseTestRunner(verbosity=2).run(suite) 118 144 success &= result.wasSuccessful() … … 136 162 137 163 cherrypy.config.update({ 138 "log.error_file": os.path.join(curdir, "test.log"), 164 "log.error_file": os.path.join(curdir, "test.error.log"), 165 "log.access_file": os.path.join(curdir, "test.access.log"), 139 166 "environment": "test_suite", 140 167 "engine.SIGHUP": None, 141 168 "engine.SIGTERM": None, 142 169 }) 143 cherrypy.server.unsubscribe()144 cherrypy.engine.start(blocking=False)145 170 return cherrypy.tree(environ, start_response) 146 171 branches/cherrypy-3.1.x/cherrypy/test/test.py
r2003 r2068 91 91 'modpygw': "modpygw", 92 92 'modwsgi': "modwsgi", 93 'modfcgid': "modfcgid", 93 94 } 94 95 default_server = "wsgi" … … 333 334 "http", self.interactive) 334 335 h.use_wsgi = True 336 elif self.server == 'modfcgid': 337 from cherrypy.test import modfcgid 338 h = modfcgid.FCGITestHarness(self.tests, self.server, 339 self.protocol, self.port, 340 "http", self.interactive) 335 341 else: 336 342 h = TestHarness(self.tests, self.server, self.protocol, branches/cherrypy-3.1.x/cherrypy/test/test_core.py
r1992 r2068 99 99 return "args: %s kwargs: %s" % (args, kwargs) 100 100 101 class ParamErrors(Test): 102 103 def one_positional(self, param1): 104 return "data" 105 one_positional.exposed = True 106 107 def one_positional_args(self, param1, *args): 108 return "data" 109 one_positional_args.exposed = True 110 111 def one_positional_args_kwargs(self, param1, *args, **kwargs): 112 return "data" 113 one_positional_args_kwargs.exposed = True 114 115 def one_positional_kwargs(self, param1, **kwargs): 116 return "data" 117 one_positional_kwargs.exposed = True 118 119 def no_positional(self): 120 return "data" 121 no_positional.exposed = True 122 123 def no_positional_args(self, *args): 124 return "data" 125 no_positional_args.exposed = True 126 127 def no_positional_args_kwargs(self, *args, **kwargs): 128 return "data" 129 no_positional_args_kwargs.exposed = True 130 131 def no_positional_kwargs(self, **kwargs): 132 return "data" 133 no_positional_kwargs.exposed = True 134 101 135 102 136 class Status(Test): … … 444 478 self.getPage("/params/?thing=a&thing=b&thing=c"
