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

♻️ Maintenance: Fixes mypy in api-server #6175

Merged
merged 29 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
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
1 change: 0 additions & 1 deletion .github/workflows/ci-testing-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,6 @@ jobs:
run: ./ci/github/unit-testing/api-server.bash install
- name: typecheck
run: ./ci/github/unit-testing/api-server.bash typecheck
continue-on-error: true
- name: test
if: always()
run: ./ci/github/unit-testing/api-server.bash test
Expand Down
1 change: 1 addition & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ warn_unused_configs = True
warn_unused_ignores = True

# SEE https://docs.pydantic.dev/mypy_plugin/#plugin-settings
# SEE https://docs.pydantic.dev/1.10/mypy_plugin/#plugin-settings
[pydantic-mypy]
init_forbid_extra = True
init_typed = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@


# python-like version
VERSION_RE = r"^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$"
SIMPLE_VERSION_RE = r"^(0|[1-9]\d*)(\.(0|[1-9]\d*)){2}(-(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*)(\.(0|[1-9]\d*|\d*[-a-zA-Z][-\da-zA-Z]*))*)?(\+[-\da-zA-Z]+(\.[-\da-zA-Z-]+)*)?$"

# Semantic version
# SEE https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
Expand Down
10 changes: 7 additions & 3 deletions packages/models-library/src/models_library/basic_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
PositiveInt,
)

from .basic_regex import SEMANTIC_VERSION_RE_W_CAPTURE_GROUPS, UUID_RE, VERSION_RE
from .basic_regex import (
SEMANTIC_VERSION_RE_W_CAPTURE_GROUPS,
SIMPLE_VERSION_RE,
UUID_RE,
)


class NonNegativeDecimal(ConstrainedDecimal):
Expand Down Expand Up @@ -41,11 +45,11 @@ class VersionTag(ConstrainedStr):
regex = re.compile(r"^v\d$")


# e.g. '1.23.11' or '2.1.0-rc2'
class VersionStr(ConstrainedStr):
regex = re.compile(VERSION_RE)
regex = re.compile(SIMPLE_VERSION_RE)


# e.g. '1.23.11' or '2.1.0-rc2' or not 0.1.0-alpha (see test_SEMANTIC_VERSION_RE_W_CAPTURE_GROUPS)
class SemanticVersionStr(ConstrainedStr):
regex = re.compile(SEMANTIC_VERSION_RE_W_CAPTURE_GROUPS)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import arrow
from pydantic import ConstrainedStr

from .basic_regex import PROPERTY_KEY_RE, VERSION_RE
from .basic_regex import PROPERTY_KEY_RE, SIMPLE_VERSION_RE
from .services_regex import (
COMPUTATIONAL_SERVICE_KEY_RE,
DYNAMIC_SERVICE_KEY_RE,
Expand Down Expand Up @@ -51,7 +51,7 @@ class ComputationalServiceKey(ServiceKey):


class ServiceVersion(ConstrainedStr):
regex = re.compile(VERSION_RE)
regex = re.compile(SIMPLE_VERSION_RE)

class Config:
frozen = True
Expand Down
6 changes: 3 additions & 3 deletions packages/models-library/tests/test_basic_regex.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
PUBLIC_VARIABLE_NAME_RE,
SEMANTIC_VERSION_RE_W_CAPTURE_GROUPS,
SEMANTIC_VERSION_RE_W_NAMED_GROUPS,
SIMPLE_VERSION_RE,
TWILIO_ALPHANUMERIC_SENDER_ID_RE,
UUID_RE,
VERSION_RE,
)
from packaging.version import Version

Expand Down Expand Up @@ -62,8 +62,8 @@ def assert_match_and_get_capture(
("2.1.0-rc2", ("2", ".0", "0", "-rc2", "rc2", None, None, None, None)),
],
)
def test_VERSION_RE(version_str, expected):
assert_match_and_get_capture(VERSION_RE, version_str, expected)
def test_SIMPLE_VERSION_RE(version_str, expected):
assert_match_and_get_capture(SIMPLE_VERSION_RE, version_str, expected)


# Many taken from https://regex101.com/r/Ly7O1x/3/
Expand Down
6 changes: 3 additions & 3 deletions packages/models-library/tests/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from typing import Any

import pytest
from models_library.basic_regex import VERSION_RE
from models_library.basic_regex import SIMPLE_VERSION_RE
from models_library.services import BootOption, ServiceMetaDataPublished
from models_library.services_base import ServiceBaseDisplay
from models_library.services_regex import (
Expand Down Expand Up @@ -151,8 +151,8 @@ def test_SERVICE_KEY_RE(service_key: str, pattern: re.Pattern):
"python_regex_pattern, json_schema_file_name, json_schema_entry_paths",
[
(SERVICE_KEY_RE, "project-v0.0.1-pydantic.json", ["key"]),
(VERSION_RE, "project-v0.0.1-pydantic.json", ["version"]),
(VERSION_RE, "node-meta-v0.0.1-pydantic.json", ["version"]),
(SIMPLE_VERSION_RE, "project-v0.0.1-pydantic.json", ["version"]),
(SIMPLE_VERSION_RE, "node-meta-v0.0.1-pydantic.json", ["version"]),
(SERVICE_KEY_RE, "node-meta-v0.0.1-pydantic.json", ["key"]),
],
)
Expand Down
8 changes: 4 additions & 4 deletions packages/models-library/tests/test_utils_service_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from pathlib import Path

