├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── README.rst ├── docs ├── Makefile ├── conf.py ├── index.rst ├── installation.rst └── plugins.rst ├── flask_debug ├── __init__.py ├── dbg.py ├── security.py └── templates │ └── flask_debug │ ├── base.html │ ├── bootstrap_base.html │ ├── config.html │ └── reflect.html ├── flask_debug_plugins ├── __init__.py └── templates │ └── flask_debug │ └── plugins.html ├── setup.py ├── tests └── test_client.py └── tox.ini /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | env: 3 | - TOXENV=py27 4 | - TOXENV=py33 5 | - TOXENV=bootstrap27 6 | - TOXENV=bootstrap33 7 | install: pip install tox 8 | script: tox 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Marc Brinkmann 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include */templates *.html 2 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Flask-Debug 2 | =========== 3 | 4 | Flask-Debug is an extension for Flask_ that displays various debugging insights 5 | during development. 6 | 7 | .. code-block:: python 8 | 9 | from flask import Flask 10 | from flask_debug import Debug 11 | 12 | app = Flask(__name__) 13 | Debug(app) 14 | app.run(debug=True) 15 | 16 | 17 | It can be manually added but also (using Flask-Appconfig_) be 18 | automatically instantiated only during development and invisible in production. 19 | 20 | Opening http://localhost:5000/_debug will show some information about the 21 | application, such as a list of registered views, url maps or configuration 22 | values. 23 | 24 | See the `documentation `_ for more 25 | details. 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = -n 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask-Bootstrap.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask-Bootstrap.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Flask-Bootstrap" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Flask-Bootstrap" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | project = u'Flask-Debug' 4 | copyright = u'2015, Marc Brinkmann' 5 | version = '0.4.2' 6 | release = '0.4.2.dev1' 7 | 8 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'alabaster'] 9 | source_suffix = '.rst' 10 | master_doc = 'index' 11 | exclude_patterns = ['_build'] 12 | pygments_style = 'monokai' 13 | 14 | 15 | html_theme = 'alabaster' 16 | html_theme_options = { 17 | 'github_user': 'mbr', 18 | 'github_repo': 'flask-debug', 19 | #'description': '', 20 | 'github_banner': True, 21 | 'gratipay_user': 'mbr', 22 | 'github_button': False, 23 | 'show_powered_by': False, 24 | 25 | # required for monokai: 26 | 'pre_bg': '#292429', 27 | } 28 | html_sidebars = { 29 | '**': [ 30 | 'about.html', 31 | 'navigation.html', 32 | 'relations.html', 33 | 'searchbox.html', 34 | 'donate.html', 35 | ] 36 | } 37 | 38 | intersphinx_mapping = {'http://docs.python.org/': None, 39 | 'http://flask.pocoo.org/docs/': None, 40 | } 41 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | Table of contents 4 | ----------------- 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | installation 10 | plugins 11 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installing and instantiating 2 | ============================ 3 | 4 | First, Flask-Debug must be installed from PyPI `_: 6 | 7 | .. code-block:: shell 8 | 9 | $ pip install flask-debug 10 | 11 | 12 | 13 | Flask-AppConfig 14 | --------------- 15 | 16 | `flask-appconfig>=0.10 `_ supports 17 | automatic initialization of Flask-Debug while developing, allowing you to 18 | completely omit it from your own code (and therefore production deployments). 19 | See the Flask-AppConfig docs for details. 20 | 21 | 22 | Security 23 | -------- 24 | 25 | **Never enable ``debug`` on a production server** (the configuration 26 | variable, the extension is safe to use in production, 27 | as it will simply refuse everything when the app is not running with 28 | debugging enabled). This is Flask basic practice (see 29 | http://flask.pocoo.org/docs/quickstart/#debug-mode). Flask-Debug tries to 30 | prevent security disasters if you forget to disable debugging in production, 31 | but please, don't! 32 | -------------------------------------------------------------------------------- /docs/plugins.rst: -------------------------------------------------------------------------------- 1 | Plugins 2 | ======= 3 | 4 | It's fairly easy to ship a plugin for Flask-Debug with your own package or 5 | Flask-extension. This allows you to ship debugging tools right along with 6 | the extension. 7 | 8 | First, create a package named ``flask_debug_yourname``, the prefix 9 | ``flask_debug_`` is important. Your ``__init__.py`` should look somewhat 10 | like this:: 11 | 12 | # file: flask_debug_myext/__init__.py 13 | 14 | template_folder = 'templates' 15 | 16 | def initialize_debug_ext(dbg): 17 | @dbg.route('/_myext/status') 18 | def debug_list_extensions(): 19 | status = 'all good' 20 | 21 | return render_template('myext/status.html', status=status) 22 | 23 | ``initialize_debug_ext()`` will be called with a ``flask.Blueprint``-Object 24 | as the first parameter, onto which you can register your own routes. The 25 | ``route()`` function will automatically a menu entry (to suppress this 26 | behavior, add an argument of ``menu_name=None``). 27 | 28 | There are a few conventions: 29 | 30 | * Views in plugins should start with ``debug_``. 31 | * URLs in routes should start with underscore + your extension name. 32 | * Inside your ``templates``-folder, you should also create subfolder named 33 | ``myext`` for all of your templates, as the template namespace is global. 34 | 35 | Flask-Debug ships a few base templates which you can use, 36 | which will use `Flask-Bootstrap `_ if available, or a minimal included template 38 | otherwise:: 39 | 40 | {# file: flask_debug_myext/templates/myext/status.html #} 41 | {% extends "flask_debug/base.html" %} 42 | 43 | {% block content %} 44 | {{super()}} 45 |

