Skip to content

Commit 9ac5e1b

Browse files
Merge branch 'docstrings-mypycheck' into 'main'
Docstrings mypycheck See merge request becp/checktool-libraries/comcheckweb-api-python!15
2 parents 136be28 + 0ca1cd7 commit 9ac5e1b

21 files changed

Lines changed: 354 additions & 148 deletions

File tree

comcheck_api/client/comcheck_client.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ def get_project(
7878
project_id: str,
7979
mode: Literal["python", "json"] = "python",
8080
) -> Optional[Union["ComBuilding", Dict[str, Any]]]:
81+
"""Fetch a single project by ID.
82+
83+
Args:
84+
project_id: The project ID to retrieve.
85+
mode: ``"python"`` returns a ``ComBuilding`` model; ``"json"`` returns a raw dict.
86+
87+
Returns:
88+
The project as a ``ComBuilding`` or dict, or ``None`` if not found.
89+
"""
8190
resp = self._service.get_project(project_id)
8291
data = resp.get("data")
8392
if data is not None:
@@ -90,13 +99,13 @@ def get_project(
9099

91100
return self._parse_data(data, mode)
92101

93-
def list_projects(self) -> Dict[str, Any]:
102+
def list_projects(self) -> List[Dict[str, Any]]:
94103
"""Get a list of all projects.
95104
96105
Returns:
97-
API response data as dictionary
106+
API response data as list of project dictionaries
98107
"""
99-
return self._service.get_project_list().get("data", {})
108+
return self._service.get_project_list().get("data", [])
100109

101110
# TODO: return of update_project should be ComBuilding
102111
def update_project(
@@ -195,6 +204,15 @@ def update_project(
195204
return self.get_project(project_id=project_id, mode=mode)
196205

197206
def _parse_data(self, data, mode):
207+
"""Convert raw API data to the requested output format.
208+
209+
Args:
210+
data: Raw dict from the API response, or ``None``.
211+
mode: ``"python"`` wraps data in a ``ComBuilding``; ``"json"`` returns it as-is.
212+
213+
Returns:
214+
A ``ComBuilding``, a raw dict, or ``None`` if ``data`` is ``None``.
215+
"""
198216
if data is None:
199217
return None
200218
if mode == "python":

comcheck_api/constants/building_area_constants.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,31 @@
55
from comcheck_api.types.core_types import WholeBldgUse
66

77
# Default building area structure with interior lighting space
8-
DEFAULT_BUILDING_AREA: WholeBldgUse = WholeBldgUse(**{
9-
"key": str(uuid4()),
10-
"wholeBldgType": "WHOLE_BUILDING_AUTOMOTIVE", # TODO: wholeBldgType is a list of enum, need to define the enum type
11-
"areaDescription": "Automotive Facility",
12-
"constructionType": "NON_RESIDENTIAL",
13-
"floorArea": 1000,
14-
"internalLoad": 0,
15-
"powerDensity": 0.71, # TODO: power density is automatically calculated based on wholeBldgType
16-
"isTenantSpace": False, # TODO: space conditioning is a list of enum, need to define the enum type
17-
"activityUse": [],
18-
"interiorLightingSpace": {
19-
"altExemptType": "EXEMPT_NOT_SET",
20-
"description": "",
21-
"numFixturesAlteredOrAdded": 0,
22-
"postAltTotalWattage": 0,
23-
"preAltNumberFixtures": 0,
24-
"preAltTotalWattage": 0,
25-
"allowanceType": None,
26-
"exemptionType": None,
27-
"allowanceFloorArea": 0,
28-
"rcrFloorToWorkplaneHeight": 0,
29-
"rcrPerimeter": 0,
30-
"rcrWorkplaneToLuminaireHeight": 0,
31-
"fixture": [],
32-
}, # redundant data, but need it for backend call
33-
})
8+
DEFAULT_BUILDING_AREA: WholeBldgUse = WholeBldgUse.model_validate(
9+
{
10+
"key": str(uuid4()),
11+
"wholeBldgType": "WHOLE_BUILDING_AUTOMOTIVE", # TODO: wholeBldgType is a list of enum, need to define the enum type
12+
"areaDescription": "Automotive Facility",
13+
"constructionType": "NON_RESIDENTIAL",
14+
"floorArea": 1000,
15+
"internalLoad": 0,
16+
"powerDensity": 0.71, # TODO: power density is automatically calculated based on wholeBldgType
17+
"isTenantSpace": False, # TODO: space conditioning is a list of enum, need to define the enum type
18+
"activityUse": [],
19+
"interiorLightingSpace": {
20+
"altExemptType": "EXEMPT_NOT_SET",
21+
"description": "",
22+
"numFixturesAlteredOrAdded": 0,
23+
"postAltTotalWattage": 0,
24+
"preAltNumberFixtures": 0,
25+
"preAltTotalWattage": 0,
26+
"allowanceType": None,
27+
"exemptionType": None,
28+
"allowanceFloorArea": 0,
29+
"rcrFloorToWorkplaneHeight": 0,
30+
"rcrPerimeter": 0,
31+
"rcrWorkplaneToLuminaireHeight": 0,
32+
"fixture": [],
33+
}, # redundant data, but need it for backend call
34+
}
35+
)

comcheck_api/constants/common_constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from comcheck_api.types.core_types import ComBuilding
22

3-
PROJECT_TEMPLATE = ComBuilding(
4-
**{
3+
PROJECT_TEMPLATE = ComBuilding.model_validate(
4+
{
55
"control": {
66
"code": "CEZ_IECC2018",
77
"complianceMode": "UA",

comcheck_api/constants/envelope_constants.py

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
)
1616
from comcheck_api.utilities.common import get_random_number
1717

18-
DEFAULT_WINDOW: Window = Window(
19-
**{
18+
DEFAULT_WINDOW: Window = Window.model_validate(
19+
{
2020
"adjacentSpaceBuildingType": "WHOLE_BUILDING_OFFICE",
2121
"adjacentSpaceType": "ADJACENT_SPACE_EXTERIOR",
2222
"allowanceType": "ENV_ALLOWANCE_NONE",
@@ -48,8 +48,8 @@
4848
}
4949
)
5050

51-
DEFAULT_DOOR: Door = Door(
52-
**{
51+
DEFAULT_DOOR: Door = Door.model_validate(
52+
{
5353
"adjacentSpaceBuildingType": None,
5454
"adjacentSpaceType": None,
5555
"allowanceType": None,
@@ -83,8 +83,8 @@
8383
}
8484
)
8585

86-
DEFAULT_SKYLIGHT: Skylight = Skylight(
87-
**{
86+
DEFAULT_SKYLIGHT: Skylight = Skylight.model_validate(
87+
{
8888
"adjacentSpaceType": None,
8989
"allowanceType": None,
9090
"assemblyType": "Skylight:Default Skylight",
@@ -110,8 +110,8 @@
110110
}
111111
)
112112

113-
DEFAULT_ROOF: Roof = Roof(
114-
**{
113+
DEFAULT_ROOF: Roof = Roof.model_validate(
114+
{
115115
"adjacentSpaceType": None,
116116
"allowanceType": None,
117117
"assemblyType": "Roof:Default Roof",
@@ -134,8 +134,8 @@
134134
}
135135
)
136136

137-
DEFAULT_FLOOR: Floor = Floor(
138-
**{
137+
DEFAULT_FLOOR: Floor = Floor.model_validate(
138+
{
139139
"adjacentSpaceType": None,
140140
"allowanceType": None,
141141
"altExemptType": None,
@@ -158,8 +158,8 @@
158158
}
159159
)
160160

161-
DEFAULT_AG_WALL: AgWall = AgWall(
162-
**{
161+
DEFAULT_AG_WALL: AgWall = AgWall.model_validate(
162+
{
163163
"adjacentSpaceType": None,
164164
"agWallConstructionDetailsType": "NONE",
165165
"agWallExteriorFinishDetailsType": None,
@@ -191,8 +191,8 @@
191191
}
192192
)
193193

194-
DEFAULT_THERMAL_BRIDGE: ThermalBridge = ThermalBridge(
195-
**{
194+
DEFAULT_THERMAL_BRIDGE: ThermalBridge = ThermalBridge.model_validate(
195+
{
196196
"chiFactor": 0,
197197
"id": get_random_number(),
198198
"numberOfPoints": 0,
@@ -204,8 +204,8 @@
204204
}
205205
)
206206

207-
DEFAULT_BG_WALL: BgWall = BgWall(
208-
**{
207+
DEFAULT_BG_WALL: BgWall = BgWall.model_validate(
208+
{
209209
"adjacentSpaceBuildingType": None,
210210
"adjacentSpaceType": None,
211211
"allowanceType": None,
@@ -235,13 +235,7 @@
235235
)
236236

237237
DEFAULT_ENVELOPE: Envelope = Envelope(
238-
agWall=[],
239-
bgWall=[],
240-
roof=[],
241-
floor=[],
242-
door=[],
243-
window=[],
244-
skylight=[]
238+
agWall=[], bgWall=[], roof=[], floor=[], door=[], window=[], skylight=[]
245239
)
246240

247241
# TODO: add values to other assemblies

comcheck_api/exceptions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ class COMCheckHTTPError(COMCheckAPIError):
1111
"""HTTP request failed."""
1212

1313
def __init__(self, status_code: int, message: str, response_data: str = ""):
14+
"""Initialize with the HTTP status code, message, and optional response body.
15+
16+
Args:
17+
status_code: The HTTP status code returned by the API.
18+
message: Human-readable error description.
19+
response_data: Raw response body text (empty string if unavailable).
20+
"""
1421
self.status_code = status_code
1522
self.response_data = response_data
1623
super().__init__(f"HTTP {status_code}: {message}")
@@ -38,5 +45,10 @@ class COMCheckProjectNotFoundError(COMCheckAPIError):
3845
"""Project not found."""
3946

4047
def __init__(self, project_id: str):
48+
"""Initialize with the ID of the project that was not found.
49+
50+
Args:
51+
project_id: The project ID that could not be located.
52+
"""
4153
self.project_id = project_id
4254
super().__init__(f"Project with ID '{project_id}' not found")

comcheck_api/managers/components/envelope/ag_wall.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""AgWall (exterior wall) manager for COMcheck projects."""
22

3-
from typing import Union
43
from comcheck_api.types.core_types import (
54
AgWall,
65
Door,
@@ -31,15 +30,9 @@ class AgWallListManager(DataManager[AgWall]):
3130
def add_new_thermal_bridge(
3231
self,
3332
ag_wall: AgWall,
34-
thermal_bridge_type: Union[
35-
ThermalBridgeTypeOptions, str
36-
] = ThermalBridgeTypeOptions.THERMAL_BRIDGE_OTHER,
37-
thermal_bridge_category: Union[
38-
ThermalBridgeCategoryOptions, str
39-
] = ThermalBridgeCategoryOptions.THERMAL_BRIDGE_UNCATEGORIZED,
40-
thermal_bridge_compliance_type: Union[
41-
ThermalBridgeComplianceTypeOptions, str
42-
] = ThermalBridgeComplianceTypeOptions.THERMAL_BRIDGE_NON_PRESCRIPTIVE,
33+
thermal_bridge_type: ThermalBridgeTypeOptions = ThermalBridgeTypeOptions.THERMAL_BRIDGE_OTHER,
34+
thermal_bridge_category: ThermalBridgeCategoryOptions = ThermalBridgeCategoryOptions.THERMAL_BRIDGE_UNCATEGORIZED,
35+
thermal_bridge_compliance_type: ThermalBridgeComplianceTypeOptions = ThermalBridgeComplianceTypeOptions.THERMAL_BRIDGE_NON_PRESCRIPTIVE,
4336
psi_factor: float = 0.0,
4437
chi_factor: float = 0.0,
4538
thermal_bridge_length: float = 0.0,

comcheck_api/managers/data_manager.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ def __init__(
5252
self._initialize_data(initial_data)
5353

5454
def _initialize_metadata(self, model_type: BaseModel | None = None) -> None:
55+
"""Resolve and store the model type and its ID field information.
56+
57+
Args:
58+
model_type: Explicit model class; falls back to the class-level ``model_type``.
59+
60+
Raises:
61+
ValueError: If no model type is available or no ID info is found for it.
62+
"""
5563
self.model_type = model_type or self.__class__.model_type
5664
if self.model_type is None:
5765
raise ValueError(
@@ -77,6 +85,11 @@ def _initialize_schema(self, schema_path: str | Path) -> None:
7785
self._schema = json.load(f)
7886

7987
def _initialize_data(self, initial_data: list[T] = []) -> None:
88+
"""Populate the manager with an initial list of items.
89+
90+
Args:
91+
initial_data: Items to add via ``add_new`` on startup.
92+
"""
8093
for item in initial_data:
8194
self.add_new(item)
8295

@@ -96,9 +109,9 @@ def _validate_item(self, item: T) -> T:
96109
model_instance = item
97110
else:
98111
model_instance = self.model_type.model_validate(item)
99-
112+
100113
return model_instance
101-
114+
102115
def _get_identifier_value(self, item: T) -> Any:
103116
"""Extract the identifier value from an item.
104117
@@ -305,6 +318,15 @@ def modify_one(self, id_value: Any, updates: T | dict[str, Any]) -> T:
305318

306319

307320
def get_model_info(model_class: Type[BaseModel]) -> IdInfo | None:
321+
"""Return the identifier field name and ID prefix for a known model class.
322+
323+
Args:
324+
model_class: The Pydantic model class to look up.
325+
326+
Returns:
327+
An ``IdInfo`` namedtuple with ``identifier`` and ``id_prefix`` fields,
328+
or ``None`` if the class is not registered.
329+
"""
308330
from comcheck_api.types.core_types import (
309331
Door,
310332
Roof,

0 commit comments

Comments
 (0)