comcheck-api 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- comcheck_api/DISCLAIMER.md +24 -0
- comcheck_api/__init__.py +99 -0
- comcheck_api/ai/__init__.py +30 -0
- comcheck_api/ai/skill/SKILL.md +285 -0
- comcheck_api/ai/skill/__init__.py +5 -0
- comcheck_api/ai/skill/reference/operations.md +101 -0
- comcheck_api/ai/skill/reference/simulation.md +99 -0
- comcheck_api/ai/skill/reference/types.md +90 -0
- comcheck_api/ai/skill/scripts/__init__.py +1 -0
- comcheck_api/ai/skill/scripts/validate_code.py +210 -0
- comcheck_api/api/__init__.py +1 -0
- comcheck_api/api/api_services.py +273 -0
- comcheck_api/cli.py +136 -0
- comcheck_api/client/__init__.py +1 -0
- comcheck_api/client/comcheck_client.py +335 -0
- comcheck_api/constants/__init__.py +0 -0
- comcheck_api/constants/building_area_constants.py +35 -0
- comcheck_api/constants/common_constants.py +116 -0
- comcheck_api/constants/envelope_constants.py +250 -0
- comcheck_api/defaults.py +150 -0
- comcheck_api/exceptions.py +54 -0
- comcheck_api/introspection.py +188 -0
- comcheck_api/managers/__init__.py +0 -0
- comcheck_api/managers/components/__init__.py +0 -0
- comcheck_api/managers/components/building_area.py +11 -0
- comcheck_api/managers/components/envelope/__init__.py +0 -0
- comcheck_api/managers/components/envelope/ag_wall.py +97 -0
- comcheck_api/managers/components/envelope/bg_wall.py +39 -0
- comcheck_api/managers/components/envelope/door.py +11 -0
- comcheck_api/managers/components/envelope/floor.py +11 -0
- comcheck_api/managers/components/envelope/roof.py +30 -0
- comcheck_api/managers/components/envelope/skylight.py +11 -0
- comcheck_api/managers/components/envelope/window.py +11 -0
- comcheck_api/managers/data_manager.py +369 -0
- comcheck_api/project_operations/__init__.py +8 -0
- comcheck_api/project_operations/project_building_area_operations.py +107 -0
- comcheck_api/project_operations/project_envelope_operations.py +899 -0
- comcheck_api/schemas/comCheck.schema.json +6463 -0
- comcheck_api/types/__init__.py +49 -0
- comcheck_api/types/api_types.py +127 -0
- comcheck_api/types/common_types.py +32 -0
- comcheck_api/types/core_types.py +4198 -0
- comcheck_api/types/custom_base_model.py +314 -0
- comcheck_api/utilities/__init__.py +5 -0
- comcheck_api/utilities/common.py +50 -0
- comcheck_api/utilities/envelope_utilities.py +46 -0
- comcheck_api/utilities/id_registry.py +79 -0
- comcheck_api/utilities/project_utilities.py +60 -0
- comcheck_api/validation.py +64 -0
- comcheck_api-1.0.0.dist-info/METADATA +244 -0
- comcheck_api-1.0.0.dist-info/RECORD +54 -0
- comcheck_api-1.0.0.dist-info/WHEEL +4 -0
- comcheck_api-1.0.0.dist-info/entry_points.txt +2 -0
- comcheck_api-1.0.0.dist-info/licenses/LICENSE +24 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""Envelope constants for COMcheck projects."""
|
|
2
|
+
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
|
|
5
|
+
from comcheck_api.types.core_types import (
|
|
6
|
+
AgWall,
|
|
7
|
+
BgWall,
|
|
8
|
+
Door,
|
|
9
|
+
Envelope,
|
|
10
|
+
Floor,
|
|
11
|
+
Roof,
|
|
12
|
+
Skylight,
|
|
13
|
+
ThermalBridge,
|
|
14
|
+
Window,
|
|
15
|
+
)
|
|
16
|
+
from comcheck_api.utilities.common import get_random_number
|
|
17
|
+
|
|
18
|
+
DEFAULT_WINDOW: Window = Window.model_validate(
|
|
19
|
+
{
|
|
20
|
+
"adjacentSpaceBuildingType": "WHOLE_BUILDING_OFFICE",
|
|
21
|
+
"adjacentSpaceType": "ADJACENT_SPACE_EXTERIOR",
|
|
22
|
+
"allowanceType": "ENV_ALLOWANCE_NONE",
|
|
23
|
+
"altExemptType": None,
|
|
24
|
+
"assemblyType": "Window:Default Window",
|
|
25
|
+
"bldgUseKey": str(uuid4()),
|
|
26
|
+
"constructionType": "NON_RESIDENTIAL",
|
|
27
|
+
"description": "",
|
|
28
|
+
"exemptionType": "ENV_EXEMPTION_NONE",
|
|
29
|
+
"frameType": "METAL",
|
|
30
|
+
"glazingMaterialType": "GLASS_GLAZING_MAT",
|
|
31
|
+
"glazingType": "TRIPLE_PANE",
|
|
32
|
+
"grossArea": 300,
|
|
33
|
+
"isSiteShading": False,
|
|
34
|
+
"orientation": "NORTH",
|
|
35
|
+
"perfDataType": "PERF_TYPE_NFRC",
|
|
36
|
+
"preAltPropShgc": 0.25,
|
|
37
|
+
"preAltPropUval": 0.35,
|
|
38
|
+
"productId": "WIN-001",
|
|
39
|
+
"productType": "FACTORY_ASSEMBLED_WINDOW",
|
|
40
|
+
"propProjectionFactor": 0.5,
|
|
41
|
+
"propShgc": 0.25,
|
|
42
|
+
"propUValue": 0.35,
|
|
43
|
+
"propVt": 0.65,
|
|
44
|
+
"solarType": "CLEAR",
|
|
45
|
+
"windowOpenType": "NON_OPERABLE_WINDOW",
|
|
46
|
+
"cavityRValue": 0,
|
|
47
|
+
"continuousRValue": 0,
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
DEFAULT_DOOR: Door = Door.model_validate(
|
|
52
|
+
{
|
|
53
|
+
"adjacentSpaceBuildingType": None,
|
|
54
|
+
"adjacentSpaceType": None,
|
|
55
|
+
"allowanceType": None,
|
|
56
|
+
"altExemptType": None,
|
|
57
|
+
"assemblyType": "Door:Default Door",
|
|
58
|
+
"bldgUseKey": str(uuid4()),
|
|
59
|
+
"cavityRValue": 0,
|
|
60
|
+
"continuousRValue": 0,
|
|
61
|
+
"constructionType": None,
|
|
62
|
+
"description": None,
|
|
63
|
+
"doorEntranceType": "ENTRANCE_DOOR",
|
|
64
|
+
"doorOpenType": "SWINGING_DOOR",
|
|
65
|
+
"doorType": "INSUL_METAL_DOOR",
|
|
66
|
+
"exemptionType": None,
|
|
67
|
+
"frameType": None,
|
|
68
|
+
"glazingMaterialType": None,
|
|
69
|
+
"glazingType": None,
|
|
70
|
+
"grossArea": 23,
|
|
71
|
+
"isSiteShading": None,
|
|
72
|
+
"orientation": "UNSPECIFIED_ORIENTATION",
|
|
73
|
+
"perfDataType": None,
|
|
74
|
+
"preAltPropShgc": 0,
|
|
75
|
+
"preAltPropUval": None,
|
|
76
|
+
"productId": None,
|
|
77
|
+
"productType": None,
|
|
78
|
+
"propProjectionFactor": 0,
|
|
79
|
+
"propShgc": 0,
|
|
80
|
+
"propUValue": 0.37,
|
|
81
|
+
"propVt": None,
|
|
82
|
+
"solarType": None,
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
DEFAULT_SKYLIGHT: Skylight = Skylight.model_validate(
|
|
87
|
+
{
|
|
88
|
+
"adjacentSpaceType": None,
|
|
89
|
+
"allowanceType": None,
|
|
90
|
+
"assemblyType": "Skylight:Default Skylight",
|
|
91
|
+
"bldgUseKey": "",
|
|
92
|
+
"curbType": "NO_CURB_SKYLIGHT",
|
|
93
|
+
"description": "",
|
|
94
|
+
"exemptionType": None,
|
|
95
|
+
"frameType": "METAL",
|
|
96
|
+
"glazingMaterialType": "GLASS_GLAZING_MAT",
|
|
97
|
+
"glazingType": "DOUBLE_PANE_LOWE",
|
|
98
|
+
"grossArea": 100,
|
|
99
|
+
"isSiteShading": None,
|
|
100
|
+
"orientation": "UNSPECIFIED_ORIENTATION",
|
|
101
|
+
"perfDataType": None,
|
|
102
|
+
"preAltPropShgc": 0,
|
|
103
|
+
"productId": None,
|
|
104
|
+
"productType": None,
|
|
105
|
+
"propProjectionFactor": 0,
|
|
106
|
+
"propShgc": 0.6,
|
|
107
|
+
"propUValue": 0.55,
|
|
108
|
+
"propVt": None,
|
|
109
|
+
"solarType": "TINTED",
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
DEFAULT_ROOF: Roof = Roof.model_validate(
|
|
114
|
+
{
|
|
115
|
+
"adjacentSpaceType": None,
|
|
116
|
+
"allowanceType": None,
|
|
117
|
+
"assemblyType": "Roof:Default Roof",
|
|
118
|
+
"bldgUseKey": str(uuid4()),
|
|
119
|
+
"cavityRValue": 0,
|
|
120
|
+
"continuousRValue": 37,
|
|
121
|
+
"description": "",
|
|
122
|
+
"exemptionType": None,
|
|
123
|
+
"grossArea": 6000,
|
|
124
|
+
"highAlbedoRoofReqType": "HA_ROOF_EXEMPTION_VEGETATED",
|
|
125
|
+
"orientation": "UNSPECIFIED_ORIENTATION",
|
|
126
|
+
"propUValue": 0.26,
|
|
127
|
+
"purlinSpacing": 0,
|
|
128
|
+
"roofInsulType": None,
|
|
129
|
+
"roofType": "ABOVE_DECK_ROOF",
|
|
130
|
+
"skylight": [],
|
|
131
|
+
"solarReflectance": 0,
|
|
132
|
+
"solarReflectanceIndex": 0,
|
|
133
|
+
"thermalEmittance": 0,
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
DEFAULT_FLOOR: Floor = Floor.model_validate(
|
|
138
|
+
{
|
|
139
|
+
"adjacentSpaceType": None,
|
|
140
|
+
"allowanceType": None,
|
|
141
|
+
"altExemptType": None,
|
|
142
|
+
"assemblyType": "Floor:Default Floor",
|
|
143
|
+
"bldgUseKey": str(uuid4()),
|
|
144
|
+
"cavityRValue": 0,
|
|
145
|
+
"constructionType": None,
|
|
146
|
+
"continuousRValue": 15,
|
|
147
|
+
"depthOfInsulation": 4,
|
|
148
|
+
"description": "",
|
|
149
|
+
"exemptionType": None,
|
|
150
|
+
"floorExposedFrameType": None,
|
|
151
|
+
"floorType": "HEATED_SLAB_ON_GRADE",
|
|
152
|
+
"grossArea": 320,
|
|
153
|
+
"hasEdgeInsul": None,
|
|
154
|
+
"insulationPosition": "VERTICAL",
|
|
155
|
+
"orientation": "UNSPECIFIED_ORIENTATION",
|
|
156
|
+
"propUValue": 0.72,
|
|
157
|
+
"slabFullInsulBelowMinRValue": 0,
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
DEFAULT_AG_WALL: AgWall = AgWall.model_validate(
|
|
162
|
+
{
|
|
163
|
+
"adjacentSpaceType": None,
|
|
164
|
+
"agWallConstructionDetailsType": "NONE",
|
|
165
|
+
"agWallExteriorFinishDetailsType": None,
|
|
166
|
+
"allowanceType": None,
|
|
167
|
+
"assemblyType": "Ext Wall:Default Exterior Wall",
|
|
168
|
+
"bldgUseKey": str(uuid4()),
|
|
169
|
+
"cavityRValue": 20,
|
|
170
|
+
"cmuType": None,
|
|
171
|
+
"concreteDensity": 0,
|
|
172
|
+
"concreteThickness": 0,
|
|
173
|
+
"continuousRValue": 10,
|
|
174
|
+
"description": "",
|
|
175
|
+
"door": [],
|
|
176
|
+
"effectiveUFactor": 0.054,
|
|
177
|
+
"exemptionType": None,
|
|
178
|
+
"furringType": None,
|
|
179
|
+
"grossArea": 4800,
|
|
180
|
+
"heatCapacity": 0,
|
|
181
|
+
"insulationPosition": None,
|
|
182
|
+
"nextToUncondSpace": None,
|
|
183
|
+
"orientation": "NORTH",
|
|
184
|
+
"otherWallType": "NONE",
|
|
185
|
+
"propUValue": 0.048,
|
|
186
|
+
"thermalBridge": [],
|
|
187
|
+
"thermalBridgeAdjustmentFactor": None,
|
|
188
|
+
"thermalBridgeExceptionType": "THERMAL_BRIDGE_EXCEPTION_NONE",
|
|
189
|
+
"wallType": "METAL_FRAME_24_AG_WALL",
|
|
190
|
+
"window": [],
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
DEFAULT_THERMAL_BRIDGE: ThermalBridge = ThermalBridge.model_validate(
|
|
195
|
+
{
|
|
196
|
+
"chiFactor": 0,
|
|
197
|
+
"id": get_random_number(),
|
|
198
|
+
"numberOfPoints": 0,
|
|
199
|
+
"psiFactor": 0.177,
|
|
200
|
+
"thermalBridgeCategory": "THERMAL_BRIDGE_LINEAR",
|
|
201
|
+
"thermalBridgeComplianceType": "THERMAL_BRIDGE_PRESCRIPTIVE",
|
|
202
|
+
"thermalBridgeLength": 100,
|
|
203
|
+
"thermalBridgeType": "THERMAL_BRIDGE_FLOOR_TO_WALL_INTERSECTION",
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
DEFAULT_BG_WALL: BgWall = BgWall.model_validate(
|
|
208
|
+
{
|
|
209
|
+
"adjacentSpaceBuildingType": None,
|
|
210
|
+
"adjacentSpaceType": None,
|
|
211
|
+
"allowanceType": None,
|
|
212
|
+
"altExemptType": None,
|
|
213
|
+
"assemblyType": "Basement:Default Basement",
|
|
214
|
+
"bldgUseKey": "",
|
|
215
|
+
"cavityRValue": 20,
|
|
216
|
+
"cmuType": None,
|
|
217
|
+
"concreteDensity": 95, # TODO: Generated value
|
|
218
|
+
"concreteThickness": 6, # TODO: Generated value, type is not correct in coreTypes
|
|
219
|
+
"constructionType": None,
|
|
220
|
+
"continuousRValue": 10,
|
|
221
|
+
"description": "",
|
|
222
|
+
"door": [],
|
|
223
|
+
"exemptionType": None,
|
|
224
|
+
"furringType": "WOOD_FURRING",
|
|
225
|
+
"grossArea": 3000,
|
|
226
|
+
"heatCapacity": 0,
|
|
227
|
+
"insulationPosition": None,
|
|
228
|
+
"orientation": "NORTH",
|
|
229
|
+
"propUValue": 0.037,
|
|
230
|
+
"wallHeight": 9,
|
|
231
|
+
"wallHeightBelowGrade": 6,
|
|
232
|
+
"wallType": "CONCRETE_BG_WALL",
|
|
233
|
+
"window": [],
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
DEFAULT_ENVELOPE: Envelope = Envelope(
|
|
238
|
+
agWall=[], bgWall=[], roof=[], floor=[], door=[], window=[], skylight=[]
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# TODO: add values to other assemblies
|
|
242
|
+
DEFAULT_ASSEMBLIES = {
|
|
243
|
+
"Window": DEFAULT_WINDOW,
|
|
244
|
+
"Roof": DEFAULT_ROOF,
|
|
245
|
+
"Skylight": DEFAULT_SKYLIGHT,
|
|
246
|
+
"AgWall": DEFAULT_AG_WALL,
|
|
247
|
+
"BgWall": DEFAULT_BG_WALL,
|
|
248
|
+
"Door": DEFAULT_DOOR,
|
|
249
|
+
"Floor": DEFAULT_FLOOR,
|
|
250
|
+
}
|
comcheck_api/defaults.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Module for project default templates/values."""
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
|
|
5
|
+
from comcheck_api.constants.building_area_constants import DEFAULT_BUILDING_AREA
|
|
6
|
+
from comcheck_api.constants.envelope_constants import (
|
|
7
|
+
DEFAULT_AG_WALL,
|
|
8
|
+
DEFAULT_BG_WALL,
|
|
9
|
+
DEFAULT_DOOR,
|
|
10
|
+
DEFAULT_FLOOR,
|
|
11
|
+
DEFAULT_ROOF,
|
|
12
|
+
DEFAULT_SKYLIGHT,
|
|
13
|
+
DEFAULT_THERMAL_BRIDGE,
|
|
14
|
+
DEFAULT_WINDOW,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from comcheck_api.constants.common_constants import PROJECT_TEMPLATE
|
|
18
|
+
|
|
19
|
+
# from comcheck_api.constants.lighting_constants import DEFAULT_FIXTURE_SCHEDULE
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_default_project_template():
|
|
23
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.ComBuilding` template.
|
|
24
|
+
|
|
25
|
+
The template is pre-populated with sensible defaults for location
|
|
26
|
+
(Boulder, CO), envelope, lighting, HVAC, and other required sections.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
A new ``ComBuilding`` instance ready to be customized.
|
|
30
|
+
"""
|
|
31
|
+
return copy.deepcopy(PROJECT_TEMPLATE)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_default_building_area_template():
|
|
35
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.WholeBldgUse` template.
|
|
36
|
+
|
|
37
|
+
Defaults to an *Automotive Facility* with 1 000 sq ft floor area
|
|
38
|
+
and interior lighting space initialized.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
A new ``WholeBldgUse`` instance.
|
|
42
|
+
"""
|
|
43
|
+
return copy.deepcopy(DEFAULT_BUILDING_AREA)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_default_roof_template():
|
|
47
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.Roof` template.
|
|
48
|
+
|
|
49
|
+
Defaults to an above-deck roof with 6 000 sq ft gross area and
|
|
50
|
+
R-37 continuous insulation.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
A new ``Roof`` instance.
|
|
54
|
+
"""
|
|
55
|
+
return copy.deepcopy(DEFAULT_ROOF)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_default_ag_wall_template():
|
|
59
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.AgWall` template.
|
|
60
|
+
|
|
61
|
+
Defaults to a metal-frame 24-inch above-grade wall with 4 800 sq ft
|
|
62
|
+
gross area, R-20 cavity / R-10 continuous insulation.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
A new ``AgWall`` instance.
|
|
66
|
+
"""
|
|
67
|
+
return copy.deepcopy(DEFAULT_AG_WALL)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_default_floor_template():
|
|
71
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.Floor` template.
|
|
72
|
+
|
|
73
|
+
Defaults to a heated slab-on-grade floor with 320 sq ft gross area
|
|
74
|
+
and R-15 continuous insulation.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
A new ``Floor`` instance.
|
|
78
|
+
"""
|
|
79
|
+
return copy.deepcopy(DEFAULT_FLOOR)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_default_bg_wall_template():
|
|
83
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.BgWall` template.
|
|
84
|
+
|
|
85
|
+
Defaults to a concrete below-grade wall with 3 000 sq ft gross area,
|
|
86
|
+
R-20 cavity / R-10 continuous insulation, and wood furring.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
A new ``BgWall`` instance.
|
|
90
|
+
"""
|
|
91
|
+
return copy.deepcopy(DEFAULT_BG_WALL)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_default_skylight_template():
|
|
95
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.Skylight` template.
|
|
96
|
+
|
|
97
|
+
Defaults to a no-curb, double-pane low-E skylight with 100 sq ft
|
|
98
|
+
gross area.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
A new ``Skylight`` instance.
|
|
102
|
+
"""
|
|
103
|
+
return copy.deepcopy(DEFAULT_SKYLIGHT)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_default_window_template():
|
|
107
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.Window` template.
|
|
108
|
+
|
|
109
|
+
Defaults to a triple-pane, non-operable, metal-frame window with
|
|
110
|
+
300 sq ft gross area and NFRC performance data.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
A new ``Window`` instance.
|
|
114
|
+
"""
|
|
115
|
+
return copy.deepcopy(DEFAULT_WINDOW)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_default_door_template():
|
|
119
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.Door` template.
|
|
120
|
+
|
|
121
|
+
Defaults to a swinging, insulated metal entrance door with 23 sq ft
|
|
122
|
+
gross area.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
A new ``Door`` instance.
|
|
126
|
+
"""
|
|
127
|
+
return copy.deepcopy(DEFAULT_DOOR)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_default_thermal_bridge_template():
|
|
131
|
+
"""Return a deep copy of the default :class:`~comcheck_api.types.core_types.ThermalBridge` template.
|
|
132
|
+
|
|
133
|
+
Defaults to a prescriptive linear floor-to-wall intersection thermal
|
|
134
|
+
bridge with a psi factor of 0.177 and 100 ft length.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
A new ``ThermalBridge`` instance.
|
|
138
|
+
"""
|
|
139
|
+
return copy.deepcopy(DEFAULT_THERMAL_BRIDGE)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_default_fixture_schedule_template():
|
|
143
|
+
"""Return a default fixture schedule template with a unique key.
|
|
144
|
+
|
|
145
|
+
.. warning::
|
|
146
|
+
Not yet implemented — raises :exc:`NotImplementedError`.
|
|
147
|
+
"""
|
|
148
|
+
# TODO: Implement when DEFAULT_FIXTURE_SCHEDULE constant is available
|
|
149
|
+
# return {**DEFAULT_FIXTURE_SCHEDULE, "scheduleFixtureKey": str(uuid4())}
|
|
150
|
+
raise NotImplementedError("DEFAULT_FIXTURE_SCHEDULE constant not yet implemented")
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Custom exceptions for COMcheck API client."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class COMCheckAPIError(Exception):
|
|
5
|
+
"""Base exception for COMcheck API errors."""
|
|
6
|
+
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class COMCheckHTTPError(COMCheckAPIError):
|
|
11
|
+
"""HTTP request failed."""
|
|
12
|
+
|
|
13
|
+
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
|
+
"""
|
|
21
|
+
self.status_code = status_code
|
|
22
|
+
self.response_data = response_data
|
|
23
|
+
super().__init__(f"HTTP {status_code}: {message}")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class COMCheckValidationError(COMCheckAPIError):
|
|
27
|
+
"""Raised when request or response data fails Pydantic or schema validation."""
|
|
28
|
+
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class COMCheckConnectionError(COMCheckAPIError):
|
|
33
|
+
"""Raised when the HTTP client cannot reach the COMcheck API server."""
|
|
34
|
+
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class COMCheckSimulationError(COMCheckAPIError):
|
|
39
|
+
"""Raised when a simulation request fails or returns unexpected data."""
|
|
40
|
+
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class COMCheckProjectNotFoundError(COMCheckAPIError):
|
|
45
|
+
"""Project not found."""
|
|
46
|
+
|
|
47
|
+
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
|
+
"""
|
|
53
|
+
self.project_id = project_id
|
|
54
|
+
super().__init__(f"Project with ID '{project_id}' not found")
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""Introspection helpers over the installed SDK.
|
|
2
|
+
|
|
3
|
+
Discoverable from the package root:
|
|
4
|
+
|
|
5
|
+
>>> from comcheck_api import list_operations, lookup_type
|
|
6
|
+
>>> ops = list_operations()
|
|
7
|
+
>>> schema = lookup_type("ComBuilding")
|
|
8
|
+
|
|
9
|
+
``list_operations`` enumerates the public functions in the project
|
|
10
|
+
operation modules. ``lookup_type`` reflects a Pydantic model or enum
|
|
11
|
+
from :mod:`comcheck_api.types`. Both return Pydantic models with
|
|
12
|
+
typed fields so IDEs and type checkers can see the shape.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import inspect
|
|
18
|
+
from typing import Any, Literal, get_args, get_origin
|
|
19
|
+
|
|
20
|
+
import pydantic
|
|
21
|
+
from pydantic import BaseModel, ConfigDict
|
|
22
|
+
|
|
23
|
+
from comcheck_api import (
|
|
24
|
+
project_building_area_operations,
|
|
25
|
+
project_envelope_operations,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
_OP_MODULES = {
|
|
29
|
+
"building_area": project_building_area_operations,
|
|
30
|
+
"envelope": project_envelope_operations,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class OperationInfo(BaseModel):
|
|
35
|
+
"""One public function in a project-operation module."""
|
|
36
|
+
|
|
37
|
+
group: str
|
|
38
|
+
module: str
|
|
39
|
+
name: str
|
|
40
|
+
signature: str
|
|
41
|
+
summary: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FieldSchema(BaseModel):
|
|
45
|
+
"""One field of a Pydantic model."""
|
|
46
|
+
|
|
47
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
48
|
+
|
|
49
|
+
name: str
|
|
50
|
+
type: str
|
|
51
|
+
required: bool
|
|
52
|
+
default: Any | None
|
|
53
|
+
description: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class EnumMember(BaseModel):
|
|
57
|
+
name: str
|
|
58
|
+
value: str
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TypeSchema(BaseModel):
|
|
62
|
+
"""Reflected schema of a Pydantic model or StrEnum."""
|
|
63
|
+
|
|
64
|
+
name: str
|
|
65
|
+
kind: Literal["model", "enum"]
|
|
66
|
+
doc: str
|
|
67
|
+
fields: list[FieldSchema] = []
|
|
68
|
+
members: list[EnumMember] = []
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def list_operations() -> list[OperationInfo]:
|
|
72
|
+
"""Discover public functions in the project operation modules.
|
|
73
|
+
|
|
74
|
+
Discovered live via :mod:`inspect` so the list always matches the
|
|
75
|
+
installed SDK version.
|
|
76
|
+
"""
|
|
77
|
+
out: list[OperationInfo] = []
|
|
78
|
+
for group, mod in _OP_MODULES.items():
|
|
79
|
+
for name, fn in inspect.getmembers(mod, inspect.isfunction):
|
|
80
|
+
if name.startswith("_"):
|
|
81
|
+
continue
|
|
82
|
+
if fn.__module__ != mod.__name__:
|
|
83
|
+
continue # skip re-exports
|
|
84
|
+
doc = inspect.getdoc(fn) or ""
|
|
85
|
+
summary = doc.split("\n", 1)[0]
|
|
86
|
+
out.append(
|
|
87
|
+
OperationInfo(
|
|
88
|
+
group=group,
|
|
89
|
+
module=fn.__module__,
|
|
90
|
+
name=name,
|
|
91
|
+
signature=f"{name}{inspect.signature(fn)}",
|
|
92
|
+
summary=summary,
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
return out
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def lookup_type(name: str) -> TypeSchema | None:
|
|
99
|
+
"""Reflect a Pydantic model or enum from :mod:`comcheck_api.types`.
|
|
100
|
+
|
|
101
|
+
Returns ``None`` if no matching type is found. Lookup is
|
|
102
|
+
case-insensitive as a fallback.
|
|
103
|
+
"""
|
|
104
|
+
from comcheck_api import types as cc_types
|
|
105
|
+
|
|
106
|
+
obj = getattr(cc_types, name, None)
|
|
107
|
+
if obj is None:
|
|
108
|
+
lower = name.lower()
|
|
109
|
+
for cand in dir(cc_types):
|
|
110
|
+
if cand.lower() == lower:
|
|
111
|
+
obj = getattr(cc_types, cand)
|
|
112
|
+
name = cand
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
if obj is None:
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
if isinstance(obj, type) and issubclass(obj, pydantic.BaseModel):
|
|
119
|
+
return _describe_model(name, obj)
|
|
120
|
+
|
|
121
|
+
if isinstance(obj, type):
|
|
122
|
+
members = [
|
|
123
|
+
EnumMember(name=member.name, value=str(member.value))
|
|
124
|
+
for member in getattr(obj, "__members__", {}).values()
|
|
125
|
+
]
|
|
126
|
+
if members:
|
|
127
|
+
return TypeSchema(
|
|
128
|
+
name=name,
|
|
129
|
+
kind="enum",
|
|
130
|
+
doc=inspect.getdoc(obj) or "",
|
|
131
|
+
members=members,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
return None
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _describe_model(name: str, model: type[pydantic.BaseModel]) -> TypeSchema:
|
|
138
|
+
fields = [
|
|
139
|
+
FieldSchema(
|
|
140
|
+
name=fname,
|
|
141
|
+
type=_render_type(finfo.annotation),
|
|
142
|
+
required=finfo.is_required(),
|
|
143
|
+
default=_render_default(finfo),
|
|
144
|
+
description=finfo.description or "",
|
|
145
|
+
)
|
|
146
|
+
for fname, finfo in model.model_fields.items()
|
|
147
|
+
]
|
|
148
|
+
return TypeSchema(
|
|
149
|
+
name=name,
|
|
150
|
+
kind="model",
|
|
151
|
+
doc=inspect.getdoc(model) or "",
|
|
152
|
+
fields=fields,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _render_type(annotation: Any) -> str:
|
|
157
|
+
if annotation is None or annotation is type(None):
|
|
158
|
+
return "None"
|
|
159
|
+
origin = get_origin(annotation)
|
|
160
|
+
if origin is None:
|
|
161
|
+
return getattr(annotation, "__name__", str(annotation))
|
|
162
|
+
args = ", ".join(_render_type(a) for a in get_args(annotation))
|
|
163
|
+
origin_name = getattr(origin, "__name__", str(origin))
|
|
164
|
+
return f"{origin_name}[{args}]"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _render_default(finfo: pydantic.fields.FieldInfo) -> Any:
|
|
168
|
+
if finfo.is_required():
|
|
169
|
+
return None
|
|
170
|
+
default = finfo.default
|
|
171
|
+
if default is pydantic.fields.PydanticUndefined:
|
|
172
|
+
return None
|
|
173
|
+
try:
|
|
174
|
+
if isinstance(default, pydantic.BaseModel):
|
|
175
|
+
return default.model_dump(mode="json")
|
|
176
|
+
return default
|
|
177
|
+
except Exception: # noqa: BLE001
|
|
178
|
+
return repr(default)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
__all__ = [
|
|
182
|
+
"OperationInfo",
|
|
183
|
+
"FieldSchema",
|
|
184
|
+
"EnumMember",
|
|
185
|
+
"TypeSchema",
|
|
186
|
+
"list_operations",
|
|
187
|
+
"lookup_type",
|
|
188
|
+
]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Building area list manager for COMcheck projects."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from comcheck_api.types.core_types import WholeBldgUse
|
|
6
|
+
from comcheck_api.managers.data_manager import DataManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BuildingAreaListManager(DataManager[WholeBldgUse]):
|
|
10
|
+
"""Manager for WholeBldgUse (building area) items."""
|
|
11
|
+
model_type = WholeBldgUse
|
|
File without changes
|