Commits

Robert Brewer  committed c740834

Separated cherrypy.server (HTTP) from cherrypy.engine (app):

1. Most CP apps must now make both a call to cherrypy.server.start(server=None) and a call to cherrypy.engine.start(blocking=True).
2. The on_start_server_list and on_stop_server_list are now on_start_engine_list and on_stop_engine_list.
3. "start_with_callback" is now an attribute of Engine. So is "request".
4. Server.start now takes a single "server" arg, which can be a server instance, a string (fully qualified class name), or None (to start the default WSGI server).
5. Server still has a wait method, but otherwise does no blocking.

  • Participants
  • Parent commits 7d84ba4
  • Branches cherrypy

Comments (0)

Files changed (24)

 import _cptree
 tree = _cptree.Tree()
 
-# Legacy code may clobber this.
 root = None
 
+import _cpengine
+engine = _cpengine.Engine()
 import _cpserver
 server = _cpserver.Server()
 

File _cpengine.py

-"""Create and manage the CherryPy application server engine."""
+"""Create and manage the CherryPy application engine."""
 
 import cgi
 import sys
 import threading
 import time
-import warnings
 
 import cherrypy
 from cherrypy import _cprequest
 from cherrypy.lib import autoreload, profiler, cptools
 
-# Use a flag to indicate the state of the application server.
+# Use a flag to indicate the state of the application engine.
 STOPPED = 0
 STARTING = None
 STARTED = 1
 
 
 class Engine(object):
-    """The application server engine, connecting HTTP servers to Requests."""
+    """The application engine, which exposes a request interface to (HTTP) servers."""
     
     request_class = _cprequest.Request
     response_class = _cprequest.Response
     
     def __init__(self):
         self.state = STOPPED
-        
-        self.seen_threads = {}
         self.interrupt = None
         
         # Startup/shutdown hooks
-        self.on_start_server_list = []
-        self.on_stop_server_list = []
+        self.on_start_engine_list = []
+        self.on_stop_engine_list = []
         self.on_start_thread_list = []
         self.on_stop_thread_list = []
+        self.seen_threads = {}
     
-    def setup(self):
-        # The only reason this method isn't in __init__ is so that
-        # "import cherrypy" can create an Engine() without a circular ref.
+    def start(self, blocking=True):
+        """Start the application engine."""
+        self.state = STARTING
+        self.interrupt = None
+        
         conf = cherrypy.config.get
         
         # Output config options to log
             from cherrypy.lib import covercp
             covercp.start()
         
-        # If sessions are stored in files and we
-        # use threading, we need a lock on the file
-        if (conf('server.thread_pool') > 1
-            and conf('session.storage_type') == 'file'):
-            cherrypy._sessionFileLock = threading.RLock()
-        
         # set cgi.maxlen which will limit the size of POST request bodies
         cgi.maxlen = conf('server.max_request_size')
         
         else:
             cherrypy.profiler = None
         
-    def start(self):
-        """Start the application server engine."""
-        self.state = STARTING
-        self.interrupt = None
-        
-        conf = cherrypy.config.get
-        
         # Autoreload. Note that, if we're not starting our own HTTP server,
         # autoreload could do Very Bad Things when it calls sys.exit, but
         # deployers will just have to be educated and responsible for it.
         if conf('autoreload.on', False):
             try:
                 freq = conf('autoreload.frequency', 1)
-                autoreload.main(self._start, freq=freq)
+                autoreload.main(self._start, args=(blocking,), freq=freq)
             except KeyboardInterrupt:
                 cherrypy.log("<Ctrl-C> hit: shutting down autoreloader", "ENGINE")
+                cherrypy.server.stop()
                 self.stop()
             except SystemExit:
                 cherrypy.log("SystemExit raised: shutting down autoreloader", "ENGINE")
+                cherrypy.server.stop()
                 self.stop()
                 # We must raise here: if this is a process spawned by
                 # autoreload, then it must return its error code to
                 raise
             return
         
-        self._start()
+        self._start(blocking)
     
-    def _start(self):
-        for func in self.on_start_server_list:
+    def _start(self, blocking=True):
+        # This is in a separate function so autoreload can call it.
+        for func in self.on_start_engine_list:
             func()
         self.state = STARTED
