Skip to content

Commit

Permalink
Fix building list and client information (#17)
Browse files Browse the repository at this point in the history
* updatin seed client to set seed org name
* add get_property and get_property_view, return all results for get_buildings
* fix client_information api
* fix mypy
* only build pull requests and dev/main push
* seed_org_name not none
* test both property results
* fix comment about filter

Co-authored-by: kflemin <[email protected]>
  • Loading branch information
nllong and kflemin authored Jan 6, 2023
1 parent 9b02f54 commit e9c3ae5
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 42 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name: CI
on:
pull_request:
push:
branches:
- "develop"
- "main"

jobs:
test:
Expand Down
1 change: 0 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ Within Python you can use the client like this:

.. code-block:: python
import pyseed
from pathlib import Path
from pyseed.seed_client import SeedClient
Expand Down
111 changes: 74 additions & 37 deletions pyseed/seed_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,17 @@ def __init__(
)

# favor the connection params over the config file
self.payload = {}
if connection_params:
# the connetion params are simply squashed on SEEDReadWriteClient init
payload = connection_params
self.payload = connection_params
elif connection_config_filepath:
payload = SeedClientWrapper.read_connection_config_file(
self.payload = SeedClientWrapper.read_connection_config_file(
connection_config_filepath
)
# read in from config file

self.client = SEEDReadWriteClient(organization_id, **payload)
self.client = SEEDReadWriteClient(organization_id, **self.payload)

@classmethod
def read_connection_config_file(cls, filepath: Path) -> dict:
Expand All @@ -114,7 +115,8 @@ def read_connection_config_file(cls, filepath: Path) -> dict:
"username": "[email protected]",
"api_key": "1b5ea1ee220c8628789c61d66253d90398e6ad03",
"port": 8000,
"use_ssl": false
"use_ssl": false,
"seed_org_name: "test-org"
}
Args:
Expand All @@ -139,6 +141,35 @@ def __init__(
) -> None:
super().__init__(organization_id, connection_params, connection_config_filepath)

# set org if you can
if self.payload and self.payload.get('seed_org_name', None):
self.get_org_by_name(self.payload['seed_org_name'], set_org_id=True)

def get_org_id(self) -> int:
"""Return the org ID that is set"""
return self.client.org_id

def get_org_by_name(self, org_name: str, set_org_id: bool = False) -> dict:
"""Set the current organization by name.
Args:
org_name (str): name of the organization to set
set_org_id (bool): set the org_id on the object for later use. Defaults to None.
Returns:
dict: {
org data
}
"""
orgs = self.get_organizations()
for org in orgs:
if org["name"] == org_name:
if set_org_id:
self.client.org_id = org["id"]
return org

raise ValueError(f"Organization '{org_name}' not found")

def instance_information(self) -> dict:
"""Return the instance information.
Expand Down Expand Up @@ -179,21 +210,25 @@ def get_organizations(self, brief: bool = True) -> Dict:
)
return orgs

def get_buildings(self) -> list:
self.client.list(endpoint="properties", data_name="pagination", per_page=1)[
"total"
]
buildings = self.client.list(
endpoint="properties",
data_name="results",
per_page=100,
cycle=self.cycle_id,
)
def get_buildings(self) -> List[dict]:
total_qry = self.client.list(endpoint="properties", data_name="pagination", per_page=100)

# print(f" total: {total_qry}")
# step through each page of the results
buildings: List[dict] = []
for i in range(1, total_qry['num_pages'] + 1):
buildings = buildings + self.client.list(
endpoint="properties",
data_name="results",
per_page=100,
page=i,
cycle=self.cycle_id,
)
# print(f"number of buildings retrieved: {len(buildings)}")

# TODO: what to do with this if paginated?
return buildings

def get_property(self, property_view_id: int) -> dict:
def get_property_view(self, property_view_id: int) -> dict:
"""Return a single property (view and state) by the property view id.
Args:
Expand All @@ -213,6 +248,29 @@ def get_property(self, property_view_id: int) -> dict:
property_view_id, endpoint="property_views", data_name="property_views"
)

