e955c94ed3
Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
222 lines
7.0 KiB
Python
222 lines
7.0 KiB
Python
# SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
# simple script to enable all addons, and disable
|
|
|
|
"""
|
|
./blender.bin --background -noaudio --factory-startup --python tests/python/bl_load_py_modules.py
|
|
"""
|
|
|
|
import bpy
|
|
import addon_utils
|
|
|
|
import sys
|
|
import os
|
|
|
|
BLACKLIST = {
|
|
"bl_i18n_utils",
|
|
"bl_previews_utils",
|
|
"cycles",
|
|
"io_export_dxf", # TODO, check on why this fails
|
|
'io_import_dxf', # Because of cydxfentity.so dependency
|
|
|
|
# Utility scripts not meant to be used as modules
|
|
os.path.join("power_sequencer", "scripts"),
|
|
# The unpacked wheel is only loaded when actually used, not directly on import:
|
|
os.path.join("io_blend_utils", "blender_bam-unpacked.whl"),
|
|
}
|
|
|
|
for mod in addon_utils.modules():
|
|
if addon_utils.module_bl_info(mod)['blender'] < (2, 80, 0):
|
|
BLACKLIST.add(mod.__name__)
|
|
|
|
# Some modules need to add to the `sys.path`.
|
|
MODULE_SYS_PATHS = {
|
|
# Runs in a Python subprocess, so its expected its basedir can be imported.
|
|
"io_blend_utils.blendfile_pack": ".",
|
|
}
|
|
|
|
if not bpy.app.build_options.freestyle:
|
|
BLACKLIST.add("render_freestyle_svg")
|
|
|
|
if not bpy.app.build_options.xr_openxr:
|
|
BLACKLIST.add("viewport_vr_preview")
|
|
|
|
BLACKLIST_DIRS = (
|
|
os.path.join(bpy.utils.user_resource('SCRIPTS')),
|
|
) + tuple(addon_utils.paths()[1:])
|
|
|
|
|
|
def module_names_recursive(mod_dir, *, parent=None):
|
|
"""
|
|
a version of bpy.path.module_names that includes non-packages
|
|
"""
|
|
|
|
is_package = os.path.exists(os.path.join(mod_dir, "__init__.py"))
|
|
|
|
for n in os.listdir(mod_dir):
|
|
if not n.startswith((".", "_")):
|
|
submod_full = os.path.join(mod_dir, n)
|
|
if os.path.isdir(submod_full):
|
|
if not parent:
|
|
subparent = n
|
|
else:
|
|
subparent = parent + "." + n
|
|
yield from module_names_recursive(submod_full, parent=subparent)
|
|
elif n.endswith(".py") and is_package is False:
|
|
submod = n[:-3]
|
|
if parent:
|
|
submod = parent + "." + submod
|
|
yield submod, submod_full
|
|
|
|
|
|
def module_names_all(mod_dir):
|
|
yield from bpy.path.module_names(mod_dir)
|
|
yield from module_names_recursive(mod_dir)
|
|
|
|
|
|
def source_list(path, filename_check=None):
|
|
from os.path import join
|
|
for dirpath, dirnames, filenames in os.walk(path):
|
|
# skip '.git'
|
|
dirnames[:] = [d for d in dirnames if not d.startswith(".")]
|
|
|
|
for filename in filenames:
|
|
filepath = join(dirpath, filename)
|
|
if filename_check is None or filename_check(filepath):
|
|
yield filepath
|
|
|
|
|
|
def load_modules():
|
|
VERBOSE = os.environ.get("BLENDER_VERBOSE") is not None
|
|
|
|
modules = []
|
|
module_paths = []
|
|
|
|
# paths blender stores scripts in.
|
|
paths = bpy.utils.script_paths()
|
|
|
|
print("Paths:")
|
|
for script_path in paths:
|
|
print("\t'%s'" % script_path)
|
|
|
|
#
|
|
# find all sys.path we added
|
|
for script_path in paths:
|
|
for mod_dir in sys.path:
|
|
if mod_dir.startswith(script_path):
|
|
if not mod_dir.startswith(BLACKLIST_DIRS):
|
|
if mod_dir not in module_paths:
|
|
if os.path.exists(mod_dir):
|
|
module_paths.append(mod_dir)
|
|
|
|
#
|
|
# collect modules from our paths.
|
|
module_names = {}
|
|
for mod_dir in module_paths:
|
|
# print("mod_dir", mod_dir)
|
|
for mod, mod_full in bpy.path.module_names(mod_dir):
|
|
if mod in BLACKLIST:
|
|
continue
|
|
if mod in module_names:
|
|
mod_dir_prev, mod_full_prev = module_names[mod]
|
|
raise Exception("Module found twice %r.\n (%r -> %r, %r -> %r)" %
|
|
(mod, mod_dir, mod_full, mod_dir_prev, mod_full_prev))
|
|
|
|
modules.append(__import__(mod))
|
|
|
|
module_names[mod] = mod_dir, mod_full
|
|
del module_names
|
|
|
|
#
|
|
# test we tested all files except for presets and templates
|
|
ignore_paths = [
|
|
os.sep + "presets" + os.sep,
|
|
os.sep + "templates_osl" + os.sep,
|
|
os.sep + "templates_py" + os.sep,
|
|
os.sep + "bl_app_templates_system" + os.sep,
|
|
] + ([(os.sep + f + os.sep) for f in BLACKLIST] +
|
|
[(os.sep + f + ".py") for f in BLACKLIST])
|
|
|
|
#
|
|
# now submodules
|
|
for m in modules:
|
|
filepath = m.__file__
|
|
if os.path.basename(filepath).startswith("__init__."):
|
|
mod_dir = os.path.dirname(filepath)
|
|
for submod, submod_full in module_names_all(mod_dir):
|
|
# fromlist is ignored, ugh.
|
|
mod_name_full = m.__name__ + "." + submod
|
|
|
|
sys_path_back = sys.path[:]
|
|
|
|
sys.path.extend([
|
|
os.path.normpath(os.path.join(mod_dir, f))
|
|
for f in MODULE_SYS_PATHS.get(mod_name_full, ())
|
|
])
|
|
|
|
try:
|
|
__import__(mod_name_full)
|
|
mod_imp = sys.modules[mod_name_full]
|
|
|
|
sys.path[:] = sys_path_back
|
|
|
|
# check we load what we ask for.
|
|
assert os.path.samefile(mod_imp.__file__, submod_full)
|
|
|
|
modules.append(mod_imp)
|
|
except Exception:
|
|
import traceback
|
|
# Module might fail to import, but we don't want whole test to fail here.
|
|
# Reasoning:
|
|
# - This module might be in ignored list (for example, preset or template),
|
|
# so failing here will cause false-positive test failure.
|
|
# - If this is module which should not be ignored, it is not added to list
|
|
# of successfully loaded modules, meaning the test will catch this
|
|
# import failure.
|
|
# - We want to catch all failures of this script instead of stopping on
|
|
# a first big failure.
|
|
do_print = True
|
|
if not VERBOSE:
|
|
for ignore in ignore_paths:
|
|
if ignore in submod_full:
|
|
do_print = False
|
|
break
|
|
if do_print:
|
|
traceback.print_exc()
|
|
|
|
#
|
|
# check which filepaths we didn't load
|
|
source_files = []
|
|
for mod_dir in module_paths:
|
|
source_files.extend(source_list(mod_dir, filename_check=lambda f: f.endswith(".py")))
|
|
|
|
source_files = list(set(source_files))
|
|
source_files.sort()
|
|
|
|
#
|
|
# remove loaded files
|
|
loaded_files = list({m.__file__ for m in modules})
|
|
loaded_files.sort()
|
|
|
|
for f in loaded_files:
|
|
source_files.remove(f)
|
|
|
|
for f in source_files:
|
|
for ignore in ignore_paths:
|
|
if ignore in f:
|
|
break
|
|
else:
|
|
raise Exception("Source file %r not loaded in test" % f)
|
|
|
|
print("loaded %d modules" % len(loaded_files))
|
|
|
|
|
|
def main():
|
|
load_modules()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|