Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Ticket #813 (closed enhancement: invalid)

Opened 13 years ago

Last modified 12 years ago

Alternative Controller Tree

Reported by: Claudio Martínez <martinezc@…> Owned by: anonymous
Priority: lowest Milestone: 0.8
Component: TurboGears Version: 0.9a6
Severity: trivial Keywords:
Cc:

Description

If you quickstart a project with: tg-admin quickstart -t tgbig

You can replace your controllers/__init__.py with:

import os
import stat
import turbogears
# replace yourproject
from yourproject.controllers.root import Root

def import_(module):
    return __import__(module.replace('/', '.'), globals(), locals(), '1')
  
def load_controllers(path='', root=True):
    if not root:
        controller = getattr(import_(path), 'Controller', None)
        if controller:
            base_controller = controller()
        else:
            base_controller = turbogears.controllers.Controller()
    else:
        base_controller = Root
        
    for module in os.listdir(path):
        try:
            st = os.lstat(os.path.join(path, module))
        except os.error:
            continue
            
        if module == '__init__.py': continue
        if root and module == 'root.py': continue
        
        if stat.S_ISDIR(st.st_mode):
            controller = load_controllers(path+'/'+module, False)
        else:
            if not module.endswith('.py'): continue
            else: module = module[:-3]
            controller = import_(path+'/'+module).Controller()
        
        setattr(base_controller, getattr(controller, '__name__', module),
                controller)
        
    return base_controller
# replace yourproject
load_controllers('yourproject/controllers')

This makes the controller tree work in a different way:

  • If you drop a new file inside the controller tree it will be added to the controller tree without needing to modify anything. You still need to restart the server of course.
  • The controller class in the files have to be named Controller
  • Translates the directory structure to the url structure automatically
  • The url portion will be given by the filename, so: controllers/test/foo.py will be  http://localhost:8080/test/foo . (setting __name__ on the controller class overrides it)

A controller directory example:

controllers/__init__.py (here's were we add this stuff)
controllers/root.py (the default one)
controllers/mycontroller.py (extend the root controller)
controllers/test1/__init__.py (index, default, foo, bar)
controllers/test1/other_controller.py (extend just by adding files)
controllers/test2/one.py (you don't even need __init__.py)
controllers/test3/__init__.py (only index)

The contents of every file, except for controllers/__init__.py and controllers/root.py, can be:

import cherrypy
import turbogears
from turbogears import controllers, expose, redirect

class Controller(controllers.Controller):
    @expose()
    def index(self):
        return 'Hello from ' + __name__

If it's not possible already in TG/CP, we could add some path information so every module can know their position in the URL (shouldn't be difficult). Modules could export their controllers urls associated to an immutable name. I'm pretty sure it's possible to eliminate every last bit of url hardcoding adapting this.

Just posting this before doing any hard work, I want to know if I'm not reinventing the wheel. I did need a way to add/remove controllers without modifying other files, works for that.

Change History

comment:1 Changed 13 years ago by max

Hmm, I doubt this is a good idea and I doubt this could ever be accepted because this setup is controversal.

comment:2 Changed 13 years ago by michele

I agree with Max, this methods builds the controller tree implicitly and moreover adds some non-standard (or non python) behaviors like the fact that __init__ is not needed for the package, the controller needs to be named "Controller", it somewhat resembles what Subway was doing and this was rejected.

comment:3 Changed 13 years ago by anonymous

Yeah, I know (implementation aside) that this was the subject of a bike shed argument.

What I needed was a way to import all the modules (controllers) without any modification on the rest of the software, think of it as a plugin system that automatically detects new stuff added

I do believe that this belongs more to a contrib folder than to TG itself.

comment:4 Changed 13 years ago by godoy

  • Status changed from new to closed
  • Resolution set to invalid

I'm closing this. I'm also -1 on this kind of thing for the reasons explained on the bikeshed. So, it's summed up "-3" (me, Michele and Max). Even the author of this ticket (I suppose anonymous above is Claudio) said that it didn't belong directly in TG.

Claudio, I believe there's a wiki page for this, you could complement it with this code.

Note: See TracTickets for help on using tickets.