Skip to content
This repository was archived by the owner on Mar 13, 2024. It is now read-only.
Open
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
65 changes: 65 additions & 0 deletions flask_toolkit/infra/module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import importlib


class AutoDiscover:
"""
This class search modules from path recursively. What it does
is actually search all the modules and run an `import_module` for each.

:param path: `pathlib.Path` object
:param pattern: Must be a string for search likes string.endswith(pattern)
:return: modules list

How to use:

autodiscover = AutoDiscover(path=...)
autodiscover()
"""

def __init__(self, path, pattern=None):
self.path = path
self.pattern = pattern
self.root = self.__get_dotted_full_path(path=path)

def __call__(self):
return self.__autodiscover(path=self.path, pattern=self.pattern)

def __autodiscover(self, path, pattern):
modules = []

for obj in path.iterdir():
if obj.name.startswith('_'):
continue

if (
obj.is_file()
Copy link
Contributor

Choose a reason for hiding this comment

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

💅 Tem uns espaços a mais aqui... acho que da pra alinhar o obj com and.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hahaha eu deixei para alinhar a condição... mas posso voltar também 🎉

and obj.suffix == '.py'
and obj.match(pattern or '*')
):
module_name = self.__normalize_module_name(
module_name='.'.join(obj.parts).replace('.py', '')
)
modules.append(importlib.import_module(module_name))

if obj.is_dir():
modules.extend(self.__autodiscover(path=obj, pattern=pattern))

return modules

def __normalize_module_name(self, module_name):
return module_name[module_name.find(self.root):]

def __get_root_parts(self, path):
def get_root_parts(path):
Copy link
Contributor

Choose a reason for hiding this comment

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

Depois me explica isso aqui? haha 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hahaha

Esse método serve para buscar o root package ou man package para fazer o import corretamente, pois nesse momento só tem o caminho absoluto do arquivo, como: /app/app/infra/event_bus/subscribes

O nome do módulo para funcionar deve ser: app.infra.event_bus.subscribes..., saka?

O que essa função faz é subir os niveis enquanto achar o __init__.py entre eles. Quando não achar significa que chegou no root da aplicação.

Esse root serve de aux para normalizar o nome do módulo, pois como disse, só tem o caminho absoluto dos arquivos e vem algo como já mencionei.

O normalize exclui tudo que vem antes do man package e aí o import fica limpo, como: app.infra.event_bus.subscribes.operations

Saka?

Isso foi feito para ser genérico, pois podemos chamar o autodiscover em qualquer lugar, como por exemplo em app.api para buscar as views. 🤔

parts = []
try:
next(path.glob('__init__.py'))
except StopIteration:
return parts
parts.append(path.name)
parts.extend(get_root_parts(path.parent))
return parts
return reversed(get_root_parts(path=path))

def __get_dotted_full_path(self, path):
return '.'.join(self.__get_root_parts(path=path))