pyramid-debugtoolbar-api-performance 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
+ # type: from pyramid.config import Configurator
2
+ from ._version import __VERSION__
3
+
4
+
5
+ # ==============================================================================
6
+
7
+
8
+ def includeme(config):
9
+ # type: (Configurator) -> None
10
+ """Register the CSV panel and routes with the debug toolbar."""
11
+ # Older setuptools imports this package to read its version at build time.
12
+ from .panels import PerformanceCsvDebugPanel
13
+
14
+ config.add_debugtoolbar_panel(PerformanceCsvDebugPanel)
15
+ config.add_route(
16
+ "debugtoolbar.api_performance_csv.function_calls",
17
+ "/api-performance/function_calls-{request_id}.csv",
18
+ )
19
+ config.add_route(
20
+ "debugtoolbar.api_performance_csv.timing",
21
+ "/api-performance/timing-{request_id}.csv",
22
+ )
23
+ config.scan("pyramid_debugtoolbar_api_performance.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,69 @@
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_performance_panel
14
+
15
+ # ==============================================================================
16
+
17
+
18
+ _ = lambda x: x
19
+
20
+
21
+ class PerformanceCsvDebugPanel(DebugPanel):
22
+ """
23
+ Panel that displays a link to Performance downloads
24
+ """
25
+
26
+ name = "performance-csv"
27
+ template = "pyramid_debugtoolbar_api_performance:templates/performance_csv.dbtmako"
28
+ title = _("Performance CSV")
29
+ nav_title = _("Performance 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 _performance_panel(self):
37
+ # utility for when we can't explicitly access the request
38
+ request = get_current_request()
39
+ performance_panel = get_performance_panel(request.toolbar_panels.values())
40
+ return performance_panel
41
+
42
+ @property
43
+ def has_content(self):
44
+ performance_panel = self._performance_panel
45
+ if performance_panel and performance_panel.data:
46
+ return True
47
+ return False
48
+
49
+ @property
50
+ def nav_subtitle(self):
51
+ return ""
52
+
53
+ def render_content(self, request):
54
+ performance_panel = get_performance_panel(request.toolbar_panels.values())
55
+ if not performance_panel:
56
+ return "No `performance` panel in request."
57
+ if not performance_panel.data:
58
+ return "No data in executed in request."
59
+ # our template might want to reference this for button visibility
60
+ self.data = performance_panel.data
61
+ return super(PerformanceCsvDebugPanel, self).render_content(request)
62
+
63
+ def render_vars(self, request):
64
+ return {
65
+ "route_url": request.route_url,
66
+ "static_path": request.static_url(STATIC_PATH),
67
+ "root_path": request.route_url(ROOT_ROUTE_NAME),
68
+ "pdtb_id": self.pdtb_id,
69
+ }
@@ -0,0 +1,31 @@
1
+ <p>
2
+ performance logging is available for this request as a CSV via the link below:
3
+ </p>
4
+
5
+
6
+ <h5>Timing</h5>
7
+ <p>
8
+ <a href="/_debug_toolbar/api-performance/timing-${pdtb_id}.csv"
9
+ class="btn btn-primary"
10
+ >
11
+ <span class="glyphicon glyphicon-download" aria-hidden="true"></span>
12
+ &nbsp;
13
+ Download Timing as CSV
14
+ </a>
15
+ </p>
16
+ <hr/>
17
+
18
+ <h5>Function Calls</h5>
19
+ <p>
20
+ % if stats:
21
+ <a href="/_debug_toolbar/api-performance/function_calls-${pdtb_id}.csv"
22
+ class="btn btn-primary"
23
+ >
24
+ <span class="glyphicon glyphicon-download" aria-hidden="true"></span>
25
+ &nbsp;
26
+ Download Function Calls as CSV
27
+ </a>
28
+ % else:
29
+ The profiler was not activated for this request. Activate the checkbox in the toolbar to use it.
30
+ % endif
31
+ </p>
@@ -0,0 +1,13 @@
1
+ # pyramid_debugtoolbar
2
+ from pyramid_debugtoolbar.panels.performance import PerformanceDebugPanel
3
+
4
+
5
+ # ==============================================================================
6
+
7
+
8
+ def get_performance_panel(toolbar_panels):
9
+ # PY3 - `toolbar_panels` is a view, not a list
10
+ for panel in toolbar_panels:
11
+ if isinstance(panel, PerformanceDebugPanel):
12
+ return panel
13
+ return None
@@ -0,0 +1,98 @@
1
+ # stdlib
2
+ import csv
3
+ import os
4
+ import re
5
+
6
+ # pyramid
7
+ from pyramid.response import Response
8
+
9
+ from pyramid.request import Request
10
+ from pyramid_debugtoolbar.panels.performance import PerformanceDebugPanel
11
+ from pyramid.view import view_config
12
+ from pyramid.exceptions import NotFound
13
+
14
+ # Python 2's csv module requires a byte buffer.
15
+ from six import StringIO
16
+
17
+ # local
18
+ from .utils import get_performance_panel
19
+
20
+
21
+ # encoding used to write filedata
22
+ ENCODING = os.environ.get("pyramid_debugtoolbar_api_sqlalchemy_encoding", "utf-8")
23
+
24
+
25
+ # ==============================================================================
26
+
27
+
28
+ def _standardized_setup(request):
29
+ # type: (Request) -> tuple[str, PerformanceDebugPanel]
30
+ """Resolve the performance panel for the requested history entry."""
31
+ request_id = request.matchdict["request_id"]
32
+ toolbar = request.pdtb_history.get(request_id, None)
33
+ if toolbar is None:
34
+ raise NotFound
35
+
36
+ panel = get_performance_panel(toolbar.panels)
37
+ if panel is None or not panel.data:
38
+ raise NotFound
39
+
40
+ return request_id, panel
41
+
42
+
43
+ def _csv_response(csvfile, report, request_id):
44
+ # type: (StringIO, str, str) -> Response
45
+ """Return a CSV attachment with a header-safe filename."""
46
+ safe_id = re.sub(r"[^a-zA-Z0-9_-]", "_", request_id)
47
+ filename = "performance-%s-%s.csv" % (report, safe_id)
48
+ response = Response(
49
+ content_type="text/csv", body=csvfile.getvalue(), charset=ENCODING
50
+ )
51
+ response.headers["Content-Disposition"] = str('attachment; filename="%s"' % filename)
52
+ response.cache_control.no_store = True
53
+ return response
54
+
55
+
56
+ @view_config(route_name="debugtoolbar.api_performance_csv.timing")
57
+ def csv_timing(request):
58
+ # type: (Request) -> Response
59
+ """Export timing rows for a recorded request."""
60
+ (request_id, panel) = _standardized_setup(request)
61
+
62
+ csvfile = StringIO()
63
+ csvwriter = csv.writer(csvfile)
64
+ for row in panel.data["timing_rows"]:
65
+ # row is `label, timing`
66
+ # example:
67
+ # 'timing_rows': (('User CPU time', '119.678 msec'),
68
+ # ('System CPU time', '64.695 msec'),
69
+ # ('Total CPU time', '184.373 msec'),
70
+ # ('Elapsed time', '205.099 msec'),
71
+ # ('Context switches', '19 voluntary, 1233 involuntary')
72
+ # )
73
+ csvwriter.writerow(row)
74
+ return _csv_response(csvfile, "timing", request_id)
75
+
76
+
77
+ @view_config(route_name="debugtoolbar.api_performance_csv.function_calls")
78
+ def csv_function_calls(request):
79
+ # type: (Request) -> Response
80
+ """Export profiler rows for a recorded request."""
81
+ (request_id, panel) = _standardized_setup(request)
82
+
83
+ csvfile = StringIO()
84
+ csvwriter = csv.writer(csvfile)
85
+ if panel.data["stats"]:
86
+ csvwriter.writerow(("Calls", "Total", "Percall", "Cumu", "CumuPer", "Func"))
87
+ for row in panel.data["function_calls"]:
88
+ csvwriter.writerow(
89
+ (
90
+ row["ncalls"],
91
+ row["tottime"],
92
+ row["percall"],
93
+ row["cumtime"],
94
+ row["percall_cum"],
95
+ row["filename_long"],
96
+ )
97
+ )
98
+ return _csv_response(csvfile, "function_calls", request_id)
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyramid_debugtoolbar_api_performance
3
+ Version: 1.0.0
4
+ Summary: performance csv exporting for pyramid_debugtoolbar
5
+ Home-page: https://github.com/jvanasco/pyramid_debugtoolbar_api_performance
6
+ Author: Jonathan Vanasco
7
+ Author-email: jvanasco@2xlp.com
8
+ License: MIT
9
+ Keywords: web,pyramid
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: setuptools<82; python_version >= "3.7" and python_version < "3.10"
32
+ Provides-Extra: testing
33
+ Requires-Dist: coverage; extra == "testing"
34
+ Requires-Dist: pytest; extra == "testing"
35
+ Dynamic: license-file
36
+
37
+ pyramid_debugtoolbar_api_performance
38
+ ====================================
39
+
40
+ .. image:: https://github.com/jvanasco/pyramid_debugtoolbar_api_performance/workflows/Python%20package/badge.svg
41
+ :alt: Build Status
42
+
43
+ `pyramid_debugtoolbar_api_performance` extends the existing `pyramid_debugtoolbar`
44
+ Performance Panel to support downloadable CSV files of profiling data.
45
+
46
+ This package does not replace the default panel, and requires it to be active.
47
+
48
+ This package is designed for application profile and to be a useful part of test
49
+ suites, allowing developers to run a series of tests and log the Performance
50
+ performance.
51
+
52
+ The package exposes two routes for CSV data:
53
+
54
+ * timing
55
+ * function_calls
56
+
57
+ Both correlate to the official Performance panel data.
58
+
59
+ The urls are generated in a machine-friendly format, so you can regex the
60
+ `request_id` off a page and pull it from the API. This is explained below...
61
+
62
+
63
+ NOTES:
64
+ ======
65
+
66
+ This packages requires pyramid_debugtoolbar 4.0 or newer
67
+
68
+
69
+ How to use this package
70
+ =======================
71
+
72
+
73
+ Update your ENVIRONMENT.ini file
74
+
75
+ .. code-block:: python
76
+
77
+ debugtoolbar.includes = pyramid_debugtoolbar_api_performance
78
+
79
+ You MUST be using `pyramid_debugtoolbar` with the Performance panel enabled.
80
+ This package simply piggybacks on the existing module's work to log queries.
81
+
82
+ You MUST use `debugtoolbar.includes`. This will not work properly via `pyramid.includes`
83
+
84
+ You can access a csv of the Profiling report via the following url hack:
85
+
86
+ .. code-block:: python
87
+
88
+ url_html = '/_debug_toolbar/{request_id}'
89
+ url_api = '/_debug_toolbar/api-performance/timing-{request_id}.csv'
90
+ url_api = '/_debug_toolbar/api-performance/function_calls-{request_id}.csv'
91
+
92
+
93
+ The file will be downloaded and offer a content-disposition as:
94
+
95
+ .. code-block:: shell
96
+
97
+ performance-{request_id}.csv
98
+
99
+ Configuration
100
+ =======================
101
+
102
+ By default, this package writes CSV files using "UTF-8" encoding.
103
+
104
+ To change this, use the environment variable `pyramid_debugtoolbar_api_performance_encoding`
105
+
106
+ .. code-block:: shell
107
+
108
+ export pyramid_debugtoolbar_api_performance_encoding=ascii
@@ -0,0 +1,11 @@
1
+ pyramid_debugtoolbar_api_performance/__init__.py,sha256=mjD0CY3hHFFQ-0ymF0CYSUwCTS9IudmIH7iE8LLxjdA,925
2
+ pyramid_debugtoolbar_api_performance/_version.py,sha256=PSFTHx0_-pj-uJ6XCRWQ4yUYRx0g1iTOGcVOTVJLZx4,83
3
+ pyramid_debugtoolbar_api_performance/panels.py,sha256=i17kEMiWRdp_WhQ6ifBIP5qCwcnFM-9I6NqG2Sj88vw,2184
4
+ pyramid_debugtoolbar_api_performance/utils.py,sha256=0IOvkGZaZ6L4ONSFZ4-jxbjLrbFdVodlmkapKXAtcJM,403
5
+ pyramid_debugtoolbar_api_performance/views.py,sha256=D-CMrpihXs8HiEgz-OFIMy-Bjgdp15qX2m4LEE2-Rl8,3284
6
+ pyramid_debugtoolbar_api_performance/templates/performance_csv.dbtmako,sha256=lsCQMT-mnmtXN_LklD10vbbZFhh-_lbxc7zKIEdxQgM,726
7
+ pyramid_debugtoolbar_api_performance-1.0.0.dist-info/licenses/LICENSE,sha256=C8rdTK7bsKZPlhmxryyAmq-_MWb71oIl8QodzMeyF2E,1076
8
+ pyramid_debugtoolbar_api_performance-1.0.0.dist-info/METADATA,sha256=tWO2ghv0KS75kHS4O6yI6NH9TMgktt0FPpiqan889co,3567
9
+ pyramid_debugtoolbar_api_performance-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
10
+ pyramid_debugtoolbar_api_performance-1.0.0.dist-info/top_level.txt,sha256=g7tWBwH3nHGxZXkzZ5g5__TuCJHNEBVbyB9SL3OUFxY,37
11
+ pyramid_debugtoolbar_api_performance-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) 2017 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_performance