lpip.models

src/lpip/models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"""Domain models for config, catalog entries, and pip requirements."""

from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum
from pathlib import Path


class SourceType(StrEnum):
    FILE = "file"
    GIT = "git"


class RefreshMode(StrEnum):
    ALWAYS = "always"
    AUTO = "auto"
    NEVER = "never"


@dataclass(frozen=True)
class PackageSource:
    """One [packages.<name>] record (ADR-0010, ADR-0011)."""

    name: str
    url: str
    revision: str | None = None
    subdirectory: str | None = None
    catalog_source: str | None = None


@dataclass(frozen=True)
class SourceConfig:
    type: SourceType
    path: str
    url: str | None = None
    revision: str | None = None
    refresh: RefreshMode | None = None
    name: str = "default"


@dataclass(frozen=True)
class PolicyConfig:
    allowed_schemes: tuple[str, ...] = ("git+ssh", "git+https")
    require_pinned_revision: bool = False


@dataclass(frozen=True)
class RuntimeConfig:
    python: str = "python3"


@dataclass(frozen=True)
class EffectiveConfig:
    """Merged config after CLI / env / files / defaults."""

    sources: tuple[SourceConfig, ...]
    policy: PolicyConfig
    runtime: RuntimeConfig
    config_path: Path | None = None

    @property
    def source(self) -> SourceConfig:
        """First source (legacy `[source]` / env overlay)."""
        return self.sources[0]


@dataclass(frozen=True)
class RenderedRequirement:
    """Pip direct-URL requirement string for one package (AC-0006)."""

    package: str
    text: str