pre-commit update and python 3.11 req

This commit is contained in:
Normann 2025-03-02 11:19:54 +01:00
parent 1f30d4e403
commit b20083a3dd
11 changed files with 9115 additions and 9115 deletions

View File

@ -12,12 +12,12 @@ repos:
- id: check-merge-conflict
exclude: '\.rst$' # Exclude .rst files
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
rev: 6.0.1
hooks:
- id: isort
name: isort
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.8
rev: v0.9.9
hooks:
# Run the linter and fix simple issues automatically
- id: ruff
@ -25,7 +25,7 @@ repos:
# Run the formatter.
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.13.0'
rev: 'v1.15.0'
hooks:
- id: mypy
additional_dependencies:
@ -34,7 +34,7 @@ repos:
- "numpy==2.1.3"
pass_filenames: false
- repo: https://github.com/jackdewinter/pymarkdown
rev: main
rev: v0.9.28
hooks:
- id: pymarkdown
files: ^docs/

View File

@ -10,7 +10,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
## System requirements
- Python >= 3.10, < 3.13
- Python >= 3.11, < 3.13
- Architecture: amd64, aarch64 (armv8)
- OS: Linux, Windows, macOS

View File

@ -287,11 +287,11 @@
| Name | Type | Read-Only | Default | Description |
| ---- | ---- | --------- | ------- | ----------- |
| `server_eos_host` | `Optional[pydantic.networks.IPvAnyAddress]` | `rw` | `0.0.0.0` | EOS server IP address. |
| `server_eos_host` | `Optional[pydantic.networks.IPvAnyAddress]` | `rw` | `127.0.0.1` | EOS server IP address. |
| `server_eos_port` | `Optional[int]` | `rw` | `8503` | EOS server IP port number. |
| `server_eos_startup_eosdash` | `Optional[bool]` | `rw` | `True` | EOS server to start EOSdash server. |
| `server_eos_verbose` | `Optional[bool]` | `rw` | `False` | Enable debug output |
| `server_eosdash_host` | `Optional[pydantic.networks.IPvAnyAddress]` | `rw` | `0.0.0.0` | EOSdash server IP address. |
| `server_eosdash_host` | `Optional[pydantic.networks.IPvAnyAddress]` | `rw` | `127.0.0.1` | EOSdash server IP address. |
| `server_eosdash_port` | `Optional[int]` | `rw` | `8504` | EOSdash server IP port number. |
:::

