Skip to content

harbor_cli.models

Models used by various modules.

Defined here to avoid circular imports when using these models in multiple modules that otherwise can't mutually import each other. Refactor to module (directory with init.py) if needed.

Classes

BaseModel

Bases: BaseModel

Source code in harbor_cli/models.py
class BaseModel(HarborAPIBaseModel):
    pass

ParamSummary

Bases: BaseModel

Serializable representation of a click.Parameter.

Source code in harbor_cli/models.py
class ParamSummary(BaseModel):
    """Serializable representation of a click.Parameter."""

    allow_from_autoenv: Optional[bool] = None
    confirmation_prompt: Optional[bool] = None
    choices: Optional[List[str]] = None
    count: Optional[bool] = None
    default: Optional[Any] = None
    envvar: Optional[str]
    expose_value: bool
    flag_value: Optional[Any] = None
    help: str
    hidden: Optional[bool] = None
    human_readable_name: str
    is_argument: bool
    is_eager: bool = False
    is_bool_flag: Optional[bool] = None
    is_flag: Optional[bool] = None
    is_option: Optional[bool]
    max: Optional[int] = None
    min: Optional[int] = None
    metavar: Optional[str]
    multiple: bool
    name: Optional[str]
    nargs: int
    opts: List[str]
    prompt: Optional[str] = None
    prompt_required: Optional[bool] = None
    required: bool
    secondary_opts: List[str] = []
    show_choices: Optional[bool] = None
    show_default: Optional[bool] = None
    show_envvar: Optional[bool] = None
    type: str
    value_from_envvar: Any

    @classmethod
    def from_param(cls, param: Parameter) -> ParamSummary:
        """Construct a new ParamSummary from a click.Parameter."""
        try:
            help_ = param.help or ""  # type: ignore
        except AttributeError:
            help_ = ""

        is_argument = isinstance(param, (Argument, TyperArgument))
        return cls(
            allow_from_autoenv=get(param, "allow_from_autoenv"),
            confirmation_prompt=get(param, "confirmation_prompt"),
            count=get(param, "count"),
            choices=get(param.type, "choices"),
            default=param.default,
            envvar=param.envvar,  # TODO: support list of envvars
            expose_value=param.expose_value,
            flag_value=get(param, "flag_value"),
            help=help_,
            hidden=get(param, "hidden"),
            human_readable_name=param.human_readable_name,
            is_argument=is_argument,
            is_bool_flag=get(param, "is_bool_flag"),
            is_eager=param.is_eager,
            is_flag=get(param, "is_flag"),
            is_option=get(param, "is_option"),
            max=get(param.type, "max"),
            min=get(param.type, "min"),
            metavar=param.metavar,
            multiple=param.multiple,
            name=param.name,
            nargs=param.nargs,
            opts=param.opts,
            prompt=get(param, "prompt"),
            prompt_required=get(param, "prompt_required"),
            required=param.required,
            secondary_opts=param.secondary_opts,
            show_choices=get(param, "show_choices"),
            show_default=get(param, "show_default"),
            show_envvar=get(param, "show_envvar"),
            type=param.type.name,
            value_from_envvar=param.value_from_envvar,
        )

    @property
    def help_plain(self) -> str:
        return markup_as_plain_text(self.help)

    @property
    def help_md(self) -> str:
        return markup_to_markdown(self.help)

    @model_validator(mode="before")
    def _fmt_metavar(cls, data: dict[str, Any]) -> dict[str, Any]:
        metavar = data.get("metavar") or data.get("human_readable_name", "")
        assert isinstance(metavar, str)
        metavar = metavar.upper()
        if data.get("multiple"):
            new_metavar = f"<{metavar},[{metavar}...]>"
        else:
            new_metavar = f"<{metavar}>"
        data["metavar"] = new_metavar
        return data

Attributes