Status for myext

46 |

Current status: {{status}}

47 | {% endblock %} 48 | 49 | To finally load the plugin, just do:: 50 | 51 | import flask_debug_myext 52 | 53 | in your extension. Before registering the debugging-blueprint onto the app, 54 | Flask-Debug will query ``sys.modules`` for all modules that look like 55 | Flask-Debug plugins and collect them. 56 | 57 | You can check out the ``flask_debug_plugins``-plugin (which lists all 58 | installed plugins) for an example. 59 | -------------------------------------------------------------------------------- /flask_debug/__init__.py: -------------------------------------------------------------------------------- 1 | from .dbg import dbg 2 | from .security import requires_debug 3 | 4 | 5 | class Debug(object): 6 | def __init__(self, app=None): 7 | import flask_debug_plugins 8 | dbg._debug_load_plugins() 9 | if app: 10 | self.init_app(app) 11 | 12 | def init_app(self, app): 13 | app.config.setdefault('FLASK_DEBUG_DISABLE_STRICT', False) 14 | app.register_blueprint(dbg) 15 | -------------------------------------------------------------------------------- /flask_debug/dbg.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | from functools import wraps 3 | import sys 4 | 5 | from flask import current_app, render_template, Blueprint, url_for, redirect, g 6 | import inflection 7 | from jinja2 import PackageLoader, ChoiceLoader 8 | 9 | from .security import requires_debug 10 | 11 | 12 | class DebugBlueprint(Blueprint): 13 | def __init__(self, *args, **kwargs): 14 | super(DebugBlueprint, self).__init__(*args, **kwargs) 15 | self.__menu = OrderedDict() 16 | self.__plugins = None 17 | 18 | def _debug_load_plugins(self): 19 | if self.__plugins is not None: 20 | # already loaded 21 | return 22 | 23 | dbg.__plugins = {} 24 | 25 | for name, mod in sys.modules.items(): 26 | if (name.startswith('flask_debug_') and 27 | hasattr(mod, 'initialize_debug_ext')): 28 | mod.initialize_debug_ext(dbg) 29 | dbg.__plugins[name] = mod 30 | 31 | # collect loaders 32 | loaders = [dbg.jinja_loader] 33 | for name, mod in dbg.__plugins.items(): 34 | template_folder = getattr(mod, 'template_folder', None) 35 | if template_folder: 36 | loaders.append(PackageLoader(name, template_folder)) 37 | 38 | # replace blueprints loader with new loader that includes extensions 39 | dbg.jinja_loader = ChoiceLoader(loaders) 40 | 41 | def _debug_get_menu(self): 42 | return self.__menu 43 | 44 | def _debug_get_plugins(self): 45 | return self.__plugins 46 | 47 | def route(self, rule, menu_name=True, require_debug=True, **options): 48 | # if only there was nonlocal in py2... 49 | wrapper = super(DebugBlueprint, self).route(rule, **options) 50 | 51 | @wraps(wrapper) 52 | def _(f): 53 | endpoint = options.get('endpoint', f.__name__) 54 | 55 | if require_debug: 56 | f = requires_debug(f) 57 | 58 | # menu entry, auto-generated 59 | name = menu_name 60 | if name is True: 61 | name = endpoint 62 | if name.startswith('debug_'): 63 | name = name[len('debug_'):] 64 | name = inflection.titleize(name) 65 | 66 | wrapped = wrapper(f) 67 | if name: 68 | endpoint = '{}.{}'.format(self.name, endpoint) 69 | self.__menu[endpoint] = name 70 | return wrapped 71 | 72 | return _ 73 | 74 | 75 | dbg = DebugBlueprint('debug', __name__, template_folder='templates') 76 | 77 | 78 | @dbg.route('/_debug/', menu_name=None) # the root 79 | def debug_root(): 80 | return redirect(url_for('.debug_reflect')) 81 | 82 | 83 | @dbg.route('/_reflect/') 84 | def debug_reflect(): 85 | return render_template( 86 | 'flask_debug/reflect.html', 87 | app=current_app, 88 | ) 89 | 90 | 91 | @dbg.route('/_config/') 92 | def debug_config(): 93 | return render_template( 94 | 'flask_debug/config.html', 95 | app=current_app, 96 | ) 97 | 98 | 99 | @dbg.before_request 100 | def make_current_app_available(): 101 | g.app = current_app 102 | g.menu = dbg._debug_get_menu() 103 | g.dbg = dbg 104 | 105 | g.bootstrap_base_template = 'flask_debug/bootstrap_base.html' 106 | if 'bootstrap' in getattr(current_app, 'extensions', {}): 107 | g.bootstrap_base_template = 'bootstrap/base.html' 108 | -------------------------------------------------------------------------------- /flask_debug/security.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from flask import current_app, abort, request 4 | 5 | 6 | def requires_debug(view): 7 | @wraps(view) 8 | def _(*args, **kwargs): 9 | strict = not current_app.config.get('FLASK_DEBUG_DISABLE_STRICT', 10 | False) 11 | if not current_app.debug: 12 | if strict: 13 | abort(404) # don't even show we have flask-debug installed 14 | abort(403, 'This function is only available if the application ' 15 | 'has been started in debug mode.') 16 | 17 | msg = [] 18 | if strict: 19 | # extra security checks 20 | msg = [] 21 | 22 | strict_env = { 23 | 'SERVER_NAME': '127.0.0.1', 24 | 'REMOTE_ADDR': '127.0.0.1', 25 | 'SERVER_PORT': '5000', 26 | } 27 | 28 | for env, val in strict_env.items(): 29 | if request.environ.get(env, None) != val: 30 | msg.append('{} is not {!r}.' 31 | .format(env, val)) 32 | 33 | if not request.environ.get('SERVER_SOFTWARE', '').startswith( 34 | 'Werkzeug/' 35 | ): 36 | msg.append('Not running on Werkzeug-Server.') 37 | 38 | if 'X-Forwarded-For' in request.headers: 39 | msg.append('Request has a X-Forwarded-For header.') 40 | 41 | if msg: 42 | msg.append('Strict security checks are enabled, to prevent ' 43 | 'security issues in case you have forgotten to ' 44 | 'disable debugging on a production system. You ' 45 | 'can disable these by setting ' 46 | 'FLASK_DEBUG_DISABLE_STRICT to True ' 47 | 'in your applications configuration.') 48 | 49 | if msg: 50 | abort(403, '\n\n'.join(msg)) 51 | return view(*args, **kwargs) 52 | return _ 53 | -------------------------------------------------------------------------------- /flask_debug/templates/flask_debug/base.html: -------------------------------------------------------------------------------- 1 | {% extends g.bootstrap_base_template %} 2 | 3 | {% block title %}{{g.menu[request.endpoint]|default('flask-debug')}}: {{g.app .name}}{% endblock %} 4 | 5 | 6 | {% block content %} 7 |
8 | {% block container %} 9 | 16 | {% endblock container %} 17 |
18 | {% endblock content %} 19 | -------------------------------------------------------------------------------- /flask_debug/templates/flask_debug/bootstrap_base.html: -------------------------------------------------------------------------------- 1 | {# this is a minimal bootstrap template in case Flask-Bootstrap is not installed -#} 2 | 3 | 4 | 5 | 6 | {% block head %} 7 | 8 | 9 | {% endblock %} 10 | {% block title %}{% endblock %} 11 | 12 | 13 | 14 | {% block body -%} 15 | {% block content %}{% endblock %} 16 | 17 | {% block scripts %} 18 | 19 | 20 | {% endblock %} 21 | 22 | {%- endblock body %} 23 | 24 | 25 | -------------------------------------------------------------------------------- /flask_debug/templates/flask_debug/config.html: -------------------------------------------------------------------------------- 1 | {% extends "flask_debug/base.html" %} 2 | 3 | {% block container %} 4 | {{super()}} 5 |

Configuration for {{g.app.name}}

6 | 7 | 8 | 9 | 10 | 11 | {% for key, value in config.items()|sort %} 12 | 13 | 14 | 15 | 16 | {% endfor %} 17 |
KeyValue
{{key}}{{'%r'|format(value)}}
18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /flask_debug/templates/flask_debug/reflect.html: -------------------------------------------------------------------------------- 1 | {% extends "flask_debug/base.html" %} 2 | 3 | {% block scripts %} 4 | {{super()}} 5 | 17 | {% endblock %} 18 | 19 | {% block container %} 20 | {{super()}} 21 |

Reflection for {{g.app.name}}

22 |

Views

23 |
24 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | {% for name, view in g.app.view_functions.items()|sort(True) %} 35 | 37 | 38 | 39 | {% endfor %} 40 |
NameView function
{{name}}{{view}}
41 | 42 |

URLMap

43 |
44 | 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | {% for rule in g.app.url_map.iter_rules()|sort(True, 56 | attribute='endpoint') %} 57 | 60 | 61 | 62 | 63 | {% endfor %} 64 |
RuleMethodsEndpoint
{{rule}}{{rule.methods|sort|join(', ')}}{{rule.endpoint}}
65 | 66 |

Converters

67 | 68 | 69 | 70 | 71 | 72 | {% for name, conv in g.app.url_map.converters.items() %} 73 | 74 | 75 | 76 | 77 | {% endfor %} 78 |
Type-nameConverter function
{{name}}{{conv}}
79 | {% endblock %} 80 | -------------------------------------------------------------------------------- /flask_debug_plugins/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import render_template 2 | 3 | from flask_debug import requires_debug 4 | 5 | 6 | template_folder = 'templates' 7 | 8 | 9 | def initialize_debug_ext(dbg): 10 | @dbg.route('/_extensions/') 11 | def debug_list_extensions(): 12 | return render_template('flask_debug/plugins.html') 13 | -------------------------------------------------------------------------------- /flask_debug_plugins/templates/flask_debug/plugins.html: -------------------------------------------------------------------------------- 1 | {% extends "flask_debug/base.html" %} 2 | 3 | {% block container %} 4 | {{super()}} 5 |

Flask-Debug plugins

6 | The following plugins for Flask -Debug have been loaded: 7 | 8 | 9 | 10 | 11 | 12 | {% for name, mod in g.dbg._debug_get_plugins().items()|sort(True) %} 13 | 14 | 15 | 16 | 17 | {% endfor %} 18 |
PluginModule
{{name}}{{mod.__file__}}
19 | 20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | 6 | from setuptools import setup, find_packages 7 | 8 | 9 | def read(fname): 10 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 11 | 12 | 13 | setup( 14 | name='Flask-Debug', 15 | version='0.4.2.dev1', 16 | description='Shows reflection/configuration to aid the development of ' 17 | 'Flask applications.', 18 | long_description=read('README.rst'), 19 | include_package_data=True, 20 | zip_safe=False, 21 | author='Marc Brinkmann', 22 | author_email='git@marcbrinkmann.de', 23 | url='http://github.com/mbr/flask-debug', 24 | license='MIT', 25 | packages=find_packages(exclude=['tests']), 26 | install_requires=['flask', 'inflection'], 27 | ) 28 | -------------------------------------------------------------------------------- /tests/test_client.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from flask import Flask 3 | from flask_debug import Debug 4 | 5 | 6 | @pytest.fixture 7 | def app(): 8 | app = Flask(__name__) 9 | Debug(app) 10 | app.config['DEBUG'] = True 11 | app.config['TESTING'] = True 12 | app.config['FLASK_DEBUG_DISABLE_STRICT'] = True 13 | 14 | assert app.debug 15 | assert app.testing 16 | return app 17 | 18 | 19 | @pytest.yield_fixture 20 | def client(app): 21 | with app.app_context(): 22 | yield app.test_client() 23 | 24 | 25 | def test_works_in_debug_mode(client): 26 | # redirect 27 | assert client.get('/_debug/').status_code == 302 28 | 29 | assert client.get('/_reflect/').status_code == 200 30 | assert client.get('/_config/').status_code == 200 31 | 32 | 33 | def test_refuses_outside_debug_mode(app, client): 34 | app.config['DEBUG'] = False 35 | 36 | # redirect 37 | assert client.get('/_debug/').status_code == 403 38 | 39 | assert client.get('/_reflect/').status_code == 403 40 | assert client.get('/_config/').status_code == 403 41 | 42 | 43 | def test_plugin_gets_properly_loaded_and_is_working(app, client): 44 | assert client.get('/_extensions/').status_code == 200 45 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27,py33,bootstrap27,bootstrap33 3 | 4 | [testenv] 5 | deps=pytest 6 | commands=py.test 7 | 8 | [testenv:bootstrap27] 9 | basepython=python2.7 10 | deps= 11 | pytest 12 | Flask-Bootstrap 13 | 14 | [testenv:bootstrap33] 15 | basepython=python3.3 16 | deps= 17 | pytest 18 | Flask-Bootstrap 19 | --------------------------------------------------------------------------------