Skip to content

Commit efbba27

Browse files
authored
Merge branch 'master' into mai/upgrade-catalog
2 parents 5b7c349 + 573b7c3 commit efbba27

File tree

14 files changed

+200
-157
lines changed

14 files changed

+200
-157
lines changed

.env-devel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ LOGIN_2FA_REQUIRED=0
333333
LOGIN_ACCOUNT_DELETION_RETENTION_DAYS=31
334334
LOGIN_REGISTRATION_CONFIRMATION_REQUIRED=0
335335
LOGIN_REGISTRATION_INVITATION_REQUIRED=0
336-
PROJECTS_INACTIVITY_INTERVAL=20
336+
PROJECTS_INACTIVITY_INTERVAL=00:00:20
337337
PROJECTS_TRASH_RETENTION_DAYS=7
338338
PROJECTS_MAX_COPY_SIZE_BYTES=30Gib
339339
PROJECTS_MAX_NUM_RUNNING_DYNAMIC_NODES=5

packages/common-library/src/common_library/json_serialization.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from uuid import UUID
2424

2525
import orjson
26-
from pydantic import NameEmail, SecretBytes, SecretStr
26+
from pydantic import AnyHttpUrl, AnyUrl, HttpUrl, NameEmail, SecretBytes, SecretStr
2727
from pydantic_core import Url
2828
from pydantic_extra_types.color import Color
2929

@@ -62,6 +62,8 @@ def decimal_encoder(dec_value: Decimal) -> int | float:
6262

6363

6464
ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = {
65+
AnyHttpUrl: str,
66+
AnyUrl: str,
6567
bytes: lambda o: o.decode(),
6668
Color: str,
6769
datetime.date: isoformat,
@@ -73,6 +75,7 @@ def decimal_encoder(dec_value: Decimal) -> int | float:
7375
frozenset: list,
7476
deque: list,
7577
GeneratorType: list,
78+
HttpUrl: str,
7679
IPv4Address: str,
7780
IPv4Interface: str,
7881
IPv4Network: str,

packages/common-library/tests/test_json_serialization.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
json_loads,
1616
)
1717
from faker import Faker
18-
from pydantic import Field, TypeAdapter
18+
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, HttpUrl, TypeAdapter
1919
from pydantic.json import pydantic_encoder
2020

2121

