Merge pull request 'fix: preserve caller globals in exec() for module Init.py/InitGui.py loading' (#240) from fix/exec-globals-regression into main
Some checks failed
Build and Test / build (push) Has been cancelled
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #240
This commit was merged in pull request #240.
This commit is contained in:
@@ -47,37 +47,43 @@ App.Console.PrintLog("░░░░█░░█░█░░█░░░█░░
|
||||
App.Console.PrintLog("░░░▀▀▀░▀░▀░▀▀▀░░▀░░░░▀░▀░▀░░░▀░░░░\n")
|
||||
|
||||
try:
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
import inspect
|
||||
from enum import IntEnum # Leak to globals (backwards compat)
|
||||
from datetime import datetime # Leak to globals (backwards compat)
|
||||
from pathlib import Path # Removed manually
|
||||
import dataclasses
|
||||
import collections
|
||||
import collections.abc as coll_abc
|
||||
import platform
|
||||
import types
|
||||
import importlib.resources as resources
|
||||
import importlib
|
||||
import dataclasses
|
||||
import functools
|
||||
import re
|
||||
import importlib
|
||||
import importlib.resources as resources
|
||||
import inspect
|
||||
import os
|
||||
import pkgutil
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
import types
|
||||
from datetime import datetime # Leak to globals (backwards compat)
|
||||
from enum import IntEnum # Leak to globals (backwards compat)
|
||||
from pathlib import Path # Removed manually
|
||||
except ImportError:
|
||||
App.Console.PrintError("\n\nSeems the python standard libs are not installed, bailing out!\n\n")
|
||||
App.Console.PrintError(
|
||||
"\n\nSeems the python standard libs are not installed, bailing out!\n\n"
|
||||
)
|
||||
raise
|
||||
|
||||
# ┌────────────────────────────────────────────────┐
|
||||
# │ Logging Frameworks │
|
||||
# └────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
def __logger(fn):
|
||||
__logger.sep = "\n"
|
||||
|
||||
def wrapper(text: object, *, sep: str | None = None) -> None:
|
||||
fn(f"{text!s}{__logger.sep if sep is None else sep}")
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
Log = __logger(App.Console.PrintLog)
|
||||
Msg = __logger(App.Console.PrintMessage)
|
||||
Err = __logger(App.Console.PrintError)
|
||||
@@ -129,18 +135,18 @@ class FCADLogger:
|
||||
"""
|
||||
|
||||
_levels = {
|
||||
'Error': 0,
|
||||
'error': 0,
|
||||
'Warning': 1,
|
||||
'warn': 1,
|
||||
'Message': 2,
|
||||
'msg': 2,
|
||||
'info': 2,
|
||||
'Log': 3,
|
||||
'log': 3,
|
||||
'debug': 3,
|
||||
'Trace': 4,
|
||||
'trace': 4,
|
||||
"Error": 0,
|
||||
"error": 0,
|
||||
"Warning": 1,
|
||||
"warn": 1,
|
||||
"Message": 2,
|
||||
"msg": 2,
|
||||
"info": 2,
|
||||
"Log": 3,
|
||||
"log": 3,
|
||||
"debug": 3,
|
||||
"Trace": 4,
|
||||
"trace": 4,
|
||||
}
|
||||
|
||||
_printer = (
|
||||
@@ -148,16 +154,16 @@ class FCADLogger:
|
||||
App.Console.PrintWarning,
|
||||
App.Console.PrintMessage,
|
||||
App.Console.PrintLog,
|
||||
App.Console.PrintLog
|
||||
App.Console.PrintLog,
|
||||
)
|
||||
|
||||
_defaults = (
|
||||
('printTag', True),
|
||||
('noUpdateUI', True),
|
||||
('timing', True),
|
||||
('lineno', True),
|
||||
('parent', None),
|
||||
('title', 'FreeCAD'),
|
||||
("printTag", True),
|
||||
("noUpdateUI", True),
|
||||
("timing", True),
|
||||
("lineno", True),
|
||||
("parent", None),
|
||||
("title", "FreeCAD"),
|
||||
)
|
||||
|
||||
printTag: bool
|
||||
@@ -239,7 +245,7 @@ class FCADLogger:
|
||||
|
||||
def log_fn(self, msg: str, *args, **kwargs) -> None:
|
||||
if self._isEnabledFor(level):
|
||||
frame = kwargs.pop('frame', 0) + 1
|
||||
frame = kwargs.pop("frame", 0) + 1
|
||||
self._log(level, msg, frame, args, kwargs)
|
||||
|
||||
log_fn.__doc__ = docstring
|
||||
@@ -279,29 +285,31 @@ class FCADLogger:
|
||||
else:
|
||||
msg = msg.format(*args, **kwargs)
|
||||
|
||||
prefix = ''
|
||||
prefix = ""
|
||||
|
||||
if self.timing:
|
||||
now = datetime.now()
|
||||
prefix += '{} '.format((now-self.laststamp).total_seconds())
|
||||
prefix += "{} ".format((now - self.laststamp).total_seconds())
|
||||
self.laststamp = now
|
||||
|
||||
if self.printTag:
|
||||
prefix += '<{}> '.format(self.tag)
|
||||
prefix += "<{}> ".format(self.tag)
|
||||
|
||||
if self.lineno:
|
||||
try:
|
||||
frame = sys._getframe(frame + 1)
|
||||
prefix += '{}({}): '.format(os.path.basename(
|
||||
frame.f_code.co_filename),frame.f_lineno)
|
||||
prefix += "{}({}): ".format(
|
||||
os.path.basename(frame.f_code.co_filename), frame.f_lineno
|
||||
)
|
||||
except Exception:
|
||||
frame = inspect.stack()[frame + 1]
|
||||
prefix += '{}({}): '.format(os.path.basename(frame[1]),frame[2])
|
||||
prefix += "{}({}): ".format(os.path.basename(frame[1]), frame[2])
|
||||
|
||||
self.__class__._printer[level]('{}{}\n'.format(prefix,msg))
|
||||
self.__class__._printer[level]("{}{}\n".format(prefix, msg))
|
||||
|
||||
if not self.noUpdateUI and App.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
try:
|
||||
FreeCADGui.updateGui()
|
||||
except Exception:
|
||||
@@ -380,7 +388,9 @@ class FCADLogger:
|
||||
except Exception as e:
|
||||
self.error(f"{msg}\n{traceback.format_exc()}", frame=1)
|
||||
if App.GuiUp:
|
||||
import FreeCADGui, PySide
|
||||
import FreeCADGui
|
||||
import PySide
|
||||
|
||||
PySide.QtGui.QMessageBox.critical(
|
||||
FreeCADGui.getMainWindow(),
|
||||
self.title,
|
||||
@@ -631,6 +641,7 @@ App.Units.YieldStrength = App.Units.Unit(-1,1,-2)
|
||||
App.Units.YoungsModulus = App.Units.Unit(-1,1,-2)
|
||||
# fmt: on
|
||||
|
||||
|
||||
# The values must match with that of the
|
||||
# C++ enum class UnitSystem
|
||||
class Scheme(IntEnum):
|
||||
@@ -645,15 +656,19 @@ class Scheme(IntEnum):
|
||||
FEM = 8
|
||||
MeterDecimal = 9
|
||||
|
||||
|
||||
App.Units.Scheme = Scheme
|
||||
|
||||
|
||||
class NumberFormat(IntEnum):
|
||||
Default = 0
|
||||
Fixed = 1
|
||||
Scientific = 2
|
||||
|
||||
|
||||
App.Units.NumberFormat = NumberFormat
|
||||
|
||||
|
||||
class ScaleType(IntEnum):
|
||||
Other = -1
|
||||
NoScaling = 0
|
||||
@@ -661,8 +676,10 @@ class ScaleType(IntEnum):
|
||||
NonUniformLeft = 2
|
||||
Uniform = 3
|
||||
|
||||
|
||||
App.ScaleType = ScaleType
|
||||
|
||||
|
||||
class PropertyType(IntEnum):
|
||||
Prop_None = 0
|
||||
Prop_ReadOnly = 1
|
||||
@@ -672,8 +689,10 @@ class PropertyType(IntEnum):
|
||||
Prop_NoRecompute = 16
|
||||
Prop_NoPersist = 32
|
||||
|
||||
|
||||
App.PropertyType = PropertyType
|
||||
|
||||
|
||||
class ReturnType(IntEnum):
|
||||
PyObject = 0
|
||||
DocObject = 1
|
||||
@@ -683,6 +702,7 @@ class ReturnType(IntEnum):
|
||||
LinkAndPlacement = 5
|
||||
LinkAndMatrix = 6
|
||||
|
||||
|
||||
App.ReturnType = ReturnType
|
||||
|
||||
|
||||
@@ -690,6 +710,7 @@ App.ReturnType = ReturnType
|
||||
# │ Init Framework │
|
||||
# └────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
class Transient:
|
||||
"""
|
||||
Mark the symbol for removal from global scope on cleanup.
|
||||
@@ -705,8 +726,12 @@ class Transient:
|
||||
def cleanup(cls) -> None:
|
||||
# Remove imports
|
||||
# os: kept for backwards compat
|
||||
keep = set(("__builtins__", "FreeCAD", "App", "os", "sys", "traceback", "inspect"))
|
||||
names = [name for name, ref in globals().items() if isinstance(ref, types.ModuleType)]
|
||||
keep = set(
|
||||
("__builtins__", "FreeCAD", "App", "os", "sys", "traceback", "inspect")
|
||||
)
|
||||
names = [
|
||||
name for name, ref in globals().items() if isinstance(ref, types.ModuleType)
|
||||
]
|
||||
for name in names:
|
||||
if name not in keep:
|
||||
del globals()[name]
|
||||
@@ -726,6 +751,7 @@ def call_in_place(fn):
|
||||
fn()
|
||||
return fn
|
||||
|
||||
|
||||
@transient
|
||||
class utils:
|
||||
HLine = "-" * 80
|
||||
@@ -755,6 +781,7 @@ class utils:
|
||||
try:
|
||||
import readline
|
||||
import rlcompleter # noqa: F401, import required
|
||||
|
||||
readline.parse_and_bind("tab: complete")
|
||||
except ImportError:
|
||||
# Note: As there is no readline on Windows,
|
||||
@@ -770,6 +797,7 @@ class PathPriority(IntEnum):
|
||||
OverrideLast = 3
|
||||
OverrideFirst = 4
|
||||
|
||||
|
||||
@transient
|
||||
@dataclasses.dataclass
|
||||
class PathSet:
|
||||
@@ -787,10 +815,16 @@ class PathSet:
|
||||
"""
|
||||
|
||||
source: list["Path | PathSet"] = dataclasses.field(default_factory=list)
|
||||
override: collections.deque["Path | PathSet"] = dataclasses.field(default_factory=collections.deque)
|
||||
fallback: collections.deque["Path | PathSet"] = dataclasses.field(default_factory=collections.deque)
|
||||
override: collections.deque["Path | PathSet"] = dataclasses.field(
|
||||
default_factory=collections.deque
|
||||
)
|
||||
fallback: collections.deque["Path | PathSet"] = dataclasses.field(
|
||||
default_factory=collections.deque
|
||||
)
|
||||
|
||||
def add(self, item: "Path | PathSet", priority: PathPriority = PathPriority.OverrideLast) -> None:
|
||||
def add(
|
||||
self, item: "Path | PathSet", priority: PathPriority = PathPriority.OverrideLast
|
||||
) -> None:
|
||||
"""Add item into the corresponding priority slot."""
|
||||
if isinstance(item, Path):
|
||||
item = item.resolve()
|
||||
@@ -828,6 +862,7 @@ class PathSet:
|
||||
"""
|
||||
return list(dict.fromkeys(self.iter()))
|
||||
|
||||
|
||||
@transient
|
||||
class SearchPaths:
|
||||
"""
|
||||
@@ -843,7 +878,9 @@ class SearchPaths:
|
||||
dll_path: PathSet
|
||||
|
||||
def __init__(self):
|
||||
self.env_path = PathSet([Path(p) for p in os.environ.get("PATH", "").split(os.pathsep)])
|
||||
self.env_path = PathSet(
|
||||
[Path(p) for p in os.environ.get("PATH", "").split(os.pathsep)]
|
||||
)
|
||||
self.sys_path = PathSet(sys.path)
|
||||
self.dll_path = PathSet()
|
||||
|
||||
@@ -853,7 +890,7 @@ class SearchPaths:
|
||||
*,
|
||||
env_path: PathPriority = PathPriority.OverrideLast,
|
||||
sys_path: PathPriority = PathPriority.OverrideFirst,
|
||||
dll_path: PathPriority = PathPriority.OverrideLast
|
||||
dll_path: PathPriority = PathPriority.OverrideLast,
|
||||
) -> None:
|
||||
"""
|
||||
Add item to required namespaces with the specified priority.
|
||||
@@ -866,7 +903,9 @@ class SearchPaths:
|
||||
|
||||
def commit(self) -> None:
|
||||
"""Apply changes to underlying namespaces and priorities."""
|
||||
os.environ["PATH"] = os.pathsep.join(str(path) for path in self.env_path.build())
|
||||
os.environ["PATH"] = os.pathsep.join(
|
||||
str(path) for path in self.env_path.build()
|
||||
)
|
||||
sys.path = [str(path) for path in self.sys_path.build()]
|
||||
|
||||
if win32 := WindowsPlatform():
|
||||
@@ -880,8 +919,10 @@ class SearchPaths:
|
||||
class Config:
|
||||
AdditionalModulePaths = utils.str_to_paths(App.ConfigGet("AdditionalModulePaths"))
|
||||
AdditionalMacroPaths = utils.str_to_paths(App.ConfigGet("AdditionalMacroPaths"))
|
||||
RunMode: str = App.ConfigGet('RunMode')
|
||||
DisabledAddons: set[str] = set(mod for mod in App.ConfigGet("DisabledAddons").split(";") if mod)
|
||||
RunMode: str = App.ConfigGet("RunMode")
|
||||
DisabledAddons: set[str] = set(
|
||||
mod for mod in App.ConfigGet("DisabledAddons").split(";") if mod
|
||||
)
|
||||
|
||||
|
||||
@transient
|
||||
@@ -891,7 +932,7 @@ class WindowsPlatform:
|
||||
"""
|
||||
|
||||
initialized = False
|
||||
enabled = platform.system() == 'Windows' and hasattr(os, "add_dll_directory")
|
||||
enabled = platform.system() == "Windows" and hasattr(os, "add_dll_directory")
|
||||
|
||||
def __init__(self) -> None:
|
||||
if not WindowsPlatform.enabled or WindowsPlatform.initialized:
|
||||
@@ -1038,7 +1079,9 @@ class ExtMod(Mod):
|
||||
|
||||
def check_disabled(self) -> bool:
|
||||
with resources.as_file(resources.files(self.name)) as base:
|
||||
return (base / self.ADDON_DISABLED).exists() or (base.parent.parent / self.ADDON_DISABLED).exists()
|
||||
return (base / self.ADDON_DISABLED).exists() or (
|
||||
base.parent.parent / self.ADDON_DISABLED
|
||||
).exists()
|
||||
|
||||
def process_metadata(self, _search_paths: SearchPaths) -> None:
|
||||
meta = self.metadata
|
||||
@@ -1047,14 +1090,16 @@ class ExtMod(Mod):
|
||||
|
||||
if not self.supports_freecad_version():
|
||||
self.state = ModState.Unsupported
|
||||
Msg(f"NOTICE: {self.name} does not support this version of FreeCAD, so is being skipped")
|
||||
Msg(
|
||||
f"NOTICE: {self.name} does not support this version of FreeCAD, so is being skipped"
|
||||
)
|
||||
|
||||
def _init_error(self, ex: Exception, error_msg: str) -> None:
|
||||
Err(f'During initialization the error "{ex!s}" occurred in {self.name}')
|
||||
Err(utils.HLine)
|
||||
Err(error_msg)
|
||||
Err(utils.HLine)
|
||||
Log(f'Init: Initializing {self.name}... failed')
|
||||
Log(f"Init: Initializing {self.name}... failed")
|
||||
Err(utils.HLine)
|
||||
Log(error_msg)
|
||||
Err(utils.HLine)
|
||||
@@ -1106,7 +1151,7 @@ class DirMod(Mod):
|
||||
|
||||
@property
|
||||
def init_mode(self) -> str:
|
||||
return "exec" if (self.path / self.INIT_PY).exists() else ''
|
||||
return "exec" if (self.path / self.INIT_PY).exists() else ""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
@@ -1126,7 +1171,9 @@ class DirMod(Mod):
|
||||
|
||||
if not self.supports_freecad_version():
|
||||
self.state = ModState.Unsupported
|
||||
Msg(f"NOTICE: {meta.Name} does not support this version of FreeCAD, so is being skipped")
|
||||
Msg(
|
||||
f"NOTICE: {meta.Name} does not support this version of FreeCAD, so is being skipped"
|
||||
)
|
||||
return
|
||||
|
||||
content = meta.Content
|
||||
@@ -1134,10 +1181,16 @@ class DirMod(Mod):
|
||||
workbenches = content["workbench"]
|
||||
for workbench in workbenches:
|
||||
if not workbench.supportsCurrentFreeCAD():
|
||||
Msg(f"NOTICE: {meta.Name} content item {workbench.Name} does not support this version of FreeCAD, so is being skipped")
|
||||
Msg(
|
||||
f"NOTICE: {meta.Name} content item {workbench.Name} does not support this version of FreeCAD, so is being skipped"
|
||||
)
|
||||
continue
|
||||
|
||||
subdirectory = workbench.Name if not workbench.Subdirectory else workbench.Subdirectory
|
||||
subdirectory = (
|
||||
workbench.Name
|
||||
if not workbench.Subdirectory
|
||||
else workbench.Subdirectory
|
||||
)
|
||||
subdirectory = re.split(r"[/\\]+", subdirectory)
|
||||
subdirectory = self.path / Path(*subdirectory)
|
||||
|
||||
@@ -1168,12 +1221,16 @@ class DirMod(Mod):
|
||||
name = self.path.name
|
||||
|
||||
if name in Config.DisabledAddons:
|
||||
Msg(f'NOTICE: Addon "{name}" disabled by presence of "--disable-addon {name}" argument')
|
||||
Msg(
|
||||
f'NOTICE: Addon "{name}" disabled by presence of "--disable-addon {name}" argument'
|
||||
)
|
||||
return True
|
||||
|
||||
for flag in (self.ALL_ADDONS_DISABLED, self.ADDON_DISABLED):
|
||||
if (self.path / flag).exists():
|
||||
Msg(f'NOTICE: Addon "{self.path!s}" disabled by presence of {flag} stopfile')
|
||||
Msg(
|
||||
f'NOTICE: Addon "{self.path!s}" disabled by presence of {flag} stopfile'
|
||||
)
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -1198,19 +1255,21 @@ class DirMod(Mod):
|
||||
init_py = self.path / self.INIT_PY
|
||||
if not init_py.exists():
|
||||
self.state = ModState.Loaded
|
||||
Log(f"Init: Initializing {self.path!s} ({self.INIT_PY} not found)... ignore")
|
||||
Log(
|
||||
f"Init: Initializing {self.path!s} ({self.INIT_PY} not found)... ignore"
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
source = init_py.read_text(encoding="utf-8")
|
||||
code = compile(source, init_py, 'exec')
|
||||
exec(code, {"__file__": str(init_py)})
|
||||
code = compile(source, init_py, "exec")
|
||||
exec(code, {**globals(), "__file__": str(init_py)})
|
||||
except Exception as ex:
|
||||
Log(f"Init: Initializing {self.path!s}... failed")
|
||||
Log(utils.HLine)
|
||||
Log(f"{traceback.format_exc()}")
|
||||
Log(utils.HLine)
|
||||
Err(f"During initialization the error \"{ex!s}\" occurred in {init_py!s}")
|
||||
Err(f'During initialization the error "{ex!s}" occurred in {init_py!s}')
|
||||
Err("Please look into the log file for further information")
|
||||
self.state = ModState.Failed
|
||||
else:
|
||||
@@ -1231,15 +1290,20 @@ class ExtModScanner:
|
||||
|
||||
def scan(self):
|
||||
import freecad
|
||||
modules = (m[1] for m in pkgutil.iter_modules(freecad.__path__, "freecad.") if m[2])
|
||||
|
||||
modules = (
|
||||
m[1] for m in pkgutil.iter_modules(freecad.__path__, "freecad.") if m[2]
|
||||
)
|
||||
for module_name in modules:
|
||||
mod = ExtMod(module_name)
|
||||
self.mods.append(mod)
|
||||
if module_name in Config.DisabledAddons:
|
||||
mod.state = ModState.Disabled
|
||||
Msg(f'NOTICE: Addon "{module_name}" disabled by presence of "--disable-addon {module_name}" argument')
|
||||
Msg(
|
||||
f'NOTICE: Addon "{module_name}" disabled by presence of "--disable-addon {module_name}" argument'
|
||||
)
|
||||
continue
|
||||
Log(f'Init: Initializing {module_name}')
|
||||
Log(f"Init: Initializing {module_name}")
|
||||
|
||||
def iter(self) -> coll_abc.Iterable[ExtMod]:
|
||||
return self.mods
|
||||
@@ -1267,7 +1331,9 @@ class DirModScanner:
|
||||
"""Paths of all discovered Mods."""
|
||||
return [mod.path for mod in self.mods.values()]
|
||||
|
||||
def scan_and_override(self, base: Path, *, flat: bool = False, warning: str | None = None) -> None:
|
||||
def scan_and_override(
|
||||
self, base: Path, *, flat: bool = False, warning: str | None = None
|
||||
) -> None:
|
||||
"""
|
||||
Scan in base with higher priority.
|
||||
"""
|
||||
@@ -1304,6 +1370,7 @@ class DirModScanner:
|
||||
# │ Init Pipeline Definition │
|
||||
# └────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
@transient
|
||||
class InitPipeline:
|
||||
"""
|
||||
@@ -1318,7 +1385,9 @@ class InitPipeline:
|
||||
# The library path is not strictly required, so if the OS itself raises an error when trying
|
||||
# to resolve it, just fall back to something reasonable. See #26864.
|
||||
std_lib = std_home / "lib"
|
||||
Log(f"Resolving library directory '{App.getLibraryDir()}' failed, using fallback '{std_lib}'")
|
||||
Log(
|
||||
f"Resolving library directory '{App.getLibraryDir()}' failed, using fallback '{std_lib}'"
|
||||
)
|
||||
dir_mod_scanner = DirModScanner()
|
||||
ext_mod_scanner = ExtModScanner()
|
||||
search_paths = SearchPaths()
|
||||
@@ -1351,7 +1420,9 @@ class InitPipeline:
|
||||
|
||||
legacy_user_mod = Path.home() / ".FreeCAD" / "Mod"
|
||||
if legacy_user_mod.exists():
|
||||
Wrn (f"User path has changed to {user_home!s}. Please move user modules and macros")
|
||||
Wrn(
|
||||
f"User path has changed to {user_home!s}. Please move user modules and macros"
|
||||
)
|
||||
|
||||
# Libraries
|
||||
libraries = PathSet()
|
||||
@@ -1492,7 +1563,11 @@ class InitPipeline:
|
||||
def setup_tty(self) -> None:
|
||||
# Note: just checking whether stdin is a TTY is not enough, as the GUI is set up only after this
|
||||
# script has run. And checking only the RunMode is not enough, as we are maybe not interactive.
|
||||
if Config.RunMode == 'Cmd' and hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
|
||||
if (
|
||||
Config.RunMode == "Cmd"
|
||||
and hasattr(sys.stdin, "isatty")
|
||||
and sys.stdin.isatty()
|
||||
):
|
||||
utils.setup_tty_tab_completion()
|
||||
|
||||
def report(self) -> None:
|
||||
@@ -1510,12 +1585,16 @@ class InitPipeline:
|
||||
output.append(output[0])
|
||||
|
||||
for mod in self.dir_mod_scanner.iter():
|
||||
output.append(f"| {mod.name:<24.24} | {mod.state.name:<10.10} | {mod.init_mode:<6.6} | {mod.path!s}")
|
||||
output.append(
|
||||
f"| {mod.name:<24.24} | {mod.state.name:<10.10} | {mod.init_mode:<6.6} | {mod.path!s}"
|
||||
)
|
||||
for alt in mod.alternative_paths:
|
||||
output.append(f"| {' ':<24.24} | {' ':<10.10} | {' ':<6.6} | {alt!s}")
|
||||
|
||||
for mod in self.ext_mod_scanner.iter():
|
||||
output.append(f"| {mod.name:<24.24} | {mod.state.name:<10.10} | {mod.init_mode:<6.6} | {mod.name}")
|
||||
output.append(
|
||||
f"| {mod.name:<24.24} | {mod.state.name:<10.10} | {mod.init_mode:<6.6} | {mod.name}"
|
||||
)
|
||||
|
||||
for line in output:
|
||||
Log(line)
|
||||
@@ -1537,14 +1616,15 @@ class InitPipeline:
|
||||
# │ Init Applications │
|
||||
# └────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
@transient
|
||||
@call_in_place
|
||||
def init_applications() -> None:
|
||||
try:
|
||||
InitPipeline().run()
|
||||
Log('Init: App::FreeCADInit.py done')
|
||||
Log("Init: App::FreeCADInit.py done")
|
||||
except Exception as ex:
|
||||
Err(f'Error in init_applications {ex!s}')
|
||||
Err(f"Error in init_applications {ex!s}")
|
||||
Err(utils.HLine)
|
||||
Err(traceback.format_exc())
|
||||
Err(utils.HLine)
|
||||
|
||||
@@ -35,13 +35,14 @@
|
||||
# | >>>> | FreeCADGuiInit | only if Gui is up |
|
||||
# +------+------------------+-----------------------------+
|
||||
|
||||
from enum import IntEnum, Enum
|
||||
from dataclasses import dataclass
|
||||
import importlib
|
||||
import re
|
||||
import traceback
|
||||
import typing
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, IntEnum
|
||||
from pathlib import Path
|
||||
import importlib
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
@@ -104,11 +105,15 @@ class Workbench:
|
||||
ToolTip = ""
|
||||
Icon = None
|
||||
|
||||
__Workbench__: "Workbench" # Injected by FreeCAD, see: Application::activateWorkbench
|
||||
__Workbench__: (
|
||||
"Workbench" # Injected by FreeCAD, see: Application::activateWorkbench
|
||||
)
|
||||
|
||||
def Initialize(self):
|
||||
"""Initializes this workbench."""
|
||||
App.Console.PrintWarning(f"{self!s}: Workbench.Initialize() not implemented in subclass!")
|
||||
App.Console.PrintWarning(
|
||||
f"{self!s}: Workbench.Initialize() not implemented in subclass!"
|
||||
)
|
||||
|
||||
def ContextMenu(self, recipient):
|
||||
pass
|
||||
@@ -295,20 +300,24 @@ class DirModGui(ModGui):
|
||||
try:
|
||||
source = init_gui_py.read_text(encoding="utf-8")
|
||||
code = compile(source, init_gui_py, "exec")
|
||||
exec(code, {"__file__": str(init_gui_py)})
|
||||
exec(code, {**globals(), "__file__": str(init_gui_py)})
|
||||
except Exception as ex:
|
||||
sep = "-" * 100 + "\n"
|
||||
Log(f"Init: Initializing {target!s}... failed\n")
|
||||
Log(sep)
|
||||
Log(traceback.format_exc())
|
||||
Log(sep)
|
||||
Err(f'During initialization the error "{ex!s}" occurred in {init_gui_py!s}\n')
|
||||
Err(
|
||||
f'During initialization the error "{ex!s}" occurred in {init_gui_py!s}\n'
|
||||
)
|
||||
Err("Look into the log file for further information\n")
|
||||
else:
|
||||
Log(f"Init: Initializing {target!s}... done\n")
|
||||
return True
|
||||
else:
|
||||
Log(f"Init: Initializing {target!s} (InitGui.py not found)... ignore\n")
|
||||
Log(
|
||||
f"Init: Initializing {target!s} (InitGui.py not found)... ignore\n"
|
||||
)
|
||||
return False
|
||||
|
||||
def process_metadata(self) -> bool:
|
||||
@@ -325,7 +334,9 @@ class DirModGui(ModGui):
|
||||
if not workbench_metadata.supportsCurrentFreeCAD():
|
||||
continue
|
||||
|
||||
subdirectory = workbench_metadata.Subdirectory or workbench_metadata.Name
|
||||
subdirectory = (
|
||||
workbench_metadata.Subdirectory or workbench_metadata.Name
|
||||
)
|
||||
subdirectory = self.mod.path / Path(*re.split(r"[/\\]+", subdirectory))
|
||||
if not subdirectory.exists():
|
||||
continue
|
||||
@@ -373,7 +384,9 @@ class ExtModGui(ModGui):
|
||||
Err(f'During initialization the error "{ex!s}" occurred\n')
|
||||
except Exception as ex:
|
||||
sep = "-" * 80 + "\n"
|
||||
Err(f'During initialization the error "{ex!s}" occurred in {self.mod.name}\n')
|
||||
Err(
|
||||
f'During initialization the error "{ex!s}" occurred in {self.mod.name}\n'
|
||||
)
|
||||
Err(sep)
|
||||
Err(traceback.format_exc())
|
||||
Err(sep)
|
||||
@@ -400,9 +413,7 @@ def InitApplications():
|
||||
gui = mod_type(mod)
|
||||
gui.load()
|
||||
if mod.init_mode:
|
||||
row = (
|
||||
f"| {mod.name:<24.24} | {mod.state.name:<10.10} | {mod.init_mode:<6.6} |\n"
|
||||
)
|
||||
row = f"| {mod.name:<24.24} | {mod.state.name:<10.10} | {mod.init_mode:<6.6} |\n"
|
||||
output.append(row)
|
||||
|
||||
output = []
|
||||
@@ -457,7 +468,9 @@ FreeCAD.addImportType("Inventor V2.1 (*.iv *.IV)", "FreeCADGui")
|
||||
FreeCAD.addImportType(
|
||||
"VRML V2.0 (*.wrl *.WRL *.vrml *.VRML *.wrz *.WRZ *.wrl.gz *.WRL.GZ)", "FreeCADGui"
|
||||
)
|
||||
FreeCAD.addImportType("Python (*.py *.FCMacro *.FCScript *.fcmacro *.fcscript)", "FreeCADGui")
|
||||
FreeCAD.addImportType(
|
||||
"Python (*.py *.FCMacro *.FCScript *.fcmacro *.fcscript)", "FreeCADGui"
|
||||
)
|
||||
FreeCAD.addExportType("Inventor V2.1 (*.iv)", "FreeCADGui")
|
||||
FreeCAD.addExportType("VRML V2.0 (*.wrl *.vrml *.wrz *.wrl.gz)", "FreeCADGui")
|
||||
FreeCAD.addExportType("X3D Extensible 3D (*.x3d *.x3dz)", "FreeCADGui")
|
||||
|
||||
Reference in New Issue
Block a user