diff --git a/src/Mod/AddonManager/Addon.py b/src/Mod/AddonManager/Addon.py index 7bb3688f0a..c660bcda1f 100644 --- a/src/Mod/AddonManager/Addon.py +++ b/src/Mod/AddonManager/Addon.py @@ -114,7 +114,7 @@ class Addon: self.blockers = [] # A list of Addons self.replaces = [] # A list of Addons self.internal_workbenches: Set[str] = set() # Required internal workbenches - self.python_required: Set[str] = set() + self.python_requires: Set[str] = set() self.python_optional: Set[str] = set() self.python_min_version = {"major": 3, "minor": 0} @@ -335,27 +335,22 @@ class Addon: if not self.version_is_ok(metadata): return + if metadata.PythonMin != "0.0.0": + split_version_string = metadata.PythonMin.split(".") + if len(split_version_string) >= 2: + try: + self.python_min_version["major"] = int(split_version_string[0]) + self.python_min_version["minor"] = int(split_version_string[1]) + FreeCAD.Console.PrintLog( + f"Package {self.name}: Requires Python {split_version_string[0]}.{split_version_string[1]} or greater\n" + ) + except ValueError: + FreeCAD.Console.PrintWarning( + f"Package {self.name}: Invalid Python version requirement specified\n" + ) + for dep in metadata.Depend: - if dep["package"].lower() == "python": - # We only support the "version_gte" attribute for Python itself - if "version_gte" in dep and "." in dep["version_gte"]: - split_version_string = dep["version_gte"].split(".") - if len(split_version_string) >= 2: - try: - self.python_min_version["major"] = int( - split_version_string[0] - ) - self.python_min_version["minor"] = int( - split_version_string[1] - ) - FreeCAD.Console.PrintLog( - f"Package {self.name}: Requires Python {split_version_string[0]}.{split_version_string[1]} or greater\n" - ) - except ValueError: - FreeCAD.Console.PrintWarning( - f"Package {self.name}: Invalid Python version requirement specified\n" - ) - elif "type" in dep: + if "type" in dep: if dep["type"] == "internal": if dep["package"] in INTERNAL_WORKBENCHES: self.requires.add(dep["package"]) @@ -369,10 +364,10 @@ class Addon: elif dep["type"] == "addon": self.requires.add(dep["package"]) elif dep["type"] == "python": - if "optional" in dep and dep["optional"].lower() == "true": + if "optional" in dep and dep["optional"]: self.python_optional.add(dep["package"]) else: - self.python_required.add(dep["package"]) + self.python_requires.add(dep["package"]) else: # Automatic resolution happens later, once we have a complete list of Addons self.requires.add(dep["package"]) @@ -517,7 +512,7 @@ class Addon: information that may be needed. """ - deps.python_required |= self.python_requires + deps.python_requires |= self.python_requires deps.python_optional |= self.python_optional deps.python_min_version["major"] = max( @@ -548,7 +543,7 @@ class Addon: deps.internal_workbenches.add(INTERNAL_WORKBENCHES[real_name]) else: # Assume it's a Python requirement of some kind: - deps.python_required.add(dep) + deps.python_requires.add(dep) for dep in self.blocks: if dep in all_repos: diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index edba157107..8b2db5f9b3 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -1043,7 +1043,7 @@ class CommandAddonManager: """Encapsulates a group of four types of dependencies: * Internal workbenches -> wbs * External addons -> external_addons - * Required Python packages -> python_required + * Required Python packages -> python_requires * Optional Python packages -> python_optional """ @@ -1081,13 +1081,13 @@ class CommandAddonManager: # Check the Python dependencies: self.python_min_version = deps.python_min_version - self.python_required = [] - for py_dep in deps.python_required: - if py_dep not in self.python_required: + self.python_requires = [] + for py_dep in deps.python_requires: + if py_dep not in self.python_requires: try: __import__(py_dep) except ImportError: - self.python_required.append(py_dep) + self.python_requires.append(py_dep) self.python_optional = [] for py_dep in deps.python_optional: @@ -1098,12 +1098,12 @@ class CommandAddonManager: self.wbs.sort() self.external_addons.sort() - self.python_required.sort() + self.python_requires.sort() self.python_optional.sort() self.python_optional = [ option for option in self.python_optional - if option not in self.python_required + if option not in self.python_requires ] def update_allowed_packages_list(self) -> None: @@ -1128,19 +1128,19 @@ class CommandAddonManager: "Could not fetch remote ALLOWED_PYTHON_PACKAGES.txt, using local copy\n" ) - def handle_disallowed_python(self, python_required: List[str]) -> bool: + def handle_disallowed_python(self, python_requires: List[str]) -> bool: """Determine if we are missing any required Python packages that are not in the allowed packages list. If so, display a message to the user, and return True. Otherwise return False.""" bad_packages = [] # self.update_allowed_packages_list() - for dep in python_required: + for dep in python_requires: if dep not in self.allowed_packages: bad_packages.append(dep) for dep in bad_packages: - python_required.remove(dep) + python_requires.remove(dep) if bad_packages: message = ( @@ -1225,7 +1225,7 @@ class CommandAddonManager: for addon in missing.external_addons: self.dependency_dialog.listWidgetAddons.addItem(addon) - for mod in missing.python_required: + for mod in missing.python_requires: self.dependency_dialog.listWidgetPythonRequired.addItem(mod) for mod in missing.python_optional: item = QtWidgets.QListWidgetItem(mod) @@ -1251,7 +1251,7 @@ class CommandAddonManager: return missing = CommandAddonManager.MissingDependencies(repo, self.item_model.repos) - if self.handle_disallowed_python(missing.python_required): + if self.handle_disallowed_python(missing.python_requires): return # For now only look at the minor version, since major is always Python 3 @@ -1292,7 +1292,7 @@ class CommandAddonManager: return if ( missing.external_addons - or missing.python_required + or missing.python_requires or missing.python_optional ): # Recoverable: ask the user if they want to install the missing deps @@ -1311,10 +1311,10 @@ class CommandAddonManager: if repo.name == name or repo.display_name == name: addons.append(repo) - python_required = [] + python_requires = [] for row in range(self.dependency_dialog.listWidgetPythonRequired.count()): item = self.dependency_dialog.listWidgetPythonRequired.item(row) - python_required.append(item.text()) + python_requires.append(item.text()) python_optional = [] for row in range(self.dependency_dialog.listWidgetPythonOptional.count()): @@ -1323,7 +1323,7 @@ class CommandAddonManager: python_optional.append(item.text()) self.dependency_installation_worker = DependencyInstallationWorker( - addons, python_required, python_optional + addons, python_requires, python_optional ) self.dependency_installation_worker.no_python_exe.connect( functools.partial(self.no_python_exe, installing_repo) diff --git a/src/Mod/AddonManager/addonmanager_devmode_add_content.py b/src/Mod/AddonManager/addonmanager_devmode_add_content.py index 7c302f856b..7ac4b1d18e 100644 --- a/src/Mod/AddonManager/addonmanager_devmode_add_content.py +++ b/src/Mod/AddonManager/addonmanager_devmode_add_content.py @@ -20,7 +20,7 @@ # * * # *************************************************************************** -""" Contains a class for adding a single content item, as well as auxilliary classes for +""" Contains a class for adding a single content item, as well as auxiliary classes for its dependent dialog boxes. """ import os @@ -547,7 +547,7 @@ class EditDependency: if dep_type and dep_name: index = self.dialog.typeComboBox.findData(dep_type) if index == -1: - raise RuntimeError(f"Invaid dependency type {dep_type}") + raise RuntimeError(f"Invalid dependency type {dep_type}") self.dialog.typeComboBox.setCurrentIndex(index) index = self.dialog.dependencyComboBox.findData(dep_name) if index == -1: diff --git a/src/Mod/AddonManager/addonmanager_macro.py b/src/Mod/AddonManager/addonmanager_macro.py index c1eb725559..e5d7b0465c 100644 --- a/src/Mod/AddonManager/addonmanager_macro.py +++ b/src/Mod/AddonManager/addonmanager_macro.py @@ -345,7 +345,7 @@ class Macro: def clean_icon(self): """Downloads the macro's icon from whatever source is specified and stores a local - copy, potentially updating the interal icon location to that local storage.""" + copy, potentially updating the internal icon location to that local storage.""" if self.icon.startswith("http://") or self.icon.startswith("https://"): FreeCAD.Console.PrintLog( f"Attempting to fetch macro icon from {self.icon}\n" diff --git a/src/Mod/AddonManager/addonmanager_workers_installation.py b/src/Mod/AddonManager/addonmanager_workers_installation.py index db1b830e72..ce61b9a998 100644 --- a/src/Mod/AddonManager/addonmanager_workers_installation.py +++ b/src/Mod/AddonManager/addonmanager_workers_installation.py @@ -377,7 +377,7 @@ class DependencyInstallationWorker(QtCore.QThread): def __init__( self, addons: List[Addon], - python_required: List[str], + python_requires: List[str], python_optional: List[str], location: os.PathLike = None, ): @@ -387,7 +387,7 @@ class DependencyInstallationWorker(QtCore.QThread): for testing purposes and shouldn't be set by normal code in most circumstances.""" QtCore.QThread.__init__(self) self.addons = addons - self.python_required = python_required + self.python_requires = python_requires self.python_optional = python_optional self.location = location @@ -395,7 +395,7 @@ class DependencyInstallationWorker(QtCore.QThread): """Normally not called directly: create the object and call start() to launch it in its own thread. Installs dependencies for the Addon.""" self._install_required_addons() - if self.python_required or self.python_optional: + if self.python_requires or self.python_optional: self._install_python_packages() self.success.emit() @@ -464,7 +464,7 @@ class DependencyInstallationWorker(QtCore.QThread): """Install the required Python package dependencies. If any fail a failure signal is emitted and the function exits without proceeding with any additional installs.""" python_exe = utils.get_python_exe() - for pymod in self.python_required: + for pymod in self.python_requires: if QtCore.QThread.currentThread().isInterruptionRequested(): return proc = subprocess.run( diff --git a/src/Mod/AddonManager/addonmanager_workers_startup.py b/src/Mod/AddonManager/addonmanager_workers_startup.py index b1b6097e4c..ccbdea47b6 100644 --- a/src/Mod/AddonManager/addonmanager_workers_startup.py +++ b/src/Mod/AddonManager/addonmanager_workers_startup.py @@ -331,7 +331,9 @@ class CreateAddonListWorker(QtCore.QThread): + "\n" ) try: - os.chdir(os.path.join(macro_cache_location,"..")) # Make sure we are not IN this directory + os.chdir( + os.path.join(macro_cache_location, "..") + ) # Make sure we are not IN this directory shutil.rmtree(macro_cache_location, onerror=self._remove_readonly) self.git_manager.clone( "https://github.com/FreeCAD/FreeCAD-macros.git", @@ -449,10 +451,11 @@ class LoadPackagesFromCacheWorker(QtCore.QThread): repo.updated_timestamp = os.path.getmtime( repo_metadata_cache_path ) - except Exception: + except Exception as e: FreeCAD.Console.PrintLog( f"Failed loading {repo_metadata_cache_path}\n" ) + FreeCAD.Console.PrintLog(str(e) + "\n") self.addon_repo.emit(repo)