Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 2068

Show
Ignore:
Timestamp:
11/08/08 12:22:41
Author:
fumanchu
Message:

Merging [2007] to [2051] from trunk in prep for releasing 3.1.1.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cherrypy-3.1.x/cherrypy/_cpconfig.py

    r1989 r2068  
    304304        engine.autoreload.match = v 
    305305    elif k == 'reload_files': 
    306         engine.autoreload.files = v 
     306        engine.autoreload.files = set(v) 
    307307    elif k == 'deadlock_poll_freq': 
    308308        engine.timeout_monitor.frequency = v 
     
    311311    elif k == 'SIGTERM': 
    312312        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) 
    313326Config.namespaces["engine"] = _engine_namespace_handler 
    314327 
  • branches/cherrypy-3.1.x/cherrypy/_cpdispatch.py

    r1893 r2068  
    2222     
    2323    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 
     30def 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 
     140try: 
     141    import inspect 
     142except ImportError: 
     143    test_callable_spec = lambda callable, args, kwargs: None 
     144 
    25145 
    26146 
  • branches/cherrypy-3.1.x/cherrypy/_cplogging.py

    r1984 r2068  
    127127                    stream=sys.stderr 
    128128                h = logging.StreamHandler(stream) 
    129                 h.setLevel(logging.DEBUG) 
    130129                h.setFormatter(logfmt) 
    131130                h._cpbuiltin = "screen" 
     
    150149    def _add_builtin_file_handler(self, log, fname): 
    151150        h = logging.FileHandler(fname) 
    152         h.setLevel(logging.DEBUG) 
    153151        h.setFormatter(logfmt) 
    154152        h._cpbuiltin = "file" 
     
    198196            if not h: 
    199197                h = WSGIErrorHandler() 
    200                 h.setLevel(logging.DEBUG) 
    201198                h.setFormatter(logfmt) 
    202199                h._cpbuiltin = "wsgi" 
  • branches/cherrypy-3.1.x/cherrypy/_cprequest.py

    r1994 r2068  
    99from cherrypy import _cpcgifs, _cpconfig 
    1010from cherrypy._cperror import format_exc, bare_error 
    11 from cherrypy.lib import http 
     11from cherrypy.lib import http, file_generator 
    1212 
    1313 
     
    748748 
    749749 
    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 chunk 
    755         chunk = input.read(chunkSize) 
    756     input.close() 
    757  
    758  
    759750class Body(object): 
    760751    """The body of the HTTP response (the response entity).""" 
  • branches/cherrypy-3.1.x/cherrypy/_cpserver.py

    r1994 r2068  
    5050    reverse_dns = False 
    5151    thread_pool = 10 
     52    thread_pool_max = -1 
    5253    max_request_header_size = 500 * 1024 
    5354    max_request_body_size = 100 * 1024 * 1024 
  • branches/cherrypy-3.1.x/cherrypy/_cptree.py

    r1989 r2068  
    154154        root: an instance of a "controller class" (a collection of page 
    155155            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. 
    156158        script_name: a string containing the "mount point" of the application. 
    157159            This should start with a slash, and be the path portion of the 
     
    169171        if isinstance(root, Application): 
    170172            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 
    171176        else: 
    172177            app = Application(root, script_name) 
    173178             
    174179            # 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")): 
    176182                favicon = os.path.join(os.getcwd(), os.path.dirname(__file__), 
    177183                                       "favicon.ico") 
  • branches/cherrypy-3.1.x/cherrypy/_cpwsgi_server.py

    r1994 r2068  
    4444                   server.thread_pool, 
    4545                   server.socket_host, 
     46                   max = server.thread_pool_max, 
    4647                   request_queue_size = server.socket_queue_size, 
    4748                   timeout = server.socket_timeout, 
  • branches/cherrypy-3.1.x/cherrypy/cherryd

    r2067 r2068  
    99 
    1010def start(configfiles=None, daemonize=False, environment=None, 
    11           fastcgi=False, pidfile=None, imports=None): 
     11          fastcgi=False, scgi=False, pidfile=None, imports=None): 
    1212    """Subscribe all engine plugins and start the engine.""" 
     13    sys.path = [''] + sys.path 
    1314    for i in imports or []: 
    1415        exec "import %s" % i 
     
    3637        engine.console_control_handler.subscribe() 
    3738     
    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). 
    4247        cherrypy.server.unsubscribe() 
    4348         
    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) 
    4860        s = servers.ServerAdapter(engine, httpserver=f, bind_addr=bindAddress) 
    4961        s.subscribe() 
     
    7183    p.add_option('-f', action="store_true", dest='fastcgi', 
    7284                 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") 
    7387    p.add_option('-i', '--import', action="append", dest='imports', 
    7488                 help="specify modules to import") 
     
    7892     
    7993    start(options.config, options.daemonize, 
    80           options.environment, options.fastcgi, options.pidfile, 
     94          options.environment, options.fastcgi, options.scgi, options.pidfile, 
    8195          options.imports) 
    8296 
  • branches/cherrypy-3.1.x/cherrypy/lib/__init__.py

    r1794 r2068  
    134134    return _Builder().build(obj) 
    135135 
     136 
     137def 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 
     146def 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  
    213213        pass 
    214214     
    215     def login_screen(self, from_page='..', username='', error_msg=''): 
     215    def login_screen(self, from_page='..', username='', error_msg='', **kwargs): 
    216216        return """<html><body> 
    217217Message: %(error_msg)s 
     
    225225                     'error_msg': error_msg} 
    226226     
    227     def do_login(self, username, password, from_page='..'): 
     227    def do_login(self, username, password, from_page='..', **kwargs): 
    228228        """Login. May raise redirect, or return True if request handled.""" 
    229229        error_msg = self.check_username_and_password(username, password) 
     
    240240            raise cherrypy.HTTPRedirect(from_page or "/") 
    241241     
    242     def do_logout(self, from_page='..'): 
     242    def do_logout(self, from_page='..', **kwargs): 
    243243        """Logout. May raise redirect, or return True if request handled.""" 
    244244        sess = cherrypy.session 
  • branches/cherrypy-3.1.x/cherrypy/lib/http.py

    r1994 r2068  
    252252 
    253253def 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    """ 
    255260    if image_map_pattern.match(query_string): 
    256261        # Server-side image map. Map the coords to 'x' and 'y' 
  • branches/cherrypy-3.1.x/cherrypy/lib/httpauth.py

    r1891 r2068  
    276276        H_A1 = H(_A1(params, password)) 
    277277 
    278     if qop == "auth" or aop == "auth-int"
     278    if qop in ("auth", "auth-int")
    279279        # If the "qop" value is "auth" or "auth-int": 
    280280        # request-digest  = <"> < KD ( H(A1),     unq(nonce-value) 
     
    291291            H_A2, 
    292292        ) 
    293  
    294293    elif qop is None: 
    295294        # If the "qop" directive is not present (this construction is 
  • branches/cherrypy-3.1.x/cherrypy/lib/profiler.py

    r1985 r2068  
    161161class make_app: 
    162162    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        """ 
    164172        self.nextapp = nextapp 
    165173        self.aggregate = aggregate 
  • branches/cherrypy-3.1.x/cherrypy/lib/sessions.py

    r1932 r2068  
    144144        # The instances are created and destroyed per-request. 
    145145        cls = self.__class__ 
    146         if not cls.clean_thread: 
     146        if self.clean_freq and not cls.clean_thread: 
    147147            # clean_up is in instancemethod and not a classmethod, 
    148148            # so that tool config can be accessed inside the method. 
     
    283283    LOCK_SUFFIX = '.lock' 
    284284     
     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     
    285290    def setup(cls, **kwargs): 
    286291        """Set up the storage system for file-based sessions. 
     
    289294        automatically when using sessions.init (as the built-in Tool does). 
    290295        """ 
    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']) 
    293298         
    294299        for k, v in kwargs.iteritems(): 
  • branches/cherrypy-3.1.x/cherrypy/lib/static.py

    r1975 r2068  
    1111 
    1212import cherrypy 
    13 from cherrypy.lib import cptools, http 
     13from cherrypy.lib import cptools, http, file_generator_limited 
    1414 
    1515 
     
    8484                # Return a single-part response. 
    8585                start, stop = r[0] 
     86                if stop > c_len: 
     87                    stop = c_len 
    8688                r_len = stop - start 
    8789                response.status = "206 Partial Content" 
     
    9092                response.headers['Content-Length'] = r_len 
    9193                bodyfile.seek(start) 
    92                 response.body = bodyfile.read(r_len) 
     94                response.body = file_generator_limited(bodyfile, r_len) 
    9395            else: 
    9496                # Return a multipart/byteranges response. 
     
    112114                               % (start, stop - 1, c_len)) 
    113115                        bodyfile.seek(start) 
    114                         yield bodyfile.read(stop - start) 
     116                        for chunk in file_generator_limited(bodyfile, stop-start): 
     117                            yield chunk 
    115118                        yield "\r\n" 
    116119                    # Final boundary 
  • branches/cherrypy-3.1.x/cherrypy/lib/xmlrpc.py

    r1955 r2068  
    4343                                  allow_none=allow_none)) 
    4444 
    45 def on_error(): 
     45def on_error(*args, **kwargs): 
    4646    body = str(sys.exc_info()[1]) 
    4747    import xmlrpclib 
  • branches/cherrypy-3.1.x/cherrypy/process/plugins.py

    r2006 r2068  
    2222        """Register this object as a (multi-channel) listener on the bus.""" 
    2323        for channel in self.bus.listeners: 
     24            # Subscribe self.start, self.exit, etc. if present. 
    2425            method = getattr(self, channel, None) 
    2526            if method is not None: 
     
    2930        """Unregister this object as a listener on the bus.""" 
    3031        for channel in self.bus.listeners: 
     32            # Unsubscribe self.start, self.exit, etc. if present. 
    3133            method = getattr(self, channel, None) 
    3234            if method is not None: 
     
    214216                self.bus.log('Started as uid: %r gid: %r' % current_ids()) 
    215217                if self.gid is not None: 
    216                     os.setgid(gid) 
     218                    os.setgid(self.gid) 
    217219                if self.uid is not None: 
    218                     os.setuid(uid) 
     220                    os.setuid(self.uid) 
    219221                self.bus.log('Running as uid: %r gid: %r' % current_ids()) 
    220222         
     
    232234         
    233235        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 
    235240 
    236241 
  • branches/cherrypy-3.1.x/cherrypy/process/servers.py

    r1974 r2068  
    125125     
    126126    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. 
    127135        from flup.server.fcgi import WSGIServer 
    128         self.fcgiserver = WSGIServer(*args, **kwargs) 
     136        self.fcgiserver = WSGIServer(*self.args, **self.kwargs) 
    129137        # TODO: report this bug upstream to flup. 
    130138        # If we don't set _oldSIGs on Windows, we get: 
     
    136144        #     for signum,handler in self._oldSIGs: 
    137145        #   AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' 
     146        self.fcgiserver._installSignalHandlers = lambda: None 
    138147        self.fcgiserver._oldSIGs = [] 
    139         self.ready = False 
    140      
    141     def start(self): 
    142         """Start the FCGI server.""" 
    143148        self.ready = True 
    144149        self.fcgiserver.run() 
     
    151156        # Force all worker threads to die off. 
    152157        self.fcgiserver._threadPool.maxSpare = 0 
     158 
     159 
     160class 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 
    153195 
    154196 
  • branches/cherrypy-3.1.x/cherrypy/process/win32.py

    r1989 r2068  
    7272    """A Web Site Process Bus implementation for Win32. 
    7373     
    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. 
    7675    """ 
    7776     
     
    10099     
    101100    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. 
    103102         
    104103        Since this class uses native win32event objects, the interval 
    105104        argument is ignored. 
    106105        """ 
    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) 
    111116 
    112117 
  • branches/cherrypy-3.1.x/cherrypy/process/wspbus.py

    r1989 r2068  
    154154                raise 
    155155            except: 
    156                 self.log("Error in %r listener %r" % (channel, listener), 
    157                          level=40, traceback=True) 
    158156                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) 
    159163        if exc: 
    160164            raise 
     
    249253     
    250254    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         
    252261        def _wait(): 
    253             while self.state != state
     262            while self.state not in states
    254263                time.sleep(interval) 
    255264         
  • branches/cherrypy-3.1.x/cherrypy/test/helper.py

    r2004 r2068  
    148148        else: 
    149149            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 
    151161 
    152162def _run_test_suite_thread(moduleNames, conf): 
  • branches/cherrypy-3.1.x/cherrypy/test/modwsgi.py

    r1824 r2068  
    3434 
    3535import os 
    36 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 
     36curdir = os.path.abspath(os.path.dirname(__file__)) 
    3737import re 
     38import sys 
    3839import time 
    3940 
    40 from cherrypy.test import test 
     41import cherrypy 
     42from cherrypy.test import test, webtest 
    4143 
    4244 
     
    5456 
    5557 
    56 APACHE_PATH = "apache" 
     58if sys.platform == 'win32': 
     59    APACHE_PATH = "httpd" 
     60else: 
     61    APACHE_PATH = "apache" 
     62 
    5763CONF_PATH = "test_mw.conf" 
    5864 
    59 conf_modwsgi = """ 
     65conf_modwsgi = r""" 
    6066# Apache2 server conf file for testing CherryPy with modpython_gateway. 
    6167 
     68ServerName 127.0.0.1 
    6269DocumentRoot "/" 
    63 Listen %%s 
     70Listen %(port)s 
     71 
     72AllowEncodedSlashes On 
     73LoadModule rewrite_module modules/mod_rewrite.so 
     74RewriteEngine on 
     75RewriteMap escaping int:escape 
     76 
     77LoadModule log_config_module modules/mod_log_config.so 
     78LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-agent}i\"" combined 
     79CustomLog "%(curdir)s/apache.access.log" combined 
     80ErrorLog "%(curdir)s/apache.error.log" 
     81LogLevel debug 
     82 
    6483LoadModule wsgi_module modules/mod_wsgi.so 
    6584LoadModule env_module modules/mod_env.so 
    6685 
    67 WSGIScriptAlias / %s 
    68 SetEnv testmod %%
    69 """ % os.path.join(curdir, 'modwsgi.py') 
     86WSGIScriptAlias / "%(curdir)s/modwsgi.py" 
     87SetEnv testmod %(testmod)
     88""" 
    7089 
    7190 
     
    7796    f = open(mpconf, 'wb') 
    7897    try: 
    79         f.write(conf_template % (port, testmod)) 
     98        output = (conf_template % 
     99                  {'port': port, 'testmod': testmod, 'curdir': curdir}) 
     100        f.write(output) 
    80101    finally: 
    81102        f.close() 
     
    114135            try: 
    115136                start(testmod, self.port, conf_template) 
     137                cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port) 
    116138                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) 
    117143                result = webtest.TerseTestRunner(verbosity=2).run(suite) 
    118144                success &= result.wasSuccessful() 
     
    136162         
    137163        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"), 
    139166            "environment": "test_suite", 
    140167            "engine.SIGHUP": None, 
    141168            "engine.SIGTERM": None, 
    142169            }) 
    143         cherrypy.server.unsubscribe() 
    144         cherrypy.engine.start(blocking=False) 
    145170    return cherrypy.tree(environ, start_response) 
    146171 
  • branches/cherrypy-3.1.x/cherrypy/test/test.py

    r2003 r2068  
    9191                         'modpygw': "modpygw", 
    9292                         'modwsgi': "modwsgi", 
     93                         'modfcgid': "modfcgid", 
    9394                         } 
    9495    default_server = "wsgi" 
     
    333334                                           "http", self.interactive) 
    334335            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) 
    335341        else: 
    336342            h = TestHarness(self.tests, self.server, self.protocol, 
  • branches/cherrypy-3.1.x/cherrypy/test/test_core.py

    r1992 r2068  
    9999            return "args: %s kwargs: %s" % (args, kwargs) 
    100100 
     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 
    101135 
    102136    class Status(Test): 
     
    444478        self.getPage("/params/?thing=a&thing=b&thing=c"