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
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)
|