123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 |
- # -*- coding: utf-8 -*-
- from importlib import import_module
- from inspect import (
- getmembers,
- isclass,
- )
- from pkgutil import walk_packages
- from typing import ( # NOQA
- Dict,
- List,
- Tuple,
- Union,
- )
- from django.conf import settings
- from django.utils.module_loading import import_string
- class SubclassesFinder:
- def __init__(self, base_classes_from_settings):
- self.base_classes = []
- for element in base_classes_from_settings:
- if isinstance(element, str):
- element = import_string(element)
- self.base_classes.append(element)
- def _should_be_imported(self, candidate_to_import): # type: (Tuple[str, type]) -> bool
- for base_class in self.base_classes:
- if issubclass(candidate_to_import[1], base_class):
- return True
- return False
- def collect_subclasses(self): # type: () -> Dict[str, List[Tuple[str, str]]]
- """
- Collect all subclasses of user-defined base classes from project.
- :return: Dictionary from module name to list of tuples.
- First element of tuple is model name and second is alias.
- Currently we set alias equal to model name,
- but in future functionality of aliasing subclasses can be added.
- """
- result = {} # type: Dict[str, List[Tuple[str, str]]]
- for loader, module_name, is_pkg in walk_packages(path=[settings.BASE_DIR]):
- subclasses_from_module = self._collect_classes_from_module(module_name)
- if subclasses_from_module:
- result[module_name] = subclasses_from_module
- return result
- def _collect_classes_from_module(self, module_name): # type: (str) -> List[Tuple[str, str]]
- for excluded_module in getattr(settings, 'SHELL_PLUS_SUBCLASSES_IMPORT_MODULES_BLACKLIST', []):
- if module_name.startswith(excluded_module):
- return []
- imported_module = import_module(module_name)
- classes_to_import = getmembers(
- imported_module, lambda element: isclass(element) and element.__module__ == imported_module.__name__
- )
- classes_to_import = list(filter(self._should_be_imported, classes_to_import))
- return [(name, name) for name, _ in classes_to_import]
|