+        if blocking:
+            self.block()
     
     def block(self):
         """Block forever (wait for stop(), KeyboardInterrupt or SystemExit)."""
                 if self.interrupt:
                     raise self.interrupt
         except KeyboardInterrupt:
-            cherrypy.log("<Ctrl-C> hit: shutting down app server", "ENGINE")
+            cherrypy.log("<Ctrl-C> hit: shutting down app engine", "ENGINE")
+            cherrypy.server.stop()
             self.stop()
         except SystemExit:
-            cherrypy.log("SystemExit raised: shutting down app server", "ENGINE")
+            cherrypy.log("SystemExit raised: shutting down app engine", "ENGINE")
+            cherrypy.server.stop()
             self.stop()
             raise
         except:
             # Don't bother logging, since we're going to re-raise.
             self.interrupt = sys.exc_info()[1]
+            # Note that we don't stop the HTTP server here.
             self.stop()
             raise
     
     def stop(self):
-        """Stop the application server engine."""
+        """Stop the application engine."""
         for thread_ident, i in self.seen_threads.iteritems():
             for func in self.on_stop_thread_list:
                 func(i)
         self.seen_threads.clear()
         
-        for func in self.on_stop_server_list:
+        for func in self.on_stop_engine_list:
             func()
         
         self.state = STOPPED
         cherrypy.log("CherryPy shut down", "ENGINE")
     
     def restart(self):
-        """Restart the application server engine."""
+        """Restart the application engine (doesn't block)."""
         self.stop()
-        self.start()
+        self.start(blocking=False)
     
     def wait(self):
         """Block the caller until ready to receive requests (or error)."""
         while not self.ready:
             time.sleep(.1)
             if self.interrupt:
-                msg = "The CherryPy application server errored"
+                msg = "The CherryPy application engine errored"
                 raise cherrypy.NotReady(msg, "ENGINE")
     
     def _is_ready(self):
         return bool(self.state == STARTED)