import pytest
from models_library.basic_regex import VERSION_RE
from models_library.basic_regex import SIMPLE_VERSION_RE
from models_library.services import ServiceInput, ServiceOutput, ServicePortKey
from models_library.utils.json_schema import jsonschema_validate_schema
from models_library.utils.services_io import get_service_io_json_schema
Expand Down Expand Up @@ -87,9 +87,9 @@ def test_against_service_metadata_configs(metadata_path: Path):
jsonschema_validate_schema(schema)


assert VERSION_RE[0] == "^"
assert VERSION_RE[-1] == "$"
_VERSION_SEARCH_RE = re.compile(VERSION_RE[1:-1]) # without $ and ^
assert SIMPLE_VERSION_RE[0] == "^"
assert SIMPLE_VERSION_RE[-1] == "$"
_VERSION_SEARCH_RE = re.compile(SIMPLE_VERSION_RE[1:-1]) # without $ and ^


def _iter_main_services() -> Iterable[Path]:
Expand Down
2 changes: 1 addition & 1 deletion packages/notifications-library/requirements/_test.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ pytest-runner
pytest-sugar
python-dotenv
pyyaml
tenacity
sqlalchemy[mypy]
tenacity
types-aiofiles
8 changes: 5 additions & 3 deletions packages/service-library/src/servicelib/utils_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

from importlib.metadata import distribution

from models_library.basic_types import VersionStr
from packaging.version import Version
from pydantic import parse_obj_as


class PackageInfo:
Expand All @@ -13,7 +15,7 @@ class PackageInfo:
Usage example:

info: Final = PackageMetaInfo(package_name="simcore-service-library")
__version__: Final[str] = info.__version__
__version__: Final[VersionStr] = info.__version__

PROJECT_NAME: Final[str] = info.project_name
VERSION: Final[Version] = info.version
Expand All @@ -37,8 +39,8 @@ def version(self) -> Version:
return Version(self._distribution.version)

@property
def __version__(self) -> str:
return self._distribution.version
def __version__(self) -> VersionStr:
return parse_obj_as(VersionStr, self._distribution.version)

@property
def api_prefix_path_tag(self) -> str:
Expand Down
3 changes: 2 additions & 1 deletion packages/service-library/tests/test_utils_meta.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Final

from models_library.basic_types import VersionStr
from packaging.version import Version
from servicelib.utils_meta import PackageInfo

Expand All @@ -8,7 +9,7 @@ def test_meta_module_implementation():
# This is what is used in _meta.py

info: Final = PackageInfo(package_name="simcore-service-library")
__version__: Final[str] = info.__version__
__version__: Final[VersionStr] = info.__version__

PROJECT_NAME: Final[str] = info.project_name
VERSION: Final[Version] = info.version
Expand Down
1 change: 1 addition & 0 deletions services/api-server/requirements/_test.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ pytest-mock
pytest-runner
respx
sqlalchemy[mypy] # adds Mypy / Pep-484 Support for ORM Mappings SEE https://docs.sqlalchemy.org/en/20/orm/extensions/mypy.html
types-aiofiles
types-boto3
2 changes: 2 additions & 0 deletions services/api-server/requirements/_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ tomli==2.0.1
# coverage
# mypy
# pytest
types-aiofiles==24.1.0.20240626
# via -r requirements/_test.in
types-awscrt==0.21.2
# via botocore-stubs
types-boto3==1.0.2
Expand Down
1 change: 1 addition & 0 deletions services/api-server/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ markers =
[mypy]
plugins =
pydantic.mypy
sqlalchemy.ext.mypy.plugin
5 changes: 3 additions & 2 deletions services/api-server/src/simcore_service_api_server/_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

from typing import Final

from models_library.basic_types import VersionStr
from packaging.version import Version
from servicelib.utils_meta import PackageInfo

info: Final = PackageInfo(package_name="simcore-service-api-server")
__version__: Final[str] = info.__version__
__version__: Final[VersionStr] = info.__version__


PROJECT_NAME: Final[str] = info.project_name
VERSION: Final[Version] = info.version
API_VERSION: Final[str] = info.__version__
API_VERSION: Final[VersionStr] = info.__version__
API_VTAG: Final[str] = info.api_prefix_path_tag
SUMMARY: Final[str] = info.get_summary()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from collections.abc import AsyncGenerator, Callable
from typing import Annotated, cast

