pyramid-debugtoolbar-api-sqlalchemy 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ from ._version import __VERSION__
2
+
3
+
4
+ # ==============================================================================
5
+
6
+
7
+ def includeme(config):
8
+ """
9
+ Pyramid hook to install this debugtoolbar plugin.
10
+
11
+ Update your ENVIRONMENT.ini file
12
+
13
+ debugtoolbar.includes = pyramid_debugtoolbar_api_sqlalchemy
14
+ """
15
+ # Legacy setuptools imports this package to discover the version.
16
+ from .panels import SqlalchemyCsvDebugPanel
17
+
18
+ config.add_debugtoolbar_panel(SqlalchemyCsvDebugPanel)
19
+ config.add_route(
20
+ "debugtoolbar.api_sqlalchemy.queries.csv",
21
+ "/api-sqlalchemy/sqlalchemy-{request_id}.csv",
22
+ )
23
+ config.scan("pyramid_debugtoolbar_api_sqlalchemy.views")
24
+ config.commit()
25
+
26
+
27
+ # ==============================================================================
@@ -0,0 +1,3 @@
1
+ """Package version shared by runtime and build metadata."""
2
+
3
+ __VERSION__ = "1.0.0"
@@ -0,0 +1,72 @@
1
+ # stdlib
2
+
3
+ # pyramid
4
+ from pyramid.threadlocal import get_current_request
5
+ from pyramid.decorator import reify
6
+
7
+ # pyramid_debugtoolbar
8
+ from pyramid_debugtoolbar.panels import DebugPanel
9
+ from pyramid_debugtoolbar.utils import STATIC_PATH
10
+ from pyramid_debugtoolbar.utils import ROOT_ROUTE_NAME
11
+
12
+ # local
13
+ from .utils import get_sqlalchemy_panel
14
+
15
+ # ==============================================================================
16
+
17
+
18
+ _ = lambda x: x
19
+
20
+
21
+ class SqlalchemyCsvDebugPanel(DebugPanel):
22
+ """
23
+ Panel that displays a link to SQLACSV download
24
+ """
25
+
26
+ name = "sqlalchemy-csv"
27
+ template = "pyramid_debugtoolbar_api_sqlalchemy:templates/sqlalchemy_csv.dbtmako"
28
+ title = _("SQLAlchemy Queries CSV")
29
+ nav_title = _("SQLAlchemy CSV")
30
+
31
+ def __init__(self, original_request):
32
+ self.token = original_request.registry.pdtb_token
33
+ self.pdtb_id = original_request.pdtb_id
34
+
35
+ @reify
36
+ def _sqlalchemy_panel(self):
37
+ # utility for when we can't explicitly access the request
38
+ request = get_current_request()
39
+ sqlalchemy_panel = get_sqlalchemy_panel(request.toolbar_panels.values())
40
+ return sqlalchemy_panel
41
+
42
+ @property
43
+ def has_content(self):
44
+ sqlalchemy_panel = self._sqlalchemy_panel
45
+ if sqlalchemy_panel and sqlalchemy_panel.queries:
46
+ return True
47
+ return False
48
+
49
+ @property
50
+ def nav_subtitle(self):
51
+ sqlalchemy_panel = self._sqlalchemy_panel
52
+ if sqlalchemy_panel and sqlalchemy_panel.queries:
53
+ return len(sqlalchemy_panel.queries)
54
+ return ""
55
+
56
+ def render_content(self, request):
57
+ sqlalchemy_panel = get_sqlalchemy_panel(request.toolbar_panels.values())
58
+ if not sqlalchemy_panel:
59
+ return "No `sqlalchemy` panel in request."
60
+ if not sqlalchemy_panel.queries:
61
+ return "No queries in executed in request."
62
+ # our template might want to reference this for button visibility
63
+ self.data = sqlalchemy_panel.data
64
+ return super(SqlalchemyCsvDebugPanel, self).render_content(request)
65
+
66
+ def render_vars(self, request):
67
+ return {
68
+ "route_url": request.route_url,
69
+ "static_path": request.static_url(STATIC_PATH),
70
+ "root_path": request.route_url(ROOT_ROUTE_NAME),
71
+ "pdtb_id": self.pdtb_id,
72
+ }
@@ -0,0 +1,14 @@
1
+ """Helpers for exporting text fields to spreadsheet CSV files."""
2
+
3
+ from six import text_type
4
+
5
+
6
+ def sanitize_spreadsheet_cell(value):
7
+ # type: (text_type) -> text_type
8
+ """Prefix formula-like text with a spreadsheet text marker."""
9
+ stripped = value.lstrip()
10
+ if value.startswith((u"\t", u"\r", u"\n")) or stripped.startswith(
11
+ (u"=", u"+", u"-", u"@", u"\uff1d", u"\uff0b", u"\uff0d", u"\uff20")
12
+ ):
13
+ return u"'" + value
14
+ return value
@@ -0,0 +1,13 @@
1
+ <p>
2
+ SqlAclhemy queries are available for this request as a CSV via the link below:
3
+ </p>
4
+
5
+ <p>
6
+ <a href="/_debug_toolbar/api-sqlalchemy/sqlalchemy-${pdtb_id}.csv"
7
+ class="btn btn-primary"
8
+ >
9
+ <span class="glyphicon glyphicon-download" aria-hidden="true"></span>
10
+ &nbsp;
11
+ Download Queries as CSV
12
+ </a>
13
+ </p>
@@ -0,0 +1,13 @@
1
+ # pyramid_debugtoolbar
2
+ from pyramid_debugtoolbar.panels.sqla import SQLADebugPanel
3
+
4
+
5
+ # ==============================================================================
6
+
7
+
8
+ def get_sqlalchemy_panel(toolbar_panels):
9
+ # PY3 - `toolbar_panels` is a view, not a list
10
+ for panel in toolbar_panels:
11
+ if isinstance(panel, SQLADebugPanel):
12
+ return panel
13
+ return None
@@ -0,0 +1,60 @@
1
+ import csv
2
+ import os
3
+ import re
4
+
5
+ from pyramid.exceptions import NotFound
6
+ from pyramid.request import Request
7
+ from pyramid.response import Response
8
+ from pyramid.view import view_config
9
+ from six import PY2, StringIO, binary_type, text_type
10
+
11
+ from .spreadsheet_utils import sanitize_spreadsheet_cell
12
+ from .utils import get_sqlalchemy_panel
13
+
14
+
15
+ ENCODING = os.environ.get("pyramid_debugtoolbar_api_sqlalchemy_encoding", "utf-8")
16
+
17
+
18
+ @view_config(route_name="debugtoolbar.api_sqlalchemy.queries.csv")
19
+ def queries_api_csv(request):
20
+ # type: (Request) -> Response
21
+ """Export the recorded SQL queries for the requested toolbar entry."""
22
+ request_id = request.matchdict["request_id"]
23
+ toolbar = request.pdtb_history.get(request_id, None)
24
+ if toolbar is None:
25
+ raise NotFound
26
+
27
+ panel = get_sqlalchemy_panel(toolbar.panels)
28
+ if panel is None:
29
+ raise NotFound
30
+
31
+ spreadsheet = request.GET.get("spreadsheet") == "1"
32
+ csvfile = StringIO()
33
+ writer = csv.writer(csvfile)
34
+ for query in panel.data.get("queries", ()):
35
+ sql = query["raw_sql"]
36
+ parameters = query["parameters"]
37
+ if spreadsheet:
38
+ sql = sanitize_spreadsheet_cell(sql)
39
+ if parameters is not None:
40
+ if isinstance(parameters, binary_type):
41
+ parameters = parameters.decode(ENCODING, "replace")
42
+ else:
43
+ parameters = text_type(parameters)
44
+ parameters = sanitize_spreadsheet_cell(parameters)
45
+ if PY2:
46
+ parameters = parameters.encode(ENCODING)
47
+ if PY2:
48
+ sql = sql.encode(ENCODING)
49
+ writer.writerow((query["duration"], sql, parameters))
50
+
51
+ response = Response(
52
+ content_type="text/csv", body=csvfile.getvalue(), charset=ENCODING
53
+ )
54
+ safe_id = re.sub(r"[^a-zA-Z0-9_-]", "_", request_id)
55
+ suffix = "-spreadsheet" if spreadsheet else ""
56
+ response.headers["Content-Disposition"] = str(
57
+ 'attachment; filename="sqlalchemy-%s%s.csv"' % (safe_id, suffix)
58
+ )
59
+ response.cache_control.no_store = True
60
+ return response
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyramid_debugtoolbar_api_sqlalchemy
3
+ Version: 1.0.0
4
+ Summary: SQLAlchemy CSV exporting for pyramid_debugtoolbar
5
+ Home-page: https://github.com/jvanasco/pyramid_debugtoolbar_api_sqlalchemy
6
+ Author: Jonathan Vanasco
7
+ Author-email: jvanasco@2xlp.com
8
+ License: MIT
9
+ Keywords: web,pyramid,sqlalchemy
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Framework :: Pyramid
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 2.7
14
+ Classifier: Programming Language :: Python :: 3.5
15
+ Classifier: Programming Language :: Python :: 3.6
16
+ Classifier: Programming Language :: Python :: 3.7
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Programming Language :: Python :: 3.15
25
+ Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
26
+ Description-Content-Type: text/x-rst
27
+ License-File: LICENSE
28
+ Requires-Dist: pyramid
29
+ Requires-Dist: pyramid_debugtoolbar>=4.0
30
+ Requires-Dist: six
31
+ Requires-Dist: sqlalchemy
32
+ Requires-Dist: setuptools<82; python_version >= "3.7" and python_version < "3.10"
33
+ Provides-Extra: testing
34
+ Requires-Dist: coverage; extra == "testing"
35
+ Requires-Dist: pytest; extra == "testing"
36
+ Dynamic: license-file
37
+
38
+ pyramid_debugtoolbar_api_sqlalchemy
39
+ ===================================
40
+
41
+ .. image:: https://github.com/jvanasco/pyramid_debugtoolbar_api_sqlalchemy/workflows/Python%20package/badge.svg
42
+ :alt: Build Status
43
+
44
+ `pyramid_debugtoolbar_api_sqlalchemy` extends the existing `pyramid_debugtoolbar`
45
+ SQLAlchemy Panel to support downloadable CSV files of profiling data.
46
+
47
+ This package does not replace the default panel, and requires it to be active.
48
+
49
+ This package is designed for application profile and to be a useful part of test
50
+ suites, allowing developers to run a series of tests and log the SQLAlchemy
51
+ performance.
52
+
53
+ If you are using the debugtoolbar directly:
54
+
55
+ * If SQLAlchemy queries exist on the request, a "SQLAlchemy CSV" tab will appear.
56
+ That will prompt you for queries.
57
+
58
+ If you are scripting:
59
+
60
+ * The urls are generated in a machine-friendly format, so you can regex the
61
+ `request_id` off a page and pull it from the API. this is explained below:
62
+
63
+
64
+ NOTES:
65
+ ======
66
+
67
+ This packages requires pyramid_debugtoolbar 4.0 or newer
68
+
69
+
70
+ How to use this package
71
+ =======================
72
+
73
+
74
+ Update your ENVIRONMENT.ini file
75
+
76
+ .. code-block:: python
77
+
78
+ debugtoolbar.includes = pyramid_debugtoolbar_api_sqlalchemy
79
+
80
+ You MUST be using `pyramid_debugtoolbar` with the SQLAlchemy panel enabled.
81
+ This just piggybacks on the existing module's work to log queries.
82
+
83
+ You MUST use `debugtoolbar.includes`. This will not work properly via `pyramid.includes`
84
+
85
+ You can access a csv of the SQLAlchemy report via the following url hack:
86
+
87
+ .. code-block:: python
88
+
89
+ url_html = '/_debug_toolbar/{request_id}'
90
+ url_api = '/_debug_toolbar/api-sqlalchemy/sqlalchemy-{request_id}.csv'
91
+
92
+ The file will be downloaded and offer a content-disposition as:
93
+
94
+ sqlalchemy-{request_id}.csv
95
+
96
+ The CSV columns are:
97
+
98
+ * execution timing
99
+ * SQLAlchemy query
100
+ * query params (json encoded)
101
+
102
+
103
+ Configuration
104
+ =======================
105
+
106
+ By default, this package writes CSV files using "UTF-8" encoding.
107
+
108
+ To change this, use the environment variable `pyramid_debugtoolbar_api_sqlalchemy_encoding`
109
+
110
+ .. code-block:: shell
111
+
112
+ export pyramid_debugtoolbar_api_sqlalchemy_encoding=ascii
@@ -0,0 +1,12 @@
1
+ pyramid_debugtoolbar_api_sqlalchemy/__init__.py,sha256=y9FeEwP0dnQHpDyT8K73JDS7I-tbsJJvqM1psCKXbbc,795
2
+ pyramid_debugtoolbar_api_sqlalchemy/_version.py,sha256=PSFTHx0_-pj-uJ6XCRWQ4yUYRx0g1iTOGcVOTVJLZx4,83
3
+ pyramid_debugtoolbar_api_sqlalchemy/panels.py,sha256=bdKXgXCBTp4orunzdJ-WzS2AVp5KfbGgKParp0QXLGs,2331
4
+ pyramid_debugtoolbar_api_sqlalchemy/spreadsheet_utils.py,sha256=ORjcJdfiZRh8rIMBSGIT9vRdLxYZs2TM5NVoPA3Y3KY,467
5
+ pyramid_debugtoolbar_api_sqlalchemy/utils.py,sha256=Go4XfCMdwfkBnrBxur4J9c785d3TUt53QYwrMR_T8Rk,381
6
+ pyramid_debugtoolbar_api_sqlalchemy/views.py,sha256=BPqeuRtfjL8uCKcO5SP7F6RLcwpAksJ-48rL4L_FTDg,2105
7
+ pyramid_debugtoolbar_api_sqlalchemy/templates/sqlalchemy_csv.dbtmako,sha256=B9iZhinOYS6kwwsJvAsySP5BsGSX-qBs-bAcPF4B7Ak,312
8
+ pyramid_debugtoolbar_api_sqlalchemy-1.0.0.dist-info/licenses/LICENSE,sha256=q2DhemYY9D6Z_XL2IvP5QjkXi3KDIc_GRHwBBpAPX8c,1076
9
+ pyramid_debugtoolbar_api_sqlalchemy-1.0.0.dist-info/METADATA,sha256=KH0MFglpfEVnN6_E4y0uyuyOIY9cHIncrv-oG6mC-6c,3627
10
+ pyramid_debugtoolbar_api_sqlalchemy-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
11
+ pyramid_debugtoolbar_api_sqlalchemy-1.0.0.dist-info/top_level.txt,sha256=MGld_Ap4yJUAEtiX6vKEc_vZ1PmOvJ2VyKbkStUPWkY,36
12
+ pyramid_debugtoolbar_api_sqlalchemy-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 jvanasco
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1 @@
1
+ pyramid_debugtoolbar_api_sqlalchemy