-    ready = property(_is_ready, doc="Return True if the server is ready to"
+    ready = property(_is_ready, doc="Return True if the engine is ready to"
                                     " receive requests, False otherwise.")
     
-    def request(self, clientAddress, remote_host, scheme="http"):
+    def request(self, client_address, remote_host, scheme="http"):
         """Obtain an HTTP Request object.
         
-        clientAddress: the (IP address, port) of the client
+        client_address: the (IP address, port) of the client
         remote_host: the IP address of the client
         scheme: either "http" or "https"; defaults to "http"
         """
         if self.state == STOPPED:
-            raise cherrypy.NotReady("The CherryPy server has stopped.")
+            raise cherrypy.NotReady("The CherryPy engine has stopped.")
         elif self.state == STARTING:
-            raise cherrypy.NotReady("The CherryPy server could not start.")
+            raise cherrypy.NotReady("The CherryPy engine could not start.")
         
         threadID = threading._get_ident()
         if threadID not in self.seen_threads:
             for func in self.on_start_thread_list:
                 func(i)
         
-        r = self.request_class(clientAddress[0], clientAddress[1],
+        r = self.request_class(client_address[0], client_address[1],
                                remote_host, scheme)
         cherrypy.serving.request = r
         cherrypy.serving.response = self.response_class()
         return r
+    
+    def start_with_callback(self, func, args=None, kwargs=None):
+        """Start, then callback the given func in a new thread."""
+        
+        if args is None:
+            args = ()
+        if kwargs is None:
+            kwargs = {}
+        args = (func,) + args
+        
+        def _callback(func, *a, **kw):
+            self.wait()
+            func(*a, **kw)
+        t = threading.Thread(target=_callback, args=args, kwargs=kwargs)
+        t.setName("CPEngine Callback " + t.getName())
+        t.start()
+        
+        self.start()
 

File _cpserver.py

-"""Create and manage the CherryPy server."""
+"""Manage an HTTP server with CherryPy."""
 
 import threading
 import time
 
 import cherrypy
 from cherrypy.lib import cptools
-from cherrypy._cpengine import Engine, STOPPED, STARTING, STARTED
 
-_missing = object()
 
-
-class Server(Engine):
+class Server(object):
+    """Manager for an HTTP server."""
     
     def __init__(self):
-        Engine.__init__(self)
-        self._is_setup = False
-        self.blocking = True
-        
         self.httpserver = None
+        self.interrupt = None
     
-    def start(self, init_only=False, server_class=_missing, server=None, **kwargs):
-        """Main function. MUST be called from the main thread.
-        
-        Set initOnly to True to keep this function from blocking.
-        Set serverClass and server to None to skip starting any HTTP server.
-        """
-        
+    def start(self, server=None):
+        """Main function. MUST be called from the main thread."""
         conf = cherrypy.config.get
-        
-        if not init_only:
-            init_only = conf('server.init_only', False)
-        
         if server is None:
             server = conf('server.instance', None)
         if server is None:
-            if server_class is _missing:
-                server_class = conf("server.class", _missing)
-            if server_class is _missing:
-                import _cpwsgi
-                server_class = _cpwsgi.WSGIServer
-            elif server_class and isinstance(server_class, basestring):
-                # Dynamically load the class from the given string
-                server_class = cptools.attributes(server_class)
-            if server_class is not None:
-                self.httpserver = server_class()
-        else:
-            if isinstance(server, basestring):
-                server = cptools.attributes(server)
-            self.httpserver = server
+            import _cpwsgi
+            server = _cpwsgi.WSGIServer()
+        if isinstance(server, basestring):
+            server = cptools.attributes(server)()
+        self.httpserver = server
         
-        self.blocking = not init_only
-        Engine.start(self)
-    
-    def _start(self):
-        if not self._is_setup:
-            self.setup()
-            self._is_setup = True
-        Engine._start(self)
-        self.start_http_server()
-        if self.blocking:
-            self.block()
-    
-    def restart(self):
-        """Restart the application server engine."""
-        self.stop()
-        self.state = STARTING
-        self.interrupt = None
-        self._start()
-    
-    def start_http_server(self, blocking=True):
-        """Start the requested HTTP server."""
-        if not self.httpserver:
-            return
-        
-        if cherrypy.config.get('server.socket_port'):
-            host = cherrypy.config.get('server.socket_host')
-            port = cherrypy.config.get('server.socket_port')
-            
+        if conf('server.socket_port'):
+            host = conf('server.socket_host')
+            port = conf('server.socket_port')
             wait_for_free_port(host, port)
-            
             if not host:
                 host = 'localhost'
             on_what = "http://%s:%s/" % (host, port)
         else:
-            on_what = "socket file: %s" % cherrypy.config.get('server.socket_file')
+            on_what = "socket file: %s" % conf('server.socket_file')
         
         # HTTP servers MUST be started in a new thread, so that the
         # main thread persists to receive KeyboardInterrupt's. If an
-        # exception is raised in the http server's main thread then it's
-        # trapped here, and the CherryPy app server is shut down (via
-        # self.interrupt).
+        # exception is raised in the http server's thread then it's
+        # trapped here, and the http server and engine are shut down.
         def _start_http():
             try:
                 self.httpserver.start()
             except KeyboardInterrupt, exc:
+                cherrypy.log("<Ctrl-C> hit: shutting down HTTP server", "SERVER")
                 self.interrupt = exc
                 self.stop()
+                cherrypy.engine.stop()
             except SystemExit, exc:
+                cherrypy.log("SystemExit raised: shutting down HTTP server", "SERVER")
                 self.interrupt = exc
                 self.stop()
+                cherrypy.engine.stop()
                 raise
         t = threading.Thread(target=_start_http)
         t.setName("CPHTTPServer " + t.getName())
         t.start()
         
-        if blocking:
-            self.wait_for_http_ready()
-        
+        self.wait()
         cherrypy.log("Serving HTTP on %s" % on_what, 'HTTP')
     
     def wait(self):
-        """Block the caller until ready to receive requests (or error)."""
-        Engine.wait(self)
-        self.wait_for_http_ready()
-    
-    def wait_for_http_ready(self):
-        if self.httpserver:
-            while (not getattr(self.httpserver, "ready", True)
-                   and not self.interrupt
-                   and self.state != STOPPED):
-                time.sleep(.1)
+        """Wait until the HTTP server is ready to receive requests."""
+        while (not getattr(self.httpserver, "ready", True)
+               and not self.interrupt):
+            time.sleep(.1)
+        
+        # Wait for port to be occupied
+        if cherrypy.config.get('server.socket_port'):
+            host = cherrypy.config.get('server.socket_host')
+            port = cherrypy.config.get('server.socket_port')
+            if not host:
+                host = 'localhost'
             
-            # Wait for port to be occupied
-            if cherrypy.config.get('server.socket_port'):
-                host = cherrypy.config.get('server.socket_host')
-                port = cherrypy.config.get('server.socket_port')
-                if not host:
-                    host = 'localhost'
-                
-                for trial in xrange(50):
-                    if self.interrupt:
-                        break
-                    try:
-                        check_port(host, port)
-                    except IOError:
-                        break
-                    else:
-                        time.sleep(.1)
+            for trial in xrange(50):
+                if self.interrupt:
+                    break
+                try:
+                    check_port(host, port)
+                except IOError:
+                    break
                 else:
-                    cherrypy.log("Port %s not bound on %s" %
-                                 (repr(port), repr(host)), 'HTTP')
-                    raise cherrypy.NotReady("Port not bound.")
+                    time.sleep(.1)
+            else:
+                cherrypy.log("Port %s not bound on %s" %
+                             (repr(port), repr(host)), 'HTTP')
+                raise cherrypy.NotReady("Port not bound.")
     
     def stop(self):
-        """Stop, including any HTTP servers."""
-        self.stop_http_server()
-        Engine.stop(self)
-    
-    def stop_http_server(self):
         """Stop the HTTP server."""
         try:
             httpstop = self.httpserver.stop
             httpstop()
             cherrypy.log("HTTP Server shut down", "HTTP")
     
-    def start_with_callback(self, func, args=None, kwargs=None,
-                            server_class = _missing, serverClass = None):
-        """Start, then callback the given func in a new thread."""
-        
-        if args is None:
-            args = ()
-        if kwargs is None:
-            kwargs = {}
-        args = (func,) + args
-        
-        def _callback(func, *args, **kwargs):
-            self.wait()
-            func(*args, **kwargs)
-        t = threading.Thread(target=_callback, args=args, kwargs=kwargs)
-        t.setName("CPServer Callback " + t.getName())
-        t.start()
-        
-        self.start(server_class = server_class)
+    def restart(self):
+        """Restart the HTTP server."""
+        self.stop()
+        self.interrupt = None
+        self.start()
 
 
 def check_port(host, port):
         # Both IIS and Apache set REMOTE_USER, when possible.
         env = environ.get
         clientAddr = (env('REMOTE_ADDR', ''), int(env('REMOTE_PORT', -1)))
-        request = cherrypy.server.request(clientAddr, env('REMOTE_ADDR', ''),
+        request = cherrypy.engine.request(clientAddr, env('REMOTE_ADDR', ''),
                                           environ['wsgi.url_scheme'])
         request.login = (env('LOGON_USER') or env('REMOTE_USER') or None)
         request.multithread = environ['wsgi.multithread']

File lib/covercp.py

                             'server.environment': "production",
                             })
     cherrypy.server.start()
+    cherrypy.engine.start()
 
 if __name__ == "__main__":
     serve(*tuple(sys.argv[1:]))

File lib/profiler.py

                             'session.storageType': "ram",
                             })
     cherrypy.server.start()