allow_from_autoenv: Optional[bool] = None class-attribute instance-attribute
confirmation_prompt: Optional[bool] = None class-attribute instance-attribute
choices: Optional[List[str]] = None class-attribute instance-attribute
count: Optional[bool] = None class-attribute instance-attribute
default: Optional[Any] = None class-attribute instance-attribute
envvar: Optional[str] instance-attribute
expose_value: bool instance-attribute
flag_value: Optional[Any] = None class-attribute instance-attribute
help: str instance-attribute
hidden: Optional[bool] = None class-attribute instance-attribute
human_readable_name: str instance-attribute
is_argument: bool instance-attribute
is_eager: bool = False class-attribute instance-attribute
is_bool_flag: Optional[bool] = None class-attribute instance-attribute
is_flag: Optional[bool] = None class-attribute instance-attribute
is_option: Optional[bool] instance-attribute
max: Optional[int] = None class-attribute instance-attribute
min: Optional[int] = None class-attribute instance-attribute
metavar: Optional[str] instance-attribute
multiple: bool instance-attribute
name: Optional[str] instance-attribute
nargs: int instance-attribute
opts: List[str] instance-attribute
prompt: Optional[str] = None class-attribute instance-attribute
prompt_required: Optional[bool] = None class-attribute instance-attribute
required: bool instance-attribute
secondary_opts: List[str] = [] class-attribute instance-attribute
show_choices: Optional[bool] = None class-attribute instance-attribute
show_default: Optional[bool] = None class-attribute instance-attribute
show_envvar: Optional[bool] = None class-attribute instance-attribute
type: str instance-attribute
value_from_envvar: Any instance-attribute
help_plain: str property
help_md: str property

Functions

from_param(param: Parameter) -> ParamSummary classmethod

Construct a new ParamSummary from a click.Parameter.

Source code in harbor_cli/models.py
@classmethod
def from_param(cls, param: Parameter) -> ParamSummary:
    """Construct a new ParamSummary from a click.Parameter."""
    try:
        help_ = param.help or ""  # type: ignore
    except AttributeError:
        help_ = ""

    is_argument = isinstance(param, (Argument, TyperArgument))
    return cls(
        allow_from_autoenv=get(param, "allow_from_autoenv"),
        confirmation_prompt=get(param, "confirmation_prompt"),
        count=get(param, "count"),
        choices=get(param.type, "choices"),
        default=param.default,
        envvar=param.envvar,  # TODO: support list of envvars
        expose_value=param.expose_value,
        flag_value=get(param, "flag_value"),
        help=help_,
        hidden=get(param, "hidden"),
        human_readable_name=param.human_readable_name,
        is_argument=is_argument,
        is_bool_flag=get(param, "is_bool_flag"),
        is_eager=param.is_eager,
        is_flag=get(param, "is_flag"),
        is_option=get(param, "is_option"),
        max=get(param.type, "max"),
        min=get(param.type, "min"),
        metavar=param.metavar,
        multiple=param.multiple,
        name=param.name,
        nargs=param.nargs,
        opts=param.opts,
        prompt=get(param, "prompt"),
        prompt_required=get(param, "prompt_required"),
        required=param.required,
        secondary_opts=param.secondary_opts,
        show_choices=get(param, "show_choices"),
        show_default=get(param, "show_default"),
        show_envvar=get(param, "show_envvar"),
        type=param.type.name,
        value_from_envvar=param.value_from_envvar,
    )

CommandSummary

Bases: BaseModel

Convenience class for accessing information about a command.

Source code in harbor_cli/models.py
class CommandSummary(BaseModel):
    """Convenience class for accessing information about a command."""

    category: Optional[str] = None  # not part of TyperCommand
    deprecated: bool
    epilog: Optional[str]
    help: str
    hidden: bool
    name: str
    options_metavar: str
    params: List[ParamSummary] = []
    score: int = 0  # match score (not part of TyperCommand)
    short_help: Optional[str]

    @classmethod
    def from_command(
        cls, command: TyperCommand, name: str | None = None, category: str | None = None
    ) -> CommandSummary:
        """Construct a new CommandSummary from a TyperCommand."""
        return cls(
            category=category,
            deprecated=command.deprecated,
            epilog=command.epilog or "",
            help=command.help or "",
            hidden=command.hidden,
            name=name or command.name or "",
            options_metavar=command.options_metavar or "",
            params=[ParamSummary.from_param(p) for p in command.params],
            short_help=command.short_help or "",
        )

    @property
    def help_plain(self) -> str:
        return markup_as_plain_text(self.help)

    @property
    def help_md(self) -> str:
        return markup_to_markdown(self.help)

    @property
    def usage(self) -> str:
        parts = [self.name]

        # Assume arg list is sorted by required/optional
        # `<POSITIONAL_ARG1> <POSITIONAL_ARG2> [OPTIONAL_ARG1] [OPTIONAL_ARG2]`
        for arg in self.arguments:
            metavar = arg.metavar or arg.human_readable_name
            parts.append(metavar)

        # Command with both required and optional options:
        # `--option1 <opt1> --option2 <opt2> [OPTIONS]`
        has_optional = False
        for option in self.options:
            if option.required:
                metavar = option.metavar or option.human_readable_name
                if option.opts:
                    s = f"{max(option.opts)} {metavar}"
                else:
                    # this shouldn't happen, but just in case. A required
                    # option without any opts is not very useful.
                    # NOTE: could raise exception here instead
                    s = metavar
                parts.append(s)
            else:
                has_optional = True
        if has_optional:
            parts.append("[OPTIONS]")

        return " ".join(parts)

    @property
    def options(self) -> List[ParamSummary]:
        return [p for p in self.params if not p.is_argument]

    @property
    def arguments(self) -> List[ParamSummary]:
        return [p for p in self.params if p.is_argument]

