arthexis 0.1.16__py3-none-any.whl → 0.1.28__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 (67) hide show
  1. {arthexis-0.1.16.dist-info → arthexis-0.1.28.dist-info}/METADATA +95 -41
  2. arthexis-0.1.28.dist-info/RECORD +112 -0
  3. config/asgi.py +1 -15
  4. config/middleware.py +47 -1
  5. config/settings.py +21 -30
  6. config/settings_helpers.py +176 -1
  7. config/urls.py +69 -1
  8. core/admin.py +805 -473
  9. core/apps.py +6 -8
  10. core/auto_upgrade.py +19 -4
  11. core/backends.py +13 -3
  12. core/celery_utils.py +73 -0
  13. core/changelog.py +66 -5
  14. core/environment.py +4 -5
  15. core/models.py +1825 -218
  16. core/notifications.py +1 -1
  17. core/reference_utils.py +10 -11
  18. core/release.py +55 -7
  19. core/sigil_builder.py +2 -2
  20. core/sigil_resolver.py +1 -66
  21. core/system.py +285 -4
  22. core/tasks.py +439 -138
  23. core/test_system_info.py +43 -5
  24. core/tests.py +516 -18
  25. core/user_data.py +94 -21
  26. core/views.py +348 -186
  27. nodes/admin.py +904 -67
  28. nodes/apps.py +12 -1
  29. nodes/feature_checks.py +30 -0
  30. nodes/models.py +800 -127
  31. nodes/rfid_sync.py +1 -1
  32. nodes/tasks.py +98 -3
  33. nodes/tests.py +1381 -152
  34. nodes/urls.py +15 -1
  35. nodes/utils.py +51 -3
  36. nodes/views.py +1382 -152
  37. ocpp/admin.py +1970 -152
  38. ocpp/consumers.py +839 -34
  39. ocpp/models.py +968 -17
  40. ocpp/network.py +398 -0
  41. ocpp/store.py +411 -43
  42. ocpp/tasks.py +261 -3
  43. ocpp/test_export_import.py +1 -0
  44. ocpp/test_rfid.py +194 -6
  45. ocpp/tests.py +1918 -87
  46. ocpp/transactions_io.py +9 -1
  47. ocpp/urls.py +8 -3
  48. ocpp/views.py +700 -53
  49. pages/admin.py +262 -30
  50. pages/apps.py +35 -0
  51. pages/context_processors.py +28 -21
  52. pages/defaults.py +1 -1
  53. pages/forms.py +31 -8
  54. pages/middleware.py +6 -2
  55. pages/models.py +86 -2
  56. pages/module_defaults.py +5 -5
  57. pages/site_config.py +137 -0
  58. pages/tests.py +1050 -126
  59. pages/urls.py +14 -2
  60. pages/utils.py +70 -0
  61. pages/views.py +622 -56
  62. arthexis-0.1.16.dist-info/RECORD +0 -111
  63. core/workgroup_urls.py +0 -17
  64. core/workgroup_views.py +0 -94
  65. {arthexis-0.1.16.dist-info → arthexis-0.1.28.dist-info}/WHEEL +0 -0
  66. {arthexis-0.1.16.dist-info → arthexis-0.1.28.dist-info}/licenses/LICENSE +0 -0
  67. {arthexis-0.1.16.dist-info → arthexis-0.1.28.dist-info}/top_level.txt +0 -0
core/user_data.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from functools import lru_cache
3
4
  from pathlib import Path
4
5
  from io import BytesIO
5
6
  from zipfile import ZipFile
@@ -65,9 +66,13 @@ def _fixture_path(user, instance) -> Path:
65
66
  return _data_dir(user) / filename
66
67
 
67
68
 
68
- def _seed_fixture_path(instance) -> Path | None:
69
- label = f"{instance._meta.app_label}.{instance._meta.model_name}"
69
+ _SEED_FIXTURE_IGNORED_FIELDS = {"is_seed_data", "is_deleted", "is_user_data"}
70
+
71
+
72
+ @lru_cache(maxsize=1)
73
+ def _seed_fixture_index():
70
74
  base = Path(settings.BASE_DIR)
75
+ index: dict[str, dict[str, object]] = {}
71
76
  for path in base.glob("**/fixtures/*.json"):
72
77
  try:
73
78
  data = json.loads(path.read_text(encoding="utf-8"))
@@ -76,28 +81,55 @@ def _seed_fixture_path(instance) -> Path | None:
76
81
  if not isinstance(data, list) or not data:
77
82
  continue
78
83
  obj = data[0]
79
- if obj.get("model") != label:
84
+ if not isinstance(obj, dict):
80
85
  continue
