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

179D updates #22

Merged
merged 31 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
72d2949
adding create_building and update_building methods
kflemin Apr 28, 2023
f05ea1e
precommit
kflemin Apr 28, 2023
0b44e3e
modify search_buildings to provide appropriate cycle id
kflemin May 2, 2023
2d1b5b8
update typing
kflemin May 2, 2023
6ec5370
Merge branch 'develop' into 179d_update
axelstudios Jun 16, 2023
5e8c086
Merge branch 'develop' into 179d_update
kflemin Jun 21, 2023
865874a
adding client methods for creating extra data columns
kflemin Jun 27, 2023
39bb035
handle 204s better
kflemin Jun 28, 2023
598a68e
precommit
kflemin Jun 28, 2023
c1e4409
precommit
kflemin Jun 28, 2023
d96695c
mypy
kflemin Jun 28, 2023
b928826
add pass throughs for file downloads
kflemin Jul 3, 2023
a149bfb
updates for audit template workflow
kflemin Jul 10, 2023
834a3c4
stub of import_portfolio_manager_report
kflemin Jul 14, 2023
028e9cd
Merge remote-tracking branch 'origin/develop' into 179d_update
nllong Jul 21, 2023
4497f5b
add spelling checks
nllong Jul 21, 2023
1d3c132
method to download property xlsx
nllong Jul 21, 2023
b79f00b
fix tests - add header to mock response
nllong Jul 21, 2023
bde662d
cleanup
nllong Jul 21, 2023
f4575ab
update with ESPM
kflemin Aug 2, 2023
152b212
fix mypy
kflemin Aug 2, 2023
f4ccdcf
adding test
kflemin Aug 2, 2023
9ed795f
fix typo
kflemin Aug 2, 2023
013df4d
remove prints
kflemin Aug 2, 2023
ead38d4
Update CHANGELOG.rst
nllong Aug 14, 2023
c9aa2d2
Update README.rst
kflemin Aug 31, 2023
f9ed3ab
fix tests
kflemin Sep 11, 2023
df127c8
adding espm secrets for testing
kflemin Sep 11, 2023
224cb53
force always pulling images and rename the conatiners to not conflict…
nllong Sep 15, 2023
526f586
force always pulling images and rename the conatiners to not conflict…
nllong Sep 15, 2023
ea33381
Merge branch '179d_update' of github.com:SEED-platform/py-seed into 1…
nllong Sep 15, 2023
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
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ Py-SEED

A python API client for the SEED Platform. This is an updated version of the Client. It is compatible with the latest version of the SEED Platform (>2.17.4). This client still has access to the previous format of generating a lower level API client by accessing `seed_client_base.SEEDOAuthReadOnlyClient`, `seed_client_base.SEEDOAuthReadWriteClient`, `seed_client_base.SEEDReadOnlyClient`, and `seed_client_base.SEEDReadWriteClient`. This lower level API is documented below under the `Low-Level Documentation`

Stakeholders
kflemin marked this conversation as resolved.
Show resolved Hide resolved
-------------

The following list of stakeholders should be considered when making changes to this module

- 179D Tax Deduction Web Application
- Earth Advantage Green Building Registry
- User scripts for managing building data

Documentation
-------------
The SEED client is a read-write client. To install the client run:
Expand Down
50 changes: 46 additions & 4 deletions pyseed/seed_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def read_connection_config_file(cls, filepath: Path) -> dict:
"api_key": "1b5ea1ee220c8628789c61d66253d90398e6ad03",
"port": 8000,
"use_ssl": false,
"seed_org_name: "test-org"
"seed_org_name": "test-org"
kflemin marked this conversation as resolved.
Show resolved Hide resolved
}

Args:
Expand Down Expand Up @@ -273,10 +273,12 @@ def get_property(self, property_id: int) -> dict:
)

def search_buildings(
self, identifier_filter: str = None, identifier_exact: str = None
self, identifier_filter: str = None, identifier_exact: str = None, cycle_id: int = None
) -> dict:
payload = {
"cycle": self.cycle_id,
if not cycle_id:
cycle_id = self.cycle_id
payload: Dict[str, Any] = {
kflemin marked this conversation as resolved.
Show resolved Hide resolved
"cycle": cycle_id,
}
if identifier_filter is not None:
payload["identifier"] = identifier_filter
Expand Down Expand Up @@ -494,6 +496,46 @@ def update_labels_of_buildings(
)
return result

def create_building(self, params: dict) -> list:
"""
Creates a building with unique ID (either pm_property_id or custom_id_1 for now)
Expects params to contain a state dictionary and a cycle id
Optionally pass in a cycle ID

Returns the created property_view id
"""
# first try matching on custom_id_1
matching_id = params.get('state', {}).get('custom_id_1', None)

if not matching_id:
# then try on pm_property_id
matching_id = params.get('state', {}).get('pm_property_id', None)

if not matching_id:
raise Exception(
"This property does not have a pm_property_id or a custom_id_1 for matching...cannot create."
)

cycle_id = params.get('cycle_id', None)
# include appropriate cycle in search (if not using the default cycle set on the class)
buildings = self.search_buildings(identifier_exact=matching_id, cycle_id=cycle_id)

if len(buildings) > 0:
raise Exception(
"A property matching the provided matching ID (pm_property_id or custom_id_1) already exists."
)

results = self.client.post(endpoint="properties", json=params)
return results

def update_building(self, id, params: dict) -> list:
"""
Updates a building's property_view
Expects id and params to contain a state dictionary
"""
results = self.client.put(id, endpoint="properties", json=params)
return results

def get_cycles(self) -> list:
"""Return a list of all the cycles for the organization.

Expand Down
2 changes: 1 addition & 1 deletion pyseed/seed_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def _check_response(self, response, *args, **kwargs):
error = False
error_msg = 'Unknown error from SEED API'
# OK, Created, Accepted
if response.status_code not in [200, 201, 202]:
if response.status_code not in [200, 201, 202, 204]:
error = True
error_msg = 'SEED returned status code: {}'.format(response.status_code)
# SEED adds a status key to the response to indicate success/error
Expand Down
62 changes: 62 additions & 0 deletions tests/test_seed_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,68 @@ def test_search_buildings(self):
properties = self.seed_client.search_buildings(identifier_filter="B-1")
assert len(properties) == 2

def test_create_update_building(self):
# create a new building (property, propertyState, propertyView)
# Update the building
completion_date = "02/02/2023"
year = '2023'
print(f" ORGANIZATION: {self.organization_id}")
cycle = self.seed_client.get_or_create_cycle(
"pyseed-api-integration-test",
date(int(year), 1, 1),
date(int(year), 12, 31),
set_cycle_id=True,
)

state = {
"organization_id": self.organization_id,
"custom_id_1": "123456",
"address_line_1": "123 Testing St",
"city": "Beverly Hills",
"state": "CA",
"postal_code": "90210",
"property_name": "Test Building",
"property_type": None,
"gross_floor_area": None,
"conditioned_floor_area": None,
"occupied_floor_area": None,
"site_eui": None,
"site_eui_modeled": None,
"source_eui_weather_normalized": None,
"source_eui": None,
"source_eui_modeled": None,
"site_eui_weather_normalized": None,
"total_ghg_emissions": None,
"total_marginal_ghg_emissions": None,
"total_ghg_emissions_intensity": None,
"total_marginal_ghg_emissions_intensity": None,
"generation_date": None,
"recent_sale_date": None,
"release_date": None,
"extra_data": {
"pathway": "new",
"completion_date": completion_date
}
}

params = {'state': state, 'cycle_id': cycle["id"]}

result = self.seed_client.create_building(params=params)
assert result["status"] == "success"
assert result["view"]["id"] is not None
view_id = result["view"]["id"]

# update that property (by ID)
state['property_name'] = 'New Name Building'

properties = self.seed_client.search_buildings(identifier_exact=state['custom_id_1'])
assert len(properties) == 1

params2 = {'state': state}
result2 = self.seed_client.update_building(view_id, params=params2)
# print(f" !!! results2 are: {result2}")
assert result2["status"] == "success"

def test_add_label_to_buildings(self):
# get seed buildings
prop_ids = []
Expand Down