[Bf-blender-cvs] [dbe6331a3b9] soc-2017-package_manager: Refactor Package class

gandalf3 noreply at git.blender.org
Mon Aug 28 09:47:06 CEST 2017


Commit: dbe6331a3b9f9e262edf043f5a621a2a3ec6d925
Author: gandalf3
Date:   Sun Aug 27 22:11:23 2017 -0700
Branches: soc-2017-package_manager
https://developer.blender.org/rBdbe6331a3b9f9e262edf043f5a621a2a3ec6d925

Refactor Package class

* Use property decorator
* Display an error when encountering an incorrectly formatted bl_info
* General cleanup

===================================================================

M	release/scripts/modules/bpkg/__init__.py
M	release/scripts/modules/bpkg/display.py
M	release/scripts/modules/bpkg/types.py
M	release/scripts/startup/bl_ui/space_userpref.py

===================================================================

diff --git a/release/scripts/modules/bpkg/__init__.py b/release/scripts/modules/bpkg/__init__.py
index d61a4627909..525acb7b6f2 100644
--- a/release/scripts/modules/bpkg/__init__.py
+++ b/release/scripts/modules/bpkg/__init__.py
@@ -5,6 +5,8 @@
 
 from . import utils
 from . import types
+from . import display
+from . import exceptions
 from pathlib import Path
 from collections import OrderedDict
 import logging
@@ -29,13 +31,19 @@ def get_repositories() -> list:
 
 def get_installed_packages(refresh=False) -> list:
     """Get list of packages installed on disk"""
+    log = logging.getLogger(__name__ + ".get_installed_packages")
     import addon_utils
     installed_pkgs = []
     #TODO: just use addon_utils for now
     for mod in addon_utils.modules(refresh=refresh):
-        pkg = types.Package.from_module(mod)
-        pkg.installed = True
-        installed_pkgs.append(pkg)
+        try:
+            pkg = types.Package.from_module(mod)
+        except exceptions.PackageException as err:
+            msg = "Error parsing package \"{}\" ({}): {}".format(mod.__name__, mod.__file__, err)
+            display.pkg_errors.append(msg)
+        else:
+            pkg.installed = True
+            installed_pkgs.append(pkg)
     return installed_pkgs
 
 def _build_packagelist() -> dict: # {{{
@@ -45,6 +53,7 @@ def _build_packagelist() -> dict: # {{{
     log = logging.getLogger(__name__ + "._build_packagelist")
 
     masterlist = {}
+    display.pkg_errors.clear()
     installed_packages = get_installed_packages(refresh=True)
     known_repositories = get_repositories()
 
diff --git a/release/scripts/modules/bpkg/display.py b/release/scripts/modules/bpkg/display.py
index 188018f3232..b06784a3056 100644
--- a/release/scripts/modules/bpkg/display.py
+++ b/release/scripts/modules/bpkg/display.py
@@ -6,3 +6,14 @@ displayed_packages = []
 expanded_packages = []
 # name of package who's preferences are shown
 preference_package = None
+
+
+#errors
+pkg_errors = []
+# def pkg_error(msg: str):
+#     """Add a package related error message"""
+#     _pkg_errors.append(msg)
+#
+# def pkg_errors() -> str:
+#     """Return list of error messages related to packages"""
+#     return _pkg_errors
diff --git a/release/scripts/modules/bpkg/types.py b/release/scripts/modules/bpkg/types.py
index 48a362c5c37..d4b1b182cf3 100644
--- a/release/scripts/modules/bpkg/types.py
+++ b/release/scripts/modules/bpkg/types.py
@@ -4,6 +4,7 @@ from pathlib import Path
 from . import exceptions
 from . import utils
 from . import actions
+from . import display
 
 class Package:
     """
@@ -12,61 +13,85 @@ class Package:
 
     log = logging.getLogger(__name__ + ".Package")
 
-    def __init__(self, package_dict:dict = None):
-        self.bl_info = {}
-        self.url     = ""
-        self.files   = []
-
-        self.repositories = set()
-        self.installed_location = None
-        self.module_name = None
-
+    def __init__(self):
+        self._bl_info = dict()
+
+        ## bl_infos ##
+        # required fields
+        self.name = str()
+        self.version = tuple()
+        self.blender = tuple()
+        # optional fields
+        self.description = str()
+        self.author = str()
+        self.category = str()
+        self.location = str()
+        self.support = 'COMMUNITY'
+        self.warning = str()
+        self.wiki_url = str()
+        self.tracker_url = str()
+
+        ## package stuff ##
+        self.url     = str()
+        self.files   = list()
+
+        ## package stuff which is not stored in repo ##
         self.installed = False
+        self.installed_location = None
         self.is_user = False
         self.enabled = False
+        self.repositories = set()
 
-        self.set_from_dict(package_dict)
-
-    def test_is_user(self) -> bool:
-        """Return true if package's install location is in user or preferences scripts path"""
-        import bpy
-        user_script_path = bpy.utils.script_path_user()
-        prefs_script_path = bpy.utils.script_path_pref()
+        ## other ##
+        self.module_name = None
 
