milieux.config
1from dataclasses import dataclass, field 2from pathlib import Path 3from typing import Annotated, Optional 4 5from fancy_dataclass import ConfigDataclass, TOMLDataclass 6from typing_extensions import Doc 7 8from milieux import PKG_NAME 9from milieux.errors import ConfigNotFoundError 10from milieux.utils import resolve_path 11 12 13################# 14# DEFAULT PATHS # 15################# 16 17def user_dir() -> Path: 18 """Gets the path to the user's directory where configs, etc. will be stored.""" 19 return Path.home() / f'.{PKG_NAME}' 20 21def user_default_config_path() -> Path: 22 """Gets the default path to the user's config file.""" 23 return user_dir() / 'config.toml' 24 25def user_default_base_dir() -> Path: 26 """Gets the default path to the user's base workspace directory.""" 27 return user_dir() / 'workspace' 28 29# global variable storing the config path 30_CONFIG_PATH: Optional[Path] = None 31 32def get_config_path() -> Path: 33 """Gets the global configuration path.""" 34 return _CONFIG_PATH or user_default_config_path() 35 36def set_config_path(cfg_path: Path) -> None: 37 """Sets the global configuration path.""" 38 global _CONFIG_PATH 39 _CONFIG_PATH = cfg_path 40 41 42########## 43# CONFIG # 44########## 45 46@dataclass 47class PipConfig(TOMLDataclass): 48 """Configurations for pip.""" 49 index_url: Annotated[ 50 Optional[str], 51 Doc('URL for PyPI index') 52 ] = None 53 54 55@dataclass 56class Config(ConfigDataclass, TOMLDataclass): # type: ignore[misc] 57 """Configurations for milieux.""" 58 base_dir: Annotated[ 59 str, 60 Doc('base directory (by default, everything will be installed here)') 61 ] = field(default_factory=lambda: str(user_default_base_dir())) 62 env_dir: Annotated[ 63 str, 64 Doc('directory for virtual environments') 65 ] = 'envs' 66 distro_dir: Annotated[ 67 str, 68 Doc('directory for distros (Python requirements files)') 69 ] = 'distros' 70 pip: PipConfig = field(default_factory=PipConfig) 71 72 @property 73 def base_dir_path(self) -> Path: 74 """Gets the path to the base workspace directory.""" 75 return Path(self.base_dir) 76 77 @property 78 def env_dir_path(self) -> Path: 79 """Gets the path to the environment directory.""" 80 return resolve_path(self.env_dir, Path(self.base_dir)) 81 82 @property 83 def distro_dir_path(self) -> Path: 84 """Gets the path to the distro directory.""" 85 return resolve_path(self.distro_dir, Path(self.base_dir)) 86 87 88def get_config() -> Config: 89 """Gets the current configurations. 90 If none are set, loads them from the user's default config path.""" 91 cfg = Config.get_config() 92 if cfg is None: 93 config_path = user_default_config_path() 94 try: 95 cfg = Config.load_config(config_path) 96 except FileNotFoundError as e: 97 raise ConfigNotFoundError(f'Could not load configs from {config_path}') from e 98 set_config_path(config_path) 99 cfg.update_config() 100 return cfg 101 102def update_command_with_index_url(cmd: list[str]) -> None: 103 """Given a `uv` command (list of arguments), if the globally configured `index_url` is set, adds a corresponding `--index-url` argument, in-place.""" 104 cfg = get_config() 105 if (index_url := cfg.pip.index_url): 106 cmd.extend(['--index-url', index_url])
def
user_dir() -> pathlib.Path:
18def user_dir() -> Path: 19 """Gets the path to the user's directory where configs, etc. will be stored.""" 20 return Path.home() / f'.{PKG_NAME}'
Gets the path to the user's directory where configs, etc. will be stored.
def
user_default_config_path() -> pathlib.Path:
22def user_default_config_path() -> Path: 23 """Gets the default path to the user's config file.""" 24 return user_dir() / 'config.toml'
Gets the default path to the user's config file.
def
user_default_base_dir() -> pathlib.Path:
26def user_default_base_dir() -> Path: 27 """Gets the default path to the user's base workspace directory.""" 28 return user_dir() / 'workspace'
Gets the default path to the user's base workspace directory.
def
get_config_path() -> pathlib.Path:
33def get_config_path() -> Path: 34 """Gets the global configuration path.""" 35 return _CONFIG_PATH or user_default_config_path()
Gets the global configuration path.
def
set_config_path(cfg_path: pathlib.Path) -> None:
37def set_config_path(cfg_path: Path) -> None: 38 """Sets the global configuration path.""" 39 global _CONFIG_PATH 40 _CONFIG_PATH = cfg_path
Sets the global configuration path.
@dataclass
class
PipConfig47@dataclass 48class PipConfig(TOMLDataclass): 49 """Configurations for pip.""" 50 index_url: Annotated[ 51 Optional[str], 52 Doc('URL for PyPI index') 53 ] = None
Configurations for pip.
@dataclass
class
Config56@dataclass 57class Config(ConfigDataclass, TOMLDataclass): # type: ignore[misc] 58 """Configurations for milieux.""" 59 base_dir: Annotated[ 60 str, 61 Doc('base directory (by default, everything will be installed here)') 62 ] = field(default_factory=lambda: str(user_default_base_dir())) 63 env_dir: Annotated[ 64 str, 65 Doc('directory for virtual environments') 66 ] = 'envs' 67 distro_dir: Annotated[ 68 str, 69 Doc('directory for distros (Python requirements files)') 70 ] = 'distros' 71 pip: PipConfig = field(default_factory=PipConfig) 72 73 @property 74 def base_dir_path(self) -> Path: 75 """Gets the path to the base workspace directory.""" 76 return Path(self.base_dir) 77 78 @property 79 def env_dir_path(self) -> Path: 80 """Gets the path to the environment directory.""" 81 return resolve_path(self.env_dir, Path(self.base_dir)) 82 83 @property 84 def distro_dir_path(self) -> Path: 85 """Gets the path to the distro directory.""" 86 return resolve_path(self.distro_dir, Path(self.base_dir))
Configurations for milieux.
Config( base_dir: typing.Annotated[str, Doc('base directory (by default, everything will be installed here)')] = <factory>, env_dir: typing.Annotated[str, Doc('directory for virtual environments')] = 'envs', distro_dir: typing.Annotated[str, Doc('directory for distros (Python requirements files)')] = 'distros', pip: PipConfig = <factory>)
base_dir: typing.Annotated[str, Doc('base directory (by default, everything will be installed here)')]
distro_dir: typing.Annotated[str, Doc('directory for distros (Python requirements files)')] =
'distros'
pip: PipConfig
base_dir_path: pathlib.Path
73 @property 74 def base_dir_path(self) -> Path: 75 """Gets the path to the base workspace directory.""" 76 return Path(self.base_dir)
Gets the path to the base workspace directory.
89def get_config() -> Config: 90 """Gets the current configurations. 91 If none are set, loads them from the user's default config path.""" 92 cfg = Config.get_config() 93 if cfg is None: 94 config_path = user_default_config_path() 95 try: 96 cfg = Config.load_config(config_path) 97 except FileNotFoundError as e: 98 raise ConfigNotFoundError(f'Could not load configs from {config_path}') from e 99 set_config_path(config_path) 100 cfg.update_config() 101 return cfg
Gets the current configurations. If none are set, loads them from the user's default config path.
def
update_command_with_index_url(cmd: list[str]) -> None:
103def update_command_with_index_url(cmd: list[str]) -> None: 104 """Given a `uv` command (list of arguments), if the globally configured `index_url` is set, adds a corresponding `--index-url` argument, in-place.""" 105 cfg = get_config() 106 if (index_url := cfg.pip.index_url): 107 cmd.extend(['--index-url', index_url])
Given a uv
command (list of arguments), if the globally configured index_url
is set, adds a corresponding --index-url
argument, in-place.