py4web-debug-tools 1.1.4__tar.gz → 1.2.1__tar.gz

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.
Files changed (21) hide show
  1. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/.gitignore +2 -1
  2. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/CHANGELOG.md +10 -0
  3. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/PKG-INFO +3 -3
  4. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/pyproject.toml +2 -2
  5. py4web_debug_tools-1.2.1/src/py4web_debug/__about__.py +1 -0
  6. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/core.py +4 -4
  7. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/debugbar.py +1 -2
  8. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/dumping.py +10 -20
  9. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/internals.py +26 -5
  10. py4web_debug_tools-1.2.1/src/py4web_debug/types.py +50 -0
  11. py4web_debug_tools-1.1.4/src/py4web_debug/__about__.py +0 -1
  12. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/README.md +0 -0
  13. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/__init__.py +0 -0
  14. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/_internals.py +0 -0
  15. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/env.py +0 -0
  16. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/py.typed +0 -0
  17. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/templates/debugbar.html +0 -0
  18. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/templates/dumpdie.html +0 -0
  19. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/templates/error_default.html +0 -0
  20. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/templates/fancy_dumpdie.html +0 -0
  21. {py4web_debug_tools-1.1.4 → py4web_debug_tools-1.2.1}/src/py4web_debug/wsgi.py +0 -0
@@ -4,4 +4,5 @@ apps
4
4
  build
5
5
  dist
6
6
  *.egg-info
7
- .idea
7
+ .idea
8
+ .env
@@ -2,6 +2,16 @@
2
2
 
3
3
  <!--next-version-placeholder-->
4
4
 
