Skip to content

Commit fd4d48d

Browse files
Merge pull request #3 from pnnl-int/documentation
Documentation
2 parents 5d06cb3 + a061e7c commit fd4d48d

37 files changed

Lines changed: 1181 additions & 48 deletions

.github/workflows/docs.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Deploy Documentation
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: false
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Install uv
24+
uses: astral-sh/setup-uv@v4
25+
26+
- name: Set up Python
27+
run: uv python install 3.12
28+
29+
- name: Install dependencies
30+
run: uv sync --group docs
31+
32+
- name: Build documentation
33+
run: uv run mkdocs build
34+
35+
- name: Upload artifact
36+
uses: actions/upload-pages-artifact@v3
37+
with:
38+
path: site
39+
40+
deploy:
41+
needs: build
42+
runs-on: ubuntu-latest
43+
environment:
44+
name: github-pages
45+
url: ${{ steps.deployment.outputs.page_url }}
46+
steps:
47+
- name: Deploy to GitHub Pages
48+
id: deployment
49+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ htmlcov/
5353

5454
.env
5555
testprojectJson/
56+
57+
# MkDocs build output
58+
site/

comcheck_api/api/api_services.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@
2323

2424

2525
class COMCheckApiService:
26-
"""COMCheck API service class for interacting with the COM API."""
26+
"""Low-level HTTP service for the COMcheck Web API.
27+
28+
Handles authentication, request construction, response parsing, and
29+
error mapping. Methods accept raw dicts as inputs and return either
30+
raw dicts or validated Pydantic response models.
31+
32+
Can be used as a context manager::
33+
34+
with COMCheckApiService(api_key="key") as svc:
35+
data = svc.get_project("123")
36+
"""
2737

2838
def __init__(self, api_key: str) -> None:
2939
"""Initialize COMCheck API service.

comcheck_api/client/comcheck_client.py

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,26 @@
1818

1919

2020
class COMcheckClient:
21-
"""COMcheck Client class for simplified project operations."""
21+
"""High-level client for the COMcheck Web API.
22+
23+
Provides user-friendly methods that accept Pydantic models as inputs
24+
and return either :class:`~comcheck_api.types.core_types.ComBuilding`
25+
models, primitives, or raw dicts depending on the operation.
26+
27+
Can be used as a context manager to ensure the underlying HTTP
28+
connection is closed::
29+
30+
with COMcheckClient(api_key="your-key") as client:
31+
project = client.get_project("123")
32+
33+
Example:
34+
```python
35+
client = COMcheckClient(api_key="your-key")
36+
projects = client.list_projects()
37+
project = client.get_project(projects[0]["projectId"])
38+
client.close()
39+
```
40+
"""
2241

2342
def __init__(self, api_key: Optional[str] = None) -> None:
2443
"""Initialize COMcheck client.
@@ -116,15 +135,21 @@ def update_project(
116135
) -> ComBuilding | dict[str, Any] | None:
117136
"""Update a project by ID.
118137
138+
The existing project is fetched first to preserve server-assigned IDs
139+
and the ``userProject`` reference. Envelope component IDs that are
140+
``None`` (auto-generated by Pydantic) are stripped before submission.
141+
119142
Args:
120-
project_id: The project ID to update
121-
project_data: The project data to send in the request body
143+
project_id: The project ID to update.
144+
project_data: A ``ComBuilding`` model with the desired state.
145+
mode: ``"python"`` returns a ``ComBuilding`` model;
146+
``"json"`` returns a raw dict.
122147
123148
Returns:
124-
API response data as dictionary
149+
The refreshed project after the update, in the requested format.
125150
126151
Raises:
127-
COMCheckProjectNotFoundError: If project is not found
152+
COMCheckProjectNotFoundError: If the project does not exist.
128153
"""
129154
# Get existing project
130155
old_project = self.get_project(project_id, mode="json")
@@ -222,13 +247,22 @@ def _parse_data(self, data, mode):
222247
def start_run_simulation(
223248
self, project: ComBuilding, project_id: Optional[int] = None
224249
) -> str:
225-
"""Start a simulation run for a given project.
250+
"""Start a compliance simulation run for a project.
251+
252+
If *project_id* is supplied the project is persisted via
253+
:meth:`update_project` before the simulation is launched.
226254
227255
Args:
228-
project: The project data to run the simulation
229-
project_id: Optional project ID, if not provided, project won't be saved
256+
project: The project data to simulate.
257+
project_id: Optional server-side project ID. When given, the
258+
project is saved before the simulation starts.
259+
230260
Returns:
231-
Simulation session ID
261+
The simulation session ID that can be passed to
262+
:meth:`get_simulation_status` and :meth:`get_simulation_result`.
263+
264+
Raises:
265+
COMCheckSimulationError: If the API returns no session data.
232266
"""
233267
logger = logging.getLogger(__name__)
234268

@@ -245,13 +279,16 @@ def start_run_simulation(
245279
return run_result.data.sessionId
246280

247281
def get_simulation_status(self, session_id: str) -> Dict[str, Any]:
248-
"""Get the status of a simulation run by session ID.
282+
"""Get the status of a running or completed simulation.
249283
250284
Args:
251-
session_id: The simulation session ID
285+
session_id: The session ID returned by :meth:`start_run_simulation`.
252286
253287
Returns:
254-
Simulation status information
288+
A dict containing ``sessionId``, ``status``, and optional ``message``.
289+
290+
Raises:
291+
COMCheckSimulationError: If the status cannot be retrieved.
255292
"""
256293
status_response = self._service.get_simulation_status(session_id)
257294
if status_response.data is None:
@@ -261,13 +298,18 @@ def get_simulation_status(self, session_id: str) -> Dict[str, Any]:
261298
return status_response.data.model_dump(mode="python")
262299

