Skip to content

Commit a616704

Browse files
Add extension tests for win32, networking, and wasapi,
create test.asmxt for dependencies, fix ext/ handling in frozen interpreters.
1 parent 536e4c9 commit a616704

File tree

4 files changed

+81
-14
lines changed

4 files changed

+81
-14
lines changed

asm-lang.exe

4.88 KB
Binary file not shown.

extensions.py

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,41 @@ def register_repl(self, *, name: str, runner: Callable[[ReplContext], int]) -> N
241241
self._services.hook_registry.register_repl(name=name, runner=runner, ext_name=self._ext_name)
242242

243243

244+
def _extension_search_roots() -> List[str]:
245+
"""Return directories to search for the interpreter's built-in `ext/`.
246+
247+
When running as a frozen executable (e.g. PyInstaller), `__file__` points to
248+
the extracted bundle, but users often ship extensions alongside the exe.
249+
Prefer the exe directory, then the bundled extraction dir, then source dir.
250+
"""
251+
252+
roots: List[str] = []
253+
if getattr(sys, "frozen", False):
254+
roots.append(os.path.dirname(os.path.abspath(sys.executable)))
255+
meipass = getattr(sys, "_MEIPASS", None)
256+
if isinstance(meipass, str) and meipass:
257+
roots.append(os.path.abspath(meipass))
258+
roots.append(os.path.dirname(os.path.abspath(__file__)))
259+
# de-dup while preserving order
260+
out: List[str] = []
261+
seen: set[str] = set()
262+
for r in roots:
263+
if r not in seen:
264+
out.append(r)
265+
seen.add(r)
266+
return out
267+
268+
269+
def _resolve_in_builtin_ext(path: str) -> Optional[str]:
270+
if os.path.isabs(path):
271+
return None
272+
for root in _extension_search_roots():
273+
candidate = os.path.join(root, "ext", path)
274+
if os.path.exists(candidate):
275+
return os.path.abspath(candidate)
276+
return None
277+
278+
244279
def _unique_module_name(path: str) -> str:
245280
base = os.path.basename(path)
246281
digest = hashlib.sha256(os.path.abspath(path).encode("utf-8")).hexdigest()[:12]
@@ -253,9 +288,9 @@ def load_extension_module(path: str) -> Any:
253288
# interpreter's own `ext` directory as a fallback before failing.
254289
if not os.path.exists(path):
255290
if not os.path.isabs(path):
256-
interpreter_ext = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ext", path)
257-
if os.path.exists(interpreter_ext):
258-
path = interpreter_ext
291+
resolved = _resolve_in_builtin_ext(path)
292+
if resolved is not None:
293+
path = resolved
259294
else:
260295
raise ASMExtensionError(f"Extension not found: {path}")
261296
else:
@@ -309,22 +344,22 @@ def read_asmx(pointer_file: str) -> List[str]:
309344
# Resolve relative entries: prefer pointer-file base dir, then
310345
# cwd, then interpreter's ext/ directory as a final fallback.
311346
candidate = line
312-
if not os.path.isabs(candidate):
347+
if not os.path.isabs(candidate): # relative path
313348
candidate_base = os.path.abspath(os.path.join(base_dir, candidate))
314-
if os.path.exists(candidate_base):
349+
if os.path.exists(candidate_base): # found relative to pointer file
315350
out.append(candidate_base)
316351
continue
317352
candidate_cwd = os.path.abspath(candidate)
318-
if os.path.exists(candidate_cwd):
353+
if os.path.exists(candidate_cwd): # found relative to cwd
319354
out.append(candidate_cwd)
320355
continue
321-
interpreter_ext = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ext", candidate)
322-
if os.path.exists(interpreter_ext):
323-
out.append(os.path.abspath(interpreter_ext))
356+
resolved = _resolve_in_builtin_ext(candidate)
357+
if resolved is not None:
358+
out.append(resolved)
324359
continue
325360
raise ASMExtensionError(f"Extension referenced in {pointer_file} not found: {candidate}")
326-
else:
327-
if os.path.exists(candidate):
361+
else: # absolute path
362+
if os.path.exists(candidate): # found as absolute path
328363
out.append(os.path.abspath(candidate))
329364
else:
330365
raise ASMExtensionError(f"Extension referenced in {pointer_file} not found: {candidate}")
@@ -345,9 +380,9 @@ def gather_extension_paths(paths: Sequence[str]) -> List[str]:
345380
# the current working directory, try the interpreter's `ext`
346381
# directory as a fallback.
347382
if not os.path.isabs(p) and not os.path.exists(p):
348-
alt = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ext", p)
349-
if os.path.exists(alt):
350-
expanded.append(os.path.abspath(alt))
383+
resolved = _resolve_in_builtin_ext(p)
384+
if resolved is not None:
385+
expanded.append(resolved)
351386
continue
352387
expanded.append(p)
353388
# normalize

test.asmln

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,36 @@ FUNC RUN_TESTS():INT{
126126

127127
PRINT("Waveform library tests passed.")
128128

129+
# Extension tests (requires interpreter to be started with these extensions loaded)
130+
PRINT()
131+
132+
PRINT("Running extension tests...")
133+
134+
# win32 extension
135+
ASSERT(EQ(win32.WIN_SLEEP(0), 0))
136+
INT: ticks = win32.WIN_CALL("kernel32", "GetTickCount64", "", "I")
137+
ASSERT(GTE(ticks, 0))
138+
INT: last_err = win32.WIN_LAST_ERROR()
139+
ASSERT(GTE(last_err, 0))
140+
PRINT("win32 extension tests passed.")
141+
142+
# networking extension (local-only; no external internet required)
143+
INT: udp = networking.UDP_BIND("127.0.0.1", 0)
144+
ASSERT(GT(udp, 0))
145+
ASSERT(EQ(networking.UDP_CLOSE(udp), 0))
146+
PRINT("networking extension tests passed.")
147+
148+
# wasapi extension (read-only queries)
149+
STR: devname = wasapi.WASAPI_GET_DEFAULT_DEVICE_NAME()
150+
ASSERT(GT(SLEN(devname), 0))
151+
INT: volpct = wasapi.WASAPI_GET_MASTER_VOLUME()
152+
ASSERT(GTE(volpct, 0))
153+
ASSERT(LTE(volpct, 1100100)) # dec 100
154+
PRINT("wasapi extension tests passed.")
155+
129156
# If we reach here all tests passed; print success code and return
157+
PRINT()
158+
130159
PRINT("All tests passed.")
131160
RETURN(0)
132161
}

test.asmxt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
networking.py
2+
wasapi.py
3+
win32.py

0 commit comments

Comments
 (0)