Attributes

category: Optional[str] = None class-attribute instance-attribute
deprecated: bool instance-attribute
epilog: Optional[str] instance-attribute
help: str instance-attribute
hidden: bool instance-attribute
name: str instance-attribute
options_metavar: str instance-attribute
params: List[ParamSummary] = [] class-attribute instance-attribute
score: int = 0 class-attribute instance-attribute
short_help: Optional[str] instance-attribute
help_plain: str property
help_md: str property
usage: str property
options: List[ParamSummary] property
arguments: List[ParamSummary] property

Functions

from_command(command: TyperCommand, name: str | None = None, category: str | None = None) -> CommandSummary classmethod

Construct a new CommandSummary from a TyperCommand.

Source code in harbor_cli/models.py
@classmethod
def from_command(
    cls, command: TyperCommand, name: str | None = None, category: str | None = None
) -> CommandSummary:
    """Construct a new CommandSummary from a TyperCommand."""
    return cls(
        category=category,
        deprecated=command.deprecated,
        epilog=command.epilog or "",
        help=command.help or "",
        hidden=command.hidden,
        name=name or command.name or "",
        options_metavar=command.options_metavar or "",
        params=[ParamSummary.from_param(p) for p in command.params],
        short_help=command.short_help or "",
    )

ProjectExtended

Bases: Project

Signal to the render function that we want to print extended information about a project.

Source code in harbor_cli/models.py
class ProjectExtended(Project):
    """Signal to the render function that we want to print extended information about a project."""

    pass

Operator

Bases: Enum

Operator used to detmerine matching of multiple search criteria.

Source code in harbor_cli/models.py
class Operator(Enum):
    """Operator used to detmerine matching of multiple search criteria."""

    AND = "and"
    OR = "or"
    XOR = "xor"

Attributes

AND = 'and' class-attribute instance-attribute
OR = 'or' class-attribute instance-attribute
XOR = 'xor' class-attribute instance-attribute

UserGroupType

Bases: StrEnum

Source code in harbor_cli/models.py
class UserGroupType(StrEnum):
    LDAP = "LDAP"
    HTTP = "HTTP"
    OIDC = "OIDC"

    @classmethod
    def from_int(cls, value: int) -> str:
        try:
            return _USERGROUPTYPE_MAPPING[value]
        except KeyError:
            raise ValueError(f"Invalid user group type: {value}")

    def as_int(self) -> int:
        try:
            return _USERGROUPTYPE_MAPPING_REVERSE[self]
        except KeyError:
            raise ValueError(f"Unknown user group type: {self}")

Attributes

LDAP = 'LDAP' class-attribute instance-attribute
HTTP = 'HTTP' class-attribute instance-attribute
OIDC = 'OIDC' class-attribute instance-attribute

Functions

from_int(value: int) -> str classmethod
Source code in harbor_cli/models.py
@classmethod
def from_int(cls, value: int) -> str:
    try:
        return _USERGROUPTYPE_MAPPING[value]
    except KeyError:
        raise ValueError(f"Invalid user group type: {value}")
as_int() -> int
Source code in harbor_cli/models.py
def as_int(self) -> int:
    try:
        return _USERGROUPTYPE_MAPPING_REVERSE[self]
    except KeyError:
        raise ValueError(f"Unknown user group type: {self}")

MemberRoleType

Bases: Enum

