Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client cleanup #68

Merged
merged 5 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ jobs:
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Install Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install poetry
uses: abatilo/actions-poetry@v2.0.0
uses: abatilo/actions-poetry@v3
with:
poetry-version: "1.3.1"
poetry-version: 1.8.3

- name: Start Alfalfa
uses: NREL/alfalfa-action@v1
Expand All @@ -36,6 +36,11 @@ jobs:
compose-file-ref: "develop"
worker-scale: 2

- name: Wait for web API
uses: iFaxity/[email protected]
with:
resource: http://localhost

- name: Run tests with poetry and pytest
run: |
poetry install
Expand Down
42 changes: 19 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The purpose of this repository is to provide a standalone client for use with the Alfalfa application. It additionally includes a Historian to quickly/easily enable saving of results from Alfalfa simulations.

# Usage
## Usage

This repo is packaged and hosted on [PyPI here](https://pypi.org/project/alfalfa-client/).

Expand All @@ -11,45 +11,41 @@ pip install alfalfa-client
```

```python
import alfalfa_client.alfalfa_client as ac
import alfalfa_client.historian as ah
from alfalfa_client.alfalfa_client import AlfalfaClient

client = ac.AlfalfaClient
historian = ah.Historian
client = AlfalfaClient("http://localhost")
```

# Setup and Testing
Additional documentation for the functions of `alfalfa-client` can be found [here](https://nrel.github.io/alfalfa-client/).

This repository is setup to use:
## Development

Prerequisites:

- [pyenv](https://github.com/pyenv/pyenv#installation) for managing python versions
- [poetry](https://python-poetry.org/docs/#installation) for managing environment
- [pre-commit](https://pre-commit.com/#install) for managing code styling
- tox for running tests in isolated build environments. See the expected python versions in [tox.ini](./tox.ini)

Assuming poetry is installed and the necessary python versions are installed, the following should exit cleanly:
Cloning and Installing:

```bash
git clone https://github.com/NREL/alfalfa-client.git
cd alfalfa-client
poetry run tox
poetry install
```

This may take some time resolving on the initial run, but subsequent runs should be faster.

See [this gist](https://gist.github.com/corymosiman12/26fb682df2d36b5c9155f344eccbe404) for additional info.

# History
Running Tests:
All `alfalfa-client` tests currently require a running instance of [Alfalfa](https://github.com/NREL/alfalfa) with at least 2 workers.

- The implemented client is previously referred to as Boptest, from the alfalfa/client/boptest.py implementation. It has been ported as a standalone package for easier usage across projects.
```bash
poetry run pytest -m integration
```

# Releasing
## Releasing

1. Merge all branches into develop, make sure tests pass
1. Finish merging PRs into develop
1. Confirm all tests pass
1. Update the version (assume version is 0.1.2): `poetry version 0.1.2`
1. Update the version test file (i.e. my-repo/tests/test_version.py) to match the above version
1. Make sure tests pass: `poetry run tox`
1. Merge develop into main (previously, master), make sure tests pass
1. Create PR to merge version update
1. Rebase develop onto main, make sure tests pass
1. Create a tag: `git tag 0.1.2`
1. Build: `poetry build`
1. Publish `poetry publish` (this will push to pypi)
Expand Down
13 changes: 5 additions & 8 deletions alfalfa_client/alfalfa_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
from urllib.parse import urljoin

import requests
from requests.exceptions import HTTPError
from requests_toolbelt import MultipartEncoder

from alfalfa_client.lib import (
Expand Down Expand Up @@ -81,13 +80,9 @@ def _request(self, endpoint: str, method="POST", parameters=None) -> requests.Re
else:
response = requests.request(method=method, url=self.url + endpoint)

if response.status_code == 400 or response.status_code == 500:
if response.status_code >= 400:
try:
body = response.json()
exception = AlfalfaAPIException(body["message"])
if "payload" in body:
exception.add_payload(json.dumps(body["payload"]))
raise exception
raise AlfalfaAPIException(response)
except json.JSONDecodeError:
pass
response.raise_for_status()
Expand Down Expand Up @@ -129,7 +124,7 @@ def wait(self, run_id: Union[RunID, List[RunID]], desired_status: str, timeout:
while time() - timeout < start_time:
try:
current_status = self.status(run_id)
except HTTPError as e:
except AlfalfaAPIException as e:
if e.response.status_code != 404:
raise e

Expand Down Expand Up @@ -280,6 +275,8 @@ def set_inputs(self, run_id: str, inputs: dict) -> None:
id = self._get_point_translation(run_id, name)
if id:
point_writes[id] = value
else:
raise AlfalfaClientException(f"No Point exists with name {name}")
self._request(f"runs/{run_id}/points/values", method="PUT", parameters={'points': point_writes})

def get_outputs(self, run_id: str) -> dict:
Expand Down
11 changes: 9 additions & 2 deletions alfalfa_client/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
from pathlib import Path
from typing import List

from requests import Response


def parallelize(func):
"""Parallelize a function
Expand Down Expand Up @@ -121,8 +123,13 @@ class AlfalfaWorkerException(AlfalfaException):
class AlfalfaAPIException(AlfalfaException):
"""Wrapper for API errors"""

def add_payload(self, payload):
self.payload = payload
def __init__(self, response: Response, *args: object) -> None:
self.response = response
body = response.json()
super().__init__(body["message"], *args)

if "payload" in body:
self.payload = json.dumps(body["payload"])

def __str__(self) -> str:
if hasattr(self, "payload"):
Expand Down
6 changes: 0 additions & 6 deletions setup.cfg

This file was deleted.

2 changes: 1 addition & 1 deletion tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def pytest_generate_tests(metafunc):
model_dir = Path(os.path.dirname(__file__)) / 'models'
if "model_path" in metafunc.fixturenames:
model_paths = [
model_dir / 'refrig_case_osw'
model_dir / 'small_office'
]

metafunc.parametrize("model_path", model_paths)
Expand Down
4 changes: 0 additions & 4 deletions tests/integration/models/refrig_case_osw/empty.osm

This file was deleted.

Loading
Loading