Skip to content

Commit f401ab3

Browse files
authored
refactor(resources): one canonical layout, scoped bases, dedup schemas (#55)
Implements plans/refactor/04-resource-layer-normalization.md: - Canonical per-resource layout everywhere: operations.py / schemas.py / resources.py. Renamed domain+usage manager.py and envVars/git/ landscape/logs models.py to resources.py; git schema.py -> schemas.py; deleted the zero-byte landscape/resources.py placeholder - envVars/ package renamed to env_vars/; the old camelCase import path remains as a deprecation shim module (warns, re-exports) - Domain entity moves to domain/schemas.py alongside its base (matching Team/Workspace); TeamDomainManager lives in domain/resources.py; domain/__init__.py gains proper re-exports - New TeamScopedResource / WorkspaceScopedResource bases in core/base.py replace six copy-pasted manager __init__s; managers expose team_id/workspace_id consistently - EnvVar derives from CamelModel like every other schema (gains to_dict/to_json/to_yaml) - PipelineStatusList is now an alias of ResourceList[PipelineStatus] instead of a reimplementation - PaginatedResponse: refresh() hoisted from the two response subclasses, limit/offset are non-Optional with defaults (drops the repeated 'or 25' re-defaulting); single _clamp_page_size helper replaces four inline min(max(...)) clamps - Deleted dead utils.dict_to_model_list Only internal module paths moved; all public re-exports (top-level codesphere, package __init__s) are unchanged, plus the envVars shim.
1 parent 49e1b14 commit f401ab3

37 files changed

Lines changed: 426 additions & 427 deletions

examples/dashboard/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
WorkspaceCreate,
3636
WorkspaceUpdate,
3737
)
38-
from codesphere.resources.workspace.envVars import EnvVar # noqa: E402
38+
from codesphere.resources.workspace.env_vars import EnvVar # noqa: E402
3939
from codesphere.resources.workspace.landscape import ( # noqa: E402
4040
PipelineStage,
4141
ProfileBuilder,

src/codesphere/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
WorkspaceStatus,
5252
WorkspaceUpdate,
5353
)
54-
from .resources.workspace.envVars import EnvVar
54+
from .resources.workspace.env_vars import EnvVar
5555

5656
logging.getLogger("codesphere").addHandler(logging.NullHandler())
5757

src/codesphere/core/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
from .base import BoundModel, CamelModel, ResourceBase, ResourceList
1+
from .base import (
2+
BoundModel,
3+
CamelModel,
4+
ResourceBase,
5+
ResourceList,
6+
TeamScopedResource,
7+
WorkspaceScopedResource,
8+
)
29
from .handler import execute_operation
310
from .operations import APIOperation, StreamOperation
411

@@ -9,5 +16,7 @@
916
"ResourceBase",
1017
"ResourceList",
1118
"StreamOperation",
19+
"TeamScopedResource",
20+
"WorkspaceScopedResource",
1221
"execute_operation",
1322
]

src/codesphere/core/base.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,22 @@ async def _execute(
3232
)
3333

3434

