mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-08-25 15:01:14 +00:00
Mypy (#217)
* Mypy: Initial support * Add to pre-commit (currently installs own deps, could maybe changed to poetry venv in the future to reuse environment and don't need duplicated types deps). * Add type hints. * Mypy: Add missing annotations
This commit is contained in:
committed by
GitHub
parent
595b73359c
commit
6e52c9bef2
@@ -15,7 +15,7 @@ from akkudoktoreos.config import EOS_DIR, AppConfig, load_config
|
||||
def load_config_tmp(tmp_path: Path) -> AppConfig:
|
||||
"""Creates an AppConfig from default.config.json with a tmp output directory."""
|
||||
config = load_config(tmp_path)
|
||||
config.directories.output = tmp_path
|
||||
config.directories.output = str(tmp_path)
|
||||
return config
|
||||
|
||||
|
||||
|
@@ -299,7 +299,7 @@ def test_cache_in_file_decorator_forces_update(cache_store):
|
||||
cache_file.write(result2)
|
||||
|
||||
# Call the decorated function again with force update (should get result from function)
|
||||
result = my_function(until_date=until_date, force_update=True)
|
||||
result = my_function(until_date=until_date, force_update=True) # type: ignore[call-arg]
|
||||
assert result == result1
|
||||
|
||||
# Assure result was written to the same cache file
|
||||
@@ -319,7 +319,7 @@ def test_cache_in_file_handles_ttl(cache_store):
|
||||
return "New result"
|
||||
|
||||
# Call the decorated function
|
||||
result = my_function(with_ttl="1 second")
|
||||
result = my_function(with_ttl="1 second") # type: ignore[call-arg]
|
||||
|
||||
# Overwrite cache file
|
||||
key = next(iter(cache_store._store))
|
||||
@@ -330,14 +330,14 @@ def test_cache_in_file_handles_ttl(cache_store):
|
||||
cache_file.seek(0) # Move to the start of the file
|
||||
assert cache_file.read() == "Modified result"
|
||||
|
||||
result = my_function(with_ttl="1 second")
|
||||
result = my_function(with_ttl="1 second") # type: ignore[call-arg]
|
||||
assert result == "Modified result"
|
||||
|
||||
# Wait one second to let the cache time out
|
||||
sleep(1)
|
||||
|
||||
# Call again - cache should be timed out
|
||||
result = my_function(with_ttl="1 second")
|
||||
result = my_function(with_ttl="1 second") # type: ignore[call-arg]
|
||||
assert result == "New result"
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ def test_cache_in_file_handles_bytes_return(cache_store):
|
||||
|
||||
# Define a function that returns bytes
|
||||
@cache_in_file()
|
||||
def my_function(until_date=None):
|
||||
def my_function(until_date=None) -> bytes:
|
||||
return b"Some binary data"
|
||||
|
||||
# Call the decorated function
|
||||
@@ -358,7 +358,14 @@ def test_cache_in_file_handles_bytes_return(cache_store):
|
||||
# Check if the binary data was written to the cache file
|
||||
key = next(iter(cache_store._store))
|
||||
cache_file = cache_store._store[key][0]
|
||||
assert len(cache_store._store) == 1
|
||||
assert cache_file is not None
|
||||
cache_file.seek(0)
|
||||
result1 = pickle.load(cache_file)
|
||||
assert result1 == result
|
||||
|
||||
# Access cache
|
||||
result = my_function(until_date=datetime.now() + timedelta(days=1))
|
||||
assert len(cache_store._store) == 1
|
||||
assert cache_store._store[key][0] is not None
|
||||
assert result1 == result
|
||||
|
@@ -8,6 +8,7 @@ from akkudoktoreos.devices.inverter import Wechselrichter, WechselrichterParamet
|
||||
from akkudoktoreos.prediction.ems import (
|
||||
EnergieManagementSystem,
|
||||
EnergieManagementSystemParameters,
|
||||
SimulationResult,
|
||||
)
|
||||
|
||||
prediction_hours = 48
|
||||
@@ -211,9 +212,9 @@ def create_ems_instance(tmp_config: AppConfig) -> EnergieManagementSystem:
|
||||
preis_euro_pro_wh_akku=preis_euro_pro_wh_akku,
|
||||
gesamtlast=gesamtlast,
|
||||
),
|
||||
wechselrichter=wechselrichter,
|
||||
eauto=eauto,
|
||||
home_appliance=home_appliance,
|
||||
wechselrichter=wechselrichter,
|
||||
)
|
||||
|
||||
return ems
|
||||
@@ -255,26 +256,7 @@ def test_simulation(create_ems_instance):
|
||||
|
||||
# Check that the result is a dictionary
|
||||
assert isinstance(result, dict), "Result should be a dictionary."
|
||||
|
||||
# Verify that the expected keys are present in the result
|
||||
expected_keys = [
|
||||
"Last_Wh_pro_Stunde",
|
||||
"Netzeinspeisung_Wh_pro_Stunde",
|
||||
"Netzbezug_Wh_pro_Stunde",
|
||||
"Kosten_Euro_pro_Stunde",
|
||||
"akku_soc_pro_stunde",
|
||||
"Einnahmen_Euro_pro_Stunde",
|
||||
"Gesamtbilanz_Euro",
|
||||
"EAuto_SoC_pro_Stunde",
|
||||
"Gesamteinnahmen_Euro",
|
||||
"Gesamtkosten_Euro",
|
||||
"Verluste_Pro_Stunde",
|
||||
"Gesamt_Verluste",
|
||||
"Home_appliance_wh_per_hour",
|
||||
]
|
||||
|
||||
for key in expected_keys:
|
||||
assert key in result, f"The key '{key}' should be present in the result."
|
||||
assert SimulationResult(**result) is not None
|
||||
|
||||
# Check the length of the main arrays
|
||||
assert (
|
||||
@@ -344,7 +326,7 @@ def test_simulation(create_ems_instance):
|
||||
assert (
|
||||
np.nansum(
|
||||
np.where(
|
||||
np.equal(result["Home_appliance_wh_per_hour"], None),
|
||||
result["Home_appliance_wh_per_hour"] is None,
|
||||
np.nan,
|
||||
np.array(result["Home_appliance_wh_per_hour"]),
|
||||
)
|
||||
|
@@ -44,13 +44,13 @@ def create_ems_instance(tmp_config: AppConfig) -> EnergieManagementSystem:
|
||||
)
|
||||
|
||||
# Parameters based on previous example data
|
||||
pv_prognose_wh = np.full(prediction_hours, 0)
|
||||
pv_prognose_wh = [0.0] * prediction_hours
|
||||
pv_prognose_wh[10] = 5000.0
|
||||
pv_prognose_wh[11] = 5000.0
|
||||
|
||||
strompreis_euro_pro_wh = np.full(48, 0.001)
|
||||
strompreis_euro_pro_wh[0:10] = 0.00001
|
||||
strompreis_euro_pro_wh[11:15] = 0.00005
|
||||
strompreis_euro_pro_wh = [0.001] * prediction_hours
|
||||
strompreis_euro_pro_wh[0:10] = [0.00001] * 10
|
||||
strompreis_euro_pro_wh[11:15] = [0.00005] * 4
|
||||
strompreis_euro_pro_wh[20] = 0.00001
|
||||
|
||||
einspeiseverguetung_euro_pro_wh = [0.00007] * len(strompreis_euro_pro_wh)
|
||||
@@ -116,9 +116,9 @@ def create_ems_instance(tmp_config: AppConfig) -> EnergieManagementSystem:
|
||||
preis_euro_pro_wh_akku=0,
|
||||
gesamtlast=gesamtlast,
|
||||
),
|
||||
wechselrichter=wechselrichter,
|
||||
eauto=eauto,
|
||||
home_appliance=home_appliance,
|
||||
wechselrichter=wechselrichter,
|
||||
)
|
||||
|
||||
ac = np.full(prediction_hours, 0)
|
||||
|
@@ -54,7 +54,7 @@ def test_optimize(
|
||||
|
||||
file = DIR_TESTDATA / fn_out
|
||||
with file.open("r") as f_out:
|
||||
expected_output_data = json.load(f_out)
|
||||
expected_result = OptimizeResponse(**json.load(f_out))
|
||||
|
||||
opt_class = optimization_problem(tmp_config, fixed_seed=42)
|
||||
start_hour = 10
|
||||
@@ -72,9 +72,7 @@ def test_optimize(
|
||||
# Assert that the output contains all expected entries.
|
||||
# This does not assert that the optimization always gives the same result!
|
||||
# Reproducibility and mathematical accuracy should be tested on the level of individual components.
|
||||
compare_dict(ergebnis, expected_output_data)
|
||||
compare_dict(ergebnis.model_dump(), expected_result.model_dump())
|
||||
|
||||
# The function creates a visualization result PDF as a side-effect.
|
||||
visualisiere_ergebnisse_patch.assert_called_once()
|
||||
|
||||
OptimizeResponse(**ergebnis)
|
||||
|
@@ -49,7 +49,7 @@ def test_config_merge(tmp_path: Path) -> None:
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
# custom configuration is broken but not updated.
|
||||
load_config(tmp_path, tmp_path, False)
|
||||
load_config(tmp_path, True, False)
|
||||
|
||||
with config_file.open("r") as f_in:
|
||||
# custom configuration is not changed.
|
||||
|
@@ -121,7 +121,7 @@ def test_update_ac_power_measurement(pv_forecast_instance, sample_forecast_start
|
||||
forecast_start = pv_forecast_instance.get_forecast_start()
|
||||
assert forecast_start == sample_forecast_start
|
||||
|
||||
updated = pv_forecast_instance.update_ac_power_measurement(forecast_start, 1000)
|
||||
updated = pv_forecast_instance.update_ac_power_measurement(1000, forecast_start)
|
||||
assert updated is True
|
||||
forecast_data = pv_forecast_instance.get_forecast_data()
|
||||
assert forecast_data[0].ac_power_measurement == 1000
|
||||
@@ -130,7 +130,7 @@ def test_update_ac_power_measurement(pv_forecast_instance, sample_forecast_start
|
||||
def test_update_ac_power_measurement_no_match(pv_forecast_instance):
|
||||
"""Test updating AC power measurement where no date matches."""
|
||||
date_time = datetime(2023, 10, 2, 1, 0, 0)
|
||||
updated = pv_forecast_instance.update_ac_power_measurement(date_time, 1000)
|
||||
updated = pv_forecast_instance.update_ac_power_measurement(1000, date_time)
|
||||
assert not updated
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ def test_timezone_behaviour(
|
||||
# Test updating AC power measurement for a specific date.
|
||||
date_time = pv_forecast_instance.get_forecast_start()
|
||||
assert date_time == sample_forecast_start
|
||||
updated = pv_forecast_instance.update_ac_power_measurement(date_time, 1000)
|
||||
updated = pv_forecast_instance.update_ac_power_measurement(1000, date_time)
|
||||
assert updated is True
|
||||
forecast_data = pv_forecast_instance.get_forecast_data()
|
||||
assert forecast_data[0].ac_power_measurement == 1000
|
||||
|
Reference in New Issue
Block a user