@@ -95,3 +95,18 @@ def test_compatiblity_with_json_interface(
9595

9696
# NOTE: cannot compare dumps directly because orjson compacts it more
9797
assert json_loads(orjson_dump) == json_loads(json_dump)
98+
99+
100+
def test_serialized_model_with_urls(faker: Faker):
101+
# See: https://github.com/ITISFoundation/osparc-simcore/pull/6852
102+
class M(BaseModel):
103+
any_http_url: AnyHttpUrl
104+
any_url: AnyUrl
105+
http_url: HttpUrl
106+
107+
obj = M(
108+
any_http_url=faker.url(),
109+
any_url=faker.url(),
110+
http_url=faker.url(),
111+
)
112+
json_dumps(obj)

packages/models-library/src/models_library/utils/_original_fastapi_encoders.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from enum import Enum
99
from pathlib import PurePath
1010
from types import GeneratorType
11-
from typing import Any, Callable, Union
11+
from typing import Any, Callable, Union, get_origin
1212

1313
from common_library.json_serialization import ENCODERS_BY_TYPE
1414
from pydantic import BaseModel
@@ -28,7 +28,8 @@ def generate_encoders_by_class_tuples(
2828
tuple
2929
)
3030
for type_, encoder in type_encoder_map.items():
31-
encoders_by_class_tuples[encoder] += (type_,)
31+
if get_origin(type_) is not Annotated:
32+
encoders_by_class_tuples[encoder] += (type_,)
3233
return encoders_by_class_tuples
3334

3435

services/api-server/src/simcore_service_api_server/exceptions/handlers/_log_streaming_errors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from ..log_streaming_errors import (
66
LogStreamerNotRegisteredError,
7-
LogStreamerRegistionConflictError,
7+
LogStreamerRegistrationConflictError,
88
LogStreamingBaseError,
99
)
1010
from ._utils import create_error_json_response
@@ -18,7 +18,7 @@ async def log_handling_error_handler(request: Request, exc: Exception) -> JSONRe
1818
status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR
1919
if isinstance(exc, LogStreamerNotRegisteredError):
2020
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
21-
elif isinstance(exc, LogStreamerRegistionConflictError):
21+
elif isinstance(exc, LogStreamerRegistrationConflictError):
2222
status_code = status.HTTP_409_CONFLICT
2323

2424
return create_error_json_response(msg, status_code=status_code)

services/api-server/src/simcore_service_api_server/exceptions/log_streaming_errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ class LogStreamerNotRegisteredError(LogStreamingBaseError):
99
msg_template = "{msg}"
1010

1111

12-
class LogStreamerRegistionConflictError(LogStreamingBaseError):
12+
class LogStreamerRegistrationConflictError(LogStreamingBaseError):
1313
msg_template = "A stream was already connected to {job_id}. Only a single stream can be connected at the time"

services/api-server/src/simcore_service_api_server/services/log_streaming.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from ..exceptions.backend_errors import BaseBackEndError
1717
from ..exceptions.log_streaming_errors import (
1818
LogStreamerNotRegisteredError,
19-
LogStreamerRegistionConflictError,
19+
LogStreamerRegistrationConflictError,
2020
)
2121
from ..models.schemas.errors import ErrorGet
2222
from ..models.schemas.jobs import JobID, JobLog
@@ -70,7 +70,7 @@ async def _distribute_logs(self, data: bytes):
7070

7171
async def register(self, job_id: JobID, queue: Queue[JobLog]):
7272
if job_id in self._log_streamers:
73-
raise LogStreamerRegistionConflictError(job_id=job_id)
73+
raise LogStreamerRegistrationConflictError(job_id=job_id)
7474
self._log_streamers[job_id] = queue
7575
await self._rabbit_client.add_topics(
7676
LoggerRabbitMessage.get_channel_name(), topics=[f"{job_id}.*"]
@@ -126,26 +126,24 @@ async def log_generator(self) -> AsyncIterable[str]:
126126
except TimeoutError:
127127
done = await self._project_done()
128128

129-
except BaseBackEndError as exc:
130-
_logger.info("%s", f"{exc}")
131-
yield ErrorGet(errors=[f"{exc}"]).model_dump_json() + _NEW_LINE
129+
except (BaseBackEndError, LogStreamerRegistrationConflictError) as exc:
130+
error_msg = f"{exc}"
131+
132+
_logger.info("%s: %s", exc.code, error_msg)
133+
yield ErrorGet(errors=[error_msg]).model_dump_json() + _NEW_LINE
134+
132135
except Exception as exc: # pylint: disable=W0718
133136
error_code = create_error_code(exc)
134-
user_error_msg = (
135-
MSG_INTERNAL_ERROR_USER_FRIENDLY_TEMPLATE + f" [{error_code}]"
136-
)
137+
error_msg = MSG_INTERNAL_ERROR_USER_FRIENDLY_TEMPLATE + f" [{error_code}]"
137138

138139
_logger.exception(
139140
**create_troubleshotting_log_kwargs(
140-
user_error_msg,
141+
error_msg,
141142
error=exc,
142143
error_code=error_code,
143144
)
144145
)
145-
yield ErrorGet(
146-
errors=[
147-
MSG_INTERNAL_ERROR_USER_FRIENDLY_TEMPLATE + f" (OEC: {error_code})"
148-
]
149-
).model_dump_json() + _NEW_LINE
146+
yield ErrorGet(errors=[error_msg]).model_dump_json() + _NEW_LINE
147+
150148
finally:
151149
await self._log_distributor.deregister(self._job_id)

services/api-server/tests/unit/test_services_rabbitmq.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
from simcore_service_api_server.services.log_streaming import (
4646
LogDistributor,
4747
LogStreamer,
48-
LogStreamerRegistionConflictError,
48+
LogStreamerRegistrationConflictError,
4949
)
5050
from tenacity import AsyncRetrying, retry_if_not_exception_type, stop_after_delay
5151

@@ -219,7 +219,7 @@ async def _(job_log: JobLog):
219219
pass
220220

221221
await log_distributor.register(project_id, _)
222-
with pytest.raises(LogStreamerRegistionConflictError):
222+
with pytest.raises(LogStreamerRegistrationConflictError):
223223
await log_distributor.register(project_id, _)
224224
await log_distributor.deregister(project_id)
225225

services/dynamic-scheduler/tests/unit/test_cli.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# pylint:disable=unused-argument
22

33
import os
4+
import traceback
45

56
import pytest
7+
from click.testing import Result
68
from pytest_simcore.helpers.monkeypatch_envs import load_dotenv, setenvs_from_dict
79
from pytest_simcore.helpers.typing_env import EnvVarsDict
810
from simcore_service_dynamic_scheduler._meta import API_VERSION
@@ -11,20 +13,26 @@
1113
from typer.testing import CliRunner
1214

1315

16+
def _format_cli_error(result: Result) -> str:
17+
assert result.exception
18+
tb_message = "\n".join(traceback.format_tb(result.exception.__traceback__))
19+
return f"Below exception was raised by the cli:\n{tb_message}"
20+
21+
1422
def test_cli_help_and_version(cli_runner: CliRunner):
1523
# simcore-service-dynamic-scheduler --help
1624
result = cli_runner.invoke(cli_main, "--help")
17-
assert result.exit_code == os.EX_OK, result.output
25+
assert result.exit_code == os.EX_OK, _format_cli_error(result)
1826

1927
result = cli_runner.invoke(cli_main, "--version")
20-
assert result.exit_code == os.EX_OK, result.output
28+
assert result.exit_code == os.EX_OK, _format_cli_error(result)
2129
assert result.stdout.strip() == API_VERSION
2230

2331

2432
def test_echo_dotenv(cli_runner: CliRunner, monkeypatch: pytest.MonkeyPatch):
2533
# simcore-service-dynamic-scheduler echo-dotenv
2634
result = cli_runner.invoke(cli_main, "echo-dotenv")
27-
assert result.exit_code == os.EX_OK, result.output
35+
assert result.exit_code == os.EX_OK, _format_cli_error(result)
2836

2937
environs = load_dotenv(result.stdout)
3038

@@ -33,10 +41,25 @@ def test_echo_dotenv(cli_runner: CliRunner, monkeypatch: pytest.MonkeyPatch):
3341
ApplicationSettings.create_from_envs()
3442

3543

36-
def test_list_settings(cli_runner: CliRunner, app_environment: EnvVarsDict):
37-
# simcore-service-dynamic-scheduler settings --show-secrets --as-json
38-
result = cli_runner.invoke(cli_main, ["settings", "--show-secrets", "--as-json"])
39-
assert result.exit_code == os.EX_OK, result.output
44+
def test_list_settings(
45+
cli_runner: CliRunner, app_environment: EnvVarsDict, monkeypatch: pytest.MonkeyPatch
46+
):
47+
with monkeypatch.context() as patch:
48+
setenvs_from_dict(
49+
patch,
50+
{
51+
**app_environment,
52+
"DYNAMIC_SCHEDULER_TRACING": "{}",
53+
"TRACING_OPENTELEMETRY_COLLECTOR_ENDPOINT": "http://replace-with-opentelemetry-collector",
54+
"TRACING_OPENTELEMETRY_COLLECTOR_PORT": "4318",
55+
},
56+
)
57+
58+
# simcore-service-dynamic-scheduler settings --show-secrets --as-json
59+
result = cli_runner.invoke(
60+
cli_main, ["settings", "--show-secrets", "--as-json"]
61+
)
62+
assert result.exit_code == os.EX_OK, _format_cli_error(result)
4063

4164
print(result.output)
4265
settings = ApplicationSettings(result.output)

services/invitations/openapi.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,6 @@
286286
},
287287
"invitation_url": {
288288
"type": "string",
289-
"maxLength": 2083,
290-
"minLength": 1,
291-
"format": "uri",
292289
"title": "Invitation Url",
293290
"description": "Invitation link"
294291
}
@@ -437,9 +434,6 @@
437434
},
438435
"docs_url": {
439436
"type": "string",
440-
"maxLength": 2083,
441-
"minLength": 1,
442-
"format": "uri",
443437
"title": "Docs Url"
444438
}
445439
},

0 commit comments

Comments
 (0)