35+
class TeamScopedResource(ResourceBase):
36+
"""Base for managers operating within one team."""
37+
38+
def __init__(self, http_client: APIHttpClient, team_id: int):
39+
super().__init__(http_client)
40+
self.team_id = team_id
41+
42+
43+
class WorkspaceScopedResource(ResourceBase):
44+
"""Base for managers operating within one workspace."""
45+
46+
def __init__(self, http_client: APIHttpClient, workspace_id: int):
47+
super().__init__(http_client)
48+
self.workspace_id = workspace_id
49+
50+
3551
class CamelModel(BaseModel):
3652
model_config = ConfigDict(
3753
alias_generator=to_camel,

src/codesphere/resources/team/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from .domain.resources import (
1+
from .domain import (
22
CustomDomainConfig,
33
Domain,
44
DomainBase,
55
DomainRouting,
66
DomainVerificationStatus,
7+
TeamDomainManager,
78
)
89
from .resources import TeamsResource
910
from .schemas import Team, TeamBase, TeamCreate
@@ -30,6 +31,7 @@
3031
"Team",
3132
"TeamBase",
3233
"TeamCreate",
34+
"TeamDomainManager",
3335
"TeamUsageManager",
3436
"TeamsResource",
3537
"UsageEventsResponse",
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from .resources import TeamDomainManager
2+
from .schemas import (
3+
CustomDomainConfig,
4+
Domain,
5+
DomainBase,
6+
DomainRouting,
7+
DomainVerificationStatus,
8+
RoutingMap,
9+
)
10+
11+
__all__ = [
12+
"CustomDomainConfig",
13+
"Domain",
14+
"DomainBase",
15+
"DomainRouting",
16+
"DomainVerificationStatus",
17+
"RoutingMap",
18+
"TeamDomainManager",
19+
]

src/codesphere/resources/team/domain/manager.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/codesphere/resources/team/domain/operations.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
from ....core.base import ResourceList
44
from ....core.operations import APIOperation
5-
from .resources import Domain
6-
from .schemas import CustomDomainConfig, DomainVerificationStatus
5+
from .schemas import CustomDomainConfig, Domain, DomainVerificationStatus
76

87
_LIST_OP = APIOperation(
98
method="GET",
Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,30 @@
1-
from __future__ import annotations
1+
from ....core.base import TeamScopedResource
2+
from .operations import _CREATE_OP, _GET_OP, _LIST_OP, _UPDATE_OP, _UPDATE_WS_OP
3+
from .schemas import CustomDomainConfig, Domain, DomainRouting, RoutingMap
24

3-
import logging
45

5-
from ....core.base import BoundModel
6-
from ....utils import update_model_fields
7-
from .schemas import (
8-
CustomDomainConfig,
9-
DomainBase,
10-
DomainRouting,
11-
DomainVerificationStatus,
12-
RoutingMap,
13-
)
6+
class TeamDomainManager(TeamScopedResource):
7+
async def list(self) -> list[Domain]:
8+
result = await self._execute(_LIST_OP, team_id=self.team_id)
9+
return result.root
1410

15-
log = logging.getLogger(__name__)
11+
async def get(self, name: str) -> Domain:
12+
return await self._execute(_GET_OP, team_id=self.team_id, name=name)
1613

14+
async def create(self, name: str) -> Domain:
15+
return await self._execute(_CREATE_OP, team_id=self.team_id, name=name)
1716

18-
class Domain(DomainBase, BoundModel):
19-
async def update(self, data: CustomDomainConfig) -> Domain:
20-
from .operations import _UPDATE_OP
21-
22-
response = await self._execute(
23-
_UPDATE_OP, team_id=self.team_id, name=self.name, data=data
17+
async def update(self, name: str, config: CustomDomainConfig) -> Domain:
18+
return await self._execute(
19+
_UPDATE_OP, team_id=self.team_id, name=name, data=config
2420
)
25-
update_model_fields(target=self, source=response)
26-
return response
2721

2822
async def update_workspace_connections(
29-
self, connections: DomainRouting | RoutingMap
23+
self, name: str, connections: DomainRouting | RoutingMap
3024
) -> Domain:
31-
from .operations import _UPDATE_WS_OP
32-
3325
payload = (
3426
connections.root if isinstance(connections, DomainRouting) else connections
3527
)
36-
response = await self._execute(
37-
_UPDATE_WS_OP, team_id=self.team_id, name=self.name, data=payload
28+
return await self._execute(
29+
_UPDATE_WS_OP, team_id=self.team_id, name=name, data=payload
3830
)
39-
update_model_fields(target=self, source=response)
40-
return response
41-
42-
async def verify_status(self) -> DomainVerificationStatus:
43-
from .operations import _VERIFY_OP
44-
45-
response = await self._execute(_VERIFY_OP, team_id=self.team_id, name=self.name)
46-
update_model_fields(target=self.domain_verification_status, source=response)
47-
return response
48-
49-
async def delete(self) -> None:
50-
from .operations import _DELETE_OP
51-
52-
await self._execute(_DELETE_OP, team_id=self.team_id, name=self.name)

src/codesphere/resources/team/domain/schemas.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
from pydantic import Field, RootModel
44

5-
from ....core.base import CamelModel
5+
from ....core.base import BoundModel, CamelModel
6+
from ....utils import update_model_fields
67

78
type RoutingMap = dict[str, list[int]]
89

@@ -48,3 +49,40 @@ class DomainBase(CamelModel):
4849
domain_verification_status: DomainVerificationStatus
4950
custom_config_revision: int | None = None
5051
custom_config: CustomDomainConfig | None = None
52+
53+
54+
class Domain(DomainBase, BoundModel):
55+
async def update(self, data: CustomDomainConfig) -> Domain:
56+
from .operations import _UPDATE_OP
57+
58+
response = await self._execute(
59+
_UPDATE_OP, team_id=self.team_id, name=self.name, data=data
60+
)
61+
update_model_fields(target=self, source=response)
62+
return response
63+
64+
async def update_workspace_connections(
65+
self, connections: DomainRouting | RoutingMap
66+
) -> Domain:
67+
from .operations import _UPDATE_WS_OP
68+
69+
payload = (
70+
connections.root if isinstance(connections, DomainRouting) else connections
71+
)
72+
response = await self._execute(
73+
_UPDATE_WS_OP, team_id=self.team_id, name=self.name, data=payload
74+
)
75+
update_model_fields(target=self, source=response)
76+
return response
77+
78+
async def verify_status(self) -> DomainVerificationStatus:
79+
from .operations import _VERIFY_OP
80+
81+
response = await self._execute(_VERIFY_OP, team_id=self.team_id, name=self.name)
82+
update_model_fields(target=self.domain_verification_status, source=response)
83+
return response
84+
85+
async def delete(self) -> None:
86+
from .operations import _DELETE_OP
87+
88+
await self._execute(_DELETE_OP, team_id=self.team_id, name=self.name)

0 commit comments

Comments
 (0)