11import os
2+ from typing import Optional
3+
4+ from rich .console import Console
25
36from .dotenv import load_env_file
47from .errors import EnvSafeError
811def venvalid (
912 specs : dict [str , object ],
1013 * ,
11- source : dict [str , str ] | None = None ,
14+ source : Optional [ dict [str , str ]] = None ,
1215 dotenv_path : str = ".env" ,
1316 dotenv_override : bool = False ,
17+ pretty : bool = False ,
18+ exit_on_error : bool = True ,
1419) -> dict [str , object ]:
1520 """
1621 Validates and loads environment variables based on declarative specifications.
@@ -20,9 +25,14 @@ def venvalid(
2025 source (dict, optional): Alternative source for the variables (default: os.environ).
2126 dotenv_path (str, optional): Path to the .env file to be loaded.
2227 dotenv_override (bool): If True, overwrites existing variables when loading .env.
28+ pretty (bool): If True, uses rich to pretty-print errors.
29+ exit_on_error (bool): If True, calls SystemExit(1) on validation errors (default=True for backwards compat).
2330
2431 Returns:
2532 dict: Validated and converted environment variables.
33+
34+ Raises:
35+ ValidationError: If exit_on_error=False and validation fails.
2636 """
2737 if source is None :
2838 load_env_file (dotenv_path , override = dotenv_override )
@@ -32,13 +42,19 @@ def venvalid(
3242
3343 for key , spec in specs .items ():
3444 raw_value = env_source .get (key )
35-
3645 try :
3746 value = _resolve_variable (key , raw_value , spec )
3847 result [key ] = value
3948 except EnvSafeError as e :
40- print (f"\n { e } \n " )
41- raise SystemExit (1 )
49+ if pretty :
50+ try :
51+ console = Console ()
52+ console .print (f"[bold red]Error:[/bold red] { e } " )
53+ except ImportError :
54+ pass
55+ if exit_on_error :
56+ raise SystemExit (1 )
57+ raise
4258
4359 return result
4460
@@ -47,7 +63,6 @@ def _resolve_variable(key: str, raw: str | None, spec: object) -> object:
4763 """
4864 Resolves and validates an environment variable based on its specification.
4965 """
50- # Case enum-style: ["dev", "prod"]
5166 if isinstance (spec , list ):
5267 if raw is None :
5368 raise EnvSafeError (f"{ key } is required and must be one of { spec } " )
@@ -62,18 +77,14 @@ def _resolve_variable(key: str, raw: str | None, spec: object) -> object:
6277
6378 if isinstance (spec , tuple ):
6479 t_candidate , options = spec
65-
6680 if not isinstance (t_candidate , type ):
6781 raise TypeError (f"{ key } : expected a type, got { t_candidate } " )
68-
6982 expected_type = t_candidate
7083 default = options .get ("default" )
7184 allowed = options .get ("allowed" )
7285 validate = options .get ("validate" )
73-
7486 elif isinstance (spec , type ):
7587 expected_type = spec
76-
7788 else :
7889 raise TypeError (f"{ key } : invalid spec type { type (spec )} " )
7990
0 commit comments