28 Commits

Author SHA1 Message Date
Jeff Widman
a758a9df7a Release 0.12.1 2022-03-28 01:16:17 -07:00
Jeff Widman
5eea25882c Fix changelog / docs link
I fat-fingered this in
https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/164 so
correcting it.
2022-03-28 01:14:12 -07:00
Jeff Widman
e954cd9fae Bump version for development 2022-03-27 23:48:24 -07:00
Jeff Widman
03d79be02c Release 0.12.0 2022-03-27 23:48:08 -07:00
Jeff Widman
7f17d2ce57 Update PyPI metadata files: add setup.cfg etc (#164)
Update to the newer PyPI / python packaging metadata file structure.

A lot of this was cribbed from how [`Flask`](https://github.com/pallets/flask) itself
exposes its metadata.
2022-03-26 21:51:54 -07:00
Nick Janetakis
30fba11f36 Remove with_ extension for Jinja 3.0 (#157)
Jinja 3.0 throws a deprecation warning that this will be removed in 3.1
because it's built into Jinja now without needing an extension.

However since folks might want to use Jinja 2 for a while this supports
both versions by only using the extension with Jinja 2.
2022-03-25 21:26:26 -07:00
jnnkB
d474a6a689 prefixed css classes, fixes #152 (#153) 2020-08-14 11:39:15 -07:00
zaw007
83d398d9d5 Support gzip response (#154)
* add gzip compress and decompress

* support gzip response
2020-08-14 11:37:37 -07:00
Jeff Widman
3929742d9c Cleanup version handling slightly (#149)
Some improvements I saw over on
https://github.com/FactoryBoy/factory_boy/pull/676/files that looked
useful here as well.
2020-03-09 13:10:02 -07:00
Jeff Widman
70abd78e55 Setup DB properly
When I switched over to `flask run` entrypoint in b92391d177,
I forgot that the `if name==__main__` code no longer triggers.
So the SQLite in-memory database wasn't getting created for the example
app.

This moves the DB creation to a werkzeug/Flask hook that runs before the
first request to the app, so that the DB table is created when we query
it.

Also updated the test which worked fine previously, but this is more
idiomatic.
2020-03-09 10:01:59 -07:00
Jeff Widman
dbea74b626 Update README.rst 2020-03-09 09:46:05 -07:00
Jeff Widman
c6102aeb14 Change docs to pull version from setup.py 2020-03-02 09:37:37 -08:00
Jeff Widman
10c9c1ae5d Update Flask-SQLAlchemy links 2020-02-22 20:39:21 -08:00
Yaser Amiri
9e600c6e13 Add flask.g section to show g object content. 2020-02-22 09:47:21 -08:00
Matthew Swabey
9b8a8afa97 Fix SQLAlchemy SELECT/EXPLAIN to use url_for to respect app prefixes. Provide url_for to all toolbar templates 2020-02-22 09:24:23 -08:00
Jeff Widman
39ac97a7e0 pycodestyle fixes 2020-02-18 01:21:40 -08:00
Jeff Widman
a5cb5a709f Bump version for development 2020-02-18 01:19:49 -08:00
Jeff Widman
02064c76ed Release 0.11.0 2020-02-18 01:11:19 -08:00
Jeff Widman
d713732807 Cleanup tox/travis
* Switch to python 3.8 in Travis. I tried to add 3.8 while keeping 3.7
and 3.6, but ran into issues with Travis config, so instead just bumped
straight to 3.8. Long term I'd like to explore moving to Azure
Pipelines, but don't have the time to figure that out just yet.
* `flake8` was renamed to `pycodestyle`
* `py.test` was deprecated in favor of `pytest`
2020-02-18 00:42:39 -08:00
Jeff Widman
b92391d177 Switch to Flask's native CLI
Drop `flask_script` in favor of Flask's native CLI:
* https://flask.palletsprojects.com/en/master/cli/

This also requires changing the tests so that `pytest` mocks the env var
`FLASK_ENV` so that the test app starts in development mode. Unlike
normal test apps, we _do_ want development/debug mode, in addition to
testing mode.
2020-02-17 23:57:04 -08:00
Florian
4964ae261f RoutesList: Do not show debugtoolbar routes 2020-02-17 22:30:10 -08:00
Pierre GIRAUD
ad847299c4 Add doc for SQL syntax highlighting 2020-02-17 21:57:01 -08:00
Jeff Widman
7ce099c3d0 Remove deprecated request.is_xhr
This was removed from `werkzeug` `1.0.0`.

Details:
* https://github.com/pallets/werkzeug/issues/1077
* https://github.com/pallets/werkzeug/issues/1714 (search for `is_xhr`)

Fix #144.
2020-02-17 21:50:56 -08:00
Jeff Widman
9c7db48362 Explicitly disable SQLALCHEMY_TRACK_MODIFICATIONS
This silences deprecation warnings.
Background: https://stackoverflow.com/a/33790196/770425

Note: This code can be removed once `flask_sqlalchemy` 3.0 ships, or any
release that includes
https://github.com/pallets/flask-sqlalchemy/pull/727.
2020-02-17 21:36:01 -08:00
Tim Gates
88f15cba35 Fix simple typo: exapanded -> expanded
Closes #141
2020-02-06 14:03:36 -08:00
Matt Good
d852042ccb Merge pull request #119 from davidism/json-available
don't use flask.json_available
2018-02-07 09:52:11 -08:00
David Lord
5bd2e8a423 flask.json_available is a no-op
it is removed in Flask 1.0
2018-02-07 07:13:21 -08:00
Jeff Widman
c27256c00a Bump dev version 2017-02-12 03:33:05 -08:00
27 changed files with 331 additions and 190 deletions

View File

@@ -1,9 +1,9 @@
sudo: false
language: python
python: "3.6"
python: "3.8"
env:
- TOXENV=py27
- TOXENV=py36
- TOXENV=py38
install:
- pip install tox
script: tox

View File

@@ -1,6 +1,54 @@
Changes
=======
0.13.0 (Unreleased)
-------------------
Enhancements:
- ??
Fixes:
- ??
0.12.1 (2022-03-28)
-------------------
Fixes:
- Correct changelog and docs URLs on PyPI
0.12.0 (2022-03-28)
-------------------
Enhancements:
- Add flask.g section to show g object content. by @Yaser-Amiri in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/118
- Support gzip response by @zaw007 in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/154
- Update PyPI metadata files: add `setup.cfg` etc by @jeffwidman in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/164
Fixes:
- Remove deprecated Jinja with_ extension for Jinja 3.0 (related to Flask 2.0) by @nickjj in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/157
- Fix SQLAlchemy SELECT/EXPLAIN to use url_for to respect app prefixes.… by @mattaw in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/143
- Setup DB properly by @jeffwidman in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/148
- prefixed css classes, fixes #152 by @jnnkB in https://github.com/flask-debugtoolbar/flask-debugtoolbar/pull/153
0.11.0 (2020-02-18)
-------------------
Enhancements:
- Switch to Flask's native CLI, dropping flask_script in the process (b92391d, thanks @jeffwidman)
- Do not show DebugToolbar routes in the route map (#86, thanks @floqqi)
- Document Pygments for SQL highlighting (#127, thanks @pgiraud)
Fixes:
- Remove deprecated flask.json_available (#119, thanks @davidism)
- Remove deprecated request.is_xhr (7ce099c, thanks @jeffwidman)
- Explicitly disable `SQLALCHEMY_TRACK_MODIFICATIONS` (9c7db48, thanks @jeffwidman)
- Fix typo (#142, thanks @timgates42)
0.10.1 (2017-02-12)
-------------------

View File

@@ -4,8 +4,8 @@ Flask Debug-toolbar
This is a port of the excellent `django-debug-toolbar <https://github.com/django-debug-toolbar/django-debug-toolbar>`_
for Flask applications.
.. image:: https://travis-ci.org/mgood/flask-debugtoolbar.png?branch=master
:target: https://travis-ci.org/mgood/flask-debugtoolbar
.. image:: https://travis-ci.org/flask-debugtoolbar/flask-debugtoolbar.png?branch=master
:target: https://travis-ci.org/flask-debugtoolbar/flask-debugtoolbar
Installation

View File

@@ -13,9 +13,12 @@
import datetime
import os
import pkg_resources
import sys
import time
import flask_debugtoolbar
BUILD_DATE = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
@@ -56,10 +59,10 @@ copyright = u'2012-{0}'.format(BUILD_DATE.year)
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.10'
# The full version, including alpha/beta/rc tags.
release = '0.10.1'
release = flask_debugtoolbar.__version__
# The short X.Y version.
version = '.'.join(release.split('.')[:2])
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -13,7 +13,7 @@ Time
flask_debugtoolbar.panels.timer.TimerDebugPanel
Shows the time taken to process the current request. The exapanded view includes the breakdown of CPU time, by user and system, wall clock time, and context switches.
Shows the time taken to process the current request. The expanded view includes the breakdown of CPU time, by user and system, wall clock time, and context switches.
.. image:: _static/screenshot-time-panel.png
@@ -72,10 +72,14 @@ Shows SQL queries run during the current request.
For additional details on query recording see the
:py:func:`~flask_sqlalchemy.get_debug_queries` documentation.
.. note:: SQL syntax highlighting requires `Pygments`_ to be installed.
.. image:: _static/screenshot-sqlalchemy-panel.png
.. _Flask-SQLAlchemy: http://flask-sqlalchemy.pocoo.org/
.. _Pygments: http://pygments.org/
Logging
-------

View File

@@ -1,8 +1,6 @@
import sys
sys.path.insert(0, '.')
# Run using: `FLASK_ENV=development flask run`
from flask import Flask, render_template, redirect, url_for
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_debugtoolbar import DebugToolbarExtension
@@ -16,7 +14,10 @@ app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = True
#)
#app.config['DEBUG_TB_HOSTS'] = ('127.0.0.1', '::1' )
app.config['SECRET_KEY'] = 'asd'
app.config['DEBUG'] = True
# TODO: This can be removed once flask_sqlalchemy 3.0 ships
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
@@ -28,6 +29,11 @@ class ExampleModel(db.Model):
value = db.Column(db.String(100), primary_key=True)
@app.before_first_request
def setup():
db.create_all()
@app.route('/')
def index():
app.logger.info("Hello there")
@@ -37,13 +43,6 @@ def index():
@app.route('/redirect')
def redirect_example():
response = redirect(url_for('index'))
response.set_cookie('test_cookie', '1')
return response
if __name__ == "__main__":
db.create_all()
manager = Manager(app)
manager.run()

View File

@@ -1,14 +1,25 @@
import os
import warnings
from flask import Blueprint, current_app, request, g, send_from_directory
from flask import Blueprint, current_app, request, g, send_from_directory, url_for
from flask.globals import _request_ctx_stack
from jinja2 import __version__ as __jinja_version__
from jinja2 import Environment, PackageLoader
from werkzeug.urls import url_quote_plus
from flask_debugtoolbar.compat import iteritems
from flask_debugtoolbar.toolbar import DebugToolbar
from flask_debugtoolbar.utils import decode_text
from flask_debugtoolbar.utils import decode_text, gzip_compress, gzip_decompress
try:
# Python 3.8+
from importlib.metadata import version
__version__ = version("Flask-DebugToolbar")
except ImportError:
import pkg_resources
__version__ = pkg_resources.get_distribution("Flask-DebugToolbar").version
module = Blueprint('debugtoolbar', __name__)
@@ -44,15 +55,20 @@ class DebugToolbarExtension(object):
def __init__(self, app=None):
self.app = app
self.debug_toolbars = {}
jinja_extensions = ['jinja2.ext.i18n']
if __jinja_version__[0] == '2':
jinja_extensions.append('jinja2.ext.with_')
# Configure jinja for the internal templates and add url rules
# for static data
self.jinja_env = Environment(
autoescape=True,
extensions=['jinja2.ext.i18n', 'jinja2.ext.with_'],
extensions=jinja_extensions,
loader=PackageLoader(__name__, 'templates'))
self.jinja_env.filters['urlencode'] = url_quote_plus
self.jinja_env.filters['printable'] = _printable
self.jinja_env.globals['url_for'] = url_for
if app is not None:
self.init_app(app)
@@ -99,6 +115,7 @@ class DebugToolbarExtension(object):
'flask_debugtoolbar.panels.logger.LoggingPanel',
'flask_debugtoolbar.panels.route_list.RouteListDebugPanel',
'flask_debugtoolbar.panels.profiler.ProfilerDebugPanel',
'flask_debugtoolbar.panels.g.GDebugPanel',
),
}
@@ -178,8 +195,7 @@ class DebugToolbarExtension(object):
# Intercept http redirect codes and display an html page with a
# link to the target.
if current_app.config['DEBUG_TB_INTERCEPT_REDIRECTS']:
if (response.status_code in self._redirect_codes and
not real_request.is_xhr):
if response.status_code in self._redirect_codes:
redirect_to = response.location
redirect_code = response.status_code
if redirect_to:
@@ -199,7 +215,10 @@ class DebugToolbarExtension(object):
response.headers['content-type'].startswith('text/html')):
return response
response_html = response.data.decode(response.charset)
if 'gzip' in response.headers.get('Content-Encoding', ''):
response_html = gzip_decompress(response.data).decode(response.charset)
else:
response_html = response.data.decode(response.charset)
no_case = response_html.lower()
body_end = no_case.rfind('</body>')
@@ -224,6 +243,8 @@ class DebugToolbarExtension(object):
content = ''.join((before, toolbar_html, after))
content = content.encode(response.charset)
if 'gzip' in response.headers.get('Content-Encoding', ''):
content = gzip_compress(content)
response.response = [content]
response.content_length = len(content)

View File

@@ -0,0 +1,29 @@
from flask import g
from flask_debugtoolbar.panels import DebugPanel
_ = lambda x: x
class GDebugPanel(DebugPanel):
"""
A panel to display flask.g content.
"""
name = 'g'
has_content = True
def nav_title(self):
return _('flask.g')
def title(self):
return _('flask.g content')
def url(self):
return ''
def content(self):
context = self.context.copy()
context.update({
'g_content': g.__dict__
})
return self.render('panels/g.html', context)

View File

@@ -26,7 +26,11 @@ class RouteListDebugPanel(DebugPanel):
return '%s %s' % (count, 'route' if count == 1 else 'routes')
def process_request(self, request):
self.routes = list(current_app.url_map.iter_rules())
self.routes = [
rule
for rule in current_app.url_map.iter_rules()
if not rule.rule.startswith('/_debug_toolbar')
]
def content(self):
return self.render('panels/route_list.html', {

View File

@@ -6,7 +6,7 @@ except ImportError:
else:
sqlalchemy_available = True
from flask import request, current_app, abort, json_available, g
from flask import request, current_app, abort, g
from flask_debugtoolbar import module
from flask_debugtoolbar.panels import DebugPanel
from flask_debugtoolbar.utils import format_fname, format_sql
@@ -59,8 +59,7 @@ def recording_enabled():
def is_available():
return (json_available and sqlalchemy_available
and extension_used() and recording_enabled())
return sqlalchemy_available and extension_used() and recording_enabled()
def get_queries():
@@ -108,7 +107,6 @@ class SQLAlchemyDebugPanel(DebugPanel):
if not queries and not is_available():
return self.render('panels/sqlalchemy_error.html', {
'json_available': json_available,
'sqlalchemy_available': sqlalchemy_available,
'extension_used': extension_used(),
'recording_enabled': recording_enabled(),

View File

@@ -53,7 +53,7 @@
}
#flDebug #flDebugToolbar li>a,
#flDebug #flDebugToolbar li>div.contentless {
#flDebug #flDebugToolbar li>div.flDebugContentless {
font-weight:normal;
font-style:normal;
text-decoration:none;
@@ -68,7 +68,7 @@
background-color:#ffc;
}
#flDebug #flDebugToolbar li.active {
#flDebug #flDebugToolbar li.flDebugActive {
background-image:url(../img/indicator.png);
background-repeat:no-repeat;
background-position:left center;
@@ -76,7 +76,7 @@
padding-left:10px;
}
#flDebug #flDebugToolbar li.active a:hover {
#flDebug #flDebugToolbar li.flDebugActive a:hover {
color:#b36a60;
background-color:transparent;
}
@@ -89,7 +89,7 @@
font-variant:small-caps;
}
#flDebug #flDebugToolbar li .switch {
#flDebug #flDebugToolbar li .flDebugSwitch {
font-size: 10px;
position: absolute;
display: block;
@@ -101,11 +101,11 @@
right: 2px;
}
#flDebug #flDebugToolbar li .switch.active {
#flDebug #flDebugToolbar li .flDebugSwitch.flDebugActive {
background-image: url(../img/tick.png);
}
#flDebug #flDebugToolbar li .switch.inactive {
#flDebug #flDebugToolbar li .flDebugSwitch.flDebugInactive {
background-image: url(../img/tick-red.png);
}
@@ -120,7 +120,7 @@
opacity:0.75;
}
#flDebug a#flShowToolBarButton {
#flDebug a#flDebugShowToolBarButton {
display:block;
height:75px;
width:30px;
@@ -138,7 +138,7 @@
opacity:0.5;
}
#flDebug a#flShowToolBarButton:hover {
#flDebug a#flDebugShowToolBarButton:hover {
background-color:#111;
padding-right:6px;
border-top-color:#FFE761;
@@ -157,7 +157,7 @@
background-color:#f5f5f5;
}
#flDebug .panelContent {
#flDebug .flDebugPanelContentParent {
display:none;
position:fixed;
margin:0;
@@ -170,7 +170,7 @@
z-index:100000000;
}
#flDebug .panelContent > div {
#flDebug .flDebugPanelContentParent > div {
border-bottom:1px solid #ddd;
}
@@ -223,7 +223,7 @@
font-size: 14px;
}
#flDebug .panelContent table {
#flDebug .flDebugPanelContentParent table {
border:1px solid #ccc;
border-collapse:collapse;
width:100%;
@@ -232,29 +232,29 @@
margin-top:0.8em;
overflow: auto;
}
#flDebug .panelContent tbody td,
#flDebug .panelContent tbody th {
#flDebug .flDebugPanelContentParent tbody td,
#flDebug .flDebugPanelContentParent tbody th {
vertical-align:top;
padding:2px 3px;
}
#flDebug .panelContent thead th {
#flDebug .flDebugPanelContentParent thead th {
padding:1px 6px 1px 3px;
text-align:left;
font-weight:bold;
font-size:14px;
}
#flDebug .panelContent tbody th {
#flDebug .flDebugPanelContentParent tbody th {
width:12em;
text-align:right;
color:#666;
padding-right:.5em;
}
#flDebug .panelContent ol li {
#flDebug .flDebugPanelContentParent ol li {
margin: 0 0 1em 2em;
}
#flDebug .panelContent pre {
#flDebug .flDebugPanelContentParent pre {
border:1px solid #ccc;
background-color:#fff;
display:block;
@@ -266,7 +266,7 @@
background-color:#fff;
}
#flDebug .panelContent .flDebugClose {
#flDebug .flDebugPanelContentParent .flDebugClose {
text-indent:-9999999px;
display:block;
position:absolute;
@@ -277,38 +277,38 @@
background:url(../img/close.png) no-repeat center center;
}
#flDebug .panelContent .flDebugClose:hover {
#flDebug .flDebugPanelContentParent .flDebugClose:hover {
background-image:url(../img/close_hover.png);
}
#flDebug .panelContent .flDebugClose.flDebugBack {
#flDebug .flDebugPanelContentParent .flDebugClose.flDebugBack {
background-image:url(../img/back.png);
}
#flDebug .panelContent .flDebugClose.flDebugBack:hover {
#flDebug .flDebugPanelContentParent .flDebugClose.flDebugBack:hover {
background-image:url(../img/back_hover.png);
}
#flDebug .panelContent dt, #flDebug .panelContent dd {
#flDebug .flDebugPanelContentParent dt, #flDebug .flDebugPanelContentParent dd {
display:block;
}
#flDebug .panelContent dt {
#flDebug .flDebugPanelContentParent dt {
margin-top:0.75em;
}
#flDebug .panelContent dd {
#flDebug .flDebugPanelContentParent dd {
margin-left:10px;
}
#flDebug a.toggleTemplate {
#flDebug a.flDebugToggleTemplate {
padding:4px;
background-color:#bbb;
-moz-border-radius:3px;
-webkit-border-radius:3px;
}
#flDebug a.toggleTemplate:hover {
#flDebug a.flDebugToggleTemplate:hover {
padding:4px;
background-color:#444;
color:#ffe761;
@@ -317,11 +317,11 @@
}
#flDebug a.flTemplateShowContext, #flDebug a.flTemplateShowContext span.toggleArrow {
#flDebug a.flDebugTemplateShowContext, #flDebug a.flDebugTemplateShowContext span.flDebugToggleArrow {
color:#999;
}
#flDebug a.flTemplateShowContext:hover, #flDebug a.flTemplateShowContext:hover span.toggleArrow {
#flDebug a.flDebugTemplateShowContext:hover, #flDebug a.flDebugTemplateShowContext:hover span.flDebugToggleArrow {
color:#000;
cursor:pointer;
}
@@ -334,7 +334,7 @@
z-index:100000002;
}
#flDebug .flSQLHideStacktraceDiv tbody th {
#flDebug .flDebugHideStacktraceDiv tbody th {
text-align: left;
}
@@ -373,25 +373,25 @@
#flDebug .highlight .cp { color:#333 } /* Comment.Preproc */
/* tablesorted */
#flDebug table.tablesorter {
#flDebug table.flDebugTablesorter {
width: 100%;
}
#flDebug table.tablesorter thead th, table.tablesorter tfoot th {
#flDebug table.flDebugTablesorter thead th, table.flDebugTablesorter tfoot th {
padding-right: 20px;
}
#flDebug table.tablesorter thead th {
#flDebug table.flDebugTablesorter thead th {
background: url(../img/bg.gif) center right no-repeat;
cursor: pointer;
}
#flDebug table.tablesorter tbody tr.odd td {
#flDebug table.flDebugTablesorter tbody tr.odd td {
background-color: #F0F0F6;
}
#flDebug table.tablesorter thead .headerSortUp {
#flDebug table.flDebugTablesorter thead .headerSortUp {
background-image: url(../img/asc.gif);
}
#flDebug table.tablesorter thead .headerSortDown {
#flDebug table.flDebugTablesorter thead .headerSortDown {
background-image: url(../img/desc.gif);
}
#flDebug table.tablesorter thead .headerSortDown, #flDebug table.tablesorter thead .headerSortUp {
#flDebug table.flDebugTablesorter thead .headerSortDown, #flDebug table.flDebugTablesorter thead .headerSortUp {
background-color: #8dbdd8;
}

