Extensions: add a Python API for user editable extension directories

Provide a convenient way to access a writable directory for extensions.
This will typically be accessed via:

  bpy.utils.extension_path_user(__package__, create=True)

This API is provided as some extensions on extensions.blender.org
are writing into the extensions own directory which is error prone:

- The extensions own directory is removed when upgrading.
- Users may not have write access to the extensions directory,
  especially with "System" repositories which may be on shared network
  drives for example.

These directories are only removed when:

- Uninstalling the extension.
- Removing the repository and its files.
This commit is contained in:
Campbell Barton
2024-06-26 14:23:17 +10:00
parent f5aaee39d2
commit 96906536db
8 changed files with 160 additions and 4 deletions

View File

@@ -795,6 +795,34 @@ _ext_base_pkg_idname_with_dot = _ext_base_pkg_idname + "."
_ext_manifest_filename_toml = "blender_manifest.toml"
def _extension_module_name_decompose(package):
"""
Returns the repository module name and the extensions ID from an extensions module name (``__package__``).
:arg module_name: The extensions module name.
:type module_name: string
:return: (repo_module_name, extension_id)
:rtype: tuple of strings
"""
if not package.startswith(_ext_base_pkg_idname_with_dot):
raise ValueError("The \"package\" does not name an extension")
repo_module, pkg_idname = package[len(_ext_base_pkg_idname_with_dot):].partition(".")[0::2]
if not (repo_module and pkg_idname):
raise ValueError("The \"package\" is expected to be a module name containing 3 components")
if "." in pkg_idname:
raise ValueError("The \"package\" is expected to be a module name containing 3 components, found {:d}".format(
pkg_idname.count(".") + 3
))
# Unlikely but possible.
if not (repo_module.isidentifier() and pkg_idname.isidentifier()):
raise ValueError("The \"package\" contains non-identifier characters")
return repo_module, pkg_idname
def _extension_preferences_idmap():
repos_idmap = {}
repos_idmap_disabled = {}