EPA-PM-API-Wrapper 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- epa_pm_api_wrapper/__init__.py +30 -0
- epa_pm_api_wrapper/__main__.py +4 -0
- epa_pm_api_wrapper/cli.py +413 -0
- epa_pm_api_wrapper/client.py +507 -0
- epa_pm_api_wrapper/exceptions.py +67 -0
- epa_pm_api_wrapper/models/__init__.py +1451 -0
- epa_pm_api_wrapper/models/accept_reject_type.py +12 -0
- epa_pm_api_wrapper/models/account.py +15 -0
- epa_pm_api_wrapper/models/account_info.py +58 -0
- epa_pm_api_wrapper/models/account_type.py +122 -0
- epa_pm_api_wrapper/models/account_type_language_preference.py +9 -0
- epa_pm_api_wrapper/models/additional_identifier.py +58 -0
- epa_pm_api_wrapper/models/additional_identifier_type.py +60 -0
- epa_pm_api_wrapper/models/additional_identifier_type_group.py +10 -0
- epa_pm_api_wrapper/models/additional_identifier_types.py +19 -0
- epa_pm_api_wrapper/models/additional_identifiers.py +19 -0
- epa_pm_api_wrapper/models/address_type.py +84 -0
- epa_pm_api_wrapper/models/address_type_state.py +159 -0
- epa_pm_api_wrapper/models/adult_education.py +17 -0
- epa_pm_api_wrapper/models/agency_type.py +41 -0
- epa_pm_api_wrapper/models/agency_type_country.py +242 -0
- epa_pm_api_wrapper/models/alerts.py +16 -0
- epa_pm_api_wrapper/models/alerts_type.py +47 -0
- epa_pm_api_wrapper/models/alerts_type_alert.py +29 -0
- epa_pm_api_wrapper/models/all_energy_meters_type.py +32 -0
- epa_pm_api_wrapper/models/all_meter_types.py +130 -0
- epa_pm_api_wrapper/models/ambulatory_surgical_center.py +16 -0
- epa_pm_api_wrapper/models/amount_of_laundry_processed_annually.py +17 -0
- epa_pm_api_wrapper/models/amount_of_laundry_processed_annually_type.py +28 -0
- epa_pm_api_wrapper/models/amount_of_laundry_processed_annually_units_type.py +9 -0
- epa_pm_api_wrapper/models/annual_research_expenditure.py +16 -0
- epa_pm_api_wrapper/models/annual_research_expenditure_type.py +22 -0
- epa_pm_api_wrapper/models/annual_research_expenditure_type_value.py +10 -0
- epa_pm_api_wrapper/models/aquarium.py +17 -0
- epa_pm_api_wrapper/models/area_of_all_walk_in_refrigeration_units.py +19 -0
- epa_pm_api_wrapper/models/average_effluent_biological_oxygen_demand.py +16 -0
- epa_pm_api_wrapper/models/average_influent_biological_oxygen_demand.py +16 -0
- epa_pm_api_wrapper/models/average_number_of_residents.py +15 -0
- epa_pm_api_wrapper/models/average_number_of_vehicles_in_inventory.py +16 -0
- epa_pm_api_wrapper/models/bank_branch.py +16 -0
- epa_pm_api_wrapper/models/bank_branch_type.py +35 -0
- epa_pm_api_wrapper/models/bank_branch_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/bar_nightclub.py +17 -0
- epa_pm_api_wrapper/models/barracks.py +17 -0
- epa_pm_api_wrapper/models/barracks_type.py +35 -0
- epa_pm_api_wrapper/models/barracks_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/baseline_and_target.py +16 -0
- epa_pm_api_wrapper/models/baseline_and_target_type.py +27 -0
- epa_pm_api_wrapper/models/baseline_type.py +41 -0
- epa_pm_api_wrapper/models/billboard_metric_setting.py +21 -0
- epa_pm_api_wrapper/models/billboard_metric_type.py +33 -0
- epa_pm_api_wrapper/models/billboard_metrics.py +11 -0
- epa_pm_api_wrapper/models/billboard_metrics_type.py +26 -0
- epa_pm_api_wrapper/models/bowling_alley.py +40 -0
- epa_pm_api_wrapper/models/bowling_alley_use_details.py +58 -0
- epa_pm_api_wrapper/models/building.py +11 -0
- epa_pm_api_wrapper/models/casino.py +16 -0
- epa_pm_api_wrapper/models/category_type.py +17 -0
- epa_pm_api_wrapper/models/cegep.py +15 -0
- epa_pm_api_wrapper/models/cegep_type.py +35 -0
- epa_pm_api_wrapper/models/cegep_type_use_details.py +131 -0
- epa_pm_api_wrapper/models/ceiling_height.py +15 -0
- epa_pm_api_wrapper/models/ceiling_height_units_type.py +27 -0
- epa_pm_api_wrapper/models/clear_height.py +16 -0
- epa_pm_api_wrapper/models/clear_height_units_type.py +26 -0
- epa_pm_api_wrapper/models/college_university.py +15 -0
- epa_pm_api_wrapper/models/college_university_type.py +37 -0
- epa_pm_api_wrapper/models/college_university_type_use_details.py +131 -0
- epa_pm_api_wrapper/models/common_entrance.py +16 -0
- epa_pm_api_wrapper/models/community_center_and_social_meeting_hall.py +46 -0
- epa_pm_api_wrapper/models/community_center_and_social_meeting_hall_use_details.py +58 -0
- epa_pm_api_wrapper/models/completely_enclosed_footage.py +15 -0
- epa_pm_api_wrapper/models/construction_status_type.py +9 -0
- epa_pm_api_wrapper/models/contact_type.py +70 -0
- epa_pm_api_wrapper/models/convenience_store_with_gas_station.py +19 -0
- epa_pm_api_wrapper/models/convenience_store_with_gas_station_type.py +37 -0
- epa_pm_api_wrapper/models/convenience_store_with_gas_station_type_use_details.py +140 -0
- epa_pm_api_wrapper/models/convenience_store_without_gas_station.py +19 -0
- epa_pm_api_wrapper/models/convenience_store_without_gas_station_type.py +37 -0
- epa_pm_api_wrapper/models/convenience_store_without_gas_station_type_use_details.py +140 -0
- epa_pm_api_wrapper/models/convention_center.py +16 -0
- epa_pm_api_wrapper/models/cooking_facilities.py +15 -0
- epa_pm_api_wrapper/models/cooking_located_onsite.py +16 -0
- epa_pm_api_wrapper/models/cooling_equipment_redundancy.py +15 -0
- epa_pm_api_wrapper/models/cooling_equipment_redundancy_type.py +22 -0
- epa_pm_api_wrapper/models/cooling_equipment_redundancy_type_value.py +12 -0
- epa_pm_api_wrapper/models/country_code.py +16 -0
- epa_pm_api_wrapper/models/country_list.py +493 -0
- epa_pm_api_wrapper/models/courthouse.py +16 -0
- epa_pm_api_wrapper/models/courthouse_type.py +35 -0
- epa_pm_api_wrapper/models/courthouse_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/custom_field.py +109 -0
- epa_pm_api_wrapper/models/custom_field_list.py +20 -0
- epa_pm_api_wrapper/models/custom_field_list_custom_field.py +17 -0
- epa_pm_api_wrapper/models/custom_field_valid_characters.py +15 -0
- epa_pm_api_wrapper/models/custom_field_when_to_prompt.py +15 -0
- epa_pm_api_wrapper/models/custom_metric.py +49 -0
- epa_pm_api_wrapper/models/custom_units_type.py +19 -0
- epa_pm_api_wrapper/models/custom_use.py +15 -0
- epa_pm_api_wrapper/models/custom_use_detail1.py +15 -0
- epa_pm_api_wrapper/models/custom_use_detail2.py +15 -0
- epa_pm_api_wrapper/models/custom_use_details_type.py +50 -0
- epa_pm_api_wrapper/models/custom_use_details_type_data_type.py +8 -0
- epa_pm_api_wrapper/models/custom_use_type.py +35 -0
- epa_pm_api_wrapper/models/custom_use_type_use_details.py +27 -0
- epa_pm_api_wrapper/models/customer.py +77 -0
- epa_pm_api_wrapper/models/customer_language_preference.py +9 -0
- epa_pm_api_wrapper/models/data_center.py +17 -0
- epa_pm_api_wrapper/models/data_center_type.py +35 -0
- epa_pm_api_wrapper/models/data_center_type_use_details.py +50 -0
- epa_pm_api_wrapper/models/data_exchange_settings.py +37 -0
- epa_pm_api_wrapper/models/data_exchange_settings_supported_meter_types.py +20 -0
- epa_pm_api_wrapper/models/data_exchange_settings_terms_of_use.py +40 -0
- epa_pm_api_wrapper/models/data_request.py +88 -0
- epa_pm_api_wrapper/models/data_request_locations.py +19 -0
- epa_pm_api_wrapper/models/data_request_locations_location.py +22 -0
- epa_pm_api_wrapper/models/data_request_requester_details.py +32 -0
- epa_pm_api_wrapper/models/data_request_status_type.py +13 -0
- epa_pm_api_wrapper/models/data_response.py +47 -0
- epa_pm_api_wrapper/models/data_response_properties.py +20 -0
- epa_pm_api_wrapper/models/data_type.py +9 -0
- epa_pm_api_wrapper/models/delivery_facility.py +16 -0
- epa_pm_api_wrapper/models/demand_tracking_type.py +35 -0
- epa_pm_api_wrapper/models/design.py +15 -0
- epa_pm_api_wrapper/models/design_base_type.py +83 -0
- epa_pm_api_wrapper/models/design_base_type_estimated_energy_list.py +17 -0
- epa_pm_api_wrapper/models/design_base_type_property_uses.py +709 -0
- epa_pm_api_wrapper/models/design_base_type_target.py +34 -0
- epa_pm_api_wrapper/models/design_unit_of_measure.py +37 -0
- epa_pm_api_wrapper/models/detail_type.py +22 -0
- epa_pm_api_wrapper/models/details_types.py +20 -0
- epa_pm_api_wrapper/models/disposal_destination_type.py +60 -0
- epa_pm_api_wrapper/models/distribution_center.py +17 -0
- epa_pm_api_wrapper/models/distribution_center_type.py +37 -0
- epa_pm_api_wrapper/models/distribution_center_type_use_details.py +76 -0
- epa_pm_api_wrapper/models/drinking_water_treatment_and_distribution.py +18 -0
- epa_pm_api_wrapper/models/drinking_water_treatment_and_distribution_type.py +37 -0
- epa_pm_api_wrapper/models/drinking_water_treatment_and_distribution_type_use_details.py +18 -0
- epa_pm_api_wrapper/models/e_grid_subregion.py +38 -0
- epa_pm_api_wrapper/models/e_grid_subregion_country.py +242 -0
- epa_pm_api_wrapper/models/e_grid_subregion_list.py +19 -0
- epa_pm_api_wrapper/models/edu.py +64 -0
- epa_pm_api_wrapper/models/edu_list.py +18 -0
- epa_pm_api_wrapper/models/electric_vehicle_charging_station.py +15 -0
- epa_pm_api_wrapper/models/empty_string.py +7 -0
- epa_pm_api_wrapper/models/empty_type.py +7 -0
- epa_pm_api_wrapper/models/enclosed_floor_area.py +15 -0
- epa_pm_api_wrapper/models/enclosed_mall.py +16 -0
- epa_pm_api_wrapper/models/energy_meter_assoc_and_config_type.py +25 -0
- epa_pm_api_wrapper/models/energy_performance_project.py +11 -0
- epa_pm_api_wrapper/models/energy_performance_project_type.py +136 -0
- epa_pm_api_wrapper/models/energy_power_station.py +20 -0
- epa_pm_api_wrapper/models/energy_uom_type.py +11 -0
- epa_pm_api_wrapper/models/enrollment.py +11 -0
- epa_pm_api_wrapper/models/error_type.py +29 -0
- epa_pm_api_wrapper/models/errors_type.py +25 -0
- epa_pm_api_wrapper/models/estimated_energy_list_type.py +19 -0
- epa_pm_api_wrapper/models/estimated_energy_type.py +58 -0
- epa_pm_api_wrapper/models/estimates_applied.py +15 -0
- epa_pm_api_wrapper/models/ev_charging_station_type.py +37 -0
- epa_pm_api_wrapper/models/ev_charging_station_type_use_details.py +41 -0
- epa_pm_api_wrapper/models/evaluation_period_type.py +35 -0
- epa_pm_api_wrapper/models/exterior_entrance_to_the_public.py +15 -0
- epa_pm_api_wrapper/models/fast_food_restaurant.py +17 -0
- epa_pm_api_wrapper/models/fast_food_restaurant_type.py +37 -0
- epa_pm_api_wrapper/models/fast_food_restaurant_type_use_details.py +84 -0
- epa_pm_api_wrapper/models/federal_agencies.py +19 -0
- epa_pm_api_wrapper/models/financial_office.py +16 -0
- epa_pm_api_wrapper/models/financial_office_type.py +35 -0
- epa_pm_api_wrapper/models/financial_office_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/fire_station.py +16 -0
- epa_pm_api_wrapper/models/fire_station_type.py +35 -0
- epa_pm_api_wrapper/models/fire_station_type_use_details.py +92 -0
- epa_pm_api_wrapper/models/fitness_center_health_club_gym.py +42 -0
- epa_pm_api_wrapper/models/fitness_center_health_club_gym_use_details.py +58 -0
- epa_pm_api_wrapper/models/fixed_film_trickle_filtration_process.py +15 -0
- epa_pm_api_wrapper/models/floor_area_type_base.py +23 -0
- epa_pm_api_wrapper/models/food_sales.py +17 -0
- epa_pm_api_wrapper/models/food_sales_type.py +35 -0
- epa_pm_api_wrapper/models/food_sales_type_use_details.py +114 -0
- epa_pm_api_wrapper/models/food_service.py +17 -0
- epa_pm_api_wrapper/models/full_service_spa_floor_area.py +15 -0
- epa_pm_api_wrapper/models/generation_location_type.py +41 -0
- epa_pm_api_wrapper/models/government_subsidized_housing.py +16 -0
- epa_pm_api_wrapper/models/grant_dollars.py +11 -0
- epa_pm_api_wrapper/models/green_power_fuel_source_enum.py +13 -0
- epa_pm_api_wrapper/models/green_power_type_enum.py +15 -0
- epa_pm_api_wrapper/models/gross_floor_area_hotel_conference_space.py +18 -0
- epa_pm_api_wrapper/models/gross_floor_area_that_is_exhibit_space.py +19 -0
- epa_pm_api_wrapper/models/gross_floor_area_type.py +24 -0
- epa_pm_api_wrapper/models/gross_floor_area_units_type.py +8 -0
- epa_pm_api_wrapper/models/gross_floor_area_used_for_food_preparation.py +19 -0
- epa_pm_api_wrapper/models/gym_center_floor_area.py +15 -0
- epa_pm_api_wrapper/models/gymnasium_floor_area.py +15 -0
- epa_pm_api_wrapper/models/has_computer_lab.py +15 -0
- epa_pm_api_wrapper/models/has_dining_hall.py +15 -0
- epa_pm_api_wrapper/models/has_laboratory.py +15 -0
- epa_pm_api_wrapper/models/hey.py +11 -0
- epa_pm_api_wrapper/models/hey_type.py +29 -0
- epa_pm_api_wrapper/models/hey_type_meter.py +35 -0
- epa_pm_api_wrapper/models/hey_type_meter_meter_data.py +22 -0
- epa_pm_api_wrapper/models/hey_type_property_info.py +35 -0
- epa_pm_api_wrapper/models/hierarchy.py +16 -0
- epa_pm_api_wrapper/models/hierarchy_type.py +84 -0
- epa_pm_api_wrapper/models/highest_award_level.py +17 -0
- epa_pm_api_wrapper/models/highest_award_level_type.py +20 -0
- epa_pm_api_wrapper/models/highest_award_level_type_value.py +11 -0
- epa_pm_api_wrapper/models/hospital.py +22 -0
- epa_pm_api_wrapper/models/hospital_type.py +35 -0
- epa_pm_api_wrapper/models/hospital_type_use_details.py +132 -0
- epa_pm_api_wrapper/models/hotel.py +17 -0
- epa_pm_api_wrapper/models/hotel_type.py +41 -0
- epa_pm_api_wrapper/models/hotel_type_use_details.py +140 -0
- epa_pm_api_wrapper/models/hours_per_day_guests_onsite.py +16 -0
- epa_pm_api_wrapper/models/hours_per_day_guests_onsite_type.py +22 -0
- epa_pm_api_wrapper/models/hours_per_day_guests_onsite_type_value.py +9 -0
- epa_pm_api_wrapper/models/ice_curling_rink.py +27 -0
- epa_pm_api_wrapper/models/ice_curling_rink_type.py +35 -0
- epa_pm_api_wrapper/models/ice_curling_rink_type_use_details.py +78 -0
- epa_pm_api_wrapper/models/ice_events.py +15 -0
- epa_pm_api_wrapper/models/individual_meter.py +86 -0
- epa_pm_api_wrapper/models/indoor_arena.py +17 -0
- epa_pm_api_wrapper/models/indoor_arena_type.py +35 -0
- epa_pm_api_wrapper/models/indoor_arena_type_use_details.py +104 -0
- epa_pm_api_wrapper/models/international_weather_station_list.py +26 -0
- epa_pm_api_wrapper/models/irrigation_area_type.py +28 -0
- epa_pm_api_wrapper/models/irrigation_area_type_base.py +30 -0
- epa_pm_api_wrapper/models/irrigation_area_units_type.py +10 -0
- epa_pm_api_wrapper/models/is_high_school.py +16 -0
- epa_pm_api_wrapper/models/is_tertiary_care.py +17 -0
- epa_pm_api_wrapper/models/it_energy_configuration_type.py +20 -0
- epa_pm_api_wrapper/models/it_energy_configuration_type_value.py +14 -0
- epa_pm_api_wrapper/models/it_energy_meter_configuration.py +16 -0
- epa_pm_api_wrapper/models/k12_school.py +16 -0
- epa_pm_api_wrapper/models/k12_school_type.py +35 -0
- epa_pm_api_wrapper/models/k12_school_type_use_details.py +126 -0
- epa_pm_api_wrapper/models/laboratory.py +17 -0
- epa_pm_api_wrapper/models/laundry_facility.py +16 -0
- epa_pm_api_wrapper/models/length_of_all_commercial_kitchen_hoods.py +19 -0
- epa_pm_api_wrapper/models/length_of_all_open_closed_refrigeration_units.py +21 -0
- epa_pm_api_wrapper/models/length_of_use_detail_type.py +26 -0
- epa_pm_api_wrapper/models/length_units_type.py +8 -0
- epa_pm_api_wrapper/models/library.py +17 -0
- epa_pm_api_wrapper/models/library_type.py +35 -0
- epa_pm_api_wrapper/models/library_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/license.py +60 -0
- epa_pm_api_wrapper/models/license_list.py +19 -0
- epa_pm_api_wrapper/models/licensed_bed_capacity.py +19 -0
- epa_pm_api_wrapper/models/lifestyle_center.py +18 -0
- epa_pm_api_wrapper/models/link_type.py +52 -0
- epa_pm_api_wrapper/models/links_type.py +19 -0
- epa_pm_api_wrapper/models/log.py +11 -0
- epa_pm_api_wrapper/models/log_type.py +79 -0
- epa_pm_api_wrapper/models/mailing_center_post_office.py +16 -0
- epa_pm_api_wrapper/models/mailing_center_post_office_type.py +37 -0
- epa_pm_api_wrapper/models/mailing_center_post_office_type_use_details.py +74 -0
- epa_pm_api_wrapper/models/manufacturing_industrial_plant.py +17 -0
- epa_pm_api_wrapper/models/manufacturing_industrial_plant_type.py +37 -0
- epa_pm_api_wrapper/models/manufacturing_industrial_plant_type_use_details.py +49 -0
- epa_pm_api_wrapper/models/mapping.py +11 -0
- epa_pm_api_wrapper/models/mapping_type.py +23 -0
- epa_pm_api_wrapper/models/maximum_number_of_floors.py +15 -0
- epa_pm_api_wrapper/models/maximum_resident_capacity.py +15 -0
- epa_pm_api_wrapper/models/medical_office.py +16 -0
- epa_pm_api_wrapper/models/medical_office_type.py +35 -0
- epa_pm_api_wrapper/models/medical_office_type_use_details.py +82 -0
- epa_pm_api_wrapper/models/meter.py +11 -0
- epa_pm_api_wrapper/models/meter_category_type.py +9 -0
- epa_pm_api_wrapper/models/meter_consumption.py +15 -0
- epa_pm_api_wrapper/models/meter_consumption_type.py +110 -0
- epa_pm_api_wrapper/models/meter_data.py +11 -0
- epa_pm_api_wrapper/models/meter_data_type.py +41 -0
- epa_pm_api_wrapper/models/meter_delivery.py +11 -0
- epa_pm_api_wrapper/models/meter_delivery_type.py +68 -0
- epa_pm_api_wrapper/models/meter_list_type.py +23 -0
- epa_pm_api_wrapper/models/meter_property_association_list.py +18 -0
- epa_pm_api_wrapper/models/meter_property_association_list_type.py +38 -0
- epa_pm_api_wrapper/models/meter_property_use_association_list.py +16 -0
- epa_pm_api_wrapper/models/meter_type.py +131 -0
- epa_pm_api_wrapper/models/meter_type_unit_of_measure.py +40 -0
- epa_pm_api_wrapper/models/metric.py +71 -0
- epa_pm_api_wrapper/models/months_in_use.py +15 -0
- epa_pm_api_wrapper/models/months_in_use_type.py +21 -0
- epa_pm_api_wrapper/models/months_main_indoor_ice_rink_in_use.py +15 -0
- epa_pm_api_wrapper/models/months_school_in_use_type.py +21 -0
- epa_pm_api_wrapper/models/movie_theater.py +15 -0
- epa_pm_api_wrapper/models/multifamily_housing.py +16 -0
- epa_pm_api_wrapper/models/multifamily_housing_type.py +37 -0
- epa_pm_api_wrapper/models/multifamily_housing_type_use_details.py +124 -0
- epa_pm_api_wrapper/models/museum.py +26 -0
- epa_pm_api_wrapper/models/museum_type.py +35 -0
- epa_pm_api_wrapper/models/museum_type_use_details.py +78 -0
- epa_pm_api_wrapper/models/non_refrigerated_warehouse.py +16 -0
- epa_pm_api_wrapper/models/non_refrigerated_warehouse_type.py +37 -0
- epa_pm_api_wrapper/models/non_refrigerated_warehouse_type_use_details.py +76 -0
- epa_pm_api_wrapper/models/notification_list.py +16 -0
- epa_pm_api_wrapper/models/notification_list_type.py +19 -0
- epa_pm_api_wrapper/models/notification_type.py +106 -0
- epa_pm_api_wrapper/models/number_of_annual_emergency_incidents.py +17 -0
- epa_pm_api_wrapper/models/number_of_bedrooms.py +15 -0
- epa_pm_api_wrapper/models/number_of_cash_registers.py +15 -0
- epa_pm_api_wrapper/models/number_of_commercial_refrigeration_units.py +16 -0
- epa_pm_api_wrapper/models/number_of_commercial_washing_machines.py +16 -0
- epa_pm_api_wrapper/models/number_of_computers.py +15 -0
- epa_pm_api_wrapper/models/number_of_concert_show_events_per_year.py +15 -0
- epa_pm_api_wrapper/models/number_of_cooking_equipment_units.py +15 -0
- epa_pm_api_wrapper/models/number_of_curling_sheets.py +16 -0
- epa_pm_api_wrapper/models/number_of_dc_fast_ev_charging_stations.py +15 -0
- epa_pm_api_wrapper/models/number_of_emergency_vehicles.py +16 -0
- epa_pm_api_wrapper/models/number_of_fteworkers.py +16 -0
- epa_pm_api_wrapper/models/number_of_full_time_students_enrolled_january_to_april.py +16 -0
- epa_pm_api_wrapper/models/number_of_full_time_students_enrolled_may_to_august.py +16 -0
- epa_pm_api_wrapper/models/number_of_full_time_students_enrolled_september_to_december.py +16 -0
- epa_pm_api_wrapper/models/number_of_guest_meals_served_per_year.py +15 -0
- epa_pm_api_wrapper/models/number_of_hotel_rooms.py +15 -0
- epa_pm_api_wrapper/models/number_of_indoor_ice_rinks.py +18 -0
- epa_pm_api_wrapper/models/number_of_laundry_hookups_in_all_units.py +16 -0
- epa_pm_api_wrapper/models/number_of_laundry_hookups_in_common_area.py +16 -0
- epa_pm_api_wrapper/models/number_of_letters_packages_per_year.py +17 -0
- epa_pm_api_wrapper/models/number_of_level_one_ev_charging_stations.py +15 -0
- epa_pm_api_wrapper/models/number_of_level_two_ev_charging_stations.py +15 -0
- epa_pm_api_wrapper/models/number_of_mri_machines.py +15 -0
- epa_pm_api_wrapper/models/number_of_open_closed_refrigeration_units.py +27 -0
- epa_pm_api_wrapper/models/number_of_paint_bays.py +16 -0
- epa_pm_api_wrapper/models/number_of_people.py +15 -0
- epa_pm_api_wrapper/models/number_of_repair_bays.py +16 -0
- epa_pm_api_wrapper/models/number_of_residential_lift_systems.py +15 -0
- epa_pm_api_wrapper/models/number_of_residential_living_units.py +20 -0
- epa_pm_api_wrapper/models/number_of_residential_living_units_high_rise_setting.py +18 -0
- epa_pm_api_wrapper/models/number_of_residential_living_units_low_rise_setting.py +18 -0
- epa_pm_api_wrapper/models/number_of_residential_living_units_mid_rise_setting.py +18 -0
- epa_pm_api_wrapper/models/number_of_residential_washing_machines.py +15 -0
- epa_pm_api_wrapper/models/number_of_rooms.py +16 -0
- epa_pm_api_wrapper/models/number_of_special_other_events_per_year.py +16 -0
- epa_pm_api_wrapper/models/number_of_sporting_events_per_year.py +15 -0
- epa_pm_api_wrapper/models/number_of_staffed_beds.py +15 -0
- epa_pm_api_wrapper/models/number_of_sterilization_units.py +15 -0
- epa_pm_api_wrapper/models/number_of_surgical_operating_beds.py +16 -0
- epa_pm_api_wrapper/models/number_of_walk_in_refrigeration_units.py +16 -0
- epa_pm_api_wrapper/models/number_of_warming_heating_equipment_units.py +15 -0
- epa_pm_api_wrapper/models/number_of_weekdays_open.py +17 -0
- epa_pm_api_wrapper/models/number_of_weekdays_type.py +21 -0
- epa_pm_api_wrapper/models/number_of_weekly_ice_resurfacing_for_all_rinks.py +23 -0
- epa_pm_api_wrapper/models/number_of_weekly_ice_resurfacing_type.py +20 -0
- epa_pm_api_wrapper/models/number_of_workers.py +16 -0
- epa_pm_api_wrapper/models/nutrient_removal.py +16 -0
- epa_pm_api_wrapper/models/occupancy_type.py +27 -0
- epa_pm_api_wrapper/models/office.py +16 -0
- epa_pm_api_wrapper/models/office_type.py +35 -0
- epa_pm_api_wrapper/models/office_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase.py +11 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type.py +224 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_amount_purchased.py +31 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_amount_purchased_percentage.py +46 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_amount_purchased_percentage_meters.py +21 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_amount_purchased_quantity.py +31 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_cost.py +31 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_fuel_sources.py +22 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_fuel_sources_fuel_source.py +35 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_rated_capacity.py +31 -0
- epa_pm_api_wrapper/models/offsite_green_power_purchase_type_renewable_generation_technologies.py +21 -0
- epa_pm_api_wrapper/models/on_site_laundry_facility.py +15 -0
- epa_pm_api_wrapper/models/onsite_laundry_type.py +20 -0
- epa_pm_api_wrapper/models/onsite_laundry_type_value.py +10 -0
- epa_pm_api_wrapper/models/onsite_renewable_detail.py +11 -0
- epa_pm_api_wrapper/models/onsite_renewable_detail_type.py +60 -0
- epa_pm_api_wrapper/models/onsite_renewable_details.py +28 -0
- epa_pm_api_wrapper/models/onsite_renewable_optional_info.py +13 -0
- epa_pm_api_wrapper/models/onsite_renewable_optional_info_type.py +134 -0
- epa_pm_api_wrapper/models/onsite_renewable_optional_info_type_rated_capacity.py +31 -0
- epa_pm_api_wrapper/models/onsite_renewable_optional_info_type_renewable_generation_technologies.py +21 -0
- epa_pm_api_wrapper/models/onsite_usage_detail_type.py +70 -0
- epa_pm_api_wrapper/models/open_footage.py +15 -0
- epa_pm_api_wrapper/models/open_on_weekends.py +16 -0
- epa_pm_api_wrapper/models/optional_floor_area_type.py +19 -0
- epa_pm_api_wrapper/models/organization_type.py +77 -0
- epa_pm_api_wrapper/models/other.py +16 -0
- epa_pm_api_wrapper/models/other_education.py +18 -0
- epa_pm_api_wrapper/models/other_entertainment_public_assembly.py +17 -0
- epa_pm_api_wrapper/models/other_lodging_residential.py +19 -0
- epa_pm_api_wrapper/models/other_mall.py +17 -0
- epa_pm_api_wrapper/models/other_public_services.py +21 -0
- epa_pm_api_wrapper/models/other_recreation.py +16 -0
- epa_pm_api_wrapper/models/other_restaurant_bar.py +17 -0
- epa_pm_api_wrapper/models/other_services.py +16 -0
- epa_pm_api_wrapper/models/other_speciality_hospital.py +17 -0
- epa_pm_api_wrapper/models/other_stadium.py +16 -0
- epa_pm_api_wrapper/models/other_stadium_type.py +35 -0
- epa_pm_api_wrapper/models/other_stadium_type_use_details.py +104 -0
- epa_pm_api_wrapper/models/other_technology_science.py +16 -0
- epa_pm_api_wrapper/models/other_type.py +35 -0
- epa_pm_api_wrapper/models/other_type_use_details.py +42 -0
- epa_pm_api_wrapper/models/other_utility.py +16 -0
- epa_pm_api_wrapper/models/outpatient_rehabilitation_physical_therapy.py +16 -0
- epa_pm_api_wrapper/models/owned_by.py +16 -0
- epa_pm_api_wrapper/models/owned_by_type.py +20 -0
- epa_pm_api_wrapper/models/owned_by_type_value.py +9 -0
- epa_pm_api_wrapper/models/parking.py +15 -0
- epa_pm_api_wrapper/models/parking_type.py +35 -0
- epa_pm_api_wrapper/models/parking_type_use_details.py +40 -0
- epa_pm_api_wrapper/models/partially_enclosed_footage.py +16 -0
- epa_pm_api_wrapper/models/ped.py +26 -0
- epa_pm_api_wrapper/models/pending_accounts_type.py +58 -0
- epa_pm_api_wrapper/models/pending_list.py +15 -0
- epa_pm_api_wrapper/models/pending_list_type.py +53 -0
- epa_pm_api_wrapper/models/pending_meters_type.py +104 -0
- epa_pm_api_wrapper/models/pending_properties_type.py +77 -0
- epa_pm_api_wrapper/models/percent_cooled.py +16 -0
- epa_pm_api_wrapper/models/percent_cooled_type.py +20 -0
- epa_pm_api_wrapper/models/percent_cooled_type_value.py +17 -0
- epa_pm_api_wrapper/models/percent_heated.py +16 -0
- epa_pm_api_wrapper/models/percent_heated_type.py +20 -0
- epa_pm_api_wrapper/models/percent_heated_type_value.py +17 -0
- epa_pm_api_wrapper/models/percent_of_gross_floor_area_that_is_common_space_only.py +16 -0
- epa_pm_api_wrapper/models/percent_of_lab_floor_area.py +16 -0
- epa_pm_api_wrapper/models/percent_office_cooled.py +11 -0
- epa_pm_api_wrapper/models/percent_office_cooled_type.py +20 -0
- epa_pm_api_wrapper/models/percent_office_cooled_type_value.py +9 -0
- epa_pm_api_wrapper/models/percent_office_heated.py +11 -0
- epa_pm_api_wrapper/models/percent_office_heated_type.py +20 -0
- epa_pm_api_wrapper/models/percent_office_heated_type_value.py +9 -0
- epa_pm_api_wrapper/models/percent_used_for_cold_storage.py +18 -0
- epa_pm_api_wrapper/models/performance_target_type.py +42 -0
- epa_pm_api_wrapper/models/performance_target_type_target_metric.py +10 -0
- epa_pm_api_wrapper/models/performance_target_type_target_value.py +107 -0
- epa_pm_api_wrapper/models/performing_arts.py +15 -0
- epa_pm_api_wrapper/models/period_type.py +8 -0
- epa_pm_api_wrapper/models/personal_services.py +17 -0
- epa_pm_api_wrapper/models/pgp.py +56 -0
- epa_pm_api_wrapper/models/pgp_list.py +18 -0
- epa_pm_api_wrapper/models/plant_data_type.py +28 -0
- epa_pm_api_wrapper/models/plant_data_type_value.py +71 -0
- epa_pm_api_wrapper/models/plant_design_flow_rate.py +16 -0
- epa_pm_api_wrapper/models/plant_design_flow_rate_type.py +22 -0
- epa_pm_api_wrapper/models/plant_design_flow_rate_units_type.py +8 -0
- epa_pm_api_wrapper/models/plant_type.py +17 -0
- epa_pm_api_wrapper/models/police_station.py +16 -0
- epa_pm_api_wrapper/models/pool_location.py +15 -0
- epa_pm_api_wrapper/models/pool_size.py +16 -0
- epa_pm_api_wrapper/models/pool_size_type.py +20 -0
- epa_pm_api_wrapper/models/pool_size_type_value.py +9 -0
- epa_pm_api_wrapper/models/pool_type.py +20 -0
- epa_pm_api_wrapper/models/pool_type_value.py +8 -0
- epa_pm_api_wrapper/models/precision_controls_for_temperature_and_humidity.py +16 -0
- epa_pm_api_wrapper/models/preschool_daycare.py +17 -0
- epa_pm_api_wrapper/models/preschool_daycare_type.py +35 -0
- epa_pm_api_wrapper/models/preschool_daycare_type_use_details.py +68 -0
- epa_pm_api_wrapper/models/primary_business_type.py +33 -0
- epa_pm_api_wrapper/models/primary_function_type.py +95 -0
- epa_pm_api_wrapper/models/prison.py +17 -0
- epa_pm_api_wrapper/models/professional_designation_list.py +23 -0
- epa_pm_api_wrapper/models/professional_designation_list_professional_designation.py +41 -0
- epa_pm_api_wrapper/models/property.py +11 -0
- epa_pm_api_wrapper/models/property_design_type.py +66 -0
- epa_pm_api_wrapper/models/property_metrics.py +15 -0
- epa_pm_api_wrapper/models/property_metrics_list.py +19 -0
- epa_pm_api_wrapper/models/property_metrics_type.py +58 -0
- epa_pm_api_wrapper/models/property_representation.py +59 -0
- epa_pm_api_wrapper/models/property_representation_property_representation_type.py +27 -0
- epa_pm_api_wrapper/models/property_type.py +192 -0
- epa_pm_api_wrapper/models/property_use.py +22 -0
- epa_pm_api_wrapper/models/race_track.py +16 -0
- epa_pm_api_wrapper/models/rated_capacity_uom_type.py +8 -0
- epa_pm_api_wrapper/models/rec_ownership_enum.py +10 -0
- epa_pm_api_wrapper/models/refrigerated_warehouse.py +17 -0
- epa_pm_api_wrapper/models/refrigerated_warehouse_type.py +37 -0
- epa_pm_api_wrapper/models/refrigerated_warehouse_type_use_details.py +66 -0
- epa_pm_api_wrapper/models/renewable_generation_technology_enum.py +11 -0
- epa_pm_api_wrapper/models/report.py +72 -0
- epa_pm_api_wrapper/models/report_error.py +53 -0
- epa_pm_api_wrapper/models/report_error_missing_metrics.py +21 -0
- epa_pm_api_wrapper/models/report_error_missing_metrics_property_missing_metric.py +43 -0
- epa_pm_api_wrapper/models/report_error_missing_metrics_property_missing_metric_metric.py +33 -0
- epa_pm_api_wrapper/models/report_metric_values_ws.py +57 -0
- epa_pm_api_wrapper/models/report_metrics.py +26 -0
- epa_pm_api_wrapper/models/report_metrics_group.py +36 -0
- epa_pm_api_wrapper/models/report_metrics_group_metrics.py +24 -0
- epa_pm_api_wrapper/models/report_metrics_group_metrics_metric.py +62 -0
- epa_pm_api_wrapper/models/report_properties.py +20 -0
- epa_pm_api_wrapper/models/report_status.py +11 -0
- epa_pm_api_wrapper/models/report_status_def.py +62 -0
- epa_pm_api_wrapper/models/report_status_type.py +33 -0
- epa_pm_api_wrapper/models/report_template.py +11 -0
- epa_pm_api_wrapper/models/report_template_type.py +63 -0
- epa_pm_api_wrapper/models/report_template_type_metrics.py +21 -0
- epa_pm_api_wrapper/models/report_type.py +17 -0
- epa_pm_api_wrapper/models/reporting_interval_type.py +15 -0
- epa_pm_api_wrapper/models/residence_hall_dormitory.py +16 -0
- epa_pm_api_wrapper/models/residence_hall_dormitory_type.py +37 -0
- epa_pm_api_wrapper/models/residence_hall_dormitory_type_use_details.py +58 -0
- epa_pm_api_wrapper/models/resident_population.py +16 -0
- epa_pm_api_wrapper/models/resident_population_type.py +20 -0
- epa_pm_api_wrapper/models/resident_population_type_value.py +12 -0
- epa_pm_api_wrapper/models/residential_care_facility.py +16 -0
- epa_pm_api_wrapper/models/residential_care_facility_type.py +37 -0
- epa_pm_api_wrapper/models/residential_care_facility_type_use_details.py +120 -0
- epa_pm_api_wrapper/models/response.py +11 -0
- epa_pm_api_wrapper/models/response_status.py +36 -0
- epa_pm_api_wrapper/models/response_status_errors.py +19 -0
- epa_pm_api_wrapper/models/response_type.py +59 -0
- epa_pm_api_wrapper/models/restaurant.py +20 -0
- epa_pm_api_wrapper/models/restaurant_type.py +35 -0
- epa_pm_api_wrapper/models/restaurant_type_use_details.py +84 -0
- epa_pm_api_wrapper/models/retail.py +17 -0
- epa_pm_api_wrapper/models/retail_type.py +35 -0
- epa_pm_api_wrapper/models/retail_type_use_details.py +130 -0
- epa_pm_api_wrapper/models/roller_rink.py +16 -0
- epa_pm_api_wrapper/models/school_district.py +15 -0
- epa_pm_api_wrapper/models/search_result_type.py +23 -0
- epa_pm_api_wrapper/models/search_results.py +15 -0
- epa_pm_api_wrapper/models/seating_capacity.py +16 -0
- epa_pm_api_wrapper/models/self_storage_facility.py +15 -0
- epa_pm_api_wrapper/models/self_storage_facility_type.py +37 -0
- epa_pm_api_wrapper/models/self_storage_facility_type_use_details.py +84 -0
- epa_pm_api_wrapper/models/send_data_response.py +43 -0
- epa_pm_api_wrapper/models/send_data_response_additional_email_addresses.py +17 -0
- epa_pm_api_wrapper/models/send_data_response_file_format.py +8 -0
- epa_pm_api_wrapper/models/senior_living_community.py +16 -0
- epa_pm_api_wrapper/models/senior_living_community_type.py +37 -0
- epa_pm_api_wrapper/models/senior_living_community_type_use_details.py +120 -0
- epa_pm_api_wrapper/models/share_level_type.py +12 -0
- epa_pm_api_wrapper/models/sharing_response.py +16 -0
- epa_pm_api_wrapper/models/sharing_response_type.py +34 -0
- epa_pm_api_wrapper/models/single_family_home.py +16 -0
- epa_pm_api_wrapper/models/single_family_home_type.py +35 -0
- epa_pm_api_wrapper/models/single_family_home_type_use_details.py +34 -0
- epa_pm_api_wrapper/models/single_store.py +15 -0
- epa_pm_api_wrapper/models/size_of_electronic_score_boards.py +15 -0
- epa_pm_api_wrapper/models/spectator_seating_capacity.py +16 -0
- epa_pm_api_wrapper/models/stadium_closed.py +17 -0
- epa_pm_api_wrapper/models/stadium_closed_type.py +35 -0
- epa_pm_api_wrapper/models/stadium_closed_type_use_details.py +104 -0
- epa_pm_api_wrapper/models/stadium_open.py +17 -0
- epa_pm_api_wrapper/models/stadium_open_type.py +35 -0
- epa_pm_api_wrapper/models/stadium_open_type_use_details.py +104 -0
- epa_pm_api_wrapper/models/state_code.py +159 -0
- epa_pm_api_wrapper/models/station.py +45 -0
- epa_pm_api_wrapper/models/status_type.py +8 -0
- epa_pm_api_wrapper/models/strip_mall.py +17 -0
- epa_pm_api_wrapper/models/student_seating_capacity.py +16 -0
- epa_pm_api_wrapper/models/supermarket.py +17 -0
- epa_pm_api_wrapper/models/supermarket_type.py +35 -0
- epa_pm_api_wrapper/models/supermarket_type_use_details.py +114 -0
- epa_pm_api_wrapper/models/supplemental_heating.py +15 -0
- epa_pm_api_wrapper/models/surgery_center_floor_area.py +16 -0
- epa_pm_api_wrapper/models/swimming_pool.py +15 -0
- epa_pm_api_wrapper/models/swimming_pool_type.py +35 -0
- epa_pm_api_wrapper/models/swimming_pool_type_use_details.py +34 -0
- epa_pm_api_wrapper/models/system_determined_string.py +7 -0
- epa_pm_api_wrapper/models/target_finder.py +11 -0
- epa_pm_api_wrapper/models/target_type_percentage_type.py +17 -0
- epa_pm_api_wrapper/models/target_type_percentage_values_type.py +107 -0
- epa_pm_api_wrapper/models/target_type_score_type.py +17 -0
- epa_pm_api_wrapper/models/target_type_score_values_type.py +106 -0
- epa_pm_api_wrapper/models/template_type.py +19 -0
- epa_pm_api_wrapper/models/template_type_value.py +15 -0
- epa_pm_api_wrapper/models/tenant_common_area_energy_type.py +21 -0
- epa_pm_api_wrapper/models/tenant_common_area_energy_use_information_type.py +31 -0
- epa_pm_api_wrapper/models/terminate_share_response_type.py +24 -0
- epa_pm_api_wrapper/models/terminate_sharing_response.py +16 -0
- epa_pm_api_wrapper/models/timeframe_type.py +103 -0
- epa_pm_api_wrapper/models/timeframe_type_baseline_period.py +18 -0
- epa_pm_api_wrapper/models/timeframe_type_compare_baseline_period.py +25 -0
- epa_pm_api_wrapper/models/timeframe_type_compare_current_period.py +25 -0
- epa_pm_api_wrapper/models/timeframe_type_current_period.py +18 -0
- epa_pm_api_wrapper/models/timeframe_type_current_vs_baseline.py +18 -0
- epa_pm_api_wrapper/models/timeframe_type_date_range.py +30 -0
- epa_pm_api_wrapper/models/timeframe_type_single_period.py +18 -0
- epa_pm_api_wrapper/models/timeframe_type_two_periods.py +24 -0
- epa_pm_api_wrapper/models/total_gross_floor_area.py +11 -0
- epa_pm_api_wrapper/models/total_ice_rink_surface_area_for_all_rinks.py +21 -0
- epa_pm_api_wrapper/models/transportation_terminal_station.py +16 -0
- epa_pm_api_wrapper/models/type_of_energy_star_partner.py +14 -0
- epa_pm_api_wrapper/models/type_of_meter.py +55 -0
- epa_pm_api_wrapper/models/type_of_waste_meter.py +122 -0
- epa_pm_api_wrapper/models/type_of_waste_meter_data_entry_method.py +18 -0
- epa_pm_api_wrapper/models/type_of_waste_meter_unit_of_measure.py +15 -0
- epa_pm_api_wrapper/models/un_auth_design_type.py +100 -0
- epa_pm_api_wrapper/models/un_auth_design_type_estimated_energy_list.py +17 -0
- epa_pm_api_wrapper/models/un_auth_design_type_property_uses.py +709 -0
- epa_pm_api_wrapper/models/un_auth_design_type_target.py +34 -0
- epa_pm_api_wrapper/models/ups_system_redundancy.py +16 -0
- epa_pm_api_wrapper/models/ups_system_redundancy_type.py +20 -0
- epa_pm_api_wrapper/models/ups_system_redundancy_type_value.py +12 -0
- epa_pm_api_wrapper/models/urgent_care_clinic_other_outpatient.py +17 -0
- epa_pm_api_wrapper/models/use_attribute_base.py +65 -0
- epa_pm_api_wrapper/models/use_attribute_base_default.py +9 -0
- epa_pm_api_wrapper/models/use_decimal_type.py +21 -0
- epa_pm_api_wrapper/models/use_details.py +1086 -0
- epa_pm_api_wrapper/models/use_integer_type.py +20 -0
- epa_pm_api_wrapper/models/use_string_type.py +19 -0
- epa_pm_api_wrapper/models/use_yes_no_type.py +20 -0
- epa_pm_api_wrapper/models/vehicle_dealership.py +16 -0
- epa_pm_api_wrapper/models/vehicle_dealership_type.py +37 -0
- epa_pm_api_wrapper/models/vehicle_dealership_type_use_details.py +84 -0
- epa_pm_api_wrapper/models/vehicle_repair_services.py +19 -0
- epa_pm_api_wrapper/models/vehicle_repair_services_type.py +37 -0
- epa_pm_api_wrapper/models/vehicle_repair_services_type_use_details.py +74 -0
- epa_pm_api_wrapper/models/verification.py +96 -0
- epa_pm_api_wrapper/models/veterinary_office.py +15 -0
- epa_pm_api_wrapper/models/vocational_school.py +16 -0
- epa_pm_api_wrapper/models/warning_type.py +29 -0
- epa_pm_api_wrapper/models/warnings_type.py +25 -0
- epa_pm_api_wrapper/models/waste_data.py +15 -0
- epa_pm_api_wrapper/models/waste_data_list.py +11 -0
- epa_pm_api_wrapper/models/waste_meter.py +11 -0
- epa_pm_api_wrapper/models/waste_meter_assoc_and_config_type.py +18 -0
- epa_pm_api_wrapper/models/waste_meter_data_type.py +32 -0
- epa_pm_api_wrapper/models/waste_meter_entry_type.py +113 -0
- epa_pm_api_wrapper/models/waste_meter_entry_type_average_percent_full.py +11 -0
- epa_pm_api_wrapper/models/waste_meter_type.py +81 -0
- epa_pm_api_wrapper/models/wastewater_treatment_plant.py +15 -0
- epa_pm_api_wrapper/models/wastewater_treatment_plant_type.py +37 -0
- epa_pm_api_wrapper/models/wastewater_treatment_plant_type_use_details.py +63 -0
- epa_pm_api_wrapper/models/water_meter_assoc_and_config_type.py +25 -0
- epa_pm_api_wrapper/models/weekly_building_occupied_hours.py +16 -0
- epa_pm_api_wrapper/models/weekly_operating_hours.py +19 -0
- epa_pm_api_wrapper/models/wholesale_club_supercenter.py +16 -0
- epa_pm_api_wrapper/models/wholesale_club_supercenter_type.py +37 -0
- epa_pm_api_wrapper/models/wholesale_club_supercenter_type_use_details.py +130 -0
- epa_pm_api_wrapper/models/worship_facility.py +19 -0
- epa_pm_api_wrapper/models/worship_facility_type.py +35 -0
- epa_pm_api_wrapper/models/worship_facility_type_use_details.py +102 -0
- epa_pm_api_wrapper/models/yes_no.py +8 -0
- epa_pm_api_wrapper/models/zoo.py +16 -0
- epa_pm_api_wrapper/py.typed +1 -0
- epa_pm_api_wrapper/resources/__init__.py +172 -0
- epa_pm_api_wrapper/resources/_base.py +22 -0
- epa_pm_api_wrapper/resources/account.py +37 -0
- epa_pm_api_wrapper/resources/association.py +145 -0
- epa_pm_api_wrapper/resources/building.py +89 -0
- epa_pm_api_wrapper/resources/consumption_data.py +142 -0
- epa_pm_api_wrapper/resources/custom_metric.py +91 -0
- epa_pm_api_wrapper/resources/customer.py +45 -0
- epa_pm_api_wrapper/resources/data_exchange.py +111 -0
- epa_pm_api_wrapper/resources/green_power.py +237 -0
- epa_pm_api_wrapper/resources/hey.py +22 -0
- epa_pm_api_wrapper/resources/hierarchy.py +59 -0
- epa_pm_api_wrapper/resources/identifier.py +92 -0
- epa_pm_api_wrapper/resources/meter.py +277 -0
- epa_pm_api_wrapper/resources/metrics.py +185 -0
- epa_pm_api_wrapper/resources/property.py +450 -0
- epa_pm_api_wrapper/resources/property_use.py +277 -0
- epa_pm_api_wrapper/resources/report.py +169 -0
- epa_pm_api_wrapper/resources/share.py +139 -0
- epa_pm_api_wrapper/resources/target_finder.py +34 -0
- epa_pm_api_wrapper/resources/verification.py +201 -0
- epa_pm_api_wrapper/resources/waste_data.py +124 -0
- epa_pm_api_wrapper/retry.py +219 -0
- epa_pm_api_wrapper-0.3.0.dist-info/METADATA +137 -0
- epa_pm_api_wrapper-0.3.0.dist-info/RECORD +654 -0
- epa_pm_api_wrapper-0.3.0.dist-info/WHEEL +4 -0
- epa_pm_api_wrapper-0.3.0.dist-info/entry_points.txt +2 -0
- epa_pm_api_wrapper-0.3.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
"""EPA Portfolio Manager API client.
|
|
2
|
+
|
|
3
|
+
Two clients are exposed:
|
|
4
|
+
|
|
5
|
+
- :class:`EpaPmClient` (sync, ``httpx.Client`` backend)
|
|
6
|
+
- :class:`EpaPmAsyncClient` (async, ``httpx.AsyncClient`` backend)
|
|
7
|
+
|
|
8
|
+
Both expose the API as attribute-namespaced resources::
|
|
9
|
+
|
|
10
|
+
client.account.get()
|
|
11
|
+
client.property.list(account_id)
|
|
12
|
+
client.report.templates.list()
|
|
13
|
+
|
|
14
|
+
…with the difference that async resource methods are coroutines::
|
|
15
|
+
|
|
16
|
+
async with EpaPmAsyncClient(user, pwd) as c:
|
|
17
|
+
acc = await c.account.get()
|
|
18
|
+
|
|
19
|
+
This module holds the shared HTTP plumbing (auth, base URL, request body
|
|
20
|
+
construction, error mapping, response parsing). The concrete request
|
|
21
|
+
methods live on each client (sync ``_request``, async ``_arequest``).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
from typing import Any, TypeVar, cast, overload
|
|
28
|
+
|
|
29
|
+
import httpx
|
|
30
|
+
from xsdata.formats.dataclass.parsers import XmlParser
|
|
31
|
+
from xsdata.formats.dataclass.serializers import XmlSerializer
|
|
32
|
+
from xsdata.formats.dataclass.serializers.config import SerializerConfig
|
|
33
|
+
|
|
34
|
+
from epa_pm_api_wrapper.exceptions import EpaErrorDetail, EpaPmApiError, EpaPmAuthError
|
|
35
|
+
from epa_pm_api_wrapper.models import Response
|
|
36
|
+
from epa_pm_api_wrapper.resources import (
|
|
37
|
+
AccountResource,
|
|
38
|
+
AssociationResource,
|
|
39
|
+
AsyncAccountResource,
|
|
40
|
+
AsyncAssociationResource,
|
|
41
|
+
AsyncBuildingResource,
|
|
42
|
+
AsyncConsumptionDataResource,
|
|
43
|
+
AsyncCustomerResource,
|
|
44
|
+
AsyncCustomMetricResource,
|
|
45
|
+
AsyncDataExchangeResource,
|
|
46
|
+
AsyncGreenPowerResource,
|
|
47
|
+
AsyncHeyResource,
|
|
48
|
+
AsyncHierarchyResource,
|
|
49
|
+
AsyncIdentifierResource,
|
|
50
|
+
AsyncMeterResource,
|
|
51
|
+
AsyncMetricsResource,
|
|
52
|
+
AsyncPropertyResource,
|
|
53
|
+
AsyncPropertyUseResource,
|
|
54
|
+
AsyncReportResource,
|
|
55
|
+
AsyncShareResource,
|
|
56
|
+
AsyncTargetFinderResource,
|
|
57
|
+
AsyncVerificationResource,
|
|
58
|
+
AsyncWasteDataResource,
|
|
59
|
+
BuildingResource,
|
|
60
|
+
ConsumptionDataResource,
|
|
61
|
+
CustomerResource,
|
|
62
|
+
CustomMetricResource,
|
|
63
|
+
DataExchangeResource,
|
|
64
|
+
GreenPowerResource,
|
|
65
|
+
HeyResource,
|
|
66
|
+
HierarchyResource,
|
|
67
|
+
IdentifierResource,
|
|
68
|
+
MeterResource,
|
|
69
|
+
MetricsResource,
|
|
70
|
+
PropertyResource,
|
|
71
|
+
PropertyUseResource,
|
|
72
|
+
ReportResource,
|
|
73
|
+
ShareResource,
|
|
74
|
+
TargetFinderResource,
|
|
75
|
+
VerificationResource,
|
|
76
|
+
WasteDataResource,
|
|
77
|
+
)
|
|
78
|
+
from epa_pm_api_wrapper.retry import AsyncRetryTransport, RetryConfig, RetryTransport
|
|
79
|
+
|
|
80
|
+
logger = logging.getLogger(__name__)
|
|
81
|
+
|
|
82
|
+
T = TypeVar("T")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _resolve_retry(retries: int | None, retry: RetryConfig | None) -> RetryConfig | None:
|
|
86
|
+
"""Resolve the retry config from the two convenience kwargs.
|
|
87
|
+
|
|
88
|
+
``retry`` wins if explicitly provided. ``retries`` overrides only the
|
|
89
|
+
attempt count. ``retries=0`` disables retries (returns ``None``).
|
|
90
|
+
Default is ``RetryConfig()`` (3 retries, exponential backoff).
|
|
91
|
+
"""
|
|
92
|
+
if retry is not None:
|
|
93
|
+
return retry
|
|
94
|
+
if retries == 0:
|
|
95
|
+
return None
|
|
96
|
+
if retries is not None:
|
|
97
|
+
return RetryConfig(max_retries=retries)
|
|
98
|
+
return RetryConfig()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _wrap_transport_sync(
|
|
102
|
+
transport: httpx.BaseTransport | None,
|
|
103
|
+
retries: int | None,
|
|
104
|
+
retry: RetryConfig | None,
|
|
105
|
+
) -> httpx.BaseTransport | None:
|
|
106
|
+
cfg = _resolve_retry(retries, retry)
|
|
107
|
+
if cfg is None:
|
|
108
|
+
return transport
|
|
109
|
+
return RetryTransport(transport, config=cfg)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _wrap_transport_async(
|
|
113
|
+
transport: httpx.AsyncBaseTransport | None,
|
|
114
|
+
retries: int | None,
|
|
115
|
+
retry: RetryConfig | None,
|
|
116
|
+
) -> httpx.AsyncBaseTransport | None:
|
|
117
|
+
cfg = _resolve_retry(retries, retry)
|
|
118
|
+
if cfg is None:
|
|
119
|
+
return transport
|
|
120
|
+
return AsyncRetryTransport(transport, config=cfg)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _to_int(value: str | None) -> int | None:
|
|
124
|
+
"""Parse an error number string into an int; return ``None`` on failure.
|
|
125
|
+
|
|
126
|
+
The XSD declares ``errorNumber`` as a string, but in practice the EPA
|
|
127
|
+
sends integer values (including negative ones like ``-200``). Callers
|
|
128
|
+
branch on integers, so we coerce here and fall back to ``None`` if a
|
|
129
|
+
future response ever surprises us with a non-integer code.
|
|
130
|
+
"""
|
|
131
|
+
if value is None:
|
|
132
|
+
return None
|
|
133
|
+
try:
|
|
134
|
+
return int(value)
|
|
135
|
+
except ValueError:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class _BaseClient:
|
|
140
|
+
"""Plumbing shared by sync and async clients (no I/O methods)."""
|
|
141
|
+
|
|
142
|
+
LIVE_BASE_URL = "https://portfoliomanager.energystar.gov/ws"
|
|
143
|
+
TEST_BASE_URL = "https://portfoliomanager.energystar.gov/wstest"
|
|
144
|
+
DEFAULT_TIMEOUT = 30.0
|
|
145
|
+
|
|
146
|
+
def __init__(
|
|
147
|
+
self,
|
|
148
|
+
username: str,
|
|
149
|
+
password: str,
|
|
150
|
+
base_url: str | None = None,
|
|
151
|
+
use_test_env: bool = False,
|
|
152
|
+
):
|
|
153
|
+
if base_url:
|
|
154
|
+
self.base_url = base_url.rstrip("/")
|
|
155
|
+
elif use_test_env:
|
|
156
|
+
self.base_url = self.TEST_BASE_URL
|
|
157
|
+
else:
|
|
158
|
+
self.base_url = self.LIVE_BASE_URL
|
|
159
|
+
|
|
160
|
+
self.auth = (username, password)
|
|
161
|
+
self.parser = XmlParser()
|
|
162
|
+
self.serializer = XmlSerializer(config=SerializerConfig(indent=" "))
|
|
163
|
+
|
|
164
|
+
def _build_request(
|
|
165
|
+
self,
|
|
166
|
+
path: str,
|
|
167
|
+
data: Any = None,
|
|
168
|
+
params: dict | None = None,
|
|
169
|
+
extra_headers: dict[str, str] | None = None,
|
|
170
|
+
) -> tuple[str, bytes | str | None, dict | None, dict[str, str]]:
|
|
171
|
+
"""Return ``(url, content, params, headers)`` ready for ``httpx.request``.
|
|
172
|
+
|
|
173
|
+
Centralizes URL construction, XML body rendering (when ``data`` is a
|
|
174
|
+
dataclass), Content-Type header injection, and the drop-None pass on
|
|
175
|
+
query params (so resources can forward optional kwargs directly).
|
|
176
|
+
"""
|
|
177
|
+
url = f"{self.base_url}/{path.lstrip('/')}"
|
|
178
|
+
|
|
179
|
+
content: bytes | str | None = None
|
|
180
|
+
headers: dict[str, str] = {}
|
|
181
|
+
if data is not None:
|
|
182
|
+
content = self.serializer.render(data)
|
|
183
|
+
headers["Content-Type"] = "application/xml"
|
|
184
|
+
if extra_headers:
|
|
185
|
+
headers.update(extra_headers)
|
|
186
|
+
|
|
187
|
+
if params is not None:
|
|
188
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
189
|
+
if not params:
|
|
190
|
+
params = None
|
|
191
|
+
|
|
192
|
+
return url, content, params, headers
|
|
193
|
+
|
|
194
|
+
def _raise_for_response(self, resp: httpx.Response) -> None:
|
|
195
|
+
"""Raise the right exception type for a non-2xx response.
|
|
196
|
+
|
|
197
|
+
401 → :class:`EpaPmAuthError`. Other non-2xx → :class:`EpaPmApiError`,
|
|
198
|
+
carrying ``errors`` parsed from a ``<response status="Error">`` body
|
|
199
|
+
when present so callers can branch on EPA error numbers without
|
|
200
|
+
regex'ing the message string.
|
|
201
|
+
"""
|
|
202
|
+
if resp.status_code == 401:
|
|
203
|
+
raise EpaPmAuthError(resp.status_code, resp.text)
|
|
204
|
+
|
|
205
|
+
if 200 <= resp.status_code < 300:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
errors: list[EpaErrorDetail] = []
|
|
209
|
+
message = resp.text
|
|
210
|
+
try:
|
|
211
|
+
parsed = self.parser.from_string(resp.text, Response)
|
|
212
|
+
if parsed and parsed.errors and parsed.errors.error:
|
|
213
|
+
errors = [
|
|
214
|
+
EpaErrorDetail(
|
|
215
|
+
error_number=_to_int(e.error_number),
|
|
216
|
+
error_description=e.error_description,
|
|
217
|
+
)
|
|
218
|
+
for e in parsed.errors.error
|
|
219
|
+
]
|
|
220
|
+
message = "; ".join(f"{e.error_number}: {e.error_description}" for e in parsed.errors.error)
|
|
221
|
+
except Exception as exc:
|
|
222
|
+
# Body wasn't a parseable error envelope; fall through with raw text.
|
|
223
|
+
logger.debug("could not parse error envelope (status=%d): %s", resp.status_code, exc)
|
|
224
|
+
|
|
225
|
+
logger.warning(
|
|
226
|
+
"EPA PM %s %s -> %d: %s",
|
|
227
|
+
resp.request.method,
|
|
228
|
+
resp.request.url,
|
|
229
|
+
resp.status_code,
|
|
230
|
+
message,
|
|
231
|
+
)
|
|
232
|
+
raise EpaPmApiError(resp.status_code, message, errors=errors)
|
|
233
|
+
|
|
234
|
+
def _parse_typed(self, resp: httpx.Response, response_type: type[T]) -> T:
|
|
235
|
+
"""Parse a 2xx body to the given dataclass type or raise on failure."""
|
|
236
|
+
if not resp.text:
|
|
237
|
+
raise EpaPmApiError(resp.status_code, "Expected response body but got empty response")
|
|
238
|
+
result = self.parser.from_string(resp.text, response_type)
|
|
239
|
+
if result is None:
|
|
240
|
+
raise EpaPmApiError(resp.status_code, "Failed to parse response")
|
|
241
|
+
return cast(T, result)
|
|
242
|
+
|
|
243
|
+
def _parse_polymorphic(self, resp: httpx.Response) -> Any:
|
|
244
|
+
"""Parse a 2xx body to whichever dataclass matches the root element."""
|
|
245
|
+
if not resp.text:
|
|
246
|
+
raise EpaPmApiError(resp.status_code, "Expected response body but got empty response")
|
|
247
|
+
result = self.parser.from_string(resp.text)
|
|
248
|
+
if result is None:
|
|
249
|
+
raise EpaPmApiError(resp.status_code, "Failed to parse response")
|
|
250
|
+
return result
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class EpaPmClient(_BaseClient):
|
|
254
|
+
"""Sync client.
|
|
255
|
+
|
|
256
|
+
Use as a context manager (``with EpaPmClient(...) as c:``) to release
|
|
257
|
+
the connection pool on exit, or call :meth:`close` manually.
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
def __init__(
|
|
261
|
+
self,
|
|
262
|
+
username: str,
|
|
263
|
+
password: str,
|
|
264
|
+
base_url: str | None = None,
|
|
265
|
+
use_test_env: bool = False,
|
|
266
|
+
timeout: float | httpx.Timeout | None = None,
|
|
267
|
+
transport: httpx.BaseTransport | None = None,
|
|
268
|
+
http_client: httpx.Client | None = None,
|
|
269
|
+
retries: int | None = None,
|
|
270
|
+
retry: RetryConfig | None = None,
|
|
271
|
+
):
|
|
272
|
+
"""Construct a sync client.
|
|
273
|
+
|
|
274
|
+
Pass ``http_client`` to fully control the underlying ``httpx.Client``
|
|
275
|
+
(proxies, custom transports, mounts, event hooks); when supplied,
|
|
276
|
+
``timeout``, ``transport``, ``retries``, and ``retry`` are ignored.
|
|
277
|
+
Otherwise the client builds its own ``httpx.Client`` with basic auth,
|
|
278
|
+
follow_redirects, the given timeout (default ``DEFAULT_TIMEOUT``
|
|
279
|
+
seconds), and an optional ``transport`` automatically wrapped with
|
|
280
|
+
:class:`RetryTransport`.
|
|
281
|
+
|
|
282
|
+
Retry behavior defaults to ``RetryConfig()`` (3 retries on 429/5xx
|
|
283
|
+
with exponential backoff). Pass ``retries=0`` to disable, ``retries=N``
|
|
284
|
+
to override just the attempt count, or ``retry=RetryConfig(...)`` for
|
|
285
|
+
full control.
|
|
286
|
+
"""
|
|
287
|
+
super().__init__(username, password, base_url=base_url, use_test_env=use_test_env)
|
|
288
|
+
|
|
289
|
+
if http_client is not None:
|
|
290
|
+
self.client = http_client
|
|
291
|
+
self._owns_client = False
|
|
292
|
+
else:
|
|
293
|
+
transport = _wrap_transport_sync(transport, retries, retry)
|
|
294
|
+
self.client = httpx.Client(
|
|
295
|
+
auth=self.auth,
|
|
296
|
+
timeout=self.DEFAULT_TIMEOUT if timeout is None else timeout,
|
|
297
|
+
transport=transport,
|
|
298
|
+
follow_redirects=True,
|
|
299
|
+
)
|
|
300
|
+
self._owns_client = True
|
|
301
|
+
|
|
302
|
+
self.account = AccountResource(self)
|
|
303
|
+
self.association = AssociationResource(self)
|
|
304
|
+
self.building = BuildingResource(self)
|
|
305
|
+
self.consumption_data = ConsumptionDataResource(self)
|
|
306
|
+
self.custom_metric = CustomMetricResource(self)
|
|
307
|
+
self.customer = CustomerResource(self)
|
|
308
|
+
self.data_exchange = DataExchangeResource(self)
|
|
309
|
+
self.green_power = GreenPowerResource(self)
|
|
310
|
+
self.hey = HeyResource(self)
|
|
311
|
+
self.hierarchy = HierarchyResource(self)
|
|
312
|
+
self.identifier = IdentifierResource(self)
|
|
313
|
+
self.meter = MeterResource(self)
|
|
314
|
+
self.metrics = MetricsResource(self)
|
|
315
|
+
self.property = PropertyResource(self)
|
|
316
|
+
self.property_use = PropertyUseResource(self)
|
|
317
|
+
self.report = ReportResource(self)
|
|
318
|
+
self.share = ShareResource(self)
|
|
319
|
+
self.target_finder = TargetFinderResource(self)
|
|
320
|
+
self.verification = VerificationResource(self)
|
|
321
|
+
self.waste_data = WasteDataResource(self)
|
|
322
|
+
|
|
323
|
+
def close(self) -> None:
|
|
324
|
+
"""Close the underlying HTTP client and release its connection pool.
|
|
325
|
+
|
|
326
|
+
Only closes a client that this instance constructed. If a custom
|
|
327
|
+
``http_client`` was passed in at init, ownership stays with the
|
|
328
|
+
caller and ``close`` is a no-op.
|
|
329
|
+
"""
|
|
330
|
+
if self._owns_client:
|
|
331
|
+
self.client.close()
|
|
332
|
+
|
|
333
|
+
def __enter__(self) -> EpaPmClient:
|
|
334
|
+
return self
|
|
335
|
+
|
|
336
|
+
def __exit__(self, exc_type: object, exc: object, tb: object) -> None:
|
|
337
|
+
self.close()
|
|
338
|
+
|
|
339
|
+
@overload
|
|
340
|
+
def _request(
|
|
341
|
+
self,
|
|
342
|
+
method: str,
|
|
343
|
+
path: str,
|
|
344
|
+
data: Any = None,
|
|
345
|
+
params: dict | None = None,
|
|
346
|
+
response_type: type[T] = ...,
|
|
347
|
+
extra_headers: dict[str, str] | None = None,
|
|
348
|
+
) -> T: ...
|
|
349
|
+
|
|
350
|
+
@overload
|
|
351
|
+
def _request(
|
|
352
|
+
self,
|
|
353
|
+
method: str,
|
|
354
|
+
path: str,
|
|
355
|
+
data: Any = None,
|
|
356
|
+
params: dict | None = None,
|
|
357
|
+
response_type: None = None,
|
|
358
|
+
extra_headers: dict[str, str] | None = None,
|
|
359
|
+
) -> None: ...
|
|
360
|
+
|
|
361
|
+
def _request(
|
|
362
|
+
self,
|
|
363
|
+
method: str,
|
|
364
|
+
path: str,
|
|
365
|
+
data: Any = None,
|
|
366
|
+
params: dict | None = None,
|
|
367
|
+
response_type: type[T] | None = None,
|
|
368
|
+
extra_headers: dict[str, str] | None = None,
|
|
369
|
+
) -> T | None:
|
|
370
|
+
url, content, params, headers = self._build_request(path, data, params, extra_headers)
|
|
371
|
+
logger.debug("EPA PM %s %s params=%s", method, url, params)
|
|
372
|
+
resp = self.client.request(method, url, content=content, params=params, headers=headers)
|
|
373
|
+
self._raise_for_response(resp)
|
|
374
|
+
if response_type:
|
|
375
|
+
return self._parse_typed(resp, response_type)
|
|
376
|
+
return None
|
|
377
|
+
|
|
378
|
+
def _request_polymorphic(self, method: str, path: str) -> Any:
|
|
379
|
+
"""GET-style request that auto-resolves the response to its concrete subtype.
|
|
380
|
+
|
|
381
|
+
Use this for endpoints whose response element name is not fixed —
|
|
382
|
+
e.g. ``GET /propertyUse/{id}`` returns ``<office>``, ``<hotel>``,
|
|
383
|
+
``<vehicleDealership>``, etc. depending on the use type. xsdata's
|
|
384
|
+
``XmlContext`` resolves the root element to the matching dataclass
|
|
385
|
+
when ``from_string`` is called without an explicit type.
|
|
386
|
+
"""
|
|
387
|
+
url, _, _, _ = self._build_request(path)
|
|
388
|
+
logger.debug("EPA PM %s %s (polymorphic)", method, url)
|
|
389
|
+
resp = self.client.request(method, url)
|
|
390
|
+
self._raise_for_response(resp)
|
|
391
|
+
return self._parse_polymorphic(resp)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class EpaPmAsyncClient(_BaseClient):
|
|
395
|
+
"""Async client backed by ``httpx.AsyncClient``.
|
|
396
|
+
|
|
397
|
+
Use as an async context manager (``async with EpaPmAsyncClient(...) as c:``)
|
|
398
|
+
to release the connection pool on exit, or call :meth:`aclose` manually.
|
|
399
|
+
All resource methods are coroutines and must be ``await``-ed.
|
|
400
|
+
"""
|
|
401
|
+
|
|
402
|
+
def __init__(
|
|
403
|
+
self,
|
|
404
|
+
username: str,
|
|
405
|
+
password: str,
|
|
406
|
+
base_url: str | None = None,
|
|
407
|
+
use_test_env: bool = False,
|
|
408
|
+
timeout: float | httpx.Timeout | None = None,
|
|
409
|
+
transport: httpx.AsyncBaseTransport | None = None,
|
|
410
|
+
http_client: httpx.AsyncClient | None = None,
|
|
411
|
+
retries: int | None = None,
|
|
412
|
+
retry: RetryConfig | None = None,
|
|
413
|
+
):
|
|
414
|
+
"""Construct an async client. See :class:`EpaPmClient` for parameter docs."""
|
|
415
|
+
super().__init__(username, password, base_url=base_url, use_test_env=use_test_env)
|
|
416
|
+
|
|
417
|
+
if http_client is not None:
|
|
418
|
+
self.client = http_client
|
|
419
|
+
self._owns_client = False
|
|
420
|
+
else:
|
|
421
|
+
transport = _wrap_transport_async(transport, retries, retry)
|
|
422
|
+
self.client = httpx.AsyncClient(
|
|
423
|
+
auth=self.auth,
|
|
424
|
+
timeout=self.DEFAULT_TIMEOUT if timeout is None else timeout,
|
|
425
|
+
transport=transport,
|
|
426
|
+
follow_redirects=True,
|
|
427
|
+
)
|
|
428
|
+
self._owns_client = True
|
|
429
|
+
|
|
430
|
+
self.account = AsyncAccountResource(self)
|
|
431
|
+
self.association = AsyncAssociationResource(self)
|
|
432
|
+
self.building = AsyncBuildingResource(self)
|
|
433
|
+
self.consumption_data = AsyncConsumptionDataResource(self)
|
|
434
|
+
self.custom_metric = AsyncCustomMetricResource(self)
|
|
435
|
+
self.customer = AsyncCustomerResource(self)
|
|
436
|
+
self.data_exchange = AsyncDataExchangeResource(self)
|
|
437
|
+
self.green_power = AsyncGreenPowerResource(self)
|
|
438
|
+
self.hey = AsyncHeyResource(self)
|
|
439
|
+
self.hierarchy = AsyncHierarchyResource(self)
|
|
440
|
+
self.identifier = AsyncIdentifierResource(self)
|
|
441
|
+
self.meter = AsyncMeterResource(self)
|
|
442
|
+
self.metrics = AsyncMetricsResource(self)
|
|
443
|
+
self.property = AsyncPropertyResource(self)
|
|
444
|
+
self.property_use = AsyncPropertyUseResource(self)
|
|
445
|
+
self.report = AsyncReportResource(self)
|
|
446
|
+
self.share = AsyncShareResource(self)
|
|
447
|
+
self.target_finder = AsyncTargetFinderResource(self)
|
|
448
|
+
self.verification = AsyncVerificationResource(self)
|
|
449
|
+
self.waste_data = AsyncWasteDataResource(self)
|
|
450
|
+
|
|
451
|
+
async def aclose(self) -> None:
|
|
452
|
+
"""Close the underlying ``httpx.AsyncClient`` (skipped if injected)."""
|
|
453
|
+
if self._owns_client:
|
|
454
|
+
await self.client.aclose()
|
|
455
|
+
|
|
456
|
+
async def __aenter__(self) -> EpaPmAsyncClient:
|
|
457
|
+
return self
|
|
458
|
+
|
|
459
|
+
async def __aexit__(self, exc_type: object, exc: object, tb: object) -> None:
|
|
460
|
+
await self.aclose()
|
|
461
|
+
|
|
462
|
+
@overload
|
|
463
|
+
async def _arequest(
|
|
464
|
+
self,
|
|
465
|
+
method: str,
|
|
466
|
+
path: str,
|
|
467
|
+
data: Any = None,
|
|
468
|
+
params: dict | None = None,
|
|
469
|
+
response_type: type[T] = ...,
|
|
470
|
+
extra_headers: dict[str, str] | None = None,
|
|
471
|
+
) -> T: ...
|
|
472
|
+
|
|
473
|
+
@overload
|
|
474
|
+
async def _arequest(
|
|
475
|
+
self,
|
|
476
|
+
method: str,
|
|
477
|
+
path: str,
|
|
478
|
+
data: Any = None,
|
|
479
|
+
params: dict | None = None,
|
|
480
|
+
response_type: None = None,
|
|
481
|
+
extra_headers: dict[str, str] | None = None,
|
|
482
|
+
) -> None: ...
|
|
483
|
+
|
|
484
|
+
async def _arequest(
|
|
485
|
+
self,
|
|
486
|
+
method: str,
|
|
487
|
+
path: str,
|
|
488
|
+
data: Any = None,
|
|
489
|
+
params: dict | None = None,
|
|
490
|
+
response_type: type[T] | None = None,
|
|
491
|
+
extra_headers: dict[str, str] | None = None,
|
|
492
|
+
) -> T | None:
|
|
493
|
+
url, content, params, headers = self._build_request(path, data, params, extra_headers)
|
|
494
|
+
logger.debug("EPA PM %s %s params=%s", method, url, params)
|
|
495
|
+
resp = await self.client.request(method, url, content=content, params=params, headers=headers)
|
|
496
|
+
self._raise_for_response(resp)
|
|
497
|
+
if response_type:
|
|
498
|
+
return self._parse_typed(resp, response_type)
|
|
499
|
+
return None
|
|
500
|
+
|
|
501
|
+
async def _arequest_polymorphic(self, method: str, path: str) -> Any:
|
|
502
|
+
"""Async equivalent of :meth:`EpaPmClient._request_polymorphic`."""
|
|
503
|
+
url, _, _, _ = self._build_request(path)
|
|
504
|
+
logger.debug("EPA PM %s %s (polymorphic)", method, url)
|
|
505
|
+
resp = await self.client.request(method, url)
|
|
506
|
+
self._raise_for_response(resp)
|
|
507
|
+
return self._parse_polymorphic(resp)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Exception types raised by the client.
|
|
2
|
+
|
|
3
|
+
``EpaPmApiError`` carries the raw HTTP details *and* the structured EPA
|
|
4
|
+
error payload when the body parses as ``<response status="Error">``. The
|
|
5
|
+
flattened message string is preserved for backwards compatibility, but
|
|
6
|
+
production callers should prefer ``error_number`` / ``errors`` for
|
|
7
|
+
branching.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class EpaErrorDetail:
|
|
17
|
+
"""One ``<error>`` element from an EPA error response."""
|
|
18
|
+
|
|
19
|
+
error_number: int | None
|
|
20
|
+
error_description: str | None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class EpaPmError(Exception):
|
|
24
|
+
"""Base exception for EPA PM API Wrapper."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class EpaPmApiError(EpaPmError):
|
|
28
|
+
"""Exception raised for errors returned by the API.
|
|
29
|
+
|
|
30
|
+
:ivar status_code: HTTP status code.
|
|
31
|
+
:ivar response_text: Raw response body (XML or plain text).
|
|
32
|
+
:ivar errors: Parsed list of EPA ``<error>`` entries when the body was
|
|
33
|
+
a structured ``<response status="Error">`` payload; empty otherwise.
|
|
34
|
+
:ivar error_number: Convenience accessor for the *first* EPA error
|
|
35
|
+
number when there's exactly one error in the payload — handy for
|
|
36
|
+
``except EpaPmApiError as e: if e.error_number == 10: ...``. Use
|
|
37
|
+
:attr:`errors` if multiple errors may be present.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
status_code: int,
|
|
43
|
+
response_text: str,
|
|
44
|
+
errors: list[EpaErrorDetail] | None = None,
|
|
45
|
+
):
|
|
46
|
+
self.status_code = status_code
|
|
47
|
+
self.response_text = response_text
|
|
48
|
+
self.errors: list[EpaErrorDetail] = errors or []
|
|
49
|
+
super().__init__(f"API error {status_code}: {response_text}")
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def error_number(self) -> int | None:
|
|
53
|
+
"""The EPA error number when exactly one error was reported, else ``None``."""
|
|
54
|
+
if len(self.errors) == 1:
|
|
55
|
+
return self.errors[0].error_number
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class EpaPmAuthError(EpaPmApiError):
|
|
60
|
+
"""Exception raised for authentication errors."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, status_code: int, response_text: str):
|
|
63
|
+
super().__init__(status_code, response_text)
|
|
64
|
+
self.args = (
|
|
65
|
+
"Authentication failed. Please check your credentials (username/password) and ensure "
|
|
66
|
+
f"you are targeting the correct environment (live vs test). Details: {response_text}",
|
|
67
|
+
)
|