263300
def get_simulation_result(self, session_id: str) -> Dict[str, Any]:
264-
"""Get the result of a simulation run by session ID.
301+
"""Get the result metrics of a completed simulation.
265302
266303
Args:
267-
session_id: The simulation session ID
304+
session_id: The session ID returned by :meth:`start_run_simulation`.
268305
269306
Returns:
270-
Simulation result information
307+
A dict containing ``sessionId``, ``performanceRating``,
308+
``energyCreditPerformanceRating``, ``proposedBpf``, and
309+
``baselineBpf``.
310+
311+
Raises:
312+
COMCheckSimulationError: If the result cannot be retrieved.
271313
"""
272314
result_response = self._service.get_simulation_result(session_id)
273315
if result_response.data is None:

comcheck_api/constants/common_constants.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
"""Default project template used to bootstrap new COMcheck projects.
2+
3+
The :data:`PROJECT_TEMPLATE` constant is a fully validated :class:`ComBuilding`
4+
instance pre-populated with sensible defaults for all required sections
5+
(envelope, lighting, HVAC, location, etc.).
6+
"""
7+
18
from comcheck_api.types.core_types import ComBuilding
29

310
PROJECT_TEMPLATE = ComBuilding.model_validate(

comcheck_api/exceptions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,19 @@ def __init__(self, status_code: int, message: str, response_data: str = ""):
2424

2525

2626
class COMCheckValidationError(COMCheckAPIError):
27-
"""Validation failed."""
27+
"""Raised when request or response data fails Pydantic or schema validation."""
2828

2929
pass
3030

3131

3232
class COMCheckConnectionError(COMCheckAPIError):
33-
"""Connection to COMcheck API failed."""
33+
"""Raised when the HTTP client cannot reach the COMcheck API server."""
3434

3535
pass
3636

3737

3838
class COMCheckSimulationError(COMCheckAPIError):
39-
"""Simulation-related error."""
39+
"""Raised when a simulation request fails or returns unexpected data."""
4040

4141
pass
4242

comcheck_api/managers/data_manager.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,14 @@ def __init__(
4343
model_type: Type[BaseModel] | None = None,
4444
schema_path: str | Path = "../schemas/comCheck.schema.json",
4545
):
46-
"""Initialize the data manager."""
46+
"""Initialize the data manager.
47+
48+
Args:
49+
initial_data: Items to pre-populate the manager with.
50+
model_type: Pydantic model class for the managed items.
51+
Falls back to the class-level ``model_type`` attribute.
52+
schema_path: Path to a JSON schema file for validation.
53+
"""
4754
self._data: list[T] = []
4855
self._schema: dict[str, Any] | None = None
4956

@@ -77,7 +84,11 @@ def _initialize_metadata(self, model_type: BaseModel | None = None) -> None:
7784
)
7885

7986
def _initialize_schema(self, schema_path: str | Path) -> None:
80-
"""Load schema if provided"""
87+
"""Load the JSON schema from disk if the file exists.
88+
89+
Args:
90+
schema_path: Path to the JSON schema file.
91+
"""
8192
if schema_path:
8293
schema_path = Path(schema_path)
8394
if schema_path.exists():
@@ -147,11 +158,16 @@ def add_new(self, item: T | dict[str, Any]) -> list[T]:
147158
return self.get_all()
148159

149160
def generate_identifier(self, item: T) -> None:
150-
"""
151-
Ensures the item has a valid and unique identifier.
161+
"""Ensure the item has a valid and unique identifier.
162+
163+
If the identifier is missing, invalid, duplicated, or does not match
164+
the expected prefix, a new unique one is generated via the ID registry.
152165
153-
If the identifier is missing, invalid, duplicated, or does not match the
154-
expected prefix, generate a new unique one.
166+
Args:
167+
item: The item whose identifier should be validated or assigned.
168+
169+
Raises:
170+
Exception: If the item is already present in the managed list.
155171
"""
156172
if any(existing is item for existing in self._data):
157173
raise Exception("Item already exists in managed list")