-        if user_script_path is not None:
-            in_user = Path(user_script_path) in Path(self.installed_location).parents
-        else:
-            in_user = False
+    def set_from_dict(self, package_dict: dict):
+        """
+        Get attributes from a dict such as produced by `to_dict`
+        """
+        if package_dict is None:
+            raise PackageException("Can't set package from None")
+        
+        self.files   = package_dict['files']
+        self.url     = package_dict['url']
+        self.bl_info = package_dict['bl_info']
 
-        if prefs_script_path is not None:
-            in_prefs = Path(prefs_script_path) in Path(self.installed_location).parents
-        else:
-            in_prefs = False
+    @classmethod
+    def from_dict(cls, package_dict: dict):
+        """
+        Return a Package with values from dict
+        """
+        pkg = cls()
+        pkg.set_from_dict(package_dict)
+        return pkg
 
-        return in_user or in_prefs
+    @classmethod
+    def from_blinfo(cls, blinfo: dict):
+        """
+        Return a Package with bl_info filled in
+        """
+        return cls.from_dict({'bl_info': blinfo})
 
-    def test_enabled(self) -> bool:
-        """Return true if package is enabled"""
-        import bpy
-        if self.module_name is not None:
-            return (self.module_name in bpy.context.user_preferences.addons)
-        else:
-            return False
+    @classmethod
+    def from_module(cls, module):
+        """
+        Return a Package object from an addon module
+        """
+        from pathlib import Path
+        filepath = Path(module.__file__)
+        if filepath.name == '__init__.py':
+            filepath = filepath.parent
 
-    def test_installed(self) -> bool:
-        """Return true if package is installed"""
-        import addon_utils
-        return len([Package.from_module(mod) for mod in addon_utils.modules(refresh=False) if
-                addon_utils.module_bl_info(mod)['name'] == self.name and
-                addon_utils.module_bl_info(mod)['version'] == self.version]) > 0
+        pkg = cls()
+        pkg.files = [filepath.name]
+        pkg.installed_location = str(filepath)
+        pkg.module_name = module.__name__
 
-    def set_installed_metadata(self, installed_pkg):
-        """Sets metadata specific to installed packages from the Package given as `installed_pkg`"""
-        self.installed = installed_pkg.test_installed()
-        self.enabled = installed_pkg.test_enabled()
-        self.is_user = installed_pkg.test_is_user()
-        self.module_name = installed_pkg.module_name
-        self.installed_location = installed_pkg.installed_location
+        try:
+            pkg.bl_info = module.bl_info
+        except AttributeError as err:
+            raise exceptions.PackageException("Module does not appear to be an addon; no bl_info attribute") from err
+        return pkg
 
     def to_dict(self) -> dict:
         """
@@ -78,111 +103,176 @@ class Package:
                 'files': self.files,
                 }
 
-    def set_from_dict(self, package_dict: dict):
-        """
-        Get attributes from a dict such as produced by `to_dict`
-        """
-        if package_dict is None:
-            package_dict = {}
-        
-        for attr in ('files', 'url', 'bl_info'):
-            if package_dict.get(attr) is not None:
-                setattr(self, attr, package_dict[attr])
-
-    # bl_info convenience getters {{{
+    # bl_info properties {{{
     # required fields
     @property
     def name(self) -> str:
         """Get name from bl_info"""
-        return self.bl_info.get('name')
+        return self._bl_info.get('name')
+    @name.setter
+    def name(self, name:str) -> str:
+        if type(name) != str:
+            raise exceptions.PackageException("refusing to set name to non str %s" % name)
+        self._bl_info['name'] = name
 
     @property
     def version(self) -> tuple:
         """Get version from bl_info"""
-        return tuple(self.bl_info.get('version'))
+        return tuple(self._bl_info.get('version'))
+    @version.setter
+    def version(self, version:tuple) -> tuple:
+        if type(version) == str:
+            raise exceptions.PackageException("Refusing to set version to non tuple %s" % version)
+        self._bl_info['version'] = version
 
     @property
     def blender(self) -> tuple:
         """Get blender from bl_info"""
-        return self.bl_info.get('blender')
+        return self._bl_info.get('blender')
+    @blender.setter
+    def blender(self, blender:tuple):
+        if type(blender) == str:
+            raise exceptions.PackageException("Refusing to set blender to non tuple %s" % blender)
+        self._bl_info['blender'] = blender
 
     # optional fields
     @property
     def description(self) -> str:
         """Get description from bl_info"""
-        return self.bl_info.get('description')
+        return self._bl_info.get('description')
+    @description.setter
+    def description(self, description:str):
+        self._bl_info['description'] = description
 
     @property
     def author(self) -> str:
         """Get author from bl_info"""
-        return self.bl_info.get('author')
+        return self._bl_info.get('author')
+    @author.setter
+    def author(self, author:str):
+        self._bl_info['author'] = author
 
     @property
     def category(self) -> str:
         """Get category from bl_info"""
-        return self.bl_info.get('category')
+        return self._bl_info.get('category')
+    @category.setter
+    def category(self, category:str):
+        self._bl_info['category'] = category
 
     @property
     def location(self) -> str:
         """Get location from bl_info"""
-        return self.bl_info.get('location')
+        return self._bl_info.get('location')
+    @location.setter
+    def location(self, location:str):
+        self._bl_info['location'] = location
 
     @property
     def support(self) -> str:
         """Get support from bl_info"""
-        return self.bl_info.get('support')
+        return self._

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list