Skip to content

muxtools.config

Project configuration discovery and editing.

BinaryMode module-attribute

BinaryMode = Literal['local', 'global', 'system']

BinarySettings pydantic-model

BinarySettings(*, prefer: BinaryMode = 'system', packages: list[str] = list(), **kwargs)

Bases: BaseModel

Show JSON schema:
{
  "additionalProperties": true,
  "properties": {
    "prefer": {
      "default": "system",
      "enum": [
        "local",
        "global",
        "system"
      ],
      "title": "Prefer",
      "type": "string"
    },
    "packages": {
      "items": {
        "type": "string"
      },
      "title": "Packages",
      "type": "array"
    }
  },
  "title": "BinarySettings",
  "type": "object"
}

Config:

  • extra: allow
  • strict: True

Fields:

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', strict=True)

prefer pydantic-field

prefer: BinaryMode = 'system'

packages pydantic-field

packages: list[str] = list()

MuxSettings pydantic-model

MuxSettings(*, show_name: str = 'Example', clean_work_dirs: bool = False, out_dir: str = 'premux', out_name: str = '$show$ - $ep$ (premux)', mkv_title_naming: str = '$show$ - $ep$', debug: bool = True, error_on_danger: bool = False, **kwargs)

Bases: BaseModel

Show JSON schema:
{
  "additionalProperties": true,
  "properties": {
    "show_name": {
      "default": "Example",
      "title": "Show Name",
      "type": "string"
    },
    "clean_work_dirs": {
      "default": false,
      "title": "Clean Work Dirs",
      "type": "boolean"
    },
    "out_dir": {
      "default": "premux",
      "title": "Out Dir",
      "type": "string"
    },
    "out_name": {
      "default": "$show$ - $ep$ (premux)",
      "title": "Out Name",
      "type": "string"
    },
    "mkv_title_naming": {
      "default": "$show$ - $ep$",
      "title": "Mkv Title Naming",
      "type": "string"
    },
    "debug": {
      "default": true,
      "title": "Debug",
      "type": "boolean"
    },
    "error_on_danger": {
      "default": false,
      "title": "Error On Danger",
      "type": "boolean"
    }
  },
  "title": "MuxSettings",
  "type": "object"
}

Config:

  • extra: allow
  • strict: True

Fields:

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', strict=True)

show_name pydantic-field

show_name: str = 'Example'

clean_work_dirs pydantic-field

clean_work_dirs: bool = False

out_dir pydantic-field

out_dir: str = 'premux'

out_name pydantic-field

out_name: str = '$show$ - $ep$ (premux)'

mkv_title_naming pydantic-field

mkv_title_naming: str = '$show$ - $ep$'

debug pydantic-field

debug: bool = True

error_on_danger pydantic-field

error_on_danger: bool = False

ProjectSettings pydantic-model

ProjectSettings(*, show_name: str = 'Example', clean_work_dirs: bool = False, out_dir: str = 'premux', out_name: str = '$show$ - $ep$ (premux)', mkv_title_naming: str = '$show$ - $ep$', debug: bool = True, error_on_danger: bool = False, binaries: BinarySettings = BinarySettings())

Bases: MuxSettings

Show JSON schema:
{
  "$defs": {
    "BinarySettings": {
      "additionalProperties": true,
      "properties": {
        "prefer": {
          "default": "system",
          "enum": [
            "local",
            "global",
            "system"
          ],
          "title": "Prefer",
          "type": "string"
        },
        "packages": {
          "items": {
            "type": "string"
          },
          "title": "Packages",
          "type": "array"
        }
      },
      "title": "BinarySettings",
      "type": "object"
    }
  },
  "additionalProperties": true,
  "properties": {
    "show_name": {
      "default": "Example",
      "title": "Show Name",
      "type": "string"
    },
    "clean_work_dirs": {
      "default": false,
      "title": "Clean Work Dirs",
      "type": "boolean"
    },
    "out_dir": {
      "default": "premux",
      "title": "Out Dir",
      "type": "string"
    },
    "out_name": {
      "default": "$show$ - $ep$ (premux)",
      "title": "Out Name",
      "type": "string"
    },
    "mkv_title_naming": {
      "default": "$show$ - $ep$",
      "title": "Mkv Title Naming",
      "type": "string"
    },
    "debug": {
      "default": true,
      "title": "Debug",
      "type": "boolean"
    },
    "error_on_danger": {
      "default": false,
      "title": "Error On Danger",
      "type": "boolean"
    },
    "binaries": {
      "$ref": "#/$defs/BinarySettings"
    }
  },
  "title": "ProjectSettings",
  "type": "object"
}

Fields:

Validators:

binaries pydantic-field

binaries: BinarySettings = BinarySettings()

reject_runtime_fields pydantic-validator

reject_runtime_fields(value: Any) -> Any
Source code in muxtools/config.py
@model_validator(mode="before")
@classmethod
def reject_runtime_fields(cls, value: Any) -> Any:
    if isinstance(value, dict) and "work_dir" in value:
        raise ValueError("work_dir is runtime-only; pass it to Setup")
    return value

ProjectConfig dataclass

ProjectConfig(path: Path, settings: ProjectSettings)
Source code in muxtools/config.py
@dataclass(frozen=True)
class ProjectConfig:
    path: Path
    settings: ProjectSettings

    @property
    def root(self) -> Path:
        return self.path.parent

    @property
    def mode(self) -> BinaryMode:
        return self.settings.binaries.prefer

    @property
    def packages(self) -> list[str]:
        return self.settings.binaries.packages

