arthexis 0.1.13__py3-none-any.whl → 0.1.14__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.

Potentially problematic release.


This version of arthexis might be problematic. Click here for more details.

Files changed (107) hide show
  1. {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/METADATA +222 -221
  2. arthexis-0.1.14.dist-info/RECORD +109 -0
  3. {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/licenses/LICENSE +674 -674
  4. config/__init__.py +5 -5
  5. config/active_app.py +15 -15
  6. config/asgi.py +43 -43
  7. config/auth_app.py +7 -7
  8. config/celery.py +32 -32
  9. config/context_processors.py +67 -69
  10. config/horologia_app.py +7 -7
  11. config/loadenv.py +11 -11
  12. config/logging.py +59 -48
  13. config/middleware.py +25 -25
  14. config/offline.py +49 -49
  15. config/settings.py +691 -682
  16. config/settings_helpers.py +109 -109
  17. config/urls.py +171 -166
  18. config/wsgi.py +17 -17
  19. core/admin.py +3771 -2809
  20. core/admin_history.py +50 -50
  21. core/admindocs.py +151 -151
  22. core/apps.py +356 -272
  23. core/auto_upgrade.py +57 -57
  24. core/backends.py +265 -236
  25. core/changelog.py +342 -0
  26. core/entity.py +133 -133
  27. core/environment.py +61 -61
  28. core/fields.py +168 -168
  29. core/form_fields.py +75 -75
  30. core/github_helper.py +188 -25
  31. core/github_issues.py +178 -172
  32. core/github_repos.py +72 -0
  33. core/lcd_screen.py +78 -78
  34. core/liveupdate.py +25 -25
  35. core/log_paths.py +100 -100
  36. core/mailer.py +85 -85
  37. core/middleware.py +91 -91
  38. core/models.py +3609 -2795
  39. core/notifications.py +105 -105
  40. core/public_wifi.py +267 -227
  41. core/reference_utils.py +108 -108
  42. core/release.py +721 -368
  43. core/rfid_import_export.py +113 -0
  44. core/sigil_builder.py +149 -149
  45. core/sigil_context.py +20 -20
  46. core/sigil_resolver.py +315 -315
  47. core/system.py +752 -493
  48. core/tasks.py +408 -394
  49. core/temp_passwords.py +181 -181
  50. core/test_system_info.py +186 -139
  51. core/tests.py +2095 -1521
  52. core/tests_liveupdate.py +17 -17
  53. core/urls.py +11 -11
  54. core/user_data.py +641 -633
  55. core/views.py +2175 -1417
  56. core/widgets.py +213 -94
  57. core/workgroup_urls.py +17 -17
  58. core/workgroup_views.py +94 -94
  59. nodes/admin.py +1720 -1161
  60. nodes/apps.py +87 -85
  61. nodes/backends.py +160 -160
  62. nodes/dns.py +203 -203
  63. nodes/feature_checks.py +133 -133
  64. nodes/lcd.py +165 -165
  65. nodes/models.py +1737 -1597
  66. nodes/reports.py +411 -411
  67. nodes/rfid_sync.py +195 -0
  68. nodes/signals.py +18 -0
  69. nodes/tasks.py +46 -46
  70. nodes/tests.py +3810 -3116
  71. nodes/urls.py +15 -14
  72. nodes/utils.py +121 -105
  73. nodes/views.py +683 -619
  74. ocpp/admin.py +948 -948
  75. ocpp/apps.py +25 -25
  76. ocpp/consumers.py +1565 -1459
  77. ocpp/evcs.py +844 -844
  78. ocpp/evcs_discovery.py +158 -158
  79. ocpp/models.py +917 -917
  80. ocpp/reference_utils.py +42 -42
  81. ocpp/routing.py +11 -11
  82. ocpp/simulator.py +745 -745
  83. ocpp/status_display.py +26 -26
  84. ocpp/store.py +601 -541
  85. ocpp/tasks.py +31 -31
  86. ocpp/test_export_import.py +130 -130
  87. ocpp/test_rfid.py +913 -702
  88. ocpp/tests.py +4445 -4094
  89. ocpp/transactions_io.py +189 -189
  90. ocpp/urls.py +50 -50
  91. ocpp/views.py +1479 -1251
  92. pages/admin.py +708 -539
  93. pages/apps.py +10 -10
  94. pages/checks.py +40 -40
  95. pages/context_processors.py +127 -119
  96. pages/defaults.py +13 -13
  97. pages/forms.py +198 -198
  98. pages/middleware.py +205 -153
  99. pages/models.py +607 -426
  100. pages/tests.py +2612 -2200
  101. pages/urls.py +25 -25
  102. pages/utils.py +12 -12
  103. pages/views.py +1165 -1128
  104. arthexis-0.1.13.dist-info/RECORD +0 -105
  105. nodes/actions.py +0 -70
  106. {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/WHEEL +0 -0
  107. {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/top_level.txt +0 -0
pages/apps.py CHANGED
@@ -1,10 +1,10 @@
1
- from django.apps import AppConfig
2
-
3
-
4
- class PagesConfig(AppConfig):
5
- default_auto_field = "django.db.models.BigAutoField"
6
- name = "pages"
7
- verbose_name = "7. Experience"
8
-
9
- def ready(self): # pragma: no cover - import for side effects
10
- from . import checks # noqa: F401
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class PagesConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "pages"
7
+ verbose_name = "7. Experience"
8
+
9
+ def ready(self): # pragma: no cover - import for side effects
10
+ from . import checks # noqa: F401
pages/checks.py CHANGED
@@ -1,40 +1,40 @@
1
- import inspect
2
-
3
- from django.core.checks import Warning, register
4
- from django.urls.resolvers import URLPattern, URLResolver
5
-
6
- from config import urls as project_urls
7
-
8
-
9
- def _collect_checks(resolver: URLResolver, errors: list, prefix: str = ""):
10
- for pattern in resolver.url_patterns:
11
- if isinstance(pattern, URLResolver):
12
- _collect_checks(pattern, errors, prefix + pattern.pattern._route)
13
- elif isinstance(pattern, URLPattern):
14
- view = pattern.callback
15
- if getattr(view, "landing", False):
16
- sig = inspect.signature(view)
17
- params = list(sig.parameters.values())
18
- if params and params[0].name == "request":
19
- params = params[1:]
20
- has_required = any(
21
- p.default is inspect._empty
22
- and p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
23
- for p in params
24
- )
25
- if has_required:
26
- errors.append(
27
- Warning(
28
- f'Landing view "{view.__module__}.{view.__name__}" requires URL parameters and cannot be a landing page.',
29
- id="pages.W001",
30
- )
31
- )
32
-
33
-
34
- @register()
35
- def landing_views_have_no_args(app_configs, **kwargs):
36
- errors: list = []
37
- for p in project_urls.urlpatterns:
38
- if isinstance(p, URLResolver):
39
- _collect_checks(p, errors, p.pattern._route)
40
- return errors
1
+ import inspect
2
+
3
+ from django.core.checks import Warning, register
4
+ from django.urls.resolvers import URLPattern, URLResolver
5
+
6
+ from config import urls as project_urls
7
+
8
+
9
+ def _collect_checks(resolver: URLResolver, errors: list, prefix: str = ""):
10
+ for pattern in resolver.url_patterns:
11
+ if isinstance(pattern, URLResolver):
12
+ _collect_checks(pattern, errors, prefix + pattern.pattern._route)
13
+ elif isinstance(pattern, URLPattern):
14
+ view = pattern.callback
15
+ if getattr(view, "landing", False):
16
+ sig = inspect.signature(view)
17
+ params = list(sig.parameters.values())
18
+ if params and params[0].name == "request":
19
+ params = params[1:]
20
+ has_required = any(
21
+ p.default is inspect._empty
22
+ and p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
23
+ for p in params
24
+ )
25
+ if has_required:
26
+ errors.append(
27
+ Warning(
28
+ f'Landing view "{view.__module__}.{view.__name__}" requires URL parameters and cannot be a landing page.',
29
+ id="pages.W001",
30
+ )
31
+ )
32
+
33
+
34
+ @register()
35
+ def landing_views_have_no_args(app_configs, **kwargs):
36
+ errors: list = []
37
+ for p in project_urls.urlpatterns:
38
+ if isinstance(p, URLResolver):
39
+ _collect_checks(p, errors, p.pattern._route)
40
+ return errors
@@ -1,119 +1,127 @@
1
- from utils.sites import get_site
2
- from django.urls import Resolver404, resolve
3
- from django.conf import settings
4
- from pathlib import Path
5
- from types import SimpleNamespace
6
- from nodes.models import Node
7
- from core.models import Reference
8
- from core.reference_utils import filter_visible_references
9
- from .models import Module
10
-
11
- _favicon_path = Path(settings.BASE_DIR) / "pages" / "fixtures" / "data" / "favicon.txt"
12
- _control_favicon_path = (
13
- Path(settings.BASE_DIR) / "pages" / "fixtures" / "data" / "favicon_control.txt"
14
- )
15
-
16
- try:
17
- _DEFAULT_FAVICON = f"data:image/png;base64,{_favicon_path.read_text().strip()}"
18
- except OSError:
19
- _DEFAULT_FAVICON = ""
20
-
21
- try:
22
- _CONTROL_FAVICON = (
23
- f"data:image/png;base64,{_control_favicon_path.read_text().strip()}"
24
- )
25
- except OSError:
26
- _CONTROL_FAVICON = _DEFAULT_FAVICON
27
-
28
-
29
- def nav_links(request):
30
- """Provide navigation links for the current site."""
31
- site = get_site(request)
32
- node = Node.get_local()
33
- role = node.role if node else None
34
- if role:
35
- modules = (
36
- Module.objects.filter(node_role=role, is_deleted=False)
37
- .select_related("application")
38
- .prefetch_related("landings")
39
- )
40
- else:
41
- modules = []
42
-
43
- valid_modules = []
44
- current_module = None
45
- for module in modules:
46
- landings = []
47
- for landing in module.landings.filter(enabled=True):
48
- try:
49
- match = resolve(landing.path)
50
- except Resolver404:
51
- continue
52
- view_func = match.func
53
- requires_login = bool(getattr(view_func, "login_required", False))
54
- if not requires_login and hasattr(view_func, "login_url"):
55
- requires_login = True
56
- staff_only = getattr(view_func, "staff_required", False)
57
- if requires_login and not request.user.is_authenticated:
58
- setattr(landing, "requires_login", True)
59
- if staff_only and not request.user.is_staff:
60
- continue
61
- landings.append(landing)
62
- if landings:
63
- app_name = getattr(module.application, "name", "").lower()
64
- if app_name == "awg":
65
- module.menu = "Calculate"
66
- elif module.path.rstrip("/").lower() == "/man":
67
- module.menu = "Manual"
68
- module.enabled_landings = landings
69
- valid_modules.append(module)
70
- if request.path.startswith(module.path):
71
- if current_module is None or len(module.path) > len(
72
- current_module.path
73
- ):
74
- current_module = module
75
-
76
- datasette_lock = Path(settings.BASE_DIR) / "locks" / "datasette.lck"
77
- if datasette_lock.exists():
78
- datasette_module = SimpleNamespace(
79
- menu_label="Data",
80
- path="/data/",
81
- enabled_landings=[SimpleNamespace(path="/data/", label="Datasette")],
82
- )
83
- valid_modules.append(datasette_module)
84
-
85
- valid_modules.sort(key=lambda m: m.menu_label.lower())
86
-
87
- if current_module and current_module.favicon:
88
- favicon_url = current_module.favicon.url
89
- else:
90
- favicon_url = None
91
- if site:
92
- try:
93
- if site.badge.favicon:
94
- favicon_url = site.badge.favicon.url
95
- except Exception:
96
- pass
97
- if not favicon_url:
98
- if node and getattr(node.role, "name", "") == "Control":
99
- favicon_url = _CONTROL_FAVICON
100
- else:
101
- favicon_url = _DEFAULT_FAVICON
102
-
103
- header_refs_qs = (
104
- Reference.objects.filter(show_in_header=True)
105
- .exclude(value="")
106
- .prefetch_related("roles", "features", "sites")
107
- )
108
- header_references = filter_visible_references(
109
- header_refs_qs,
110
- request=request,
111
- site=site,
112
- node=node,
113
- )
114
-
115
- return {
116
- "nav_modules": valid_modules,
117
- "favicon_url": favicon_url,
118
- "header_references": header_references,
119
- }
1
+ from utils.sites import get_site
2
+ from django.urls import Resolver404, resolve
3
+ from django.conf import settings
4
+ from pathlib import Path
5
+ from types import SimpleNamespace
6
+ from nodes.models import Node
7
+ from core.models import Reference
8
+ from core.reference_utils import filter_visible_references
9
+ from .models import Module
10
+
11
+ _FAVICON_DIR = Path(settings.BASE_DIR) / "pages" / "fixtures" / "data"
12
+ _FAVICON_FILENAMES = {
13
+ "default": "favicon.txt",
14
+ "Constellation": "favicon_constellation.txt",
15
+ "Control": "favicon_control.txt",
16
+ "Satellite": "favicon_satellite.txt",
17
+ }
18
+
19
+
20
+ def _load_favicon(filename: str) -> str:
21
+ path = _FAVICON_DIR / filename
22
+ try:
23
+ return f"data:image/png;base64,{path.read_text().strip()}"
24
+ except OSError:
25
+ return ""
26
+
27
+
28
+ _DEFAULT_FAVICON = _load_favicon(_FAVICON_FILENAMES["default"])
29
+ _ROLE_FAVICONS = {
30
+ role: (_load_favicon(filename) or _DEFAULT_FAVICON)
31
+ for role, filename in _FAVICON_FILENAMES.items()
32
+ if role != "default"
33
+ }
34
+
35
+
36
+ def nav_links(request):
37
+ """Provide navigation links for the current site."""
38
+ site = get_site(request)
39
+ node = Node.get_local()
40
+ role = node.role if node else None
41
+ if role:
42
+ modules = (
43
+ Module.objects.filter(node_role=role, is_deleted=False)
44
+ .select_related("application")
45
+ .prefetch_related("landings")
46
+ )
47
+ else:
48
+ modules = []
49
+
50
+ valid_modules = []
51
+ datasette_enabled = False
52
+ current_module = None
53
+ for module in modules:
54
+ landings = []
55
+ for landing in module.landings.filter(enabled=True):
56
+ try:
57
+ match = resolve(landing.path)
58
+ except Resolver404:
59
+ continue
60
+ view_func = match.func
61
+ requires_login = bool(getattr(view_func, "login_required", False))
62
+ if not requires_login and hasattr(view_func, "login_url"):
63
+ requires_login = True
64
+ staff_only = getattr(view_func, "staff_required", False)
65
+ if requires_login and not request.user.is_authenticated:
66
+ setattr(landing, "requires_login", True)
67
+ if staff_only and not request.user.is_staff:
68
+ continue
69
+ landings.append(landing)
70
+ if landings:
71
+ app_name = getattr(module.application, "name", "").lower()
72
+ if app_name == "awg":
73
+ module.menu = "Calculate"
74
+ elif module.path.rstrip("/").lower() == "/man":
75
+ module.menu = "Manual"
76
+ module.enabled_landings = landings
77
+ valid_modules.append(module)
78
+ if request.path.startswith(module.path):
79
+ if current_module is None or len(module.path) > len(
80
+ current_module.path
81
+ ):
82
+ current_module = module
83
+
84
+ datasette_lock = Path(settings.BASE_DIR) / "locks" / "datasette.lck"
85
+ if datasette_lock.exists():
86
+ datasette_enabled = True
87
+ datasette_module = SimpleNamespace(
88
+ menu_label="Data",
89
+ path="/data/",
90
+ enabled_landings=[SimpleNamespace(path="/data/", label="Datasette")],
91
+ )
92
+ valid_modules.append(datasette_module)
93
+
94
+ valid_modules.sort(key=lambda m: m.menu_label.lower())
95
+
96
+ if current_module and current_module.favicon:
97
+ favicon_url = current_module.favicon.url
98
+ else:
99
+ favicon_url = None
100
+ if site:
101
+ try:
102
+ if site.badge.favicon:
103
+ favicon_url = site.badge.favicon.url
104
+ except Exception:
105
+ pass
106
+ if not favicon_url:
107
+ role_name = getattr(getattr(node, "role", None), "name", "")
108
+ favicon_url = _ROLE_FAVICONS.get(role_name, _DEFAULT_FAVICON) or _DEFAULT_FAVICON
109
+
110
+ header_refs_qs = (
111
+ Reference.objects.filter(show_in_header=True)
112
+ .exclude(value="")
113
+ .prefetch_related("roles", "features", "sites")
114
+ )
115
+ header_references = filter_visible_references(
116
+ header_refs_qs,
117
+ request=request,
118
+ site=site,
119
+ node=node,
120
+ )
121
+
122
+ return {
123
+ "nav_modules": valid_modules,
124
+ "favicon_url": favicon_url,
125
+ "header_references": header_references,
126
+ "datasette_enabled": datasette_enabled,
127
+ }
pages/defaults.py CHANGED
@@ -1,13 +1,13 @@
1
- """Default configuration for the pages application."""
2
- from __future__ import annotations
3
-
4
- from typing import Dict
5
-
6
- DEFAULT_APPLICATION_DESCRIPTIONS: Dict[str, str] = {
7
- "awg": "Power, Energy and Cost calculations.",
8
- "core": "Support for Business Processes and monetization.",
9
- "ocpp": "Compatibility with Standards and Good Practices.",
10
- "nodes": "System and Node-level operations,",
11
- "pages": "User QA, Continuity Design and Chaos Testing.",
12
- "teams": "Identity, Entitlements and Access Controls.",
13
- }
1
+ """Default configuration for the pages application."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Dict
5
+
6
+ DEFAULT_APPLICATION_DESCRIPTIONS: Dict[str, str] = {
7
+ "awg": "Power, Energy and Cost calculations.",
8
+ "core": "Support for Business Processes and monetization.",
9
+ "ocpp": "Compatibility with Standards and Good Practices.",
10
+ "nodes": "System and Node-level operations,",
11
+ "pages": "User QA, Continuity Design and Chaos Testing.",
12
+ "teams": "Identity, Entitlements and Access Controls.",
13
+ }