Source code in harbor_cli/models.py
class MemberRoleType(Enum):
    ADMIN = "admin"
    DEVELOPER = "developer"
    GUEST = "guest"
    MAINTAINER = "maintainer"
    LIMITED_GUEST = "limited_guest"

    @classmethod
    def from_int(cls, value: int) -> MemberRoleType:
        try:
            return _MEMBERROLETYPE_MAPPING[value]
        except KeyError:
            raise ValueError(f"Unknown role type: {value}")

    def as_int(self) -> int:
        try:
            return _MEMBERROLETYPE_MAPPING_REVERSE[self]
        except KeyError:
            raise ValueError(f"Unknown role type: {self}")

Attributes

ADMIN = 'admin' class-attribute instance-attribute
DEVELOPER = 'developer' class-attribute instance-attribute
GUEST = 'guest' class-attribute instance-attribute
MAINTAINER = 'maintainer' class-attribute instance-attribute
LIMITED_GUEST = 'limited_guest' class-attribute instance-attribute

Functions

from_int(value: int) -> MemberRoleType classmethod
Source code in harbor_cli/models.py
@classmethod
def from_int(cls, value: int) -> MemberRoleType:
    try:
        return _MEMBERROLETYPE_MAPPING[value]
    except KeyError:
        raise ValueError(f"Unknown role type: {value}")
as_int() -> int
Source code in harbor_cli/models.py
def as_int(self) -> int:
    try:
        return _MEMBERROLETYPE_MAPPING_REVERSE[self]
    except KeyError:
        raise ValueError(f"Unknown role type: {self}")

ArtifactVulnerabilitySummary

Bases: BaseModel

Source code in harbor_cli/models.py
class ArtifactVulnerabilitySummary(BaseModel):
    artifact: str
    tags: List[str]
    summary: Optional[NativeReportSummary]
    # Not a property since we don't keep the original artifact around
    artifact_short: str = Field(..., exclude=True)

    @classmethod
    def from_artifactinfo(cls, artifact: ArtifactInfo) -> ArtifactVulnerabilitySummary:
        return cls(
            artifact=artifact.name_with_digest_full,
            artifact_short=artifact.name_with_digest,
            tags=artifact.tags,
            summary=artifact.artifact.scan,
        )

Attributes

artifact: str instance-attribute
tags: List[str] instance-attribute
summary: Optional[NativeReportSummary] instance-attribute
artifact_short: str = Field(..., exclude=True) class-attribute instance-attribute

Functions

from_artifactinfo(artifact: ArtifactInfo) -> ArtifactVulnerabilitySummary classmethod
Source code in harbor_cli/models.py
@classmethod
def from_artifactinfo(cls, artifact: ArtifactInfo) -> ArtifactVulnerabilitySummary:
    return cls(
        artifact=artifact.name_with_digest_full,
        artifact_short=artifact.name_with_digest,
        tags=artifact.tags,
        summary=artifact.artifact.scan,
    )

MetadataFields

Bases: RootModel

Renders a mapping of one or more metadata fields as a table.

Source code in harbor_cli/models.py
class MetadataFields(RootModel):
    """Renders a mapping of one or more metadata fields as a table."""

    root: Dict[str, Any]

    def as_table(self, **kwargs: Any) -> Iterable[Table]:  # type: ignore
        from .output.table._utils import get_table

        table = get_table(
            "Metadata Field",
            columns=["Field", "Value"],
            data=list(self.root),
        )
        for k, v in self.root.items():
            table.add_row(k, str(v))
        yield table

Attributes

root: Dict[str, Any] instance-attribute

Functions

as_table(**kwargs: Any) -> Iterable[Table]
Source code in harbor_cli/models.py
def as_table(self, **kwargs: Any) -> Iterable[Table]:  # type: ignore
    from .output.table._utils import get_table

    table = get_table(
        "Metadata Field",
        columns=["Field", "Value"],
        data=list(self.root),
    )
    for k, v in self.root.items():
        table.add_row(k, str(v))
    yield table

ProjectCreateResult

Bases: BaseModel

Source code in harbor_cli/models.py
class ProjectCreateResult(BaseModel):
    location: str
    project: ProjectReq

Attributes

location: str instance-attribute
project: ProjectReq instance-attribute

Functions

get(param: Any, attr: str) -> Any

Source code in harbor_cli/models.py
def get(param: Any, attr: str) -> Any:
    return getattr(param, attr, None)