5
+ ## v1.2.1 (2024-11-20)
6
+
7
+ ### Fix
8
+
9
+ * Allow logger to be set to False in case you're using py4webs default logger (PY4WEB_ERRORLOG=:stderr) ([`43639f3`](https://github.com/trialandsuccess/py4web-debug-tools/commit/43639f377d92b2f8b96bbdb31f61251fde95f831))
10
+
11
+ ## v1.2.0 (2023-11-06)
12
+ ### Feature
13
+ * Allow custom `error_logger` for tools.enable ([`a8301bc`](https://github.com/trialandsuccess/py4web-debug-tools/commit/a8301bc1762984fc5af420075acdc09e97bcc378))
14
+
5
15
  ## v1.1.4 (2023-07-19)
6
16
 
7
17
 
@@ -1,12 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: py4web-debug-tools
3
- Version: 1.1.4
3
+ Version: 1.2.1
4
4
  Summary: Debug Tools for py4web
5
5
  Project-URL: Documentation, https://github.com/trialandsuccess/py4web-debug-tools#readme
6
6
  Project-URL: Issues, https://github.com/trialandsuccess/py4web-debug-tools/issues
7
7
  Project-URL: Source, https://github.com/trialandsuccess/py4web-debug-tools
8
8
  Author-email: Robin van der Noord <contact@trialandsuccess.nl>
9
- License-Expression: MIT
9
+ License: MIT
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Programming Language :: Python
12
12
  Classifier: Programming Language :: Python :: 3.10
@@ -110,7 +110,9 @@ exclude = ["venv", ".bak"]
110
110
  [tool.ruff]
111
111
  target-version = "py311"
112
112
  line-length = 120
113
+ extend-exclude = ["*.bak/", "venv*/"]
113
114
 
115
+ [tool.ruff.lint]
114
116
  select = [
115
117
  "F", # pyflake error
116
118
  "E", # pycodestyle error
@@ -129,8 +131,6 @@ unfixable = [
129
131
  # Don't touch unused imports
130
132
  "F401",
131
133
  ]
132
- extend-exclude = ["*.bak/", "venv*/"]
133
-
134
134
  ignore = [
135
135
  "RUF013" # implicit Optional
136
136
  ]
@@ -0,0 +1 @@
1
+ __version__ = "1.2.1"
@@ -7,7 +7,7 @@ from py4web import DAL as P4WDAL
7
7
 
8
8
  from .debugbar import DebugBar, DummyDebugBar
9
9
  from .env import is_debug
10
- from .internals import T_Renderer, patch_py4
10
+ from .internals import T_Logger, T_Renderer, patch_py4
11
11
 
12
12
 
13
13
  @dataclass
@@ -45,6 +45,8 @@ class DebugTools:
45
45
  # error screen settings:
46
46
  errorpage_enabled: bool = None, # value of 'enabled' is used by default
47
47
  errorpage_renderer: T_Renderer = None,
48
+ # can be set to False to disable (e.g. when using PY4WEB_ERRORLOG: ":stderr"):
49
+ error_logger: T_Logger | typing.Literal[False] | None = None,
48
50
  # debugbar settings:
49
51
  debugbar_enabled: bool = None, # value of 'enabled' is used by default
50
52
  debugbar_fancy_rendering: bool = True,
@@ -53,8 +55,6 @@ class DebugTools:
53
55
  ) -> None:
54
56
  """
55
57
  By default, on_off looks at PY4WEB_DEBUG_MODE in the env
56
-
57
- @todo: debugbar style (bootstrap/default, bulma, ...)
58
58
  """
59
59
  if enabled is None:
60
60
  enabled = is_debug()
@@ -73,7 +73,7 @@ class DebugTools:
73
73
 
74
74
  if enabled:
75
75
  if self.config.errorpage.enabled:
76
- patch_py4(errorpage_renderer)
76
+ patch_py4(errorpage_renderer, error_logger)
77
77
 
78
78
  if self.config.debugbar.enabled:
79
79
  if not db:
@@ -160,8 +160,7 @@ def convert_for_debugbar(value: typing.Any) -> str:
160
160
  return _prune_long_values(value)
161
161
 
162
162
 
163
- class DummyDebugBar(TypedFixture):
164
- ...
163
+ class DummyDebugBar(TypedFixture): ...
165
164
 
166
165
 
167
166
  class DebugBar(TypedFixture):
@@ -10,35 +10,25 @@ from .env import is_debug
10
10
 
11
11
 
12
12
  class PossiblyAsDict(typing.Protocol):
13
- def as_dict(self) -> dict[str, typing.Any]:
14
- ...
13
+ def as_dict(self) -> dict[str, typing.Any]: ...
15
14
 
16
- def asdict(self) -> dict[str, typing.Any]:
17
- ...
15
+ def asdict(self) -> dict[str, typing.Any]: ...
18
16
 
19
- def _asdict(self) -> dict[str, typing.Any]:
20
- ...
17
+ def _asdict(self) -> dict[str, typing.Any]: ...
21
18
 
22
- def _as_dict(self) -> dict[str, typing.Any]:
23
- ...
19
+ def _as_dict(self) -> dict[str, typing.Any]: ...
24
20
 
25
- def to_dict(self) -> dict[str, typing.Any]:
26
- ...
21
+ def to_dict(self) -> dict[str, typing.Any]: ...
27
22
 
28
- def todict(self) -> dict[str, typing.Any]:
29
- ...
23
+ def todict(self) -> dict[str, typing.Any]: ...
30
24
 
31
- def _todict(self) -> dict[str, typing.Any]:
32
- ...
25
+ def _todict(self) -> dict[str, typing.Any]: ...
33
26
 
34
- def _to_dict(self) -> dict[str, typing.Any]:
35
- ...
27
+ def _to_dict(self) -> dict[str, typing.Any]: ...
36
28
 
37
- def __json__(self) -> dict[str, typing.Any]:
38
- ...
29
+ def __json__(self) -> dict[str, typing.Any]: ...
39
30
 
40
- def as_list(self) -> list[typing.Any]:
41
- ...
31
+ def as_list(self) -> list[typing.Any]: ...
42
32
 
43
33
 
44
34
  class DDJsonEncoder(ConfigurableJsonEncoder):
@@ -22,6 +22,8 @@ from py4web.core import (
22
22
  from typing_extensions import NotRequired
23
23
  from yatl import XML
24
24
 
25
+ from .types import ErrorSnapshot
26
+
25
27
 
26
28
  class ContextDict(typing.TypedDict):
27
29
  code: int
@@ -48,7 +50,7 @@ def custom_error_page(
48
50
  message: str = None,
49
51
  traceback: str = "",
50
52
  err_type: str | typing.Type[Exception] | None = None,
51
- bare_exception: Exception | str = None,
53
+ bare_exception: typing.Optional[Exception | str] = None,
52
54
  renderer: T_Renderer = None,
53
55
  ) -> str:
54
56
  if err_type and not isinstance(err_type, str):
@@ -108,11 +110,23 @@ def custom_error_page(
108
110
  return typing.cast(str, result)
109
111
 
110
112
 
113
+ def default_error_logger(snapshot: ErrorSnapshot) -> None:
114
+ logging.error(snapshot["traceback"])
115
+
116
+
117
+ T_Logger = typing.Callable[[ErrorSnapshot], None]
118
+
119
+
111
120
  class patch_py4:
112
121
  # THIS IS ONLY CALLED ONCE, WHEN tools.enable IS CALLED OR py4web_debug.wsgi IS USED!
113
122
  renderer: T_Renderer | None = None
123
+ logger: T_Logger | typing.Literal[False] | None = None
124
+
125
+ def __init__(self, renderer: T_Renderer = None, logger: T_Logger | bool | None = None):
126
+ if logger is True:
127
+ # use default logger:
128
+ logger = None
114
129
 
115
- def __init__(self, renderer: T_Renderer = None):
116
130
  def custom_catch_errors(app_name: str, func: AnyFunc) -> typing.Callable[..., str]:
117
131
  """Catches and logs errors in an action; also sets request.app_name"""
118
132
 
@@ -136,14 +150,19 @@ class patch_py4:
136
150
  except bottle.HTTPResponse:
137
151
  raise
138
152
  except Exception as e:
153
+ err_code = 500
139
154
  snapshot = get_error_snapshot()
140
- logging.error(snapshot["traceback"])
155
+ if self.logger is not False:
156
+ # False - don't log
157
+ # None - default logger
158
+ (self.logger or default_error_logger)(snapshot)
159
+
141
160
  ticket_uuid = error_logger.log(request.app_name, snapshot) or "unknown"
142
- response.status = 500
161
+ response.status = err_code
143
162
 
144
163
  raise bottle.HTTPResponse(
145
164
  body=custom_error_page(
146
- 500,
165
+ err_code,
147
166
  button_text=ticket_uuid,
148
167
  href=f"/_dashboard/ticket/{ticket_uuid}",
149
168
  traceback=tb.format_exc(),
@@ -162,3 +181,5 @@ class patch_py4:
162
181
 
163
182
  # allows swapping renderer on the fly with tools.set_renderer():
164
183
  patch_py4.renderer = renderer
184
+ _logger = getattr(patch_py4, "logger", None) or logger
185
+ patch_py4.logger = staticmethod(_logger) if _logger else None
@@ -0,0 +1,50 @@
1
+ from typing import TypedDict
2
+
3
+
4
+ class SystemInfo(TypedDict):
5
+ machine: str
6
+ node: str
7
+ platform: str
8
+ processor: str
9
+ python_branch: str
10
+ python_build: tuple[str, str]
11
+ python_compiler: str
12
+ python_implementation: str
13
+ python_revision: str
14
+ python_version: str
15
+ python_version_tuple: tuple[str, str, str]
16
+ release: str
17
+ system: str
18
+ uname: tuple[str, str, str, str, str]
19
+
20
+
21
+ class OsEnviron(TypedDict):
22
+ SHELL: str
23
+ SESSION_MANAGER: str
24
+ QT_ACCESSIBILITY: str
25
+ # ... (other key-value pairs)
26
+
27
+
28
+ class StackFrame(TypedDict):
29
+ file: str
30
+ func: str
31
+ lnum: int
32
+ code: list[str]
33
+
34
+
35
+ class Traceback(TypedDict):
36
+ file: str
37
+ func: str
38
+ lnum: int
39
+ code: list[str]
40
+
41
+
42
+ class ErrorSnapshot(TypedDict):
43
+ timestamp: str
44
+ python_version: str
45
+ platform_info: SystemInfo
46
+ os_environ: OsEnviron
47
+ traceback: str
48
+ exception_type: str
49
+ exception_value: str
50
+ stackframes: list[StackFrame]
@@ -1 +0,0 @@
1
- __version__ = "1.1.4"