Skip to content

models

Pyproject models.

RustConfig

Bases: BaseModel

Rust configuration model.

Source code in src/somesy/rust/models.py
 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
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
class RustConfig(BaseModel):
    """Rust configuration model."""

    model_config = dict(use_enum_values=True)

    name: Annotated[
        str,
        Field(
            pattern=r"^[A-Za-z0-9]+([_-][A-Za-z0-9]+)*$",
            max_length=64,
            description="Package name",
        ),
    ]
    version: Annotated[
        str,
        Field(
            pattern=r"^\d+(\.\d+)*((a|b|rc)\d+)?(post\d+)?(dev\d+)?$",
            description="Package version",
        ),
    ]
    description: Annotated[
        Optional[str], Field(description="Package description")
    ] = None
    license: Annotated[
        Optional[str],
        Field(
            description="A combination SPDX license identifiers with AND, OR and so on."
        ),
    ] = None
    authors: Annotated[Set[str], Field(description="Package authors")]
    maintainers: Annotated[
        Optional[Set[str]], Field(description="Package maintainers")
    ] = None
    readme: Annotated[
        Optional[Union[Path, List[Path]]], Field(description="Package readme file(s)")
    ] = None
    license_file: Annotated[
        Optional[Path], Field(description="Package license file")
    ] = None
    homepage: Annotated[
        Optional[HttpUrlStr], Field(description="Package homepage")
    ] = None
    repository: Annotated[
        Optional[HttpUrlStr], Field(description="Package repository")
    ] = None
    documentation: Annotated[
        Optional[HttpUrlStr], Field(description="Package documentation page")
    ] = None
    keywords: Annotated[
        Optional[Set[str]], Field(description="Keywords that describe the package")
    ] = None
    classifiers: Annotated[
        Optional[List[str]], Field(description="pypi classifiers")
    ] = None
    urls: Annotated[
        Optional[Dict[str, HttpUrlStr]], Field(description="Package URLs")
    ] = None

    @model_validator(mode="before")
    @classmethod
    def license_or_file(cls, values):
        """License and license file are mutually exclusive."""
        if "license" in values and "license_file" in values:
            raise ValueError("license and license_file are mutually exclusive")
        return values

    @field_validator("version")
    @classmethod
    def validate_version(cls, v):
        """Validate version using PEP 440."""
        try:
            _ = parse_version(v)
        except ValueError as err:
            raise ValueError("Invalid version") from err
        return v

    @field_validator("readme", "license_file")
    @classmethod
    def validate_readme(cls, v):
        """Validate readme file(s) by checking whether files exist."""
        if isinstance(v, list):
            if any(not e.is_file() for e in v):
                raise ValueError("Some file(s) do not exist")
        else:
            if not v.is_file():
                raise ValueError("File does not exist")

    @field_validator("keywords")
    @classmethod
    def check_keywords_field(cls, v):
        """Check the keywords field."""
        if v is None:
            return v

        # Check if number of keywords is at most 5
        if v is not None and len(v) > 5:
            raise ValueError("A maximum of 5 keywords is allowed")

        for keyword in v:
            check_keyword(keyword)

        return v

license_or_file classmethod

license_or_file(values)

License and license file are mutually exclusive.

Source code in src/somesy/rust/models.py
71
72
73
74
75
76
77
@model_validator(mode="before")
@classmethod
def license_or_file(cls, values):
    """License and license file are mutually exclusive."""
    if "license" in values and "license_file" in values:
        raise ValueError("license and license_file are mutually exclusive")
    return values

validate_version classmethod

validate_version(v)

Validate version using PEP 440.

Source code in src/somesy/rust/models.py
79
80
81
82
83
84
85
86
87
@field_validator("version")
@classmethod
def validate_version(cls, v):
    """Validate version using PEP 440."""
    try:
        _ = parse_version(v)
    except ValueError as err:
        raise ValueError("Invalid version") from err
    return v

validate_readme classmethod

validate_readme(v)

Validate readme file(s) by checking whether files exist.

Source code in src/somesy/rust/models.py
89
90
91
92
93
94
95
96
97
98
@field_validator("readme", "license_file")
@classmethod
def validate_readme(cls, v):
    """Validate readme file(s) by checking whether files exist."""
    if isinstance(v, list):
        if any(not e.is_file() for e in v):
            raise ValueError("Some file(s) do not exist")
    else:
        if not v.is_file():
            raise ValueError("File does not exist")

check_keywords_field classmethod

check_keywords_field(v)

Check the keywords field.

Source code in src/somesy/rust/models.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
@field_validator("keywords")
@classmethod
def check_keywords_field(cls, v):
    """Check the keywords field."""
    if v is None:
        return v

    # Check if number of keywords is at most 5
    if v is not None and len(v) > 5:
        raise ValueError("A maximum of 5 keywords is allowed")

    for keyword in v:
        check_keyword(keyword)

    return v

check_keyword

check_keyword(keyword: str)

Check if keyword is valid.

Source code in src/somesy/rust/models.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def check_keyword(keyword: str):
    """Check if keyword is valid."""
    # Check if keyword is ASCII and has at most 20 characters
    if not keyword.isascii() or len(keyword) > 20:
        raise ValueError(
            "Each keyword must be ASCII text and have at most 20 characters"
        )

    # Check if keyword starts with an alphanumeric character
    if not re.match(r"^[a-zA-Z0-9]", keyword):
        raise ValueError("Each keyword must start with an alphanumeric character")

    # Check if keyword contains only allowed characters
    if not re.match(r"^[a-zA-Z0-9_\-+]+$", keyword):
        raise ValueError("Keywords can only contain letters, numbers, _, -, or +")