comcheck_api/types/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@
1717

1818

1919
def _collect_exports(mod: ModuleType) -> List[str]:
20-
"""Collect exportable names from a module."""
20+
"""Collect public names exported by a module.
21+
22+
Uses the module's ``__all__`` list when available; otherwise falls back to
23+
all names that do not start with an underscore.
24+
25+
Args:
26+
mod: The module to inspect.
27+
28+
Returns:
29+
List of exportable name strings.
30+
"""
2131
if hasattr(mod, "__all__"):
2232
return list(mod.__all__)
2333
return [name for name in dir(mod) if not name.startswith("_")]

comcheck_api/types/api_types.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,86 @@
1+
"""Pydantic models for COMcheck API request and response payloads.
2+
3+
These models represent the JSON structures returned by the COMcheck Web API
4+
and are used internally by :class:`~comcheck_api.api.COMCheckApiService` and
5+
:class:`~comcheck_api.client.COMcheckClient` for type-safe deserialization.
6+
"""
7+
18
from typing import Any
29
from pydantic import BaseModel, ConfigDict
310

411

512
class ApiResponse(BaseModel):
13+
"""Base model for all COMcheck API responses.
14+
15+
Attributes:
16+
success: Whether the API call succeeded.
17+
message: Optional human-readable message from the server.
18+
data: Response payload (type varies by endpoint).
19+
errors: List of error strings, if any.
20+
"""
21+
622
success: bool
723
message: str | None = None
824
data: Any = None
925
errors: list[str] | None = None
1026

1127

1228
class SessionInfo(BaseModel):
29+
"""Session metadata returned when a simulation is started.
30+
31+
Attributes:
32+
sessionId: Unique identifier for the simulation session.
33+
"""
34+
1335
model_config = ConfigDict(extra="allow")
1436
sessionId: str
1537

1638

1739
class RunSimulationResponse(ApiResponse):
40+
"""Response from the ``start-run-simulation`` endpoint.
41+
42+
Attributes:
43+
data: Session information for the started simulation, or ``None`` on failure.
44+
"""
45+
1846
data: SessionInfo | None = None
1947

2048

2149
class StatusInfo(BaseModel):
50+
"""Simulation status details.
51+
52+
Attributes:
53+
sessionId: The simulation session identifier.
54+
status: Current status string (e.g. ``"COMPLETED"``, ``"IN_PROGRESS"``).
55+
message: Optional status message from the server.
56+
"""
57+
2258
sessionId: str
2359
status: str
2460
message: str | None = None
2561

2662

2763
class SimulationStatusResponse(ApiResponse):
64+
"""Response from the ``get-status-simulation`` endpoint.
65+
66+
Attributes:
67+
data: Status details for the queried session, or ``None`` on failure.
68+
"""
69+
2870
data: StatusInfo | None = None
2971

3072

3173
class SimulationResultInfo(BaseModel):
74+
"""Simulation result metrics.
75+
76+
Attributes:
77+
sessionId: The simulation session identifier.
78+
performanceRating: Overall performance rating (percentage).
79+
energyCreditPerformanceRating: Energy credit performance rating.
80+
proposedBpf: Proposed building performance factor.
81+
baselineBpf: Baseline building performance factor.
82+
"""
83+
3284
sessionId: str
3385
performanceRating: float | None = None
3486
energyCreditPerformanceRating: float | None = None
@@ -37,4 +89,10 @@ class SimulationResultInfo(BaseModel):
3789

3890

3991
class SimulationResultResponse(ApiResponse):
92+
"""Response from the ``get-result-simulation`` endpoint.
93+
94+
Attributes:
95+
data: Result metrics for the queried session, or ``None`` on failure.
96+
"""
97+
4098
data: SimulationResultInfo | None = None

0 commit comments

Comments
 (0)