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,201 @@
|
|
|
1
|
+
"""Verification resource — `/property/{propertyId}/verification` endpoints
|
|
2
|
+
plus the nested `verification.designations` sub-namespace for professional
|
|
3
|
+
designation management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from epa_pm_api_wrapper.models import (
|
|
11
|
+
ProfessionalDesignationList,
|
|
12
|
+
Response,
|
|
13
|
+
Verification,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from ._base import AsyncResource, Resource
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from epa_pm_api_wrapper.client import EpaPmAsyncClient, EpaPmClient
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class VerificationDesignationsResource(Resource):
|
|
23
|
+
def list(self, property_id: int) -> Verification:
|
|
24
|
+
"""Get the verification record (which carries the designation list)."""
|
|
25
|
+
return self._client._request(
|
|
26
|
+
"GET",
|
|
27
|
+
f"property/{property_id}/verification/professionalDesignation",
|
|
28
|
+
response_type=Verification,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def delete_all(self, property_id: int) -> Response:
|
|
32
|
+
"""Remove all professional designations from a property's verification."""
|
|
33
|
+
return self._client._request(
|
|
34
|
+
"DELETE",
|
|
35
|
+
f"property/{property_id}/verification/professionalDesignation",
|
|
36
|
+
response_type=Response,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def add(self, property_id: int, designation_type_id: int, data: ProfessionalDesignationList) -> Response:
|
|
40
|
+
"""Add a professional designation entry."""
|
|
41
|
+
return self._client._request(
|
|
42
|
+
"POST",
|
|
43
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}",
|
|
44
|
+
data=data,
|
|
45
|
+
response_type=Response,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def update(self, property_id: int, designation_type_id: int, data: ProfessionalDesignationList) -> Response:
|
|
49
|
+
"""Update licenses for a designation type."""
|
|
50
|
+
return self._client._request(
|
|
51
|
+
"PUT",
|
|
52
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}",
|
|
53
|
+
data=data,
|
|
54
|
+
response_type=Response,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def delete_type(self, property_id: int, designation_type_id: int) -> Response:
|
|
58
|
+
"""Remove all entries of a single designation type."""
|
|
59
|
+
return self._client._request(
|
|
60
|
+
"DELETE",
|
|
61
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}",
|
|
62
|
+
response_type=Response,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def update_license(
|
|
66
|
+
self,
|
|
67
|
+
property_id: int,
|
|
68
|
+
designation_type_id: int,
|
|
69
|
+
index: int,
|
|
70
|
+
data: ProfessionalDesignationList,
|
|
71
|
+
) -> Response:
|
|
72
|
+
"""Update a specific license entry within a designation type."""
|
|
73
|
+
return self._client._request(
|
|
74
|
+
"PUT",
|
|
75
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}/{index}",
|
|
76
|
+
data=data,
|
|
77
|
+
response_type=Response,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def delete_license(self, property_id: int, designation_type_id: int, index: int) -> Response:
|
|
81
|
+
"""Remove a specific license entry within a designation type."""
|
|
82
|
+
return self._client._request(
|
|
83
|
+
"DELETE",
|
|
84
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}/{index}",
|
|
85
|
+
response_type=Response,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def types(self) -> ProfessionalDesignationList:
|
|
89
|
+
"""List the EPA-defined professional designation types (catalog)."""
|
|
90
|
+
return self._client._request(
|
|
91
|
+
"GET", "property/professionalDesignation/list", response_type=ProfessionalDesignationList
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class VerificationResource(Resource):
|
|
96
|
+
def __init__(self, client: EpaPmClient) -> None:
|
|
97
|
+
super().__init__(client)
|
|
98
|
+
self.designations = VerificationDesignationsResource(client)
|
|
99
|
+
|
|
100
|
+
def get(self, property_id: int) -> Verification:
|
|
101
|
+
"""Get verification (verifier) information for a property."""
|
|
102
|
+
return self._client._request("GET", f"property/{property_id}/verification", response_type=Verification)
|
|
103
|
+
|
|
104
|
+
def create(self, property_id: int, data: Verification) -> Response:
|
|
105
|
+
"""Create verification information for a property."""
|
|
106
|
+
return self._client._request("POST", f"property/{property_id}/verification", data=data, response_type=Response)
|
|
107
|
+
|
|
108
|
+
def update(self, property_id: int, data: Verification) -> Response:
|
|
109
|
+
"""Update verification information for a property."""
|
|
110
|
+
return self._client._request("PUT", f"property/{property_id}/verification", data=data, response_type=Response)
|
|
111
|
+
|
|
112
|
+
def delete(self, property_id: int) -> Response:
|
|
113
|
+
"""Remove verification information from a property."""
|
|
114
|
+
return self._client._request("DELETE", f"property/{property_id}/verification", response_type=Response)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class AsyncVerificationDesignationsResource(AsyncResource):
|
|
118
|
+
async def list(self, property_id: int) -> Verification:
|
|
119
|
+
return await self._client._arequest(
|
|
120
|
+
"GET",
|
|
121
|
+
f"property/{property_id}/verification/professionalDesignation",
|
|
122
|
+
response_type=Verification,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
async def delete_all(self, property_id: int) -> Response:
|
|
126
|
+
return await self._client._arequest(
|
|
127
|
+
"DELETE",
|
|
128
|
+
f"property/{property_id}/verification/professionalDesignation",
|
|
129
|
+
response_type=Response,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
async def add(self, property_id: int, designation_type_id: int, data: ProfessionalDesignationList) -> Response:
|
|
133
|
+
return await self._client._arequest(
|
|
134
|
+
"POST",
|
|
135
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}",
|
|
136
|
+
data=data,
|
|
137
|
+
response_type=Response,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
async def update(self, property_id: int, designation_type_id: int, data: ProfessionalDesignationList) -> Response:
|
|
141
|
+
return await self._client._arequest(
|
|
142
|
+
"PUT",
|
|
143
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}",
|
|
144
|
+
data=data,
|
|
145
|
+
response_type=Response,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
async def delete_type(self, property_id: int, designation_type_id: int) -> Response:
|
|
149
|
+
return await self._client._arequest(
|
|
150
|
+
"DELETE",
|
|
151
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}",
|
|
152
|
+
response_type=Response,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
async def update_license(
|
|
156
|
+
self,
|
|
157
|
+
property_id: int,
|
|
158
|
+
designation_type_id: int,
|
|
159
|
+
index: int,
|
|
160
|
+
data: ProfessionalDesignationList,
|
|
161
|
+
) -> Response:
|
|
162
|
+
return await self._client._arequest(
|
|
163
|
+
"PUT",
|
|
164
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}/{index}",
|
|
165
|
+
data=data,
|
|
166
|
+
response_type=Response,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
async def delete_license(self, property_id: int, designation_type_id: int, index: int) -> Response:
|
|
170
|
+
return await self._client._arequest(
|
|
171
|
+
"DELETE",
|
|
172
|
+
f"property/{property_id}/verification/professionalDesignation/{designation_type_id}/{index}",
|
|
173
|
+
response_type=Response,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
async def types(self) -> ProfessionalDesignationList:
|
|
177
|
+
return await self._client._arequest(
|
|
178
|
+
"GET", "property/professionalDesignation/list", response_type=ProfessionalDesignationList
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class AsyncVerificationResource(AsyncResource):
|
|
183
|
+
def __init__(self, client: EpaPmAsyncClient) -> None:
|
|
184
|
+
super().__init__(client)
|
|
185
|
+
self.designations = AsyncVerificationDesignationsResource(client)
|
|
186
|
+
|
|
187
|
+
async def get(self, property_id: int) -> Verification:
|
|
188
|
+
return await self._client._arequest("GET", f"property/{property_id}/verification", response_type=Verification)
|
|
189
|
+
|
|
190
|
+
async def create(self, property_id: int, data: Verification) -> Response:
|
|
191
|
+
return await self._client._arequest(
|
|
192
|
+
"POST", f"property/{property_id}/verification", data=data, response_type=Response
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
async def update(self, property_id: int, data: Verification) -> Response:
|
|
196
|
+
return await self._client._arequest(
|
|
197
|
+
"PUT", f"property/{property_id}/verification", data=data, response_type=Response
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
async def delete(self, property_id: int) -> Response:
|
|
201
|
+
return await self._client._arequest("DELETE", f"property/{property_id}/verification", response_type=Response)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Waste data resource — `/meter/{meterId}/wasteData` and `/wasteData/{id}` endpoints."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import AsyncIterator, Iterator
|
|
6
|
+
|
|
7
|
+
from epa_pm_api_wrapper.models import Response, WasteData, WasteDataList
|
|
8
|
+
|
|
9
|
+
from ._base import AsyncResource, Resource
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class WasteDataResource(Resource):
|
|
13
|
+
def list(
|
|
14
|
+
self,
|
|
15
|
+
meter_id: int,
|
|
16
|
+
page: int | None = None,
|
|
17
|
+
start_date: str | None = None,
|
|
18
|
+
end_date: str | None = None,
|
|
19
|
+
) -> WasteDataList:
|
|
20
|
+
"""Get waste data for a meter (up to 120 records per page)."""
|
|
21
|
+
params = {"page": page, "startDate": start_date, "endDate": end_date}
|
|
22
|
+
return self._client._request("GET", f"meter/{meter_id}/wasteData", params=params, response_type=WasteDataList)
|
|
23
|
+
|
|
24
|
+
def add(self, meter_id: int, data: WasteData) -> Response:
|
|
25
|
+
"""Add a waste data record to a meter."""
|
|
26
|
+
return self._client._request("POST", f"meter/{meter_id}/wasteData", data=data, response_type=Response)
|
|
27
|
+
|
|
28
|
+
def delete_range(self, meter_id: int, start_date: str, end_date: str) -> Response:
|
|
29
|
+
"""Delete waste data records on a meter within a date range."""
|
|
30
|
+
return self._client._request(
|
|
31
|
+
"DELETE",
|
|
32
|
+
f"meter/{meter_id}/wasteData",
|
|
33
|
+
params={"startDate": start_date, "endDate": end_date},
|
|
34
|
+
response_type=Response,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def update(self, waste_data_id: int, data: WasteData) -> Response:
|
|
38
|
+
"""Update a single waste data record."""
|
|
39
|
+
return self._client._request("PUT", f"wasteData/{waste_data_id}", data=data, response_type=Response)
|
|
40
|
+
|
|
41
|
+
def delete(self, waste_data_id: int) -> Response:
|
|
42
|
+
"""Delete a single waste data record."""
|
|
43
|
+
return self._client._request("DELETE", f"wasteData/{waste_data_id}", response_type=Response)
|
|
44
|
+
|
|
45
|
+
def what_changed(self, customer_id: int, date: str) -> Response:
|
|
46
|
+
"""List meters under a connected customer with waste data modified on/after ``date``."""
|
|
47
|
+
return self._client._request(
|
|
48
|
+
"GET",
|
|
49
|
+
f"customer/{customer_id}/meter/wasteData/whatChanged",
|
|
50
|
+
params={"date": date},
|
|
51
|
+
response_type=Response,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def iter(
|
|
55
|
+
self,
|
|
56
|
+
meter_id: int,
|
|
57
|
+
start_date: str | None = None,
|
|
58
|
+
end_date: str | None = None,
|
|
59
|
+
) -> Iterator[WasteData]:
|
|
60
|
+
"""Iterate over every waste record for a meter, paging internally (120/page)."""
|
|
61
|
+
page = 1
|
|
62
|
+
while True:
|
|
63
|
+
data = self.list(meter_id, page=page, start_date=start_date, end_date=end_date)
|
|
64
|
+
records = data.waste_data or []
|
|
65
|
+
if not records:
|
|
66
|
+
return
|
|
67
|
+
yield from records
|
|
68
|
+
page += 1
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AsyncWasteDataResource(AsyncResource):
|
|
72
|
+
async def list(
|
|
73
|
+
self,
|
|
74
|
+
meter_id: int,
|
|
75
|
+
page: int | None = None,
|
|
76
|
+
start_date: str | None = None,
|
|
77
|
+
end_date: str | None = None,
|
|
78
|
+
) -> WasteDataList:
|
|
79
|
+
params = {"page": page, "startDate": start_date, "endDate": end_date}
|
|
80
|
+
return await self._client._arequest(
|
|
81
|
+
"GET", f"meter/{meter_id}/wasteData", params=params, response_type=WasteDataList
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
async def add(self, meter_id: int, data: WasteData) -> Response:
|
|
85
|
+
return await self._client._arequest("POST", f"meter/{meter_id}/wasteData", data=data, response_type=Response)
|
|
86
|
+
|
|
87
|
+
async def delete_range(self, meter_id: int, start_date: str, end_date: str) -> Response:
|
|
88
|
+
return await self._client._arequest(
|
|
89
|
+
"DELETE",
|
|
90
|
+
f"meter/{meter_id}/wasteData",
|
|
91
|
+
params={"startDate": start_date, "endDate": end_date},
|
|
92
|
+
response_type=Response,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
async def update(self, waste_data_id: int, data: WasteData) -> Response:
|
|
96
|
+
return await self._client._arequest("PUT", f"wasteData/{waste_data_id}", data=data, response_type=Response)
|
|
97
|
+
|
|
98
|
+
async def delete(self, waste_data_id: int) -> Response:
|
|
99
|
+
return await self._client._arequest("DELETE", f"wasteData/{waste_data_id}", response_type=Response)
|
|
100
|
+
|
|
101
|
+
async def what_changed(self, customer_id: int, date: str) -> Response:
|
|
102
|
+
return await self._client._arequest(
|
|
103
|
+
"GET",
|
|
104
|
+
f"customer/{customer_id}/meter/wasteData/whatChanged",
|
|
105
|
+
params={"date": date},
|
|
106
|
+
response_type=Response,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
async def iter(
|
|
110
|
+
self,
|
|
111
|
+
meter_id: int,
|
|
112
|
+
start_date: str | None = None,
|
|
113
|
+
end_date: str | None = None,
|
|
114
|
+
) -> AsyncIterator[WasteData]:
|
|
115
|
+
"""Async equivalent of :meth:`WasteDataResource.iter`."""
|
|
116
|
+
page = 1
|
|
117
|
+
while True:
|
|
118
|
+
data = await self.list(meter_id, page=page, start_date=start_date, end_date=end_date)
|
|
119
|
+
records = data.waste_data or []
|
|
120
|
+
if not records:
|
|
121
|
+
return
|
|
122
|
+
for record in records:
|
|
123
|
+
yield record
|
|
124
|
+
page += 1
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Retry transport for transient HTTP failures.
|
|
2
|
+
|
|
3
|
+
Wraps an underlying ``httpx`` transport with retry/backoff for the responses
|
|
4
|
+
EPA most commonly returns when the system is under stress: 429 (rate limited),
|
|
5
|
+
502/503/504 (gateway/upstream errors), and connection-level failures
|
|
6
|
+
(``httpx.ConnectError`` / ``httpx.ReadTimeout``). Auth (401) and client-side
|
|
7
|
+
4xx errors are *not* retried — they will not change on retry.
|
|
8
|
+
|
|
9
|
+
Two transports, sync and async, share the same :class:`RetryConfig` and the
|
|
10
|
+
same backoff math. The default schedule is exponential with full jitter:
|
|
11
|
+
``delay = uniform(0, base * 2**attempt)`` clamped to ``max_delay``. The HTTP
|
|
12
|
+
``Retry-After`` header (numeric seconds form) overrides the computed delay
|
|
13
|
+
when present.
|
|
14
|
+
|
|
15
|
+
Transports are stacked: the user-supplied ``transport`` (or the default
|
|
16
|
+
``httpx.HTTPTransport`` httpx builds for us) sits inside the retry transport.
|
|
17
|
+
This means proxies and other transport-layer customizations still apply.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import asyncio
|
|
23
|
+
import logging
|
|
24
|
+
import random
|
|
25
|
+
import time
|
|
26
|
+
from dataclasses import dataclass, field
|
|
27
|
+
|
|
28
|
+
import httpx
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
DEFAULT_RETRY_STATUS_CODES = frozenset({429, 502, 503, 504})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class RetryConfig:
|
|
37
|
+
"""Retry behavior for the client transport layer.
|
|
38
|
+
|
|
39
|
+
Pass to ``EpaPmClient(retry=...)`` / ``EpaPmAsyncClient(retry=...)`` to
|
|
40
|
+
override the defaults. Pass ``retries=0`` on the client to disable.
|
|
41
|
+
|
|
42
|
+
:ivar max_retries: How many times to retry after the initial attempt
|
|
43
|
+
(default 3 → up to 4 total requests).
|
|
44
|
+
:ivar base_delay: Base for the exponential backoff in seconds.
|
|
45
|
+
:ivar max_delay: Cap on a single backoff sleep, in seconds.
|
|
46
|
+
:ivar retry_status_codes: HTTP status codes treated as transient.
|
|
47
|
+
:ivar respect_retry_after: Honor ``Retry-After`` headers (numeric form)
|
|
48
|
+
when the server provides them, capped at ``max_delay``.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
max_retries: int = 3
|
|
52
|
+
base_delay: float = 0.5
|
|
53
|
+
max_delay: float = 30.0
|
|
54
|
+
retry_status_codes: frozenset[int] = field(default_factory=lambda: DEFAULT_RETRY_STATUS_CODES)
|
|
55
|
+
respect_retry_after: bool = True
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _retryable_status(response: httpx.Response, cfg: RetryConfig) -> bool:
|
|
59
|
+
return response.status_code in cfg.retry_status_codes
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _retry_after_seconds(response: httpx.Response, cfg: RetryConfig) -> float | None:
|
|
63
|
+
"""Return the server-suggested delay in seconds, or ``None``.
|
|
64
|
+
|
|
65
|
+
Only the numeric form of ``Retry-After`` is honored; HTTP-date form falls
|
|
66
|
+
back to client-side backoff (it requires clock-correlation we'd rather
|
|
67
|
+
not assume).
|
|
68
|
+
"""
|
|
69
|
+
if not cfg.respect_retry_after:
|
|
70
|
+
return None
|
|
71
|
+
raw = response.headers.get("retry-after")
|
|
72
|
+
if not raw:
|
|
73
|
+
return None
|
|
74
|
+
try:
|
|
75
|
+
return min(float(raw), cfg.max_delay)
|
|
76
|
+
except ValueError:
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _backoff_seconds(attempt: int, cfg: RetryConfig) -> float:
|
|
81
|
+
"""Exponential backoff with full jitter, capped at ``max_delay``.
|
|
82
|
+
|
|
83
|
+
``attempt`` is 0-indexed (first retry → attempt=0).
|
|
84
|
+
"""
|
|
85
|
+
upper = min(cfg.max_delay, cfg.base_delay * (2**attempt))
|
|
86
|
+
return random.uniform(0, upper)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _delay_for(response: httpx.Response | None, attempt: int, cfg: RetryConfig) -> float:
|
|
90
|
+
"""Server-hint delay if available, else backoff."""
|
|
91
|
+
if response is not None:
|
|
92
|
+
hinted = _retry_after_seconds(response, cfg)
|
|
93
|
+
if hinted is not None:
|
|
94
|
+
return hinted
|
|
95
|
+
return _backoff_seconds(attempt, cfg)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
_RETRYABLE_EXCEPTIONS: tuple[type[Exception], ...] = (
|
|
99
|
+
httpx.ConnectError,
|
|
100
|
+
httpx.ReadTimeout,
|
|
101
|
+
httpx.WriteTimeout,
|
|
102
|
+
httpx.PoolTimeout,
|
|
103
|
+
httpx.RemoteProtocolError,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class RetryTransport(httpx.BaseTransport):
|
|
108
|
+
"""Sync retry transport. Wrap an existing transport (or omit for the default)."""
|
|
109
|
+
|
|
110
|
+
def __init__(self, wrapped: httpx.BaseTransport | None = None, config: RetryConfig | None = None):
|
|
111
|
+
self._wrapped = wrapped if wrapped is not None else httpx.HTTPTransport()
|
|
112
|
+
self._config = config or RetryConfig()
|
|
113
|
+
|
|
114
|
+
def handle_request(self, request: httpx.Request) -> httpx.Response:
|
|
115
|
+
cfg = self._config
|
|
116
|
+
last_exc: Exception | None = None
|
|
117
|
+
for attempt in range(cfg.max_retries + 1):
|
|
118
|
+
try:
|
|
119
|
+
response = self._wrapped.handle_request(request)
|
|
120
|
+
except _RETRYABLE_EXCEPTIONS as exc:
|
|
121
|
+
last_exc = exc
|
|
122
|
+
if attempt >= cfg.max_retries:
|
|
123
|
+
logger.warning("request to %s failed after %d attempts: %s", request.url, attempt + 1, exc)
|
|
124
|
+
raise
|
|
125
|
+
delay = _delay_for(None, attempt, cfg)
|
|
126
|
+
logger.info(
|
|
127
|
+
"retrying %s after %s (attempt %d/%d, sleep %.2fs)",
|
|
128
|
+
request.url,
|
|
129
|
+
type(exc).__name__,
|
|
130
|
+
attempt + 1,
|
|
131
|
+
cfg.max_retries,
|
|
132
|
+
delay,
|
|
133
|
+
)
|
|
134
|
+
time.sleep(delay)
|
|
135
|
+
continue
|
|
136
|
+
|
|
137
|
+
if attempt >= cfg.max_retries or not _retryable_status(response, cfg):
|
|
138
|
+
return response
|
|
139
|
+
|
|
140
|
+
# Drain the body so the connection can be released to the pool.
|
|
141
|
+
response.read()
|
|
142
|
+
response.close()
|
|
143
|
+
delay = _delay_for(response, attempt, cfg)
|
|
144
|
+
logger.info(
|
|
145
|
+
"retrying %s after HTTP %d (attempt %d/%d, sleep %.2fs)",
|
|
146
|
+
request.url,
|
|
147
|
+
response.status_code,
|
|
148
|
+
attempt + 1,
|
|
149
|
+
cfg.max_retries,
|
|
150
|
+
delay,
|
|
151
|
+
)
|
|
152
|
+
time.sleep(delay)
|
|
153
|
+
|
|
154
|
+
# Should not be reachable — the loop returns or raises — but mypy/ty
|
|
155
|
+
# want a definite outcome.
|
|
156
|
+
if last_exc is not None:
|
|
157
|
+
raise last_exc
|
|
158
|
+
raise RuntimeError("RetryTransport: unreachable") # pragma: no cover
|
|
159
|
+
|
|
160
|
+
def close(self) -> None:
|
|
161
|
+
self._wrapped.close()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class AsyncRetryTransport(httpx.AsyncBaseTransport):
|
|
165
|
+
"""Async retry transport. Wrap an existing transport (or omit for the default)."""
|
|
166
|
+
|
|
167
|
+
def __init__(
|
|
168
|
+
self,
|
|
169
|
+
wrapped: httpx.AsyncBaseTransport | None = None,
|
|
170
|
+
config: RetryConfig | None = None,
|
|
171
|
+
):
|
|
172
|
+
self._wrapped = wrapped if wrapped is not None else httpx.AsyncHTTPTransport()
|
|
173
|
+
self._config = config or RetryConfig()
|
|
174
|
+
|
|
175
|
+
async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
|
|
176
|
+
cfg = self._config
|
|
177
|
+
last_exc: Exception | None = None
|
|
178
|
+
for attempt in range(cfg.max_retries + 1):
|
|
179
|
+
try:
|
|
180
|
+
response = await self._wrapped.handle_async_request(request)
|
|
181
|
+
except _RETRYABLE_EXCEPTIONS as exc:
|
|
182
|
+
last_exc = exc
|
|
183
|
+
if attempt >= cfg.max_retries:
|
|
184
|
+
logger.warning("request to %s failed after %d attempts: %s", request.url, attempt + 1, exc)
|
|
185
|
+
raise
|
|
186
|
+
delay = _delay_for(None, attempt, cfg)
|
|
187
|
+
logger.info(
|
|
188
|
+
"retrying %s after %s (attempt %d/%d, sleep %.2fs)",
|
|
189
|
+
request.url,
|
|
190
|
+
type(exc).__name__,
|
|
191
|
+
attempt + 1,
|
|
192
|
+
cfg.max_retries,
|
|
193
|
+
delay,
|
|
194
|
+
)
|
|
195
|
+
await asyncio.sleep(delay)
|
|
196
|
+
continue
|
|
197
|
+
|
|
198
|
+
if attempt >= cfg.max_retries or not _retryable_status(response, cfg):
|
|
199
|
+
return response
|
|
200
|
+
|
|
201
|
+
await response.aread()
|
|
202
|
+
await response.aclose()
|
|
203
|
+
delay = _delay_for(response, attempt, cfg)
|
|
204
|
+
logger.info(
|
|
205
|
+
"retrying %s after HTTP %d (attempt %d/%d, sleep %.2fs)",
|
|
206
|
+
request.url,
|
|
207
|
+
response.status_code,
|
|
208
|
+
attempt + 1,
|
|
209
|
+
cfg.max_retries,
|
|
210
|
+
delay,
|
|
211
|
+
)
|
|
212
|
+
await asyncio.sleep(delay)
|
|
213
|
+
|
|
214
|
+
if last_exc is not None:
|
|
215
|
+
raise last_exc
|
|
216
|
+
raise RuntimeError("AsyncRetryTransport: unreachable") # pragma: no cover
|
|
217
|
+
|
|
218
|
+
async def aclose(self) -> None:
|
|
219
|
+
await self._wrapped.aclose()
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: EPA-PM-API-Wrapper
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Client wrapper for the EPA Portfolio Manager API.
|
|
5
|
+
Project-URL: bugs, https://github.com/harryw1/EPA-PM-API-Wrapper/issues
|
|
6
|
+
Project-URL: changelog, https://github.com/harryw1/EPA-PM-API-Wrapper/releases
|
|
7
|
+
Project-URL: documentation, https://harryw1.github.io/EPA-PM-API-Wrapper/
|
|
8
|
+
Project-URL: homepage, https://github.com/harryw1/EPA-PM-API-Wrapper
|
|
9
|
+
Author-email: Harrison Weiss <haweiss@dcas.nyc.gov>
|
|
10
|
+
Maintainer-email: Harrison Weiss <haweiss@dcas.nyc.gov>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: httpx>=0.28.1
|
|
26
|
+
Requires-Dist: python-dotenv>=1.2.2
|
|
27
|
+
Requires-Dist: rich>=13.7
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Requires-Dist: xsdata>=26.2
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# EPA PM API Wrapper
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/EPA-PM-API-Wrapper/)
|
|
35
|
+
[](https://github.com/harryw1/EPA-PM-API-Wrapper/actions/workflows/ci.yml)
|
|
36
|
+
[](https://pypi.org/project/EPA-PM-API-Wrapper/)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
Client wrapper for the EPA Portfolio Manager API.
|
|
40
|
+
|
|
41
|
+
* [GitHub](https://github.com/harryw1/EPA-PM-API-Wrapper/) | [PyPI](https://pypi.org/project/EPA-PM-API-Wrapper/) | [Documentation](https://harryw1.github.io/EPA-PM-API-Wrapper/)
|
|
42
|
+
* Created by [Harrison Weiss](https://publicpresence.org) | GitHub [@harryw1](https://github.com/harryw1) | PyPI [@harryw1](https://pypi.org/user/harryw1/)
|
|
43
|
+
* MIT License
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
* **Full API coverage:** Every public endpoint in the ENERGY STAR Portfolio Manager web services API is bound — account, property, propertyUse, building, meter, consumption, waste, reporting, target finder, HEY, and the various catalogs (federal agencies, eGrid, weather stations, EDU/PGP).
|
|
48
|
+
* **Sync and async clients:** `EpaPmClient` and `EpaPmAsyncClient` share the same resource-namespaced surface; pick whichever fits your runtime.
|
|
49
|
+
* **Typed XML models:** Request and response payloads are dataclasses generated from the EPA XSDs (via `xsdata`), so IDE autocomplete and type checkers work out of the box.
|
|
50
|
+
* **Structured error handling:** `EpaPmApiError` carries `status_code`, a parsed `errors` list, and an `error_number` accessor for branching without regexing the message; `EpaPmAuthError` covers 401s.
|
|
51
|
+
* **Production-ready transport:** Configurable timeout/transport/`httpx.Client` injection, context-manager lifecycle, and built-in retry/backoff for 429 + 5xx + connection-level errors with `Retry-After` support.
|
|
52
|
+
* **Pagination iterators:** `client.consumption_data.iter(meter_id)` and `client.waste_data.iter(meter_id)` walk pages internally.
|
|
53
|
+
* **Live and test environments:** Switch between production and `wstest` with a single flag.
|
|
54
|
+
* **CLI included:** A `typer`-based CLI (`epa_pm_api_wrapper`) for ad-hoc lookups across the most common resources.
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
The CLI will prompt for credentials or read them from environment variables.
|
|
59
|
+
|
|
60
|
+
### Environment Variables
|
|
61
|
+
|
|
62
|
+
You can set the following environment variables:
|
|
63
|
+
|
|
64
|
+
* `EPA_PM_USERNAME`
|
|
65
|
+
* `EPA_PM_PASSWORD`
|
|
66
|
+
* `EPA_PM_TEST`: Set to `true` to target the test environment instead of live.
|
|
67
|
+
|
|
68
|
+
### Using a `.env` file
|
|
69
|
+
|
|
70
|
+
Copy the example file and fill in your credentials:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cp .env.example .env
|
|
74
|
+
# Edit .env with your credentials
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The CLI will automatically detect and load this file.
|
|
78
|
+
|
|
79
|
+
## Documentation
|
|
80
|
+
|
|
81
|
+
Documentation is built with [Zensical](https://zensical.org/) and deployed to GitHub Pages.
|
|
82
|
+
|
|
83
|
+
* **Live site:** https://harryw1.github.io/EPA-PM-API-Wrapper/
|
|
84
|
+
* **Preview locally:** `just docs-serve` (serves at http://localhost:8000)
|
|
85
|
+
* **Build:** `just docs-build`
|
|
86
|
+
|
|
87
|
+
API documentation is auto-generated from docstrings using [mkdocstrings](https://mkdocstrings.github.io/).
|
|
88
|
+
|
|
89
|
+
Docs deploy automatically on push to `main` via GitHub Actions. To enable this, go to your repo's Settings > Pages and set the source to **GitHub Actions**.
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
To set up for local development:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Clone your fork
|
|
97
|
+
git clone git@github.com:your_username/EPA-PM-API-Wrapper.git
|
|
98
|
+
cd EPA-PM-API-Wrapper
|
|
99
|
+
|
|
100
|
+
# Install in editable mode with live updates
|
|
101
|
+
uv tool install --editable .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This installs the CLI globally but with live updates - any changes you make to the source code are immediately available when you run `epa_pm_api_wrapper`.
|
|
105
|
+
|
|
106
|
+
Run tests:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run pytest
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Run quality checks (format, lint, type check, test):
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
just qa
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Versioning
|
|
119
|
+
|
|
120
|
+
This project follows [Semantic Versioning](https://semver.org/). The public
|
|
121
|
+
API is everything exported from `epa_pm_api_wrapper.__all__` plus the
|
|
122
|
+
attribute-namespaced resource methods on `EpaPmClient` / `EpaPmAsyncClient`.
|
|
123
|
+
Anything in a private module (leading underscore) or the internal
|
|
124
|
+
`_request` / `_arequest` plumbing is implementation detail and may change
|
|
125
|
+
in any release.
|
|
126
|
+
|
|
127
|
+
Pin to a compatible release range when depending on this library:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
EPA-PM-API-Wrapper>=0.3,<0.4
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Author
|
|
134
|
+
|
|
135
|
+
EPA PM API Wrapper was created in 2026 by Harrison Weiss.
|
|
136
|
+
|
|
137
|
+
Built with [Cookiecutter](https://github.com/cookiecutter/cookiecutter) and the [audreyfeldroy/cookiecutter-pypackage](https://github.com/audreyfeldroy/cookiecutter-pypackage) project template.
|