path instance-attribute

path: Path

settings instance-attribute

settings: ProjectSettings

root property

root: Path

mode property

mode: BinaryMode

packages property

packages: list[str]

EffectiveBinaryConfig dataclass

EffectiveBinaryConfig(mode: BinaryMode, packages: list[str], project_config: ProjectConfig | None = None)
Source code in muxtools/config.py
@dataclass(frozen=True)
class EffectiveBinaryConfig:
    mode: BinaryMode
    packages: list[str]
    project_config: ProjectConfig | None = None

mode instance-attribute

mode: BinaryMode

packages instance-attribute

packages: list[str]

project_config class-attribute instance-attribute

project_config: ProjectConfig | None = None

global_binary_path

global_binary_path() -> Path
Source code in muxtools/config.py
def global_binary_path() -> Path:
    value = os.environ.get("MUXTOOLS_BINARIES_GLOBAL_PATH", "")
    return Path(value) if value else user_data_path("muxtools", appauthor=False) / "bins"

resolve_binary_config

resolve_binary_config(project_config: ProjectConfig | None) -> EffectiveBinaryConfig | None
Source code in muxtools/config.py
def resolve_binary_config(project_config: ProjectConfig | None) -> EffectiveBinaryConfig | None:
    if project_config is not None:
        return EffectiveBinaryConfig(project_config.mode, list(project_config.packages), project_config)
    if not _environment_boolean("MUXTOOLS_BINARIES_MANAGED_GLOBAL"):
        return None
    packages = [value.strip() for value in os.environ.get("MUXTOOLS_BINARIES_PACKAGES", "").split(",") if value.strip()]
    return EffectiveBinaryConfig("global", packages)

load_config

load_config(path: Path) -> ProjectConfig
Source code in muxtools/config.py
def load_config(path: Path) -> ProjectConfig:
    path = path.resolve()
    doc = _read(path)
    node: Any = doc
    for part in _section(path):
        if part not in node:
            raise ValueError(f"No muxtools configuration in {path}")
        node = node[part]
    return ProjectConfig(path, ProjectSettings.model_validate(node.unwrap()))

discover_config

discover_config(start: Path | None = None, explicit: Path | None = None) -> ProjectConfig | None
Source code in muxtools/config.py
def discover_config(start: Path | None = None, explicit: Path | None = None) -> ProjectConfig | None:
    if explicit is not None:
        return load_config(explicit)
    directory = (start or Path.cwd()).resolve()
    if directory.is_file():
        directory = directory.parent
    for parent in (directory, *directory.parents):
        matches = []
        for name in ("pyproject.toml", "muxtools.toml"):
            path = parent / name
            if path.exists():
                doc = _read(path)
                node: Any = doc
                found = True
                for part in _section(path):
                    if part not in node:
                        found = False
                        break
                    node = node[part]
                if found:
                    matches.append(path)
        if len(matches) > 1:
            raise ValueError(f"Ambiguous muxtools configuration in {parent}; select a config explicitly")
        if matches:
            return load_config(matches[0])
    return None

update_config

update_config(path: Path, values: dict[str, Any] | None = None, packages: list[str] | None = None) -> ProjectConfig
Source code in muxtools/config.py
def update_config(path: Path, values: dict[str, Any] | None = None, packages: list[str] | None = None) -> ProjectConfig:
    path = path.resolve()
    doc = _read(path)
    node: Any = doc
    for part in _section(path):
        if part not in node:
            node[part] = tomlkit.table()
        node = node[part]
    for key, value in (values or {}).items():
        if key != "binaries":
            node[key] = value
    if "binaries" not in node:
        node["binaries"] = tomlkit.table()
    binary = node["binaries"]
    for key, value in (values or {}).get("binaries", {}).items():
        binary[key] = value
    if packages is not None:
        binary["packages"] = packages
    settings = ProjectSettings.model_validate(node.unwrap())
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(tomlkit.dumps(doc), encoding="utf-8")
    return ProjectConfig(path, settings)

init_config

init_config(path: Path, mode: BinaryMode = 'local') -> ProjectConfig
Source code in muxtools/config.py
def init_config(path: Path, mode: BinaryMode = "local") -> ProjectConfig:
    if path.exists():
        try:
            return load_config(path)
        except ValidationError:
            raise
        except ValueError:
            pass
    defaults = ProjectSettings(binaries=BinarySettings(prefer=mode)).model_dump()
    return update_config(path, defaults)

migrate_config

migrate_config(source: Path, destination: Path) -> ProjectConfig
Source code in muxtools/config.py
def migrate_config(source: Path, destination: Path) -> ProjectConfig:
    from configparser import ConfigParser

    parser = ConfigParser()
    if not parser.read(source, encoding="utf-8") or not parser.has_section("SETUP"):
        raise ValueError(f"No [SETUP] section in {source}")
    if destination.exists():
        try:
            load_config(destination)
        except ValidationError:
            raise
        except ValueError:
            pass
        else:
            raise ValueError(f"muxtools configuration already exists in {destination}")
    settings = parser["SETUP"]
    booleans = {"clean_work_dirs", "debug", "error_on_danger"}
    excluded = {"work_dir", "allow_binary_download", "binaries"}
    values: dict[str, Any] = {key: settings.getboolean(key) if key in booleans else settings[key] for key in settings if key not in excluded}
    values["binaries"] = {"prefer": "local" if settings.getboolean("allow_binary_download", fallback=False) else "system", "packages": []}
    return update_config(destination, values)