More discussion to follow. I just spent a man-year of work making CP 3
do all this and more and be beautiful at the same time, and I'll be
damned if I let TG devolve back to preferring the ugliness of bare WSGI
and Paste.
Robert Brewer
System Architect
Amor Ministries
fuma...@amor.org
Mmm... strong words.
I don't think anyone is suggesting bare WSGI and Paste for TurboGears.
This isn't how WSGI or Paste is intended to be used.
Comparisons are perhaps a little difficult here, because the layers
don't match up quite right:
Paste
CherryPy
Pylons
TurboGears
That is, CherryPy works on a higher level than Paste, in places closer
to a "real" framework like Pylons; similarly, TurboGears works on a
level that includes a lot more functionality than Pylons. Paste and
CherryPy are not addressing equivalent sets of features. And many of
the things that TG 2.0 is looking for are quite possibly better drawn
from Pylons than Paste -- in that there's ideas in Paste that are
(intentionally) only half-baked, and Pylons more fully exposes them in a
way that could also make sense for TurboGears.
And further, Paste itself is factored into three distinct pieces, most
of which CherryPy includes in its one package; TG is free to cherrypick
(sorry, pun not intended) from Paste's offerings:
* Paste Deploy, the configuration system
* Paste core, the WSGI tools
* Paste Script, the app server (also a file layout generator and other
stuff)
The app server in Paste Script is merely there because I needed
something, I'm not going to argue that it's a wonderful app server; I
think CherryPy's is largely in the same position. The file layout stuff
and other tools in Paste Script don't have equivalents in CherryPy, so
there's no comparison to be made there.
So there's Paste Deploy (the configuration system) and Paste core (a
bunch of WSGI tools).
If TurboGears uses Paste core's WSGI tools or not, it really doesn't
much matter to me. There's lots of useful pieces in there, and I'm
happy to point them out, but you could copy and rename those and tweak
them as you wish and it would be perfectly fine. There's nothing
singular about the implementations in Paste. The argument there is
really about a framework that uses WSGI internally, and one that does
not. Not everything should be squeezed into WSGI -- certainly I've seen
things that seem odd or wrong to me (e.g., wsgiform). It would probably
be easier to debate specific places -- e.g., what is the advantage of
CP's request object over a request object that purely wraps a WSGI
environment (like paste.wsgiwrappers.WSGIRequest)? Or, what is the
advantage of writing authentication using a CherryPy-specific technique
over WSGI middleware?
Configuration is the other big issue. The core of Paste Deploy is
really an interface, not a specific configuration file format. You
could quite reasonably create another config file format, or load
configs from a database or whatever, if you access the same interface
that Paste Deploy accesses.
There's three interfaces that Paste Deploy defines:
paste.app_factory: (global_conf, **local_conf)
paste.filter_app_factory: (app, global_conf, **local_conf)
paste.composite_factory: (loader, global_conf, **local_conf)
All three of these return a WSGI application. "app" is the wrapped WSGI
application. "loader" is an object that can load other apps by name
(used for dispatchers that dispatch to multiple applications).
global_conf is the "inherited" configuration -- configuration that
wasn't specifically intended for this component, but which might provide
useful advise. E.g., you might look for a "debug" global value.
Looking for a global "document_root" value probably isn't very
meaningful, so you are not forced to respect the values in global_conf,
nor are they automatically folded together.
local_conf is restricted, in that the values can all be strings, and
strings should be specially handled. Thus the string 'false' shouldn't
be interpreted as true in a boolean context. It is up to the
application to coerce the values as necessary; no validation of any kind
is part of the interface, except for function signatures.
These three interfaces are how everything is set up in Paste Deploy.
These application/middleware factories are really what defines a "Paste"
application, I suppose -- that is, a configurable object that produces
WSGI applications. You can define these interfaces for code without
including any part of Paste. It is probably possible to provide these
interfaces right now with CherryPy as the application factory (maybe
using something like paste.registry to swap configs if that is indeed a
problem).
It should be noted that configuration is not process-wide in Paste; it
is local to the object returned by the factory. The same application
can be instantiated twice with different configurations, and should
respond properly. It doesn't *have* to of course -- though if it can't,
it should probably raise an exception the second time it is invoked. If
this really is required I'd consider the app/framework to have
"middling" WSGI support, rather than "good" WSGI support (this has long
been a problem with Django, for instance, which has lots of global
process-wide configuration).
Personally I find Paste Deploy's actual configuration to be workable,
but I can certainly imagine other ways to approach the problem. I
believe the interfaces are sufficiently generic that it is possible to
build other configuration systems or other ways to define a website
layout. You can rely on the interfaces Paste Deploy uses to not change,
and as you can see there's no direct bindings to the configuration file
format.
I'm not sure how to compare this to CherryPy's configuration, as I don't
really know what the most core or essential part of CherryPy's
configuration is. Perhaps you could shed light on that.
--
Ian Bicking | ia...@colorstudy.com | http://blog.ianbicking.org
fumanchu wrote:
> More discussion to follow. I just spent a man-year of work making CP 3
> do all this and more and be beautiful at the same time, and I'll be
> damned if I let TG devolve back to preferring the ugliness of bare
> WSGI
> and Paste.
First of all I'd like to say that CP3 does really looks beautiful and
that it's wsgiserver is really good. Whatever TG 2.0 becomes it will
surely use it's server by default.
As I've mentioned, the only problem I've seen when experimenting with
it is how it handles module globals because of the way I'd like to
build the WSGI stack for the application. I know that CherryPy can
already build a tree composed of CP and wsgi apps, however, from what
I've seen (I hope I'm wrong but I believe I'm not) it seems to me
that CherryPy wants to be the only one building the stack.
What I mean with this is that by the way I've seen a CP app is
mounted and the server started, the whole tree is built by CP
mechanisms, mounted under a given prefix and served. This is what
the quickstart function looks like:
def quickstart(root, script_name="", config=None):
"""Mount the given app, start the engine and builtin server,
then block."""
if config:
cherrypy.config.update(config)
cherrypy.tree.mount(root, script_name, config)
cherrypy.server.quickstart()
cherrypy.engine.start()
CP and wsgi apps are mounted or grafted into a global cherrypy.tree,
and then a global server and a global engine are started.
However, I'd like to use Paste Deploy for deployment of TG apps. This
is for many reasons, most importantly:
* it looks like it's powerful enough for our needs (composing apps,
applying filters, configuring a server (even CP), etc...) I know CP3
can already do this, but, read on...
* It's not tied to any particular framework. Pylons is using it and
it looks like any wsgi compliant framework/app could use it too (just
implement it's interface and provide entry points... could even be
done by a user wanting to integrate a non "paste-enabled" wsgi app
into it's workflow).
The last point I believe to be very important because I'd like to see
other framework's apps easy to deploy along TG apps and the opposite
way around too, TG apps being easy to deploy along other frameworks'
apps.
I'd like to stress the fact that this deployment should be easy and
as standardized as possible for the end user too (sysadmins, etc..),
not only developers.
To achieve this it looks obvious to me that we (wsgi frameworks)
shall agree on a "standard", framework-independent interface and
paste deploy's is the only one I know of (is there any other?)
So I began experimenting and I got to this paste.app_factory
implementation for deploying a CP3 app: http://paste.turbogears.org/
paste/769. cputils looks like this: http://paste.turbogears.org/paste/
770.
What I'm trying to achieve with this are self contained CP apps (with
their own tree, config, etc...) which can be mounted by a
paste.URLMap (or any other composite app factory) at *any* point in
the tree.
However, I haven't found easy to isolate each CP app because of the
mentioned use of globals. cherrypy.config is easy to monkey patch to
be app specific. cherrypy.request and reponse too. I know they're
already thread-local, but what if a CP app dispatches (in the same
thread) to a wsgi app that turns out to be another CP app wrapped
into an opaque WSGI app?, would they get app-specific cp globals? To
put it in other words:
_tree = Tree()
# mount stuff
# global tree
cherrypy.tree.graft(_tree, '/foo')
cherrypy.tree.graft(another_app, '/bar')
and a little diagram:
This is merely the default, because most users, especially new ones,
want to deploy a single application. Hence the name "quickstart". If
you want to do more than that, then naturally you must take more manual
control over the mounting and startup process, and CherryPy 3 gives you
LOTS of control over that (which CP 2 did not).
> * It's not tied to any particular framework. Pylons is using it and
> it looks like any wsgi compliant framework/app could use it too (just
> implement it's interface and provide entry points... could even be
> done by a user wanting to integrate a non "paste-enabled" wsgi app
> into it's workflow).
Despite the rhetoric, frameworks are not evil per se; they provide a
common interface to all components and are crucial for performing
expensive operations _once_. WSGI does provide a
lowest-common-denominator interface, but few people want to program to
the WSGI interface all day long. So alternatives (like CherryPy, or
paste.wsgiwrappers) are recommended to make working with WSGI more
pleasant. But there's a vicious circle which accompanies the desire to
"not have a framework":
1. You build your initial offering using middleware from project A.
2. The developers of project A find that parsing headers, params, and
various calculated data is slow, so they cache behind the scenes in
library Z.
3. The holy grail of WSGI middleware is that we should be able to
steal code from lots of different projects, so you add another bit of
WSGI middleware from project B.
4. The developers of project B find that parsing headers, params, and
various calculated data is slow, so they cache behind the scenes in
library Y.
5. As the number of libraries Z, Y, X... increases, the number of
times the same data is parsed rises (increasing CPU time) and ALSO the
number of places it is cached (increasing memory footprint).
6. Turbogears finds this state of affairs unacceptable, and decrees,
"we will only support middleware built with library Z (or no library)".
7. Library Z therefore plays the role of a framework, no matter how
much "proof by repeated assertion" that it is "not a framework" floats
around in its marketing.
Why go through that entire loop when CherryPy is ready now to play the
part of library Z?
> The last point I believe to be very important because I'd like to see
> other framework's apps easy to deploy along TG apps and the opposite
> way around too, TG apps being easy to deploy along other frameworks'
> apps.
>
> I'd like to stress the fact that this deployment should be easy and
> as standardized as possible for the end user too (sysadmins, etc..),
> not only developers.
>
> To achieve this it looks obvious to me that we (wsgi frameworks)
> shall agree on a "standard", framework-independent interface and
> paste deploy's is the only one I know of (is there any other?)
That goal should be addressed on web-sig, I think. Choosing a current
implementation (of any portion of a web stack) and expecting each web
tool to declare it a "standard" has a pretty poor track record in the
world of Python web apps. The WSGI standard, by contrast, was hashed
out on web-sig for quite some time, taking input from all possible
players in that space.
> So I began experimenting and I got to this paste.app_factory
> implementation for deploying a CP3 app: http://paste.turbogears.org/
> paste/769. cputils looks like this: http://paste.turbogears.org/paste/
> 770.
I only get the following for those:
770 HTTP/1.1 500 Internal Server ErrorContent-Type: text/plain
Content-Length: 35
Date: Fri, 05 Jan 2007 23:54:07 GMT
Server: CherryPy/2.2.1
Unrecoverable error in the server.
> What I'm trying to achieve with this are self contained CP apps (with
> their own tree, config, etc...) which can be mounted by a
> paste.URLMap (or any other composite app factory) at *any* point in
> the tree.
Then I haven't communicated the architecture of CherryPy properly. A
"self-contained app" (CP or otherwise) shouldn't have a Tree. The
CherryPy Tree class is WSGI middleware for app dispatch, much like
paste.urlparser.URLResolver. And it can dispatch to CP apps or
arbitrary WSGI apps equally well.
Tree dispatch is separate from the "handler dispatch" that occurs once
we've finished with the WSGI stack and are inside a request object.
> However, I haven't found easy to isolate each CP app because of the
> mentioned use of globals. cherrypy.config is easy to monkey patch to
> be app specific. cherrypy.request and reponse too. I know they're
> already thread-local, but what if a CP app dispatches (in the same
> thread) to a wsgi app that turns out to be another CP app wrapped
> into an opaque WSGI app?
First, I should clarify by repeating that CP _applications_ should not
"dispatch to a wsgi app". A CP Tree instance might, because that's what
it's made for. But a CP3 Application instance is just that: a WSGI
application object and not middleware. There is a wsgiapp Tool in the
distro, but frankly, I don't recommend it--there are much better ways
to compose WSGI components. Most of CherryPy makes web application
development easier, not middleware development. And this is IMO a
proper focus, because the VAST majority of CP users (and TG users) are
going to spend the VAST majority of their time writing web apps, not
WSGI middleware.
> would they get app-specific cp globals? To
> put it in other words:
>
> _tree = Tree()
> # mount stuff
>
> # global tree
> cherrypy.tree.graft(_tree, '/foo')
> cherrypy.tree.graft(another_app, '/bar')
>
> Would CP controllers under _tree see a different cp.config,
> cp.request, cp.response, etc... than those under cp.tree?
Yes, they would. The request and response objects are in a threadlocal;
you get a different one for each request. You even get a different one
when you InternalRedirect, now.
The config is in three parts: global config, app config, and a
"request.config" which is "all the items in the first two that apply to
the current request" in a single dict. The global config is truly
global, but that's as it should be. Anything you don't want to put in
all applications should go in each app's config. This is nothing more
than proper separation.
> This is why some sort of stacked, thread-local proxy is needed.
I agree it needs to be thread-local, but it doesn't need to be
"stacked" unless one *application* (not middleware) truly calls another
*application*, which isn't AFAICT a use-case of the WSGI spec. In
addition, CherryPy's expectation is that WSGI middleware should not use
cherrypy globals, and no CherryPy middleware does.
> So it seems to me that if TG wants to use CP3's engine and use
> paste.deploy's interfaces some patching or monkey-patching is
> needed... I'm really not very comfortable with this sort of monkey-
> patching because we seem to be poking too many CP internals again.
> Experience with 1.0 has taught us that this leads to a hard time if
> we want to migrate to newer CP versions.
I don't think you should use paste.deploy's interfaces. They're not a
standard yet by any stretch of the imagination, and I've written
extensively on why CherryPy's deployment interface is better at
http://www.cherrypy.org/wiki/CherryPyAndPaste.
> TG 2.0 want's to build on independent components which can
> be stolen, adapted or written from scratch and be reused in
> other frameworks/apps so it looks like WSGI middleware is
> a better alternative to CP's tools/hooks because the latter
> can only be used in CP apps.
This is a non-sequitur. Nothing about CP keeps you from *using* WSGI
components from anywhere, whether stolen, adapted or written from
scratch. Please, beg, borrow and steal good code from these sources.
But at the end of the day, middleware cannot implement all
functionality (and I would argue little of the interesting
functionality) for extending the request/response process. So you'll
need some code to allow plugins inside the application itself, after
all the WSGI layers have done their thing. CherryPy is ready, willing,
and able to provide that extension system today. Why reinvent it?
Now, if you want to argue that CP Tools deny you the ability to share
your code with others, that's a different tangent. But IMO that desire
pales in comparison to the desire to have a useful, beautiful, fast web
framework. Not to mention that the vast majority of Tools are short
bits of code and could be ported to uglier middleware versions with a
couple quick greps. I have no problem making those who want to steal MY
code do that work; it's silly to make ME do it (and make my toolset
ugly in the process in order to support it).
> This brings us to a point that we should consider
> what CP3 provides us with. If we don't need config,
> deployment, tools and filters we're left with the
> server and it's dispatching mechanisms which is
> what most TG users are used to and love.
There's something missing from the above list: management. You are
going to end up reinventing the entire set of management layers, like
CherryPy's Server class (which governs the HTTP server, and can now
start/stop/manage multiple HTTP servers), the Engine class (which
governs the OS process) and the Toolbox (which provides a plugin
architecture). You do need Tools in some form, as I've argued above.
You might decide that you want more of CherryPy's builtin tools to be
implemented as middleware, which is fine. Whether you used CP or not,
you'd have to supply those.
But CP already has solid, tested, versions of these features that
already exist, and they are manageable in code, by code, like any good
component-management and plugin architecture. Why reinvent all that? My
guess is that, using a single page of CherryPy 3 code, TG could provide
an admin webapp which allowed a new developer to compose apps,
middleware, and tools into a complete web stack without ever taking the
server down. This is possible because the arrangement of components in
CherryPy 3 is done using objects, not config-file entries (although you
may use config files to declare those objects).
Borrowing the terminology of the
http://en.wikipedia.org/wiki/Capability_Maturity_Model (despite its
weaknesses) may shed some light on what I'm describing here.
Organizational processes, including software projects, can be arranged
in the following rough order:
1 - Initial
2 - Repeatable
3 - Defined
4 - Managed
5 - Optimizing
Turbogears has been moderately successful thus far, but has only
partially reached Level 3. "...standard processes are used to establish
consistency across the organization. Projects establish their defined
processes by the organization's set of standard processes according
to tailoring guidelines." Turbogears is largely in this position (in
the HTTP arena) because of its use of a framework; namely, CherryPy 2.
"At level 3, the standards, process descriptions, and procedures for a
project are tailored from the organization's set of standard
processes to suit a particular project or organizational unit." HTTP
standards for Turbogears 1.0 apps are largely tailored from CherryPy 2.
CherryPy 3 was made to take Turbogears (and ad-hoc users of CP) to
Level 4 and beyond, by providing a layer of management to the
components of the HTTP process. "A critical distinction between
maturity level 3 and maturity level 4 is the predictability of process
performance." Using CherryPy 3 as the basis for TG 2 will provide you
with that predictability. Switching to Paste at this point will take
Turbogears back to Level 1, because performance will be less
predictable, standards go back to being specified per-component, and
the discipline of repeatability is actively discouraged by the "take
code from anywhere" mindset.
> Taken all this into account I believe it's less risky
> to use CP3 server and emulate CP3's dispatching
> rather than heavily monkey-patching CP3's internals.
I put a LOT of work into CherryPy 3 making sure that, at every possible
point where TG has or might monkeypatch CP, there is a beautiful object
or attribute which is designed to be replaced with a subclass or other
delegate to meet your needs. Since Paste provides neither application
management nor application extension tools, TG will have to rewrite
those. Why do so when CherryPy already has proven solutions in this
space?
paste.wsgiwrappers is a way of helping people use the WSGI interface; it
isn't an alternative to that interface. It is very much constrained to
what WSGI allows, and I've gone out of my way to keep it that way.
> But there's a vicious circle which accompanies the desire to
> "not have a framework":
>
> 1. You build your initial offering using middleware from project A.
> 2. The developers of project A find that parsing headers, params, and
> various calculated data is slow, so they cache behind the scenes in
> library Z.
Headers are already parsed. The query string must be parsed, and
possibly the request body. I'm not sure what else really needs to be
parsed.
> 3. The holy grail of WSGI middleware is that we should be able to
> steal code from lots of different projects, so you add another bit of
> WSGI middleware from project B.
> 4. The developers of project B find that parsing headers, params, and
> various calculated data is slow, so they cache behind the scenes in
> library Y.
> 5. As the number of libraries Z, Y, X... increases, the number of
> times the same data is parsed rises (increasing CPU time) and ALSO the
> number of places it is cached (increasing memory footprint).
This seems like you're looking for a problem that does not yet exist,
and may never exist. So long as the results are semantically correct,
the overhead (memory or CPU) that you are referring to is not that
large, and dependent on the software stack.
Nevertheless, I'm already in the progress of addressing this. The ad
hoc solution that Paste has used is described here:
http://wsgi.org/wsgi/Specifications/handling_post_forms -- but I
withdrew that as a specification as I'm working on a library to handle
the case more generally, in HTTPEncode
(http://svn.pythonpaste.org/Paste/HTTPEncode/trunk) and WSGIFilter
(http://svn.pythonpaste.org/Paste/WSGIFilter/trunk). Once I'm more
comfortable with that I'll probably try to write it up as a
specification again.
> 6. Turbogears finds this state of affairs unacceptable, and decrees,
> "we will only support middleware built with library Z (or no library)".
Performance concerns do not require any kind of restriction like that,
they only lead people to advise certain combinations. As long as other
combinations *work*, there's no reason to restrict people's choices. As
long as everyone obeys WSGI (and doesn't try to pass information through
non-WSGI channels) then they *will* work together.
> 7. Library Z therefore plays the role of a framework, no matter how
> much "proof by repeated assertion" that it is "not a framework" floats
> around in its marketing.
It's not a framework, just the basis of a well-performing stack that
TurboGears uses and recommends.
> Why go through that entire loop when CherryPy is ready now to play the
> part of library Z?
CherryPy is ready now to be a library for using WSGI?
>> The last point I believe to be very important because I'd like to see
>> other framework's apps easy to deploy along TG apps and the opposite
>> way around too, TG apps being easy to deploy along other frameworks'
>> apps.
>>
>> I'd like to stress the fact that this deployment should be easy and
>> as standardized as possible for the end user too (sysadmins, etc..),
>> not only developers.
>>
>> To achieve this it looks obvious to me that we (wsgi frameworks)
>> shall agree on a "standard", framework-independent interface and
>> paste deploy's is the only one I know of (is there any other?)
>
> That goal should be addressed on web-sig, I think. Choosing a current
> implementation (of any portion of a web stack) and expecting each web
> tool to declare it a "standard" has a pretty poor track record in the
> world of Python web apps. The WSGI standard, by contrast, was hashed
> out on web-sig for quite some time, taking input from all possible
> players in that space.
I brought up the possibility on Web-SIG of standardizing on something
based on these interfaces, but no one seemed interested in it. Mostly
Luke Arno was the most interested in stuff, and he prefers constructing
stacks in Python so a standard interface didn't mean much to him.
>> However, I haven't found easy to isolate each CP app because of the
>> mentioned use of globals. cherrypy.config is easy to monkey patch to
>> be app specific. cherrypy.request and reponse too. I know they're
>> already thread-local, but what if a CP app dispatches (in the same
>> thread) to a wsgi app that turns out to be another CP app wrapped
>> into an opaque WSGI app?
>
> First, I should clarify by repeating that CP _applications_ should not
> "dispatch to a wsgi app". A CP Tree instance might, because that's what
> it's made for. But a CP3 Application instance is just that: a WSGI
> application object and not middleware. There is a wsgiapp Tool in the
> distro, but frankly, I don't recommend it--there are much better ways
> to compose WSGI components. Most of CherryPy makes web application
> development easier, not middleware development. And this is IMO a
> proper focus, because the VAST majority of CP users (and TG users) are
> going to spend the VAST majority of their time writing web apps, not
> WSGI middleware.
No ceilings! We (the larger programming community) is okay at reusing
libraries and certain patterns, but so far not so good at reusing code
that is more complex, in the case of web frameworks, code that has UI
and multiple screens worth of interacting data.
Mounting a subapplication in your application allows you to create
reusable code on this scale (which is hardly a large scale, but
uncommonly large in current practice). This is the scale of reuse that
TurboGears is struggling to achieve, and what can make TurboGears more
than just Another Nice Framework.
>> This is why some sort of stacked, thread-local proxy is needed.
>
> I agree it needs to be thread-local, but it doesn't need to be
> "stacked" unless one *application* (not middleware) truly calls another
> *application*, which isn't AFAICT a use-case of the WSGI spec. In
> addition, CherryPy's expectation is that WSGI middleware should not use
> cherrypy globals, and no CherryPy middleware does.
It's definitely a use case for the WSGI spec. "Application" is just a
role -- one side of the communication plays the part of server, the
other of application. The labels only apply to that communication.
Applications can forward requests to other applications. Much of the
middleware I find myself writing is both middleware and application --
that is, some but not all requests get forwarded on to another
application, or the dispatch is handled dynamically, or an application
is instantiated based information in the request and then the request is
forwarded to that short-lived application. All these patterns are useful.
>> So it seems to me that if TG wants to use CP3's engine and use
>> paste.deploy's interfaces some patching or monkey-patching is
>> needed... I'm really not very comfortable with this sort of monkey-
>> patching because we seem to be poking too many CP internals again.
>> Experience with 1.0 has taught us that this leads to a hard time if
>> we want to migrate to newer CP versions.
>
> I don't think you should use paste.deploy's interfaces. They're not a
> standard yet by any stretch of the imagination, and I've written
> extensively on why CherryPy's deployment interface is better at
> http://www.cherrypy.org/wiki/CherryPyAndPaste.
I think I'll have to write a full retort to that comparison, because
there's just too much in there to go over it here.
As far as configuration, I'm not really clear on your argument. It
doesn't look substantially different to me, except that the only way to
configure dispatchers in CP (like Paste's URLMap or CP's Tree) is
through ad hoc code.
>> TG 2.0 want's to build on independent components which can
>> be stolen, adapted or written from scratch and be reused in
>> other frameworks/apps so it looks like WSGI middleware is
>> a better alternative to CP's tools/hooks because the latter
>> can only be used in CP apps.
>
> This is a non-sequitur. Nothing about CP keeps you from *using* WSGI
> components from anywhere, whether stolen, adapted or written from
> scratch. Please, beg, borrow and steal good code from these sources.
> But at the end of the day, middleware cannot implement all
> functionality (and I would argue little of the interesting
> functionality) for extending the request/response process. So you'll
> need some code to allow plugins inside the application itself, after
> all the WSGI layers have done their thing. CherryPy is ready, willing,
> and able to provide that extension system today. Why reinvent it?
AFAICT TurboGears has its own heavy use of decorators for some plugins,
normal library code of course, the toolbox and other extensions, and
lots of other stuff. They know their way around plugins.
>> This brings us to a point that we should consider
>> what CP3 provides us with. If we don't need config,
>> deployment, tools and filters we're left with the
>> server and it's dispatching mechanisms which is
>> what most TG users are used to and love.
>
> There's something missing from the above list: management. You are
> going to end up reinventing the entire set of management layers, like
> CherryPy's Server class (which governs the HTTP server, and can now
> start/stop/manage multiple HTTP servers), the Engine class (which
> governs the OS process)
Paste Script has some of this, but I personally find supervisor2 much
more robust so I don't plan to pursue this direction further inside Paste.
> and the Toolbox (which provides a plugin
> architecture). You do need Tools in some form, as I've argued above.
> You might decide that you want more of CherryPy's builtin tools to be
> implemented as middleware, which is fine. Whether you used CP or not,
> you'd have to supply those.
>
> But CP already has solid, tested, versions of these features that
> already exist, and they are manageable in code, by code, like any good
> component-management and plugin architecture. Why reinvent all that? My
> guess is that, using a single page of CherryPy 3 code, TG could provide
> an admin webapp which allowed a new developer to compose apps,
> middleware, and tools into a complete web stack without ever taking the
> server down. This is possible because the arrangement of components in
> CherryPy 3 is done using objects, not config-file entries (although you
> may use config files to declare those objects).
As I've shown, the Paste Deploy interfaces are simple callables, and
entirely manipulable programmatically, in entirely obvious ways.
> I put a LOT of work into CherryPy 3 making sure that, at every possible
> point where TG has or might monkeypatch CP, there is a beautiful object
> or attribute which is designed to be replaced with a subclass or other
> delegate to meet your needs. Since Paste provides neither application
> management nor application extension tools, TG will have to rewrite
> those. Why do so when CherryPy already has proven solutions in this
> space?
I'm not really sure what specific tools you are referring to. Certainly
Paste doesn't include everything; but it has lots of stuff in it, and
there are several complementary packages, and developers using WSGI
tools who would be interested in collaborating with TurboGears
developers. I don't think writing the code is the hard part here, it's
writing the system that's hard. We're very focused on the system, on
the site, on how it all works together -- possibly more focused on that
than on the writing of individual applications.
Yes. Although, more importantly, CherryPy is ready now to be a library
for building web applications. Focusing on WSGI misses the forest for
the trees.
> > First, I should clarify by repeating that CP _applications_ should not
> > "dispatch to a wsgi app". A CP Tree instance might, because that's what
> > it's made for. But a CP3 Application instance is just that: a WSGI
> > application object and not middleware. There is a wsgiapp Tool in the
> > distro, but frankly, I don't recommend it--there are much better ways
> > to compose WSGI components. Most of CherryPy makes web application
> > development easier, not middleware development. And this is IMO a
> > proper focus, because the VAST majority of CP users (and TG users) are
> > going to spend the VAST majority of their time writing web apps, not
> > WSGI middleware.
>
> No ceilings! We (the larger programming community) is okay at reusing
> libraries and certain patterns, but so far not so good at reusing code
> that is more complex, in the case of web frameworks, code that has UI
> and multiple screens worth of interacting data.
>
> Mounting a subapplication in your application allows you to create
> reusable code on this scale (which is hardly a large scale, but
> uncommonly large in current practice). This is the scale of reuse that
> TurboGears is struggling to achieve, and what can make TurboGears more
> than just Another Nice Framework.
Sure; and WSGI middleware is a good place to arrange this mounting,
which is why CherryPy 3 not only allows, but actively encourages and
makes easier the composition of a WSGI stack. CherryPy's Server class
is just as good for managing someone else's HTTP server; CherryPy's
Tree class is just as good for mounting other people's WSGI components,
and you may even decide one of those "subapplications" should be a
CherryPy Application.
> >> This is why some sort of stacked, thread-local proxy is needed.
> >
> > I agree it needs to be thread-local, but it doesn't need to be
> > "stacked" unless one *application* (not middleware) truly calls another
> > *application*, which isn't AFAICT a use-case of the WSGI spec. In
> > addition, CherryPy's expectation is that WSGI middleware should not use
> > cherrypy globals, and no CherryPy middleware does.
>
> It's definitely a use case for the WSGI spec. "Application" is just a
> role -- one side of the communication plays the part of server, the
> other of application. The labels only apply to that communication.
> Applications can forward requests to other applications. Much of the
> middleware I find myself writing is both middleware and application --
Much? If you're using the term "application" as a "role" then I think
you mean "ALL middleware I find myself writing is both middleware and
application". The mixing of terminology is getting a bit thick. Let me
restate my comment adopting another term from the spec: "pure"
servers/gateways and applications/frameworks (as opposed to middleware,
which plays both sides):
First, I should clarify by repeating that CP _applications_
should not "dispatch to a wsgi app". CP Application objects
are always "pure" WSGI applications. A CP Tree instance
might dispatch, because that's what it's made for; it's middleware.
But a CP3 Application instance is just that: a "pure" WSGI
application object and not middleware. There is a wsgiapp
Tool in the distro, but frankly, I don't recommend it--there
are much better ways to compose a WSGI stack. Most of
CherryPy makes "pure" web application development easier,
not middleware development. And this is IMO a proper focus,
because the VAST majority of CP users (and TG users) are
going to spend the VAST majority of their time writing code on
the far side of a "pure" WSGI application interface, not WSGI
middleware.
> This is why some sort of stacked, thread-local proxy is needed.
I agree it needs to be thread-local, but it doesn't need to
be "stacked" unless one "pure" application (not middleware)
truly calls another "pure" application, which isn't AFAICT a
use-case of the WSGI spec. CherryPy's expectation is that
WSGI middleware should not use cherrypy globals, and no
CherryPy middleware does.
Ian Bicking also wrote:
> that is, some but not all requests get forwarded on to another
> application, or the dispatch is handled dynamically, or an application
> is instantiated based information in the request and then the request is
> forwarded to that short-lived application. All these patterns are useful.
No argument there; this is in fact the best use of
middleware--dynamically choosing which WSGI call point to call next.
This is the essence of a WSGI dispatcher, for example, which uses
SCRIPT_NAME + PATH_INFO to make that choice.