On May 22, 2007, at 11:07 PM, Alberto Valverde wrote:
>
>
> On May 21, 2007, at 10:53 PM, Ian Charnas wrote:
>
>>
>> So are we still on for a TurboGears sprint this upcoming saturday?
>> How do we do this? Do we all jump on IRC at a certain time and
>> decide
>> what to do?
>
> It'll be probably be good to open up a page in the docs.tg.org wiki
> to make some planning...
>
> I'll be in to work on a new test infrastructure to eventually port
> all failing controller tests to put TG back in the "green" zone. The
> other big task needing work is poring the config module to CP3's new
> config system . Some coordination between my work and the "config
> team" is needed since a pre-requisite to my part is to have a TG app
> nicely wrapped in a WSGI app (possibly with a paste.app_factory entry-
> point implemented) since I'm planning to use paste fixture for the
> testing.
>
> Some notes + brainstorming:
>
> CP3 uses the Application object to create the mentioned WSGI app
> which receives the app's config as a constructor's parameter so we'll
> have to agree on how we create initialize this object. Maybe
> something like this:
>
> - add a new wsgiapp.py module inside quickstarted apps which
> implements the paste.app_factory entrypoint to return a TG/CP3 app.
> This module uses some helper functions inside TG's startup.py (or
> even a TGWSGIApp Application subclass) to initialize and stack TG's
> specific middleware (none ATM, expect EvalException, but we need to
> leave room for future growth).
>
> - This entrypoint could be called by PasteScript's paster passing a
> paste.deploy config file which would override config parameters
> defined in well knownt app.cfg et al. tg-admin should grow a new
> "serve" commad (which delegates to paster serve) which loads a TG app
> with no paste.deploy config and mounts it at /. This new "serve "
> commands deprecates good 'ol start-myapp.py (which can be left as a
> backwards compatibility artifact which simply delegates to tg-admin
> serve).
>
> A quick mental topological sort leaves tasks in this way:
>
> 1) wrap TG apps with CP3's Application object
> 1.5) (at this point I can start migrating the testing framework)
> 2) this Application object receives an app config dict so... adapt
> current config.py so it can load TG' config and pass it to the
> Application constructor. The "config" team could work on a rewrite of
> the config module so it produces a properly formatted config dict to
> feed to Appliaction)
> 3) implement the paste.app_factory entry point which can receive a
> *possible* paste.deploy config or a dummy one that points to app.cfg
> and returns this WSGI app object. The possible paste.deploy config
> should override values in app.cfg if present.
> 4) implement the tg-admin "serve" command
> 5) glue all this together so "tg-admin serve my.config" launches a TG
> app and start-myapp delegates to this
>
> Sorry for my poor communication of this ideas.... I'm speaking from
> memory and it has been months since other work has displaced this
> task from the foreground of my badly multi-tasking brain ;)
Yesterday I comitted some changes on the trunk implementing these
ideas. Some comments:
- turbogears.config is now a paste.config.DispatchingConfig which
provides conetxtual config for each TG app mounted in the same
process. It preserves the original inteface (update_config, update,
get) plus, being a proxy to a dict, has now other useful methods like
items, __getitem__, __setitem__, etc ("items" will be specially
useful in view.load_engines to dump all available template engine
options to each engines, no need to "cherry-pick" them one by one.
It's structure is something like this:
{"/": {config options for the current app, this key is accessible at
cherrypy.request.config during a request},
"tg_widgets": {tools.staticdir.on: True, tools.staticdir.dir:
"some_dir"},
....}
The preferred method of accessing app configuration is through
turbogears.config which proxies to the dict that was merged with the
apps config at the app factory. cherrypy will use each path's key
when calclating which tools to apply depending on the path.
- The WSGI app is built inside the users app at
myapp.wsgiapp:WSGIApp.app_factory.
This is the paste.app_factory entry point. Most work is done in the
superclass (defined in turbogears.wsgi) but, being the final subclass
available inside the users app it allows for easy customization, eg:
* __call__ can be overriden to execute per-request actions, branch to
other wsgi apps, etc... This function has the WSGI app signature
(environ, start_response) so the full flexibility of WSGI is
available at this point.
* app_factory can be extended to further wrap the app in middleware
between the resuting TG app (and all its middleware) and the server
def app_factory(self, global_conf, root=None, full_stack=None,
**app_conf):
app = super(...).app_factory(....)
app = MyMiddleWare(app, ...)
.....
return app
Note that middleware stacked here will be outside TG's context
* __init__ can be overriden to stack middleware below the TG app.
This middleware will be inside the context of the TG app:
def __init__(self, root=None):
super(....).__init__(root)
self.wsgiapp = MyMiddleware(self.wsgiapp, ....)
Note that this middleware can also be declared in the CP3 config file
- There are some architectural changes needed to allow for multiple
apps per process:
* We're making heavy use of module globals for customization
(view.variable_providers, view.loadBases, scheduler, database.engine,
etc...) This should be modified because these globals will be shared
by all instances of TG apps used in the same process, extension
authors should pay special attention to this...
The solution I've comed up with is to provide a proxy at
turbogears.globals which proxies to app.globals (a globals object
bound to the WSGI app that wraps the root controller). This way all
these globals will be in the context of the WSGI app that configured
them during a request. I've implemented view.engines this way (so
each app can have it's own kid.defaultoutput, etc...) but others
still need to be ported/rewritten (database.engine, scheduler, etc)
- Since the app_factory ep is implemented, paster can already be used
to launch a TG app. I've made the changes needed to the quickstarted
template so you can try it out like this:
$ paster serve depoly_cfg.ini
Which should have the same effect as calling start-myapp.py (I've
rewritten start_turbogears so 1.0 startup scripts remain compatible).
start-myapp.py should be deprecated so all apps are loaded using the
paste.deploy API. Since the minimal deploy ini config file is so
simple, "tg-admin serve" could emulate what it does when no
deployment config is specified, so when you run "tg-admin serve"
inside a projects egg it should start up the app automatically. If a
deployment config is passed as a parameter, it should use that
instead. Some cool things you can already do with this:
[DEFAULT]
[server:main]
use= egg:PasteScript#cherrypy
host = 0.0.0.0
port = 8080
[composite:main]
use = egg:Paste#urlmap
/ = app1
/app2 = app2
[app:app1]
use = egg:TestApp
app_id = app1
tg.config_file = %(here)s/dev.cfg
[app:app2]
use = egg:TestApp
tg.config_file = %(here)s/dev.cfg
app_id = app2
kid.encoding = iso-8859-1
kid.outputformat= xhtml
This will mount the same TG app at / and /app2 but with different
configuration settings (they could even use different dev.cfg and
dev2.cfg) and serve it with CP3's wsgi server (swap it with Paste's
if you feel inclined to for didactical purposes)
Please note that multiple apps per process is still broken since we
use so many module globals. I haven't tested it yet but, for example,
I believe both apps would share the same db engine... this needs to
be sorted out.
Some low hanging fruit we need need to address:
* rewrite view.load_engines so it all template plugin confg options
can be used. Maybe even replace the whole view module and implement
it as a class we can instantiate and bind to turbogears.globals so
each app has it's own configured set of engines. This is implemented
in TW as the EngineManager... maybe we can take ideas from there, or,
better still, factor it out into an independent egg both TW and TG
can share.
* Move the scheduler to turbogears.globals, so each app has it's own
scheduler
* Ditto with database.engine
* more I'm failing to recall....
Some more complex stuff:
* Move all module globals: view.variable_providers,
turbogears.call_on_startup, etc so they're bound to each app. This
will require a change to the extensions API to work properly,
however, a proxy can be left at the original location for backwards
compatibility. This allows for a smooth degradation: non conforming
extension will still work in a single app per process scenario, but
will break when multiple TG apps cohabitate the same process.... this
will put some pressure on extension authors to upgrade them ;)
* Write the new testutils using paste fixture to port all TG
controller tests.
* more I'm failing to recall....
Well, gotta run now... comments welcomed :)
Alberto
PS: Looks like Saturday's sprint is going to be lots of fun! :)
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"TurboGears Trunk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/turbogears-trunk?hl=en
-~----------~----~----~----~------~----~------~--~---