Skip to content

omnipy.components.remote.models

CLASS DESCRIPTION
HttpUrlModel
QueryParamsModel
UrlDataclassModel
UrlPathModel

DEFAULT_PORTS module-attribute

DEFAULT_PORTS = {80, 443}

QueryParamsJoinerModel module-attribute

QueryParamsJoinerModel = NestedJoinItemsModel.adjust(
    "QueryParamsJoinerModel", delimiters=("&", "=")
)

QueryParamsSplitterModel module-attribute

QueryParamsSplitterModel = NestedSplitToItemsModel.adjust(
    "QueryParamsSplitterModel", delimiters=("&", "=")
)

AutoResponseContentModel

Bases: Model[ResponseContentPydModel | StrictBytesModel | StrictStrModel | JsonListOrDictModel]

CLASS DESCRIPTION
Config
Source code in src/omnipy/components/remote/models.py
class AutoResponseContentModel(Model[ResponseContentPydModel | StrictBytesModel | StrictStrModel
                                     | JsonListOrDictModel]):
    class Config(Model.Config):
        smart_union = False

    @classmethod
    def _parse_data(  # type: ignore[override]
        cls,
        data: ResponseContentPydModel | StrictBytesModel | StrictStrModel | AnyJsonListOrDictModel
    ) -> StrictBytesModel | StrictStrModel | AnyJsonListOrDictModel:
        if isinstance(data, ResponseContentPydModel):
            assert isinstance(data.content_type, ModelFriendlyMimeType)

            mimetype_tuple = (data.content_type.type, data.content_type.subtype)
            match mimetype_tuple:
                case ('application', 'json'):
                    return JsonListOrDictModel(data.response)
                case ('text', 'plain'):
                    return StrictStrModel(data.response)
                case ('application', 'octet-stream') | _:
                    return StrictBytesModel(data.response)
        else:
            return data

Config

Bases: Model.Config

ATTRIBUTE DESCRIPTION
smart_union

Source code in src/omnipy/components/remote/models.py
class Config(Model.Config):
    smart_union = False

smart_union class-attribute instance-attribute

smart_union = False

HttpUrlModel

Bases: Model[UrlDataclassModel | str]

METHOD DESCRIPTION
to_data
Source code in src/omnipy/components/remote/models.py
class HttpUrlModel(Model[UrlDataclassModel | str]):
    if TYPE_CHECKING:

        def __new__(cls, *args: Any, **kwargs: Any) -> 'HttpUrlModel_UrlDataclassModel':
            ...

    @classmethod
    def _parse_data(cls, data: UrlDataclassModel | str) -> UrlDataclassModel:
        if data == '':
            data = 'http://localhost/'
        if data == 'https://':
            data = 'https://localhost/'
        # For validation only
        url_obj = pyd.Url(str(data) if isinstance(data, UrlDataclassModel) else data)

        parts: dict[str, str | int | None] = {}
        for key in UrlDataclassModel.__fields__.keys():
            match key:
                case 'scheme':
                    val = url_obj.scheme
                    assert val in {'http', 'https'}, f'Unsupported scheme: {val}'
                    parts[key] = val
                case 'host':
                    parts[key] = url_obj.unicode_host()
                case 'username' | 'password' | 'path' | 'fragment':
                    val = getattr(url_obj, key)
                    parts[key] = unquote(val) if val is not None else None
                case _:
                    parts[key] = getattr(url_obj, key)

        return UrlDataclassModel(**{
            key: val  # type: ignore[arg-type]
            for key, val in parts.items()
            if val is not None
        })

    def __add__(self, other: str) -> 'HttpUrlModel':
        return HttpUrlModel(str(self) + other)

    def to_data(self) -> str:
        return str(self.content)

    def __str__(self) -> str:
        return str(self.content)

to_data

to_data() -> str
Source code in src/omnipy/components/remote/models.py
def to_data(self) -> str:
    return str(self.content)

HttpUrlModel_UrlDataclassModel

Bases: HttpUrlModel, UrlDataclassModel

Source code in src/omnipy/components/remote/models.py
class HttpUrlModel_UrlDataclassModel(HttpUrlModel, UrlDataclassModel):  # type: ignore[misc]
    ...

ModelFriendlyMimeType

Bases: pyd.BaseModel

ATTRIBUTE DESCRIPTION
parameters

TYPE: tuple[tuple[str, str], ...]

subtype

TYPE: str

suffix

TYPE: str

type

TYPE: str

Source code in src/omnipy/components/remote/models.py
class ModelFriendlyMimeType(pyd.BaseModel):
    type: str
    subtype: str
    suffix: str
    parameters: tuple[tuple[str, str], ...]

