pep8 edits and avoid naming conflicts with python builtins
[blender.git] / release / scripts / modules / addon_utils.py
index 07f1dc618dcc4223e03f3dbf8892ca62af7cc651..de662b47c4dc65444724c6f38d7daccefd34c22d 100644 (file)
@@ -16,7 +16,7 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8 compliant>
+# <pep8-80 compliant>
 
 __all__ = (
     "paths",
@@ -26,11 +26,16 @@ __all__ = (
     "disable",
     "reset_all",
     "module_bl_info",
-)
+    )
 
 import bpy as _bpy
 
 
+error_duplicates = False
+error_encoding = False
+addons_fake_modules = {}
+
+
 def paths():
     # RELEASE SCRIPTS: official scripts distributed in Blender releases
     paths = _bpy.utils.script_paths("addons")
@@ -47,12 +52,19 @@ def paths():
 
 
 def modules(module_cache):
+    global error_duplicates
+    global error_encoding
     import os
 
+    error_duplicates = False
+    error_encoding = False
+
     path_list = paths()
 
     # fake module importing
-    def fake_module(mod_name, mod_path, speedy=True):
+    def fake_module(mod_name, mod_path, speedy=True, force_support=None):
+        global error_encoding
+
         if _bpy.app.debug:
             print("fake_module", mod_path, mod_name)
         import ast
@@ -63,12 +75,28 @@ def modules(module_cache):
             line_iter = iter(file_mod)
             l = ""
             while not l.startswith("bl_info"):
-                l = line_iter.readline()
+                try:
+                    l = line_iter.readline()
+                except UnicodeDecodeError as e:
+                    if not error_encoding:
+                        error_encoding = True
+                        print("Error reading file as UTF-8:", mod_path, e)
+                    file_mod.close()
+                    return None
+
                 if len(l) == 0:
                     break
             while l.rstrip():
                 lines.append(l)
-                l = line_iter.readline()
+                try:
+                    l = line_iter.readline()
+                except UnicodeDecodeError as e:
+                    if not error_encoding:
+                        error_encoding = True
+                        print("Error reading file as UTF-8:", mod_path, e)
+                    file_mod.close()
+                    return None
+
             data = "".join(lines)
 
         else:
@@ -106,6 +134,9 @@ def modules(module_cache):
                 traceback.print_exc()
                 raise
 
+            if force_support is not None:
+                mod.bl_info["support"] = force_support
+
             return mod
         else:
             return None
@@ -113,27 +144,48 @@ def modules(module_cache):
     modules_stale = set(module_cache.keys())
 
     for path in path_list:
+
+        # force all contrib addons to be 'TESTING'
+        if path.endswith("addons_contrib") or path.endswith("addons_extern"):
+            force_support = 'TESTING'
+        else:
+            force_support = None
+
         for mod_name, mod_path in _bpy.path.module_names(path):
             modules_stale -= {mod_name}
             mod = module_cache.get(mod_name)
             if mod:
-                if mod.__time__ != os.path.getmtime(mod_path):
-                    print("reloading addon:", mod_name, mod.__time__, os.path.getmtime(mod_path), mod_path)
+                if mod.__file__ != mod_path:
+                    print("multiple addons with the same name:\n  %r\n  %r" %
+                          (mod.__file__, mod_path))
+                    error_duplicates = True
+
+                elif mod.__time__ != os.path.getmtime(mod_path):
+                    print("reloading addon:",
+                          mod_name,
+                          mod.__time__,
+                          os.path.getmtime(mod_path),
+                          mod_path,
+                          )
                     del module_cache[mod_name]
                     mod = None
 
             if mod is None:
-                mod = fake_module(mod_name, mod_path)
+                mod = fake_module(mod_name,
+                                  mod_path,
+                                  force_support=force_support)
                 if mod:
                     module_cache[mod_name] = mod
 
-    # just incase we get stale modules, not likely
+    # just in case we get stale modules, not likely
     for mod_stale in modules_stale:
         del module_cache[mod_stale]
     del modules_stale
 
     mod_list = list(module_cache.values())
-    mod_list.sort(key=lambda mod: (mod.bl_info['category'], mod.bl_info['name']))
+    mod_list.sort(key=lambda mod: (mod.bl_info['category'],
+                                   mod.bl_info['name'],
+                                   ))
     return mod_list
 
 
@@ -153,8 +205,9 @@ def check(module_name):
     loaded_state = mod and getattr(mod, "__addon_enabled__", Ellipsis)
 
     if loaded_state is Ellipsis:
-        print("Warning: addon-module %r found module but without"
-               " __addon_enabled__ field, possible name collision from file: %r" %
+        print("Warning: addon-module %r found module "
+               "but without __addon_enabled__ field, "
+               "possible name collision from file: %r" %
                (module_name, getattr(mod, "__file__", "<unknown>")))
 
         loaded_state = False
@@ -168,7 +221,7 @@ def enable(module_name, default_set=True):
 
     :arg module_name: The name of the addon and module.
     :type module_name: string
-    :return: the loaded module or None on failier.
+    :return: the loaded module or None on failure.
     :rtype: module
     """
 
@@ -197,7 +250,8 @@ def enable(module_name, default_set=True):
                 return None
             mod.__addon_enabled__ = False
 
-    # Split registering up into 3 steps so we can undo if it fails par way through
+    # Split registering up into 3 steps so we can undo
+    # if it fails par way through.
     # 1) try import
     try:
         mod = __import__(module_name)
@@ -220,7 +274,7 @@ def enable(module_name, default_set=True):
 
     # * OK loaded successfully! *
     if default_set:
-        # just incase its enabled alredy
+        # just in case its enabled already
         ext = _bpy.context.user_preferences.addons.get(module_name)
         if not ext:
             ext = _bpy.context.user_preferences.addons.new()
@@ -244,8 +298,9 @@ def disable(module_name, default_set=True):
     import sys
     mod = sys.modules.get(module_name)
 
-    # possible this addon is from a previous session and didnt load a module this time.
-    # so even if the module is not found, still disable the addon in the user prefs.
+    # possible this addon is from a previous session and didn't load a
+    # module this time. So even if the module is not found, still disable
+    # the addon in the user prefs.
     if mod:
         mod.__addon_enabled__ = False
 
@@ -257,7 +312,7 @@ def disable(module_name, default_set=True):
     else:
         print("addon_utils.disable", module_name, "not loaded")
 
-    # could be in more then once, unlikely but better do this just incase.
+    # could be in more then once, unlikely but better do this just in case.
     addons = _bpy.context.user_preferences.addons
 
     if default_set:
@@ -300,7 +355,22 @@ def reset_all(reload_scripts=False):
                 disable(mod_name)
 
 
-def module_bl_info(mod, info_basis={"name": "", "author": "", "version": (), "blender": (), "api": 0, "location": "", "description": "", "wiki_url": "", "tracker_url": "", "support": 'COMMUNITY', "category": "", "warning": "", "show_expanded": False}):
+def module_bl_info(mod, info_basis={"name": "",
+                                    "author": "",
+                                    "version": (),
+                                    "blender": (),
+                                    "api": 0,
+                                    "location": "",
+                                    "description": "",
+                                    "wiki_url": "",
+                                    "tracker_url": "",
+                                    "support": 'COMMUNITY',
+                                    "category": "",
+                                    "warning": "",
+                                    "show_expanded": False,
+                                    }
+                   ):
+
     addon_info = getattr(mod, "bl_info", {})
 
     # avoid re-initializing