pyweber 1.6.0.dev1__tar.gz → 1.6.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.
- {pyweber-1.6.0.dev1/pyweber.egg-info → pyweber-1.6.1}/PKG-INFO +14 -5
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/README.md +11 -3
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyproject.toml +5 -3
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/__init__.py +18 -1
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/connection/session.py +14 -3
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/connection/websocket.py +240 -122
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/core/element.py +21 -4
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/core/events.py +70 -7
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/core/template.py +68 -1
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/core/window.py +5 -2
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/element.py +11 -8
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/ws_message.py +18 -3
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/pyweber/pyweber.py +17 -3
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/config.toml +3 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/js.js +78 -4
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/security.py +78 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1/pyweber.egg-info}/PKG-INFO +14 -5
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/LICENSE +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/MANIFEST.in +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/NOTICE +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/admin/index.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/admin/src/script.js +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/admin/src/style.css +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/auth/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/auth/decorators.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/auth/passwords.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/auth/rbac.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/auth/session.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/cli/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/cli/commands.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/components/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/components/form.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/components/general.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/components/input.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/config/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/config/config.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/connection/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/connection/http.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/connection/reload.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/connection/selector.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/core/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/core/html_parser.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/cli.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/config.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/engine.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/model.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/query.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/db/session.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/context.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/cookies.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/create_app.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/dom_merge.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/error_pages.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/field.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/field_storage.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/file.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/file_stream.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/handoff.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/headers.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/middleware.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/openapi.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/rate_limit.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/request.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/response.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/routes.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/run.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/security.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/stream_stats.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/strem_stats.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/task_manager.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/models/template_diff.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/pyweber/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/services/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/services/openapi_setup.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/services/response_pipeline.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/services/static_files.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/services/template_service.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/session_store/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/.gitignore +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/css.css +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/docs.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/android-chrome-192x192.png +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/android-chrome-512x512.png +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/apple-touch-icon.png +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/favicon-16x16.png +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/favicon-32x32.png +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/favicon.ico +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/pyweber.png +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/favicon/site.webmanifest +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/handlers.js +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/html.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/html401.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/html404.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/html500.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/loading.html +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/main.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/pyweber.css +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/static/update.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/testing/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/testing/client.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/__init__.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/async_utils.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/deprecation.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/exceptions.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/icons.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/loads.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/mime.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/types.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber/utils/utils.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber.egg-info/SOURCES.txt +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber.egg-info/dependency_links.txt +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber.egg-info/entry_points.txt +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber.egg-info/requires.txt +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/pyweber.egg-info/top_level.txt +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/setup.cfg +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/tests/test_config.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/tests/test_context.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/tests/test_cookies.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/tests/test_public_api.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/tests/test_response.py +0 -0
- {pyweber-1.6.0.dev1 → pyweber-1.6.1}/tests/test_template_diff.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyweber
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.1
|
|
4
4
|
Summary: A lightweight Python framework for building and managing web applications.
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Pyweber Limitada <pypi.dev@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Documentation, https://pyweber.dev/
|
|
8
8
|
Project-URL: Source, https://github.com/pyweber/pyweber
|
|
@@ -10,6 +10,7 @@ Project-URL: Tracker, https://github.com/pyweber/pyweber/issues
|
|
|
10
10
|
Project-URL: PyPI, https://pypi.org/project/pyweber/
|
|
11
11
|
Project-URL: YouTube, https://youtube.com/@devpythonMZ
|
|
12
12
|
Project-URL: Examples, https://github.com/pyweber-examples
|
|
13
|
+
Project-URL: Security, https://pyweber.dev/guides/supported-versions/
|
|
13
14
|
Requires-Python: >=3.10
|
|
14
15
|
Description-Content-Type: text/markdown
|
|
15
16
|
License-File: LICENSE
|
|
@@ -55,17 +56,25 @@ Pyweber is a lightweight Python web framework designed to create dynamic, reacti
|
|
|
55
56
|
- **Intuitive DOM Manipulation**: Query and modify elements with familiar selectors
|
|
56
57
|
- **Event-Driven Programming**: Handle user interactions with Python event handlers
|
|
57
58
|
- **WebSocket Integration**: Real-time communication between client and server
|
|
58
|
-
- **Template Handoff (1.3.0)**: WebSocket sessions reuse the HTTP-rendered template — handlers are not executed twice on connect
|
|
59
|
+
- **Template Handoff (1.3.0+)**: WebSocket sessions reuse the HTTP-rendered template — handlers are not executed twice on connect
|
|
60
|
+
- **Identity-preserving sync (1.6.0+)**: `self` / subclass element refs stay valid after WS connect
|
|
61
|
+
- **Optional ORM & Redis sessions (1.6.0+)**: `pyweber[db]`, `pyweber[redis]`
|
|
62
|
+
- **Auth & RBAC (1.5+)**: signed login cookie, roles/permissions
|
|
59
63
|
- **Minimal Configuration**: Get started quickly with sensible defaults
|
|
60
64
|
|
|
61
65
|
## Quick Start
|
|
62
66
|
|
|
63
67
|
### Installation
|
|
64
68
|
|
|
69
|
+
!!! danger "Avoid ≤ 1.3.1"
|
|
70
|
+
Older lines are **not recommended** for production. Use a current release:
|
|
71
|
+
|
|
65
72
|
```bash
|
|
66
|
-
pip install pyweber
|
|
73
|
+
pip install -U 'pyweber>=1.6'
|
|
67
74
|
```
|
|
68
75
|
|
|
76
|
+
See [Supported versions](https://pyweber.dev/guides/supported-versions/) (docs) for yank / security notes. `pyproject.toml` cannot warn when someone pins an old wheel — that requires [PyPI yanking](https://docs.pypi.org/project-management/yanking/).
|
|
77
|
+
|
|
69
78
|
### Create a Project
|
|
70
79
|
|
|
71
80
|
```bash
|
|
@@ -262,7 +271,7 @@ pyweber add-section --section-name database
|
|
|
262
271
|
pyweber --update
|
|
263
272
|
```
|
|
264
273
|
|
|
265
|
-
Visit [Pyweber Docs](https://pyweber.dev/) for complete documentation. See [CHANGELOG.md](CHANGELOG.md) for release notes (latest: **1.
|
|
274
|
+
Visit [Pyweber Docs](https://pyweber.dev/) for complete documentation. See [CHANGELOG.md](CHANGELOG.md) for release notes (latest: **1.6.0** — optional ORM/Redis, identity-preserving WS sync, reactive event fixes).
|
|
266
275
|
|
|
267
276
|
## License
|
|
268
277
|
|
|
@@ -14,17 +14,25 @@ Pyweber is a lightweight Python web framework designed to create dynamic, reacti
|
|
|
14
14
|
- **Intuitive DOM Manipulation**: Query and modify elements with familiar selectors
|
|
15
15
|
- **Event-Driven Programming**: Handle user interactions with Python event handlers
|
|
16
16
|
- **WebSocket Integration**: Real-time communication between client and server
|
|
17
|
-
- **Template Handoff (1.3.0)**: WebSocket sessions reuse the HTTP-rendered template — handlers are not executed twice on connect
|
|
17
|
+
- **Template Handoff (1.3.0+)**: WebSocket sessions reuse the HTTP-rendered template — handlers are not executed twice on connect
|
|
18
|
+
- **Identity-preserving sync (1.6.0+)**: `self` / subclass element refs stay valid after WS connect
|
|
19
|
+
- **Optional ORM & Redis sessions (1.6.0+)**: `pyweber[db]`, `pyweber[redis]`
|
|
20
|
+
- **Auth & RBAC (1.5+)**: signed login cookie, roles/permissions
|
|
18
21
|
- **Minimal Configuration**: Get started quickly with sensible defaults
|
|
19
22
|
|
|
20
23
|
## Quick Start
|
|
21
24
|
|
|
22
25
|
### Installation
|
|
23
26
|
|
|
27
|
+
!!! danger "Avoid ≤ 1.3.1"
|
|
28
|
+
Older lines are **not recommended** for production. Use a current release:
|
|
29
|
+
|
|
24
30
|
```bash
|
|
25
|
-
pip install pyweber
|
|
31
|
+
pip install -U 'pyweber>=1.6'
|
|
26
32
|
```
|
|
27
33
|
|
|
34
|
+
See [Supported versions](https://pyweber.dev/guides/supported-versions/) (docs) for yank / security notes. `pyproject.toml` cannot warn when someone pins an old wheel — that requires [PyPI yanking](https://docs.pypi.org/project-management/yanking/).
|
|
35
|
+
|
|
28
36
|
### Create a Project
|
|
29
37
|
|
|
30
38
|
```bash
|
|
@@ -221,7 +229,7 @@ pyweber add-section --section-name database
|
|
|
221
229
|
pyweber --update
|
|
222
230
|
```
|
|
223
231
|
|
|
224
|
-
Visit [Pyweber Docs](https://pyweber.dev/) for complete documentation. See [CHANGELOG.md](CHANGELOG.md) for release notes (latest: **1.
|
|
232
|
+
Visit [Pyweber Docs](https://pyweber.dev/) for complete documentation. See [CHANGELOG.md](CHANGELOG.md) for release notes (latest: **1.6.0** — optional ORM/Redis, identity-preserving WS sync, reactive event fixes).
|
|
225
233
|
|
|
226
234
|
## License
|
|
227
235
|
|
|
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyweber"
|
|
7
|
-
version = "1.6.
|
|
7
|
+
version = "1.6.1"
|
|
8
8
|
description = "A lightweight Python framework for building and managing web applications."
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
authors = [{ name = "
|
|
10
|
+
authors = [{ name = "Pyweber Limitada", email = "pypi.dev@gmail.com" }]
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
requires-python = ">=3.10"
|
|
13
13
|
dependencies = ["watchdog", "toml", "questionary", "qrcode[pil]"]
|
|
@@ -18,6 +18,8 @@ Tracker = "https://github.com/pyweber/pyweber/issues"
|
|
|
18
18
|
PyPI = "https://pypi.org/project/pyweber/"
|
|
19
19
|
YouTube = "https://youtube.com/@devpythonMZ"
|
|
20
20
|
Examples = "https://github.com/pyweber-examples"
|
|
21
|
+
# Supported versions / security policy (≤1.3.1 not recommended; yank on PyPI — not via this file)
|
|
22
|
+
Security = "https://pyweber.dev/guides/supported-versions/"
|
|
21
23
|
|
|
22
24
|
[project.scripts]
|
|
23
25
|
pyweber = "pyweber.cli.commands:app"
|
|
@@ -43,5 +45,5 @@ pyweber = ["static/**/*", "admin/**/*"]
|
|
|
43
45
|
omit = ["pyweber/cli/commands.py"]
|
|
44
46
|
|
|
45
47
|
[tool.coverage.report]
|
|
46
|
-
fail_under =
|
|
48
|
+
fail_under = 88
|
|
47
49
|
show_missing = true
|
|
@@ -105,7 +105,6 @@ from .utils.types import (
|
|
|
105
105
|
EventType,
|
|
106
106
|
HTMLTag,
|
|
107
107
|
HTTPStatusCode,
|
|
108
|
-
JWTAlgorithms,
|
|
109
108
|
NonSelfClosingHTMLTags,
|
|
110
109
|
WebSocketStatusCode,
|
|
111
110
|
WindowEventType,
|
|
@@ -305,3 +304,21 @@ __all__ = [
|
|
|
305
304
|
'Label',
|
|
306
305
|
'TextArea',
|
|
307
306
|
]
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def __getattr__(name: str):
|
|
310
|
+
if name == 'JWTAlgorithms':
|
|
311
|
+
from pyweber.utils.deprecation import warn_deprecated
|
|
312
|
+
from pyweber.utils.types import JWTAlgorithms as _JWTAlgorithms
|
|
313
|
+
|
|
314
|
+
warn_deprecated(
|
|
315
|
+
'pyweber.JWTAlgorithms',
|
|
316
|
+
alternative=(
|
|
317
|
+
'pyjwt (or similar) for encode/decode/verify; '
|
|
318
|
+
'pyweber.auth for session login. '
|
|
319
|
+
'JWTAlgorithms remains an algorithm-name enum only until 2.0'
|
|
320
|
+
),
|
|
321
|
+
removal='2.0',
|
|
322
|
+
)
|
|
323
|
+
return _JWTAlgorithms
|
|
324
|
+
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
|
|
@@ -21,7 +21,12 @@ class Session:
|
|
|
21
21
|
self.session_id = session_id
|
|
22
22
|
self.create_at = time()
|
|
23
23
|
self.current_route = current_route
|
|
24
|
-
|
|
24
|
+
# Must be a distinct snapshot for TemplateDiff; aliasing template makes
|
|
25
|
+
# every e.update() produce an empty diff (mutations visible on both sides).
|
|
26
|
+
try:
|
|
27
|
+
self.old_template = template.clone()
|
|
28
|
+
except Exception:
|
|
29
|
+
self.old_template = None
|
|
25
30
|
|
|
26
31
|
|
|
27
32
|
class SessionManager:
|
|
@@ -57,8 +62,14 @@ class SessionManager:
|
|
|
57
62
|
self._schedule_persist(session)
|
|
58
63
|
|
|
59
64
|
def remove_session(self, session_id: str):
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
session = self.sessions.pop(session_id, None)
|
|
66
|
+
if session is not None:
|
|
67
|
+
try:
|
|
68
|
+
from pyweber.core.events import cleanup_template_events
|
|
69
|
+
cleanup_template_events(getattr(session, 'template', None))
|
|
70
|
+
cleanup_template_events(getattr(session, 'old_template', None))
|
|
71
|
+
except Exception as exc:
|
|
72
|
+
logger.debug('EventBook cleanup skipped: %s', exc)
|
|
62
73
|
self._schedule_delete(session_id)
|
|
63
74
|
|
|
64
75
|
def get_session(self, session_id: str):
|