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.

Files changed (112) hide show
  1. arthexis-0.1.26.dist-info/METADATA +272 -0
  2. arthexis-0.1.26.dist-info/RECORD +111 -0
  3. {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/licenses/LICENSE +674 -674
  4. config/__init__.py +5 -5
  5. config/active_app.py +15 -15
  6. config/asgi.py +29 -29
  7. config/auth_app.py +7 -7
  8. config/celery.py +32 -25
  9. config/context_processors.py +67 -68
  10. config/horologia_app.py +7 -7
  11. config/loadenv.py +11 -11
  12. config/logging.py +59 -48
  13. config/middleware.py +71 -25
  14. config/offline.py +49 -49
  15. config/settings.py +676 -492
  16. config/settings_helpers.py +109 -0
  17. config/urls.py +228 -159
  18. config/wsgi.py +17 -17
  19. core/admin.py +4052 -2066
  20. core/admin_history.py +50 -50
  21. core/admindocs.py +192 -151
  22. core/apps.py +350 -223
  23. core/auto_upgrade.py +72 -0
  24. core/backends.py +311 -124
  25. core/changelog.py +403 -0
  26. core/entity.py +149 -133
  27. core/environment.py +60 -43
  28. core/fields.py +168 -75
  29. core/form_fields.py +75 -0
  30. core/github_helper.py +188 -25
  31. core/github_issues.py +183 -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 +114 -100
  36. core/mailer.py +89 -83
  37. core/middleware.py +91 -91
  38. core/models.py +5041 -2195
  39. core/notifications.py +105 -105
  40. core/public_wifi.py +267 -227
  41. core/reference_utils.py +107 -0
  42. core/release.py +940 -346
  43. core/rfid_import_export.py +113 -0
  44. core/sigil_builder.py +149 -131
  45. core/sigil_context.py +20 -20
  46. core/sigil_resolver.py +250 -284
  47. core/system.py +1425 -230
  48. core/tasks.py +538 -199
  49. core/temp_passwords.py +181 -0
  50. core/test_system_info.py +202 -43
  51. core/tests.py +2673 -1069
  52. core/tests_liveupdate.py +17 -17
  53. core/urls.py +11 -11
  54. core/user_data.py +681 -495
  55. core/views.py +2484 -789
  56. core/widgets.py +213 -51
  57. nodes/admin.py +2236 -445
  58. nodes/apps.py +98 -70
  59. nodes/backends.py +160 -53
  60. nodes/dns.py +203 -0
  61. nodes/feature_checks.py +133 -0
  62. nodes/lcd.py +165 -165
  63. nodes/models.py +2375 -870
  64. nodes/reports.py +411 -0
  65. nodes/rfid_sync.py +210 -0
  66. nodes/signals.py +18 -0
  67. nodes/tasks.py +141 -46
  68. nodes/tests.py +5045 -1489
  69. nodes/urls.py +29 -13
  70. nodes/utils.py +172 -73
  71. nodes/views.py +1768 -304
  72. ocpp/admin.py +1775 -481
  73. ocpp/apps.py +25 -25
  74. ocpp/consumers.py +1843 -630
  75. ocpp/evcs.py +844 -928
  76. ocpp/evcs_discovery.py +158 -0
  77. ocpp/models.py +1417 -640
  78. ocpp/network.py +398 -0
  79. ocpp/reference_utils.py +42 -0
  80. ocpp/routing.py +11 -9
  81. ocpp/simulator.py +745 -368
  82. ocpp/status_display.py +26 -0
  83. ocpp/store.py +603 -403
  84. ocpp/tasks.py +479 -31
  85. ocpp/test_export_import.py +131 -130
  86. ocpp/test_rfid.py +1072 -540
  87. ocpp/tests.py +5494 -2296
  88. ocpp/transactions_io.py +197 -165
  89. ocpp/urls.py +50 -50
  90. ocpp/views.py +2024 -912
  91. pages/admin.py +1123 -396
  92. pages/apps.py +45 -10
  93. pages/checks.py +40 -40
  94. pages/context_processors.py +151 -85
  95. pages/defaults.py +13 -0
  96. pages/forms.py +221 -0
  97. pages/middleware.py +213 -153
  98. pages/models.py +720 -252
  99. pages/module_defaults.py +156 -0
  100. pages/site_config.py +137 -0
  101. pages/tasks.py +74 -0
  102. pages/tests.py +4009 -1389
  103. pages/urls.py +38 -20
  104. pages/utils.py +93 -12
  105. pages/views.py +1736 -762
  106. arthexis-0.1.9.dist-info/METADATA +0 -168
  107. arthexis-0.1.9.dist-info/RECORD +0 -92
  108. core/workgroup_urls.py +0 -17
  109. core/workgroup_views.py +0 -94
  110. nodes/actions.py +0 -70
  111. {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/WHEEL +0 -0
  112. {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/top_level.txt +0 -0
ocpp/evcs_discovery.py ADDED
@@ -0,0 +1,158 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ from dataclasses import dataclass
5
+ from ipaddress import IPv4Address
6
+ from typing import Iterable, Sequence
7
+
8
+ DEFAULT_TOP_PORTS = 200
9
+ DEFAULT_CONSOLE_PORT = 8900
10
+ PORT_PREFERENCES: Sequence[int] = (
11
+ DEFAULT_CONSOLE_PORT,
12
+ 8443,
13
+ 9443,
14
+ 443,
15
+ 8080,
16
+ 8800,
17
+ 8000,
18
+ 8001,
19
+ 8880,
20
+ 80,
21
+ )
22
+ HTTPS_PORTS = {443, 8443, 9443}
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class ConsoleEndpoint:
27
+ host: str
28
+ port: int
29
+ secure: bool = False
30
+
31
+ @property
32
+ def url(self) -> str:
33
+ return build_console_url(self.host, self.port, self.secure)
34
+
35
+
36
+ def scan_open_ports(
37
+ host: str,
38
+ *,
39
+ nmap_path: str = "nmap",
40
+ full: bool = False,
41
+ top_ports: int = DEFAULT_TOP_PORTS,
42
+ ) -> list[int]:
43
+ """Return the list of open TCP ports discovered with nmap.
44
+
45
+ The function mirrors the behaviour of the ``evcs_discover`` shell script.
46
+ It uses nmap's grepable output so the caller can avoid touching the
47
+ filesystem and parse the results quickly.
48
+ """
49
+
50
+ port_args: list[str]
51
+ if full:
52
+ port_args = ["-p-"]
53
+ else:
54
+ if top_ports <= 0:
55
+ raise ValueError("top_ports must be greater than zero")
56
+ port_args = ["--top-ports", str(top_ports)]
57
+
58
+ args = [
59
+ nmap_path,
60
+ "-sS",
61
+ "-Pn",
62
+ "-n",
63
+ "-T4",
64
+ "--open",
65
+ *port_args,
66
+ host,
67
+ "-oG",
68
+ "-",
69
+ ]
70
+
71
+ try:
72
+ proc = subprocess.run(
73
+ args,
74
+ check=False,
75
+ capture_output=True,
76
+ text=True,
77
+ )
78
+ except FileNotFoundError:
79
+ return []
80
+ except subprocess.SubprocessError:
81
+ return []
82
+
83
+ if proc.returncode != 0:
84
+ return []
85
+
86
+ return _parse_nmap_open_ports(proc.stdout)
87
+
88
+
89
+ def _parse_nmap_open_ports(output: str) -> list[int]:
90
+ ports: list[int] = []
91
+ for line in output.splitlines():
92
+ if "Ports:" not in line:
93
+ continue
94
+ try:
95
+ _, ports_section = line.split("Ports:", 1)
96
+ except ValueError:
97
+ continue
98
+ for entry in ports_section.split(","):
99
+ entry = entry.strip()
100
+ if not entry:
101
+ continue
102
+ parts = entry.split("/")
103
+ if len(parts) < 2:
104
+ continue
105
+ state = parts[1].strip().lower()
106
+ if state != "open":
107
+ continue
108
+ try:
109
+ port = int(parts[0])
110
+ except ValueError:
111
+ continue
112
+ if port not in ports:
113
+ ports.append(port)
114
+ return ports
115
+
116
+
117
+ def prioritise_ports(ports: Iterable[int]) -> list[int]:
118
+ """Order ports so the most likely console endpoints are tried first."""
119
+
120
+ unique = []
121
+ seen = set()
122
+ available = list(dict.fromkeys(ports))
123
+ for preferred in PORT_PREFERENCES:
124
+ if preferred in available and preferred not in seen:
125
+ unique.append(preferred)
126
+ seen.add(preferred)
127
+ for port in available:
128
+ if port not in seen:
129
+ unique.append(port)
130
+ seen.add(port)
131
+ return unique
132
+
133
+
134
+ def select_console_port(ports: Sequence[int]) -> ConsoleEndpoint | None:
135
+ """Pick the best console port from a list of open ports."""
136
+
137
+ if not ports:
138
+ return None
139
+ ordered = prioritise_ports(ports)
140
+ if not ordered:
141
+ return None
142
+ port = ordered[0]
143
+ secure = port in HTTPS_PORTS
144
+ return ConsoleEndpoint(host="", port=port, secure=secure)
145
+
146
+
147
+ def build_console_url(host: str, port: int, secure: bool) -> str:
148
+ scheme = "https" if secure else "http"
149
+ host_part = host
150
+ if ":" in host and not host.startswith("["):
151
+ host_part = f"[{host}]"
152
+ return f"{scheme}://{host_part}:{port}"
153
+
154
+
155
+ def normalise_host(host: str | IPv4Address) -> str:
156
+ if isinstance(host, IPv4Address):
157
+ return str(host)
158
+ return str(host)