Closed ojob closed 4 years ago
Note: seems related to https://github.com/bottlepy/bottle/issues/603#issuecomment-38384072, and is closer to https://github.com/bottlepy/bottle/issues/603#issuecomment-38903401.
However, having a function returning all entry points functions (like proposed in second link juste above) is kinda akward in resulting code, when many entry points are to be created.
You should not subclass bottle.Bottle
, unless you want to change its behaviour. It is not designed to work as a base class for applications. You can programmatically add routes to a bottle instance, so implementing your own application base class (with a fancy meta-class that magically injects a specialized @route
implementation into the local namespace during class declaration) is the way to go. No need to change bottle.Bottle
for that.
There are some attempts to implement such a base class (or other ways to create bottle apps) around, if you look for them. The reusability-pattern I have seen the most is to just create the application within a function:
def create_app(**settings):
app = bottle.Bottle()
...
return app
A base-class could add a lot of metaclass-magic to the mix, for example, inject specialized decorators to be used at declatarion-time or make sure the final class is callable. But I'm not sure if that really helps. Explicit is better than implicit, after all.
Well, I did look for them, as already indicated in the initial description. I found them quirky, hence my proposal for supporting subclassing.
Thanks for your answer, I'll keep my code for me then :) Have a nice day
Having used an example similar to what @defnull pointed out in production projects over 4 year, in my humble opinion the most elegant and / or uniform way is to use a factory function that returns a configured bottle.Bottle instance. Some of the most common operations during this configuration - so that it useful for other use cases - include the following step below
def create_app(**configuration):
app = bottle.Bottle()
# register custom URL filters. (I.E a custom uuid for creating @get('/<id:uuid>'))
# install plugins for Bottle instance
# bind hooks
# Replace / Patch bottle defaults (I.E i replace default bottle jsonDecoder with OrJSON that
# supports Dataclasses, datetimes etc
# bind HTTP Error handlers
return app
A generic implementation of this factory, plus ready utils for plugins, filters, hooks could be useful to others.
@defnull, what would be a simple and recommended way to create a class for an application? (which builds the Bottle object and starts it)
Here is an old question about this: Bottle framework and OOP, using method instead of function, I would be interested about the "canonical way", blessed by the creator of the library :)
I was thinking about something like:
import bottle
class App:
def __init__(self, port=80):
self.app = bottle.Bottle()
self.port = port
def setup_routes(self):
@self.app.route("/foo")
def foo():
return("foo")
@self.app.route("/bar")
def bar():
return("bar")
def start(self):
self.app.run(port=self.port)
a = App()
a.setup_routes()
a.start()
PS: I noted the fact that it's not a good idea to subclass bottle.Bottle
(in your previous comment).
Currently in bottle, the
@route
decorator is aBottle
instance attribute, making it harder to subclass, as following code will not work, as not syntaxically correct:So, considering some different options, and trying not to go down the bottleCBV route that seems quite weird to me, I setup a workaround in a personal project (see here), which sums up as follows:
With just this, we can now subclass in a lean way:
I'd be happy to propose a Pull Request to integrate this, what do you think about this?
Some comments and thoughts:
@route
module decorator may use different attribute names, and could also consider a list of acceptable methods. Hooks shall also be considered, I've worked around this already;set_routes
method tobottle.Bottle
class directly.