Skip to content

Commit cbce32e

Browse files
authored
feat(model-export): provide model methods to export data (#40)
* feat(model-export): provide model methods to export data
1 parent 8ad8739 commit cbce32e

File tree

6 files changed

+343
-14
lines changed

6 files changed

+343
-14
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies = [
1717
"pydantic-settings>=2.11.0",
1818
"python-dateutil>=2.9.0.post0",
1919
"python-dotenv>=1.2.1",
20+
"pyyaml>=6.0.2",
2021
"typing-extensions>=4.14.0",
2122
"urllib3>=2.4.0",
2223
]

src/codesphere/core/base.py

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
from typing import Generic, List, TypeVar
1+
from typing import Any, Generic, List, Literal, TypeVar
2+
3+
import yaml
24
from pydantic import BaseModel, ConfigDict, RootModel
35
from pydantic.alias_generators import to_camel
46

57
from ..http_client import APIHttpClient
68
from .handler import _APIOperationExecutor
79

8-
ModelT = TypeVar("ModelT")
10+
ModelT = TypeVar("ModelT", bound=BaseModel)
911

1012

1113
class ResourceBase(_APIOperationExecutor):
@@ -20,6 +22,58 @@ class CamelModel(BaseModel):
2022
serialize_by_alias=True,
2123
)
2224

25+
def to_dict(
26+
self, *, by_alias: bool = True, exclude_none: bool = False
27+
) -> dict[str, Any]:
28+
"""Export model as a Python dictionary.
29+
30+
Args:
31+
by_alias: Use camelCase keys (API format) if True, snake_case if False.
32+
exclude_none: Exclude fields with None values if True.
33+
34+
Returns:
35+
Dictionary representation of the model.
36+
"""
37+
return self.model_dump(by_alias=by_alias, exclude_none=exclude_none)
38+
39+
def to_json(
40+
self,
41+
*,
42+
by_alias: bool = True,
43+
exclude_none: bool = False,
44+
indent: int | None = None,
45+
) -> str:
46+
"""Export model as a JSON string.
47+
48+
Args:
49+
by_alias: Use camelCase keys (API format) if True, snake_case if False.
50+
exclude_none: Exclude fields with None values if True.
51+
indent: Number of spaces for indentation. None for compact output.
52+
53+
Returns:
54+
JSON string representation of the model.
55+
"""
56+
return self.model_dump_json(
57+
by_alias=by_alias, exclude_none=exclude_none, indent=indent
58+
)
59+
60+
def to_yaml(self, *, by_alias: bool = True, exclude_none: bool = False) -> str:
61+
"""Export model as a YAML string.
62+
63+
Args:
64+
by_alias: Use camelCase keys (API format) if True, snake_case if False.
65+
exclude_none: Exclude fields with None values if True.
66+
67+
Returns:
68+
YAML string representation of the model.
69+
"""
70+
data = self.model_dump(
71+
by_alias=by_alias, exclude_none=exclude_none, mode="json"
72+
)
73+
return yaml.safe_dump(
74+
data, default_flow_style=False, allow_unicode=True, sort_keys=False
75+
)
76+
2377

2478
class ResourceList(RootModel[List[ModelT]], Generic[ModelT]):
2579
root: List[ModelT]
@@ -32,3 +86,67 @@ def __getitem__(self, item):
3286

3387
def __len__(self):
3488
return len(self.root)
89+
90+
def to_list(
91+
self,
92+
*,
93+
by_alias: bool = True,
94+
exclude_none: bool = False,
95+
mode: Literal["python", "json"] = "python",
96+
) -> list[dict[str, Any]]:
97+
"""Export all items as a list of dictionaries.
98+
99+
Args:
100+
by_alias: Use camelCase keys (API format) if True, snake_case if False.
101+
exclude_none: Exclude fields with None values if True.
102+
mode: Serialization mode. "python" returns native Python objects,
103+
"json" returns JSON-compatible types (e.g., datetime as ISO string).
104+
105+
Returns:
106+
List of dictionary representations.
107+
"""
108+
return [
109+
item.model_dump(by_alias=by_alias, exclude_none=exclude_none, mode=mode)
110+
for item in self.root
111+
]
112+
113+
def to_json(
114+
self,
115+
*,
116+
by_alias: bool = True,
117+
exclude_none: bool = False,
118+
indent: int | None = None,
119+
) -> str:
120+
"""Export all items as a JSON array string.
121+
122+
Args:
123+
by_alias: Use camelCase keys (API format) if True, snake_case if False.
124+
exclude_none: Exclude fields with None values if True.
125+
indent: Number of spaces for indentation. None for compact output.
126+
127+
Returns:
128+
JSON array string representation.
129+
"""
130+
import json
131+
132+
return json.dumps(
133+
self.to_list(by_alias=by_alias, exclude_none=exclude_none, mode="json"),
134+
indent=indent,
135+
)
136+
137+
def to_yaml(self, *, by_alias: bool = True, exclude_none: bool = False) -> str:
138+
"""Export all items as a YAML string.
139+
140+
Args:
141+
by_alias: Use camelCase keys (API format) if True, snake_case if False.
142+
exclude_none: Exclude fields with None values if True.
143+
144+
Returns:
145+
YAML string representation.
146+
"""
147+
return yaml.safe_dump(
148+
self.to_list(by_alias=by_alias, exclude_none=exclude_none, mode="json"),
149+
default_flow_style=False,
150+
allow_unicode=True,
151+
sort_keys=False,
152+
)

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
from typing import List, Union
2+
23
from pydantic import Field
34

45
from ....core.base import ResourceList
56
from ....core.handler import _APIOperationExecutor
67
from ....core.operations import AsyncCallable
78
from ....http_client import APIHttpClient
8-
from .schemas import CustomDomainConfig, DomainRouting, RoutingMap
9-
from .resources import Domain
109
from .operations import _CREATE_OP, _GET_OP, _LIST_OP, _UPDATE_OP, _UPDATE_WS_OP
10+
from .resources import Domain
11+
from .schemas import CustomDomainConfig, DomainRouting, RoutingMap
1112

1213

1314
class TeamDomainManager(_APIOperationExecutor):
14-
"""
15-
Verwaltet Domains im Kontext eines spezifischen Teams.
16-
Zugriff typischerweise über 'team.domains'.
17-
"""
18-
1915
def __init__(self, http_client: APIHttpClient, team_id: int):
2016
self._http_client = http_client
2117
self.team_id = team_id

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
2+
23
from typing import Dict, List, Optional, TypeAlias
4+
35
from pydantic import Field, RootModel
46

57
from ....core.base import CamelModel
@@ -31,10 +33,6 @@ class CustomDomainConfig(CamelModel):
3133

3234

3335
class DomainRouting(RootModel):
34-
"""
35-
Helper class to build the routing configuration.
36-
"""
37-
3836
root: RoutingMap = Field(default_factory=dict)
3937

4038
def add(self, path: str, workspace_ids: List[int]) -> DomainRouting:

0 commit comments

Comments
 (0)