arthexis 0.1.9__py3-none-any.whl → 0.1.26__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.
- arthexis-0.1.26.dist-info/METADATA +272 -0
- arthexis-0.1.26.dist-info/RECORD +111 -0
- {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/licenses/LICENSE +674 -674
- config/__init__.py +5 -5
- config/active_app.py +15 -15
- config/asgi.py +29 -29
- config/auth_app.py +7 -7
- config/celery.py +32 -25
- config/context_processors.py +67 -68
- config/horologia_app.py +7 -7
- config/loadenv.py +11 -11
- config/logging.py +59 -48
- config/middleware.py +71 -25
- config/offline.py +49 -49
- config/settings.py +676 -492
- config/settings_helpers.py +109 -0
- config/urls.py +228 -159
- config/wsgi.py +17 -17
- core/admin.py +4052 -2066
- core/admin_history.py +50 -50
- core/admindocs.py +192 -151
- core/apps.py +350 -223
- core/auto_upgrade.py +72 -0
- core/backends.py +311 -124
- core/changelog.py +403 -0
- core/entity.py +149 -133
- core/environment.py +60 -43
- core/fields.py +168 -75
- core/form_fields.py +75 -0
- core/github_helper.py +188 -25
- core/github_issues.py +183 -172
- core/github_repos.py +72 -0
- core/lcd_screen.py +78 -78
- core/liveupdate.py +25 -25
- core/log_paths.py +114 -100
- core/mailer.py +89 -83
- core/middleware.py +91 -91
- core/models.py +5041 -2195
- core/notifications.py +105 -105
- core/public_wifi.py +267 -227
- core/reference_utils.py +107 -0
- core/release.py +940 -346
- core/rfid_import_export.py +113 -0
- core/sigil_builder.py +149 -131
- core/sigil_context.py +20 -20
- core/sigil_resolver.py +250 -284
- core/system.py +1425 -230
- core/tasks.py +538 -199
- core/temp_passwords.py +181 -0
- core/test_system_info.py +202 -43
- core/tests.py +2673 -1069
- core/tests_liveupdate.py +17 -17
- core/urls.py +11 -11
- core/user_data.py +681 -495
- core/views.py +2484 -789
- core/widgets.py +213 -51
- nodes/admin.py +2236 -445
- nodes/apps.py +98 -70
- nodes/backends.py +160 -53
- nodes/dns.py +203 -0
- nodes/feature_checks.py +133 -0
- nodes/lcd.py +165 -165
- nodes/models.py +2375 -870
- nodes/reports.py +411 -0
- nodes/rfid_sync.py +210 -0
- nodes/signals.py +18 -0
- nodes/tasks.py +141 -46
- nodes/tests.py +5045 -1489
- nodes/urls.py +29 -13
- nodes/utils.py +172 -73
- nodes/views.py +1768 -304
- ocpp/admin.py +1775 -481
- ocpp/apps.py +25 -25
- ocpp/consumers.py +1843 -630
- ocpp/evcs.py +844 -928
- ocpp/evcs_discovery.py +158 -0
- ocpp/models.py +1417 -640
- ocpp/network.py +398 -0
- ocpp/reference_utils.py +42 -0
- ocpp/routing.py +11 -9
- ocpp/simulator.py +745 -368
- ocpp/status_display.py +26 -0
- ocpp/store.py +603 -403
- ocpp/tasks.py +479 -31
- ocpp/test_export_import.py +131 -130
- ocpp/test_rfid.py +1072 -540
- ocpp/tests.py +5494 -2296
- ocpp/transactions_io.py +197 -165
- ocpp/urls.py +50 -50
- ocpp/views.py +2024 -912
- pages/admin.py +1123 -396
- pages/apps.py +45 -10
- pages/checks.py +40 -40
- pages/context_processors.py +151 -85
- pages/defaults.py +13 -0
- pages/forms.py +221 -0
- pages/middleware.py +213 -153
- pages/models.py +720 -252
- pages/module_defaults.py +156 -0
- pages/site_config.py +137 -0
- pages/tasks.py +74 -0
- pages/tests.py +4009 -1389
- pages/urls.py +38 -20
- pages/utils.py +93 -12
- pages/views.py +1736 -762
- arthexis-0.1.9.dist-info/METADATA +0 -168
- arthexis-0.1.9.dist-info/RECORD +0 -92
- core/workgroup_urls.py +0 -17
- core/workgroup_views.py +0 -94
- nodes/actions.py +0 -70
- {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/WHEEL +0 -0
- {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/top_level.txt +0 -0
core/sigil_resolver.py
CHANGED
|
@@ -1,284 +1,250 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import os
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
from django.
|
|
9
|
-
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if not
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
lookup_root,
|
|
252
|
-
key_upper or normalized_key or raw_key,
|
|
253
|
-
)
|
|
254
|
-
return _failed_resolution(original_token)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
def resolve_sigils(text: str, current: Optional[models.Model] = None) -> str:
|
|
258
|
-
result = ""
|
|
259
|
-
i = 0
|
|
260
|
-
while i < len(text):
|
|
261
|
-
if text[i] == "[":
|
|
262
|
-
depth = 1
|
|
263
|
-
j = i + 1
|
|
264
|
-
while j < len(text) and depth:
|
|
265
|
-
if text[j] == "[":
|
|
266
|
-
depth += 1
|
|
267
|
-
elif text[j] == "]":
|
|
268
|
-
depth -= 1
|
|
269
|
-
j += 1
|
|
270
|
-
if depth:
|
|
271
|
-
result += text[i]
|
|
272
|
-
i += 1
|
|
273
|
-
continue
|
|
274
|
-
token = text[i + 1 : j - 1]
|
|
275
|
-
result += _resolve_token(token, current)
|
|
276
|
-
i = j
|
|
277
|
-
else:
|
|
278
|
-
result += text[i]
|
|
279
|
-
i += 1
|
|
280
|
-
return result
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
def resolve_sigil(sigil: str, current: Optional[models.Model] = None) -> str:
|
|
284
|
-
return resolve_sigils(sigil, current)
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from django.apps import apps
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.core import serializers
|
|
8
|
+
from django.db import models
|
|
9
|
+
|
|
10
|
+
from .sigil_context import get_context
|
|
11
|
+
from .system import get_system_sigil_values, resolve_system_namespace_value
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger("core.entity")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _first_instance(model: type[models.Model]) -> Optional[models.Model]:
|
|
17
|
+
qs = model.objects
|
|
18
|
+
ordering = list(getattr(model._meta, "ordering", []))
|
|
19
|
+
if ordering:
|
|
20
|
+
qs = qs.order_by(*ordering)
|
|
21
|
+
else:
|
|
22
|
+
qs = qs.order_by("?")
|
|
23
|
+
return qs.first()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _failed_resolution(token: str) -> str:
|
|
27
|
+
return f"[{token}]"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _resolve_token(token: str, current: Optional[models.Model] = None) -> str:
|
|
31
|
+
original_token = token
|
|
32
|
+
i = 0
|
|
33
|
+
n = len(token)
|
|
34
|
+
root_name = ""
|
|
35
|
+
while i < n and token[i] not in ":=.":
|
|
36
|
+
root_name += token[i]
|
|
37
|
+
i += 1
|
|
38
|
+
if not root_name:
|
|
39
|
+
return _failed_resolution(original_token)
|
|
40
|
+
filter_field = None
|
|
41
|
+
if i < n and token[i] == ":":
|
|
42
|
+
i += 1
|
|
43
|
+
field = ""
|
|
44
|
+
while i < n and token[i] != "=":
|
|
45
|
+
field += token[i]
|
|
46
|
+
i += 1
|
|
47
|
+
if i == n:
|
|
48
|
+
return _failed_resolution(original_token)
|
|
49
|
+
filter_field = field.replace("-", "_")
|
|
50
|
+
instance_id = None
|
|
51
|
+
if i < n and token[i] == "=":
|
|
52
|
+
i += 1
|
|
53
|
+
start = i
|
|
54
|
+
depth = 0
|
|
55
|
+
while i < n:
|
|
56
|
+
ch = token[i]
|
|
57
|
+
if ch == "[":
|
|
58
|
+
depth += 1
|
|
59
|
+
elif ch == "]" and depth:
|
|
60
|
+
depth -= 1
|
|
61
|
+
elif ch == "." and depth == 0:
|
|
62
|
+
break
|
|
63
|
+
i += 1
|
|
64
|
+
instance_id = token[start:i]
|
|
65
|
+
key = None
|
|
66
|
+
if i < n and token[i] == ".":
|
|
67
|
+
i += 1
|
|
68
|
+
start = i
|
|
69
|
+
while i < n and token[i] != "=":
|
|
70
|
+
i += 1
|
|
71
|
+
key = token[start:i]
|
|
72
|
+
param = None
|
|
73
|
+
if i < n and token[i] == "=":
|
|
74
|
+
param = token[i + 1 :]
|
|
75
|
+
normalized_root = root_name.replace("-", "_")
|
|
76
|
+
lookup_root = normalized_root.upper()
|
|
77
|
+
raw_key = key
|
|
78
|
+
normalized_key = None
|
|
79
|
+
key_upper = None
|
|
80
|
+
key_lower = None
|
|
81
|
+
if key:
|
|
82
|
+
normalized_key = key.replace("-", "_")
|
|
83
|
+
key_upper = normalized_key.upper()
|
|
84
|
+
key_lower = normalized_key.lower()
|
|
85
|
+
if param:
|
|
86
|
+
param = resolve_sigils(param, current)
|
|
87
|
+
if instance_id:
|
|
88
|
+
instance_id = resolve_sigils(instance_id, current)
|
|
89
|
+
SigilRoot = apps.get_model("core", "SigilRoot")
|
|
90
|
+
try:
|
|
91
|
+
root = SigilRoot.objects.get(prefix__iexact=lookup_root)
|
|
92
|
+
except SigilRoot.DoesNotExist:
|
|
93
|
+
logger.warning("Unknown sigil root [%s]", lookup_root)
|
|
94
|
+
return _failed_resolution(original_token)
|
|
95
|
+
except Exception:
|
|
96
|
+
logger.exception(
|
|
97
|
+
"Error resolving sigil [%s.%s]",
|
|
98
|
+
lookup_root,
|
|
99
|
+
key_upper or normalized_key or raw_key,
|
|
100
|
+
)
|
|
101
|
+
return _failed_resolution(original_token)
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
if root.context_type == SigilRoot.Context.CONFIG:
|
|
105
|
+
if not normalized_key:
|
|
106
|
+
return ""
|
|
107
|
+
if root.prefix.upper() == "ENV":
|
|
108
|
+
candidates = []
|
|
109
|
+
if raw_key:
|
|
110
|
+
candidates.append(raw_key.replace("-", "_"))
|
|
111
|
+
if normalized_key:
|
|
112
|
+
candidates.append(normalized_key)
|
|
113
|
+
if key_upper:
|
|
114
|
+
candidates.append(key_upper)
|
|
115
|
+
if key_lower:
|
|
116
|
+
candidates.append(key_lower)
|
|
117
|
+
seen_candidates: set[str] = set()
|
|
118
|
+
for candidate in candidates:
|
|
119
|
+
if not candidate or candidate in seen_candidates:
|
|
120
|
+
continue
|
|
121
|
+
seen_candidates.add(candidate)
|
|
122
|
+
val = os.environ.get(candidate)
|
|
123
|
+
if val is not None:
|
|
124
|
+
return val
|
|
125
|
+
logger.warning(
|
|
126
|
+
"Missing environment variable for sigil [ENV.%s]",
|
|
127
|
+
key_upper or normalized_key or raw_key or "",
|
|
128
|
+
)
|
|
129
|
+
return _failed_resolution(original_token)
|
|
130
|
+
if root.prefix.upper() == "CONF":
|
|
131
|
+
for candidate in [normalized_key, key_upper, key_lower]:
|
|
132
|
+
if not candidate:
|
|
133
|
+
continue
|
|
134
|
+
sentinel = object()
|
|
135
|
+
value = getattr(settings, candidate, sentinel)
|
|
136
|
+
if value is not sentinel:
|
|
137
|
+
return str(value)
|
|
138
|
+
return ""
|
|
139
|
+
if root.prefix.upper() == "SYS":
|
|
140
|
+
values = get_system_sigil_values()
|
|
141
|
+
candidates = {
|
|
142
|
+
key_upper,
|
|
143
|
+
normalized_key.upper() if normalized_key else None,
|
|
144
|
+
(raw_key or "").upper(),
|
|
145
|
+
}
|
|
146
|
+
for candidate in candidates:
|
|
147
|
+
if not candidate:
|
|
148
|
+
continue
|
|
149
|
+
if candidate in values:
|
|
150
|
+
return values[candidate]
|
|
151
|
+
resolved = resolve_system_namespace_value(candidate)
|
|
152
|
+
if resolved is not None:
|
|
153
|
+
return resolved
|
|
154
|
+
logger.warning(
|
|
155
|
+
"Missing system information for sigil [SYS.%s]",
|
|
156
|
+
key_upper or normalized_key or raw_key or "",
|
|
157
|
+
)
|
|
158
|
+
return _failed_resolution(original_token)
|
|
159
|
+
elif root.context_type == SigilRoot.Context.ENTITY:
|
|
160
|
+
model = root.content_type.model_class() if root.content_type else None
|
|
161
|
+
instance = None
|
|
162
|
+
if model:
|
|
163
|
+
if instance_id:
|
|
164
|
+
try:
|
|
165
|
+
if filter_field:
|
|
166
|
+
field_name = filter_field.lower()
|
|
167
|
+
try:
|
|
168
|
+
field_obj = model._meta.get_field(field_name)
|
|
169
|
+
except Exception:
|
|
170
|
+
field_obj = None
|
|
171
|
+
lookup: dict[str, str] = {}
|
|
172
|
+
if field_obj and isinstance(field_obj, models.CharField):
|
|
173
|
+
lookup = {f"{field_name}__iexact": instance_id}
|
|
174
|
+
else:
|
|
175
|
+
lookup = {field_name: instance_id}
|
|
176
|
+
instance = model.objects.filter(**lookup).first()
|
|
177
|
+
else:
|
|
178
|
+
instance = model.objects.filter(pk=instance_id).first()
|
|
179
|
+
except Exception:
|
|
180
|
+
instance = None
|
|
181
|
+
if instance is None and not filter_field:
|
|
182
|
+
for field in model._meta.fields:
|
|
183
|
+
if field.unique and isinstance(field, models.CharField):
|
|
184
|
+
instance = model.objects.filter(
|
|
185
|
+
**{f"{field.name}__iexact": instance_id}
|
|
186
|
+
).first()
|
|
187
|
+
if instance:
|
|
188
|
+
break
|
|
189
|
+
elif current and isinstance(current, model):
|
|
190
|
+
instance = current
|
|
191
|
+
else:
|
|
192
|
+
ctx = get_context()
|
|
193
|
+
inst_pk = ctx.get(model)
|
|
194
|
+
if inst_pk is not None:
|
|
195
|
+
instance = model.objects.filter(pk=inst_pk).first()
|
|
196
|
+
if instance is None:
|
|
197
|
+
instance = _first_instance(model)
|
|
198
|
+
if instance:
|
|
199
|
+
if normalized_key:
|
|
200
|
+
field = next(
|
|
201
|
+
(
|
|
202
|
+
f
|
|
203
|
+
for f in model._meta.fields
|
|
204
|
+
if f.name.lower() == (key_lower or "")
|
|
205
|
+
),
|
|
206
|
+
None,
|
|
207
|
+
)
|
|
208
|
+
if field:
|
|
209
|
+
val = getattr(instance, field.attname)
|
|
210
|
+
return "" if val is None else str(val)
|
|
211
|
+
return _failed_resolution(original_token)
|
|
212
|
+
return serializers.serialize("json", [instance])
|
|
213
|
+
return _failed_resolution(original_token)
|
|
214
|
+
except Exception:
|
|
215
|
+
logger.exception(
|
|
216
|
+
"Error resolving sigil [%s.%s]",
|
|
217
|
+
lookup_root,
|
|
218
|
+
key_upper or normalized_key or raw_key,
|
|
219
|
+
)
|
|
220
|
+
return _failed_resolution(original_token)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def resolve_sigils(text: str, current: Optional[models.Model] = None) -> str:
|
|
224
|
+
result = ""
|
|
225
|
+
i = 0
|
|
226
|
+
while i < len(text):
|
|
227
|
+
if text[i] == "[":
|
|
228
|
+
depth = 1
|
|
229
|
+
j = i + 1
|
|
230
|
+
while j < len(text) and depth:
|
|
231
|
+
if text[j] == "[":
|
|
232
|
+
depth += 1
|
|
233
|
+
elif text[j] == "]":
|
|
234
|
+
depth -= 1
|
|
235
|
+
j += 1
|
|
236
|
+
if depth:
|
|
237
|
+
result += text[i]
|
|
238
|
+
i += 1
|
|
239
|
+
continue
|
|
240
|
+
token = text[i + 1 : j - 1]
|
|
241
|
+
result += _resolve_token(token, current)
|
|
242
|
+
i = j
|
|
243
|
+
else:
|
|
244
|
+
result += text[i]
|
|
245
|
+
i += 1
|
|
246
|
+
return result
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def resolve_sigil(sigil: str, current: Optional[models.Model] = None) -> str:
|
|
250
|
+
return resolve_sigils(sigil, current)
|