11"""Command line interface for Parxy document processing."""
22
33import json
4- import os
54import tomllib
65from datetime import timedelta
76from pathlib import Path
8- from typing import Optional , List , Annotated , Dict
7+ from typing import Optional , List , Annotated
98
109import typer
1110
2019console = Console ()
2120
2221
23- DEFAULT_MIDDLEWARE_PROFILES : Dict [str , List [str ]] = {
24- 'default' : [],
25- }
26-
27-
28- def _load_middleware_profiles (config_path : Optional [Path ]) -> Dict [str , List [str ]]:
29- """Load middleware profiles from optional config file.
22+ def _load_middleware_from_config (config_path : Path ) -> List [str ]:
23+ """Load middleware class paths from a config file.
3024
3125 Supports JSON, TOML, YAML and YML. The expected structure is either:
32- - ``{"middleware_profiles": {"profile": [" path.to.Middleware"]}} ``
33- - ``{"profiles": {"profile ": ["path.to.Middleware"]} }``
26+ - A top-level list: ``["path.to.Middleware1", " path.to.Middleware2"] ``
27+ - An object with a ``middleware`` key: ``{"middleware ": ["path.to.Middleware"]}``
3428 """
35- profiles = dict (DEFAULT_MIDDLEWARE_PROFILES )
36- if config_path is None :
37- return profiles
38-
3929 if not config_path .exists ():
4030 raise typer .BadParameter (f'Middleware config file not found: { config_path } ' )
4131
4232 suffix = config_path .suffix .lower ()
43- raw_data = None
4433
45- if suffix in { '.json' } :
34+ if suffix == '.json' :
4635 raw_data = json .loads (config_path .read_text (encoding = 'utf-8' ))
47- elif suffix in { '.toml' } :
36+ elif suffix == '.toml' :
4837 raw_data = tomllib .loads (config_path .read_text (encoding = 'utf-8' ))
4938 elif suffix in {'.yaml' , '.yml' }:
5039 try :
@@ -59,60 +48,43 @@ def _load_middleware_profiles(config_path: Optional[Path]) -> Dict[str, List[str
5948 'Unsupported middleware config format. Use .json, .toml, .yaml or .yml'
6049 )
6150
62- if not isinstance (raw_data , dict ):
63- raise typer .BadParameter (
64- 'Middleware config must be an object/map at top level.'
65- )
66-
67- custom_profiles = raw_data .get ('middleware_profiles' ) or raw_data .get ('profiles' )
68- if custom_profiles is None :
69- return profiles
70-
71- if not isinstance (custom_profiles , dict ):
51+ if isinstance (raw_data , list ):
52+ middleware_list = raw_data
53+ elif isinstance (raw_data , dict ):
54+ middleware_list = raw_data .get ('middleware' , [])
55+ if not isinstance (middleware_list , list ):
56+ raise typer .BadParameter (
57+ 'middleware_config: "middleware" key must be a list of class paths.'
58+ )
59+ else :
7260 raise typer .BadParameter (
73- 'middleware_profiles must be a map of profile names to middleware paths .'
61+ 'Middleware config must be a list or an object with a " middleware" key .'
7462 )
7563
76- for name , middleware_list in custom_profiles .items ():
77- if not isinstance (name , str ) or not isinstance (middleware_list , list ):
78- raise typer .BadParameter (
79- 'Each profile must map to a list of middleware class paths.'
80- )
81- if not all (isinstance (item , str ) for item in middleware_list ):
82- raise typer .BadParameter ('Middleware class paths must be strings.' )
83- profiles [name ] = middleware_list
64+ if not all (isinstance (item , str ) for item in middleware_list ):
65+ raise typer .BadParameter ('Middleware class paths must be strings.' )
8466
85- return profiles
67+ return middleware_list
8668
8769
88- def configure_middleware_profile (
89- profile : Optional [str ],
70+ def configure_middleware (
71+ middleware : Optional [List [ str ] ],
9072 config_path : Optional [Path ],
9173) -> None :
92- """Configure global middleware registry from a selected profile."""
93- selected_profile = profile or os .getenv ('PARXY_MIDDLEWARE_PROFILE' )
94- if not selected_profile :
95- return
74+ """Configure global middleware from inline class paths and/or a config file."""
75+ paths : List [str ] = list (middleware or [])
9676
97- env_config_path = os .getenv ('PARXY_MIDDLEWARE_CONFIG' )
98- effective_config = config_path or (
99- Path (env_config_path ) if env_config_path else None
100- )
101- profiles = _load_middleware_profiles (effective_config )
77+ if config_path is not None :
78+ paths .extend (_load_middleware_from_config (config_path ))
10279
103- if selected_profile not in profiles :
104- available = ', ' .join (sorted (profiles .keys ()))
105- raise typer .BadParameter (
106- f'Unknown middleware profile: { selected_profile } . Available profiles: { available } '
107- )
80+ if not paths :
81+ return
10882
109- middleware_paths = profiles [selected_profile ]
11083 Parxy .clear_middleware ()
111- if middleware_paths :
112- Parxy .with_middleware (middleware_paths )
84+ Parxy .with_middleware (paths )
11385
11486 console .info (
115- f" Using middleware profile ' { selected_profile } ' ( { len (middleware_paths )} middleware)."
87+ f' Using { len (paths )} middleware class { "es" if len ( paths ) != 1 else "" } .'
11688 )
11789
11890
@@ -360,20 +332,20 @@ def parse(
360332 min = 1 ,
361333 ),
362334 ] = None ,
363- middleware_profile : Annotated [
364- Optional [str ],
335+ middleware : Annotated [
336+ Optional [List [ str ] ],
365337 typer .Option (
366- '--middleware-profile ' ,
367- envvar = 'PARXY_MIDDLEWARE_PROFILE ' ,
368- help = 'Middleware profile name to activate. Built-in: default. Additional profiles can be loaded via --middleware-config .' ,
338+ '--middleware' ,
339+ '-p ' ,
340+ help = 'Middleware class path(s) to apply. Can be specified multiple times (e.g. --middleware my.pkg.MyMiddleware) .' ,
369341 ),
370342 ] = None ,
371343 middleware_config : Annotated [
372344 Optional [str ],
373345 typer .Option (
374346 '--middleware-config' ,
375347 envvar = 'PARXY_MIDDLEWARE_CONFIG' ,
376- help = 'Path to a .json/.toml/.yaml config file defining custom middleware profiles. ' ,
348+ help = 'Path to a .json/.toml/.yaml file with a list of middleware class paths to apply. Appended after inline middleware with --middleware ' ,
377349 ),
378350 ] = None ,
379351):
@@ -427,9 +399,8 @@ def parse(
427399 # Calculate total tasks
428400 total_tasks = len (files ) * len (drivers )
429401
430-
431- configure_middleware_profile (
432- profile = middleware_profile ,
402+ configure_middleware (
403+ middleware = middleware ,
433404 config_path = Path (middleware_config ) if middleware_config else None ,
434405 )
435406
0 commit comments