from __future__ import annotations from typing import Any, Callable, Dict, Iterable, Sequence from importlib import import_module as _import_module # A cmdlet is a callable taking (result, args, config) -> int Cmdlet = Callable[[Any, Sequence[str], Dict[str, Any]], int] # Registry of command-name -> cmdlet function REGISTRY: Dict[str, Cmdlet] = {} def register(names: Iterable[str]): """Decorator to register a function under one or more command names. Usage: @register(["add-tags"]) def _run(result, args, config) -> int: ... """ def _wrap(fn: Cmdlet) -> Cmdlet: for name in names: REGISTRY[name.replace('_', '-').lower()] = fn return fn return _wrap def get(cmd_name: str) -> Cmdlet | None: return REGISTRY.get(cmd_name.replace('_', '-').lower()) # Dynamically import all cmdlet modules in this directory (ignore files starting with _ and __init__.py) # Cmdlets self-register when instantiated via their __init__ method import os cmdlet_dir = os.path.dirname(__file__) for filename in os.listdir(cmdlet_dir): if not ( filename.endswith(".py") and not filename.startswith("_") and filename != "__init__.py" ): continue mod_name = filename[:-3] # Enforce Powershell-style two-word cmdlet naming (e.g., add_file, get_file) # Skip native/utility scripts that are not cmdlets (e.g., adjective, worker, matrix, pipe) if "_" not in mod_name: continue try: _import_module(f".{mod_name}", __name__) except Exception as e: import sys print(f"Error importing cmdlet '{mod_name}': {e}", file=sys.stderr) continue # Import and register native commands that are not considered cmdlets try: from cmdnats import register_native_commands as _register_native_commands _register_native_commands(REGISTRY) except Exception: # Native commands are optional; ignore if unavailable pass # Import root-level modules that also register cmdlets for _root_mod in ("select_cmdlet",): try: _import_module(_root_mod) except Exception: # Allow missing optional modules continue # Also import helper modules that register cmdlets try: import API.alldebrid as _alldebrid except Exception: pass