from aiopg.sa import Engine
from fastapi import Depends
Expand All @@ -11,12 +12,12 @@


def get_db_engine(request: Request) -> Engine:
return request.app.state.engine
return cast(Engine, request.app.state.engine)


def get_repository(repo_type: type[BaseRepository]) -> Callable:
async def _get_repo(
engine: Engine = Depends(get_db_engine),
engine: Annotated[Engine, Depends(get_db_engine)],
) -> AsyncGenerator[BaseRepository, None]:
# NOTE: 2 different ideas were tried here with not so good
# 1st one was acquiring a connection per repository which lead to the following issue https://github.com/ITISFoundation/osparc-simcore/pull/1966
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from pydantic import AnyUrl, ByteSize, PositiveInt, ValidationError, parse_obj_as
from servicelib.fastapi.requests_decorators import cancel_on_disconnect
from simcore_sdk.node_ports_common.constants import SIMCORE_LOCATION
from simcore_sdk.node_ports_common.file_io_utils import UploadableFileObject
from simcore_sdk.node_ports_common.filemanager import (
UploadableFileObject,
UploadedFile,
UploadedFolder,
abort_upload,
Expand Down Expand Up @@ -59,8 +59,9 @@
status.HTTP_404_NOT_FOUND: {
"description": "File not found",
"model": ErrorGet,
}
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
},
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}


async def _get_file(
Expand Down Expand Up @@ -353,7 +354,7 @@ async def abort_multipart_upload(
file: File = File(
id=file_id,
filename=client_file.filename,
sha256_checksum=client_file.sha256_checksum,
checksum=client_file.sha256_checksum,
pcrespov marked this conversation as resolved.
Show resolved Hide resolved
e_tag=None,
)
abort_link: URL = await storage_client.create_abort_upload_link(
Expand Down Expand Up @@ -382,7 +383,7 @@ async def complete_multipart_upload(
file: File = File(
id=file_id,
filename=client_file.filename,
sha256_checksum=client_file.sha256_checksum,
checksum=client_file.sha256_checksum,
pcrespov marked this conversation as resolved.
Show resolved Hide resolved
e_tag=None,
)
complete_link: URL = await storage_client.create_complete_upload_link(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
status.HTTP_404_NOT_FOUND: {
"description": "Not found",
"model": ErrorGet,
}
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
},
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}

router = APIRouter()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ def _compose_job_resource_name(solver_key, solver_version, job_id) -> str:
status.HTTP_404_NOT_FOUND: {
"description": "Metadata not found",
"model": ErrorGet,
}
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
},
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}

JOBS_STATUS_CODES: dict[int | str, dict[str, Any]] = {
status.HTTP_402_PAYMENT_REQUIRED: {
Expand All @@ -75,7 +76,8 @@ def _compose_job_resource_name(solver_key, solver_version, job_id) -> str:
"description": "Job/wallet/pricing details not found",
"model": ErrorGet,
},
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}


@router.post(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
"description": "Job not found",
"model": ErrorGet,
},
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}

_LOGFILE_STATUS_CODES: dict[int | str, dict[str, Any]] = {
status.HTTP_200_OK: {
Expand All @@ -91,8 +92,9 @@
status.HTTP_404_NOT_FOUND: {
"description": "Pricing unit not found",
"model": ErrorGet,
}
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
},
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}

_LOGSTREAM_STATUS_CODES: dict[int | str, dict[str, Any]] = {
status.HTTP_200_OK: {
Expand All @@ -103,7 +105,8 @@
"description": "Conflict: Logs are already being streamed",
"model": ErrorGet,
},
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}

router = APIRouter()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
from collections.abc import Callable
from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, Header, Query, Request, status
from fastapi.encoders import jsonable_encoder
Expand Down Expand Up @@ -116,7 +117,8 @@ async def create_study_job(
)

await webserver_api.patch_project(
project_id=job.id, patch_params=ProjectPatch(name=job.name)
project_id=job.id,
pcrespov marked this conversation as resolved.
Show resolved Hide resolved
patch_params=ProjectPatch(name=job.name), # type: ignore[arg-type]
)

project_inputs = await webserver_api.get_project_inputs(project_id=project.uuid)
Expand All @@ -140,11 +142,9 @@ async def create_study_job(
)

for node_label, file_link in new_project_file_inputs.items():
node_id = file_param_nodes[node_label]

await webserver_api.update_node_outputs(
project_id=project.uuid,
node_id=node_id,
node_id=UUID(file_param_nodes[node_label]),
new_node_outputs=NodeOutputs(outputs={"outFile": file_link}),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
status.HTTP_404_NOT_FOUND: {
"description": "User not found",
"model": ErrorGet,
}
} | DEFAULT_BACKEND_SERVICE_STATUS_CODES
},
**DEFAULT_BACKEND_SERVICE_STATUS_CODES,
}


@router.get("", response_model=Profile, responses=_USER_STATUS_CODES)
Expand Down
Loading
Loading