Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: __build_app function clean-up and make all modules accessible #1240

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions src/viur/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def setDefaultDomainLanguage(domain: str, lang: str):
conf.i18n.domain_language_mapping[host] = lang.lower()


def buildApp(modules: ModuleType | object, renderers: ModuleType | object, default: str = None) -> Module:
def __build_app(modules: ModuleType | object, renderers: ModuleType | object, default: str = None) -> Module:
"""
Creates the application-context for the current instance.

Expand Down Expand Up @@ -118,12 +118,6 @@ def buildApp(modules: ModuleType | object, renderers: ModuleType | object, defau
renderers[key][subkey] = render
del renderers_root

# instanciate root module
if hasattr(modules, "index"):
root = modules.index("index", "")
else:
root = Module("index", "")

# assign ViUR system modules
from viur.core.modules.moduleconf import ModuleConf # noqa: E402 # import works only here because circular imports
from viur.core.modules.script import Script # noqa: E402 # import works only here because circular imports
Expand All @@ -135,20 +129,29 @@ def buildApp(modules: ModuleType | object, renderers: ModuleType | object, defau
modules._translation = Translation
modules.script = Script

# create module mappings
# Resolver defines the URL mapping
resolver = {}

# Index is mapping all module instances for global access
index = (modules.index if hasattr(modules, "index") else Module)("index", "")
index.register(resolver, renderers[default]["default"](parent=index))

for module_name, module_cls in vars(modules).items(): # iterate over all modules
if module_name == "index":
continue # ignore index, as it has been processed before!

if module_name in renderers:
raise NameError(f"Cannot name module {module_name!r}, as it is a reserved render's name")

if not ( # we define the cases we want to use and then negate them all
(inspect.isclass(module_cls) and issubclass(module_cls, Module) # is a normal Module class
and not issubclass(module_cls, InstancedModule)) # but not a "instantiable" Module
or isinstance(module_cls, InstancedModule) # is an already instanced Module
):
continue

if module_name == "index":
root.register(resolver, renderers[default]["default"](parent=root))
continue
# remember module_instance for default renderer.
module_instance = default_module_instance = None

for render_name, render in renderers.items(): # look, if a particular renderer should be built
# Only continue when module_cls is configured for this render
Expand All @@ -163,15 +166,15 @@ def buildApp(modules: ModuleType | object, renderers: ModuleType | object, defau

# Attach the module-specific or the default render
if render_name == default: # default or render (sub)namespace?
setattr(root, module_name, module_instance)
default_module_instance = module_instance
target = resolver
else:
if getattr(root, render_name, True) is True:
if getattr(index, render_name, True) is True:
# Render is not build yet, or it is just the simple marker that a given render should be build
setattr(root, render_name, Module(render_name, "/" + render_name))
setattr(index, render_name, Module(render_name, "/" + render_name))

# Attach the module to the given renderer node
setattr(getattr(root, render_name), module_name, module_instance)
setattr(getattr(index, render_name), module_name, module_instance)
target = resolver.setdefault(render_name, {})

module_instance.register(target, render.get(module_name, render["default"])(parent=module_instance))
Expand All @@ -180,8 +183,14 @@ def buildApp(modules: ModuleType | object, renderers: ModuleType | object, defau
if "_postProcessAppObj" in render: # todo: This is ugly!
render["_postProcessAppObj"](target)

conf.main_resolver = resolver
# Ugly solution, but there is no better way to do it in ViUR 3:
# Allow that any module can be accessed by `conf.main_app.<modulename>`,
# either with default render or the last created render.
# This behavior does NOT influence the routing.
if default_module_instance or module_instance:
setattr(index, module_name, default_module_instance or module_instance)

# fixme: Below is also ugly...
if default in renderers and hasattr(renderers[default]["default"], "renderEmail"):
conf.emailRenderer = renderers[default]["default"]().renderEmail
elif "html" in renderers:
Expand All @@ -192,7 +201,8 @@ def buildApp(modules: ModuleType | object, renderers: ModuleType | object, defau
import pprint
logging.debug(pprint.pformat(resolver))

return root
conf.main_resolver = resolver
conf.main_app = index


def setup(modules: ModuleType | object, render: ModuleType | object = None, default: str = "html"):
Expand All @@ -215,7 +225,8 @@ def setup(modules: ModuleType | object, render: ModuleType | object = None, de
if not render:
import viur.core.render
render = viur.core.render
conf.main_app = buildApp(modules, render, default)

__build_app(modules, render, default)

# Send warning email in case trace is activated in a cloud environment
if ((conf.debug.trace
Expand Down
Loading