mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-30 09:43:43 -04:00 
			
		
		
		
	
		
			
	
	
		
			101 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			101 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|  | import pathlib | ||
|  | import re | ||
|  | from dataclasses import dataclass, field | ||
|  | 
 | ||
|  | from utils import PROJECT_DIR, log, render_python_template | ||
|  | 
 | ||
|  | template = """# This file is auto-generated by gen_schema_exports.py
 | ||
|  | {% for file in data.module.files %}{{ file.import_str() }} | ||
|  | {% endfor %} | ||
|  | 
 | ||
|  | __all__ = [ | ||
|  |     {% for file in data.module.files %} | ||
|  |     {%- for class in file.classes -%} | ||
|  |     "{{ class }}", | ||
|  |     {%- endfor -%} | ||
|  |     {%- endfor %} | ||
|  | ] | ||
|  | 
 | ||
|  | """
 | ||
|  | 
 | ||
|  | SCHEMA_PATH = PROJECT_DIR / "mealie" / "schema" | ||
|  | 
 | ||
|  | SKIP = {"static", "__pycache__"} | ||
|  | 
 | ||
|  | 
 | ||
|  | class PyFile: | ||
|  |     import_path: str | ||
|  |     """The import path of the file""" | ||
|  | 
 | ||
|  |     classes: list[str] | ||
|  |     """A list of classes in the file""" | ||
|  | 
 | ||
|  |     def __init__(self, path: pathlib.Path): | ||
|  |         self.import_path = path.stem | ||
|  |         self.classes = [] | ||
|  | 
 | ||
|  |         self.classes = PyFile.extract_classes(path) | ||
|  |         self.classes.sort() | ||
|  | 
 | ||
|  |     def import_str(self) -> str: | ||
|  |         """Returns a string that can be used to import the file""" | ||
|  |         return f"from .{self.import_path} import {', '.join(self.classes)}" | ||
|  | 
 | ||
|  |     @staticmethod | ||
|  |     def extract_classes(file_path: pathlib.Path) -> list[str]: | ||
|  |         name = file_path.stem | ||
|  | 
 | ||
|  |         if name == "__init__" or name.startswith("_"): | ||
|  |             return [] | ||
|  | 
 | ||
|  |         classes = re.findall(r"(?m)^class\s(\w+)", file_path.read_text()) | ||
|  |         return classes | ||
|  | 
 | ||
|  | 
 | ||
|  | @dataclass | ||
|  | class Modules: | ||
|  |     directory: pathlib.Path | ||
|  |     """The directory to search for modules""" | ||
|  | 
 | ||
|  |     files: list[PyFile] = field(default_factory=list) | ||
|  |     """A list of files in the directory""" | ||
|  | 
 | ||
|  |     def __post_init__(self): | ||
|  |         for file in self.directory.glob("*.py"): | ||
|  |             if file.name.startswith("_"): | ||
|  |                 continue | ||
|  | 
 | ||
|  |             pfile = PyFile(file) | ||
|  | 
 | ||
|  |             if len(pfile.classes) > 0: | ||
|  |                 self.files.append(pfile) | ||
|  | 
 | ||
|  |             else: | ||
|  |                 log.debug(f"Skipping {file.name} as it has no classes") | ||
|  | 
 | ||
|  | 
 | ||
|  | def find_modules(root: pathlib.Path) -> list[Modules]: | ||
|  |     """Finds all the top level modules in the provided folder""" | ||
|  |     modules: list[Modules] = [] | ||
|  |     for file in root.iterdir(): | ||
|  |         if file.is_dir() and file.name not in SKIP: | ||
|  |             modules.append(Modules(directory=file)) | ||
|  | 
 | ||
|  |     return modules | ||
|  | 
 | ||
|  | 
 | ||
|  | def main(): | ||
|  |     modules = find_modules(SCHEMA_PATH) | ||
|  | 
 | ||
|  |     for module in modules: | ||
|  |         log.debug(f"Module: {module.directory.name}") | ||
|  |         for file in module.files: | ||
|  |             log.debug(f"  File: {file.import_path}") | ||
|  |             log.debug(f"    Classes: [{', '.join(file.classes)}]") | ||
|  | 
 | ||
|  |         render_python_template(template, module.directory / "__init__.py", {"module": module}) | ||
|  | 
 | ||
|  | 
 | ||
|  | if __name__ == "__main__": | ||
|  |     main() |