From 474f1ceef627513384f97aa1b393a2da9ab6a2cc Mon Sep 17 00:00:00 2001 From: Alex Swindler Date: Wed, 29 May 2024 12:38:32 -0600 Subject: [PATCH] Fix unnecessary typing --- pyseed/seed_client.py | 279 ++++++++++++++++++------------------- pyseed/seed_client_base.py | 26 ++-- 2 files changed, 152 insertions(+), 153 deletions(-) diff --git a/pyseed/seed_client.py b/pyseed/seed_client.py index 965dd02..27039d5 100644 --- a/pyseed/seed_client.py +++ b/pyseed/seed_client.py @@ -4,7 +4,7 @@ """ # Imports from Standard Library -from typing import Any, Dict, List, Optional, Union +from typing import Any, Optional, Union # Imports from Third Party Modules import json @@ -31,14 +31,14 @@ class SeedClientWrapper(object): def __init__( self, organization_id: int, - connection_params: Optional[Dict] = None, + connection_params: Optional[dict] = None, connection_config_filepath: Optional[Path] = None, ) -> None: """wrapper around SEEDReadWriteClient. Args: organization_id (int): _description_ - connection_params (Dict, Optional): parameters to connect to SEED. Defaults to None. If using, then must contain the following: + connection_params (dict, optional): parameters to connect to SEED. Defaults to None. If using, then must contain the following: { "name": "not used - can be any string", "base_url": "http://127.0.0.1", @@ -47,7 +47,7 @@ def __init__( "port": 8000, "use_ssl": false } - connection_config_filepath (Path, Optional): path to the parameters (JSON file). Defaults to None. + connection_config_filepath (Path, optional): path to the parameters (JSON file). Defaults to None. Raises: Exception: SeedClientWrapper @@ -71,7 +71,7 @@ def __init__( self.client = SEEDReadWriteClient(organization_id, **self.payload) @classmethod - def read_connection_config_file(cls, filepath: Path) -> Dict: + def read_connection_config_file(cls, filepath: Path) -> dict: """Read in the connection config file and return the connection params. This file can be mostly created by calling the following from the SEED root directory: @@ -105,7 +105,7 @@ class SeedClient(SeedClientWrapper): def __init__( self, organization_id: int, - connection_params: Optional[Dict] = None, + connection_params: Optional[dict] = None, connection_config_filepath: Optional[Path] = None, ) -> None: super().__init__(organization_id, connection_params, connection_config_filepath) @@ -118,7 +118,7 @@ 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: + def get_org_by_name(self, org_name: str, set_org_id: bool = False) -> dict: """Set the current organization by name. Args: @@ -126,7 +126,7 @@ def get_org_by_name(self, org_name: str, set_org_id: bool = False) -> Dict: set_org_id (bool): set the org_id on the object for later use. Defaults to None. Returns: - Dict: { + dict: { org data } """ @@ -139,11 +139,11 @@ def get_org_by_name(self, org_name: str, set_org_id: bool = False) -> Dict: raise ValueError(f"Organization '{org_name}' not found") - def instance_information(self) -> Dict: + def instance_information(self) -> dict: """Return the instance information. Returns: - Dict: instance information + dict: instance information """ # http://localhost:8000/api/version/ # add in URL to the SEED instance @@ -153,11 +153,11 @@ def instance_information(self) -> Dict: info["username"] = self.client.username return info - def get_organizations(self, brief: bool = True) -> Dict: - """Get a List organizations (that one is allowed to view) + def get_organizations(self, brief: bool = True) -> dict: + """Get a list organizations (that one is allowed to view) Args: - brief (bool, Optional): if True, then only return the organization id with some other basic info. Defaults to True. + brief (bool, optional): if True, then only return the organization id with some other basic info. Defaults to True. Returns: Dict: [ { @@ -179,11 +179,11 @@ def get_organizations(self, brief: bool = True) -> Dict: ) return orgs - def get_buildings(self) -> List[Dict]: + def get_buildings(self) -> list[dict]: total_qry = self.client.list(endpoint="properties", data_name="pagination", per_page=100) # step through each page of the results - buildings: List[Dict] = [] + buildings: list[dict] = [] for i in range(1, total_qry['num_pages'] + 1): buildings = buildings + self.client.list( endpoint="properties", @@ -196,7 +196,7 @@ def get_buildings(self) -> List[Dict]: return buildings - def get_property_view(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. It is recommended to use the more verbose version of `get_property` below. @@ -204,7 +204,7 @@ def get_property_view(self, property_view_id: int) -> Dict: property_view_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} and resolves to {host}/api/v3/property_views/{property_view_id} Returns: - Dict: { + dict: { 'id': property_view_id, 'state': { 'extra_data': {}, @@ -217,14 +217,14 @@ 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_view_id: int) -> Dict: + 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} + property_view_id (int): ID of the property view with a property to return. This is the ID that is in the URL http://SEED_URL/app/#/properties/{property_view_id} Returns: - Dict: { + dict: { 'state': { 'extra_data': {}, }, @@ -235,7 +235,7 @@ def get_property(self, property_view_id: int) -> Dict: ... } """ - # NOTE: this seems to be the call that OEP uses (returns property and labels Dictionaries) + # NOTE: this seems to be the call that OEP uses (returns property and labels dictionaries) return self.client.get( property_view_id, endpoint="properties", data_name="properties" ) @@ -245,10 +245,10 @@ def search_buildings( identifier_filter: Optional[str] = None, identifier_exact: Optional[str] = None, cycle_id: Optional[int] = None, - ) -> Dict: + ) -> dict: if not cycle_id: cycle_id = self.cycle_id - payload: Dict[str, Any] = { + payload: dict[str, Any] = { "cycle": cycle_id, } if identifier_filter is not None: @@ -262,14 +262,14 @@ def search_buildings( ) return properties - def get_labels(self, filter_by_name: Optional[List] = None) -> List: - """Get a List of all the labels in the organization. Filter by name if desired. + def get_labels(self, filter_by_name: Optional[list] = None) -> list: + """Get a list of all the labels in the organization. Filter by name if desired. Args: - filter_by_name (List, Optional): List of subset of labels to return. Defaults to None. + filter_by_name (list, optional): List of subset of labels to return. Defaults to None. Returns: - List: [ + list: [ { 'id': 8, 'name': 'Call', @@ -292,16 +292,16 @@ def get_labels(self, filter_by_name: Optional[List] = None) -> List: def get_or_create_label( self, label_name: str, color: str = "blue", show_in_list: bool = False - ) -> Dict: + ) -> dict: """_summary_ Args: label_name (str): Name of label. SEED enforces uniqueness of label names within an organization. - color (str, Optional): Default color of the label. Must be from red, blue, light blue, green, white, orange, gray. 'blue' is the default. - show_in_list (bool, Optional): If true, then the label is shown in the inventory List page as part of the column. Defaults to False. + color (str, optional): Default color of the label. Must be from red, blue, light blue, green, white, orange, gray. 'blue' is the default. + show_in_list (bool, optional): If true, then the label is shown in the inventory list page as part of the column. Defaults to False. Returns: - Dict: { + dict: { 'id': 87, 'name': 'label name', 'color': 'green', @@ -323,20 +323,20 @@ def update_label( new_label_name: Optional[str] = None, new_color: Optional[str] = None, new_show_in_list: Optional[bool] = None, - ) -> Dict: + ) -> dict: """Update an existing label with the new_* fields. If the new_* fields are not provided, then the existing values are used. Args: label_name (str): Name of existing label. This is required and must match an existing label name for the organization - new_label_name (str, Optional): New name of the label. Defaults to None. - new_color (str, Optional): New color of the label. Must be from red, blue, light blue, green, white, orange, gray. Defaults to None - new_show_in_list (bool, Optional): New boolean on whether to show the label in the inventory List page. Defaults to None. + new_label_name (str, optional): New name of the label. Defaults to None. + new_color (str, optional): New color of the label. Must be from red, blue, light blue, green, white, orange, gray. Defaults to None + new_show_in_list (bool, optional): New boolean on whether to show the label in the inventory list page. Defaults to None. Raises: Exception: If the label does not exist, then throw an error. Returns: - Dict: { + dict: { 'id': 87, 'name': 'label name', 'color': 'green', @@ -344,7 +344,7 @@ def update_label( 'show_in_list': true } """ - # color (str, Optional): Default color of the label. Must be from red, blue, light blue, green, white, orange, gray. 'blue' is the default. + # color (str, optional): Default color of the label. Must be from red, blue, light blue, green, white, orange, gray. 'blue' is the default. # get the existing label label = self.get_labels(filter_by_name=[label_name]) if len(label) != 1: @@ -367,14 +367,14 @@ def update_label( current_label["id"], endpoint="labels", json=current_label ) - def delete_label(self, label_name: str) -> Dict: + def delete_label(self, label_name: str) -> dict: """Deletes an existing label. This method will look up the ID of the label to delete. Args: label_name (str): Name of the label to delete. Returns: - Dict: _description_ + dict: _description_ """ label = self.get_labels(filter_by_name=[label_name]) if len(label) != 1: @@ -383,21 +383,21 @@ def delete_label(self, label_name: str) -> Dict: return self.client.delete(id, endpoint="labels") - def get_view_ids_with_label(self, label_names: Union[str, List] = []) -> List: + 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. + 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 (str, 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 + 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): + # 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( @@ -409,24 +409,24 @@ def get_view_ids_with_label(self, label_names: Union[str, List] = []) -> List: def update_labels_of_buildings( self, - add_label_names: List, - remove_label_names: List, - building_ids: List, + add_label_names: list, + remove_label_names: list, + building_ids: list, inventory_type: str = "property", - ) -> Dict: + ) -> dict: """Add label names to the passed building ids. Args: - add_label_names (List): List of label names to add, will be converted to IDs - remove_label_names (List): List of label names to remove, will be converted to IDs - building_ids (List): List of building IDs (property_view_id) to add/remove labels - inventory_type (str, Optional): taxlot or property inventory. Defaults to 'property'. + add_label_names (list): list of label names to add, will be converted to IDs + remove_label_names (list): list of label names to remove, will be converted to IDs + building_ids (list): list of building IDs (property_view_id) to add/remove labels + inventory_type (str, optional): taxlot or property inventory. Defaults to 'property'. Raises: ValueError: if you don't pass the inventory type correction it will error out Returns: - Dict: { + dict: { 'status': 'success', 'num_updated': 3, 'labels': [ @@ -472,10 +472,10 @@ def update_labels_of_buildings( ) return result - def create_building(self, params: Dict) -> List: + 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 + Expects params to contain a state dictionary and a cycle id Optionally pass in a cycle ID Returns the created property_view id @@ -504,10 +504,10 @@ def create_building(self, params: Dict) -> List: results = self.client.post(endpoint="properties", json=params) return results - def update_building(self, id, params: Dict) -> List: + def update_building(self, id, params: dict) -> list: """ Updates a building's property_view - Expects id and params to contain a state Dictionary + Expects id and params to contain a state dictionary """ results = self.client.put(id, endpoint="properties", json=params) return results @@ -516,7 +516,7 @@ def get_cycles(self) -> list: """Return a list of all the cycles for the organization. Returns: - List: [ + list: [ { 'name': '2021 Calendar Year', 'start': '2020-12-31T23:53:00-08:00', @@ -540,7 +540,7 @@ def get_cycles(self) -> list: cycles = self.client.list(endpoint="cycles") return cycles["cycles"] - def create_cycle(self, cycle_name: str, start_date: date, end_date: date) -> Dict: + def create_cycle(self, cycle_name: str, start_date: date, end_date: date) -> dict: """Name of the cycle to create. If the cycle already exists, then it will create a new one. This is the default behavior of SEED. @@ -550,7 +550,7 @@ def create_cycle(self, cycle_name: str, start_date: date, end_date: date) -> Dic end_date (date): MM/DD/YYYY of end data for cycle Returns: - Dict: { + dict: { 'name': 'new cycle 351cd7e1', 'start': '2021-01-01T00:00:00-08:00', 'end': '2022-01-01T00:00:00-08:00', @@ -583,7 +583,7 @@ def get_or_create_cycle( start_date: date, end_date: date, set_cycle_id: bool = False, - ) -> Dict: + ) -> dict: """Get or create a new cycle. If the cycle_name already exists, then it simply returns the existing cycle. However, if the cycle_name does not exist, then it will create a new cycle. Args: @@ -593,7 +593,7 @@ def get_or_create_cycle( set_cycle_id (str): Set the object's cycle_id to the resulting cycle that is returned (either existing or newly created) Returns: - Dict: { + dict: { 'name': 'Calendar Year 2022', 'start': '2021-01-01T00:00:00-08:00', 'end': '2022-01-01T00:00:00-08:00', @@ -635,15 +635,15 @@ def get_or_create_cycle( # to keep the response consistent add back in the status return selected - def get_cycle_by_name(self, cycle_name: str, set_cycle_id: Optional[bool] = None) -> Dict: + def get_cycle_by_name(self, cycle_name: str, set_cycle_id: bool = False) -> dict: """Set the current cycle by name. Args: cycle_name (str): name of the cycle to set - set_cycle_id (bool): set the cycle_id on the object for later use. Defaults to None. + set_cycle_id (bool): set the cycle_id on the object for later use. Defaults to False. Returns: - Dict: { + dict: { 'name': 'Calendar Year 2022', 'start': '2021-01-01T00:00:00-08:00', 'end': '2022-01-01T00:00:00-08:00', @@ -661,14 +661,14 @@ def get_cycle_by_name(self, cycle_name: str, set_cycle_id: Optional[bool] = None raise ValueError(f"cycle '{cycle_name}' not found") - def delete_cycle(self, cycle_id: str) -> Dict: + 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 Args: cycle_id (str): ID of the cycle to delete Returns: - Dict: + dict: """ result = self.client.delete(cycle_id, endpoint="cycles") progress_key = result.get("progress_key", None) @@ -678,7 +678,7 @@ def delete_cycle(self, cycle_id: str) -> Dict: return result - def get_or_create_dataset(self, dataset_name: str) -> Dict: + def get_or_create_dataset(self, dataset_name: str) -> dict: """Get or create a SEED dataset which is used to hold data files that are uploaded to SEED. @@ -686,7 +686,7 @@ def get_or_create_dataset(self, dataset_name: str) -> Dict: dataset_name (str): dataset name to get or create. Names can be duplicated! Returns: - Dict: resulting dataset record + dict: resulting dataset record """ post_data = {"name": dataset_name} @@ -696,7 +696,7 @@ def get_or_create_dataset(self, dataset_name: str) -> Dict: logger.info(f"Dataset already created, returning {dataset['name']}") return dataset - # create a new dataset - this doesn't return the entire Dict back + # create a new dataset - this doesn't return the entire dict back # so after creating go and get the individual dataset dataset = self.client.post(endpoint="datasets", json=post_data) selected = {} @@ -708,7 +708,7 @@ def get_or_create_dataset(self, dataset_name: str) -> Dict: def upload_datafile( self, dataset_id: int, data_file: str, upload_datatype: str - ) -> Dict: + ) -> dict: """Upload a datafile file Args: @@ -717,7 +717,7 @@ def upload_datafile( upload_datatype (str): Type of data in file ('Assessed Raw', 'Portfolio Raw') Returns: - Dict: uploaded file record + dict: uploaded file record { "import_file_id": 54, "success": true, @@ -739,14 +739,14 @@ def upload_datafile( files=files_params, ) - def track_progress_result(self, progress_key) -> Dict: + def track_progress_result(self, progress_key) -> dict: """Delays the sequence until progress is at 100 percent Args: progress_key (str): the key to track Returns: - Dict: progress_result + dict: progress_result { 'status': 'success', # 'not_started', 'in_progress', 'parsing', 'success', 'error' 'status_message': '', @@ -783,15 +783,15 @@ def track_progress_result(self, progress_key) -> Dict: return progress_result - def get_column_mapping_profiles(self, profile_type: str = "All") -> Dict: + def get_column_mapping_profiles(self, profile_type: str = "All") -> dict: """get the list of column mapping profiles. If profile_type is provided then return the list of profiles of that type. Args: - profile_type (str, Optional): Type of column mappings to return, can be 'Normal', 'BuildingSync Default'. Defaults to 'All', which includes both Normal and BuildingSync. + profile_type (str, optional): Type of column mappings to return, can be 'Normal', 'BuildingSync Default'. Defaults to 'All', which includes both Normal and BuildingSync. Returns: - Dict: column mapping profiles + dict: column mapping profiles """ result = self.client.post(endpoint="column_mapping_profiles_filter") indices_to_remove = [] @@ -813,7 +813,7 @@ def get_column_mapping_profiles(self, profile_type: str = "All") -> Dict: def get_column_mapping_profile( self, column_mapping_profile_name: str - ) -> Optional[Dict]: + ) -> Optional[dict]: """get a specific column mapping profile. Currently, filter does not take an argument by name, so return them all and find the one that matches the column_mapping_profile_name. @@ -822,7 +822,7 @@ def get_column_mapping_profile( column_mapping_profile_name (str): Name of column_mapping_profile to return Returns: - Dict: single column mapping profile + dict: single column mapping profile """ results = self.client.post(endpoint="column_mapping_profiles_filter") for item in results: @@ -833,8 +833,8 @@ def get_column_mapping_profile( return None def create_or_update_column_mapping_profile( - self, mapping_profile_name: str, mappings: List - ) -> Dict: + self, mapping_profile_name: str, mappings: list + ) -> dict: """Create or update an existing mapping profile from a list of mappings This only works for 'Normal' column mapping profiles, that is, it does not work for @@ -843,7 +843,7 @@ def create_or_update_column_mapping_profile( Args: mapping_profile_name (str): profile name - mappings (List): list of mappings in the form of + mappings (list): list of mappings in the form of [ { "from_field": "Address 1", @@ -861,7 +861,7 @@ def create_or_update_column_mapping_profile( ] Returns: - Dict: { + dict: { 'id': 1 'profile_type': 'Normal', 'name': 'Profile Name', @@ -895,7 +895,7 @@ def create_or_update_column_mapping_profile( def create_or_update_column_mapping_profile_from_file( self, mapping_profile_name: str, mapping_file: str - ) -> Dict: + ) -> dict: """creates or updates a mapping profile. The format of the mapping file is a CSV with the following format: Raw Columns, units, SEED Table, SEED Columns\n @@ -912,7 +912,7 @@ def create_or_update_column_mapping_profile_from_file( mapping_file (str): _description_ Returns: - Dict: { + dict: { 'id': 1 'profile_type': 'Normal', 'name': 'Profile Name', @@ -930,16 +930,16 @@ def create_or_update_column_mapping_profile_from_file( ) def set_import_file_column_mappings( - self, import_file_id: int, mappings: List - ) -> Dict: + self, import_file_id: int, mappings: list + ) -> dict: """Sets the column mappings onto the import file record. Args: import_file_id (int): ID of the import file of interest - mappings (List): list of column mappings in the form of the results of column mapping profiles + mappings (list): list of column mappings in the form of the results of column mapping profiles Returns: - Dict: Dict of status + dict: dict of status """ return self.client.post( "org_column_mapping_import_file", @@ -948,11 +948,11 @@ def set_import_file_column_mappings( json={"mappings": mappings}, ) - def get_columns(self) -> Dict: + def get_columns(self) -> dict: """get the list of columns. Returns: - Dict: { + dict: { "status": "success", "columns: [{...}] } @@ -960,7 +960,7 @@ def get_columns(self) -> Dict: result = self.client.list(endpoint="columns") return result - def create_extra_data_column(self, column_name: str, display_name: str, inventory_type: str, column_description: str, data_type: str) -> Dict: + def create_extra_data_column(self, column_name: str, display_name: str, inventory_type: str, column_description: str, data_type: str) -> dict: """ create an extra data column. If column exists, skip Args: 'column_name': 'project_type', @@ -970,7 +970,7 @@ def create_extra_data_column(self, column_name: str, display_name: str, inventor 'data_type': 'string', Returns: - Dict:{ + dict:{ "status": "success", "column": { "id": 151, @@ -1004,17 +1004,16 @@ def create_extra_data_column(self, column_name: str, display_name: str, inventor return result - def create_extra_data_columns_from_file(self, columns_csv_filepath: str) -> List: + def create_extra_data_columns_from_file(self, columns_csv_filepath: str) -> list: """ create extra data columns from a csv file. if column exist, skip. Args: 'columns_csv_filepath': 'path/to/file' file is expected to have headers: column_name, display_name, column_description, - inventory_type (Property or Taxlot), and data_type (SEED column data_types) See example file at tests/data/test-seed-create-columns.csv Returns: - List:[{ + list:[{ "status": "success", "column": { "id": 151, @@ -1025,8 +1024,8 @@ def create_extra_data_columns_from_file(self, columns_csv_filepath: str) -> List """ # open file in read mode with open(columns_csv_filepath, 'r') as f: - Dict_reader = DictReader(f) - columns = list(Dict_reader) + dict_reader = DictReader(f) + columns = list(dict_reader) results = [] for col in columns: @@ -1035,7 +1034,7 @@ def create_extra_data_columns_from_file(self, columns_csv_filepath: str) -> List return results - def get_meters(self, property_id: int) -> List: + def get_meters(self, property_id: int) -> list: """Return the list of meters assigned to a property (the property view id). Note that meters are attached to the property (not the state nor the property view). @@ -1043,7 +1042,7 @@ def get_meters(self, property_id: int) -> List: property_id (int): property id to get the meters Returns: - Dict: [ + dict: [ { 'id': 584, 'type': 'Cost', @@ -1059,7 +1058,7 @@ def get_meters(self, property_id: int) -> List: url_args={"PK": property_id}) return meters - def get_meter(self, property_view_id: int, meter_type: str, source: str, source_id: str) -> Union[Dict, None]: + def get_meter(self, property_view_id: int, meter_type: str, source: str, source_id: str) -> Union[dict, None]: """get a meter for a property view. Args: @@ -1069,7 +1068,7 @@ def get_meter(self, property_view_id: int, meter_type: str, source: str, source_ source_id (str): Identifier, if GreenButton, then format is xpath like Returns: - Dict: meter object + dict: meter object """ # return all the meters for the property and see if the meter exists, if so, return it meters = self.get_meters(property_view_id) @@ -1079,7 +1078,7 @@ def get_meter(self, property_view_id: int, meter_type: str, source: str, source_ else: return None - def get_or_create_meter(self, property_view_id: int, meter_type: str, source: str, source_id: str) -> Optional[Dict[Any, Any]]: + def get_or_create_meter(self, property_view_id: int, meter_type: str, source: str, source_id: str) -> Optional[dict[Any, Any]]: """get or create a meter for a property view. Args: @@ -1089,7 +1088,7 @@ def get_or_create_meter(self, property_view_id: int, meter_type: str, source: st source_id (str): Identifier, if GreenButton, then format is xpath like Returns: - Dict: meter object + dict: meter object """ # return all the meters for the property and see if the meter exists, if so, return it meter = self.get_meter(property_view_id, meter_type, source, source_id) @@ -1109,7 +1108,7 @@ def get_or_create_meter(self, property_view_id: int, meter_type: str, source: st return meter - def delete_meter(self, property_view_id: int, meter_id: int) -> Dict: + def delete_meter(self, property_view_id: int, meter_id: int) -> dict: """Delete a meter from the property. Args: @@ -1117,22 +1116,22 @@ def delete_meter(self, property_view_id: int, meter_id: int) -> Dict: meter_id (int): meter id Returns: - Dict: status of the deletion + dict: status of the deletion """ return self.client.delete( meter_id, endpoint='properties_meters', url_args={"PK": property_view_id} ) - def upsert_meter_readings_bulk(self, property_view_id: int, meter_id: int, data: List) -> Dict: + def upsert_meter_readings_bulk(self, property_view_id: int, meter_id: int, data: list) -> dict: """Upsert meter readings for a property's meter with the bulk method. Args: property_view_id (int): property view id meter_id (int): meter id - data (List): list of dictionaries of meter readings + data (list): list of dictionaries of meter readings Returns: - Dict: list of all meter reading objects + dict: list of all meter reading objects """ # get the meter data for the property readings = self.client.post( @@ -1140,13 +1139,13 @@ def upsert_meter_readings_bulk(self, property_view_id: int, meter_id: int, data: ) return readings - def get_meter_data(self, property_id, interval: str = 'Exact', excluded_meter_ids: List = []): + def get_meter_data(self, property_id, interval: str = 'Exact', excluded_meter_ids: list = []): """Return the meter data from the property. Args: property_id (_type_): property view id - interval (str, Optional): How to aggregate the data, can be 'Exact', 'Month', or 'Year'. Defaults to 'Exact'. - excluded_meter_ids (List, Optional): IDs to exclude. Defaults to []]. + interval (str, optional): How to aggregate the data, can be 'Exact', 'Month', or 'Year'. Defaults to 'Exact'. + excluded_meter_ids (list, optional): IDs to exclude. Defaults to []]. """ payload = { "interval": interval, @@ -1155,7 +1154,7 @@ def get_meter_data(self, property_id, interval: str = 'Exact', excluded_meter_id meter_data = self.client.post(endpoint='properties_meter_usage', url_args={"PK": property_id}, json=payload) return meter_data - def start_save_data(self, import_file_id: int, multiple_cycle_upload: bool = False) -> 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. @@ -1164,7 +1163,7 @@ def start_save_data(self, import_file_id: int, multiple_cycle_upload: bool = Fal multiple_cycle_upload (bool): whether to use multiple cycle upload Returns: - Dict: progress key + dict: progress key { "status": "success", "progress_key": ":1:SEED:start_save_data:PROG:90", @@ -1178,7 +1177,7 @@ def start_save_data(self, import_file_id: int, multiple_cycle_upload: bool = Fal "multiple_cycle_upload": multiple_cycle_upload}, ) - def start_map_data(self, import_file_id: int) -> Dict: + def start_map_data(self, import_file_id: int) -> dict: """start the background process to save the data file to the database. This is the state before the mapping. @@ -1186,7 +1185,7 @@ def start_map_data(self, import_file_id: int) -> Dict: import_file_id (int): id of the import file to save Returns: - Dict: progress key + dict: progress key { "status": "success", "progress_key": ":1:SEED:map_data:PROG:90", @@ -1199,7 +1198,7 @@ def start_map_data(self, import_file_id: int) -> Dict: json={"remap": True}, ) - def start_system_matching_and_geocoding(self, import_file_id: int) -> Dict: + def start_system_matching_and_geocoding(self, import_file_id: int) -> dict: """start the background process save mappings and start system matching/geocoding. This is the state after the mapping. @@ -1207,7 +1206,7 @@ def start_system_matching_and_geocoding(self, import_file_id: int) -> Dict: import_file_id (int): id of the import file to save Returns: - Dict: progress key + dict: progress key { "progress_data": { "status": "success", @@ -1239,14 +1238,14 @@ def start_system_matching_and_geocoding(self, import_file_id: int) -> Dict: "import_files_start_matching_pk", url_args={"PK": import_file_id} ) - def get_matching_results(self, import_file_id: int) -> Dict: + def get_matching_results(self, import_file_id: int) -> dict: """matching results summary Args: import_file_id (int): ID of the import file Returns: - Dict: { + dict: { 'initial_incoming': 0, 'duplicates_against_existing': 0, 'duplicates_within_file': 0, @@ -1285,7 +1284,7 @@ def check_meters_tab_exist(self, import_file_id: int) -> bool: # if the data is set to True, then return such return response - def get_pm_report_template_names(self, pm_username: str, pm_password: str) -> Dict: + def get_pm_report_template_names(self, pm_username: str, pm_password: str) -> dict: """Download the PM report templates. Args: @@ -1293,7 +1292,7 @@ def get_pm_report_template_names(self, pm_username: str, pm_password: str) -> Di pm_password (str): password for Energystar Portfolio Manager Sample return shown below. - Returns: Dict: { + Returns: dict: { "status": "success", "templates": [ { @@ -1324,13 +1323,13 @@ def get_pm_report_template_names(self, pm_username: str, pm_password: str) -> Di # Return the report templates return response - def download_pm_report(self, pm_username: str, pm_password: str, pm_template: Dict) -> str: + def download_pm_report(self, pm_username: str, pm_password: str, pm_template: dict) -> str: """Download a PM report. Args: pm_username (str): username for Energystar Portfolio Manager pm_password (str): password for Energystar Portfolio Manager - pm_template (Dict): the full template object dict returned from get_pm_report_template_names + pm_template (dict): the full template object dict returned from get_pm_report_template_names Sample return shown below. Returns the path to the report template workbook file @@ -1397,7 +1396,7 @@ def download_pm_report(self, pm_username: str, pm_password: str, pm_template: Di # Return the report templates return datafile_path - def import_files_reuse_inventory_file_for_meters(self, import_file_id: int) -> Dict: + def import_files_reuse_inventory_file_for_meters(self, import_file_id: int) -> dict: """Reuse an import file to create all the meter entries. This method is used for ESPM related data files. The result will be another import_file ID for the meters that will then need to be "re-saved". Note that the returning import_file_id @@ -1407,7 +1406,7 @@ def import_files_reuse_inventory_file_for_meters(self, import_file_id: int) -> D import_file_id (int): ID of the import file to reuse. Returns: - Dict: { + dict: { "status": "success", "import_file_id": 16 } @@ -1426,7 +1425,7 @@ def upload_and_match_datafile( column_mappings_file: str, import_meters_if_exist: bool = False, **kwargs, - ) -> Dict: + ) -> dict: """Upload a file to the cycle_id that is defined in the constructor. This carries the upload of the file through the whole ingestion process (map, merge, pair, geocode). @@ -1500,7 +1499,7 @@ def upload_and_match_datafile( return matching_results - def retrieve_at_building_and_update(self, audit_template_building_id: int, cycle_id: int, seed_id: int) -> Dict: + def retrieve_at_building_and_update(self, audit_template_building_id: int, cycle_id: int, seed_id: int) -> dict: """Connect to audit template and retrieve audit XML by building ID Args: @@ -1509,7 +1508,7 @@ def retrieve_at_building_and_update(self, audit_template_building_id: int, cycle seed_id (int): PropertyView ID in SEED Returns: - Dict: Response from the SEED API + dict: Response from the SEED API """ # api/v3/audit_template/pk/get_building_xml @@ -1547,7 +1546,7 @@ def retrieve_at_submission_and_update( seed_id: int, report_format: str = 'pdf', filename: Optional[str] = None, - ) -> Dict: + ) -> dict: """Connect to audit template and retrieve audit report by submission ID Args: @@ -1558,7 +1557,7 @@ def retrieve_at_submission_and_update( filename (str): filename to use to upload to SEED Returns: - Dict: Response from the SEED API + dict: Response from the SEED API including the PDF file (if that format was requested) """ @@ -1616,7 +1615,7 @@ def retrieve_at_submission_and_update( return response2 - def retrieve_portfolio_manager_property(self, username: str, password: str, pm_property_id: int, save_file_name: Path) -> Dict: + 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 Args: @@ -1626,7 +1625,7 @@ def retrieve_portfolio_manager_property(self, username: str, password: str, pm_p save_file_name (Path): Location to save the file, preferably an absolute path Returns: - bool: Did the file download? + dict: Did the file download? """ if save_file_name.exists(): raise Exception(f"Save filename already exists, save to a new file name: {save_file_name}") @@ -1645,13 +1644,13 @@ def retrieve_portfolio_manager_property(self, username: str, password: str, pm_p result['status'] = 'success' return result - def import_portfolio_manager_property(self, seed_id: int, cycle_id: int, mapping_profile_id: int, file_path: str) -> Dict: + def import_portfolio_manager_property(self, seed_id: int, cycle_id: int, mapping_profile_id: int, file_path: str) -> dict: """Import the downloaded xlsx file into SEED on a specific propertyID Args: seed_id (int): Property view ID to update with the ESPM file cycle_id (int): Cycle ID mapping_profile_id (int): Column Mapping Profile ID - file: path to file downloaded from the retrieve_portfolio_manager_report method above + file_path: path to file downloaded from the retrieve_portfolio_manager_report method above ESPM file will have meter data that we want to handle (electricity and natural gas) in the 'Meter Entries' tab""" @@ -1671,7 +1670,7 @@ 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: + 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. @@ -1680,7 +1679,7 @@ def retrieve_analyses_for_property(self, property_id: int) -> Dict: 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 + dict: list of all the analyses that have run (or failed) for the property view """ return self.client.get( None, @@ -1690,7 +1689,7 @@ def retrieve_analyses_for_property(self, property_id: int) -> Dict: include_org_id_query_param=True, ) - def retrieve_analysis_result(self, analysis_id: int, analysis_view_id: int) -> Dict: + 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. @@ -1699,7 +1698,7 @@ def retrieve_analysis_result(self, analysis_id: int, analysis_view_id: int) -> D analysis_view_id (int): ID of the analysis view Returns: - Dict: Return the detailed results of a single analysis view + dict: Return the detailed results of a single analysis view """ return self.client.get( None, diff --git a/pyseed/seed_client_base.py b/pyseed/seed_client_base.py index a661e9f..22a009c 100644 --- a/pyseed/seed_client_base.py +++ b/pyseed/seed_client_base.py @@ -33,21 +33,23 @@ # Constants (Should end with a slash) URLS = { 'v3': { - 'columns': '/api/v3/columns/', 'column_mapping_profiles': '/api/v3/column_mapping_profiles/', 'column_mapping_profiles_filter': '/api/v3/column_mapping_profiles/filter/', + 'columns': '/api/v3/columns/', 'cycles': '/api/v3/cycles/', 'datasets': '/api/v3/datasets/', 'gbr_properties': '/api/v3/gbr_properties/', 'green_assessment': '/api/v3/green_assessments/', 'green_assessment_property': '/api/v3/green_assessment_properties/', 'green_assessment_url': '/api/v3/green_assessment_urls/', + 'import_files': '/api/v3/import_files/', + 'import_files_reuse_inventory_file_for_meters': '/api/v3/import_files/reuse_inventory_file_for_meters/', 'labels': '/api/v3/labels/', 'labels_property': '/api/v3/labels_property/', 'labels_taxlot': '/api/v3/labels_taxlot/', - 'import_files': '/api/v3/import_files/', - 'import_files_reuse_inventory_file_for_meters': '/api/v3/import_files/reuse_inventory_file_for_meters/', 'organizations': '/api/v3/organizations/', + 'portfolio_manager_report': '/api/v3/portfolio_manager/report/', + 'portfolio_manager_report_templates': '/api/v3/portfolio_manager/template_list/', 'properties': '/api/v3/properties/', 'properties_labels': '/api/v3/properties/labels/', 'properties_search': '/api/v3/properties/search/', @@ -58,27 +60,25 @@ # No versioning endpoints 'version': '/api/version/', # POSTs with replaceable keys - 'import_files_start_save_data_pk': '/api/v3/import_files/PK/start_save_data/', + 'import_files_check_meters_tab_exists_pk': '/api/v3/import_files/PK/check_meters_tab_exists/', 'import_files_start_map_data_pk': '/api/v3/import_files/PK/map/', 'import_files_start_matching_pk': '/api/v3/import_files/PK/start_system_matching_and_geocoding/', - 'import_files_check_meters_tab_exists_pk': '/api/v3/import_files/PK/check_meters_tab_exists/', + 'import_files_start_save_data_pk': '/api/v3/import_files/PK/start_save_data/', 'org_column_mapping_import_file': 'api/v3/organizations/ORG_ID/column_mappings/', - 'portfolio_manager_report_templates': '/api/v3/portfolio_manager/template_list/', - 'portfolio_manager_report': '/api/v3/portfolio_manager/report/', - # PUTs with replaceable keys: 'portfolio_manager_property_download': '/api/v3/portfolio_manager/PK/download/', + # PUTs with replaceable keys: 'properties_update_with_buildingsync': 'api/v3/properties/PK/update_with_building_sync/', - 'property_update_with_espm': 'api/v3/properties/PK/update_with_espm/', 'properties_upload_inventory_document': 'api/v3/properties/PK/upload_inventory_document', + 'property_update_with_espm': 'api/v3/properties/PK/update_with_espm/', # GETs with replaceable keys 'analyses_views': '/api/v3/analyses/PK/views/ANALYSIS_VIEW_PK/', + 'audit_template_building_xml': '/api/v3/audit_template/PK/get_building_xml', + 'audit_template_submission': '/api/v3/audit_template/PK/get_submission', 'import_files_matching_results': '/api/v3/import_files/PK/matching_and_geocoding_results/', 'progress': '/api/v3/progress/PROGRESS_KEY/', - 'properties_meters': '/api/v3/properties/PK/meters/', - 'properties_meter_usage': '/api/v3/properties/PK/meter_usage/', 'properties_analyses': '/api/v3/properties/PK/analyses/', - 'audit_template_building_xml': '/api/v3/audit_template/PK/get_building_xml', - 'audit_template_submission': '/api/v3/audit_template/PK/get_submission', + 'properties_meter_usage': '/api/v3/properties/PK/meter_usage/', + 'properties_meters': '/api/v3/properties/PK/meters/', # GET & POST with replaceable keys 'properties_meters_reading': '/api/v3/properties/PK/meters/METER_PK/readings/', }