diff --git a/src/umlizer/class_graph.py b/src/umlizer/class_graph.py index f01c0e1..1ecef80 100644 --- a/src/umlizer/class_graph.py +++ b/src/umlizer/class_graph.py @@ -254,7 +254,8 @@ def _get_entity_class_uml(klass: ClassDef) -> str: def _search_modules( - target: str, exclude_pattern: list[str] = ['__pycache__'] + target: str, + exclude_pattern: list[str] = ['__pycache__'], ) -> list[str]: """ Search for Python modules in a given path, excluding specified patterns. @@ -372,7 +373,9 @@ def create_diagram( def load_classes_definition( - source: Path, verbose: bool = False + source: Path, + exclude: str, + verbose: bool = False, ) -> list[ClassDef]: """ Load classes definition from the source code located at the specified path. @@ -381,6 +384,7 @@ def load_classes_definition( ---------- source : Path The path to the source code. + exclude: pattern that excludes directories, modules or classes verbose : bool, optional Flag to enable verbose logging, by default False. @@ -404,7 +408,11 @@ def load_classes_definition( raise_error(f'Path "{path_str}" doesn\'t exist.', 1) if os.path.isdir(path_str): sys.path.insert(0, path_str) - module_files.extend(_search_modules(path_str)) + exclude_pattern = [exclude.strip() for exclude in exclude.split(',')] + exclude_pattern.append('__pycache__') + module_files.extend( + _search_modules(path_str, exclude_pattern=exclude_pattern) + ) else: module_files.append(path_str) diff --git a/src/umlizer/cli.py b/src/umlizer/cli.py index a2e22e0..8e3c72d 100644 --- a/src/umlizer/cli.py +++ b/src/umlizer/cli.py @@ -100,6 +100,15 @@ def class_( ..., help='Target path where the UML graph will be generated.' ), ] = Path('/tmp/'), + exclude: Annotated[ + str, + typer.Option( + help=( + 'Exclude directories, modules, or classes ' + '(eg. "migrations/*,scripts/*").' + ) + ), + ] = '', verbose: Annotated[ bool, typer.Option(help='Active the verbose mode.') ] = False, @@ -109,7 +118,7 @@ def class_( target = make_absolute(target) / 'class_graph' classes_nodes = class_graph.load_classes_definition( - source, verbose=verbose + source, exclude=exclude, verbose=verbose ) with open(f'{target}.yaml', 'w') as f: diff --git a/src/umlizer/utils.py b/src/umlizer/utils.py index 066ff20..559b187 100644 --- a/src/umlizer/utils.py +++ b/src/umlizer/utils.py @@ -1,9 +1,34 @@ """A set of utilitary tools.""" import inspect +import re from typing import Any +def blob_to_regex(blob: str) -> str: + """ + Convert a blob pattern to a regular expression. + + Parameters + ---------- + blob : str + The blob pattern to convert. + + Returns + ------- + str + The equivalent regular expression. + """ + # Escape special characters except for * and ? + blob = re.escape(blob) + + # Replace the escaped * and ? with their regex equivalents + blob = blob.replace(r'\*', '.*').replace(r'\?', '.') + + # Add start and end line anchors to the pattern + return '^' + blob + '$' + + def is_function(obj: Any) -> bool: """ Check if the given object is a function, method, or built-in method.