Add to sys.modules
Among other ways to make fake modules, can simply add it to sys.modules
>>> import sys
>>> sys.modules["function"] = bpy.data.texts['function.py'].as_module()
>>> from function import function
>>> function()
hello
Have a good link re fake modules and namespaces, will look for it.
https://stackoverflow.com/questions/5122465/can-i-fake-a-package-or-at-least-a-module-in-python-for-testing-purposes/27476659#27476659
Will add this link here too, https://dev.to/dangerontheranger/dependency-injection-with-import-hooks-in-python-3-5hap in can make a fake namespace that can be imported as if a regular module.
An example using above (stripped of comments to make shorter) making the function method appear to come from module my_addon.utils
import importlib.abc
import importlib.machinery
import sys
import types
class DependencyInjectorFinder(importlib.abc.MetaPathFinder):
def init(self, loader):
self._loader = loader
def find_spec(self, fullname, path, target=None):
if self._loader.provides(fullname):
return self._gen_spec(fullname)
def _gen_spec(self, fullname):
spec = importlib.machinery.ModuleSpec(fullname, self._loader)
return spec
class DependencyInjectorLoader(importlib.abc.Loader):
_COMMON_PREFIX = "my_addon."
def init(self):
self._services = {}
self._dummy_module = types.ModuleType(self._COMMON_PREFIX[:-1])
self._dummy_module.__path__ = []
def provide(self, service_name, module):
self._services[service_name] = module
def provides(self, fullname):
if self._truncate_name(fullname) in self._services:
return True
else:
return self._COMMON_PREFIX.startswith(fullname)
def create_module(self, spec):
service_name = self._truncate_name(spec.name)
if service_name not in self._services:
return self._dummy_module
module = self._services[service_name]
return module
def exec_module(self, module):
pass
def _truncate_name(self, fullname):
return fullname[len(self._COMMON_PREFIX):]
class DependencyInjector:
def __init__(self):
self._loader = DependencyInjectorLoader()
self._finder = DependencyInjectorFinder(self._loader)
def install(self):
sys.meta_path.append(self._finder)
def provide(self, service_name, module):
self._loader.provide(service_name, module)
if name == "main":
import bpy
injector = DependencyInjector()
injector.provide("utils", bpy.data.texts["functions.py"].as_module())
injector.install()
import my_addon.utils as utils
utils.function()
output
hello
Hello WorldI've ever seen :) – Gorgious Feb 23 '21 at 07:17from my_addon.libs import matplotlibto inject some dummy for the case of the real one not installed. In this case OP can develop a script in blend file text editor to look likefrom my_addon.utils import functionThanks for the feedback, it's appreciated. – batFINGER Feb 23 '21 at 08:27