parameters instance-attribute

parameters: tuple[tuple[str, str], ...]

subtype instance-attribute

subtype: str

suffix instance-attribute

suffix: str

type instance-attribute

type: str

QueryParamsModel

Bases: Model[dict[str, str] | tuple[tuple[str, str], ...] | tuple[str, ...] | str]

METHOD DESCRIPTION
to_data
Source code in src/omnipy/components/remote/models.py
class QueryParamsModel(Model[dict[str, str] | tuple[tuple[str, str], ...] | tuple[str, ...] | str]):
    if TYPE_CHECKING and TYPE_CHECKER != 'mypy':

        def __new__(cls, *args: Any, **kwargs: Any) -> 'QueryParamsModel_dict':
            ...

    @classmethod
    def _validate_tuple_of_pairs(
            cls, params_list: list[str | list] | str) -> TypeGuard[list[tuple[str, str]]]:
        # The validated type is really a list of lists of two items, but we can't express that with
        # Python type hints, so we use a list of tuple pairs instead.
        return all(isinstance(param, list) and len(param) == 2 for param in params_list)

    @classmethod
    def _parse_data(
        cls, data: dict[str, str] | tuple[tuple[str, str], ...] | tuple[str, ...] | str
    ) -> dict[str, str]:
        if isinstance(data, dict):
            return data

        params_list = QueryParamsSplitterModel(data).content
        assert cls._validate_tuple_of_pairs(params_list), \
            (f'Each parameter must have 2 elements only: [key, value]. '
             f'Incorrect parameter list: {params_list}')

        return dict((unquote(key), unquote(val)) for key, val in params_list)

    def to_data(self) -> str:
        with hold_and_reset_prev_attrib_value(self.config.model,
                                              'dynamically_convert_elements_to_models'):
            self.config.model.dynamically_convert_elements_to_models = False
            assert isinstance(self.content, dict)
            url_encoded_content = tuple(
                (quote(key), quote(val)) for key, val in self.content.items())
            return cast(str, QueryParamsJoinerModel(url_encoded_content).to_data())

    def __str__(self) -> str:
        return self.to_data()

to_data

to_data() -> str
Source code in src/omnipy/components/remote/models.py
def to_data(self) -> str:
    with hold_and_reset_prev_attrib_value(self.config.model,
                                          'dynamically_convert_elements_to_models'):
        self.config.model.dynamically_convert_elements_to_models = False
        assert isinstance(self.content, dict)
        url_encoded_content = tuple(
            (quote(key), quote(val)) for key, val in self.content.items())
        return cast(str, QueryParamsJoinerModel(url_encoded_content).to_data())

QueryParamsModel_dict

Bases: QueryParamsModel, dict

Source code in src/omnipy/components/remote/models.py
class QueryParamsModel_dict(QueryParamsModel, dict):  # type: ignore[misc]
    ...

ResponseContentPydModel

Bases: pyd.BaseModel

CLASS DESCRIPTION
Config
METHOD DESCRIPTION
parse_content_type
ATTRIBUTE DESCRIPTION
content_type

TYPE: ModelFriendlyMimeType | str

response

TYPE: object

Source code in src/omnipy/components/remote/models.py
class ResponseContentPydModel(pyd.BaseModel):
    content_type: ModelFriendlyMimeType | str
    response: object

    class Config:
        arbitrary_types_allowed = True

    @pyd.validator('content_type', allow_reuse=True)
    def parse_content_type(cls, content_type: ModelFriendlyMimeType | str) -> ModelFriendlyMimeType:
        from .lazy_import import MimeType, parse_mimetype

        if isinstance(content_type, ModelFriendlyMimeType):
            return content_type

        mime_type: MimeType = parse_mimetype(content_type)
        return ModelFriendlyMimeType(
            type=mime_type.type,
            subtype=mime_type.subtype,
            suffix=mime_type.suffix,
            parameters=tuple(mime_type.parameters.items()),
        )

content_type instance-attribute

content_type: ModelFriendlyMimeType | str

response instance-attribute

response: object

Config

ATTRIBUTE DESCRIPTION
arbitrary_types_allowed

Source code in src/omnipy/components/remote/models.py
class Config:
    arbitrary_types_allowed = True

arbitrary_types_allowed class-attribute instance-attribute

arbitrary_types_allowed = True

parse_content_type

