Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ catalog API schema models moved to models-library #4553

Merged
merged 27 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions packages/models-library/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,30 @@ def read_reqs(reqs_path: Path) -> set[str]:
) # STRICK requirements


SETUP = dict(
name="simcore-models-library",
version=Path(CURRENT_DIR / "VERSION").read_text().strip(),
author="Sylvain Anderegg (sanderegg)",
description="Core service library for simcore pydantic models",
python_requires="~=3.10",
classifiers=[
SETUP = {
"name": "simcore-models-library",
"version": Path(CURRENT_DIR / "VERSION").read_text().strip(),
"author": "Sylvain Anderegg (sanderegg)",
"description": "Core service library for simcore pydantic models",
"python_requires": "~=3.10",
"classifiers": [
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Programming Language :: Python :: 3.10",
],
long_description=Path(CURRENT_DIR / "README.md").read_text(),
license="MIT license",
install_requires=INSTALL_REQUIREMENTS,
packages=find_packages(where="src"),
package_dir={"": "src"},
include_package_data=True,
test_suite="tests",
tests_require=TEST_REQUIREMENTS,
extras_require={"test": TEST_REQUIREMENTS},
zip_safe=False,
)
"long_description": Path(CURRENT_DIR / "README.md").read_text(),
"license": "MIT license",
"install_requires": INSTALL_REQUIREMENTS,
"packages": find_packages(where="src"),
"package_dir": {"": "src"},
"include_package_data": True,
"test_suite": "tests",
"tests_require": TEST_REQUIREMENTS,
"extras_require": {"test": TEST_REQUIREMENTS},
"zip_safe": False,
}


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Any, ClassVar

from pydantic import BaseModel, Field

from ..basic_types import VersionStr


class Meta(BaseModel):
name: str
version: VersionStr
released: dict[str, VersionStr] | None = Field(
None, description="Maps every route's path tag with a released version"
)

class Config:
schema_extra: ClassVar[dict[str, Any]] = {
"example": {
"name": "simcore_service_foo",
"version": "2.4.45",
"released": {"v1": "1.3.4", "v2": "2.4.45"},
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from models_library.users import GroupID
from pydantic import BaseModel

from .services import ServiceKey, ServiceVersion
from ..services import ServiceKey, ServiceVersion
from ..users import GroupID


class ServiceAccessRightsGet(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
from typing import Optional
from typing import Any, ClassVar

from models_library.emails import LowerCaseEmailStr
from models_library.services import ServiceDockerData, ServiceMetaData
from models_library.services_access import ServiceAccessRights
from models_library.services_resources import ServiceResourcesDict
from pydantic import Extra
from pydantic.main import BaseModel

from ..emails import LowerCaseEmailStr
from ..services import ServiceDockerData, ServiceMetaData
from ..services_access import ServiceAccessRights
from ..services_resources import ServiceResourcesDict


# OpenAPI models (contain both service metadata and access rights)
class ServiceUpdate(ServiceMetaData, ServiceAccessRights):
class Config:
schema_extra = {
schema_extra: ClassVar[dict[str, Any]] = {
"example": {
# ServiceAccessRights
"accessRights": {
Expand Down Expand Up @@ -64,16 +63,16 @@ class Config:
class ServiceGet(
ServiceDockerData, ServiceAccessRights, ServiceMetaData
): # pylint: disable=too-many-ancestors
owner: Optional[LowerCaseEmailStr]
owner: LowerCaseEmailStr | None

class Config:
allow_population_by_field_name = True
extra = Extra.ignore
schema_extra = {
schema_extra: ClassVar[dict[str, Any]] = {
"example": {
"name": "File Picker",
"thumbnail": None,
"description": "File Picker",
"description": "description",
"classifiers": [],
"quality": {},
"accessRights": {
Expand Down Expand Up @@ -109,32 +108,4 @@ class Config:
}


# TODO: prototype for next iteration
# Items are non-detailed version of resources listed
class ServiceItem(BaseModel):
class Config:
extra = Extra.ignore
schema_extra = {
"example": {
"title": "File Picker", # NEW: rename 'name' as title (so it is not confused with an identifier!)
"thumbnail": None, # optional
"description": "File Picker",
"classifiers_url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/classifiers",
"quality": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/quality",
"access_rights_url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/access_rights",
"key_id": "simcore/services/frontend/file-picker", # NEW: renames key -> key_id
"version": "1.0.0",
"id": "a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4", # NEW: alternative identifier to key_id:version
"integration-version": "1.0.0",
"type": "dynamic",
"badges_url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/badges",
"authors_url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/authors",
"inputs_url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/inputs",
"outputs_url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4/outputs",
"owner": "[email protected]", # NEW, replaces "contact": "[email protected]"
"url": "https://catalog:8080/services/a8f5a503-01d5-40bc-b416-f5b7cc5d1fa4", # NEW self
}
}


ServiceResourcesGet = ServiceResourcesDict
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
from typing import Any, Literal, Optional, Union
from typing import Any, ClassVar, Literal

from models_library.basic_regex import PUBLIC_VARIABLE_NAME_RE
from models_library.services import ServiceInput, ServiceOutput
from models_library.utils.services_io import (
from pydantic import BaseModel, Field

from ..basic_regex import PUBLIC_VARIABLE_NAME_RE
from ..services import ServiceInput, ServiceOutput
from ..utils.services_io import (
get_service_io_json_schema,
guess_media_type,
update_schema_doc,
)
from pydantic import BaseModel, Field

PortKindStr = Literal["input", "output"]


#
# Model -------------------------------------------------------------------------------
#


class ServicePortGet(BaseModel):
key: str = Field(
...,
Expand All @@ -25,14 +21,14 @@ class ServicePortGet(BaseModel):
title="Key name",
)
kind: PortKindStr
content_media_type: Optional[str] = None
content_schema: Optional[dict[str, Any]] = Field(
content_media_type: str | None = None
content_schema: dict[str, Any] | None = Field(
None,
description="jsonschema for the port's value. SEE https://json-schema.org/understanding-json-schema/",
)

class Config:
schema_extra = {
schema_extra: ClassVar[dict[str, Any]] = {
"example": {
"key": "input_1",
"kind": "input",
Expand All @@ -51,7 +47,7 @@ def from_service_io(
cls,
kind: PortKindStr,
key: str,
port: Union[ServiceInput, ServiceOutput],
port: ServiceInput | ServiceOutput,
) -> "ServicePortGet":
kwargs: dict[str, Any] = {"key": key, "kind": kind}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
from typing import Optional

from models_library.generated_models.docker_rest_api import (
ServiceSpec as DockerServiceSpec,
)
from pydantic import BaseModel, Field

from ..generated_models.docker_rest_api import ServiceSpec as DockerServiceSpec


class ServiceSpecifications(BaseModel):
sidecar: Optional[DockerServiceSpec] = Field(
sidecar: DockerServiceSpec | None = Field(
default=None,
description="schedule-time specifications for the service sidecar (follows Docker Service creation API, see https://docs.docker.com/engine/api/v1.25/#operation/ServiceCreate)",
)
service: Optional[DockerServiceSpec] = Field(
service: DockerServiceSpec | None = Field(
default=None,
description="schedule-time specifications specifications for the service (follows Docker Service creation API (specifically only the Resources part), see https://docs.docker.com/engine/api/v1.41/#tag/Service/operation/ServiceCreate",
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import logging
from typing import TypeAlias

from pydantic import BaseModel, ConstrainedFloat, Field, validate_arguments, validator

_logger = logging.getLogger(__name__)

TaskId = str

ProgressMessage = str
ProgressMessage: TypeAlias = str


class ProgressPercent(ConstrainedFloat):
Expand All @@ -21,7 +22,7 @@ class TaskProgress(BaseModel):
"""

message: ProgressMessage = Field(default="")
percent: ProgressPercent = Field(default=ProgressPercent(0.0))
percent: ProgressPercent = Field(default=0.0) # type: ignore[assignment]

@validate_arguments
def update(
Expand All @@ -35,14 +36,15 @@ def update(
self.message = message
if percent:
if not (0.0 <= percent <= 1.0):
raise ValueError(f"{percent=} must be in range [0.0, 1.0]")
msg = f"percent={percent!r} must be in range [0.0, 1.0]"
raise ValueError(msg)
self.percent = percent

_logger.debug("Progress update: %s", f"{self}")

@classmethod
def create(cls) -> "TaskProgress":
return cls.parse_obj(dict(message="", percent=0.0))
return cls.parse_obj({"message": "", "percent": 0.0})

@validator("percent")
@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@
from typing import Any, ClassVar
from uuid import UUID

from models_library.projects_nodes_io import (
LocationID,
LocationName,
NodeID,
SimcoreS3FileID,
StorageFileID,
)
from pydantic import (
BaseModel,
ByteSize,
Expand All @@ -34,6 +27,13 @@

from .basic_regex import DATCORE_DATASET_NAME_RE, S3_BUCKET_NAME_RE
from .generics import ListModel
from .projects_nodes_io import (
LocationID,
LocationName,
NodeID,
SimcoreS3FileID,
StorageFileID,
)

ETag = str

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Config:

def data(
self,
*,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
Expand All @@ -49,6 +50,7 @@ def data(

def data_json(
self,
*,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
from pydantic import Field, validator

from ..api_schemas_long_running_tasks.tasks import TaskGet
from ..basic_types import HttpUrlWithCustomMinLength
from ..emails import LowerCaseEmailStr
from ..projects import ClassifierID, DateTimeStr, NodesDict, ProjectID
from ..projects_access import AccessRights, GroupIDStr
from ..projects_nodes import HttpUrlWithCustomMinLength
from ..projects_state import ProjectState
from ..projects_ui import StudyUI
from ..utils.common_validators import empty_str_to_none, none_to_empty_str
from ..utils.common_validators import (
empty_str_to_none_pre_validator,
none_to_empty_str_pre_validator,
)
from ..utils.pydantic_tools_extension import FieldNotRequired
from ._base import EmptyModel, InputSchema, OutputSchema
from .permalinks import ProjectPermalink
Expand All @@ -35,7 +38,7 @@ class ProjectCreateNew(InputSchema):

_empty_is_none = validator(
"uuid", "thumbnail", "description", allow_reuse=True, pre=True
)(empty_str_to_none)
)(empty_str_to_none_pre_validator)


# NOTE: based on OVERRIDABLE_DOCUMENT_KEYS
Expand All @@ -46,7 +49,7 @@ class ProjectCopyOverride(InputSchema):
prj_owner: LowerCaseEmailStr

_empty_is_none = validator("thumbnail", allow_reuse=True, pre=True)(
empty_str_to_none
empty_str_to_none_pre_validator
)


Expand All @@ -69,7 +72,7 @@ class ProjectGet(OutputSchema):
permalink: ProjectPermalink = FieldNotRequired()

_empty_description = validator("description", allow_reuse=True, pre=True)(
none_to_empty_str
none_to_empty_str_pre_validator
)


Expand Down Expand Up @@ -99,7 +102,7 @@ class ProjectReplace(InputSchema):
)

_empty_is_none = validator("thumbnail", allow_reuse=True, pre=True)(
empty_str_to_none
empty_str_to_none_pre_validator
)


Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from datetime import datetime
from enum import Enum

from models_library.projects import ProjectID
from models_library.projects_nodes_io import NodeID
from models_library.services import ServiceKey, ServiceVersion
from pydantic import BaseModel

from ..projects import ProjectID
from ..projects_nodes_io import NodeID
from ..services import ServiceKey, ServiceVersion

# Frontend API


Expand Down
Loading