/
niceSOFT
/
python3-hatchling
Обзор
Документация
Войти
/
niceSOFT
/
python3-hatchling
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/hatch/config/model.py
789 строк
25 KB
Dimitri Papadopoulos Orfanos
Upgrade Ruff to 0.13.2 (#1890)
28 сен 2025, 21:20
Не верифицирован
28 сен 2025, 21:20
aff6f39
Код
Авторство
О чём код?
import os FIELD_TO_PARSE = object() class ConfigurationError(Exception): def __init__(self, *args, location): self.location = location super().__init__(*args) def __str__(self): return f"Error parsing config:\n{self.location}\n {super().__str__()}" def parse_config(obj): if isinstance(obj, LazilyParsedConfig): obj.parse_fields() elif isinstance(obj, list): for o in obj: parse_config(o) elif isinstance(obj, dict): for o in obj.values(): parse_config(o) class LazilyParsedConfig: def __init__(self, config: dict, steps: tuple = ()): self.raw_data = config self.steps = steps def parse_fields(self): for attribute in self.__dict__: _, prefix, name = attribute.partition("_field_") if prefix: parse_config(getattr(self, name)) def raise_error(self, message, *, extra_steps=()): import inspect field = inspect.currentframe().f_back.f_code.co_name raise ConfigurationError(message, location=" -> ".join([*self.steps, field, *extra_steps])) class RootConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_mode = FIELD_TO_PARSE self._field_project = FIELD_TO_PARSE self._field_shell = FIELD_TO_PARSE self._field_dirs = FIELD_TO_PARSE self._field_projects = FIELD_TO_PARSE self._field_publish = FIELD_TO_PARSE self._field_template = FIELD_TO_PARSE self._field_terminal = FIELD_TO_PARSE @property def mode(self): if self._field_mode is FIELD_TO_PARSE: if "mode" in self.raw_data: mode = self.raw_data["mode"] if not isinstance(mode, str): self.raise_error("must be a string") valid_modes = ("aware", "local", "project") if mode not in valid_modes: self.raise_error(f"must be one of: {', '.join(valid_modes)}") self._field_mode = mode else: self._field_mode = self.raw_data["mode"] = "local" return self._field_mode @mode.setter def mode(self, value): self.raw_data["mode"] = value self._field_mode = FIELD_TO_PARSE @property def project(self): if self._field_project is FIELD_TO_PARSE: if "project" in self.raw_data: project = self.raw_data["project"] if not isinstance(project, str): self.raise_error("must be a string") self._field_project = project else: self._field_project = self.raw_data["project"] = "" return self._field_project @project.setter def project(self, value): self.raw_data["project"] = value self._field_project = FIELD_TO_PARSE @property def shell(self): if self._field_shell is FIELD_TO_PARSE: if "shell" in self.raw_data: shell = self.raw_data["shell"] if isinstance(shell, str): self._field_shell = ShellConfig({"name": shell}, ("shell",)) elif isinstance(shell, dict): self._field_shell = ShellConfig(shell, ("shell",)) else: self.raise_error("must be a string or table") else: self.raw_data["shell"] = "" self._field_shell = ShellConfig({"name": ""}, ("shell",)) return self._field_shell @shell.setter def shell(self, value): self.raw_data["shell"] = value self._field_shell = FIELD_TO_PARSE @property def dirs(self): if self._field_dirs is FIELD_TO_PARSE: if "dirs" in self.raw_data: dirs = self.raw_data["dirs"] if not isinstance(dirs, dict): self.raise_error("must be a table") self._field_dirs = DirsConfig(dirs, ("dirs",)) else: dirs = {} self.raw_data["dirs"] = dirs self._field_dirs = DirsConfig(dirs, ("dirs",)) return self._field_dirs @dirs.setter def dirs(self, value): self.raw_data["dirs"] = value self._field_dirs = FIELD_TO_PARSE @property def projects(self): if self._field_projects is FIELD_TO_PARSE: if "projects" in self.raw_data: projects = self.raw_data["projects"] if not isinstance(projects, dict): self.raise_error("must be a table") project_data = {} for name, data in projects.items(): if isinstance(data, str): project_data[name] = ProjectConfig({"location": data}, ("projects", name)) elif isinstance(data, dict): project_data[name] = ProjectConfig(data, ("projects", name)) else: self.raise_error("must be a string or table", extra_steps=(name,)) self._field_projects = project_data else: self._field_projects = self.raw_data["projects"] = {} return self._field_projects @projects.setter def projects(self, value): self.raw_data["projects"] = value self._field_projects = FIELD_TO_PARSE @property def publish(self): if self._field_publish is FIELD_TO_PARSE: if "publish" in self.raw_data: publish = self.raw_data["publish"] if not isinstance(publish, dict): self.raise_error("must be a table") for name, data in publish.items(): if not isinstance(data, dict): self.raise_error("must be a table", extra_steps=(name,)) self._field_publish = publish else: self._field_publish = self.raw_data["publish"] = {"index": {"repo": "main"}} return self._field_publish @publish.setter def publish(self, value): self.raw_data["publish"] = value self._field_publish = FIELD_TO_PARSE @property def template(self): if self._field_template is FIELD_TO_PARSE: if "template" in self.raw_data: template = self.raw_data["template"] if not isinstance(template, dict): self.raise_error("must be a table") self._field_template = TemplateConfig(template, ("template",)) else: template = {} self.raw_data["template"] = template self._field_template = TemplateConfig(template, ("template",)) return self._field_template @template.setter def template(self, value): self.raw_data["template"] = value self._field_template = FIELD_TO_PARSE @property def terminal(self): if self._field_terminal is FIELD_TO_PARSE: if "terminal" in self.raw_data: terminal = self.raw_data["terminal"] if not isinstance(terminal, dict): self.raise_error("must be a table") self._field_terminal = TerminalConfig(terminal, ("terminal",)) else: terminal = {} self.raw_data["terminal"] = terminal self._field_terminal = TerminalConfig(terminal, ("terminal",)) return self._field_terminal @terminal.setter def terminal(self, value): self.raw_data["terminal"] = value self._field_terminal = FIELD_TO_PARSE class ShellConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_name = FIELD_TO_PARSE self._field_path = FIELD_TO_PARSE self._field_args = FIELD_TO_PARSE @property def name(self): if self._field_name is FIELD_TO_PARSE: if "name" in self.raw_data: name = self.raw_data["name"] if not isinstance(name, str): self.raise_error("must be a string") self._field_name = name else: self.raise_error("required field") return self._field_name @name.setter def name(self, value): self.raw_data["name"] = value self._field_name = FIELD_TO_PARSE @property def path(self): if self._field_path is FIELD_TO_PARSE: if "path" in self.raw_data: path = self.raw_data["path"] if not isinstance(path, str): self.raise_error("must be a string") self._field_path = path else: self._field_path = self.raw_data["path"] = self.name return self._field_path @path.setter def path(self, value): self.raw_data["path"] = value self._field_path = FIELD_TO_PARSE @property def args(self): if self._field_args is FIELD_TO_PARSE: if "args" in self.raw_data: args = self.raw_data["args"] if not isinstance(args, list): self.raise_error("must be an array") for i, entry in enumerate(args, 1): if not isinstance(entry, str): self.raise_error("must be a string", extra_steps=(str(i),)) self._field_args = args else: self._field_args = self.raw_data["args"] = [] return self._field_args @args.setter def args(self, value): self.raw_data["args"] = value self._field_args = FIELD_TO_PARSE class DirsConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_project = FIELD_TO_PARSE self._field_env = FIELD_TO_PARSE self._field_python = FIELD_TO_PARSE self._field_data = FIELD_TO_PARSE self._field_cache = FIELD_TO_PARSE @property def project(self): if self._field_project is FIELD_TO_PARSE: if "project" in self.raw_data: project = self.raw_data["project"] if not isinstance(project, list): self.raise_error("must be an array") for i, entry in enumerate(project, 1): if not isinstance(entry, str): self.raise_error("must be a string", extra_steps=(str(i),)) self._field_project = project else: self._field_project = self.raw_data["project"] = [] return self._field_project @project.setter def project(self, value): self.raw_data["project"] = value self._field_project = FIELD_TO_PARSE @property def env(self): if self._field_env is FIELD_TO_PARSE: if "env" in self.raw_data: env = self.raw_data["env"] if not isinstance(env, dict): self.raise_error("must be a table") for key, value in env.items(): if not isinstance(value, str): self.raise_error("must be a string", extra_steps=(key,)) self._field_env = env else: self._field_env = self.raw_data["env"] = {} return self._field_env @env.setter def env(self, value): self.raw_data["env"] = value self._field_env = FIELD_TO_PARSE @property def python(self): if self._field_python is FIELD_TO_PARSE: if "python" in self.raw_data: python = self.raw_data["python"] if not isinstance(python, str): self.raise_error("must be a string") self._field_python = python else: self._field_python = self.raw_data["python"] = "isolated" return self._field_python @python.setter def python(self, value): self.raw_data["python"] = value self._field_python = FIELD_TO_PARSE @property def data(self): if self._field_data is FIELD_TO_PARSE: if "data" in self.raw_data: data = self.raw_data["data"] if not isinstance(data, str): self.raise_error("must be a string") self._field_data = data else: from platformdirs import user_data_dir self._field_data = self.raw_data["data"] = user_data_dir("hatch", appauthor=False) return self._field_data @data.setter def data(self, value): self.raw_data["data"] = value self._field_data = FIELD_TO_PARSE @property def cache(self): if self._field_cache is FIELD_TO_PARSE: if "cache" in self.raw_data: cache = self.raw_data["cache"] if not isinstance(cache, str): self.raise_error("must be a string") self._field_cache = cache else: from platformdirs import user_cache_dir self._field_cache = self.raw_data["cache"] = user_cache_dir("hatch", appauthor=False) return self._field_cache @cache.setter def cache(self, value): self.raw_data["cache"] = value self._field_cache = FIELD_TO_PARSE class ProjectConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_location = FIELD_TO_PARSE @property def location(self): if self._field_location is FIELD_TO_PARSE: if "location" in self.raw_data: location = self.raw_data["location"] if not isinstance(location, str): self.raise_error("must be a string") self._field_location = location else: self.raise_error("required field") return self._field_location @location.setter def location(self, value): self.raw_data["location"] = value self._field_location = FIELD_TO_PARSE class TemplateConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_name = FIELD_TO_PARSE self._field_email = FIELD_TO_PARSE self._field_licenses = FIELD_TO_PARSE self._field_plugins = FIELD_TO_PARSE @property def name(self): if self._field_name is FIELD_TO_PARSE: if "name" in self.raw_data: name = self.raw_data["name"] if not isinstance(name, str): self.raise_error("must be a string") self._field_name = name else: name = os.environ.get("GIT_AUTHOR_NAME") if name is None: import subprocess try: name = subprocess.check_output( ["git", "config", "--get", "user.name"], # noqa: S607 text=True, ).strip() except Exception: # noqa: BLE001 name = "U.N. Owen" self._field_name = self.raw_data["name"] = name return self._field_name @name.setter def name(self, value): self.raw_data["name"] = value self._field_name = FIELD_TO_PARSE @property def email(self): if self._field_email is FIELD_TO_PARSE: if "email" in self.raw_data: email = self.raw_data["email"] if not isinstance(email, str): self.raise_error("must be a string") self._field_email = email else: email = os.environ.get("GIT_AUTHOR_EMAIL") if email is None: import subprocess try: email = subprocess.check_output( ["git", "config", "--get", "user.email"], # noqa: S607 text=True, ).strip() except Exception: # noqa: BLE001 email = "void@some.where" self._field_email = self.raw_data["email"] = email return self._field_email @email.setter def email(self, value): self.raw_data["email"] = value self._field_email = FIELD_TO_PARSE @property def licenses(self): if self._field_licenses is FIELD_TO_PARSE: if "licenses" in self.raw_data: licenses = self.raw_data["licenses"] if not isinstance(licenses, dict): self.raise_error("must be a table") self._field_licenses = LicensesConfig(licenses, (*self.steps, "licenses")) else: licenses = {} self.raw_data["licenses"] = licenses self._field_licenses = LicensesConfig(licenses, (*self.steps, "licenses")) return self._field_licenses @licenses.setter def licenses(self, value): self.raw_data["licenses"] = value self._field_licenses = FIELD_TO_PARSE @property def plugins(self): if self._field_plugins is FIELD_TO_PARSE: if "plugins" in self.raw_data: plugins = self.raw_data["plugins"] if not isinstance(plugins, dict): self.raise_error("must be a table") for name, data in plugins.items(): if not isinstance(data, dict): self.raise_error("must be a table", extra_steps=(name,)) self._field_plugins = plugins else: self._field_plugins = self.raw_data["plugins"] = { "default": {"tests": True, "ci": False, "src-layout": True} } return self._field_plugins @plugins.setter def plugins(self, value): self.raw_data["plugins"] = value self._field_plugins = FIELD_TO_PARSE class LicensesConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_headers = FIELD_TO_PARSE self._field_default = FIELD_TO_PARSE @property def headers(self): if self._field_headers is FIELD_TO_PARSE: if "headers" in self.raw_data: headers = self.raw_data["headers"] if not isinstance(headers, bool): self.raise_error("must be a boolean") self._field_headers = headers else: self._field_headers = self.raw_data["headers"] = True return self._field_headers @headers.setter def headers(self, value): self.raw_data["headers"] = value self._field_headers = FIELD_TO_PARSE @property def default(self): if self._field_default is FIELD_TO_PARSE: if "default" in self.raw_data: default = self.raw_data["default"] if not isinstance(default, list): self.raise_error("must be an array") for i, entry in enumerate(default, 1): if not isinstance(entry, str): self.raise_error("must be a string", extra_steps=(str(i),)) self._field_default = default else: self._field_default = self.raw_data["default"] = ["MIT"] return self._field_default @default.setter def default(self, value): self.raw_data["default"] = value self._field_default = FIELD_TO_PARSE class TerminalConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_styles = FIELD_TO_PARSE @property def styles(self): if self._field_styles is FIELD_TO_PARSE: if "styles" in self.raw_data: styles = self.raw_data["styles"] if not isinstance(styles, dict): self.raise_error("must be a table") self._field_styles = StylesConfig(styles, (*self.steps, "styles")) else: styles = {} self.raw_data["styles"] = styles self._field_styles = StylesConfig(styles, (*self.steps, "styles")) return self._field_styles @styles.setter def styles(self, value): self.raw_data["styles"] = value self._field_styles = FIELD_TO_PARSE class StylesConfig(LazilyParsedConfig): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._field_info = FIELD_TO_PARSE self._field_success = FIELD_TO_PARSE self._field_error = FIELD_TO_PARSE self._field_warning = FIELD_TO_PARSE self._field_waiting = FIELD_TO_PARSE self._field_debug = FIELD_TO_PARSE self._field_spinner = FIELD_TO_PARSE @property def info(self): if self._field_info is FIELD_TO_PARSE: if "info" in self.raw_data: info = self.raw_data["info"] if not isinstance(info, str): self.raise_error("must be a string") self._field_info = info else: self._field_info = self.raw_data["info"] = "bold" return self._field_info @info.setter def info(self, value): self.raw_data["info"] = value self._field_info = FIELD_TO_PARSE @property def success(self): if self._field_success is FIELD_TO_PARSE: if "success" in self.raw_data: success = self.raw_data["success"] if not isinstance(success, str): self.raise_error("must be a string") self._field_success = success else: self._field_success = self.raw_data["success"] = "bold cyan" return self._field_success @success.setter def success(self, value): self.raw_data["success"] = value self._field_success = FIELD_TO_PARSE @property def error(self): if self._field_error is FIELD_TO_PARSE: if "error" in self.raw_data: error = self.raw_data["error"] if not isinstance(error, str): self.raise_error("must be a string") self._field_error = error else: self._field_error = self.raw_data["error"] = "bold red" return self._field_error @error.setter def error(self, value): self.raw_data["error"] = value self._field_error = FIELD_TO_PARSE @property def warning(self): if self._field_warning is FIELD_TO_PARSE: if "warning" in self.raw_data: warning = self.raw_data["warning"] if not isinstance(warning, str): self.raise_error("must be a string") self._field_warning = warning else: self._field_warning = self.raw_data["warning"] = "bold yellow" return self._field_warning @warning.setter def warning(self, value): self.raw_data["warning"] = value self._field_warning = FIELD_TO_PARSE @property def waiting(self): if self._field_waiting is FIELD_TO_PARSE: if "waiting" in self.raw_data: waiting = self.raw_data["waiting"] if not isinstance(waiting, str): self.raise_error("must be a string") self._field_waiting = waiting else: self._field_waiting = self.raw_data["waiting"] = "bold magenta" return self._field_waiting @waiting.setter def waiting(self, value): self.raw_data["waiting"] = value self._field_waiting = FIELD_TO_PARSE @property def debug(self): if self._field_debug is FIELD_TO_PARSE: if "debug" in self.raw_data: debug = self.raw_data["debug"] if not isinstance(debug, str): self.raise_error("must be a string") self._field_debug = debug else: self._field_debug = self.raw_data["debug"] = "bold" return self._field_debug @debug.setter def debug(self, value): self.raw_data["debug"] = value self._field_debug = FIELD_TO_PARSE @property def spinner(self): if self._field_spinner is FIELD_TO_PARSE: if "spinner" in self.raw_data: spinner = self.raw_data["spinner"] if not isinstance(spinner, str): self.raise_error("must be a string") self._field_spinner = spinner else: self._field_spinner = self.raw_data["spinner"] = "simpleDotsScrolling" return self._field_spinner @spinner.setter def spinner(self, value): self.raw_data["spinner"] = value self._field_spinner = FIELD_TO_PARSE