Skip to content

Commit 06a4679

Browse files
authored
Merge branch 'master' into pr-osparc-team-black-feedback
2 parents 3bf331e + 45f3a3e commit 06a4679

File tree

70 files changed

+1351
-831
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1351
-831
lines changed

.github/mergify.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
pull_request_rules:
2+
- name: Automatic merge
3+
description: Conditions required for automatic merging of a PR
4+
conditions:
5+
# let Mergify know that the PR can be merged (added manually)
6+
- label = 🤖-automerge
7+
# block Mergify from merging the PR (added manually)
8+
- label != 🤖-do-not-merge
9+
10+
# list of CI checks that need to pass in order for the PR to be merged
11+
- check-success=unit-tests
12+
- check-success=integration-tests
13+
- check-success=system-tests
14+
15+
# Check for required reviews
16+
- "#approved-reviews-by>=2" # Requires 2 approving reviews
17+
- "#changes-requested-reviews-by=0" # No changes requested
18+
- "#review-threads-unresolved=0" # All review threads resolved
19+
20+
# Optional but recommended checks
21+
- base=master
22+
- -draft # PR is not in draft state
23+
- -conflict # No merge conflicts
24+
actions:
25+
merge:
26+
27+
- name: automatic update for PR ready to be merged
28+
conditions:
29+
- -draft
30+
- label=🤖-automerge
31+
actions:
32+
update:
33+
34+
- name: retry CI on failure
35+
conditions:
36+
- base=master
37+
- or:
38+
- check-failure=unit-tests
39+
- check-failure=integration-tests
40+
- check-failure=system-tests
41+
actions:
42+
github_actions:
43+
workflow:
44+
dispatch:
45+
- workflow: .github/workflows/ci-testing-deploy.yml
46+

