Skip to content

feat: Improved __init__.py for skeletons and modules #137

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
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
67 changes: 30 additions & 37 deletions deploy/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,57 +9,50 @@
# Automatic imports are done here! #
####################################

import logging
import types
import viur
import os
import importlib
import inspect
from pathlib import Path
from viur.core import Module as __viur_Module

_viur_modules = {}
# Get the current directory (where this __init__.py is located)
__current_dir = Path(__file__).parent

BLACKLIST = [] # filenames that should be blacklisted for the import
# Define a blacklist of filenames (without path)
BLACKLIST = {"exclude_this.py", "ignore_me.py"}


def _import_modules(_dir: Path, _prefix: str = "") -> None:
for _path in _dir.iterdir():
if _path.is_dir():
_import_modules(_path, f"{_prefix}{_path.stem}.")
continue
# Recursive function to find all .py files in subdirectories
def __find_py_files(directory):
py_files = []
for root, _, files in os.walk(directory):
for file in files:
if file.endswith(".py") and file != "__init__.py" and file not in BLACKLIST:
py_files.append(Path(root) / file)

elif _path.stem.startswith("_") or _path.suffix != ".py":
continue
return py_files

_module = _prefix + _path.stem

try:
_import = __import__(_module, globals(), locals(), [_module], level=1)
# Iterate over all Python files in the module hierarchy
for __py_file in __find_py_files(__current_dir):
# Convert file path to module name
__relative_path = __py_file.relative_to(__current_dir)
__module_name = ".".join(__relative_path.with_suffix("").parts)

for _name in dir(_import):
if _name.startswith("_"):
continue
# Import the module
__module = importlib.import_module(f".{__module_name}", package=__name__)

_symbol = getattr(_import, _name)
if (getattr(_symbol, "__module__", None) != f"modules.{_module}"
or isinstance(_symbol, viur.core.Module) or isinstance(_symbol, types.FunctionType)):
continue
# Inspect module for classes of type Module
for name, obj in inspect.getmembers(__module, inspect.isclass):
if issubclass(obj, __viur_Module) and obj.__module__ == __module.__name__:
# Import the class into the current namespace
print(name.lower(), obj)
Copy link
Member

@sveneberth sveneberth Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use print and use the logging framework.

Even if it is not established, maybe also a custom logger

log = logging.getLogger("my-project").getChild(__name__).getChild("autoloader")

Using the root logger is actually mostly a bad idea, but that's another problem in ViUR and ViUR projects ...

globals()[name.lower()] = obj

if (alias := f"{_prefix}{_name.lower()}") not in BLACKLIST:
logging.debug(f"Importing {_symbol} as {alias}")
_viur_modules[alias] = _symbol

except Exception:
logging.exception(f"Unable to import '{_module}'")
raise


_import_modules(Path(__file__).resolve().parent)

globals().update(_viur_modules)

del _viur_modules, Path, logging, viur, _import_modules, BLACKLIST

#########################################
# Manual imports can also be done here! #
#########################################

# noinspection PyUnresolvedReferences
from viur.core.modules.site import Site as s # noqa: E402
from viur.core.modules.site import Site as s # noqa: E402, E401
33 changes: 24 additions & 9 deletions deploy/skeletons/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
# This is the ViUR default skeleton importer;
# If any other importing logic is wanted, please switch to manual import calls in this file, and remove
# the dynamic code provided below.

import os
import importlib


def import_submodules(package_dir, package_name):
"""
Recursively imports all modules in the given package directory.

:param package_dir: Path to the directory of the package
:param package_name: Name of the package
"""
for entry in os.listdir(package_dir):
entry_path = os.path.join(package_dir, entry)
if os.path.isdir(entry_path) and os.path.exists(os.path.join(entry_path, "__init__.py")):
# Recursively import subpackages
import_submodules(entry_path, f"{package_name}.{entry}")
elif entry.endswith(".py") and entry != "__init__.py":
# Import the module
module_name = entry[:-3] # Remove the .py extension
importlib.import_module(f"{package_name}.{module_name}")

for skelModule in os.listdir(os.path.dirname(__file__)):
if skelModule == "__init__.py" or not skelModule.endswith(".py"):
continue

__import__(skelModule[:-3], globals(), locals(), level=1)
# Set the base directory and package name
base_dir = os.path.dirname(__file__)
base_package = os.path.basename(base_dir)

del skelModule
# Import all submodules recursively
import_submodules(base_dir, base_package)