+    cherrypy.engine.start()
 
 
 if __name__ == "__main__":

File test/benchmark.py

 
 started = False
 def startup(req=None):
-    """Start the CherryPy app server in 'serverless' mode (for WSGI)."""
+    """Start the CherryPy app engine with no server (for WSGI)."""
     global started
     if not started:
         started = True
-        cherrypy.server.start(init_only=True, server_class=None)
+        cherrypy.engine.start(blocking=False)
     return 0 # apache.OK
 
 
         if ab_opt:
             global AB_PATH
             AB_PATH = ab_opt
-        cherrypy.server.start(init_only=True, server_class=None)
+        cherrypy.engine.start(blocking=False)
     
     import modpython_gateway
     return modpython_gateway.handler(req)
             cherrypy.server.request_class = NullRequest
             cherrypy.server.response_class = NullResponse
         
+        cherrypy.server.start()
         # This will block
-        cherrypy.server.start_with_callback(run)
+        cherrypy.engine.start_with_callback(run)

File test/helper.py

     of test modules. The config, however, is reset for each module.
     """
     setConfig(conf)
-    cherrypy.server.start_with_callback(_run_test_suite_thread,
-                                        args = (moduleNames, conf),
-                                        server_class = server)
+    cherrypy.server.start(server)
+    cherrypy.engine.start_with_callback(_run_test_suite_thread,
+                                        args=(moduleNames, conf))
 
 def _run_test_suite_thread(moduleNames, conf):
     for testmod in moduleNames:
         conf = {}
     setConfig(conf)
     try:
-        cherrypy.server.start_with_callback(_test_main_thread, *args, **kwargs)
+        cherrypy.server.start()
+        cherrypy.engine.start_with_callback(_test_main_thread, *args, **kwargs)
     except KeyboardInterrupt:
         cherrypy.server.stop()
+        cherrypy.engine.stop()
 
 def _test_main_thread():
     try:

File test/modpy.py

             "server.environment": "production",
             })
         m.setup_server()
-        cherrypy.server.start(init_only=True, server_class=None, server=None)
+        cherrypy.engine.start(blocking=False)
     from mod_python import apache
     return apache.OK
 

File test/test_noserver.py

 cherrypy.root.test = HelloWorld()
 
 cherrypy.config.update({"server.environment": "production"})
-cherrypy.server.start(server_class = None)
+cherrypy.engine.start()
 

File test/test_session_concurrency.py

     data_dict[index] = int(data)
 
 # Start server
-thread.start_new_thread(cherrypy.server.start, ())
+cherrypy.server.start()
+thread.start_new_thread(cherrypy.engine.start, ())
 
 # Start client
 time.sleep(2)
     time.sleep(1)
 
 cherrypy.server.stop()
+cherrypy.engine.stop()
 
 m = max(data_dict.values())
 expected_m = 1 + (client_thread_count * request_count)

File test/test_states.py

     ctrlc.exposed = True
     
     def restart(self):
-        cherrypy.server.restart()
+        cherrypy.engine.restart()
         return "app was restarted succesfully"
     restart.exposed = True
 
     
     def test_0_NormalStateFlow(self):
         if not self.server_class:
-            # Without having called "cherrypy.server.start()", we should
+            # Without having called "cherrypy.engine.start()", we should
             # get a NotReady error
             self.assertRaises(cherrypy.NotReady, self.getPage, "/")
         
         self.assertEqual(len(db_connection.threads), 0)
         
         # Test server start
-        cherrypy.server.start(True, self.server_class)
-        self.assertEqual(cherrypy.server.state, 1)
+        cherrypy.server.start(self.server_class)
+        cherrypy.engine.start(blocking=False)
+        self.assertEqual(cherrypy.engine.state, 1)
         
         if self.server_class:
             host = cherrypy.config.get('server.socket_host')
         self.assertBody("Hello World")
         self.assertEqual(len(db_connection.threads), 1)
         
-        # Test server stop
-        cherrypy.server.stop()
-        self.assertEqual(cherrypy.server.state, 0)
+        # Test engine stop
+        cherrypy.engine.stop()
+        self.assertEqual(cherrypy.engine.state, 0)
         
-        # Verify that the on_stop_server function was called
+        # Verify that the on_stop_engine function was called
         self.assertEqual(db_connection.running, False)
         self.assertEqual(len(db_connection.threads), 0)
         
         def stoptest():
             self.getPage("/")
             self.assertBody("Hello World")
-            cherrypy.server.stop()
-        cherrypy.server.start_with_callback(stoptest, server_class=self.server_class)
-        self.assertEqual(cherrypy.server.state, 0)
+            cherrypy.engine.stop()
+        cherrypy.engine.start_with_callback(stoptest)
+        self.assertEqual(cherrypy.engine.state, 0)
+        cherrypy.server.stop()
     
     def test_1_Restart(self):
-        cherrypy.server.start(True, self.server_class)
+        cherrypy.server.start(self.server_class)
+        cherrypy.engine.start(blocking=False)
         
         # The db_connection should be running now
         self.assertEqual(db_connection.running, True)
         self.assertEqual(len(db_connection.threads), 1)
         
         # Test server restart from this thread
-        cherrypy.server.restart()
-        self.assertEqual(cherrypy.server.state, 1)
+        cherrypy.engine.restart()
+        self.assertEqual(cherrypy.engine.state, 1)
         self.getPage("/")
         self.assertBody("Hello World")
         self.assertEqual(db_connection.running, True)
         
         # Test server restart from inside a page handler
         self.getPage("/restart")
-        self.assertEqual(cherrypy.server.state, 1)
+        self.assertEqual(cherrypy.engine.state, 1)
         self.assertBody("app was restarted succesfully")
         self.assertEqual(db_connection.running, True)
         self.assertEqual(db_connection.startcount, sc + 2)
         # Note that the "/restart" request has been flushed.
         self.assertEqual(len(db_connection.threads), 0)
         
-        cherrypy.server.stop()
-        self.assertEqual(cherrypy.server.state, 0)
+        cherrypy.engine.stop()
+        self.assertEqual(cherrypy.engine.state, 0)
         self.assertEqual(db_connection.running, False)
         self.assertEqual(len(db_connection.threads), 0)
+        cherrypy.server.stop()
     
     def test_2_KeyboardInterrupt(self):
         if self.server_class:
             threading.Thread(target=interrupt).start()
             
             # We must start the server in this, the main thread
-            cherrypy.server.start(False, self.server_class)
+            cherrypy.server.start(self.server_class)
             # Time passes...
-            self.assertEqual(cherrypy.server.state, 0)
             self.assertEqual(db_connection.running, False)
             self.assertEqual(len(db_connection.threads), 0)
             
                 self.assertRaises(BadStatusLine, self.getPage, "/ctrlc")
             threading.Thread(target=interrupt).start()
             
-            cherrypy.server.start(False, self.server_class)
+            cherrypy.server.start(self.server_class)
             # Time passes...
-            self.assertEqual(cherrypy.server.state, 0)
             self.assertEqual(db_connection.running, False)
             self.assertEqual(len(db_connection.threads), 0)
 
     try:
         global db_connection
         db_connection = Dependency()
-        cherrypy.server.on_start_server_list.append(db_connection.start)
-        cherrypy.server.on_stop_server_list.append(db_connection.stop)
-        cherrypy.server.on_start_thread_list.append(db_connection.startthread)
-        cherrypy.server.on_stop_thread_list.append(db_connection.stopthread)
+        cherrypy.engine.on_start_engine_list.append(db_connection.start)
+        cherrypy.engine.on_stop_engine_list.append(db_connection.stop)
+        cherrypy.engine.on_start_thread_list.append(db_connection.startthread)
+        cherrypy.engine.on_stop_thread_list.append(db_connection.stopthread)
         
         helper.CPTestRunner.run(suite)
     finally:
         cherrypy.server.stop()
+        cherrypy.engine.stop()
 
 
 def run_all(host, port):

File tutorial/bonus-sqlobject.py

 
 cherrypy.root = ContactManager()
 cherrypy.server.start()
+cherrypy.engine.start()

File tutorial/tut01_helloworld.py

     cherrypy.config.update(file = 'tutorial.conf')
     # Start the CherryPy server.
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut02_expose_methods.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut03_get_and_post.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()

File tutorial/tut04_complex_site.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut05_derived_objects.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut06_default_method.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut07_sessions.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut08_generators_and_yield.py

 if __name__ == '__main__':
     cherrypy.config.update(file = 'tutorial.conf')
     cherrypy.server.start()
+    cherrypy.engine.start()
 

File tutorial/tut09_files.py

     cherrypy.config.update(file = 'tutorial.conf')
     # Start the CherryPy server.
     cherrypy.server.start()
+    cherrypy.engine.start()

File tutorial/tut10_http_errors.py

     cherrypy.config.update(file = 'tutorial.conf')
     # Start the CherryPy server.
     cherrypy.server.start()
+    cherrypy.engine.start()

File tutorial/tutorial.conf

 server.socket_port = 8080
 server.thread_pool = 10
 server.environment = "production"
-# server.showTracebacks = True
-# server.logToScreen = False
+# server.show_tracebacks = True
+server.log_to_screen = True