.ruff.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
select = [
2+
lint.select = [
33
"A", # [https://pypi.org/project/flake8-builtins/]
44
"ARG", # [https://pypi.org/project/flake8-unused-arguments/]
55
"ASYNC", # [https://pypi.org/project/flake8-async/]
@@ -40,7 +40,7 @@ select = [
4040
"W", # [https://pypi.org/project/pycodestyle/] warnings
4141
"YTT", # [https://pypi.org/project/flake8-2020/]
4242
]
43-
ignore = [
43+
lint.ignore = [
4444
"E501", # line too long, handled by black
4545
"S101", # use of `assert` detected hanbled by pylance, does not support noseq
4646
"TID252", # [*] Relative imports from parent modules are banned
@@ -50,7 +50,7 @@ ignore = [
5050
target-version = "py311"
5151

5252

53-
[per-file-ignores]
53+
[lint.per-file-ignores]
5454
"**/{tests,pytest_simcore}/**" = [
5555
"T201", # print found
5656
"ARG001", # unused function argument
@@ -64,10 +64,10 @@ target-version = "py311"
6464
"FBT001", # Boolean positional arg in function definition
6565
]
6666

67-
[flake8-pytest-style]
67+
[lint.flake8-pytest-style]
6868
fixture-parentheses = false
6969
parametrize-names-type = "csv"
7070

7171

72-
[pylint]
72+
[lint.pylint]
7373
max-args = 10

packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from datetime import datetime
2-
from typing import NamedTuple
2+
from typing import Annotated, Self
33

4-
from pydantic import ConfigDict, PositiveInt, field_validator
4+
from pydantic import ConfigDict, Field, field_validator
55

66
from ..access_rights import AccessRights
77
from ..basic_types import IDStr
8-
from ..folders import FolderID
8+
from ..folders import FolderDB, FolderID
99
from ..groups import GroupID
1010
from ..utils.common_validators import null_or_none_str_to_none_validator
1111
from ..workspaces import WorkspaceID
@@ -16,17 +16,40 @@ class FolderGet(OutputSchema):
1616
folder_id: FolderID
1717
parent_folder_id: FolderID | None = None
1818
name: str
19+
1920
created_at: datetime
2021
modified_at: datetime
2122
trashed_at: datetime | None
23+
trashed_by: Annotated[
24+
GroupID | None, Field(description="The primary gid of the user who trashed")
25+
]
2226
owner: GroupID
2327
workspace_id: WorkspaceID | None
2428
my_access_rights: AccessRights
2529

30+
@classmethod
31+
def from_domain_model(
32+
cls,
33+
folder_db: FolderDB,
34+
trashed_by_primary_gid: GroupID | None,
35+
user_folder_access_rights: AccessRights,
36+
) -> Self:
37+
if (folder_db.trashed_by is None) ^ (trashed_by_primary_gid is None):
38+
msg = f"Incompatible inputs: {folder_db.trashed_by=} but not {trashed_by_primary_gid=}"
39+
raise ValueError(msg)
2640

27-
class FolderGetPage(NamedTuple):
28-
items: list[FolderGet]
29-
total: PositiveInt
41+
return cls(
42+
folder_id=folder_db.folder_id,
43+
parent_folder_id=folder_db.parent_folder_id,
44+
name=folder_db.name,
45+
created_at=folder_db.created,
46+
modified_at=folder_db.modified,
47+
trashed_at=folder_db.trashed,
48+
trashed_by=trashed_by_primary_gid,
49+
owner=folder_db.created_by_gid,
50+
workspace_id=folder_db.workspace_id,
51+
my_access_rights=user_folder_access_rights,
52+
)
3053

3154

3255
class FolderCreateBodyParams(InputSchema):

packages/models-library/src/models_library/api_schemas_webserver/projects.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
66
"""
77

8+
import copy
89
from datetime import datetime
910
from typing import Annotated, Any, Literal, Self, TypeAlias
1011

1112
from common_library.dict_tools import remap_keys
12-
from models_library.folders import FolderID
13-
from models_library.utils._original_fastapi_encoders import jsonable_encoder
14-
from models_library.workspaces import WorkspaceID
1513
from pydantic import (
1614
BeforeValidator,
1715
ConfigDict,
@@ -25,10 +23,12 @@
2523
from ..basic_types import LongTruncatedStr, ShortTruncatedStr
2624
from ..emails import LowerCaseEmailStr
2725
from ..folders import FolderID
26+
from ..groups import GroupID
2827
from ..projects import ClassifierID, DateTimeStr, NodesDict, ProjectID
2928
from ..projects_access import AccessRights, GroupIDStr
3029
from ..projects_state import ProjectState
3130
from ..projects_ui import StudyUI
31+
from ..utils._original_fastapi_encoders import jsonable_encoder
3232
from ..utils.common_validators import (
3333
empty_str_to_none_pre_validator,
3434
none_to_empty_str_pre_validator,
@@ -98,6 +98,9 @@ class ProjectGet(OutputSchema):
9898
folder_id: FolderID | None
9999

100100
trashed_at: datetime | None
101+
trashed_by: Annotated[
102+
GroupID | None, Field(description="The primary gid of the user who trashed")
103+
]
101104

102105
_empty_description = field_validator("description", mode="before")(
103106
none_to_empty_str_pre_validator
@@ -107,10 +110,20 @@ class ProjectGet(OutputSchema):
107110

108111
@classmethod
109112
def from_domain_model(cls, project_data: dict[str, Any]) -> Self:
113+
trimmed_data = copy.copy(project_data)
114+
# project_data["trashed_by"] is a UserID
115+
# project_data["trashed_by_primary_gid"] is a GroupID
116+
trimmed_data.pop("trashed_by", None)
117+
trimmed_data.pop("trashedBy", None)
118+
110119
return cls.model_validate(
111120
remap_keys(
112-
project_data,
113-
rename={"trashed": "trashed_at"},
121+
trimmed_data,
122+
rename={
123+
"trashed": "trashed_at",
124+
"trashed_by_primary_gid": "trashed_by",
125+
"trashedByPrimaryGid": "trashedBy",
126+
},
114127
)
115128
)
116129

@@ -127,7 +140,8 @@ class ProjectReplace(InputSchema):
127140
name: ShortTruncatedStr
128141
description: LongTruncatedStr
129142
thumbnail: Annotated[
130-
HttpUrl | None, BeforeValidator(empty_str_to_none_pre_validator)
143+
HttpUrl | None,
144+
BeforeValidator(empty_str_to_none_pre_validator),
131145
] = Field(default=None)
132146
creation_date: DateTimeStr
133147
last_change_date: DateTimeStr

packages/models-library/src/models_library/api_schemas_webserver/workspaces.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from datetime import datetime
2-
from typing import Self
2+
from typing import Annotated, Self
33

4-
from pydantic import ConfigDict
4+
from pydantic import ConfigDict, Field
55

66
from ..access_rights import AccessRights
77
from ..basic_types import IDStr
88
from ..groups import GroupID
9-
from ..users import UserID
109
from ..workspaces import UserWorkspaceWithAccessRights, WorkspaceID
1110
from ._base import InputSchema, OutputSchema
1211

@@ -19,7 +18,9 @@ class WorkspaceGet(OutputSchema):
1918
created_at: datetime
2019
modified_at: datetime
2120
trashed_at: datetime | None
22-
trashed_by: UserID | None
21+
trashed_by: Annotated[
22+
GroupID | None, Field(description="The primary gid of the user who trashed")
23+
]
2324
my_access_rights: AccessRights
2425
access_rights: dict[GroupID, AccessRights]
2526

@@ -33,7 +34,7 @@ def from_domain_model(cls, wks: UserWorkspaceWithAccessRights) -> Self:
3334
created_at=wks.created,
3435
modified_at=wks.modified,
3536
trashed_at=wks.trashed,
36-
trashed_by=wks.trashed_by if wks.trashed else None,
37+
trashed_by=wks.trashed_by_primary_gid if wks.trashed else None,
3738
my_access_rights=wks.my_access_rights,
3839
access_rights=wks.access_rights,
3940
)
Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
from datetime import datetime
22
from enum import auto
3-
from typing import TypeAlias
3+
from typing import NamedTuple, TypeAlias
44

5-
from pydantic import (
6-
BaseModel,
7-
ConfigDict,
8-
Field,
9-
PositiveInt,
10-
ValidationInfo,
11-
field_validator,
12-
)
5+
from pydantic import BaseModel, ConfigDict, PositiveInt, ValidationInfo, field_validator
136

147
from .access_rights import AccessRights
158
from .groups import GroupID
@@ -43,38 +36,31 @@ def validate_folder_id(cls, value, info: ValidationInfo):
4336
return value
4437

4538

46-
#
47-
# DB
48-
#
49-
50-
5139
class FolderDB(BaseModel):
5240
folder_id: FolderID
5341
name: str
5442
parent_folder_id: FolderID | None
55-
created_by_gid: GroupID = Field(
56-
...,
57-
description="GID of the group that owns this wallet",
58-
)
59-
created: datetime = Field(
60-
...,
61-
description="Timestamp on creation",
62-
)
63-
modified: datetime = Field(
64-
...,
65-
description="Timestamp of last modification",
66-
)
67-
trashed: datetime | None = Field(
68-
...,
69-
)
70-
71-
user_id: UserID | None
72-
workspace_id: WorkspaceID | None
7343

44+
created_by_gid: GroupID
45+
created: datetime
46+
modified: datetime
47+
48+
trashed: datetime | None
49+
trashed_by: UserID | None
50+
trashed_explicitly: bool
51+
52+
user_id: UserID | None # owner?
53+
workspace_id: WorkspaceID | None
7454
model_config = ConfigDict(from_attributes=True)
7555

7656

77-
class UserFolderAccessRightsDB(FolderDB):
57+
class UserFolder(FolderDB):
7858
my_access_rights: AccessRights
7959

8060
model_config = ConfigDict(from_attributes=True)
61+
62+
63+
class FolderTuple(NamedTuple):
64+
folder_db: FolderDB
65+
trashed_by_primary_gid: GroupID | None
66+
my_access_rights: AccessRights

packages/models-library/src/models_library/projects.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from .basic_regex import DATE_RE, UUID_RE_BASE
1717
from .emails import LowerCaseEmailStr
18+
from .groups import GroupID
1819
from .projects_access import AccessRights, GroupIDStr
1920
from .projects_nodes import Node
2021
from .projects_nodes_io import NodeIDStr
@@ -106,7 +107,7 @@ class ProjectAtDB(BaseProjectModel):
106107

107108
@field_validator("project_type", mode="before")
108109
@classmethod
109-
def convert_sql_alchemy_enum(cls, v):
110+
def _convert_sql_alchemy_enum(cls, v):
110111
if isinstance(v, Enum):
111112
return v.value
112113
return v
@@ -185,8 +186,12 @@ class Project(BaseProjectModel):
185186

186187
trashed: datetime | None = None
187188
trashed_by: Annotated[UserID | None, Field(alias="trashedBy")] = None
189+
trashed_by_primary_gid: Annotated[
190+
GroupID | None, Field(alias="trashedByPrimaryGid")
191+
] = None
188192
trashed_explicitly: Annotated[bool, Field(alias="trashedExplicitly")] = False
189193

190194
model_config = ConfigDict(
195+
# NOTE: this is a security measure until we get rid of the ProjectDict variants
191196
extra="forbid",
192197
)

packages/models-library/src/models_library/workspaces.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Workspace(BaseModel):
4747
workspace_id: WorkspaceID
4848
name: str
4949
description: str | None
50-
owner_primary_gid: PositiveInt = Field(
50+
owner_primary_gid: GroupID = Field(
5151
...,
5252
description="GID of the group that owns this wallet",
5353
)
@@ -62,6 +62,14 @@ class Workspace(BaseModel):
6262
)
6363
trashed: datetime | None
6464
trashed_by: UserID | None
65+
trashed_by_primary_gid: GroupID | None = None
66+
67+
model_config = ConfigDict(from_attributes=True)
68+
69+
70+
class UserWorkspaceWithAccessRights(Workspace):
71+
my_access_rights: AccessRights
72+
access_rights: dict[GroupID, AccessRights]
6573

6674
model_config = ConfigDict(from_attributes=True)
6775

@@ -72,10 +80,3 @@ class WorkspaceUpdates(BaseModel):
7280
thumbnail: str | None = None
7381
trashed: datetime | None = None
7482
trashed_by: UserID | None = None
75-
76-
77-
class UserWorkspaceWithAccessRights(Workspace):
78-
my_access_rights: AccessRights
79-
access_rights: dict[GroupID, AccessRights]
80-
81-
model_config = ConfigDict(from_attributes=True)

0 commit comments

Comments
 (0)