View File

@@ -14,16 +14,16 @@
current = $('#flDebug #' + this.className + '-content');
if (current.is(':visible')) {
$(document).trigger('close.flDebug');
$(this).parent().removeClass('active');
$(this).parent().removeClass('flDebugActive');
} else {
$('.panelContent').hide(); // Hide any that are already open
$('.flDebugPanelContentParent').hide(); // Hide any that are already open
current.show();
$('#flDebugToolbar li').removeClass('active');
$(this).parent().addClass('active');
$('#flDebugToolbar li').removeClass('flDebugActive');
$(this).parent().addClass('flDebugActive');
}
return false;
});
$('#flDebugPanelList li .switch').click(function() {
$('#flDebugPanelList li .flDebugSwitch').click(function() {
var $panel = $(this).parent();
var $this = $(this);
var dom_id = $panel.attr('id');
@@ -33,13 +33,13 @@
var active = (active_str) ? active_str.split(';') : [];
active = $.grep(active, function(n,i) { return n != dom_id; });
if ($this.hasClass('active')) {
$this.removeClass('active');
$this.addClass('inactive');
if ($this.hasClass('flDebugActive')) {
$this.removeClass('flDebugActive');
$this.addClass('flDebugInactive');
} else {
active.push(dom_id);
$this.removeClass('inactive');
$this.addClass('active');
$this.removeClass('flDebugInactive');
$this.addClass('flDebugActive');
}
if (active.length > 0) {
@@ -54,10 +54,10 @@
});
$('#flDebug a.flDebugClose').click(function() {
$(document).trigger('close.flDebug');
$('#flDebugToolbar li').removeClass('active');
$('#flDebugToolbar li').removeClass('flDebugActive');
return false;
});
$('#flDebug a.remoteCall').click(function() {
$('#flDebug a.flDebugRemoteCall').click(function() {
$('#flDebugWindow').load(this.href, {}, function() {
$('#flDebugWindow a.flDebugBack').click(function() {
$(this).parent().parent().hide();
@@ -67,20 +67,20 @@
$('#flDebugWindow').show();
return false;
});
$('#flDebugTemplatePanel a.flTemplateShowContext').click(function() {
fldt.toggle_arrow($(this).children('.toggleArrow'))
$('#flDebugTemplatePanel a.flDebugTemplateShowContext').click(function() {
fldt.toggle_arrow($(this).children('.flDebugToggleArrow'))
fldt.toggle_content($(this).parent().next());
return false;
});
$('#flDebugSQLPanel a.flSQLShowStacktrace').click(function() {
fldt.toggle_content($('.flSQLHideStacktraceDiv', $(this).parents('tr')));
$('#flDebugSQLPanel a.flDebugShowStacktrace').click(function() {
fldt.toggle_content($('.flDebugHideStacktraceDiv', $(this).parents('tr')));
return false;
});
$('#flHideToolBarButton').click(function() {
$('#flDebugHideToolBarButton').click(function() {
fldt.hide_toolbar(true);
return false;
});
$('#flShowToolBarButton').click(function() {
$('#flDebugShowToolBarButton').click(function() {
fldt.show_toolbar();
return false;
});
@@ -91,8 +91,8 @@
return;
}
// If a panel is open, close that
if ($('.panelContent').is(':visible')) {
$('.panelContent').hide();
if ($('.flDebugPanelContentParent').is(':visible')) {
$('.flDebugPanelContentParent').hide();
return;
}
// Otherwise, just minimize the toolbar
@@ -106,7 +106,7 @@
} else {
fldt.show_toolbar(false);
}
$('#flDebug table.tablesorter').each(function() {
$('#flDebug table.flDebugTablesorter').each(function() {
var headers = {};
$(this).find('thead th').each(function(idx, elem) {
headers[idx] = $(elem).data();
@@ -137,8 +137,8 @@
// close any sub panels
$('#flDebugWindow').hide();
// close all panels
$('.panelContent').hide();
$('#flDebugToolbar li').removeClass('active');
$('.flDebugPanelContentParent').hide();
$('#flDebugToolbar li').removeClass('flDebugActive');
// finally close toolbar
$('#flDebugToolbar').hide('fast');
$('#flDebugToolbarHandle').show();

View File

@@ -7,7 +7,7 @@
<div style="display: none;" id="flDebugToolbar">
<ol id="flDebugPanelList">
{% if panels %}
<li><a id="flHideToolBarButton" href="#" title="Hide Toolbar">Hide &raquo;</a></li>
<li><a id="flDebugHideToolBarButton" href="#" title="Hide Toolbar">Hide &raquo;</a></li>
{% else %}
<li id="flDebugButton">DEBUG</li>
{% endif %}
@@ -17,7 +17,7 @@
{% if panel.has_content %}
<a href="{{ panel.url()|default("#") }}" title="{{ panel.title() }}" class="{{ panel.dom_id() }}">
{% else %}
<div class="contentless">
<div class="flDebugContentless">
{% endif %}
{{ panel.nav_title() }}
@@ -29,29 +29,29 @@
</div>
{% endif %}
{% if panel.user_activate %}
<span class="switch {{ 'active' if panel.is_active else 'inactive' }}" title="Enable or disable the panel"></span>
<span class="flDebugSwitch {{ 'flDebugActive' if panel.is_active else 'flDebugInactive' }}" title="Enable or disable the panel"></span>
{% endif %}
</li>
{% endfor %}
</ol>
</div>
<div style="display:none;" id="flDebugToolbarHandle">
<a title="Show Toolbar" id="flShowToolBarButton" href="#">&laquo;</a>
<a title="Show Toolbar" id="flDebugShowToolBarButton" href="#">&laquo;</a>
</div>
{% for panel in panels %}
{% if panel.has_content %}
<div id="{{ panel.dom_id() }}-content" class="panelContent">
<div id="{{ panel.dom_id() }}-content" class="flDebugPanelContentParent">
<div class="flDebugPanelTitle">
<a href="" class="flDebugClose">Close</a>
<h3>{{ panel.title()|safe }}</h3>
</div>
<div class="flDebugPanelContent">
<div class="scroll">
<div class="flDebugScroll">
{{ panel.content()|safe }}
</div>
</div>
</div>
{% endif %}
{% endfor %}
<div id="flDebugWindow" class="panelContent"></div>
<div id="flDebugWindow" class="flDebugPanelContentParent"></div>
</div>

View File

@@ -0,0 +1,16 @@
<table>
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for key, value in g_content|dictsort %}
<tr class="{{ loop.cycle('flDebugOdd', 'flDebugEven') }}">
<td>{{ key|escape }}</td>
<td>{{ value|escape }}</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@@ -1,4 +1,4 @@
<table id="debug_toolbar_profiler_table" class="tablesorter">
<table id="flDebugProfilerTable" class="flDebugTablesorter">
<thead>
<tr>
<th data-sorter="digit">Calls</th>

View File

@@ -1,4 +1,4 @@
<table class="tablesorter">
<table class="flDebugTablesorter">
<thead>
<tr>
<th>&nbsp;(ms)</th>
@@ -13,14 +13,14 @@
<td>{{ '%.4f'|format(query.duration * 1000) }}</td>
<td>
{% if query.signed_query %}
<a class="remoteCall" href="/_debug_toolbar/views/sqlalchemy/sql_select?query={{ query.signed_query }}&amp;duration={{ query.duration|urlencode }}">SELECT</a><br />
<a class="remoteCall" href="/_debug_toolbar/views/sqlalchemy/sql_explain?query={{ query.signed_query }}&amp;duration={{ query.duration|urlencode }}">EXPLAIN</a><br />
<a class="flDebugRemoteCall" href="{{ url_for('debugtoolbar.sql_select', explain=False, query=query.signed_query, duration=query.duration )}}">SELECT</a><br />
<a class="flDebugRemoteCall" href="{{ url_for('debugtoolbar.sql_select', explain=True, query=query.signed_query, duration=query.duration )}}">EXPLAIN</a><br />
{% endif %}
</td>
<td title="{{ query.context_long }}">
{{ query.context }}
</td>
<td class="syntax">
<td class="flDebugSyntax">
<div class="flDebugSqlWrap">
<div class="flDebugSql">{{ query.sql }}</div>
</div>

View File

@@ -6,16 +6,11 @@
</p>
<ol>
{% if not json_available or not sqlalchemy_available %}
{% if not sqlalchemy_available %}
<li>
<h5>Install required libraries:</h5>
<ul>
{% if not json_available %}
<li>simplejson</li>
{% endif %}
{% if not sqlalchemy_available %}
<li>Flask-SQLAlchemy</li>
{% endif %}
</ul>
</li>
{% endif %}
@@ -25,7 +20,7 @@
<h5>Configure Flask-SQLAlchemy:</h5>
<p>
The Flask-SQLAlchemy extension needs to be configured for this application.
Please see the <a href="http://flask-sqlalchemy.pocoo.org/latest/quickstart/">
Please see the <a href="https://flask-sqlalchemy.palletsprojects.com/en/master/quickstart/">
Flask-SQLAlchemy documentation</a> for details.
</p>
</li>
@@ -40,7 +35,7 @@
<pre>app.config['SQLALCHEMY_RECORD_QUERIES'] = True</pre>
<p>
See the
<a href="http://flask-sqlalchemy.pocoo.org/latest/api/#flask.ext.sqlalchemy.get_debug_queries">
<a href="https://flask-sqlalchemy.palletsprojects.com/en/master/api/#flask_sqlalchemy.get_debug_queries">
documention of Flask-SQLAlchemy's <code>get_debug_queries()</code></a>
for additional details.
</p>

View File

@@ -11,7 +11,7 @@
<dd>{{ '%.4f'|format(duration * 1000) }} ms</dd>
</dl>
{% if result %}
<table class="flSqlSelect">
<table class="flDebugSelect">
<thead>
<tr>
{% for h in headers %}

View File

@@ -18,46 +18,46 @@
{% set toolbar_height = 25 %}
{% set editor_width = request.cookies.get('fldt_editor_size')|int(40) %}
#panel, #editor, #preview, #splitter, #toolbar {
#flDebugPanel, #flDebugEditor, #flDebugPreview, #flDebugSplitter, #flDebugToolbar {
box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
border: none;
}
#panel, #preview { position: fixed; }
#panel > div { position: absolute; }
#flDebugPanel, #flDebugPreview { position: fixed; }
#flDebugPanel > div { position: absolute; }
#panel { width: {{ editor_width }}%; height: 100%; top: 0; left: 0; bottom: 0; }
#toolbar { top: 0; width: 100%; height: {{ toolbar_height }}px; border-bottom: 1px solid black; padding: 2px 4px; }
#editor { top: {{ toolbar_height }}px; bottom: 0; width: 100%; }
#preview { top: 0; bottom: 0; right: 0; height: 100%; width: {{ 100 - editor_width }}%; }
#flDebugPanel { width: {{ editor_width }}%; height: 100%; top: 0; left: 0; bottom: 0; }
#flDebugToolbar { top: 0; width: 100%; height: {{ toolbar_height }}px; border-bottom: 1px solid black; padding: 2px 4px; }
#flDebugEditor { top: {{ toolbar_height }}px; bottom: 0; width: 100%; }
#flDebugPreview { top: 0; bottom: 0; right: 0; height: 100%; width: {{ 100 - editor_width }}%; }
/* need a dummy element over the page so that drag events don't get captured by the preview iframe */
#drag-handler { display: none; position: fixed; width: 100%; height: 100%; z-index: 1000; }
#splitter { width: 8px; height: 100%; top: 0; bottom: 0; right: -1px; z-index: 999; cursor: e-resize; border-right: 1px solid black; }
#flDebugDragHandler { display: none; position: fixed; width: 100%; height: 100%; z-index: 1000; }
#flDebugSplitter { width: 8px; height: 100%; top: 0; bottom: 0; right: -1px; z-index: 999; cursor: e-resize; border-right: 1px solid black; }
.CodeMirror, .CodeMirror-scroll { height: 100%; }
.syntax-error { background: red !important; }
#toolbar button { margin: 0; }
#save { float: left; }
#close { float: right; }
#flDebugToolbar button { margin: 0; }
#flDebugSave { float: left; }
#flDebugClose { float: right; }
{% endwith %}
</style>
</head>
<body>
<div id="drag-handler"></div>
<div id="panel">
<div id="toolbar">
<button id="save">Save</button>
<button id="close">Close</button>
<div id="flDebugDragHandler"></div>
<div id="flDebugPanel">
<div id="flDebugToolbar">
<button id="flDebugSave">Save</button>
<button id="flDebugClose">Close</button>
</div>
<div id="editor">
<div id="flDebugEditor">
<textarea name="{{ templates[0].name }}" id="code">{{ templates[0].source }}</textarea>
</div>
<div id="splitter"></div>
<div id="flDebugSplitter"></div>
</div>
<iframe id="preview"></iframe>
<iframe id="flDebugPreview"></iframe>
<script src="{{ static_path }}codemirror/codemirror.js"></script>
<script src="{{ static_path }}codemirror/util/closetag.js"></script>
@@ -68,11 +68,11 @@
<script src="{{ static_path }}codemirror/mode/htmlmixed/htmlmixed.js"></script>
<script src="{{ static_path }}codemirror/mode/jinja2/jinja2.js"></script>
<script>{% raw %}
$('#drag-handler')
$('#flDebugDragHandler')
.mousemove(function(e) {
var size = 100 * e.pageX / $(document).width();
$('#panel').css('width', size + '%');
$('#preview').css('width', (100 - size) + '%');
$('#flDebugPanel').css('width', size + '%');
$('#flDebugPreview').css('width', (100 - size) + '%');
return false;
})
.mouseup(function(e) {
@@ -82,12 +82,12 @@
return false;
});
$('#splitter').mousedown(function() {
$('#drag-handler').show();
$('#flDebugSplitter').mousedown(function() {
$('#flDebugDragHandler').show();
return false;
});
$('#save').click(function() {
$('#flDebugSave').click(function() {
$.ajax({
type: 'POST'
, url: document.baseURI + '/save'
@@ -95,7 +95,7 @@
});
});
$('#close').click(function() {
$('#flDebugClose').click(function() {
document.location = document.location;
});
@@ -117,7 +117,7 @@
}
});
var previewFrame = document.getElementById('preview');
var previewFrame = document.getElementById('flDebugPreview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
var errorLine = null;

View File

@@ -5,7 +5,7 @@
<body>
<h1>Redirect ({{ redirect_code }})</h1>
<p>Location: <a href="{{ redirect_to }}">{{ redirect_to }}</a></p>
<p class="notice">
<p class="flDebugNotice">
The Flask Debug Toolbar has intercepted a redirect to the above URL for
debug viewing purposes. You can click the above link to continue with the
redirect as normal. If you'd like to disable this feature, you can set the

View File

@@ -1,6 +1,8 @@
import itertools
import os.path
import sys
import io
import gzip
try:
from pygments import highlight
@@ -83,3 +85,14 @@ def format_sql(query, args):
query,
SqlLexer(),
HtmlFormatter(noclasses=True, style=PYGMENT_STYLE)))
def gzip_compress(data, compresslevel=6):
buff = io.BytesIO()
with gzip.GzipFile(fileobj=buff, mode='wb', compresslevel=compresslevel) as f:
f.write(data)
return buff.getvalue()
def gzip_decompress(data):
with gzip.GzipFile(fileobj=io.BytesIO(data), mode='rb') as f:
return f.read()

6
pyproject.toml Normal file
View File

@@ -0,0 +1,6 @@
[build-system]
requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"

View File

@@ -1,2 +1,35 @@
[bdist_wheel]
universal=1
[metadata]
name = Flask-DebugToolbar
version = 0.12.1
author = Michael van Tellingen
author_email = michaelvantellingen@gmail.com
maintainer = Matt Good
maintainer_email = matt@matt-good.net
description = A toolbar overlay for debugging Flask applications.
long_description = file: README.rst
long_description_content_type = text/x-rst
keywords = flask, debug, toolbar
url = https://github.com/flask-debugtoolbar/flask-debugtoolbar
project_urls =
Changelog = https://github.com/flask-debugtoolbar/flask-debugtoolbar/blob/master/CHANGES.rst
Documentation = https://flask-debugtoolbar.readthedocs.io/
classifiers =
Development Status :: 4 - Beta
Environment :: Web Environment
Framework :: Flask
Intended Audience :: Developers
License :: OSI Approved :: BSD License
Operating System :: OS Independent
Programming Language :: Python
Topic :: Internet :: WWW/HTTP :: Dynamic Content
Topic :: Software Development :: Libraries :: Python Modules
[options]
packages = find:
package_dir = = flask_debugtoolbar
include_package_data = True
python_requires = >=2.7
# Dependencies are in setup.py for GitHub's dependency graph.
[options.packages.find]
where = flask_debugtoolbar

View File

@@ -1,48 +1,12 @@
import os
from setuptools import setup
here = os.path.abspath(os.path.dirname(__file__))
try:
README = open(os.path.join(here, 'README.rst')).read()
CHANGES = open(os.path.join(here, 'CHANGES.rst')).read()
except:
README = ''
CHANGES = ''
# Metadata goes in setup.cfg. These are here for GitHub's dependency graph.
setup(
name='Flask-DebugToolbar',
version='0.10.1',
url='https://flask-debugtoolbar.readthedocs.io/',
license='BSD',
author='Michael van Tellingen',
author_email='michaelvantellingen@gmail.com',
maintainer='Matt Good',
maintainer_email='matt@matt-good.net',
description='A toolbar overlay for debugging Flask applications.',
long_description=README + '\n\n' + CHANGES,
zip_safe=False,
platforms='any',
include_package_data=True,
packages=['flask_debugtoolbar',
'flask_debugtoolbar.panels'
],
name="Flask-DebugToolbar",
install_requires=[
'Flask>=0.8',
'Blinker',
'itsdangerous',
'werkzeug',
],
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
'Topic :: Software Development :: Libraries :: Python Modules'
]
)

View File

@@ -5,9 +5,11 @@ from flask_debugtoolbar import DebugToolbarExtension
app = Flask('basic_app')
app.debug = True
app.config['SECRET_KEY'] = 'abc123'
# TODO: This can be removed once flask_sqlalchemy 3.0 ships
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# make sure these are printable in the config panel
app.config['BYTES_VALUE'] = b'\x00'
app.config['UNICODE_VALUE'] = u'\uffff'
@@ -21,12 +23,12 @@ class Foo(db.Model):
id = db.Column(db.Integer, primary_key=True)
@app.before_first_request
def setup():
db.create_all()
@app.route('/')
def index():
db.create_all()
Foo.query.filter_by(id=1).all()
return render_template('basic_app.html')
if __name__ == '__main__':
app.run()

6
test/conftest.py Normal file
View File

@@ -0,0 +1,6 @@
import pytest
@pytest.fixture(autouse=True)
def mock_env_development(monkeypatch):
monkeypatch.setenv("FLASK_ENV", "development")

10
tox.ini
View File

@@ -1,5 +1,5 @@
[tox]
envlist = py27,py36,stylecheck
envlist = py27,py36,py37,py38,stylecheck
[testenv]
deps =
@@ -7,13 +7,13 @@ deps =
Flask-SQLAlchemy
Pygments
commands =
py.test
pytest
[testenv:stylecheck]
deps =
flake8
pycodestyle
commands =
flake8 flask_debugtoolbar test
pycodestyle flask_debugtoolbar test
[flake8]
[pycodestyle]
max-line-length = 100