parse_content_type(content_type: ModelFriendlyMimeType | str) -> ModelFriendlyMimeType
Source code in src/omnipy/components/remote/models.py
@pyd.validator('content_type', allow_reuse=True)
def parse_content_type(cls, content_type: ModelFriendlyMimeType | str) -> ModelFriendlyMimeType:
    from .lazy_import import MimeType, parse_mimetype

    if isinstance(content_type, ModelFriendlyMimeType):
        return content_type

    mime_type: MimeType = parse_mimetype(content_type)
    return ModelFriendlyMimeType(
        type=mime_type.type,
        subtype=mime_type.subtype,
        suffix=mime_type.suffix,
        parameters=tuple(mime_type.parameters.items()),
    )

UrlDataclassModel

Bases: pyd.BaseModel

ATTRIBUTE DESCRIPTION
fragment

TYPE: str | None

host

TYPE: str

password

TYPE: str | None

path

TYPE: UrlPathModel_PurePosixPath

port

TYPE: int | None

query

TYPE: QueryParamsModel_dict

scheme

TYPE: str

username

TYPE: str | None

Source code in src/omnipy/components/remote/models.py
class UrlDataclassModel(pyd.BaseModel):
    # Mutable fields
    scheme: str
    username: str | None = None
    password: str | None = None
    host: str = 'localhost'
    port: int | None = None

    if TYPE_CHECKING:
        path: UrlPathModel_PurePosixPath = pyd.Field(default_factory=UrlPathModel)
        query: QueryParamsModel_dict = pyd.Field(default_factory=QueryParamsModel)

    else:
        path: UrlPathModel = pyd.Field(default_factory=UrlPathModel)
        query: QueryParamsModel = pyd.Field(default_factory=QueryParamsModel)

    fragment: str | None = None

    def __str__(self) -> str:
        kwargs: dict[str, str | int] = {}
        for key, val in self.dict().items():
            if val is None:
                continue
            match key:
                case 'port':
                    if val in DEFAULT_PORTS:
                        continue
                    kwargs[key] = val
                case 'path':
                    # Fix for second problem described in
                    # https://github.com/pydantic/pydantic/issues/7186#issuecomment-1912791497
                    if val != '.':
                        kwargs[key] = val.lstrip('/')
                case 'query':
                    if val:
                        kwargs[key] = str(val)
                case _:
                    kwargs[key] = val

        return str(pyd.Url.build(**kwargs))  # type: ignore[arg-type]

fragment class-attribute instance-attribute

fragment: str | None = None

host class-attribute instance-attribute

host: str = 'localhost'

password class-attribute instance-attribute

password: str | None = None

path class-attribute instance-attribute

port class-attribute instance-attribute

port: int | None = None

query class-attribute instance-attribute

query: QueryParamsModel_dict = pyd.Field(default_factory=QueryParamsModel)

scheme instance-attribute

scheme: str

username class-attribute instance-attribute

username: str | None = None

UrlPathModel

Bases: Model[PurePosixPath | str]

METHOD DESCRIPTION
to_data
Source code in src/omnipy/components/remote/models.py
class UrlPathModel(Model[PurePosixPath | str]):
    if TYPE_CHECKING and TYPE_CHECKER != 'mypy':

        def __new__(cls, *args: Any, **kwargs: Any) -> 'UrlPathModel_PurePosixPath':
            ...

    @classmethod
    def _parse_data(cls, data: PurePosixPath | str) -> PurePosixPath:
        return PurePosixPath(data) if isinstance(data, str) else data

    def to_data(self) -> str:
        return str(self.content)

    def __str__(self) -> str:
        return str(self.content)

    def _slash_operator(self, other: PurePosixPath | str | object) -> PurePosixPath:
        content = cast(PurePosixPath, self.content)
        match other:
            case PurePosixPath() | str():
                return content / other
            case _:
                return content / str(other)

    def __truediv__(self, other: PurePosixPath | str | object) -> 'UrlPathModel_PurePosixPath':
        return UrlPathModel(self._slash_operator(other))

    def __floordiv__(self, other: PurePosixPath | str | object) -> 'UrlPathModel_PurePosixPath':
        self.content = self._slash_operator(other)
        return self  # type: ignore[return-value]

    def __add__(self, other: PurePosixPath | str | object) -> 'UrlPathModel_PurePosixPath':
        return UrlPathModel(str(self) + str(other))

to_data

to_data() -> str
Source code in src/omnipy/components/remote/models.py
def to_data(self) -> str:
    return str(self.content)

UrlPathModel_PurePosixPath

Bases: UrlPathModel, PurePosixPath

Source code in src/omnipy/components/remote/models.py
class UrlPathModel_PurePosixPath(UrlPathModel, PurePosixPath):  # type: ignore[misc]
    ...