bottlepy / bottle

bottle.py is a fast and simple micro-framework for python web-applications.
http://bottlepy.org/
MIT License
8.4k stars 1.46k forks source link

Improve __repr__ of Route #1261

Closed oz123 closed 3 years ago

oz123 commented 3 years ago

The current improvement really helps when using multiple apps.

When I start such an application I like logging which routes are available, for example one can do:

for r in main_app.routes:
    print(r)

Which previously gave this:

<GET '<:re:(de|us)?\\/?>' <function index at 0x7f750fda9670>>
<GET '/<:re:(de/|us/)?>hello/<name:path>/<_id:int>/' <function _index_with_param at 0x7f750fda9700>>
<GET '/<:re:(de/|us/)?><:re:foo>/' <function _index at 0x7f750fda9820>>
<GET '/<:re:(de/|us/)?><url:path>/' <function main at 0x7f750fda9940>>
<GET '<:re:(de|us)?\\/?>' <function main at 0x7f750fda9940>>
<GET '/admin/login/' <function Auth.get_login_template at 0x7f751061e670>>
<POST '/admin/login/' <function Auth.post_login_template at 0x7f751061e700>>
<GET '/admin/' <function index at 0x7f750fd21940>>
<GET '/editor/' <function editor at 0x7f750f930ca0>>
<POST '/editor/template/' <function template_ at 0x7f750f930dc0>>
<GET '/editor/preview/<name:path>' <function load_tmp_template at 0x7f750f930ee0>>
<POST '/editor/validate-jinja/' <function convert at 0x7f750f937040>>
<GET '/static/front/<filepath:path>' <function app_factory.<locals>.server_static at 0x7f750f937af0>>
<GET '/static/admin/<filepath:path>' <function app_factory.<locals>.server_static at 0x7f750f937c10>>
<GET '/static/editor/<filepath:path>' <function app_factory.<locals>.server_static at 0x7f750f937d30>>

Memory addresses are of very little use (I can only tell which route is which because I mount them to different prefixes (e.g. editor, admin, etc.). This also mathes the directory structure on the file system. However, this is not always the case, some times I mount applications without prefix.

With the current patch I can immidietly tell where a route is coming from:

apps.front.views:index GET <:re:(de|us)?\/?>
apps.front.views:_index_with_param GET /<:re:(de/|us/)?>hello/<name:path>/<_id:int>/
apps.front.views:_index GET /<:re:(de/|us/)?><:re:foo>/
apps.front.views:main GET /<:re:(de/|us/)?><url:path>/
apps.front.views:main GET <:re:(de|us)?\/?>
tiny.auth:get_login_template GET /admin/login/
tiny.auth:post_login_template POST /admin/login/
apps.admin.views:index GET /admin/
apps.editor.views:editor GET /editor/
apps.editor.views:template_ POST /editor/template/
apps.editor.views:load_tmp_template GET /editor/preview/<name:path>
apps.editor.views:convert POST /editor/validate-jinja/
__main__:server_static GET /static/front/<filepath:path>
__main__:server_static GET /static/admin/<filepath:path>
__main__:server_static GET /static/editor/<filepath:path>

I think this little patch might be usefull for others too.

defnull commented 3 years ago

Are you absolutely sure that cb.__module__ and cb.__name__ are always defined, no matter what? How about getattr() with a sensible default?

oz123 commented 3 years ago

I think you are right. If views are created dynamically they might not have __module__. The default is None, so I don't think an exception will be thrown. __name__ is always defined. Would you like me to change something?

defnull commented 3 years ago

I cannot think of a way to create a callable that does not define both attributes, so the change is fine I think.