def get_property(self, property_id: int) -> dict:
"""Return a single property by the property id.
Args:
property__id (int): ID of the property to return. This is the ID that is in the URL http://SEED_URL/app/#/properties/{property_view_id}
Returns:
dict: {
'state': {
'extra_data': {},
},
'cycle': {...},
'property': {...},
'labels': {...},
'measures': {...}
...
}
"""
# NOTE: this seems to be the call that OEP uses (returns property and labels dictionaries)
return self.client.get(
property_id, endpoint="properties", data_name="properties"
)

def search_buildings(
self, identifier_filter: str = None, identifier_exact: str = None
) -> dict:
Expand Down Expand Up @@ -584,27 +642,6 @@ def get_cycle_by_name(self, cycle_name: str, set_cycle_id: bool = None) -> dict:

raise ValueError(f"cycle '{cycle_name}' not found")

def get_org_by_name(self, org_name: str, set_org_id: bool = False) -> dict:
"""Set the current organization by name.
Args:
org_name (str): name of the organization to set
set_org_id (bool): set the org_id on the object for later use. Defaults to None.
Returns:
dict: {
org data
}
"""
orgs = self.get_organizations()
for org in orgs:
if org["name"] == org_name:
if set_org_id:
self.client.org_id = org["id"]
return org

raise ValueError(f"Organization '{org_name}' not found")

def delete_cycle(self, cycle_id: str) -> dict:
"""Delete the cycle. This will only work if there are no properties or tax lots in the cycle
Expand Down
3 changes: 2 additions & 1 deletion pyseed/seed_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,15 @@ def _check_response(self, response, *args, **kwargs):
# this is a system matching response, which is okay. return the success flag of this
status_flag = response.json()['progress_data'].get('status', None)
error = status_flag not in ['not-started', 'success', 'parsing']
elif not any(key in ['results', 'readings', 'data', 'status', 'id', 'organizations'] for key in response.json().keys()):
elif not any(key in ['results', 'readings', 'data', 'status', 'id', 'organizations', 'sha'] for key in response.json().keys()):
# In some cases there is not a 'status' field, so check if there are
# any other keys in the response that depict a success:
# readings - this comes from meters
# data - lots of responses just return the data flag
# status - sometimes the status comes back as complete
# id - For some object creates, the response is simply the object back in JSON format with an ID field.
# organizations - this is the only key when returning the list of orgs
# sha - When parsing the version of SEED
error = True

elif not isinstance(response.json(), list):
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10

[options]
packages = find:
Expand Down
12 changes: 9 additions & 3 deletions tests/test_seed_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ def test_seed_orgs(self):
orgs = self.seed_client.get_organizations()
assert len(orgs) > 0

# need to figure out what org to look for
# org = self.seed_client.get_org_by_name('nrel', set_org_id=False)
# assert org['name'] == 'nrel'
def test_seed_client_info(self):
info = self.seed_client.instance_information()
assert set(("version", "sha")).issubset(info.keys())

def test_seed_buildings(self):
buildings = self.seed_client.get_buildings()
Expand All @@ -100,10 +100,16 @@ def test_search_buildings(self):
assert len(properties) == 1

prop = self.seed_client.get_property(properties[0]["id"])
assert prop["state"]["address_line_1"] == "111 Street Lane, Chicago, IL"
assert prop["state"]["extra_data"]["EUI Target"] == 120

# test the property view (same as previous, just less data)
prop = self.seed_client.get_property_view(properties[0]["id"])
assert prop["id"] == properties[0]["id"]
assert prop["state"]["address_line_1"] == "111 Street Lane, Chicago, IL"
assert prop["state"]["extra_data"]["EUI Target"] == 120

# There are 2 if filtering, because B-1 and B-10
properties = self.seed_client.search_buildings(identifier_filter="B-1")
assert len(properties) == 2

Expand Down

0 comments on commit e9c3ae5

Please sign in to comment.