Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are some best practices for structuring cherrypy apps?

I'm writing a cherrypy app and I was wondering what the best way is for structuring my handlers and code for larger applications?

I realize assignment is simple trough cherrypy.root, but what are some practices for writing the handlers and assigning them?

(Allow me to prove my confusion!) My initial thought is to write a standard handler class that infers a template to run based on the current URL or class/method combination. Then I would assign one instance of that handler multiple times to the path to create pages. I don't see this working however as the recursive references wouldn't work quite right.

So, given the fact that I'm already drawing blanks on how my own source code should look, I'd love some pointers and examples!

Feel free to ask some detailed questions for me to clarify. While there is plenty of cherrypy tutorial material out there, it tends to only scratch the surface.

like image 212
Alexander Trauzzi Avatar asked Apr 18 '10 17:04

Alexander Trauzzi


People also ask

What does CherryPy expose do?

In a nutshell, once CherryPy has found and called an exposed method, it is up to you, as a developer, to provide the tools to implement your application's logic. CherryPy takes the opinion that you, the developer, know best.

Is CherryPy a Web server?

CherryPy can be a web server itself or one can launch it via any WSGI compatible environment. It does not deal with tasks such as templating for output rendering or backend access. The framework is extensible with filters, which are called at defined points in the request/response processing.


2 Answers

CherryPy deliberately doesn't require you to subclass from a framework-provided base class so that you are free to design your own inheritance mechanism, or, more importantly, use none at all. You are certainly free to define your own base class and inherit from it; in this way, you can standardize handler construction and configuration via the __init__ method of your class, and via class-level variables and methods.

However, the preferred approach is different. For most web applications, you don't really want to vary the actual construction logic of your handlers, nor do you care much about class-level variables or methods; instead, you want reusable variables and methods per URI or per subtree of URI's or per site, not per class. You tend to vary one set of handlers from another set more by instance configuration (handler metadata) and instance methods (handler logic). Traditional class-based inheritance can do this, but it's a bit of a blunt instrument for that kind of customization.

CherryPy, therefore, is designed to provide this sort of per-resource-set customization that class-based inheritance doesn't do well. It provides this through 1) the design of its configuration system, which allows you to bind metadata to a single URI, a subtree of URI's, a subtree of handlers, or a whole site with the same syntax (see http://docs.cherrypy.org/dev/intro/concepts/config.html for an overview), and 2) the hooks and tools system, which allows you to bind logic to a single URI, a subtree of URI's, a subtree of handlers, or a whole site. See http://docs.cherrypy.org/dev/intro/concepts/tools.html

So, practically: do use normal attributes on cherrypy.root to build your tree of handlers:

def make_app():
    root = Root()
    root.foo = Foo()
    root.bars = BarCollection()
    return root

However, don't make Root, Foo and Bar inherit from a common base class. Instead, write independent Tools to do things like "infer templates". That is, instead of:

from cherrypy import expose

class Foo(MyAppBase):
    @expose()
    def index(self, a, b, c):
        ...

root.foo = Foo(template='foo.html')

write:

from cherrypy import expose, tools

class Foo(object):
    @tools.render(template='foo.html')
    @expose()
    def index(self, a, b, c):
        ...

root.foo = Foo()

...where 'tools.render' is a CherryPy Tool you have written to look up and apply the given template. This approach will allow you to override the arguments to the Tool in your config file and avoid having to repackage or patch your code:

[/foo/]
tools.render.template = 'foo2.html'
like image 99
fumanchu Avatar answered Sep 23 '22 03:09

fumanchu


This question is wildly subjective - but I'll give it a shot.

  • First of all, always keep database and data code separate to the web code. What I do is have lots of small files with one class each in a DB/ folder which are all joined together into a Base.py file, e.g:

    Web/
        Base.py - The main "base" class, which includes the classes in other 
                  web files, starts the web server in __init__
        Users.py - The class which includes methods generally from "DB/Users.py" 
                   which checks permissions etc before returning (you may 
                   wish to add DB-level security later though)
        ...
    DB/
        Base.py - The main base DB class, includes the other DB classes. Creates 
                  new SQLAlchemy/whatever instances and create database schemas if 
                  they don't etc. May pay to have database-wide methods
                  here to keep creating connections etc in one place if you 
                  decide to change databases later 
        Users.py - The user/password etc DB storage class file
        ...
    Templates/
        (HTML templates go here)
    Static/
        (Static images/CSS/javscript etc go here)
    
    Don't forget the __init__.py in each module directory of course so python can find the modules in subdirectories
  • It doesn't always matter what methods you use for structuring code in my opinion, but be consistent. I write a document up with all my conventions with my justifications for using them and try to follow them up to the point it makes sense to, but as always a foolish consistency is the hobgoblin of small minds, as quoting the python style docs :-)

  • Try to use classes rather than straight functions. It mightn't matter for small projects, but for anything non-trivial things can become difficult. It's my preference to have many files with a specific purpose and only a single class in a single file except where it makes sense to have multiple

  • This one is probably controversial - I usually name my classes Class and just reference it by the module name. I'll give an example of Base.py:
    import Users
    class Base(Users.Class):
        def __init__(self):
            Users.Class.__init__(self)
    
    This helps to reduce problems when other modules reference each other when importing, as from Users import Users will conflict if Users.py has from Base import x so I always reference by module name. This is just a personal preference though, so do what you want :-P

Hopefully you should get an idea from this post though.

like image 44
cryo Avatar answered Sep 24 '22 03:09

cryo