17910
openapi.json

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ authors = [
description = "This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period."
readme = "README.md"
license = {file = "LICENSE"}
requires-python = ">=3.10"
requires-python = ">=3.11"
classifiers = [
"Development Status :: 3 - Alpha",
"Programming Language :: Python :: 3",

View File

@ -1224,14 +1224,14 @@ class DataImportMixin:
# We jump back by 1 hour
# Repeat the value(s) (reuse value index)
for i in range(interval_steps_per_hour):
logger.debug(f"{i+1}: Repeat at {next_time} with index {value_index}")
logger.debug(f"{i + 1}: Repeat at {next_time} with index {value_index}")
timestamps_with_indices.append((next_time, value_index))
next_time = next_time.add(seconds=interval.total_seconds())
else:
# We jump forward by 1 hour
# Drop the value(s)
logger.debug(
f"{i+1}: Skip {interval_steps_per_hour} at {next_time} with index {value_index}"
f"{i + 1}: Skip {interval_steps_per_hour} at {next_time} with index {value_index}"
)
value_index += interval_steps_per_hour

View File

@ -114,9 +114,9 @@ def test_soc_limits(setup_pv_battery):
def test_max_charge_power_w(setup_pv_battery):
battery = setup_pv_battery
battery.setup()
assert (
battery.parameters.max_charge_power_w == 8000
), "Default max charge power should be 5000W, We ask for 8000W here"
assert battery.parameters.max_charge_power_w == 8000, (
"Default max charge power should be 5000W, We ask for 8000W here"
)
def test_charge_energy_within_limits(setup_pv_battery):
@ -140,9 +140,9 @@ def test_charge_energy_exceeds_capacity(setup_pv_battery):
# Try to overcharge beyond max capacity
charged_wh, losses_wh = battery.charge_energy(wh=20000, hour=2)
assert (
charged_wh + initial_soc_wh <= battery.max_soc_wh
), "Charging should not exceed max capacity"
assert charged_wh + initial_soc_wh <= battery.max_soc_wh, (
"Charging should not exceed max capacity"
)
assert losses_wh >= 0, "Losses should not be negative"
assert battery.soc_wh == battery.max_soc_wh, "SOC should be at max after overcharge attempt"
@ -172,9 +172,9 @@ def test_charge_energy_relative_power(setup_pv_battery):
assert charged_wh > 0, "Charging should occur with relative power"
assert losses_wh >= 0, "Losses should not be negative"
assert (
charged_wh <= battery.max_charge_power_w * relative_power
), "Charging should respect relative power limit"
assert charged_wh <= battery.max_charge_power_w * relative_power, (
"Charging should respect relative power limit"
)
assert battery.soc_wh > 0, "SOC should increase after charging"
@ -201,19 +201,19 @@ def test_car_and_pv_battery_discharge_and_max_charge_power(setup_pv_battery, set
# Test discharge for PV battery
pv_discharged_wh, pv_loss_wh = pv_battery.discharge_energy(3000, 5)
assert pv_discharged_wh > 0, "PV battery should discharge energy"
assert (
pv_battery.current_soc_percentage() >= pv_battery.parameters.min_soc_percentage
), "PV battery SOC should stay above min SOC"
assert (
pv_battery.parameters.max_charge_power_w == 8000
), "PV battery max charge power should remain as defined"
assert pv_battery.current_soc_percentage() >= pv_battery.parameters.min_soc_percentage, (
"PV battery SOC should stay above min SOC"
)
assert pv_battery.parameters.max_charge_power_w == 8000, (
"PV battery max charge power should remain as defined"
)
# Test discharge for car battery
car_discharged_wh, car_loss_wh = car_battery.discharge_energy(5000, 10)
assert car_discharged_wh > 0, "Car battery should discharge energy"
assert (
car_battery.current_soc_percentage() >= car_battery.parameters.min_soc_percentage
), "Car battery SOC should stay above min SOC"
assert (
car_battery.parameters.max_charge_power_w == 7000
), "Car battery max charge power should remain as defined"
assert car_battery.current_soc_percentage() >= car_battery.parameters.min_soc_percentage, (
"Car battery SOC should stay above min SOC"
)
assert car_battery.parameters.max_charge_power_w == 7000, (
"Car battery max charge power should remain as defined"
)

View File

@ -283,69 +283,69 @@ def test_simulation(create_ems_instance):
assert SimulationResult(**result) is not None
# Check the length of the main arrays
assert (
len(result["Last_Wh_pro_Stunde"]) == 47
), "The length of 'Last_Wh_pro_Stunde' should be 48."
assert (
len(result["Netzeinspeisung_Wh_pro_Stunde"]) == 47
), "The length of 'Netzeinspeisung_Wh_pro_Stunde' should be 48."
assert (
len(result["Netzbezug_Wh_pro_Stunde"]) == 47
), "The length of 'Netzbezug_Wh_pro_Stunde' should be 48."
assert (
len(result["Kosten_Euro_pro_Stunde"]) == 47
), "The length of 'Kosten_Euro_pro_Stunde' should be 48."
assert (
len(result["akku_soc_pro_stunde"]) == 47
), "The length of 'akku_soc_pro_stunde' should be 48."
assert len(result["Last_Wh_pro_Stunde"]) == 47, (
"The length of 'Last_Wh_pro_Stunde' should be 48."
)
assert len(result["Netzeinspeisung_Wh_pro_Stunde"]) == 47, (
"The length of 'Netzeinspeisung_Wh_pro_Stunde' should be 48."
)
assert len(result["Netzbezug_Wh_pro_Stunde"]) == 47, (
"The length of 'Netzbezug_Wh_pro_Stunde' should be 48."
)
assert len(result["Kosten_Euro_pro_Stunde"]) == 47, (
"The length of 'Kosten_Euro_pro_Stunde' should be 48."
)
assert len(result["akku_soc_pro_stunde"]) == 47, (
"The length of 'akku_soc_pro_stunde' should be 48."
)
# Verify specific values in the 'Last_Wh_pro_Stunde' array
assert (
result["Last_Wh_pro_Stunde"][1] == 1527.13
), "The value at index 1 of 'Last_Wh_pro_Stunde' should be 1527.13."
assert (
result["Last_Wh_pro_Stunde"][2] == 1468.88
), "The value at index 2 of 'Last_Wh_pro_Stunde' should be 1468.88."
assert (
result["Last_Wh_pro_Stunde"][12] == 1132.03
), "The value at index 12 of 'Last_Wh_pro_Stunde' should be 1132.03."
assert result["Last_Wh_pro_Stunde"][1] == 1527.13, (
"The value at index 1 of 'Last_Wh_pro_Stunde' should be 1527.13."
)
assert result["Last_Wh_pro_Stunde"][2] == 1468.88, (
"The value at index 2 of 'Last_Wh_pro_Stunde' should be 1468.88."
)
assert result["Last_Wh_pro_Stunde"][12] == 1132.03, (
"The value at index 12 of 'Last_Wh_pro_Stunde' should be 1132.03."
)
# Verify that the value at index 0 is 'None'
# Check that 'Netzeinspeisung_Wh_pro_Stunde' and 'Netzbezug_Wh_pro_Stunde' are consistent
assert (
result["Netzbezug_Wh_pro_Stunde"][1] == 0
), "The value at index 1 of 'Netzbezug_Wh_pro_Stunde' should be 0."
assert result["Netzbezug_Wh_pro_Stunde"][1] == 0, (
"The value at index 1 of 'Netzbezug_Wh_pro_Stunde' should be 0."
)
# Verify the total balance
assert (
abs(result["Gesamtbilanz_Euro"] - 1.958185274567674) < 1e-5
), "Total balance should be 1.958185274567674."
assert abs(result["Gesamtbilanz_Euro"] - 1.958185274567674) < 1e-5, (
"Total balance should be 1.958185274567674."
)
# Check total revenue and total costs
assert (
abs(result["Gesamteinnahmen_Euro"] - 1.168863124510214) < 1e-5
), "Total revenue should be 1.168863124510214."
assert (
abs(result["Gesamtkosten_Euro"] - 3.127048399077888) < 1e-5
), "Total costs should be 3.127048399077888 ."
assert abs(result["Gesamteinnahmen_Euro"] - 1.168863124510214) < 1e-5, (
"Total revenue should be 1.168863124510214."
)
assert abs(result["Gesamtkosten_Euro"] - 3.127048399077888) < 1e-5, (
"Total costs should be 3.127048399077888 ."
)
# Check the losses
assert (
abs(result["Gesamt_Verluste"] - 2871.5330639359036) < 1e-5
), "Total losses should be 2871.5330639359036 ."
assert abs(result["Gesamt_Verluste"] - 2871.5330639359036) < 1e-5, (
"Total losses should be 2871.5330639359036 ."
)
# Check the values in 'akku_soc_pro_stunde'
assert (
result["akku_soc_pro_stunde"][-1] == 42.151590909090906
), "The value at index -1 of 'akku_soc_pro_stunde' should be 42.151590909090906."
assert (
result["akku_soc_pro_stunde"][1] == 60.08659090909091
), "The value at index 1 of 'akku_soc_pro_stunde' should be 60.08659090909091."
assert result["akku_soc_pro_stunde"][-1] == 42.151590909090906, (
"The value at index -1 of 'akku_soc_pro_stunde' should be 42.151590909090906."
)
assert result["akku_soc_pro_stunde"][1] == 60.08659090909091, (
"The value at index 1 of 'akku_soc_pro_stunde' should be 60.08659090909091."
)
# Check home appliances
assert (
sum(ems.home_appliance.get_load_curve()) == 2000
), "The sum of 'ems.home_appliance.get_load_curve()' should be 2000."
assert sum(ems.home_appliance.get_load_curve()) == 2000, (
"The sum of 'ems.home_appliance.get_load_curve()' should be 2000."
)
assert (
np.nansum(

View File

@ -216,44 +216,44 @@ def test_simulation(create_ems_instance):
assert key in result, f"The key '{key}' should be present in the result."
# Check the length of the main arrays
assert (
len(result["Last_Wh_pro_Stunde"]) == 48
), "The length of 'Last_Wh_pro_Stunde' should be 48."
assert (
len(result["Netzeinspeisung_Wh_pro_Stunde"]) == 48
), "The length of 'Netzeinspeisung_Wh_pro_Stunde' should be 48."
assert (
len(result["Netzbezug_Wh_pro_Stunde"]) == 48
), "The length of 'Netzbezug_Wh_pro_Stunde' should be 48."
assert (
len(result["Kosten_Euro_pro_Stunde"]) == 48
), "The length of 'Kosten_Euro_pro_Stunde' should be 48."
assert (
len(result["akku_soc_pro_stunde"]) == 48
), "The length of 'akku_soc_pro_stunde' should be 48."
assert len(result["Last_Wh_pro_Stunde"]) == 48, (
"The length of 'Last_Wh_pro_Stunde' should be 48."
)
assert len(result["Netzeinspeisung_Wh_pro_Stunde"]) == 48, (
"The length of 'Netzeinspeisung_Wh_pro_Stunde' should be 48."
)
assert len(result["Netzbezug_Wh_pro_Stunde"]) == 48, (
"The length of 'Netzbezug_Wh_pro_Stunde' should be 48."
)
assert len(result["Kosten_Euro_pro_Stunde"]) == 48, (
"The length of 'Kosten_Euro_pro_Stunde' should be 48."
)
assert len(result["akku_soc_pro_stunde"]) == 48, (
"The length of 'akku_soc_pro_stunde' should be 48."
)
# Verfify DC and AC Charge Bins
assert (
abs(result["akku_soc_pro_stunde"][2] - 44.70681818181818) < 1e-5
), "'akku_soc_pro_stunde[2]' should be 44.70681818181818."
assert (
abs(result["akku_soc_pro_stunde"][10] - 10.0) < 1e-5
), "'akku_soc_pro_stunde[10]' should be 10."
assert abs(result["akku_soc_pro_stunde"][2] - 44.70681818181818) < 1e-5, (
"'akku_soc_pro_stunde[2]' should be 44.70681818181818."
)
assert abs(result["akku_soc_pro_stunde"][10] - 10.0) < 1e-5, (
"'akku_soc_pro_stunde[10]' should be 10."
)
assert (
abs(result["Netzeinspeisung_Wh_pro_Stunde"][10] - 3946.93) < 1e-3
), "'Netzeinspeisung_Wh_pro_Stunde[11]' should be 3946.93."
assert abs(result["Netzeinspeisung_Wh_pro_Stunde"][10] - 3946.93) < 1e-3, (
"'Netzeinspeisung_Wh_pro_Stunde[11]' should be 3946.93."
)
assert (
abs(result["Netzeinspeisung_Wh_pro_Stunde"][11] - 0.0) < 1e-3
), "'Netzeinspeisung_Wh_pro_Stunde[11]' should be 0.0."
assert abs(result["Netzeinspeisung_Wh_pro_Stunde"][11] - 0.0) < 1e-3, (
"'Netzeinspeisung_Wh_pro_Stunde[11]' should be 0.0."
)
assert (
abs(result["akku_soc_pro_stunde"][20] - 10) < 1e-5
), "'akku_soc_pro_stunde[20]' should be 10."
assert (
abs(result["Last_Wh_pro_Stunde"][20] - 6050.98) < 1e-3
), "'Last_Wh_pro_Stunde[20]' should be 6050.98."
assert abs(result["akku_soc_pro_stunde"][20] - 10) < 1e-5, (
"'akku_soc_pro_stunde[20]' should be 10."
)
assert abs(result["Last_Wh_pro_Stunde"][20] - 6050.98) < 1e-3, (
"'Last_Wh_pro_Stunde[20]' should be 6050.98."
)
print("All tests passed successfully.")
@ -266,9 +266,9 @@ def test_set_parameters(create_ems_instance):
assert ems.load_energy_array is not None, "load_energy_array should not be None"
assert ems.pv_prediction_wh is not None, "pv_prediction_wh should not be None"
assert ems.elect_price_hourly is not None, "elect_price_hourly should not be None"
assert (
ems.elect_revenue_per_hour_arr is not None
), "elect_revenue_per_hour_arr should not be None"
assert ems.elect_revenue_per_hour_arr is not None, (
"elect_revenue_per_hour_arr should not be None"
)
def test_set_akku_discharge_hours(create_ems_instance):
@ -276,9 +276,9 @@ def test_set_akku_discharge_hours(create_ems_instance):
ems = create_ems_instance
discharge_hours = np.full(ems.config.prediction_hours, 1.0)
ems.set_akku_discharge_hours(discharge_hours)
assert np.array_equal(
ems.battery.discharge_array, discharge_hours
), "Discharge hours should be set correctly"
assert np.array_equal(ems.battery.discharge_array, discharge_hours), (
"Discharge hours should be set correctly"
)
def test_set_akku_ac_charge_hours(create_ems_instance):
@ -286,9 +286,9 @@ def test_set_akku_ac_charge_hours(create_ems_instance):
ems = create_ems_instance
ac_charge_hours = np.full(ems.config.prediction_hours, 1.0)
ems.set_akku_ac_charge_hours(ac_charge_hours)
assert np.array_equal(
ems.ac_charge_hours, ac_charge_hours
), "AC charge hours should be set correctly"
assert np.array_equal(ems.ac_charge_hours, ac_charge_hours), (
"AC charge hours should be set correctly"
)
def test_set_akku_dc_charge_hours(create_ems_instance):
@ -296,9 +296,9 @@ def test_set_akku_dc_charge_hours(create_ems_instance):
ems = create_ems_instance
dc_charge_hours = np.full(ems.config.prediction_hours, 1.0)
ems.set_akku_dc_charge_hours(dc_charge_hours)
assert np.array_equal(
ems.dc_charge_hours, dc_charge_hours
), "DC charge hours should be set correctly"
assert np.array_equal(ems.dc_charge_hours, dc_charge_hours), (
"DC charge hours should be set correctly"
)
def test_set_ev_charge_hours(create_ems_instance):
@ -306,9 +306,9 @@ def test_set_ev_charge_hours(create_ems_instance):
ems = create_ems_instance
ev_charge_hours = np.full(ems.config.prediction_hours, 1.0)
ems.set_ev_charge_hours(ev_charge_hours)
assert np.array_equal(
ems.ev_charge_hours, ev_charge_hours
), "EV charge hours should be set correctly"
assert np.array_equal(ems.ev_charge_hours, ev_charge_hours), (
"EV charge hours should be set correctly"
)
def test_reset(create_ems_instance):
@ -316,9 +316,9 @@ def test_reset(create_ems_instance):
ems = create_ems_instance
ems.reset()
assert ems.ev.current_soc_percentage() == 100, "EV SOC should be reset to initial value"
assert (
ems.battery.current_soc_percentage() == 80
), "Battery SOC should be reset to initial value"
assert ems.battery.current_soc_percentage() == 80, (
"Battery SOC should be reset to initial value"
)
def test_simulate_start_now(create_ems_instance):

View File

@ -588,9 +588,9 @@ class TestDataProvider:
"""Test that DataProvider enforces singleton behavior."""
instance1 = provider
instance2 = DerivedDataProvider()
assert (
instance1 is instance2
), "Singleton pattern is not enforced; instances are not the same."
assert instance1 is instance2, (
"Singleton pattern is not enforced; instances are not the same."
)
def test_update_method_with_defaults(self, provider, sample_start_datetime, monkeypatch):
"""Test the `update` method with default parameters."""
@ -608,9 +608,9 @@ class TestDataProvider:
DerivedDataProvider.provider_updated = False
provider.update_data(force_enable=True)
assert provider.enabled() is False, "Provider should be disabled, but enabled() is True."
assert (
DerivedDataProvider.provider_updated is True
), "Provider should have been executed, but was not."
assert DerivedDataProvider.provider_updated is True, (
"Provider should have been executed, but was not."
)
def test_delete_by_datetime(self, provider, sample_start_datetime):
"""Test `delete_by_datetime` method for removing records by datetime range."""
@ -625,12 +625,12 @@ class TestDataProvider:
start_datetime=sample_start_datetime - to_duration("2 hours"),
end_datetime=sample_start_datetime + to_duration("2 hours"),
)
assert (
len(provider.records) == 1
), "Only one record should remain after deletion by datetime."
assert provider.records[0].date_time == sample_start_datetime - to_duration(
"3 hours"
), "Unexpected record remains."
assert len(provider.records) == 1, (
"Only one record should remain after deletion by datetime."
)
assert provider.records[0].date_time == sample_start_datetime - to_duration("3 hours"), (
"Unexpected record remains."
)
class TestDataImportProvider:

View File

@ -151,9 +151,9 @@ class TestPredictionProvider:
"""Test that PredictionProvider enforces singleton behavior."""
instance1 = provider
instance2 = DerivedPredictionProvider()
assert (
instance1 is instance2
), "Singleton pattern is not enforced; instances are not the same."
assert instance1 is instance2, (
"Singleton pattern is not enforced; instances are not the same."
)
def test_update_computed_fields(self, provider, sample_start_datetime):
"""Test that computed fields `end_datetime` and `keep_datetime` are correctly calculated."""
@ -169,12 +169,12 @@ class TestPredictionProvider:
provider.config.prediction_historic_hours * 3600
)
assert (
provider.end_datetime == expected_end_datetime
), "End datetime is not calculated correctly."
assert (
provider.keep_datetime == expected_keep_datetime
), "Keep datetime is not calculated correctly."
assert provider.end_datetime == expected_end_datetime, (
"End datetime is not calculated correctly."
)
assert provider.keep_datetime == expected_keep_datetime, (
"Keep datetime is not calculated correctly."
)
def test_update_method_with_defaults(
self, provider, sample_start_datetime, config_eos, monkeypatch
@ -214,9 +214,9 @@ class TestPredictionProvider:
DerivedPredictionProvider.provider_updated = False
provider.update_data(force_enable=True)
assert provider.enabled() is False, "Provider should be disabled, but enabled() is True."
assert (
DerivedPredictionProvider.provider_updated is True
), "Provider should have been executed, but was not."
assert DerivedPredictionProvider.provider_updated is True, (
"Provider should have been executed, but was not."
)
def test_delete_by_datetime(self, provider, sample_start_datetime):
"""Test `delete_by_datetime` method for removing records by datetime range."""
@ -231,12 +231,12 @@ class TestPredictionProvider:
start_datetime=sample_start_datetime - to_duration("2 hours"),
end_datetime=sample_start_datetime + to_duration("2 hours"),
)
assert (
len(provider.records) == 1
), "Only one record should remain after deletion by datetime."
assert provider.records[0].date_time == sample_start_datetime - to_duration(
"3 hours"
), "Unexpected record remains."
assert len(provider.records) == 1, (
"Only one record should remain after deletion by datetime."
)
assert provider.records[0].date_time == sample_start_datetime - to_duration("3 hours"), (
"Unexpected record remains."
)
class TestPredictionContainer: