Skip to content

Commit

Permalink
0.4.1 Release
Browse files Browse the repository at this point in the history
  • Loading branch information
axelstudios committed Nov 27, 2023
1 parent bcb3d89 commit 2361ad2
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 53 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exclude: |
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: check-added-large-files
Expand Down Expand Up @@ -40,7 +40,7 @@ repos:
- id: flake8
args: ["--ignore=E501,E402,W503,W504,E731,F401"]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.3
rev: v3.1.0
hooks:
- id: prettier
types_or: [css, yaml, markdown, html, scss, javascript]
Expand Down
17 changes: 16 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Changelog
=========

0.4.1
-----

What's Changed
**************

* Configure seed to load small EEEJ dataset for integration test by @kflemin in https://github.com/SEED-platform/py-seed/pull/33
* Add analysis retrieve methods by @nllong in https://github.com/SEED-platform/py-seed/pull/34
* Added multiple cycle upload argument by @anchapin in https://github.com/SEED-platform/py-seed/pull/27
* Endpoint to download an Audit Template Report Submission and store in SEED by @kflemin in https://github.com/SEED-platform/py-seed/pull/36

**Full Changelog**: https://github.com/SEED-platform/py-seed/commits/v0.4.1

0.4.0
-----

Expand All @@ -15,7 +28,9 @@ What's Changed
* Add new endpoints to support 179D by @kflemin in https://github.com/SEED-platform/py-seed/pull/22
* Increase timeout for server start by @nllong in https://github.com/SEED-platform/py-seed/pull/31

## New Contributors
New Contributors
****************

* @kflemin made their first contribution in https://github.com/SEED-platform/py-seed/pull/22

**Full Changelog**: https://github.com/SEED-platform/py-seed/commits/v0.4.0
Expand Down
66 changes: 30 additions & 36 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Py-SEED
py-SEED
=======

.. image:: https://github.com/seed-platform/py-seed/actions/workflows/ci.yml/badge.svg?branch=develop
Expand All @@ -7,17 +7,28 @@ Py-SEED
.. image:: https://badge.fury.io/py/py-seed.svg
:target: https://pypi.python.org/pypi/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`
py-SEED serves as a Python client for the SEED Platform API. This library is purpose-built for Python applications, enabling interaction with the SEED Platform API to access property lists, create properties, establish connections, and retrieve data from ENERGY STAR(R) Portfolio Manager, BETTER, and other sources. The SEED Platform has a robust API, granting users access to every front-end feature seamlessly via the API. Currently, this library exposes the most commonly used SEED API endpoints and will undergo continuous updates tailored to the community's evolving needs. py-SEED offers two interaction levels: a high-level API providing familiar endpoints for easy connectivity to SEED's API, and a low-level API that allows read-write access to any SEED API, demanding a deeper understanding of the SEED API architecture

py-SEED is compatible with the latest version of the SEED Platform (>2.17.4) and only support SEED API Version 3.

More information can be found here:

* https://seed-platform.org
* https://energy.gov/eere/buildings/standard-energy-efficiency-data-platform
* https://github.com/SEED-platform
* https://buildingdata.energy.gov/#/seed
* https://github.com/SEED-platform/pyseed-examples


Stakeholders
-------------

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
- ECAM
* 179D Tax Deduction Web Application
* Earth Advantage Green Building Registry
* User scripts for managing building data
* ECAM

Documentation
-------------
Expand Down Expand Up @@ -55,39 +66,20 @@ Within Python you can use the client like this:
'tests/data/test-seed-data-mappings.csv'
)
# See the projects unit tests for more examples.
# See the projects unit tests for more examples. https://github.com/SEED-platform/py-seed/blob/develop/tests/test_seed_client.py
# Or look at the py-SEED examples repository: https://github.com/SEED-platform/pyseed-examples
Low-Level Documentation
-----------------------
This provides two user authentication based Python clients and two OAuth2 authentication based Python clients for interacting with the SEED Platform Api::
This client has access to the lower level API client by accessing `seed_client_base.SEEDOAuthReadOnlyClient`, `seed_client_base.SEEDOAuthReadWriteClient`, `seed_client_base.SEEDReadOnlyClient`, and `seed_client_base.SEEDReadWriteClient`. This provides two user authentication based Python clients and two authentication methods, basic and `OAuth2 <https://github.com/GreenBuildingRegistry/jwt_oauth2>`_. More information on authentication can be seen in the following py-SEED classes:


SEEDOAuthReadOnlyClient
SEEDOAuthReadWriteClient
SEEDReadOnlyClient
SEEDReadWriteClient



(The OAuthMixin is constructed around the the JWTGrantClient found in jwt-oauth2lib. see https://github.com/GreenBuildingRegistry/jwt_oauth2)

SEED (Standard Energy Efficiency Data Platform™) is an open source "web-based application that helps organizations easily manage data on the energy performance of large groups of buildings" funded by the United States Department of Energy.

More information can be found here:

* https://energy.gov/eere/buildings/standard-energy-efficiency-data-platform
* https://seed-platform.org
* https://github.com/SEED-platform
* https://buildingdata.energy.gov/#/seed


Note the clients do not provide per api-call methods, but does provide the standard CRUD methods: get, list, put, post, patch, delete

The intended use of these clients is to be further subclassed or wrapped in functions to provide the desired functionality. The CRUD methods are provided via mixins so its possible to create a client for example without the ability to delete by subclassing SEEDUserAuthBaseClient, or SEEDOAuthBaseClient, and adding only the mixins that provided the Create, Read and Update capabilities.

Basic usage for the provided clients is below.

Usage:
Note the clients do not provide per api-call methods, but does provide the standard CRUD methods: get, list, put, post, patch, delete. The intended use of these clients is to be further subclassed or wrapped in functions to provide the desired functionality. The CRUD methods are provided via mixins so its possible to create a client for example without the ability to delete by subclassing SEEDUserAuthBaseClient, or SEEDOAuthBaseClient, and adding only the mixins that provided the Create, Read and Update capabilities. Basic usage for the provided low-level clients is as follows:


.. code-block:: python
Expand All @@ -107,8 +99,8 @@ Usage:
# get a single property
seed_client.get(property_pk, endpoint='properties')
Local Testing
-------------
Testing
-------

Tests can be run via the `pytest` command.

Expand All @@ -120,15 +112,15 @@ You will need to export environment variables for a test portfolio manager accou
SEED_PM_PW


SEED Platform
-------------
SEED (Standard Energy Efficiency Data Platform™) is an open source "web-based application that helps organizations easily manage data on the energy performance of large groups of buildings" funded by the United States Department of Energy.


License
-------
Full details in LICENSE file.

Changelog
---------
py-SEED was developed for use in the greenbuildingregistry project but has been extended for various uses, including Salesforce data transfer and SEED data analysis.

For a full changelog see `CHANGELOG.rst <https://github.com/seed-platform/py-seed/blob/master/CHANGELOG.rst>`_.

Releasing
---------
Expand All @@ -142,4 +134,6 @@ Releasing
rm -rf dist
python setup.py sdist
pip install twine
# make sure to check the dist package for errors in the RST files
twine check dist/*
twine upload dist/*
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"apibase",
"buildingsync",
"codeauthor",
"datafile",
"dname",
"durl",
"ECAM",
Expand Down
130 changes: 121 additions & 9 deletions pyseed/seed_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ def get_property_view(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.
def get_property(self, property_view_id: int) -> dict:
"""Return a single property by the property view 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}
Expand All @@ -236,7 +236,7 @@ def get_property(self, property_id: int) -> dict:
"""
# 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"
property_view_id, endpoint="properties", data_name="properties"
)

def search_buildings(
Expand Down Expand Up @@ -379,18 +379,23 @@ def delete_label(self, label_name: str) -> dict:

return self.client.delete(id, endpoint="labels")

def get_view_ids_with_label(self, label_names: list = []) -> list:
"""Get the view IDs of the properties with a given label name.
def get_view_ids_with_label(self, label_names: Union[str, list] = []) -> list:
"""Get the view IDs of the properties with a given label name(s). Can be a single
label or a list of labels.
Note that with labels, the data.selected field is for property view ids! SEED was updated
in June 2022 to add in the label_names to filter on.
Args:
label_names (list, optional): list of the labels to filter on. Defaults to [].
label_names (str, list, optional): list of the labels to filter on. Defaults to [].
Returns:
list: list of labels and the views they are associated with
"""
# if the label_names is not a list, then make it one
if not isinstance(label_names, list):
label_names = [label_names]

properties = self.client.post(
endpoint="properties_labels",
cycle=self.cycle_id,
Expand Down Expand Up @@ -1149,12 +1154,13 @@ def get_meter_data(self, property_id, interval: str = 'Exact', excluded_meter_id
def save_meter_data(self, property_id: int, meter_id: int, meter_data) -> dict:
pass

def start_save_data(self, import_file_id: int) -> dict:
def start_save_data(self, import_file_id: int, multiple_cycle_upload: bool = False) -> dict:
"""start the background process to save the data file to the database.
This is the state before the mapping.
Args:
import_file_id (int): id of the import file to save
multiple_cycle_upload (bool): whether to use multiple cycle upload
Returns:
dict: progress key
Expand All @@ -1167,7 +1173,8 @@ def start_save_data(self, import_file_id: int) -> dict:
return self.client.post(
"import_files_start_save_data_pk",
url_args={"PK": import_file_id},
json={"cycle_id": self.cycle_id},
json={"cycle_id": self.cycle_id,
"multiple_cycle_upload": multiple_cycle_upload},
)

def start_map_data(self, import_file_id: int) -> dict:
Expand Down Expand Up @@ -1316,6 +1323,7 @@ def upload_and_match_datafile(
column_mapping_profile_name (str): Name of the column mapping profile to use
column_mappings_file (str): Mapping that will be uploaded to the column_mapping_profile_name
import_meters_if_exist (bool): If true, will import meters from the meter tab if they exist in the datafile. Defaults to False.
multiple_cycle_upload (bool): Whether to use multiple cycle upload. Defaults to False.
Returns:
dict: {
Expand All @@ -1326,9 +1334,10 @@ def upload_and_match_datafile(
dataset = self.get_or_create_dataset(dataset_name)
result = self.upload_datafile(dataset["id"], datafile, datafile_type)
import_file_id = result["import_file_id"]
multiple_cycle_upload = kwargs.pop("multiple_cycle_upload", False)

# start processing
result = self.start_save_data(import_file_id)
result = self.start_save_data(import_file_id, multiple_cycle_upload)
progress_key = result.get("progress_key", None)

# wait until upload is complete
Expand Down Expand Up @@ -1418,6 +1427,71 @@ def retrieve_at_building_and_update(self, audit_template_building_id: int, cycle

return response

def retrieve_at_submission_and_update(self, audit_template_submission_id: int, cycle_id: int, seed_id: int, report_format: str = 'pdf', filename: str = None) -> dict:
"""Connect to audit template and retrieve audit report by submission ID
Args:
audit_template_submission_id (int): ID of the AT submission report (different than building ID)
cycle_id (int): Cycle ID in SEED (needed for XML but not actually for PDF)
seed_id (int): PropertyView ID in SEED
file_format (str): pdf or xml report, defaults to pdf
filename (str): filename to use to upload to SEED
Returns:
dict: Response from the SEED API
including the PDF file (if that format was requested)
"""

# api/v3/audit_template/pk/get_submission
# accepts pdf or xml
response = self.client.get(
None,
required_pk=False,
endpoint="audit_template_submission",
url_args={"PK": audit_template_submission_id},
report_format=report_format
)

if response['status'] == 'success':
if report_format.lower() == 'pdf':
pdf_file = response['content']
if not filename:
filename = 'at_submission_report_' + str(audit_template_submission_id) + '.pdf'
files = [
('file', (filename, pdf_file)),
('file_type', (None, 1))
]
response2 = self.client.put(
None,
required_pk=False,
endpoint="properties_upload_inventory_document",
url_args={"PK": seed_id},
files=files
)
response2['pdf_report'] = pdf_file
else:
# assume XML
# now post to api/v3/properties/PK/update_with_buildingsync
xml_file = response['content']
if not filename:
filename = 'at_' + str(int(time.time() * 1000)) + '.xml'

files = [
('file', (filename, xml_file)),
('file_type', (None, 1))
]

response2 = self.client.put(
None,
required_pk=False,
endpoint="properties_update_with_buildingsync",
url_args={"PK": seed_id},
files=files,
cycle_id=cycle_id
)

return response2

def retrieve_portfolio_manager_property(self, username: str, password: str, pm_property_id: int, save_file_name: Path) -> dict:
"""Connect to portfolio manager and download an individual properties data in Excel format
Expand Down Expand Up @@ -1472,3 +1546,41 @@ def import_portfolio_manager_property(self, seed_id: int, cycle_id: int, mapping
)

return response

def retrieve_analyses_for_property(self, property_id: int) -> dict:
"""Retrieve a list of all the analyses for a single property id. Since this
is a property ID, then it is all the analyses for the all cycles. Note that this endpoint
requires the passing of the organization id as a query parameter, otherwise it fails.
Args:
property_id (int): Property view id to return the list of analyses
Returns:
dict: list of all the analyses that have run (or failed) for the property view
"""
return self.client.get(
None,
required_pk=False,
endpoint="properties_analyses",
url_args={"PK": property_id},
include_org_id_query_param=True,
)

def retrieve_analysis_result(self, analysis_id: int, analysis_view_id: int) -> dict:
"""Return the detailed JSON of a single analysis view. The endpoint in SEED is
typically: https://dev1.seed-platform.org/app/#/analyses/274/runs/14693.
Args:
analysis_id (int): ID of the analysis
analysis_view_id (int): ID of the analysis view
Returns:
dict: Return the detailed results of a single analysis view
"""
return self.client.get(
None,
required_pk=False,
endpoint="analyses_views",
url_args={"PK": analysis_id, "ANALYSIS_VIEW_PK": analysis_view_id},
include_org_id_query_param=True,
)
Loading

0 comments on commit 2361ad2

Please sign in to comment.