Skip to content

Commit a3bfa09

Browse files
committed
Update PyInstaller engine and related files
1 parent b982dfa commit a3bfa09

5 files changed

Lines changed: 496 additions & 205 deletions

File tree

ENGINES/pyinstaller/__init__.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,56 @@
1-
from .engine import PyInstallerEngine
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright 2025 Ague Samuel Amen
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
215

3-
__all__ = ["PyInstallerEngine"]
16+
from __future__ import annotations
17+
18+
import importlib
19+
import pkgutil
20+
21+
__all__: list[str] = []
22+
23+
# Explicit registration to ensure the engine is available even if auto-import misses it
24+
try:
25+
from engine_sdk import registry as _registry # type: ignore
26+
27+
from .engine import PyInstallerEngine as _PyInstallerEngine
28+
29+
if _registry:
30+
_registry.register(_PyInstallerEngine)
31+
except Exception:
32+
pass
33+
34+
35+
def _auto_import_all() -> None:
36+
"""
37+
Import all Python modules and subpackages contained in this package.
38+
This ensures any engine definitions or side-effects are loaded on import.
39+
"""
40+
try:
41+
pkg_name = __name__
42+
for _finder, name, _ispkg in pkgutil.walk_packages(
43+
__path__, prefix=f"{pkg_name}."
44+
):
45+
try:
46+
importlib.import_module(name)
47+
short = name.rsplit(".", 1)[-1]
48+
if short not in __all__:
49+
__all__.append(short)
50+
except Exception:
51+
pass
52+
except Exception:
53+
pass
54+
55+
56+
_auto_import_all()

ENGINES/pyinstaller/auto_plugins.py

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: Apache-2.0
2-
# Copyright 2026 Ague Samuel Amen
2+
# Copyright 2025 Ague Samuel Amen
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16+
1617
from __future__ import annotations
1718

1819
# Engine-controlled auto builder for PyInstaller
@@ -27,38 +28,82 @@ def AUTO_BUILDER(
2728
Build PyInstaller arguments from the engine-owned mapping.
2829
2930
Mapping conventions supported for an entry value under key "pyinstaller":
30-
- str: a single CLI argument (e.g., "--collect-all=numpy")
31-
- list[str]: multiple CLI arguments
32-
- dict: expects 'args' or 'flags' -> str | list[str]
33-
- True: ignored by default (no generic meaning)
31+
- True: emit ["--collect-all", {import_name}] for the matched package
32+
- str: a single CLI arg; supports {import_name} placeholder
33+
- list[str]: multiple CLI args; supports {import_name} placeholder
34+
- dict: expects 'args' or 'flags' -> str | list[str]; supports placeholder
3435
"""
3536
out: list[str] = []
36-
seen = set()
37+
seen_items = set()
38+
seen_collect_all = set()
3739

3840
for pkg, entry in matched.items():
3941
if not isinstance(entry, dict):
4042
continue
4143
val = entry.get("pyinstaller")
42-
if val is None:
43-
continue
44+
import_name = pkg_to_import.get(pkg, pkg)
45+
4446
args: list[str] = []
45-
if isinstance(val, str):
46-
tmpl_import = pkg_to_import.get(pkg, pkg)
47-
args = [val.replace("{import_name}", tmpl_import)]
47+
if val is True:
48+
if import_name and import_name not in seen_collect_all:
49+
args = ["--collect-all", import_name]
50+
seen_collect_all.add(import_name)
51+
elif isinstance(val, str):
52+
# Split single string into proper argv tokens (e.g. "--collect-all {import_name}")
53+
s = val.replace("{import_name}", import_name)
54+
try:
55+
import shlex as _shlex
56+
57+
args = _shlex.split(s)
58+
except Exception:
59+
args = s.split()
4860
elif isinstance(val, list):
49-
tmpl_import = pkg_to_import.get(pkg, pkg)
50-
args = [str(x).replace("{import_name}", tmpl_import) for x in val]
61+
# Flatten list entries, splitting any that contain spaces
62+
tmp: list[str] = []
63+
for x in val:
64+
s = str(x).replace("{import_name}", import_name)
65+
try:
66+
import shlex as _shlex
67+
68+
parts = _shlex.split(s)
69+
except Exception:
70+
parts = s.split()
71+
tmp.extend(parts)
72+
args = tmp
5173
elif isinstance(val, dict):
52-
tmpl_import = pkg_to_import.get(pkg, pkg)
5374
a = val.get("args") or val.get("flags")
5475
if isinstance(a, list):
55-
args = [str(x).replace("{import_name}", tmpl_import) for x in a]
76+
tmp: list[str] = []
77+
for x in a:
78+
s = str(x).replace("{import_name}", import_name)
79+
try:
80+
import shlex as _shlex
81+
82+
parts = _shlex.split(s)
83+
except Exception:
84+
parts = s.split()
85+
tmp.extend(parts)
86+
args = tmp
5687
elif isinstance(a, str):
57-
args = [str(a).replace("{import_name}", tmpl_import)]
58-
for a in args:
59-
if a not in seen:
60-
out.append(a)
61-
seen.add(a)
88+
s = str(a).replace("{import_name}", import_name)
89+
try:
90+
import shlex as _shlex
91+
92+
args = _shlex.split(s)
93+
except Exception:
94+
args = s.split()
95+
96+
# de-dup while preserving order
97+
i = 0
98+
while i < len(args):
99+
item = args[i]
100+
key = item
101+
if item == "--collect-all" and (i + 1) < len(args):
102+
key = f"--collect-all {args[i+1]}"
103+
if key not in seen_items:
104+
out.append(item)
105+
seen_items.add(key)
106+
i += 1
62107

63108
return out
64109

0 commit comments

Comments
 (0)