diff --git a/src/App/FreeCADInit.py b/src/App/FreeCADInit.py index 471f435dc4..3d44e3d6ec 100644 --- a/src/App/FreeCADInit.py +++ b/src/App/FreeCADInit.py @@ -1,28 +1,28 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -#*************************************************************************** -#* Copyright (c) 2001,2002 Jürgen Riegel * -#* Copyright (c) 2025 Frank Martínez * -#* * -#* This file is part of the FreeCAD CAx development system. * -#* * -#* This program is free software you can redistribute it and/or modify * -#* it under the terms of the GNU Lesser General Public License (LGPL) * -#* as published by the Free Software Foundation either version 2 of * -#* the License, or (at your option) any later version. * -#* for detail see the LICENCE text file. * -#* * -#* FreeCAD is distributed in the hope that it will be useful, * -#* but WITHOUT ANY WARRANTY without even the implied warranty of * -#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -#* GNU Lesser General Public License for more details. * -#* * -#* You should have received a copy of the GNU Library General Public * -#* License along with FreeCAD if not, write to the Free Software * -#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * -#* USA * -#* * -#***************************************************************************/ +# *************************************************************************** +# * Copyright (c) 2001,2002 Jürgen Riegel * +# * Copyright (c) 2025 Frank Martínez * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# ***************************************************************************/ # FreeCAD init module - App # @@ -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 @@ -247,13 +253,13 @@ class FCADLogger: return log_fn def _log( - self, - level: int, - msg: str, - frame: int = 0, - args: tuple = (), - kwargs: dict | None = None, - ) -> None: + self, + level: int, + msg: str, + frame: int = 0, + args: tuple = (), + kwargs: dict | None = None, + ) -> None: """ Internal log printing function. @@ -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) + frame = sys._getframe(frame + 1) + 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]) + frame = inspect.stack()[frame + 1] + 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: @@ -332,13 +340,13 @@ class FCADLogger: return catch_fn def _catch( - self, - level: int, - msg: str, - func: callable, - args: tuple = (), - kwargs: dict | None = None, - ) -> object | None: + self, + level: int, + msg: str, + func: callable, + args: tuple = (), + kwargs: dict | None = None, + ) -> object | None: """ Internal function to log exception of any callable. @@ -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,21 +1090,23 @@ 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) def run_init(self) -> None: try: - module = importlib.import_module(self.name) # Implicit run of __init__.py + module = importlib.import_module(self.name) # Implicit run of __init__.py except Exception as ex: self._init_error(ex, traceback.format_exc()) self.state = ModState.Failed @@ -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 @@ -1251,7 +1315,7 @@ class DirModScanner: Sacan in the filesystem for Dir based Mods in the valid locations. """ - EXCLUDE: set[str] = set(["", "CVS", "__init__.py"]) # Why? + EXCLUDE: set[str] = set(["", "CVS", "__init__.py"]) # Why? mods: dict[str, DirMod] visited: set[str] @@ -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) diff --git a/src/Gui/FreeCADGuiInit.py b/src/Gui/FreeCADGuiInit.py index eba658a363..1161f92c9f 100644 --- a/src/Gui/FreeCADGuiInit.py +++ b/src/Gui/FreeCADGuiInit.py @@ -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")