@@ -26,24 +26,44 @@ def get_sqlspec_group() -> "Group":
2626 @click .group (name = "sqlspec" )
2727 @click .option (
2828 "--config" ,
29- help = "Dotted path to SQLSpec config(s) or callable function (e.g. 'myapp.config.get_configs')" ,
30- required = True ,
29+ help = "Dotted path to SQLSpec config(s) or callable function (env: SQLSPEC_CONFIG)" ,
30+ required = False ,
31+ default = None ,
3132 type = str ,
33+ envvar = "SQLSPEC_CONFIG" ,
3234 )
3335 @click .option (
3436 "--validate-config" , is_flag = True , default = False , help = "Validate configuration before executing migrations"
3537 )
3638 @click .pass_context
37- def sqlspec_group (ctx : "click.Context" , config : str , validate_config : bool ) -> None :
39+ def sqlspec_group (ctx : "click.Context" , config : str | None , validate_config : bool ) -> None :
3840 """SQLSpec CLI commands."""
3941 from rich import get_console
4042
4143 from sqlspec .exceptions import ConfigResolverError
44+ from sqlspec .utils .config_discovery import discover_config_from_pyproject
4245 from sqlspec .utils .config_resolver import resolve_config_sync
4346
4447 console = get_console ()
4548 ctx .ensure_object (dict )
4649
50+ # Click already handled: CLI flag > SQLSPEC_CONFIG env var
51+ # Now check pyproject.toml as final fallback
52+ if config is None :
53+ config = discover_config_from_pyproject ()
54+ if config :
55+ console .print ("[dim]Using config from pyproject.toml[/]" )
56+
57+ # No config from any source - show helpful error
58+ if config is None :
59+ console .print ("[red]Error: No SQLSpec config found.[/]" )
60+ console .print ("\n Specify config using one of:" )
61+ console .print (" 1. CLI flag: sqlspec --config myapp.config:get_configs <command>" )
62+ console .print (" 2. Environment var: export SQLSPEC_CONFIG=myapp.config:get_configs" )
63+ console .print (" 3. pyproject.toml: [tool.sqlspec]" )
64+ console .print (' config = "myapp.config:get_configs"' )
65+ ctx .exit (1 )
66+
4767 # Add current working directory to sys.path to allow loading local config modules
4868 cwd = str (Path .cwd ())
4969 cwd_added = False
@@ -52,11 +72,34 @@ def sqlspec_group(ctx: "click.Context", config: str, validate_config: bool) -> N
5272 cwd_added = True
5373
5474 try :
55- config_result = resolve_config_sync (config )
56- if isinstance (config_result , Sequence ) and not isinstance (config_result , str ):
57- ctx .obj ["configs" ] = list (config_result )
58- else :
59- ctx .obj ["configs" ] = [config_result ]
75+ # Split comma-separated config paths and resolve each
76+ all_configs : list [AsyncDatabaseConfig [Any , Any , Any ] | SyncDatabaseConfig [Any , Any , Any ]] = []
77+ for config_path in config .split ("," ):
78+ config_path = config_path .strip ()
79+ if not config_path :
80+ continue
81+ config_result = resolve_config_sync (config_path )
82+ if isinstance (config_result , Sequence ) and not isinstance (config_result , str ):
83+ all_configs .extend (config_result )
84+ else :
85+ all_configs .append (
86+ cast ("AsyncDatabaseConfig[Any, Any, Any] | SyncDatabaseConfig[Any, Any, Any]" , config_result )
87+ )
88+
89+ # Deduplicate by bind_key (later configs override earlier ones)
90+ configs_by_key : dict [
91+ str | None , AsyncDatabaseConfig [Any , Any , Any ] | SyncDatabaseConfig [Any , Any , Any ]
92+ ] = {}
93+ for cfg in all_configs :
94+ configs_by_key [cfg .bind_key ] = cfg
95+
96+ ctx .obj ["configs" ] = list (configs_by_key .values ())
97+
98+ # Check for empty configs after resolution
99+ if not ctx .obj ["configs" ]:
100+ console .print ("[red]Error: No valid configs found after resolution.[/]" )
101+ console .print ("\n Ensure your config path returns valid config instance(s)." )
102+ ctx .exit (1 )
60103
61104 ctx .obj ["validate_config" ] = validate_config
62105
0 commit comments