Ver a proveniência

Get rid of inheritance-level-based module selection and instead raise an exception if there are no or multiple matching modules

tags/v1.0
JustAnotherArchivist há 3 anos
ascendente
cometimento
5f9547d600
1 ficheiros alterados com 17 adições e 24 eliminações
  1. +17
    -24
      codearchiver/core.py

+ 17
- 24
codearchiver/core.py Ver ficheiro

@@ -145,35 +145,28 @@ def get_module_class(inputUrl: InputURL) -> typing.Type['Module']:
# This can't be done at the top because the modules need to refer back to the Module class.
import codearchiver.modules

# Collect all the Module subclasses and their inheritance level
modules = {} # Module -> level:int
# Collect all the Module subclasses
modules = set()
q = queue.Queue()
q.put_nowait((Module, 0))
q.put_nowait(Module)
while not q.empty():
class_, level = q.get_nowait()
class_ = q.get_nowait()
for c in class_.__subclasses__():
logger.debug(f'Found module {c.__module__}.{c.__name__} at level {level + 1}')
modules[c] = level + 1 # Implicitly only keeps the highest level, i.e. deepest inheritance
q.put_nowait((c, level + 1))

# Restructure into level->[modules] mapping
levels = collections.defaultdict(list)
for class_, level in modules.items():
levels[level].append(class_)

# Process in descending level order
for level in reversed(levels):
matches = [class_ for class_ in levels[level] if class_.matches(inputUrl)]
if len(matches) >= 2:
logger.warning('Multiple matching modules for input URL, using the first found')
logger.debug(f'Matching modules at level {level}: {matches!r}')
logger.debug(f'Modules: {levels!r}')
if matches:
logger.info(f'Selecting module {matches[0].__module__}.{matches[0].__name__}')
return matches[0]
logger.debug(f'Found module {c.__module__}.{c.__name__}')
modules.add(c)
q.put_nowait(c)

matches = [class_ for class_ in modules if class_.matches(inputUrl)]
if len(matches) >= 2:
logger.error('Multiple matching modules for input URL')
logger.debug(f'Matching modules: {matches!r}')
raise RuntimeError('Multiple matching modules for input URL')
if matches:
logger.info(f'Selecting module {matches[0].__module__}.{matches[0].__name__}')
return matches[0]
raise RuntimeError('No matching modules for input URL')


def get_module_instance(inputUrl: InputURL, **kwargs) -> 'Module':
'''Get an instance of the Module class most suitable for handling `inputUrl`.'''
return get_module_class(inputUrl)(inputUrl, **kwargs)


Carregando…
Cancelar
Guardar