81
- pk = obj.get("pk")
82
- if pk is not None and pk == instance.pk:
83
- return path
84
- fields = obj.get("fields", {}) or {}
86
+ label = obj.get("model")
87
+ if not isinstance(label, str):
88
+ continue
89
+ fields = obj.get("fields") or {}
90
+ if not isinstance(fields, dict):
91
+ fields = {}
85
92
  comparable_fields = {
86
93
  key: value
87
94
  for key, value in fields.items()
88
- if key not in {"is_seed_data", "is_deleted", "is_user_data"}
95
+ if key not in _SEED_FIXTURE_IGNORED_FIELDS
89
96
  }
97
+ pk = obj.get("pk")
98
+ entries = index.setdefault(label, {"pk": {}, "fields": []})
99
+ pk_index = entries.setdefault("pk", {})
100
+ field_index = entries.setdefault("fields", [])
101
+ if pk is not None:
102
+ pk_index[pk] = path
90
103
  if comparable_fields:
91
- match = True
92
- for field_name, value in comparable_fields.items():
93
- if not hasattr(instance, field_name):
94
- match = False
95
- break
96
- if getattr(instance, field_name) != value:
97
- match = False
98
- break
99
- if match:
100
- return path
104
+ field_index.append((comparable_fields, path))
105
+ return index
106
+
107
+
108
+ def _seed_fixture_path(instance, *, index=None) -> Path | None:
109
+ label = f"{instance._meta.app_label}.{instance._meta.model_name}"
110
+ fixture_index = index or _seed_fixture_index()
111
+ entries = fixture_index.get(label)
112
+ if not entries:
113
+ return None
114
+ pk = getattr(instance, "pk", None)
115
+ pk_index = entries.get("pk", {})
116
+ if pk is not None:
117
+ path = pk_index.get(pk)
118
+ if path is not None:
119
+ return path
120
+ for comparable_fields, path in entries.get("fields", []):
121
+ match = True
122
+ if not isinstance(comparable_fields, dict):
123
+ continue
124
+ for field_name, value in comparable_fields.items():
125
+ if not hasattr(instance, field_name):
126
+ match = False
127
+ break
128
+ if getattr(instance, field_name) != value:
129
+ match = False
130
+ break
131
+ if match:
132
+ return path
101
133
  return None
102
134
 
103
135
 
@@ -201,9 +233,49 @@ def dump_user_fixture(instance, user=None) -> None:
201
233
 
202
234
  def delete_user_fixture(instance, user=None) -> None:
203
235
  target_user = user or _resolve_fixture_user(instance)
204
- if target_user is None:
236
+ filename = (
237
+ f"{instance._meta.app_label}_{instance._meta.model_name}_{instance.pk}.json"
238
+ )
239
+
240
+ def _remove_for_user(candidate) -> None:
241
+ if candidate is None:
242
+ return
243
+ base_path = Path(
244
+ getattr(candidate, "data_path", "") or Path(settings.BASE_DIR) / "data"
245
+ )
246
+ username = _username_for(candidate)
247
+ if not username:
248
+ return
249
+ user_dir = base_path / username
250
+ if user_dir.exists():
251
+ (user_dir / filename).unlink(missing_ok=True)
252
+
253
+ if target_user is not None:
254
+ _remove_for_user(target_user)
205
255
  return
206
- _fixture_path(target_user, instance).unlink(missing_ok=True)
256
+
257
+ root = Path(settings.BASE_DIR) / "data"
258
+ if root.exists():
259
+ (root / filename).unlink(missing_ok=True)
260
+ for path in root.iterdir():
261
+ if path.is_dir():
262
+ (path / filename).unlink(missing_ok=True)
263
+
264
+ UserModel = get_user_model()
265
+ manager = getattr(UserModel, "all_objects", UserModel._default_manager)
266
+ for candidate in manager.all():
267
+ data_path = getattr(candidate, "data_path", "")
268
+ if not data_path:
269
+ continue
270
+ base_path = Path(data_path)
271
+ if not base_path.exists():
272
+ continue
273
+ username = _username_for(candidate)
274
+ if not username:
275
+ continue
276
+ user_dir = base_path / username
277
+ if user_dir.exists():
278
+ (user_dir / filename).unlink(missing_ok=True)
207
279
 
208
280
 
209
281
  def _mark_fixture_user_data(path: Path) -> None:
@@ -541,6 +613,7 @@ def _iter_entity_admin_models():
541
613
 
542
614
  def _seed_data_view(request):
543
615
  sections = []
616
+ fixture_index = _seed_fixture_index()
544
617
  for model, model_admin in _iter_entity_admin_models():
545
618
  objs = model.objects.filter(is_seed_data=True)
546
619
  if not objs.exists():
@@ -551,7 +624,7 @@ def _seed_data_view(request):
551
624
  f"admin:{obj._meta.app_label}_{obj._meta.model_name}_change",
552
625
  args=[obj.pk],
553
626
  )
554
- fixture = _seed_fixture_path(obj)
627
+ fixture = _seed_fixture_path(obj, index=fixture_index)
555
628
  items.append({"url": url, "label": str(obj), "fixture": fixture})
556
629
  sections.append({"opts": model._meta, "items": items})
557
630
  context = admin.site.each_context(request)