chore: adapt pdf visualization (#1205)

Change PDF visualization to be created on demand and per optimization algorithm. The PDF
for the GENETIC0 optimization is provided by the /visualization_results.pdf endpoint.
There is no change in the interface.

By this the optimization algorithm is offloaded from the PDF generation which spares some
time.

To cope with several users may call the /visualization_results.pdf endpoint at the same
time the PDF is generated on the fly without any intermediate file taking the stored
GENETIC0 solution as an input. SVG picture generation is removed as this would again
create intermediate files. Chart pictures can easily be taken from the PDF.

To allow on demand creation of the optimization results visualization the optimisation
solution stored is extended by several new attributes. To keep the deprecated
/optimize endpoint compatible the optimization solution is stripped to the legacy
content before returned. Due to the extension of the solution the optimization tests were
adapted to cover the extended content.

The optimization tests are adapted to test the generated visualization report by
the pypdf reader. Pypdf is added to the development dependencies.

Besides the adaptation several fixes and improvements are added:

* feat: extend /v1/prediction/series endpoint by resampling and filling

  Add parameters for resampling and filling. Add the processing parameter
  to control wether raw data or resampled data shall be returned.

* feat: extend /v1/measurement/series endpoint by resampling and filling

  Add parameters for resampling and filling: Add the processing parameter
  to control wether raw data or resampled data shall be returned.

* feat: standardize and improve API error response

  Use FASTApi exception handlers to provide a standardized API exception handling.
  All exceptions are logged.

  Exception traces are only returned if the new logging configuration parameter
  logging.api_logging_level is set to "DEBUG" or "TRACE". Avoids unwanted leackage
  of server internals on exceptions.

* fix: align to intervall when resampling

  Ensure resampling is aligned to interval also when the buckets are shifted due to the
  align_to_intervall parameter is set.

* chore: make dropna mandatory and default to True

* chore: refactor key_to_xxx data management methods

  Make key_to_series the central method for data resampling and fill.
  Add a new key_to_raw_series to retrieve the data as it is stored
  (without resampling and filling).

  Users of key_to_series were mostly moved to key_to_raw_series as this resembles
  the former interface. Especially in predictions and tests this was done.

* chore: create test data sub-directory for each optimization algorithm

  To prevent cluttering the test data directory and ease test data management for
  optimization algorithms each algorithm got it's own sub-directory. The current
  test data was moved to these sub-directories.

* chore: update version

Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
Bobby Noelte
2026-08-01 12:45:19 +02:00
committed by GitHub
parent 8344974c16
commit 1905682113
61 changed files with 29450 additions and 9083 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ DOCKER_COMPOSE_DATA_DIR=${HOME}/.local/share/net.akkudoktor.eos
# -----------------------------------------------------------------------------
# Image / build
# -----------------------------------------------------------------------------
VERSION=0.3.0.dev2607301181843779
VERSION=0.3.0.dev2608010961051894
PYTHON_VERSION=3.13.9
# -----------------------------------------------------------------------------
+1 -1
View File
@@ -6,7 +6,7 @@
# the root directory (no add-on folder as usual).
name: "Akkudoktor-EOS"
version: "0.3.0.dev2607301181843779"
version: "0.3.0.dev2608010961051894"
slug: "eos"
description: "Akkudoktor-EOS add-on"
url: "https://github.com/Akkudoktor-EOS/EOS"
+1
View File
@@ -162,6 +162,7 @@
}
},
"logging": {
"api_level": "TRACE",
"console_level": "TRACE",
"file_level": "TRACE"
},
+5 -2
View File
@@ -7,8 +7,9 @@
| Name | Environment Variable | Type | Read-Only | Default | Description |
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `str | None` | `rw` | `None` | Logging level when logging to console. |
| file_level | `EOS_LOGGING__FILE_LEVEL` | `str | None` | `rw` | `None` | Logging level when logging to file. |
| api_level | `EOS_LOGGING__API_LEVEL` | `str | None` | `rw` | `None` | Logging level for API response. |
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `str | None` | `rw` | `None` | Logging level for logging to console. |
| file_level | `EOS_LOGGING__FILE_LEVEL` | `str | None` | `rw` | `None` | Logging level for logging to file. |
| file_path | | `pathlib.Path | None` | `ro` | `N/A` | Computed log file path based on data output path. |
:::
<!-- pyml enable line-length -->
@@ -21,6 +22,7 @@
```json
{
"logging": {
"api_level": "TRACE",
"console_level": "TRACE",
"file_level": "TRACE"
}
@@ -36,6 +38,7 @@
```json
{
"logging": {
"api_level": "TRACE",
"console_level": "TRACE",
"file_level": "TRACE",
"file_path": "/home/user/.local/share/net.akkudoktor.eos/output/eos.log"
+170 -5
View File
@@ -1,6 +1,6 @@
# Akkudoktor-EOS
**Version**: `v0.3.0.dev2607301181843779`
**Version**: `v0.3.0.dev2608010961051894`
<!-- pyml disable line-length -->
**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.
@@ -143,7 +143,7 @@ Note:
**Request Body**:
- `application/json`: {
"$ref": "#/components/schemas/Genetic0OptimizationParameters"
"$ref": "#/components/schemas/Genetic0OptimizationParameters-Input"
}
**Responses**:
@@ -948,6 +948,14 @@ Merge the measurement data given as dataframe into EOS measurements.
Fastapi Measurement Keys Get
<!-- pyml disable line-length -->
```python
"""
Get a list of available measurement keys.
"""
```
<!-- pyml enable line-length -->
**Responses**:
- **200**: Successful Response
@@ -997,7 +1005,73 @@ Fastapi Measurement Series Get
<!-- pyml disable line-length -->
```python
"""
Get the measurements of given key as series.
Get measurements for given key within given date range as series.
Args:
key (str): Measurement key
start_datetime (Optional[str]): Starting datetime (inclusive).
Defaults to datetime of first measurement.
end_datetime (Optional[str]: Ending datetime (exclusive).
Defaults to datetime after latest measurement.
interval (Optional[str]): Time duration for each interval.
Defaults to 1 hour.
fill_method (str): Method to handle missing values during resampling.
- 'linear': Linearly interpolate missing values (for numeric data only).
- 'time': Interpolate missing values (for numeric data only).
- 'ffill': Forward fill missing values.
- 'bfill': Backward fill missing values.
- Defaults to 'linear' for numeric values, otherwise 'ffill'.
resample_method (str):
Method used to aggregate values within a resampling interval.
- "first": Use the first value in each interval.
- "mean": Compute the arithmetic mean of all samples in each interval.
- "interval_mean": Compute the time-weighted mean assuming each
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]): resampling boundary
"strict" → only values inside [start, end)
"context" → include one value before and after for proper resampling
align_to_interval (bool): When True, snap the resample origin to the nearest
UTC epoch-aligned boundary of ``interval`` before resampling. This ensures
that bucket timestamps always fall on wall-clock-round times regardless of
when ``start_datetime`` falls:
- 15-minute interval → buckets on :00, :15, :30, :45
- 1-hour interval → buckets on the hour
When False (default), the origin is ``query_start`` (or ``"start_day"`` when
no start is given), preserving the existing behaviour where buckets are
aligned to the query window rather than the clock.
Set to True when storing compacted records back to the database so that the
resulting timestamps are predictable and human-readable. Leave False for
forecast or reporting queries where alignment to the exact query window is
more important than clock-round boundaries.
processing (SeriesProcessing):
Processing mode for the returned series.
- ``SeriesProcessing.RESAMPLED``: Return a processed series.
Measurements are first filtered by ``start_datetime``,
``end_datetime``, and ``dropna``, then resampled according to
``interval`` and ``resample_method``, and finally missing values
are filled using ``fill_method``.
- ``SeriesProcessing.RAW``: Return the original measurement series.
Measurements are filtered by ``start_datetime``,
``end_datetime``, and ``dropna`` only. No resampling or filling is
performed, and ``interval``, ``fill_method``,
``resample_method``, ``boundary``, and
``align_to_interval`` are ignored.
Defaults to ``SeriesProcessing.RAW``.
Returns:
Series
"""
```
<!-- pyml enable line-length -->
@@ -1006,6 +1080,24 @@ Get the measurements of given key as series.
- `key` (query, required): Measurement key.
- `start_datetime` (query, optional): Starting datetime (inclusive).
- `end_datetime` (query, optional): Ending datetime (exclusive).
- `interval` (query, optional): Time duration for each interval. Defaults to 1 hour.
- `fill_method` (query, optional): Method to handle missing values during resampling.
- `resample_method` (query, optional): Method used to aggregate values within a resampling interval.
- `dropna` (query, optional): Drop NAN/ None values before processing.
- `boundary` (query, optional): Resampling boundary mode.
- `align_to_interval` (query, optional): Snap resample origin to the nearest UTC epoch-aligned boundary of interval.
- `processing` (query, optional): Processing mode. 'raw' returns original measurement data without resampling or filling.
**Responses**:
- **200**: Successful Response
@@ -1118,7 +1210,7 @@ Args:
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool, optional): Whether to drop NAN/ None values before processing.
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]): resampling boundary
"strict" → only values inside [start, end)
@@ -1288,7 +1380,7 @@ Args:
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool, optional): Whether to drop NAN/ None values before processing.
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]): resampling boundary
"strict" → only values inside [start, end)
@@ -1423,6 +1515,65 @@ Args:
Defaults to start datetime of latest prediction.
end_datetime (Optional[str]: Ending datetime (exclusive).
Defaults to end datetime of latest prediction.
interval (Optional[str]): Time duration for each interval.
Defaults to 1 hour.
fill_method (str): Method to handle missing values during resampling.
- 'linear': Linearly interpolate missing values (for numeric data only).
- 'time': Interpolate missing values (for numeric data only).
- 'ffill': Forward fill missing values.
- 'bfill': Backward fill missing values.
- Defaults to 'linear' for numeric values, otherwise 'ffill'.
resample_method (str):
Method used to aggregate values within a resampling interval.
- "first": Use the first value in each interval.
- "mean": Compute the arithmetic mean of all samples in each interval.
- "interval_mean": Compute the time-weighted mean assuming each
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]): resampling boundary
"strict" → only values inside [start, end)
"context" → include one value before and after for proper resampling
align_to_interval (bool): When True, snap the resample origin to the nearest
UTC epoch-aligned boundary of ``interval`` before resampling. This ensures
that bucket timestamps always fall on wall-clock-round times regardless of
when ``start_datetime`` falls:
- 15-minute interval → buckets on :00, :15, :30, :45
- 1-hour interval → buckets on the hour
When False (default), the origin is ``query_start`` (or ``"start_day"`` when
no start is given), preserving the existing behaviour where buckets are
aligned to the query window rather than the clock.
Set to True when storing compacted records back to the database so that the
resulting timestamps are predictable and human-readable. Leave False for
forecast or reporting queries where alignment to the exact query window is
more important than clock-round boundaries.
processing (SeriesProcessing):
Processing mode for the returned series.
- ``SeriesProcessing.RESAMPLED``: Return a processed series.
Measurements are first filtered by ``start_datetime``,
``end_datetime``, and ``dropna``, then resampled according to
``interval`` and ``resample_method``, and finally missing values
are filled using ``fill_method``.
- ``SeriesProcessing.RAW``: Return the original measurement series.
Measurements are filtered by ``start_datetime``,
``end_datetime``, and ``dropna`` only. No resampling or filling is
performed, and ``interval``, ``fill_method``,
``resample_method``, ``boundary``, and
``align_to_interval`` are ignored.
Defaults to ``SeriesProcessing.RAW``.
Returns:
Array
"""
```
<!-- pyml enable line-length -->
@@ -1435,6 +1586,20 @@ Args:
- `end_datetime` (query, optional): Ending datetime (exclusive).
- `interval` (query, optional): Time duration for each interval. Defaults to 1 hour.
- `fill_method` (query, optional): Method to handle missing values during resampling.
- `resample_method` (query, optional): Method used to aggregate values within a resampling interval.
- `dropna` (query, optional): Drop NAN/ None values before processing.
- `boundary` (query, optional): Resampling boundary mode.
- `align_to_interval` (query, optional): Snap resample origin to the nearest UTC epoch-aligned boundary of interval.
- `processing` (query, optional): Processing mode. 'raw' returns original measurement data without resampling or filling.
**Responses**:
- **200**: Successful Response
+1605 -38
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -84,6 +84,7 @@ dev = [
"pytest-cov==7.1.0",
"pytest-xprocess==1.0.2",
"coverage==7.15.2",
"pypdf==6.14.2",
]
[project.urls]
+318 -120
View File
@@ -1009,7 +1009,7 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
key: str,
start_datetime: Optional[DateTime] = None,
end_datetime: Optional[DateTime] = None,
dropna: Optional[bool] = None,
dropna: bool = True,
) -> Dict[DateTime, Any]:
"""Extract a dictionary indexed by the date_time field of the DataRecords.
@@ -1020,7 +1020,7 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
key (str): The field name in the DataRecord from which to extract values.
start_datetime (datetime, optional): The start date to filter records (inclusive).
end_datetime (datetime, optional): The end date to filter records (exclusive).
dropna: (bool, optional): Whether to drop NAN/ None values before processing. Defaults to True.
dropna: (bool): Whether to drop NAN/ None values before processing. Defaults to True.
Returns:
Dict[datetime, Any]: A dictionary with the date_time of each record as the key
@@ -1038,8 +1038,6 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
end_timestamp = DatabaseTimestamp.from_datetime(end_datetime) if end_datetime else None
# Create a dictionary to hold date_time and corresponding values
if dropna is None:
dropna = True
filtered_data = {}
async for record in self.db_iterate_records(start_timestamp, end_timestamp):
if (
@@ -1090,7 +1088,7 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
key: str,
start_datetime: Optional[DateTime] = None,
end_datetime: Optional[DateTime] = None,
dropna: Optional[bool] = None,
dropna: bool = True,
) -> Tuple[list[DateTime], list[Optional[float]]]:
"""Extracts two lists from data records within an optional date range.
@@ -1102,7 +1100,7 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
key (str): The key of the attribute in DataRecord to extract.
start_datetime (datetime, optional): The start date for filtering the records (inclusive).
end_datetime (datetime, optional): The end date for filtering the records (exclusive).
dropna: (bool, optional): Whether to drop NAN/ None values before processing. Defaults to True.
dropna: (bool): Whether to drop NAN/ None values before processing. Defaults to True.
Returns:
tuple: A tuple containing a list of datetime values and a list of extracted values.
@@ -1119,8 +1117,6 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
end_timestamp = DatabaseTimestamp.from_datetime(end_datetime) if end_datetime else None
# Create two lists to hold date_time and corresponding values
if dropna is None:
dropna = True
filtered_records = []
async for record in self.db_iterate_records(start_timestamp, end_timestamp):
if (
@@ -1155,48 +1151,51 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
async with self._record_lock:
await self._key_from_lists(key, dates, values)
async def key_to_series(
async def key_to_raw_series(
self,
key: str,
start_datetime: Optional[DateTime] = None,
end_datetime: Optional[DateTime] = None,
dropna: Optional[bool] = None,
dropna: bool = True,
) -> pd.Series:
"""Extract a series indexed by the date_time field from data records within an optional date range.
"""Return the raw time series stored for a key.
Retrieves the timestamps and values exactly as stored by the underlying data provider.
The returned index therefore represents the original timestamps of the stored records.
Args:
key (str): The field name in the DataRecord from which to extract values.
start_datetime (datetime, optional): The start date for filtering the records (inclusive).
end_datetime (datetime, optional): The end date for filtering the records (exclusive).
dropna: (bool, optional): Whether to drop NAN/ None values before processing. Defaults to True.
key: Field name to extract from the stored records.
start_datetime: Inclusive lower bound for timestamps.
end_datetime: Exclusive upper bound for timestamps.
dropna: Whether to discard records whose value is None or NaN.
Returns:
pd.Series: A Pandas Series with the index as the date_time of each record
and the values extracted from the specified key.
A pandas Series indexed by the original timestamps.
Raises:
KeyError: If the specified key is not found in any of the DataRecords.
KeyError: If the key does not exist.
"""
# Normalize datetime arguments
start_datetime = to_datetime(start_datetime, to_maxtime=False) if start_datetime else None
end_datetime = to_datetime(end_datetime, to_maxtime=False) if end_datetime else None
dates, values = await self.key_to_lists(
key=key, start_datetime=start_datetime, end_datetime=end_datetime, dropna=dropna
)
series = pd.Series(data=values, index=pd.DatetimeIndex(dates), name=key)
# Construct series
index = pd.to_datetime(dates, utc=True)
series = pd.Series(values, index=index, name=key)
# Check for correct series
if not isinstance(series.index, pd.DatetimeIndex):
raise TypeError(f"Expected pd.DatetimeIndex, but got {type(series.index).__name__}.")
if series.index.tz is None:
raise TypeError("Expected timezone-aware DatetimeIndex.")
return series
async def key_from_series(self, key: str, series: pd.Series) -> None:
"""Update the DataSequence from a Pandas Series.
The series index should represent the date_time of each DataRecord, and the series values
should represent the corresponding data values for the specified key.
Args:
series (pd.Series): A Pandas Series containing data to update the DataSequence.
key (str): The field name in the DataRecord that corresponds to the values in the Series.
"""
async with self._record_lock:
await self._key_from_series(key, series)
async def key_to_array(
async def key_to_series(
self,
key: str,
start_datetime: Optional[DateTime] = None,
@@ -1204,11 +1203,25 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: Optional[bool] = True,
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> NDArray[Shape["*"], Any]:
"""Extract an array indexed by fixed time intervals from data records within an optional date range.
) -> pd.Series:
"""Return a pandas Series for a data key.
The method performs all preprocessing required for resampling:
- validates the input arguments,
- extends the query window when context resampling is requested,
- loads the raw database values,
- inserts boundary values when necessary,
- determines the resampling origin,
- performs aggregation,
- fills missing values,
- truncates the result back to the requested interval.
The DatetimeIndex represents the actual bucket timestamps and should therefore be
considered the authoritative timestamp information for the resampled data.
Args:
key (str): The field name in the DataRecord from which to extract values.
@@ -1232,7 +1245,7 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool, optional): Whether to drop NAN/ None values before processing.
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]): resampling boundary
"strict" → only values inside [start, end)
@@ -1255,14 +1268,12 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
more important than clock-round boundaries.
Returns:
np.ndarray: A NumPy Array of the values at the chosen frequency extracted from the
specified key.
A resampled pandas Series whose index contains the correct timestamps
for every returned value.
Raises:
KeyError: If the specified key is not found in any of the DataRecords.
"""
self._validate_key(key)
# Validate fill method
if fill_method not in ("ffill", "bfill", "linear", "time", "none", None):
raise ValueError(f"Unsupported fill method: {fill_method}")
@@ -1307,36 +1318,40 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
else:
query_end = DatabaseTimestamp.to_datetime(query_end_timestamp).add(seconds=1)
# Load raw lists (already sorted & filtered)
dates, values = await self.key_to_lists(
# Load raw series
series = await self.key_to_raw_series(
key=key, start_datetime=query_start, end_datetime=query_end, dropna=dropna
)
values_len = len(values)
# Bring lists into shape
if values_len < 1:
# No values, assume at least one value set to None
if query_start is not None:
dates.append(query_start - interval)
else:
dates.append(to_datetime(to_maxtime=False))
values.append(None)
# Ensure we have at least one value
if series.empty:
dummy_time = (
query_start - interval if query_start is not None else to_datetime(to_maxtime=False)
)
series = pd.Series(
[None],
index=pd.DatetimeIndex([dummy_time], tz="UTC"),
name=key,
)
if query_start is not None:
start_index = 0
while start_index < values_len:
if compare_datetimes(dates[start_index], query_start).ge:
break
start_index += 1
idx = series.index
# Number of samples before query_start
start_index = idx.searchsorted(pd.Timestamp(query_start), side="left")
if start_index == 0:
# No value before start
# Add dummy value
dates.insert(0, query_start - interval)
values.insert(0, values[0])
# No value before query_start -> prepend dummy
prepend = pd.Series(
[series.iloc[0]],
index=pd.DatetimeIndex([query_start - interval], tz="UTC"),
name=key,
)
series = pd.concat([prepend, series])
elif start_index > 1:
# Truncate all values before latest value before query_start
dates = dates[start_index - 1 :]
values = values[start_index - 1 :]
# Keep only the last sample before query_start
series = series.iloc[start_index - 1 :]
# Determine resample origin
if align_to_interval:
@@ -1360,23 +1375,17 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
resample_origin = "start_day"
if query_end is not None:
if compare_datetimes(dates[-1], query_end).lt:
# Add dummy value at query_end
dates.append(query_end)
values.append(values[-1])
# Construct series
index = pd.to_datetime(dates, utc=True)
series = pd.Series(values, index=index, name=key)
if series.index.inferred_type != "datetime64":
raise TypeError(
f"Expected DatetimeIndex, but got {type(series.index)} "
f"infered to {series.index.inferred_type}: {series}"
)
if compare_datetimes(to_datetime(series.index[-1]), query_end).lt:
append = pd.Series(
[series.iloc[-1]],
index=pd.DatetimeIndex([query_end], tz="UTC"),
name=key,
)
series = pd.concat([series, append])
# Check for numeric values
numeric = pd.to_numeric(series.dropna(), errors="coerce")
is_numeric = numeric.notna().all()
numeric_series = pd.to_numeric(series, errors="coerce") # ensures float64, not object dtype
is_numeric = numeric_series.dropna().notna().all()
# Determine default fill method depending on dtype
if fill_method is None:
@@ -1388,10 +1397,7 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
# Perform the resampling
if is_numeric:
# Step 1: aggregate — collapses sub-interval data (e.g. 4x 15min → 1h mean).
# Produces NaN for buckets where no data existed at all.
numeric_series = pd.to_numeric(
series, errors="coerce"
) # ← ensures float64, not object dtype
# numeric_series has NaN for buckets where no data existed at all.
if resample_method == "first":
resampled = numeric_series.resample(
@@ -1433,22 +1439,114 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
elif fill_method == "bfill":
resampled = resampled.bfill()
if start_datetime is not None and len(resampled) > 0:
resampled = resampled.truncate(before=start_datetime)
if end_datetime is not None and len(resampled) > 0:
resampled = resampled.truncate(after=end_datetime.subtract(seconds=1))
logger.debug(
"Resampled for '{}' with length {}: {}...{}",
"Resampled series for '{}' with length {}: {}...{}",
key,
len(resampled),
resampled[:10],
resampled[-10:],
)
# Convert the resampled series to a NumPy array
if start_datetime is not None and len(resampled) > 0:
resampled = resampled.truncate(before=start_datetime)
if end_datetime is not None and len(resampled) > 0:
resampled = resampled.truncate(after=end_datetime.subtract(seconds=1))
array = resampled.values
return resampled
# Convert NaN to None if there are actually NaNs
async def key_from_series(self, key: str, series: pd.Series) -> None:
"""Update the DataSequence from a Pandas Series.
The series index should represent the date_time of each DataRecord, and the series values
should represent the corresponding data values for the specified key.
Args:
series (pd.Series): A Pandas Series containing data to update the DataSequence.
key (str): The field name in the DataRecord that corresponds to the values in the Series.
"""
async with self._record_lock:
await self._key_from_series(key, series)
async def key_to_array(
self,
key: str,
start_datetime: Optional[DateTime] = None,
end_datetime: Optional[DateTime] = None,
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> NDArray[Shape["*"], Any]:
"""Extract an array indexed by fixed time intervals from data records within an optional date range.
Args:
key (str): The field name in the DataRecord from which to extract values.
start_datetime (datetime, optional): The start date for filtering the records (inclusive).
end_datetime (datetime, optional): The end date for filtering the records (exclusive).
interval (duration, optional): The fixed time interval. Defaults to 1 hour.
fill_method (str): Method to handle missing values during resampling.
- 'linear': Linearly interpolate missing values (for numeric data only).
- 'time': Interpolate missing values (for numeric data only).
- 'ffill': Forward fill missing values.
- 'bfill': Backward fill missing values.
- Defaults to 'linear' for numeric values, otherwise 'ffill'.
resample_method (str):
Method used to aggregate values within a resampling interval.
- "first": Use the first value in each interval.
- "mean": Compute the arithmetic mean of all samples in each interval.
- "interval_mean": Compute the time-weighted mean assuming each
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]): resampling boundary
"strict" → only values inside [start, end)
"context" → include one value before and after for proper resampling
align_to_interval (bool): When True, snap the resample origin to the nearest
UTC epoch-aligned boundary of ``interval`` before resampling. This ensures
that bucket timestamps always fall on wall-clock-round times regardless of
when ``start_datetime`` falls:
- 15-minute interval → buckets on :00, :15, :30, :45
- 1-hour interval → buckets on the hour
When False (default), the origin is ``query_start`` (or ``"start_day"`` when
no start is given), preserving the existing behaviour where buckets are
aligned to the query window rather than the clock.
Set to True when storing compacted records back to the database so that the
resulting timestamps are predictable and human-readable. Leave False for
forecast or reporting queries where alignment to the exact query window is
more important than clock-round boundaries.
Returns:
np.ndarray: A NumPy Array of the values at the chosen frequency extracted from the
specified key.
Raises:
KeyError: If the specified key is not found in any of the DataRecords.
"""
series = await self.key_to_series(
key=key,
start_datetime=start_datetime,
end_datetime=end_datetime,
interval=interval,
fill_method=fill_method,
resample_method=resample_method,
dropna=dropna,
boundary=boundary,
align_to_interval=align_to_interval,
)
array = series.to_numpy()
# Convert NaN to None if necessary
if (
isinstance(array, np.ndarray)
and np.issubdtype(array.dtype.type, np.floating)
@@ -1458,7 +1556,11 @@ class DataSequence(DataABC, DatabaseRecordProtocolMixin[DataRecord]):
array[pd.isna(array)] = None
logger.debug(
"Array for '{}' with length {}: {}...{}", key, len(array), array[:10], array[-10:]
"Array for '{}' with length {}: {}...{}",
key,
len(array),
array[:10],
array[-10:],
)
return array
@@ -2380,12 +2482,12 @@ class DataContainer(SingletonMixin, DataABC):
# Log as warning and continue so the remaining providers still run.
logger.warning(error)
async def key_to_series(
async def key_to_raw_series(
self,
key: str,
start_datetime: Optional[DateTime] = None,
end_datetime: Optional[DateTime] = None,
dropna: Optional[bool] = None,
dropna: bool = True,
) -> pd.Series:
"""Extract a series indexed by the date_time field from data records within an optional date range.
@@ -2395,7 +2497,93 @@ class DataContainer(SingletonMixin, DataABC):
key (str): The field name in the DataRecord from which to extract values.
start_datetime (datetime, optional): The start date for filtering the records (inclusive).
end_datetime (datetime, optional): The end date for filtering the records (exclusive).
dropna: (bool, optional): Whether to drop NAN/ None values before processing. Defaults to True.
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
Returns:
pd.Series: A Pandas Series with the index as the date_time of each record
and the values extracted from the specified key.
Raises:
KeyError: If the specified key is not found in any of the DataRecords.
"""
series = None
for provider in self.enabled_providers:
try:
series = await provider.key_to_raw_series(
key=key,
start_datetime=start_datetime,
end_datetime=end_datetime,
dropna=dropna,
)
break
except KeyError:
continue
if series is None:
raise KeyError(f"No data found for key '{key}'.")
return series
async def key_to_series(
self,
key: str,
start_datetime: Optional[DateTime] = None,
end_datetime: Optional[DateTime] = None,
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> pd.Series:
"""Extract a series indexed by the date_time field from data records within an optional date range.
Iterates through providers to find and return the first available series for the specified key.
Args:
key (str): The field name in the DataRecord from which to extract values.
start_datetime (datetime, optional): The start date for filtering the records (inclusive).
end_datetime (datetime, optional): The end date for filtering the records (exclusive).
interval (duration, optional): The fixed time interval. Defaults to 1 hour.
fill_method (str): Method to handle missing values during resampling.
- 'linear': Linearly interpolate missing values (for numeric data only).
- 'time': Interpolate missing values (for numeric data only).
- 'ffill': Forward fill missing values.
- 'bfill': Backward fill missing values.
- Defaults to 'linear' for numeric values, otherwise 'ffill'.
resample_method (str):
Method used to aggregate values within a resampling interval.
- "first": Use the first value in each interval.
- "mean": Compute the arithmetic mean of all samples in each interval.
- "interval_mean": Compute the time-weighted mean assuming each
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]):
"strict" → only values inside [start, end)
"context" → include one value before and after for proper resampling
align_to_interval (bool): When True, snap the resample origin to the nearest
UTC epoch-aligned boundary of ``interval`` before resampling. This ensures
that bucket timestamps always fall on wall-clock-round times regardless of
when ``start_datetime`` falls:
- 15-minute interval → buckets on :00, :15, :30, :45
- 1-hour interval → buckets on the hour
When False (default), the origin is ``query_start`` (or ``"start_day"`` when
no start is given), preserving the existing behaviour where buckets are
aligned to the query window rather than the clock.
Set to True when storing compacted records back to the database so that the
resulting timestamps are predictable and human-readable. Leave False for
forecast or reporting queries where alignment to the exact query window is
more important than clock-round boundaries.
Returns:
pd.Series: A Pandas Series with the index as the date_time of each record
@@ -2408,10 +2596,15 @@ class DataContainer(SingletonMixin, DataABC):
for provider in self.enabled_providers:
try:
series = await provider.key_to_series(
key,
key=key,
start_datetime=start_datetime,
end_datetime=end_datetime,
interval=interval,
fill_method=fill_method,
resample_method=resample_method,
dropna=dropna,
boundary=boundary,
align_to_interval=align_to_interval,
)
break
except KeyError:
@@ -2430,7 +2623,7 @@ class DataContainer(SingletonMixin, DataABC):
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: Optional[bool] = True,
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> NDArray[Shape["*"], Any]:
@@ -2460,7 +2653,7 @@ class DataContainer(SingletonMixin, DataABC):
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool, optional): Whether to drop NAN/ None values before processing.
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]):
"strict" → only values inside [start, end)
@@ -2495,7 +2688,7 @@ class DataContainer(SingletonMixin, DataABC):
for provider in self.enabled_providers:
try:
array = await provider.key_to_array(
key,
key=key,
start_datetime=start_datetime,
end_datetime=end_datetime,
interval=interval,
@@ -2522,13 +2715,13 @@ class DataContainer(SingletonMixin, DataABC):
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: Optional[bool] = True,
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> pd.DataFrame:
"""Retrieve a dataframe indexed by fixed time intervals for specified keys from the data in each DataProvider.
Generates a pandas DataFrame using the NumPy arrays for each specified key, ensuring a common time index.
Generates a pandas DataFrame of data for each specified key, ensuring a common time index.
Args:
keys (list[str]): The field names in the DataRecords from which to extract values.
@@ -2552,7 +2745,7 @@ class DataContainer(SingletonMixin, DataABC):
value remains valid until the next timestamp (piecewise-constant
signal).
dropna: (bool, optional): Whether to drop NAN/ None values before processing.
dropna: (bool): Whether to drop NAN/ None values before processing.
Defaults to True.
boundary (Literal["strict", "context"]):
"strict" → only values inside [start, end)
@@ -2575,17 +2768,23 @@ class DataContainer(SingletonMixin, DataABC):
more important than clock-round boundaries.
Returns:
pd.DataFrame: A DataFrame where each column represents a key's array with a common time index.
pd.DataFrame: A DataFrame whose columns contain the (resampled) values
for each requested key and whose index is the common (resampled) DatetimeIndex.
Raises:
KeyError: If no valid data is found for any of the requested keys.
ValueError: If any retrieved array has a different time index than the first one.
ValueError: If any retrieved series has a different DatetimeIndex than the first one.
"""
if not keys:
raise ValueError("keys must not be empty.")
# Ensure datetime objects are normalized
start_datetime = to_datetime(start_datetime, to_maxtime=False) if start_datetime else None
end_datetime = to_datetime(end_datetime, to_maxtime=False) if end_datetime else None
if interval is None:
interval = to_duration("1 hour")
if start_datetime is None:
# Take earliest datetime of all providers that are enabled
for provider in self.enabled_providers:
@@ -2601,7 +2800,6 @@ class DataContainer(SingletonMixin, DataABC):
if end_datetime is None:
end_datetime = max_dt
elif max_dt and compare_datetimes(max_dt, end_datetime).gt:
min_dt = await provider.min_datetime()
end_datetime = max_dt
if end_datetime:
end_datetime = end_datetime.add(seconds=1)
@@ -2611,17 +2809,13 @@ class DataContainer(SingletonMixin, DataABC):
raise ValueError(
f"Can not determine datetime range. Got '{start_datetime}'..'{end_datetime}'."
)
reference_index = pd.date_range(
start=start_datetime,
end=end_datetime,
freq=interval,
inclusive="left",
)
data = {}
reference_index: Optional[pd.DatetimeIndex] = None
data: dict[str, pd.Series] = {}
for key in keys:
try:
array = await self.key_to_array(
series = await self.key_to_series(
key=key,
start_datetime=start_datetime,
end_datetime=end_datetime,
@@ -2632,20 +2826,24 @@ class DataContainer(SingletonMixin, DataABC):
boundary=boundary,
align_to_interval=align_to_interval,
)
if len(array) != len(reference_index):
raise ValueError(
f"Array length mismatch for key '{key}' (expected {len(reference_index)}, got {len(array)})"
if not isinstance(series.index, pd.DatetimeIndex): # make mypy happy
raise TypeError(
f"Expected DatetimeIndex for key '{key}', got {type(series.index).__name__}"
)
data[key] = array
if reference_index is None:
reference_index = series.index
elif not series.index.equals(reference_index):
raise ValueError(f"Time index mismatch for key '{key}'.")
data[key] = series
except KeyError as e:
raise KeyError(f"Failed to retrieve data for key '{key}': {e}")
raise KeyError(f"Failed to retrieve data for key '{key}': {e}") from e
if not data:
raise KeyError(f"No valid data found for the requested keys {keys}.")
return pd.DataFrame(data, index=reference_index)
return pd.DataFrame(data) # Pandas aligns the series in data by their index
async def key_delete_by_datetime(
self,
+1 -1
View File
@@ -549,7 +549,7 @@ class DatabaseRecordProtocolMixin(
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: Optional[bool] = True,
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> NDArray[Shape["*"], Any]: ...
+10 -2
View File
@@ -15,10 +15,18 @@ from akkudoktoreos.core.logabc import LOGGING_LEVELS
class LoggingCommonSettings(SettingsBaseModel):
"""Logging Configuration."""
api_level: Optional[str] = Field(
default=None,
json_schema_extra={
"description": "Logging level for API response.",
"examples": LOGGING_LEVELS,
},
)
console_level: Optional[str] = Field(
default=None,
json_schema_extra={
"description": "Logging level when logging to console.",
"description": "Logging level for logging to console.",
"examples": LOGGING_LEVELS,
},
)
@@ -26,7 +34,7 @@ class LoggingCommonSettings(SettingsBaseModel):
file_level: Optional[str] = Field(
default=None,
json_schema_extra={
"description": "Logging level when logging to file.",
"description": "Logging level for logging to file.",
"examples": LOGGING_LEVELS,
},
)
@@ -1221,39 +1221,20 @@ class GeneticOptimization(OptimizationBase):
else:
discharge = discharge.tolist()
# Visualize the results in PDF
try:
from akkudoktoreos.utils.visualize import prepare_visualize
visualize = {
"ac_charge": ac_charge_hours,
"dc_charge": dc_charge_hours,
"discharge_allowed": discharge,
"ev_charge_hours_float": ev_charge_hours_float,
"result": GeneticSimulationResult(**simulation_result).model_dump(),
"ev_obj": self.simulation.ev.to_dict() if self.simulation.ev else None,
"start_solution": start_solution,
"washingstart": washingstart_int,
"extra_data": extra_data,
"fitness_history": self.fitness_history,
"fixed_seed": self.fix_seed,
}
prepare_visualize(parameters, visualize, start_hour=start_hour)
except Exception as ex:
error_msg = f"Visualization failed: {ex}"
logger.error(error_msg)
return GeneticSolution(
**{
"parameters": parameters,
"ac_charge": ac_charge_hours,
"dc_charge": dc_charge_hours,
"discharge_allowed": discharge,
"ev_charge_hours_float": ev_charge_hours_float,
"result": GeneticSimulationResult(**simulation_result),
"ev_obj": self.simulation.ev,
"start_hour": start_hour,
"start_solution": start_solution,
"washingstart": washingstart_int,
"extra_data": extra_data,
"fitness_history": self.fitness_history,
"fixed_seed": self.fix_seed,
}
)
@@ -1,6 +1,6 @@
"""Genetic algorithm optimisation solution."""
from typing import Any, Optional
from typing import Any, Optional, Union
import numpy as np
import pandas as pd
@@ -27,6 +27,9 @@ from akkudoktoreos.devices.devicesabc import (
)
from akkudoktoreos.devices.genetic.battery import Battery
from akkudoktoreos.optimization.genetic.geneticdevices import GeneticParametersBaseModel
from akkudoktoreos.optimization.genetic.geneticparams import (
GeneticOptimizationParameters,
)
from akkudoktoreos.optimization.optimization import OptimizationSolution
from akkudoktoreos.utils.datetimeutil import to_datetime, to_duration
from akkudoktoreos.utils.utils import NumpyEncoder
@@ -247,6 +250,9 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
model_config = ConfigDict(populate_by_name=True, extra="ignore")
parameters: GeneticOptimizationParameters = Field(
json_schema_extra={"description": "Optimization parameters used to generate solution."}
)
ac_charge: list[float] = Field(
json_schema_extra={
"description": "Array with AC charging values as relative power (0.0-1.0), other values set to 0."
@@ -273,6 +279,10 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
validation_alias=AliasChoices("ev_obj", "eauto_obj"),
json_schema_extra={"description": "Electric vehicle state after optimization."},
)
start_hour: int = Field(
default=0,
json_schema_extra={"description": "Start hour."},
)
start_solution: Optional[list[float]] = Field(
default=None,
json_schema_extra={
@@ -285,6 +295,28 @@ class GeneticSolution(ConfigMixin, GeneticParametersBaseModel):
"description": "Can be `null` or contain an object representing the start of washing (if applicable)."
},
)
extra_data: Optional[dict[str, Union[list[int], list[float]]]] = Field(
default=None,
json_schema_extra={
"description": ("Dictionary of balance: TBD, losses: TBD, constraints: TBD.")
},
)
fitness_history: Optional[dict[str, Union[list[int], list[float]]]] = Field(
default=None,
json_schema_extra={
"description": (
"Dictionary of "
"gen: Generation numbers (X-axis), "
"avg: Average fitness for each generation (Y-axis), "
"max: Maximum fitness for each generation (Y-axis), "
"min: Minimum fitness for each generation (Y-axis)."
)
},
)
fixed_seed: Optional[int] = Field(
default=None,
json_schema_extra={"description": "Fixed seed."},
)
# Computed fields for backward compatibility (deprecated German names)
@computed_field(json_schema_extra={"deprecated": True})
@@ -1,7 +1,7 @@
import json
import os
import textwrap
from collections.abc import Sequence
from io import BytesIO
from typing import Callable, Optional, Union
import matplotlib
@@ -12,7 +12,7 @@ import pendulum
from matplotlib.backends.backend_pdf import PdfPages
from akkudoktoreos.core.coreabc import ConfigMixin, get_ems
from akkudoktoreos.optimization.genetic.genetic import GeneticOptimizationParameters
from akkudoktoreos.optimization.genetic.geneticsolution import GeneticSolution
from akkudoktoreos.utils.datetimeutil import DateTime, to_datetime
matplotlib.use(
@@ -23,39 +23,29 @@ matplotlib.use(
debug_visualize: bool = False
class VisualizationReport(ConfigMixin):
class GeneticVisualizationReport(ConfigMixin):
def __init__(
self,
filename: str = "visualization_results.pdf",
version: str = "0.0.1",
create_img: bool = True,
) -> None:
# Initialize the report with a given filename and empty groups
self.filename = filename
# Initialize the report with empty groups
self.groups: list[list[Callable[[], None]]] = [] # Store groups of charts
self.current_group: list[
Callable[[], None]
] = [] # Store current group of charts being created
self.pdf_pages = PdfPages(filename, metadata={}) # Initialize PdfPages without metadata
# file like buffer to create the PDF
self._buffer = BytesIO()
self.pdf_pages: PdfPages | None = None
self.version = version # overwrite version as test for constant output of pdf for test
self.current_time = to_datetime(
as_string="YYYY-MM-DD HH:mm:ss", in_timezone=self.config.general.timezone
)
self.create_img = create_img
def add_chart_to_group(self, chart_func: Callable[[], None], title: str | None) -> None:
"""Add a chart function to the current group and save it as a PNG and SVG."""
self.current_group.append(chart_func)
if self.create_img and title:
server_output_dir = self.config.cache.path()
server_output_dir.mkdir(parents=True, exist_ok=True)
fig, ax = plt.subplots()
chart_func()
plt.tight_layout() # Adjust the layout to ensure titles are not cut off
sanitized_title = "".join(c if c.isalnum() else "_" for c in title)
chart_filename_base = os.path.join(server_output_dir, f"chart_{sanitized_title}")
fig.savefig(f"{chart_filename_base}.svg")
plt.close(fig)
def finalize_group(self) -> None:
"""Finalize the current group and prepare for a new group."""
@@ -66,22 +56,15 @@ class VisualizationReport(ConfigMixin):
self.current_group = [] # Reset current group for new charts
def _initialize_pdf(self) -> None:
"""Create the output directory if it doesn't exist and initialize the PDF."""
output_dir = self.config.general.data_output_path
# If self.filename is already a valid path, use it; otherwise, combine it with output_dir
if os.path.isabs(self.filename):
output_file = self.filename
else:
output_dir.mkdir(parents=True, exist_ok=True)
output_file = os.path.join(output_dir, self.filename)
self.pdf_pages = PdfPages(
output_file, metadata={}
) # Re-initialize PdfPages without metadata
"""Initialize the PDF."""
self._buffer = BytesIO()
self.pdf_pages = PdfPages(self._buffer, metadata={}) # Initialize PdfPages without metadata
def _save_group_to_pdf(self, group: list[Callable[[], None]]) -> None:
"""Save a group of charts to the PDF."""
if self.pdf_pages is None: # make mypy happy
raise RuntimeError("Report not initialized")
fig_count = len(group) # Number of charts in the group
if fig_count == 0:
@@ -305,7 +288,7 @@ class VisualizationReport(ConfigMixin):
def create_bar_chart(
self,
labels: list[str],
values_list: Sequence[Union[int, float, list[Union[int, float]]]],
values_list: Sequence[Sequence[int | float]],
title: str,
ylabel: str,
xlabels: Optional[list[str]] = None,
@@ -371,6 +354,9 @@ class VisualizationReport(ConfigMixin):
"""Add a page with text content to the PDF."""
def chart() -> None:
if self.pdf_pages is None: # make mypy happy
raise RuntimeError("Report not initialized")
fig = plt.figure(figsize=(8.5, 11)) # Create a standard page size
plt.axis("off") # Turn off axes for a clean page
wrapped_text = textwrap.fill(text, width=80) # Wrap text to fit the page width
@@ -398,6 +384,9 @@ class VisualizationReport(ConfigMixin):
"""
def chart() -> None:
if self.pdf_pages is None: # make mypy happy
raise RuntimeError("Report not initialized")
# Convert JSON object to a formatted string
json_str = json.dumps(json_obj, indent=4)
@@ -424,31 +413,37 @@ class VisualizationReport(ConfigMixin):
self.add_chart_to_group(chart, title) # Treat the JSON page as a "chart" in the group
def generate_pdf(self) -> None:
"""Generate the PDF report with all the added chart groups."""
def generate_pdf(self) -> bytes:
"""Generate the PDF report with all the added chart groups.
Returns:
PDF report as bytes object
"""
self._initialize_pdf() # Initialize the PDF
buffer = BytesIO()
self.pdf_pages = PdfPages(buffer, metadata={})
for group in self.groups:
self._save_group_to_pdf(group) # Save each group to the PDF
self._save_group_to_pdf(group)
self.pdf_pages.close() # Close the PDF to finalize the report
self.pdf_pages.close()
return buffer.getvalue()
def prepare_visualize(
parameters: GeneticOptimizationParameters,
results: dict,
filename: str = "visualization_results.pdf",
start_hour: int = 0,
) -> None:
def genetic_prepare_visualize(
solution: GeneticSolution,
) -> bytes:
global debug_visualize
report = VisualizationReport(filename)
report = GeneticVisualizationReport()
next_full_hour_date = get_ems().start_datetime
start_hour = solution.start_hour
# Group 1:
report.create_line_chart_date(
next_full_hour_date,
[
parameters.ems.total_load[start_hour:],
solution.parameters.ems.total_load[start_hour:],
],
title="Load Profile",
# xlabel="Hours", # not enough space
@@ -458,7 +453,7 @@ def prepare_visualize(
report.create_line_chart_date(
next_full_hour_date,
[
parameters.ems.pv_forecast_wh[start_hour:],
solution.parameters.ems.pv_forecast_wh[start_hour:],
],
title="PV Forecast",
# xlabel="Hours", # not enough space
@@ -469,10 +464,10 @@ def prepare_visualize(
next_full_hour_date,
[
np.full(
len(parameters.ems.total_load) - start_hour,
parameters.ems.feed_in_tariff_per_wh[start_hour:]
if isinstance(parameters.ems.feed_in_tariff_per_wh, list)
else parameters.ems.feed_in_tariff_per_wh,
len(solution.parameters.ems.total_load) - start_hour,
solution.parameters.ems.feed_in_tariff_per_wh[start_hour:]
if isinstance(solution.parameters.ems.feed_in_tariff_per_wh, list)
else solution.parameters.ems.feed_in_tariff_per_wh,
)
],
title="Remuneration",
@@ -480,11 +475,11 @@ def prepare_visualize(
ylabel="amount/Wh",
x2label=None, # not enough space
)
if parameters.temperature_forecast:
if solution.parameters.temperature_forecast:
report.create_line_chart_date(
next_full_hour_date,
[
parameters.temperature_forecast[start_hour:],
solution.parameters.temperature_forecast[start_hour:],
],
title="Temperature Forecast",
# xlabel="Hours", # not enough space
@@ -495,13 +490,13 @@ def prepare_visualize(
# Group 2:
report.create_line_chart_date(
next_full_hour_date, # start_date
[
results["result"]["load_wh_per_hour"],
results["result"]["home_appliance_wh_per_hour"],
results["result"]["grid_feed_in_wh_per_hour"],
results["result"]["grid_consumption_wh_per_hour"],
results["result"]["losses_per_hour"],
start_date=next_full_hour_date, # start_date
y_list=[
solution.result.load_wh_per_hour,
solution.result.home_appliance_wh_per_hour,
solution.result.grid_feed_in_wh_per_hour,
solution.result.grid_consumption_wh_per_hour,
solution.result.losses_per_hour,
],
title="Energy Flow per Hour",
# xlabel="Date", # not enough space
@@ -520,8 +515,8 @@ def prepare_visualize(
# Group 3:
report.create_line_chart_date(
next_full_hour_date, # start_date
[results["result"]["battery_soc_per_hour"], results["result"]["ev_soc_per_hour"]],
start_date=next_full_hour_date,
y_list=[solution.result.battery_soc_per_hour, solution.result.ev_soc_per_hour],
title="Battery SOC",
# xlabel="Date", # not enough space
ylabel="%",
@@ -532,8 +527,8 @@ def prepare_visualize(
markers=["o", "x"],
)
report.create_line_chart_date(
next_full_hour_date, # start_date
[parameters.ems.electricity_price_per_wh[start_hour:]],
start_date=next_full_hour_date, # start_date
y_list=[solution.parameters.ems.electricity_price_per_wh[start_hour:]],
# title="Electricity Price", # not enough space
# xlabel="Date", # not enough space
ylabel="Electricity Price (amount/Wh)",
@@ -550,11 +545,11 @@ def prepare_visualize(
labels = labels[start_hour:] + labels
report.create_bar_chart(
labels,
[
results["ac_charge"][start_hour:],
results["dc_charge"][start_hour:],
results["discharge_allowed"][start_hour:],
labels=labels,
values_list=[
solution.ac_charge[start_hour:],
solution.dc_charge[start_hour:],
solution.discharge_allowed[start_hour:],
],
title="AC/DC Charging and Discharge Overview",
ylabel="Relative Power (0-1) / Discharge (0 or 1)",
@@ -570,8 +565,8 @@ def prepare_visualize(
report.create_line_chart_date(
next_full_hour_date, # start_date
[
results["result"]["costs_per_hour"],
results["result"]["revenue_per_hour"],
solution.result.costs_per_hour,
solution.result.revenue_per_hour,
],
title="Financial Balance per Hour",
# xlabel="Date", # not enough space
@@ -579,21 +574,22 @@ def prepare_visualize(
labels=["Costs", "Revenue"],
)
extra_data = results["extra_data"]
report.create_scatter_plot(
extra_data["losses"],
extra_data["balance"],
title="Scatter Plot",
xlabel="losses",
ylabel="balance",
c=extra_data["constraints"],
)
extra_data = solution.extra_data
if extra_data:
report.create_scatter_plot(
x=np.array(extra_data["losses"]),
y=np.array(extra_data["balance"]),
title="Scatter Plot",
xlabel="losses",
ylabel="balance",
c=np.array(extra_data["constraints"]),
)
values_list = [
[
results["result"]["total_costs"],
results["result"]["total_revenue"],
results["result"]["total_balance"],
solution.result.total_costs,
solution.result.total_revenue,
solution.result.total_balance,
]
]
labels = ["Total Costs [amount]", "Total Revenue [amount]", "Total Balance [amount]"]
@@ -609,69 +605,77 @@ def prepare_visualize(
report.finalize_group()
# Group 1: Scatter plot of losses vs balance with color-coded constraints
f1 = np.array(extra_data["losses"]) # Losses
f2 = np.array(extra_data["balance"]) # Balance
n1 = np.array(extra_data["constraints"]) # Constraints
if extra_data:
f1 = np.array(extra_data["losses"]) # Losses
f2 = np.array(extra_data["balance"]) # Balance
n1 = np.array(extra_data["constraints"]) # Constraints
# Filter data where 'constraints' < 0.01
filtered_indices = n1 < 0.01
filtered_losses = f1[filtered_indices]
filtered_balance = f2[filtered_indices]
# Filter data where 'constraints' < 0.01
filtered_indices = n1 < 0.01
filtered_losses = f1[filtered_indices]
filtered_balance = f2[filtered_indices]
# Group 2: Violin plot for filtered losses
if filtered_losses.size > 0:
report.create_violin_plot(
data_list=[filtered_losses], # Data for filtered losses
labels=["Filtered Losses"], # Label for the violin plot
title="Violin Plot for Filtered Losses (Constraint < 0.01)",
xlabel="Losses",
ylabel="Values",
)
else:
print("No data available for filtered losses violin plot (Constraint < 0.01)")
# Group 2: Violin plot for filtered losses
if filtered_losses.size > 0:
report.create_violin_plot(
data_list=[filtered_losses], # Data for filtered losses
labels=["Filtered Losses"], # Label for the violin plot
title="Violin Plot for Filtered Losses (Constraint < 0.01)",
xlabel="Losses",
ylabel="Values",
)
else:
print("No data available for filtered losses violin plot (Constraint < 0.01)")
# Group 3: Violin plot for filtered balance
if filtered_balance.size > 0:
report.create_violin_plot(
data_list=[filtered_balance], # Data for filtered balance
labels=["Filtered Balance"], # Label for the violin plot
title="Violin Plot for Filtered Balance (Constraint < 0.01)",
xlabel="Balance",
ylabel="Values",
)
else:
print("No data available for filtered balance violin plot (Constraint < 0.01)")
if extra_data:
if filtered_balance.size > 0:
report.create_violin_plot(
data_list=[filtered_balance], # Data for filtered balance
labels=["Filtered Balance"], # Label for the violin plot
title="Violin Plot for Filtered Balance (Constraint < 0.01)",
xlabel="Balance",
ylabel="Values",
)
else:
print("No data available for filtered balance violin plot (Constraint < 0.01)")
if filtered_balance.size > 0 or filtered_losses.size > 0:
report.finalize_group()
if solution.fitness_history:
if debug_visualize or solution.fixed_seed:
report.create_line_chart(
start_hour=0,
y_list=[
np.array(solution.fitness_history["avg"]),
np.array(solution.fitness_history["max"]),
np.array(solution.fitness_history["min"]),
],
title=f"DEBUG: Generation Fitness for seed {solution.fixed_seed}",
xlabel="Generation",
ylabel="Fitness",
labels=[
"avg",
"max",
"min",
],
markers=[".", ".", "."],
)
report.finalize_group()
if filtered_balance.size > 0 or filtered_losses.size > 0:
report.finalize_group()
if debug_visualize or results["fixed_seed"]:
report.create_line_chart(
0,
[
results["fitness_history"]["avg"],
results["fitness_history"]["max"],
results["fitness_history"]["min"],
],
title=f"DEBUG: Generation Fitness for seed {results['fixed_seed']}",
xlabel="Generation",
ylabel="Fitness",
labels=[
"avg",
"max",
"min",
],
markers=[".", ".", "."],
)
report.finalize_group()
# Generate the PDF report
report.generate_pdf()
pdf = report.generate_pdf()
# Return pdf (a bytes object)
return pdf
def generate_example_report(filename: str = "example_report.pdf") -> None:
def genetic_generate_example_report(filename: str = "example_report.pdf") -> None:
"""Generate example visualization report."""
global debug_visualize
report = VisualizationReport(filename, "test")
report = GeneticVisualizationReport("test")
x_hours = 0 # Define x-axis start values (e.g., hours)
# Group 1: Adding charts to be displayed on the same page
@@ -785,9 +789,13 @@ def generate_example_report(filename: str = "example_report.pdf") -> None:
ylabel="test",
)
report.finalize_group()
# Generate the PDF report
report.generate_pdf()
# Generate the PDF report (a bytes object)
pdf = report.generate_pdf()
# write to file
with open(filename, "wb") as f:
f.write(pdf)
if __name__ == "__main__":
generate_example_report()
genetic_generate_example_report()
@@ -1067,7 +1067,7 @@ class Genetic0Optimization(OptimizationBase):
# Start hour has to be in sync with energy management
if start_hour != self.ems.start_datetime.hour:
raise ValueError(
f"Start hour not synced. EMS {self.ems.start_datetime.hour} vs. GENETIC {start_hour}."
f"Start hour not synced. EMS {self.ems.start_datetime.hour} vs. GENETIC0 {start_hour}."
)
# Set the number of generations
@@ -1224,39 +1224,20 @@ class Genetic0Optimization(OptimizationBase):
else:
discharge = discharge.tolist()
# Visualize the results in PDF
try:
from akkudoktoreos.utils.visualize import prepare_visualize
visualize = {
"ac_charge": ac_charge_hours,
"dc_charge": dc_charge_hours,
"discharge_allowed": discharge,
"ev_charge_hours_float": ev_charge_hours_float,
"result": Genetic0SimulationResult(**simulation_result).model_dump(),
"ev_obj": self.simulation.ev.to_dict() if self.simulation.ev else None,
"start_solution": start_solution,
"washingstart": washingstart_int,
"extra_data": extra_data,
"fitness_history": self.fitness_history,
"fixed_seed": self.fix_seed,
}
prepare_visualize(parameters, visualize, start_hour=start_hour)
except Exception as ex:
error_msg = f"Visualization failed: {ex}"
logger.error(error_msg)
return Genetic0Solution(
**{
"parameters": parameters,
"ac_charge": ac_charge_hours,
"dc_charge": dc_charge_hours,
"discharge_allowed": discharge,
"ev_charge_hours_float": ev_charge_hours_float,
"result": Genetic0SimulationResult(**simulation_result),
"ev_obj": self.simulation.ev,
"start_hour": start_hour,
"start_solution": start_solution,
"washingstart": washingstart_int,
"extra_data": extra_data,
"fitness_history": self.fitness_history,
"fixed_seed": self.fix_seed,
}
)
@@ -1,6 +1,6 @@
"""Genetic0 algorithm optimisation solution."""
from typing import Any, Optional
from typing import Any, Optional, Union
import numpy as np
import pandas as pd
@@ -29,6 +29,9 @@ from akkudoktoreos.devices.genetic0.genetic0battery import Genetic0Battery
from akkudoktoreos.optimization.genetic0.genetic0devices import (
Genetic0ParametersBaseModel,
)
from akkudoktoreos.optimization.genetic0.genetic0params import (
Genetic0OptimizationParameters,
)
from akkudoktoreos.optimization.optimization import OptimizationSolution
from akkudoktoreos.utils.datetimeutil import to_datetime, to_duration
from akkudoktoreos.utils.utils import NumpyEncoder
@@ -244,8 +247,9 @@ class Genetic0SimulationResult(Genetic0ParametersBaseModel):
return NumpyEncoder.convert_numpy(field)[0]
class Genetic0Solution(ConfigMixin, Genetic0ParametersBaseModel):
"""**Note**: The first value of "load_wh_per_hour", "grid_feed_in_wh_per_hour", and "grid_consumption_wh_per_hour", will be set to null in the JSON output and represented as NaN or None in the corresponding classes' data returns. This approach is adopted to ensure that the current hour's processing remains unchanged."""
# Legacy GENETIC solution dataset. To keep the /optimize endpoint compatible.
class Genetic0SolutionLegacy(Genetic0ParametersBaseModel):
"""GENETIC0 solution legacy dataset."""
model_config = ConfigDict(populate_by_name=True, extra="ignore")
@@ -317,6 +321,109 @@ class Genetic0Solution(ConfigMixin, Genetic0ParametersBaseModel):
return Genetic0ElectricVehicleResult(**field.to_dict())
return field
class Genetic0Solution(ConfigMixin, Genetic0ParametersBaseModel):
"""**Note**: The first value of "load_wh_per_hour", "grid_feed_in_wh_per_hour", and "grid_consumption_wh_per_hour", will be set to null in the JSON output and represented as NaN or None in the corresponding classes' data returns. This approach is adopted to ensure that the current hour's processing remains unchanged."""
model_config = ConfigDict(populate_by_name=True, extra="ignore")
parameters: Genetic0OptimizationParameters = Field(
json_schema_extra={"description": "Optimization parameters used to generate solution."}
)
ac_charge: list[float] = Field(
json_schema_extra={
"description": "Array with AC charging values as relative power (0.0-1.0), other values set to 0."
}
)
dc_charge: list[float] = Field(
json_schema_extra={
"description": "Array with DC charging values as relative power (0-1), other values set to 0."
}
)
discharge_allowed: list[int] = Field(
json_schema_extra={
"description": "Array with discharge values (1 for discharge, 0 otherwise)."
}
)
ev_charge_hours_float: Optional[list[float]] = Field(
validation_alias=AliasChoices("ev_charge_hours_float", "eautocharge_hours_float"),
json_schema_extra={
"description": "Array with EV charging values as relative power (0.0-1.0), or `null` if no EV is optimized."
},
)
result: Genetic0SimulationResult
ev_obj: Optional[Genetic0ElectricVehicleResult] = Field(
validation_alias=AliasChoices("ev_obj", "eauto_obj"),
json_schema_extra={"description": "Electric vehicle state after optimization."},
)
start_hour: int = Field(
default=0,
json_schema_extra={"description": "Start hour."},
)
start_solution: Optional[list[float]] = Field(
default=None,
json_schema_extra={
"description": "An array of binary values (0 or 1) representing a possible starting solution for the simulation."
},
)
washingstart: Optional[int] = Field(
default=None,
json_schema_extra={
"description": "Can be `null` or contain an object representing the start of washing (if applicable)."
},
)
extra_data: Optional[dict[str, Union[list[int], list[float]]]] = Field(
default=None,
json_schema_extra={
"description": ("Dictionary of balance: TBD, losses: TBD, constraints: TBD.")
},
)
fitness_history: Optional[dict[str, Union[list[int], list[float]]]] = Field(
default=None,
json_schema_extra={
"description": (
"Dictionary of "
"gen: Generation numbers (X-axis), "
"avg: Average fitness for each generation (Y-axis), "
"max: Maximum fitness for each generation (Y-axis), "
"min: Minimum fitness for each generation (Y-axis)."
)
},
)
fixed_seed: Optional[int] = Field(
default=None,
json_schema_extra={"description": "Fixed seed."},
)
# Computed fields for backward compatibility (deprecated German names)
@computed_field(json_schema_extra={"deprecated": True})
def eautocharge_hours_float(self) -> Optional[list[float]]:
"""Deprecated: Use ev_charge_hours_float instead."""
return self.ev_charge_hours_float
@computed_field(json_schema_extra={"deprecated": True})
def eauto_obj(self) -> Optional[Genetic0ElectricVehicleResult]:
"""Deprecated: Use ev_obj instead."""
return self.ev_obj
@field_validator(
"ac_charge",
"dc_charge",
"discharge_allowed",
mode="before",
)
def convert_numpy(cls, field: Any) -> Any:
return NumpyEncoder.convert_numpy(field)[0]
@field_validator(
"ev_obj",
mode="before",
)
def convert_eauto(cls, field: Any) -> Any:
if isinstance(field, Genetic0Battery):
return Genetic0ElectricVehicleResult(**field.to_dict())
return field
def _battery_device_id(self) -> str:
"""Get battery device id."""
try:
@@ -0,0 +1,801 @@
import json
import textwrap
from collections.abc import Sequence
from io import BytesIO
from typing import Callable, Optional, Union
import matplotlib
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import numpy as np
import pendulum
from matplotlib.backends.backend_pdf import PdfPages
from akkudoktoreos.core.coreabc import ConfigMixin, get_ems
from akkudoktoreos.optimization.genetic0.genetic0solution import Genetic0Solution
from akkudoktoreos.utils.datetimeutil import DateTime, to_datetime
matplotlib.use(
"Agg"
) # non-interactive backend that can only write to files, backend needed to stay in main thread.
debug_visualize: bool = False
class Genetic0VisualizationReport(ConfigMixin):
def __init__(
self,
version: str = "0.0.1",
) -> None:
# Initialize the report with empty groups
self.groups: list[list[Callable[[], None]]] = [] # Store groups of charts
self.current_group: list[
Callable[[], None]
] = [] # Store current group of charts being created
# file like buffer to create the PDF
self._buffer = BytesIO()
self.pdf_pages: PdfPages | None = None
self.version = version # overwrite version as test for constant output of pdf for test
self.current_time = to_datetime(
as_string="YYYY-MM-DD HH:mm:ss", in_timezone=self.config.general.timezone
)
def add_chart_to_group(self, chart_func: Callable[[], None], title: str | None) -> None:
"""Add a chart function to the current group and save it as a PNG and SVG."""
self.current_group.append(chart_func)
def finalize_group(self) -> None:
"""Finalize the current group and prepare for a new group."""
if self.current_group: # Check if current group has charts
self.groups.append(self.current_group) # Add current group to groups
else:
print("Finalizing an empty group!") # Warn if group is empty
self.current_group = [] # Reset current group for new charts
def _initialize_pdf(self) -> None:
"""Initialize the PDF."""
self._buffer = BytesIO()
self.pdf_pages = PdfPages(self._buffer, metadata={}) # Initialize PdfPages without metadata
def _save_group_to_pdf(self, group: list[Callable[[], None]]) -> None:
"""Save a group of charts to the PDF."""
if self.pdf_pages is None: # make mypy happy
raise RuntimeError("Report not initialized")
fig_count = len(group) # Number of charts in the group
if fig_count == 0:
print("Attempted to save an empty group to PDF!")
return
# Check for special charts before creating layout
special_keywords = {"add_text_page", "add_json_page"}
for chart_func in group:
if any(keyword in chart_func.__qualname__ for keyword in special_keywords):
chart_func() # Special chart functions handle their own rendering
return
# Create layout only if no special charts are detected
if fig_count == 3:
fig = plt.figure(figsize=(14, 10))
ax1 = fig.add_subplot(2, 1, 1)
ax2 = fig.add_subplot(2, 2, 3)
ax3 = fig.add_subplot(2, 2, 4)
axs = [ax1, ax2, ax3]
else:
cols = 2 if fig_count > 1 else 1
rows = (fig_count + 1) // 2
fig, axs = plt.subplots(rows, cols, figsize=(14, 7 * rows))
axs = list(np.array(axs).reshape(-1))
# Add footer text with current time to each page
if self.version == "test":
current_time = "test"
else:
current_time = self.current_time
fig.text(
0.5,
0.02,
f"Generated on: {current_time} with version: {self.version}",
ha="center",
va="center",
fontsize=10,
)
# Render each chart in its corresponding axis
for idx, chart_func in enumerate(group):
plt.sca(axs[idx]) # Set current axis
chart_func() # Render the chart
# Save the figure to the PDF and clean up
for idx in range(fig_count, len(axs)):
axs[idx].set_visible(False)
self.pdf_pages.savefig(fig) # Save the figure to the PDF
plt.close(fig)
def create_line_chart_date(
self,
start_date: DateTime,
y_list: list[Union[np.ndarray, list[Optional[float]], list[float]]],
ylabel: str,
xlabel: Optional[str] = None,
title: Optional[str] = None,
labels: Optional[list[str]] = None,
markers: Optional[list[str]] = None,
line_styles: Optional[list[str]] = None,
x2label: Optional[Union[str, None]] = "Hours Since Start",
) -> None:
"""Create a line chart and add it to the current group."""
def chart() -> None:
timestamps = [
start_date.add(hours=i) for i in range(len(y_list[0]))
] # 840 timestamps at 1-hour intervals
for idx, y_data in enumerate(y_list):
label = labels[idx] if labels else None # Chart label
marker = markers[idx] if markers and idx < len(markers) else "o" # Marker style
line_style = line_styles[idx] if line_styles and idx < len(line_styles) else "-"
plt.plot(
timestamps, y_data, label=label, marker=marker, linestyle=line_style
) # Plot line
# Format the time axis
plt.gca().xaxis.set_major_formatter(
mdates.DateFormatter("%Y-%m-%d", tz=self.config.general.timezone)
) # Show date and time
plt.gca().xaxis.set_major_locator(
mdates.DayLocator(interval=1, tz=self.config.general.timezone)
) # Major ticks every day
plt.gca().xaxis.set_minor_locator(
mdates.HourLocator(interval=2, tz=self.config.general.timezone)
)
# Minor ticks every 6 hours
plt.gca().xaxis.set_minor_formatter(
mdates.DateFormatter("%H", tz=self.config.general.timezone)
)
# plt.gcf().autofmt_xdate(rotation=45, which="major")
# Auto-format the x-axis for readability
# Move major tick labels further down to avoid collision with minor tick labels
for plt_label in plt.gca().get_xticklabels(which="major"):
plt_label.set_y(-0.04)
# Add labels, title, and legend
if xlabel:
plt.xlabel(xlabel)
plt.ylabel(ylabel)
if title:
plt.title(title)
if labels:
plt.legend()
plt.grid(True)
# Add vertical line for the current date if within the axis range
current_time = pendulum.now(self.config.general.timezone)
if timestamps[0].subtract(hours=2) <= current_time <= timestamps[-1]:
plt.axvline(current_time, color="r", linestyle="--", label="Now")
plt.text(current_time, plt.ylim()[1], "Now", color="r", ha="center", va="bottom")
# Add a second x-axis on top
ax1 = plt.gca()
ax2 = ax1.twiny()
ax2.set_xlim(ax1.get_xlim()) # Align the second axis with the first
# Generate integer hour labels
hours_since_start = [(t - timestamps[0]).total_seconds() / 3600 for t in timestamps]
# ax2.set_xticks(timestamps[::48]) # Set ticks every 12 hours
# ax2.set_xticklabels([f"{int(h)}" for h in hours_since_start[::48]])
# ax2.set_xticks(timestamps[:: len(timestamps) // 24]) # Select 10 evenly spaced ticks
ax2.set_xticks(timestamps[:: len(timestamps) // 12]) # Select 10 evenly spaced ticks
# ax2.set_xticklabels([f"{int(h)}" for h in hours_since_start[:: len(timestamps) // 24]])
ax2.set_xticklabels([f"{int(h)}" for h in hours_since_start[:: len(timestamps) // 12]])
if x2label:
ax2.set_xlabel(x2label)
# Ensure ax1 and ax2 are aligned
# assert ax1.get_xlim() == ax2.get_xlim(), "ax1 and ax2 are not aligned"
self.add_chart_to_group(chart, title) # Add chart function to current group
def create_line_chart(
self,
start_hour: Optional[int],
y_list: list[Union[np.ndarray, list[Optional[float]], list[float]]],
title: str,
xlabel: str,
ylabel: str,
labels: Optional[list[str]] = None,
markers: Optional[list[str]] = None,
line_styles: Optional[list[str]] = None,
) -> None:
"""Create a line chart and add it to the current group."""
def chart() -> None:
nonlocal start_hour # Allow modifying `x` within the nested function
if start_hour is None:
start_hour = 0
first_element = y_list[0]
x: np.ndarray
# Case 1: y_list contains np.ndarray elements
if isinstance(first_element, np.ndarray):
x = np.arange(
start_hour, start_hour + len(first_element)
) # Start at x and extend by ndarray length
# Case 2: y_list contains float elements (1D list)
elif isinstance(first_element, float):
x = np.arange(
start_hour, start_hour + len(y_list)
) # Start at x and extend by list length
# Case 3: y_list is a nested list of floats
elif isinstance(first_element, list) and all(
isinstance(i, float) for i in first_element
):
max_len = max(len(sublist) for sublist in y_list)
x = np.arange(
start_hour, start_hour + max_len
) # Start at x and extend by max sublist length
else:
print(f"Unsupported y_list structure: {type(y_list)}, {y_list}")
raise TypeError(
"y_list elements must be np.ndarray, float, or a nested list of floats"
)
for idx, y_data in enumerate(y_list):
label = labels[idx] if labels else None # Chart label
marker = markers[idx] if markers and idx < len(markers) else "o" # Marker style
line_style = (
line_styles[idx] if line_styles and idx < len(line_styles) else "-"
) # Line style
plt.plot(x, y_data, label=label, marker=marker, linestyle=line_style) # Plot line
plt.title(title) # Set title
plt.xlabel(xlabel) # Set x-axis label
plt.ylabel(ylabel) # Set y-axis label
if labels:
plt.legend() # Show legend if labels are provided
plt.grid(True) # Show grid
plt.xlim(x[0] - 0.5, x[-1] + 0.5) # Adjust x-limits
self.add_chart_to_group(chart, title) # Add chart function to current group
def create_scatter_plot(
self,
x: np.ndarray,
y: np.ndarray,
title: str,
xlabel: str,
ylabel: str,
c: Optional[np.ndarray] = None,
) -> None:
"""Create a scatter plot and add it to the current group."""
def chart() -> None:
scatter = plt.scatter(x, y, c=c, cmap="viridis") # Create scatter plot
plt.title(title) # Set title
plt.xlabel(xlabel) # Set x-axis label
plt.ylabel(ylabel) # Set y-axis label
if c is not None:
plt.colorbar(scatter, label="Constraint") # Add colorbar if color data is provided
plt.grid(True) # Show grid
self.add_chart_to_group(chart, title) # Add chart function to current group
def create_bar_chart(
self,
labels: Sequence[str],
values_list: Sequence[Sequence[int | float]],
title: str,
ylabel: str,
xlabels: Optional[list[str]] = None,
label_names: Optional[list[str]] = None,
colors: Optional[list[str]] = None,
bar_width: float = 0.35,
bottom: Optional[int] = None,
) -> None:
"""Create a bar chart and add it to the current group."""
def chart() -> None:
num_groups = len(values_list) # Number of data groups
num_bars = len(labels) # Number of bars (categories)
# Calculate the positions for each bar group on the x-axis
x = np.arange(num_bars) # x positions for bars
offset = np.linspace(
-bar_width * (num_groups - 1) / 2, bar_width * (num_groups - 1) / 2, num_groups
) # Bar offsets
for i, values in enumerate(values_list):
bottom_use = None
if bottom == i + 1: # Set bottom if specified
bottom_use = 1
color = colors[i] if colors and i < len(colors) else None # Bar color
label_name = label_names[i] if label_names else None # Bar label
plt.bar(
x + offset[i],
values,
bar_width,
label=label_name,
color=color,
zorder=2,
alpha=0.6,
bottom=bottom_use,
) # Create bar
if xlabels:
plt.xticks(x, labels) # Add custom labels to the x-axis
plt.title(title) # Set title
plt.ylabel(ylabel) # Set y-axis label
if colors and label_names:
plt.legend() # Show legend if colors are provided
plt.grid(True, zorder=0) # Show grid in the background
plt.xlim(-0.5, len(labels) - 0.5) # Set x-axis limits
self.add_chart_to_group(chart, title) # Add chart function to current group
def create_violin_plot(
self, data_list: list[np.ndarray], labels: list[str], title: str, xlabel: str, ylabel: str
) -> None:
"""Create a violin plot and add it to the current group."""
def chart() -> None:
plt.violinplot(data_list, showmeans=True, showmedians=True) # Create violin plot
plt.xticks(np.arange(1, len(labels) + 1), labels) # Set x-ticks and labels
plt.title(title) # Set title
plt.xlabel(xlabel) # Set x-axis label
plt.ylabel(ylabel) # Set y-axis label
plt.grid(True) # Show grid
self.add_chart_to_group(chart, title) # Add chart function to current group
def add_text_page(self, text: str, title: Optional[str] = None, fontsize: int = 12) -> None:
"""Add a page with text content to the PDF."""
def chart() -> None:
if self.pdf_pages is None: # make mypy happy
raise RuntimeError("Report not initialized")
fig = plt.figure(figsize=(8.5, 11)) # Create a standard page size
plt.axis("off") # Turn off axes for a clean page
wrapped_text = textwrap.fill(text, width=80) # Wrap text to fit the page width
y = 0.95 # Start at the top of the page
if title:
plt.text(0.5, y, title, ha="center", va="top", fontsize=fontsize + 4, weight="bold")
y -= 0.05 # Add space after the title
plt.text(0.5, y, wrapped_text, ha="center", va="top", fontsize=fontsize, wrap=True)
self.pdf_pages.savefig(fig) # Save the figure as a page in the PDF
plt.close(fig) # Close the figure to free up memory
self.add_chart_to_group(chart, title) # Treat the text page as a "chart" in the group
def add_json_page(
self, json_obj: dict, title: Optional[str] = None, fontsize: int = 12
) -> None:
"""Add a page with a formatted JSON object to the PDF.
Args:
json_obj (dict): The JSON object to display.
title (Optional[str]): An optional title for the page.
fontsize (int): The font size for the JSON text.
"""
def chart() -> None:
if self.pdf_pages is None: # make mypy happy
raise RuntimeError("Report not initialized")
# Convert JSON object to a formatted string
json_str = json.dumps(json_obj, indent=4)
fig = plt.figure(figsize=(8.5, 11)) # Standard page size
plt.axis("off") # Turn off axes for a clean page
y = 0.95 # Start at the top of the page
if title:
plt.text(0.5, y, title, ha="center", va="top", fontsize=fontsize + 4, weight="bold")
y -= 0.05 # Add space after the title
# Split the JSON string into lines and render them
lines = json_str.splitlines()
for line in lines:
plt.text(0.05, y, line, ha="left", va="top", fontsize=fontsize, family="monospace")
y -= 0.02 # Move down for the next line
# Stop if the text exceeds the page
if y < 0.05:
break
self.pdf_pages.savefig(fig) # Save the figure as a page in the PDF
plt.close(fig) # Close the figure to free up memory
self.add_chart_to_group(chart, title) # Treat the JSON page as a "chart" in the group
def generate_pdf(self) -> bytes:
"""Generate the PDF report with all the added chart groups.
Returns:
PDF report as bytes object
"""
self._initialize_pdf() # Initialize the PDF
buffer = BytesIO()
self.pdf_pages = PdfPages(buffer, metadata={})
for group in self.groups:
self._save_group_to_pdf(group)
self.pdf_pages.close()
return buffer.getvalue()
def genetic0_prepare_visualize(
solution: Genetic0Solution,
) -> bytes:
global debug_visualize
report = Genetic0VisualizationReport()
next_full_hour_date = get_ems().start_datetime
start_hour = solution.start_hour
# Group 1:
report.create_line_chart_date(
next_full_hour_date,
[
solution.parameters.ems.total_load[start_hour:],
],
title="Load Profile",
# xlabel="Hours", # not enough space
ylabel="Load (Wh)",
labels=["Total Load (Wh)"],
)
report.create_line_chart_date(
next_full_hour_date,
[
solution.parameters.ems.pv_forecast_wh[start_hour:],
],
title="PV Forecast",
# xlabel="Hours", # not enough space
ylabel="PV Generation (Wh)",
)
report.create_line_chart_date(
next_full_hour_date,
[
np.full(
len(solution.parameters.ems.total_load) - start_hour,
solution.parameters.ems.feed_in_tariff_per_wh[start_hour:]
if isinstance(solution.parameters.ems.feed_in_tariff_per_wh, list)
else solution.parameters.ems.feed_in_tariff_per_wh,
)
],
title="Remuneration",
# xlabel="Hours", # not enough space
ylabel="amount/Wh",
x2label=None, # not enough space
)
if solution.parameters.temperature_forecast:
report.create_line_chart_date(
next_full_hour_date,
[
solution.parameters.temperature_forecast[start_hour:],
],
title="Temperature Forecast",
# xlabel="Hours", # not enough space
ylabel="°C",
x2label=None, # not enough space
)
report.finalize_group()
# Group 2:
report.create_line_chart_date(
start_date=next_full_hour_date, # start_date
y_list=[
solution.result.load_wh_per_hour,
solution.result.home_appliance_wh_per_hour,
solution.result.grid_feed_in_wh_per_hour,
solution.result.grid_consumption_wh_per_hour,
solution.result.losses_per_hour,
],
title="Energy Flow per Hour",
# xlabel="Date", # not enough space
ylabel="Energy (Wh)",
labels=[
"Load (Wh)",
"Household Device (Wh)",
"Grid Feed-in (Wh)",
"Grid Consumption (Wh)",
"Losses (Wh)",
],
markers=["o", "o", "x", "^", "^"],
line_styles=["-", "--", ":", "-.", "-"],
)
report.finalize_group()
# Group 3:
report.create_line_chart_date(
start_date=next_full_hour_date,
y_list=[solution.result.battery_soc_per_hour, solution.result.ev_soc_per_hour],
title="Battery SOC",
# xlabel="Date", # not enough space
ylabel="%",
labels=[
"Battery SOC (%)",
"Electric Vehicle SOC (%)",
],
markers=["o", "x"],
)
report.create_line_chart_date(
start_date=next_full_hour_date, # start_date
y_list=[solution.parameters.ems.electricity_price_per_wh[start_hour:]],
# title="Electricity Price", # not enough space
# xlabel="Date", # not enough space
ylabel="Electricity Price (amount/Wh)",
x2label=None, # not enough space
)
labels = list(
item
for sublist in zip(
list(str(i) for i in range(0, 23, 2)), list(str(" ") for i in range(0, 23, 2))
)
for item in sublist
)
labels = labels[start_hour:] + labels
report.create_bar_chart(
labels=labels,
values_list=[
solution.ac_charge[start_hour:],
solution.dc_charge[start_hour:],
solution.discharge_allowed[start_hour:],
],
title="AC/DC Charging and Discharge Overview",
ylabel="Relative Power (0-1) / Discharge (0 or 1)",
label_names=["AC Charging (relative)", "DC Charging (relative)", "Discharge Allowed"],
colors=["blue", "green", "red"],
bottom=3,
xlabels=labels,
)
report.finalize_group()
# Group 4:
report.create_line_chart_date(
next_full_hour_date, # start_date
[
solution.result.costs_per_hour,
solution.result.revenue_per_hour,
],
title="Financial Balance per Hour",
# xlabel="Date", # not enough space
ylabel="Amount",
labels=["Costs", "Revenue"],
)
extra_data = solution.extra_data
if extra_data:
report.create_scatter_plot(
x=np.array(extra_data["losses"]),
y=np.array(extra_data["balance"]),
title="Scatter Plot",
xlabel="losses",
ylabel="balance",
c=np.array(extra_data["constraints"]),
)
values_list = [
[
solution.result.total_costs,
solution.result.total_revenue,
solution.result.total_balance,
]
]
labels = ["Total Costs [amount]", "Total Revenue [amount]", "Total Balance [amount]"]
report.create_bar_chart(
labels=labels,
values_list=values_list,
title="Financial Overview",
ylabel="Amount",
xlabels=["Total Costs [amount]", "Total Revenue [amount]", "Total Balance [amount]"],
)
report.finalize_group()
# Group 1: Scatter plot of losses vs balance with color-coded constraints
if extra_data:
f1 = np.array(extra_data["losses"]) # Losses
f2 = np.array(extra_data["balance"]) # Balance
n1 = np.array(extra_data["constraints"]) # Constraints
# Filter data where 'constraints' < 0.01
filtered_indices = n1 < 0.01
filtered_losses = f1[filtered_indices]
filtered_balance = f2[filtered_indices]
# Group 2: Violin plot for filtered losses
if filtered_losses.size > 0:
report.create_violin_plot(
data_list=[filtered_losses], # Data for filtered losses
labels=["Filtered Losses"], # Label for the violin plot
title="Violin Plot for Filtered Losses (Constraint < 0.01)",
xlabel="Losses",
ylabel="Values",
)
else:
print("No data available for filtered losses violin plot (Constraint < 0.01)")
# Group 3: Violin plot for filtered balance
if extra_data:
if filtered_balance.size > 0:
report.create_violin_plot(
data_list=[filtered_balance], # Data for filtered balance
labels=["Filtered Balance"], # Label for the violin plot
title="Violin Plot for Filtered Balance (Constraint < 0.01)",
xlabel="Balance",
ylabel="Values",
)
else:
print("No data available for filtered balance violin plot (Constraint < 0.01)")
if filtered_balance.size > 0 or filtered_losses.size > 0:
report.finalize_group()
if solution.fitness_history:
if debug_visualize or solution.fixed_seed:
report.create_line_chart(
start_hour=0,
y_list=[
np.array(solution.fitness_history["avg"]),
np.array(solution.fitness_history["max"]),
np.array(solution.fitness_history["min"]),
],
title=f"DEBUG: Generation Fitness for seed {solution.fixed_seed}",
xlabel="Generation",
ylabel="Fitness",
labels=[
"avg",
"max",
"min",
],
markers=[".", ".", "."],
)
report.finalize_group()
# Generate the PDF report
pdf = report.generate_pdf()
# Return pdf (a bytes object)
return pdf
def genetic0_generate_example_report(filename: str = "example_report.pdf") -> None:
"""Generate example visualization report."""
global debug_visualize
report = Genetic0VisualizationReport("test")
x_hours = 0 # Define x-axis start values (e.g., hours)
# Group 1: Adding charts to be displayed on the same page
report.create_line_chart(
x_hours,
[np.array([10, 20, 30, 40])],
title="Load Profile",
xlabel="Hours",
ylabel="Load (Wh)",
)
report.create_line_chart(
x_hours,
[np.array([5, 15, 25, 35])],
title="PV Forecast",
xlabel="Hours",
ylabel="PV Generation (Wh)",
)
report.create_line_chart(
x_hours,
[np.array([5, 15, 25, 35])],
title="PV Forecast",
xlabel="Hours",
ylabel="PV Generation (Wh)",
)
# Note: If there are only 3 charts per page, the first is as wide as the page
report.finalize_group() # Finalize the first group of charts
# Group 2: Adding more charts to be displayed on another page
report.create_line_chart(
x_hours,
[np.array([0.2, 0.25, 0.3, 0.35])],
title="Electricity Price",
xlabel="Hours",
ylabel="Price (€/Wh)",
)
report.create_bar_chart(
["Costs", "Revenue", "Balance"],
[[500.0], [600.0], [100.0]],
title="Financial Overview",
ylabel="Euro",
label_names=["AC Charging (relative)", "DC Charging (relative)", "Discharge Allowed"],
colors=["red", "green", "blue"],
)
report.create_scatter_plot(
np.array([5, 6, 7, 8]),
np.array([100, 200, 150, 250]),
title="Scatter Plot",
xlabel="Losses",
ylabel="Balance",
c=np.array([0.1, 0.2, 0.3, 0.4]),
)
report.finalize_group() # Finalize the second group of charts
# Group 3: Adding a violin plot
data = [np.random.normal(0, std, 100) for std in range(1, 5)] # Example data for violin plot
report.create_violin_plot(
data,
labels=["Group 1", "Group 2", "Group 3", "Group 4"],
title="Violin Plot",
xlabel="Groups",
ylabel="Values",
)
data = [np.random.normal(0, 1, 100)] # Example data for violin plot
report.create_violin_plot(
data, labels=["Group 1"], title="Violin Plot", xlabel="Group", ylabel="Values"
)
report.finalize_group() # Finalize the third group of charts
debug_visualize = True # set level for example report
if debug_visualize:
report.create_line_chart(
x_hours,
[np.array([0.2, 0.25, 0.3, 0.35])],
title="DEBUG",
xlabel="DEBUG",
ylabel="DEBUG",
)
report.finalize_group() # Finalize the third group of charts
report.add_text_page(
text=" Bisher passierte folgendes:"
"Am Anfang wurde das Universum erschaffen."
"Das machte viele Leute sehr wütend und wurde allent-"
"halben als Schritt in die falsche Richtung angesehen...",
title="Don't Panic!",
fontsize=14,
)
report.finalize_group()
sample_json = {
"name": "Visualization Report",
"version": 1.0,
"charts": [
{"type": "line", "data_points": 50},
{"type": "bar", "categories": 10},
],
"metadata": {"author": "AI Assistant", "date": "2025-01-11"},
}
report.add_json_page(json_obj=sample_json, title="Formatted JSON Data", fontsize=10)
report.finalize_group()
report.create_line_chart_date(
pendulum.now().subtract(hours=0),
[list(np.random.random(840))],
title="test",
xlabel="test",
ylabel="test",
)
report.finalize_group()
# Generate the PDF report (a bytes object)
pdf = report.generate_pdf()
# write to file
with open(filename, "wb") as f:
f.write(pdf)
if __name__ == "__main__":
genetic0_generate_example_report()
@@ -217,7 +217,7 @@ class ElecPriceEnergyCharts(ElecPriceProvider):
# Determine if update is needed and how many days
past_days = 35
if self.highest_orig_datetime:
history_series = await self.key_to_series(
history_series = await self.key_to_raw_series(
key="elecprice_marketprice_wh", start_datetime=self.ems_start_datetime
)
# If history lower, then start_datetime
@@ -170,7 +170,7 @@ class FeedInTariffEnergyCharts(FeedInTariffProvider):
past_days = 35
needs_history_refresh = False
if self.highest_orig_datetime:
raw_history = await self.key_to_series(
raw_history = await self.key_to_raw_series(
key="feed_in_tariff_wh",
end_datetime=to_datetime(self.highest_orig_datetime).add(seconds=1),
)
@@ -243,7 +243,7 @@ class FeedInTariffEnergyCharts(FeedInTariffProvider):
logger.error(error_msg)
raise ValueError(error_msg)
raw_series = await self.key_to_series(
raw_series = await self.key_to_raw_series(
key="feed_in_tariff_wh",
end_datetime=to_datetime(self.highest_orig_datetime).add(seconds=1),
)
@@ -132,7 +132,7 @@ class WeatherBrightSky(WeatherProvider):
error_msg = f"No WeatherDataRecord key for '{description}'"
logger.error(error_msg)
raise ValueError(error_msg)
series = await self.key_to_series(key)
series = await self.key_to_raw_series(key)
return series
async def _description_from_series(self, description: str, data: pd.Series) -> None:
@@ -218,7 +218,7 @@ class WeatherOpenMeteo(WeatherProvider):
error_msg = f"No WeatherDataRecord key for '{description}'"
logger.error(error_msg)
raise ValueError(error_msg)
series = await self.key_to_series(key)
series = await self.key_to_raw_series(key)
return series
async def _description_from_series(self, description: str, data: pd.Series) -> None:
File diff suppressed because it is too large Load Diff
+105
View File
@@ -1,4 +1,109 @@
import html
import traceback
from dataclasses import dataclass
from fastapi import FastAPI, Request
from fastapi.exceptions import HTTPException, RequestValidationError
from fastapi.responses import JSONResponse
from loguru import logger
from akkudoktoreos.core.coreabc import get_config
@dataclass(slots=True)
class EOSProblem(Exception):
"""Application exception returned as RFC 7807 Problem Details."""
status: int
title: str
detail: str
type: str = "about:blank"
cause: Exception | None = None
def __str__(self) -> str:
return self.detail
def _problem_response(
*,
request: Request,
status: int,
title: str,
detail: str,
type: str,
cause: Exception | None = None,
) -> JSONResponse:
body = {
"type": type,
"title": title,
"status": status,
"detail": detail,
"instance": request.url.path,
}
if cause is not None:
logger.exception(cause)
if get_config().logging.api_level in ("TRACE", "DEBUG"):
body["traceback"] = traceback.format_exception(cause)
return JSONResponse(
status_code=status,
media_type="application/problem+json",
content=body,
)
async def eos_problem_handler(request: Request, exc: EOSProblem) -> JSONResponse:
return _problem_response(
request=request,
status=exc.status,
title=exc.title,
detail=exc.detail,
cause=exc.cause,
type=exc.type,
)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
return _problem_response(
request=request,
status=exc.status_code,
title="HTTP Error",
detail=str(exc.detail),
cause=exc,
type="about:blank",
)
async def unexpected_exception_handler(request: Request, exc: Exception) -> JSONResponse:
return _problem_response(
request=request,
status=500,
title="Internal Server Error",
detail=str(exc),
cause=exc,
type="/problems/internal-server-error",
)
async def validation_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
return _problem_response(
request=request,
status=422,
title="Validation Error",
detail="Request validation failed.",
cause=exc,
type="/problems/validation",
)
def register_problem_handlers(app: FastAPI) -> None:
app.add_exception_handler(EOSProblem, eos_problem_handler)
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(Exception, unexpected_exception_handler)
app.add_exception_handler(RequestValidationError, validation_handler)
ERROR_PAGE_TEMPLATE = """
<!DOCTYPE html>
+3 -3
View File
@@ -180,11 +180,11 @@ class TestDataSequence:
retrieved_record = await sequence.get_by_datetime(dt1)
assert retrieved_record.data_value == 0.9 # Record should have merged with new value
async def test_key_to_series(self, sequence):
async def test_key_to_raw_series(self, sequence):
dt = to_datetime(datetime(2023, 11, 6))
record = self.create_test_record(dt, 0.8)
await sequence.insert_by_datetime(record)
series = await sequence.key_to_series("data_value")
series = await sequence.key_to_raw_series("data_value")
assert isinstance(series, pd.Series)
retrieved_record = await sequence.get_by_datetime(dt)
@@ -228,7 +228,7 @@ class TestDataSequence:
assert retrieved_record2 is not None
assert retrieved_record2.data_value == 8.0
series = await sequence.key_to_series(
series = await sequence.key_to_raw_series(
key="data_value", start_datetime=start_datetime, end_datetime=end_datetime
)
assert len(series) == 2
+1 -1
View File
@@ -265,7 +265,7 @@ class SampleSequence(DatabaseRecordProtocolMixin[SampleRecord]):
interval: Optional[Duration] = None,
fill_method: Optional[FillMethod] = None,
resample_method: ResampleMethod = "mean",
dropna: Optional[bool] = True,
dropna: bool = True,
boundary: BoundaryMode = "context",
align_to_interval: bool = False,
) -> NDArray[Shape["*"], Any]:
+1 -1
View File
@@ -393,7 +393,7 @@ class TestElecPriceTibber:
assert forecast_call["forecast_slots"] == 22
# (a)+(c) Stored records keep the native 15-min grid across today and the forecast.
stored = await tibber_provider.key_to_series(
stored = await tibber_provider.key_to_raw_series(
"elecprice_marketprice_wh",
start_datetime=to_datetime("2026-07-09T00:00:00+00:00"),
end_datetime=to_datetime("2026-07-09T06:15:00+00:00"),
+1 -1
View File
@@ -93,7 +93,7 @@ class TestFeedInTariffEnergyCharts:
with patch.object(provider, "_request_forecast", return_value=energy_charts_data):
await provider._update_data(force_update=True)
result = await provider.key_to_series(
result = await provider.key_to_raw_series(
key="feed_in_tariff_wh",
start_datetime=start,
end_datetime=start.add(hours=provider.config.prediction.hours),
+52 -36
View File
@@ -1,9 +1,12 @@
import json
from io import BytesIO
from pathlib import Path
from typing import Any
from unittest.mock import patch
import pytest
from pydantic import ValidationError
from pypdf import PdfReader
from akkudoktoreos.config.config import ConfigEOS
from akkudoktoreos.core.cache import CacheEnergyManagementStore
@@ -13,14 +16,14 @@ from akkudoktoreos.optimization.genetic0.genetic0params import (
Genetic0OptimizationParameters,
)
from akkudoktoreos.optimization.genetic0.genetic0solution import Genetic0Solution
from akkudoktoreos.utils.datetimeutil import to_datetime
from akkudoktoreos.utils.visualize import (
prepare_visualize, # Import the new prepare_visualize
from akkudoktoreos.optimization.genetic0.genetic0visualize import (
genetic0_prepare_visualize,
)
from akkudoktoreos.utils.datetimeutil import to_datetime
ems_eos = get_ems(init=True) # init once
DIR_TESTDATA = Path(__file__).parent / "testdata"
DIR_TESTDATA = Path(__file__).parent / "testdata" / "genetic0"
def compare_dict(actual: dict[str, Any], expected: dict[str, Any]):
@@ -40,11 +43,11 @@ def compare_dict(actual: dict[str, Any], expected: dict[str, Any]):
@pytest.mark.parametrize(
"fn_in, fn_out, ngen, break_even",
[
("genetic0optimize_input_1.json", "genetic0optimize_result_1.json", 3, 0),
("genetic0optimize_input_2.json", "genetic0optimize_result_2.json", 3, 0),
("genetic0optimize_input_2.json", "genetic0optimize_result_2_full.json", 400, 0),
("genetic0optimize_input_1.json", "genetic0optimize_result_1_be.json", 3, 1),
("genetic0optimize_input_2.json", "genetic0optimize_result_2_be.json", 3, 1),
("optimize_input_1.json", "optimize_result_1.json", 3, 0),
("optimize_input_2.json", "optimize_result_2.json", 3, 0),
("optimize_input_2.json", "optimize_result_2_full.json", 400, 0),
("optimize_input_1.json", "optimize_result_1_be.json", 3, 1),
("optimize_input_2.json", "optimize_result_2_be.json", 3, 1),
],
)
async def test_optimize(
@@ -90,20 +93,10 @@ async def test_optimize(
)
# Load input and output data
file = DIR_TESTDATA / fn_in
with file.open("r") as f_in:
parameter_file = DIR_TESTDATA / fn_in
with parameter_file.open("r") as f_in:
input_data = Genetic0OptimizationParameters(**json.load(f_in))
file = DIR_TESTDATA / fn_out
# In case a new test case is added, we don't want to fail here, so the new output is written
# to disk before
try:
with file.open("r") as f_out:
expected_data = json.load(f_out)
expected_result = Genetic0Solution(**expected_data)
except FileNotFoundError:
pass
# Fake energy management run start datetime
ems_eos.set_start_datetime(to_datetime().set(hour=fixed_start_hour))
@@ -116,27 +109,37 @@ async def test_optimize(
if ngen > 10 and not is_finalize:
pytest.skip()
visualize_filename = str((DIR_TESTDATA / f"new_{fn_out}").with_suffix(".pdf"))
with patch(
"akkudoktoreos.utils.visualize.prepare_visualize",
side_effect=lambda parameters, results, *args, **kwargs: prepare_visualize(
parameters, results, filename=visualize_filename, **kwargs
),
) as prepare_visualize_patch:
# Call the optimization function
genetic0_solution = genetic0_optimization.optimize_ems(
parameters=input_data, start_hour=fixed_start_hour, ngen=ngen
)
# The function creates a visualization result PDF as a side-effect.
prepare_visualize_patch.assert_called_once()
assert Path(visualize_filename).exists()
# Call the optimization function
genetic0_solution = genetic0_optimization.optimize_ems(
parameters=input_data, start_hour=fixed_start_hour, ngen=ngen
)
# Write test output to file, so we can take it as new data on intended change
TESTDATA_FILE = DIR_TESTDATA / f"new_{fn_out}"
with TESTDATA_FILE.open("w", encoding="utf-8", newline="\n") as f_out:
f_out.write(genetic0_solution.model_dump_json(indent=4, exclude_unset=True))
solution_file = DIR_TESTDATA / fn_out
# In case a new test case is added, we don't want to fail here, so the new output is written
# to disk before
try:
with solution_file.open("r") as f_out:
expected_data = json.load(f_out)
expected_result = Genetic0Solution(**expected_data)
except ValidationError:
# Expected genetic solution data does not fit to Genetic0Solution data schema
# Possibly the Genetic0Solution class changed.
pytest.fail(
f"ValidationError: Can not load expected solution from {solution_file}\n"
f"cp {TESTDATA_FILE} {solution_file}\n"
)
except FileNotFoundError:
# Should not happen
pytest.fail(
f"FileNotFoundError: Can not load expected solution from {solution_file}\n"
f"cp {TESTDATA_FILE} {solution_file}\n"
)
assert genetic0_solution.result.Gesamtbilanz_Euro == pytest.approx(
expected_result.result.Gesamtbilanz_Euro
)
@@ -153,3 +156,16 @@ async def test_optimize(
# Check the correct generic energy management plan is created
plan = genetic0_solution.energy_management_plan()
# @TODO
# Check visualization works
pdf = genetic0_prepare_visualize(
solution=genetic0_solution,
)
assert pdf.startswith(b"%PDF-")
reader = PdfReader(BytesIO(pdf))
assert len(reader.pages) == 6
# Everything passed, remove generated files
TESTDATA_FILE.unlink()
+37
View File
@@ -0,0 +1,37 @@
from pathlib import Path
from matplotlib.testing.compare import compare_images
from akkudoktoreos.optimization.genetic0.genetic0visualize import (
genetic0_generate_example_report,
)
filename = "example_report.pdf"
DIR_TESTDATA = Path(__file__).parent / "testdata" / "genetic0"
reference_file = DIR_TESTDATA / "test_example_report.pdf"
reference_png_file = DIR_TESTDATA / "test_example_report_pdf.png"
output_file = DIR_TESTDATA / "test_example_report_new.pdf"
output_png_file = DIR_TESTDATA / "test_example_report_new_pdf.png"
def test_generate_pdf_example(config_eos):
"""Test generation of example visualization report."""
# Generate PDF
genetic0_generate_example_report(filename=str(output_file))
# Check if the file exists
assert output_file.exists()
# Compare the generated file with the reference file
comparison = compare_images(str(reference_file), str(output_file), tol=0)
# Assert that there are no differences
assert comparison is None, f"Images differ: {comparison}"
# Everything passed, remove compare file
reference_png_file.unlink()
output_file.unlink()
output_png_file.unlink()
+47 -31
View File
@@ -1,9 +1,12 @@
import json
from io import BytesIO
from pathlib import Path
from typing import Any
from unittest.mock import patch
import pytest
from pydantic import ValidationError
from pypdf import PdfReader
from akkudoktoreos.config.config import ConfigEOS
from akkudoktoreos.core.cache import CacheEnergyManagementStore
@@ -13,14 +16,14 @@ from akkudoktoreos.optimization.genetic.geneticparams import (
GeneticOptimizationParameters,
)
from akkudoktoreos.optimization.genetic.geneticsolution import GeneticSolution
from akkudoktoreos.utils.datetimeutil import to_datetime
from akkudoktoreos.utils.visualize import (
prepare_visualize, # Import the new prepare_visualize
from akkudoktoreos.optimization.genetic.geneticvisualize import (
genetic_prepare_visualize,
)
from akkudoktoreos.utils.datetimeutil import to_datetime
ems_eos = get_ems(init=True) # init once
DIR_TESTDATA = Path(__file__).parent / "testdata"
DIR_TESTDATA = Path(__file__).parent / "testdata" / "genetic"
def compare_dict(actual: dict[str, Any], expected: dict[str, Any]):
@@ -90,20 +93,10 @@ async def test_optimize(
)
# Load input and output data
file = DIR_TESTDATA / fn_in
with file.open("r") as f_in:
parameter_file = DIR_TESTDATA / fn_in
with parameter_file.open("r") as f_in:
input_data = GeneticOptimizationParameters(**json.load(f_in))
file = DIR_TESTDATA / fn_out
# In case a new test case is added, we don't want to fail here, so the new output is written
# to disk before
try:
with file.open("r") as f_out:
expected_data = json.load(f_out)
expected_result = GeneticSolution(**expected_data)
except FileNotFoundError:
pass
# Fake energy management run start datetime
ems_eos.set_start_datetime(to_datetime().set(hour=fixed_start_hour))
@@ -116,27 +109,37 @@ async def test_optimize(
if ngen > 10 and not is_finalize:
pytest.skip()
visualize_filename = str((DIR_TESTDATA / f"new_{fn_out}").with_suffix(".pdf"))
with patch(
"akkudoktoreos.utils.visualize.prepare_visualize",
side_effect=lambda parameters, results, *args, **kwargs: prepare_visualize(
parameters, results, filename=visualize_filename, **kwargs
),
) as prepare_visualize_patch:
# Call the optimization function
genetic_solution = genetic_optimization.optimize_ems(
parameters=input_data, start_hour=fixed_start_hour, ngen=ngen
)
# The function creates a visualization result PDF as a side-effect.
prepare_visualize_patch.assert_called_once()
assert Path(visualize_filename).exists()
# Call the optimization function
genetic_solution = genetic_optimization.optimize_ems(
parameters=input_data, start_hour=fixed_start_hour, ngen=ngen
)
# Write test output to file, so we can take it as new data on intended change
TESTDATA_FILE = DIR_TESTDATA / f"new_{fn_out}"
with TESTDATA_FILE.open("w", encoding="utf-8", newline="\n") as f_out:
f_out.write(genetic_solution.model_dump_json(indent=4, exclude_unset=True))
solution_file = DIR_TESTDATA / fn_out
# In case a new test case is added, we don't want to fail here, so the new output is written
# to disk before
try:
with solution_file.open("r") as f_out:
expected_data = json.load(f_out)
expected_result = GeneticSolution(**expected_data)
except ValidationError:
# Expected genetic solution data does not fit to GeneticSolution data schema
# Possibly the GeneticSolution class changed.
pytest.fail(
f"ValidationError: Can not load expected solution from {solution_file}\n"
f"cp {TESTDATA_FILE} {solution_file}\n"
)
except FileNotFoundError:
# Should not happen
pytest.fail(
f"FileNotFoundError: Can not load expected solution from {solution_file}\n"
f"cp {TESTDATA_FILE} {solution_file}\n"
)
assert genetic_solution.result.Gesamtbilanz_Euro == pytest.approx(
expected_result.result.Gesamtbilanz_Euro
)
@@ -153,3 +156,16 @@ async def test_optimize(
# Check the correct generic energy management plan is created
plan = genetic_solution.energy_management_plan()
# @TODO
# Check visualization works
pdf = genetic_prepare_visualize(
solution=genetic_solution,
)
assert pdf.startswith(b"%PDF-")
reader = PdfReader(BytesIO(pdf))
assert len(reader.pages) == 6
# Everything passed, remove generated files
TESTDATA_FILE.unlink()
@@ -2,20 +2,24 @@ from pathlib import Path
from matplotlib.testing.compare import compare_images
from akkudoktoreos.utils.visualize import generate_example_report
from akkudoktoreos.optimization.genetic.geneticvisualize import (
genetic_generate_example_report,
)
filename = "example_report.pdf"
DIR_TESTDATA = Path(__file__).parent / "testdata"
DIR_TESTDATA = Path(__file__).parent / "testdata" / "genetic"
reference_file = DIR_TESTDATA / "test_example_report.pdf"
reference_png_file = DIR_TESTDATA / "test_example_report_pdf.png"
output_file = DIR_TESTDATA / "test_example_report_new.pdf"
output_png_file = DIR_TESTDATA / "test_example_report_new_pdf.png"
def test_generate_pdf_example(config_eos):
"""Test generation of example visualization report."""
# Generate PDF
generate_example_report(filename=str(output_file))
genetic_generate_example_report(filename=str(output_file))
# Check if the file exists
assert output_file.exists()
@@ -25,3 +29,8 @@ def test_generate_pdf_example(config_eos):
# Assert that there are no differences
assert comparison is None, f"Images differ: {comparison}"
# Everything passed, remove compare file
reference_png_file.unlink()
output_file.unlink()
output_png_file.unlink()
+2 -2
View File
@@ -346,7 +346,7 @@ async def test_timezone_behaviour(
other_end_datetime = other_start_datetime + to_duration("24 hours")
expected_end_datetime = to_datetime("2024-10-07T00:00:00+0200", in_timezone=other_timezone)
assert compare_datetimes(other_end_datetime, expected_end_datetime).equal
forecast_temps = await provider.key_to_series(
forecast_temps = await provider.key_to_raw_series(
"pvforecastakkudoktor_temp_air", other_start_datetime, other_end_datetime
)
assert len(forecast_temps) == 23 # 24-1, first temperature is null
@@ -355,7 +355,7 @@ async def test_timezone_behaviour(
# Test fetching AC power forecast
other_end_datetime = other_start_datetime + to_duration("48 hours")
forecast_measured = await provider.key_to_series(
forecast_measured = await provider.key_to_raw_series(
"pvforecastakkudoktor_ac_power_measured", other_start_datetime, other_end_datetime
)
assert len(forecast_measured) == 1
+76 -12
View File
@@ -45,7 +45,13 @@ class TestSystem:
result = requests.post(f"{server}/v1/prediction/update/BrightSky")
assert result.status_code == HTTPStatus.OK
result = requests.get(f"{server}/v1/prediction/series?key=weather_temp_air")
result = requests.get(
f"{server}/v1/prediction/series",
params={
"key": "weather_temp_air",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK
data = result.json()
@@ -72,7 +78,13 @@ class TestSystem:
result = requests.post(f"{server}/v1/prediction/update/ClearOutside")
assert result.status_code == HTTPStatus.OK, f"Failed: {result.headers} {result.text}"
result = requests.get(f"{server}/v1/prediction/series?key=weather_temp_air")
result = requests.get(
f"{server}/v1/prediction/series",
params={
"key": "weather_temp_air",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK
data = result.json()
@@ -103,7 +115,13 @@ class TestSystem:
result = requests.post(f"{server}/v1/prediction/update/PVForecastAkkudoktor")
assert result.status_code == HTTPStatus.OK, f"Failed: {result.headers} {result.text}"
result = requests.get(f"{server}/v1/prediction/series?key=pvforecast_ac_power")
result = requests.get(
f"{server}/v1/prediction/series",
params={
"key": "pvforecast_ac_power",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK
data = result.json()
@@ -134,7 +152,13 @@ class TestSystem:
result = requests.post(f"{server}/v1/prediction/update/ElecPriceAkkudoktor")
assert result.status_code == HTTPStatus.OK
result = requests.get(f"{server}/v1/prediction/series?key=elecprice_marketprice_wh")
result = requests.get(
f"{server}/v1/prediction/series",
params={
"key": "elecprice_marketprice_wh",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK
data = result.json()
@@ -161,7 +185,13 @@ class TestSystem:
result = requests.post(f"{server}/v1/prediction/update/LoadAkkudoktor")
assert result.status_code == HTTPStatus.OK
result = requests.get(f"{server}/v1/prediction/series?key=loadforecast_power_w")
result = requests.get(
f"{server}/v1/prediction/series",
params={
"key": "loadforecast_power_w",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK
data = result.json()
@@ -318,7 +348,13 @@ class TestSystem:
# ----------------------------------------------------------------------
# 4. GET /v1/measurement/series
# ----------------------------------------------------------------------
result = requests.get(f"{server}/v1/measurement/series", params={"key": "pv1_emr"})
result = requests.get(
f"{server}/v1/measurement/series",
params={
"key": "pv1_emr",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK, f"Failed to GET series: {result.text}"
series_response = result.json()
@@ -330,7 +366,11 @@ class TestSystem:
# Non-existent key must be rejected
result = requests.get(
f"{server}/v1/measurement/series", params={"key": "non_existent_key"}
f"{server}/v1/measurement/series",
params={
"key": "non_existent_key",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.NOT_FOUND, (
f"Expected 404 for unknown series key, got {result.status_code}"
@@ -362,7 +402,13 @@ class TestSystem:
assert len(series_response["data"]) >= 3
# Verify the data round-trips correctly
result = requests.get(f"{server}/v1/measurement/series", params={"key": "pv2_emr"})
result = requests.get(
f"{server}/v1/measurement/series",
params={
"key": "pv2_emr",
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK
fetched = result.json()
fetched_values = list(fetched["data"].values())
@@ -400,7 +446,13 @@ class TestSystem:
# Verify data was loaded for both columns
for key in ("pv1_emr", "load1_emr"):
result = requests.get(f"{server}/v1/measurement/series", params={"key": key})
result = requests.get(
f"{server}/v1/measurement/series",
params={
"key": key,
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK, f"Failed to verify series for {key}"
series_response = result.json()
assert len(series_response["data"]) >= 3, f"Expected >=3 data points for {key}"
@@ -443,7 +495,13 @@ class TestSystem:
("load1_emr", [60.5, 55.3]),
("pv2_emr", [150.8, 175.2]),
):
result = requests.get(f"{server}/v1/measurement/series", params={"key": key})
result = requests.get(
f"{server}/v1/measurement/series",
params={
"key": key,
"processing": "raw",
}
)
assert result.status_code == HTTPStatus.OK, f"Failed to verify {key} after data PUT"
fetched = result.json()
fetched_values = list(fetched["data"].values())
@@ -581,7 +639,10 @@ class TestSystem:
# ----------------------------------------------------------------------
result = requests.get(
f"{server}/v1/measurement/series",
params={"key": "pv1_emr_kwh"},
params={
"key": "pv1_emr_kwh",
"processing": "raw",
},
)
assert result.status_code == HTTPStatus.OK
@@ -727,7 +788,10 @@ class TestSystem:
# ----------------------------------------------------------------------
result = requests.get(
f"{server}/v1/measurement/series",
params={"key": "pv1_emr_kwh"},
params={
"key": "pv1_emr_kwh",
"processing": "raw",
},
)
assert result.status_code == HTTPStatus.OK
+1
View File
@@ -162,6 +162,7 @@
}
},
"logging": {
"api_level": "TRACE",
"console_level": "TRACE",
"file_level": "TRACE"
},
+5 -2
View File
@@ -7,8 +7,9 @@
| Name | Environment Variable | Type | Read-Only | Default | Description |
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `str | None` | `rw` | `None` | Logging level when logging to console. |
| file_level | `EOS_LOGGING__FILE_LEVEL` | `str | None` | `rw` | `None` | Logging level when logging to file. |
| api_level | `EOS_LOGGING__API_LEVEL` | `str | None` | `rw` | `None` | Logging level for API response. |
| console_level | `EOS_LOGGING__CONSOLE_LEVEL` | `str | None` | `rw` | `None` | Logging level for logging to console. |
| file_level | `EOS_LOGGING__FILE_LEVEL` | `str | None` | `rw` | `None` | Logging level for logging to file. |
| file_path | | `pathlib.Path | None` | `ro` | `N/A` | Computed log file path based on data output path. |
:::
<!-- pyml enable line-length -->
@@ -21,6 +22,7 @@
```json
{
"logging": {
"api_level": "TRACE",
"console_level": "TRACE",
"file_level": "TRACE"
}
@@ -36,6 +38,7 @@
```json
{
"logging": {
"api_level": "TRACE",
"console_level": "TRACE",
"file_level": "TRACE",
"file_path": "/home/user/.local/share/net.akkudoktor.eos/output/eos.log"
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
-772
View File
@@ -1,772 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
1,
1,
1,
1,
0,
1,
0,
0,
1,
0,
1,
1,
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
0,
0,
1,
0
],
"eautocharge_hours_float": null,
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
1063.91,
1320.56,
1132.03,
1163.67,
1176.82,
1216.22,
1103.78,
1129.12,
1178.71,
1050.98,
988.56,
912.38,
704.61,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.19391086083906173,
0.18681973047764083,
0.12880892587597292,
0.02404700392596282,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.12500582038027028,
0.14608958812480227,
0.09047346757070289,
0.010404817872487553,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 2878.660271824896,
"Gesamtbilanz_Euro": 1.053854835771092,
"Gesamteinnahmen_Euro": 0.9055602150669013,
"Gesamtkosten_Euro": 1.9594150508379933,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
0.004569992000000018,
0.0,
0.0,
0.0,
4.482711108977355e-14,
0.0,
0.016809914659344942,
0.0,
0.05480703000000003,
0.0,
0.291163892,
0.0,
0.0,
0.0,
0.0,
0.22802125600000003,
0.0,
0.182970359,
0.162995926,
0.0,
0.26411047,
0.0,
0.0,
0.0,
0.0,
0.0,
0.010682755832597498,
0.0,
0.0003442778967139274,
0.0,
0.028137079449292023,
0.0,
0.08231598,
0.174597189,
0.293043269,
0.0,
0.16484566
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
20.660000000000082,
0.0,
0.0,
0.0,
2.236881790906864e-10,
0.0,
74.05248748610107,
0.0,
171.54000000000008,
0.0,
980.68,
0.0,
0.0,
0.0,
0.0,
694.34,
0.0,
556.31,
488.89,
0.0,
799.85,
0.0,
0.0,
0.0,
0.0,
0.0,
56.853410498124,
0.0,
1.7179535764168035,
0.0,
123.95189184710142,
0.0,
257.64,
566.69,
987.01,
0.0,
592.97
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
2770.155154843739,
2668.8532925377262,
1840.127512513899,
343.5286275137546,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1785.797434003861,
2086.994116068604,
1292.4781081528986,
148.64025532125078,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
0.0,
29.157272727272726,
3.7179773678125034,
582.6180000000041,
188.65138141872444,
10.782457846871594,
0.0,
59.810111380126784,
0.0,
99.72409090909093,
0.0,
124.41545454545451,
96.08318181818186,
70.41409090909087,
118.37045454545455,
0.0,
83.01681818181817,
0.0,
0.0,
69.12409090909085,
0.0,
109.96227272727276,
47.952272727272714,
16.01263877609336,
55.946263193163475,
161.62968357967037,
14.209990740225123,
538.2984000000038,
227.42215349036655,
10.13011689299087,
0.0,
44.377460775206174,
0.0,
0.0,
0.0,
100.08954545454549,
0.0
],
"akku_soc_pro_stunde": [
80.0,
79.4714617768595,
79.4714617768595,
78.55109331955923,
78.57585051614844,
94.75968384947988,
100.0,
100.0,
100.0,
100.0,
100.0,
96.85214359504131,
96.85214359504131,
92.92488808539943,
89.89195936639118,
87.6692923553719,
83.93285123966942,
83.93285123966942,
81.31237086776858,
81.31237086776858,
81.31237086776858,
79.13042355371898,
79.13042355371898,
75.65939221763084,
74.14574724517905,
74.30696088041155,
74.82732877552169,
78.33526266026307,
78.72998462526934,
93.68271795860093,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
96.84060778236915
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 32400.000000000004,
"initial_soc_percentage": 54
},
"start_solution": [
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
2.0,
1.0,
1.0,
0.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
2.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"washingstart": null
}
-772
View File
@@ -1,772 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
0,
1,
1,
1,
1,
1,
0,
1,
0,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0
],
"eautocharge_hours_float": null,
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
1063.91,
1320.56,
1132.03,
1163.67,
1176.82,
1216.22,
1103.78,
1129.12,
1178.71,
1050.98,
988.56,
912.38,
704.61,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.19478794541504615,
0.18681973047764083,
0.12880892587597292,
0.02404700392596282,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.17104472158211628,
0.14608958812480227,
0.09047346757070289,
0.010404817872487553,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 2804.7326610375394,
"Gesamtbilanz_Euro": 0.9004618481798127,
"Gesamteinnahmen_Euro": 0.9524762008447317,
"Gesamtkosten_Euro": 1.8529380490245444,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
0.004569992000000018,
0.0,
0.0018232052307313393,
0.0,
4.482711108977355e-14,
0.0,
0.016809914659344942,
0.0,
0.05480703000000003,
0.0,
0.291163892,
0.0,
0.19588158,
0.174739608,
0.0,
0.0,
0.0,
0.0,
0.0,
0.16677339,
0.0,
0.24530383800000005,
0.08545095,
0.007989913613567745,
0.028255713342252034,
0.0,
0.010682755832597498,
0.0,
0.0003442778967139274,
0.0,
0.028137079449292023,
0.0,
0.08231598,
0.0,
0.293043269,
0.0,
0.16484566
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
20.660000000000082,
0.0,
9.703061366318996,
0.0,
2.236881790906864e-10,
0.0,
74.05248748610107,
0.0,
171.54000000000008,
0.0,
980.68,
0.0,
704.61,
516.37,
0.0,
0.0,
0.0,
0.0,
0.0,
506.91,
0.0,
806.3900000000001,
351.65,
35.04348076126204,
127.73830624887898,
0.0,
56.853410498124,
0.0,
1.7179535764168035,
0.0,
123.95189184710142,
0.0,
257.64,
0.0,
987.01,
0.0,
592.97
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
2782.6849345006594,
2668.8532925377262,
1840.127512513899,
343.5286275137546,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2443.4960226016615,
2086.994116068604,
1292.4781081528986,
148.64025532125078,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
0.0,
29.157272727272726,
2.3948326360417305,
582.6180000000041,
187.1478078598941,
10.782457846871594,
0.0,
59.810111380126784,
0.0,
99.72409090909093,
0.0,
124.41545454545451,
0.0,
0.0,
118.37045454545455,
94.68272727272722,
83.01681818181817,
75.86045454545456,
66.66681818181814,
0.0,
109.0704545454546,
0.0,
0.0,
11.233982308648535,
38.52740325013451,
161.62968357967037,
14.209990740225123,
538.2984000000038,
148.49832285863067,
10.13011689299087,
0.0,
44.377460775206174,
0.0,
77.27590909090907,
0.0,
100.08954545454549,
0.0
],
"akku_soc_pro_stunde": [
80.0,
79.4714617768595,
79.4714617768595,
78.55109331955923,
78.61761644833817,
94.80144978166962,
100.0,
100.0,
100.0,
100.0,
100.0,
96.85214359504131,
96.85214359504131,
92.92488808539943,
92.92488808539943,
92.92488808539943,
89.18844696969695,
86.19972451790632,
83.57924414600548,
81.18465909090907,
79.08027720385672,
79.08027720385672,
75.63739669421484,
75.63739669421484,
75.63739669421484,
75.94945175834397,
77.01965740418103,
80.52759128892241,
80.92231325392866,
95.87504658726026,
100.0,
100.0,
100.0,
100.0,
100.0,
97.56073519283747,
97.56073519283747,
94.40134297520663
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 32400.000000000004,
"initial_soc_percentage": 54
},
"start_solution": [
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"washingstart": null
}
-818
View File
@@ -1,818 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
1,
1,
1,
1,
0,
1,
1,
1,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
1
],
"eautocharge_hours_float": [
1.0,
0.5,
0.375,
0.375,
1.0,
0.75,
1.0,
0.75,
0.5,
0.875,
0.0,
0.875,
0.75,
1.0,
0.625,
0.375,
0.75,
0.875,
0.625,
1.0,
0.75,
0.375,
0.75,
0.5,
0.5,
0.625,
0.875,
0.5,
0.0,
0.0,
0.75,
0.875,
0.0,
0.0,
1.0,
0.375,
0.375,
1.0,
0.0,
0.875,
0.5,
1.0,
0.625,
0.75,
0.875,
1.0,
0.5,
0.5
],
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
10240.91,
14186.56,
11620.03,
11218.67,
7609.82,
9082.22,
10280.78,
2177.92,
1178.71,
1050.98,
1988.56,
912.38,
1704.6100000000001,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
5.0,
20.294999999999998,
33.405,
50.885000000000005,
61.809999999999995,
68.365,
81.475,
96.77,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.010924611164505103,
0.25751345302450973,
0.14608958812480227,
0.07926913850394514,
0.010404817872487553,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 5766.286846118221,
"Gesamtbilanz_Euro": 12.78299149726557,
"Gesamteinnahmen_Euro": 0.5042016086902498,
"Gesamtkosten_Euro": 13.28719310595582,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
2.034522392,
2.737606326,
1.9651220859999998,
0.9557324300000001,
0.4189863,
1.1236923319999998,
1.64866014,
0.07038454500000005,
0.05480703000000003,
0.0,
0.588063892,
0.0,
0.47388158,
0.174739608,
0.28801899,
0.0,
0.0,
0.0,
0.0,
0.16677339,
0.0,
0.0,
0.0,
0.007989913613567745,
0.028255713342252034,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.08231598,
0.174597189,
0.293043269,
0.0,
0.0
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
9197.66,
13079.82,
10458.34,
5199.85,
2090.75,
5112.339999999999,
7262.820000000001,
234.85000000000014,
171.54000000000008,
0.0,
1980.6799999999998,
0.0,
1704.6100000000001,
516.37,
868.05,
0.0,
0.0,
0.0,
0.0,
506.91,
0.0,
0.0,
0.0,
35.04348076126204,
127.73830624887898,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
257.64,
566.69,
987.01,
0.0,
0.0
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
156.06587377864435,
3678.7636146358536,
2086.994116068604,
1132.4162643420734,
148.64025532125078,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
483.0,
1014.0,
552.0,
465.0,
207.0,
414.0,
483.0,
55.200000000000045,
0.0,
99.72409090909093,
120.0,
124.41545454545451,
120.0,
0.0,
0.0,
94.68272727272722,
83.01681818181817,
75.86045454545456,
66.66681818181814,
0.0,
109.0704545454546,
109.96227272727276,
47.952272727272714,
11.233982308648535,
38.52740325013451,
161.62968357967037,
21.962728535423857,
519.5704951465664,
0.5004782113116364,
10.13011689299087,
36.109951963721926,
44.377460775206174,
0.0,
0.0,
0.0,
100.08954545454549,
80.85954545454547
],
"akku_soc_pro_stunde": [
80.0,
79.4714617768595,
79.4714617768595,
96.13812844352617,
96.13812844352617,
99.4714617768595,
99.4714617768595,
99.4714617768595,
99.4714617768595,
99.4714617768595,
99.4714617768595,
96.32360537190083,
99.65693870523415,
95.72968319559227,
99.0630165289256,
99.0630165289256,
99.0630165289256,
96.07429407713497,
93.45381370523414,
91.05922865013771,
88.95484676308537,
88.95484676308537,
85.51196625344349,
82.04093491735533,
80.52728994490354,
80.83934500903268,
81.90955065486975,
85.41748453961112,
85.56748624593055,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
96.84060778236915
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.875,
0.75,
1.0,
0.625,
0.375,
0.75,
0.875,
0.1,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 59110.8,
"initial_soc_percentage": 5
},
"start_solution": [
0.0,
0.0,
2.0,
0.0,
1.0,
1.0,
0.0,
2.0,
1.0,
1.0,
1.0,
0.0,
2.0,
0.0,
2.0,
0.0,
2.0,
2.0,
0.0,
2.0,
1.0,
2.0,
1.0,
2.0,
2.0,
2.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
1.0,
1.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
2.0,
0.0,
2.0,
1.0,
1.0,
6.0,
2.0,
1.0,
1.0,
6.0,
4.0,
6.0,
4.0,
2.0,
5.0,
0.0,
5.0,
4.0,
6.0,
3.0,
1.0,
4.0,
5.0,
3.0,
6.0,
4.0,
1.0,
4.0,
2.0,
2.0,
3.0,
5.0,
2.0,
0.0,
0.0,
4.0,
5.0,
0.0,
0.0,
6.0,
1.0,
1.0,
6.0,
0.0,
5.0,
2.0,
6.0,
3.0,
4.0,
5.0,
6.0,
2.0,
2.0,
14.0
],
"washingstart": 14
}
-818
View File
@@ -1,818 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
1,
1,
0,
0,
1
],
"eautocharge_hours_float": [
0.625,
0.375,
0.5,
1.0,
1.0,
0.75,
0.5,
0.375,
0.375,
0.625,
0.75,
0.875,
0.625,
0.625,
0.625,
1.0,
0.375,
0.625,
0.875,
0.0,
0.5,
0.0,
0.0,
0.5,
0.875,
0.625,
0.75,
0.5,
0.375,
0.375,
0.75,
0.625,
1.0,
0.375,
0.625,
0.625,
0.0,
0.5,
0.875,
0.375,
0.5,
0.875,
0.5,
0.875,
0.75,
0.625,
0.75,
0.0
],
"result": {
"Last_Wh_pro_Stunde": [
8919.07,
10240.91,
7875.5599999999995,
7687.03,
7718.67,
11664.82,
5149.22,
6347.78,
1129.12,
8678.71,
3550.98,
988.56,
912.38,
704.61,
516.37,
868.05,
5694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
6141.98,
1056.97,
992.46,
6155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
18.11,
33.405,
44.330000000000005,
55.254999999999995,
66.18,
83.66,
90.215,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 10674.660531928814,
"Gesamtbilanz_Euro": 14.366070195145795,
"Gesamteinnahmen_Euro": 0.0,
"Gesamtkosten_Euro": 14.366070195145795,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.81824412,
1.061242392,
0.49579402599999994,
0.399351386,
0.13127915000000007,
1.2316083,
0.259218932,
0.7558691399999999,
0.061530097476751734,
2.4510570300000003,
0.0,
0.0,
0.26650619799999997,
0.19588158,
0.13029273082161758,
0.28801899,
1.870021256,
0.199865757,
0.0,
0.0,
0.16677339,
0.0,
1.7663038380000002,
0.08545095,
0.007989913613567745,
1.134255713342252,
0.025392879919306634,
0.010682755832597498,
4.174095896658514e-14,
0.0003442778967139274,
0.0,
0.0,
0.04565364324294593,
0.0,
0.0,
0.293043269,
0.214398479,
0.0
],
"Netzbezug_Wh_pro_Stunde": [
3588.79,
4797.66,
2368.8199999999997,
2125.34,
714.2500000000003,
6145.75,
1179.3400000000001,
3329.8199999999997,
205.30563055305882,
7671.54,
0.0,
0.0,
912.38,
704.61,
385.0258003002884,
868.05,
5694.34,
608.79,
0.0,
0.0,
506.91,
0.0,
5806.39,
351.65,
35.04348076126204,
5127.738306248879,
121.32288542430308,
56.853410498124,
2.270998855635753e-10,
1.7179535764168035,
0.0,
0.0,
152.3311419517715,
0.0,
0.0,
987.01,
733.99,
0.0
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
1014.0,
1083.0,
945.0,
945.0,
479.4,
552.0,
207.0,
276.0,
73.03732433363291,
600.0,
440.6331818181816,
133.72909090909081,
0.0,
0.0,
17.910572686324315,
0.0,
600.0,
0.0,
75.86045454545456,
66.66681818181814,
0.0,
109.0704545454546,
600.0,
0.0,
11.233982308648535,
638.5274032501345,
145.08565374908358,
14.209990740225123,
538.2983999999728,
441.7178455708299,
260.56941082122324,
171.99990368477063,
41.441862965787436,
35.132727272727266,
77.27590909090907,
0.0,
0.0,
80.85954545454547
],
"akku_soc_pro_stunde": [
80.0,
61.06060606060606,
42.12121212121212,
23.18181818181818,
4.242424242424243,
0.0,
0.0,
0.0,
0.0,
2.0288145648231377,
18.695481231489804,
4.786605542784571,
0.5653589863107422,
0.5653589863107422,
0.5653589863107422,
0.0,
0.0,
16.666666666666664,
16.666666666666664,
14.272081611570247,
12.167699724517906,
12.167699724517906,
8.724819214876034,
25.391485881542703,
25.391485881542703,
25.703540945671826,
43.44041325817556,
47.47057030676122,
47.86529227176747,
62.81802560510005,
75.08796575984533,
82.04461281340734,
85.81933369454761,
86.97049655470836,
85.86150895140257,
83.42224414424004,
83.42224414424004,
83.42224414424004
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.75,
0.875,
0.625,
0.625,
0.625,
1.0,
0.375,
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 59373.0,
"initial_soc_percentage": 5
},
"start_solution": [
2.0,
2.0,
0.0,
0.0,
2.0,
0.0,
0.0,
2.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
0.0,
2.0,
1.0,
1.0,
0.0,
0.0,
1.0,
1.0,
2.0,
0.0,
1.0,
1.0,
0.0,
1.0,
2.0,
0.0,
0.0,
2.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
0.0,
1.0,
1.0,
0.0,
0.0,
1.0,
3.0,
1.0,
2.0,
6.0,
6.0,
4.0,
2.0,
1.0,
1.0,
3.0,
4.0,
5.0,
3.0,
3.0,
3.0,
6.0,
1.0,
3.0,
5.0,
0.0,
2.0,
0.0,
0.0,
2.0,
5.0,
3.0,
4.0,
2.0,
1.0,
1.0,
4.0,
3.0,
6.0,
1.0,
3.0,
3.0,
0.0,
2.0,
5.0,
1.0,
2.0,
5.0,
2.0,
5.0,
4.0,
3.0,
4.0,
0.0,
19.0
],
"washingstart": 19
}
-818
View File
@@ -1,818 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
],
"eautocharge_hours_float": [
0.875,
0.75,
0.5,
1.0,
0.625,
0.625,
0.875,
0.625,
0.875,
0.875,
0.0,
1.0,
0.5,
0.625,
1.0,
0.75,
0.5,
0.625,
0.375,
0.5,
0.625,
0.625,
0.5,
0.625,
0.625,
0.0,
0.625,
0.5,
0.5,
1.0,
0.375,
0.625,
0.875,
0.5,
0.5,
0.75,
0.75,
0.75,
0.0,
0.875,
0.75,
1.0,
1.0,
0.75,
0.625,
0.875,
0.5,
0.875
],
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
11551.91,
6564.5599999999995,
7687.03,
14151.67,
11542.82,
6460.22,
7658.78,
5062.12,
1178.71,
1050.98,
988.56,
912.38,
704.61,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
5.0,
22.48,
31.22,
42.144999999999996,
59.62499999999999,
72.735,
81.475,
92.4,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 7647.623819992857,
"Gesamtbilanz_Euro": 7.824605715847156,
"Gesamteinnahmen_Euro": 0.0,
"Gesamtkosten_Euro": 7.824605715847156,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.027996119999999992,
1.351235592,
1.1423217259999998,
1.226111386,
1.4948178300000001,
1.2071595,
0.0,
1.0534661399999998,
0.0,
0.0,
0.0,
0.0,
0.0,
0.19588158,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01995551999999987,
0.08545095,
0.007989913613567745,
0.012219458233588571,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Netzbezug_Wh_pro_Stunde": [
122.78999999999996,
6108.66,
5457.82,
6525.34,
8132.85,
6023.75,
0.0,
4640.82,
0.0,
0.0,
0.0,
0.0,
0.0,
704.61,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
65.59999999999957,
351.65,
35.04348076126204,
55.24167375040041,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
0.0,
1152.0,
276.0,
345.0,
552.0,
414.0,
615.5918181818183,
345.0,
632.3249999999998,
23.391818181818195,
99.72409090909093,
133.72909090909081,
124.41545454545451,
0.0,
70.41409090909087,
118.37045454545455,
94.68272727272722,
83.01681818181817,
75.86045454545456,
66.66681818181814,
69.12409090909085,
109.0704545454546,
101.01681818181828,
0.0,
11.233982308648535,
48.41330768174522,
161.62968357967037,
21.962728535423857,
538.2984000000038,
441.95211196761403,
260.56941082122324,
171.99990368477063,
62.214291413756285,
35.132727272727266,
77.27590909090907,
134.59227272727276,
100.08954545454549,
80.85954545454547
],
"akku_soc_pro_stunde": [
80.0,
80.0,
61.06060606060606,
61.06060606060606,
61.06060606060606,
61.06060606060606,
61.06060606060606,
50.341167355371894,
50.341167355371894,
36.91550447658402,
36.17712637741047,
33.0292699724518,
28.808023415977967,
24.88076790633609,
24.88076790633609,
22.658100895316807,
18.921659779614323,
15.932937327823693,
13.312456955922865,
10.917871900826448,
8.813490013774107,
6.63154269972452,
3.1886621900826473,
0.0,
0.0,
0.3120550641291261,
1.07020564583707,
4.578139530578446,
4.728141236897871,
19.68087457022947,
31.94341995234899,
38.90006700591099,
42.674787887051245,
43.17025540478875,
42.06126780148296,
39.622002994320425,
35.373509537020155,
32.214117319389295
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.5,
0.625,
1.0,
0.75,
0.5,
0.625,
0.375,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 59373.0,
"initial_soc_percentage": 5
},
"start_solution": [
0.0,
0.0,
2.0,
1.0,
0.0,
1.0,
2.0,
2.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
5.0,
4.0,
2.0,
6.0,
3.0,
3.0,
5.0,
3.0,
5.0,
5.0,
0.0,
6.0,
2.0,
3.0,
6.0,
4.0,
2.0,
3.0,
1.0,
2.0,
3.0,
3.0,
2.0,
3.0,
3.0,
0.0,
3.0,
2.0,
2.0,
6.0,
1.0,
3.0,
5.0,
2.0,
2.0,
4.0,
4.0,
4.0,
0.0,
5.0,
4.0,
6.0,
6.0,
4.0,
3.0,
5.0,
2.0,
5.0,
14.0
],
"washingstart": 14
}
-772
View File
@@ -1,772 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
1,
1,
1,
1,
0,
1,
0,
0,
1,
0,
1,
1,
1,
1,
1,
0,
1,
0,
1,
0,
1,
0,
0,
0,
1,
0
],
"eautocharge_hours_float": null,
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
1063.91,
1320.56,
1132.03,
1163.67,
1176.82,
1216.22,
1103.78,
1129.12,
1178.71,
1050.98,
988.56,
912.38,
704.61,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.19391086083906173,
0.18681973047764083,
0.12880892587597292,
0.02404700392596282,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.12500582038027028,
0.14608958812480227,
0.09047346757070289,
0.010404817872487553,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 2878.660271824896,
"Gesamtbilanz_Euro": 1.053854835771092,
"Gesamteinnahmen_Euro": 0.9055602150669013,
"Gesamtkosten_Euro": 1.9594150508379933,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
0.004569992000000018,
0.0,
0.0,
0.0,
4.482711108977355e-14,
0.0,
0.016809914659344942,
0.0,
0.05480703000000003,
0.0,
0.291163892,
0.0,
0.0,
0.0,
0.0,
0.22802125600000003,
0.0,
0.182970359,
0.162995926,
0.0,
0.26411047,
0.0,
0.0,
0.0,
0.0,
0.0,
0.010682755832597498,
0.0,
0.0003442778967139274,
0.0,
0.028137079449292023,
0.0,
0.08231598,
0.174597189,
0.293043269,
0.0,
0.16484566
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
20.660000000000082,
0.0,
0.0,
0.0,
2.236881790906864e-10,
0.0,
74.05248748610107,
0.0,
171.54000000000008,
0.0,
980.68,
0.0,
0.0,
0.0,
0.0,
694.34,
0.0,
556.31,
488.89,
0.0,
799.85,
0.0,
0.0,
0.0,
0.0,
0.0,
56.853410498124,
0.0,
1.7179535764168035,
0.0,
123.95189184710142,
0.0,
257.64,
566.69,
987.01,
0.0,
592.97
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
2770.155154843739,
2668.8532925377262,
1840.127512513899,
343.5286275137546,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1785.797434003861,
2086.994116068604,
1292.4781081528986,
148.64025532125078,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
0.0,
29.157272727272726,
3.7179773678125034,
582.6180000000041,
188.65138141872444,
10.782457846871594,
0.0,
59.810111380126784,
0.0,
99.72409090909093,
0.0,
124.41545454545451,
96.08318181818186,
70.41409090909087,
118.37045454545455,
0.0,
83.01681818181817,
0.0,
0.0,
69.12409090909085,
0.0,
109.96227272727276,
47.952272727272714,
16.01263877609336,
55.946263193163475,
161.62968357967037,
14.209990740225123,
538.2984000000038,
227.42215349036655,
10.13011689299087,
0.0,
44.377460775206174,
0.0,
0.0,
0.0,
100.08954545454549,
0.0
],
"akku_soc_pro_stunde": [
80.0,
79.4714617768595,
79.4714617768595,
78.55109331955923,
78.57585051614844,
94.75968384947988,
100.0,
100.0,
100.0,
100.0,
100.0,
96.85214359504131,
96.85214359504131,
92.92488808539943,
89.89195936639118,
87.6692923553719,
83.93285123966942,
83.93285123966942,
81.31237086776858,
81.31237086776858,
81.31237086776858,
79.13042355371898,
79.13042355371898,
75.65939221763084,
74.14574724517905,
74.30696088041155,
74.82732877552169,
78.33526266026307,
78.72998462526934,
93.68271795860093,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
96.84060778236915
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 32400.000000000004,
"initial_soc_percentage": 54
},
"start_solution": [
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
2.0,
1.0,
1.0,
0.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
2.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"washingstart": null
}
-772
View File
@@ -1,772 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
0,
1,
1,
1,
1,
1,
0,
1,
0,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0
],
"eautocharge_hours_float": null,
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
1063.91,
1320.56,
1132.03,
1163.67,
1176.82,
1216.22,
1103.78,
1129.12,
1178.71,
1050.98,
988.56,
912.38,
704.61,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0,
54.0
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.19478794541504615,
0.18681973047764083,
0.12880892587597292,
0.02404700392596282,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.17104472158211628,
0.14608958812480227,
0.09047346757070289,
0.010404817872487553,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 2804.7326610375394,
"Gesamtbilanz_Euro": 0.9004618481798127,
"Gesamteinnahmen_Euro": 0.9524762008447317,
"Gesamtkosten_Euro": 1.8529380490245444,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
0.004569992000000018,
0.0,
0.0018232052307313393,
0.0,
4.482711108977355e-14,
0.0,
0.016809914659344942,
0.0,
0.05480703000000003,
0.0,
0.291163892,
0.0,
0.19588158,
0.174739608,
0.0,
0.0,
0.0,
0.0,
0.0,
0.16677339,
0.0,
0.24530383800000005,
0.08545095,
0.007989913613567745,
0.028255713342252034,
0.0,
0.010682755832597498,
0.0,
0.0003442778967139274,
0.0,
0.028137079449292023,
0.0,
0.08231598,
0.0,
0.293043269,
0.0,
0.16484566
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
20.660000000000082,
0.0,
9.703061366318996,
0.0,
2.236881790906864e-10,
0.0,
74.05248748610107,
0.0,
171.54000000000008,
0.0,
980.68,
0.0,
704.61,
516.37,
0.0,
0.0,
0.0,
0.0,
0.0,
506.91,
0.0,
806.3900000000001,
351.65,
35.04348076126204,
127.73830624887898,
0.0,
56.853410498124,
0.0,
1.7179535764168035,
0.0,
123.95189184710142,
0.0,
257.64,
0.0,
987.01,
0.0,
592.97
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
2782.6849345006594,
2668.8532925377262,
1840.127512513899,
343.5286275137546,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2443.4960226016615,
2086.994116068604,
1292.4781081528986,
148.64025532125078,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
0.0,
29.157272727272726,
2.3948326360417305,
582.6180000000041,
187.1478078598941,
10.782457846871594,
0.0,
59.810111380126784,
0.0,
99.72409090909093,
0.0,
124.41545454545451,
0.0,
0.0,
118.37045454545455,
94.68272727272722,
83.01681818181817,
75.86045454545456,
66.66681818181814,
0.0,
109.0704545454546,
0.0,
0.0,
11.233982308648535,
38.52740325013451,
161.62968357967037,
14.209990740225123,
538.2984000000038,
148.49832285863067,
10.13011689299087,
0.0,
44.377460775206174,
0.0,
77.27590909090907,
0.0,
100.08954545454549,
0.0
],
"akku_soc_pro_stunde": [
80.0,
79.4714617768595,
79.4714617768595,
78.55109331955923,
78.61761644833817,
94.80144978166962,
100.0,
100.0,
100.0,
100.0,
100.0,
96.85214359504131,
96.85214359504131,
92.92488808539943,
92.92488808539943,
92.92488808539943,
89.18844696969695,
86.19972451790632,
83.57924414600548,
81.18465909090907,
79.08027720385672,
79.08027720385672,
75.63739669421484,
75.63739669421484,
75.63739669421484,
75.94945175834397,
77.01965740418103,
80.52759128892241,
80.92231325392866,
95.87504658726026,
100.0,
100.0,
100.0,
100.0,
100.0,
97.56073519283747,
97.56073519283747,
94.40134297520663
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 32400.000000000004,
"initial_soc_percentage": 54
},
"start_solution": [
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"washingstart": null
}
-818
View File
@@ -1,818 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
0,
0,
1,
1,
1,
1,
0,
1,
1,
1,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
1
],
"eautocharge_hours_float": [
1.0,
0.5,
0.375,
0.375,
1.0,
0.75,
1.0,
0.75,
0.5,
0.875,
0.0,
0.875,
0.75,
1.0,
0.625,
0.375,
0.75,
0.875,
0.625,
1.0,
0.75,
0.375,
0.75,
0.5,
0.5,
0.625,
0.875,
0.5,
0.0,
0.0,
0.75,
0.875,
0.0,
0.0,
1.0,
0.375,
0.375,
1.0,
0.0,
0.875,
0.5,
1.0,
0.625,
0.75,
0.875,
1.0,
0.5,
0.5
],
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
10240.91,
14186.56,
11620.03,
11218.67,
7609.82,
9082.22,
10280.78,
2177.92,
1178.71,
1050.98,
1988.56,
912.38,
1704.6100000000001,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
5.0,
20.294999999999998,
33.405,
50.885000000000005,
61.809999999999995,
68.365,
81.475,
96.77,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518,
98.518
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.010924611164505103,
0.25751345302450973,
0.14608958812480227,
0.07926913850394514,
0.010404817872487553,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 5766.286846118221,
"Gesamtbilanz_Euro": 12.78299149726557,
"Gesamteinnahmen_Euro": 0.5042016086902498,
"Gesamtkosten_Euro": 13.28719310595582,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
2.034522392,
2.737606326,
1.9651220859999998,
0.9557324300000001,
0.4189863,
1.1236923319999998,
1.64866014,
0.07038454500000005,
0.05480703000000003,
0.0,
0.588063892,
0.0,
0.47388158,
0.174739608,
0.28801899,
0.0,
0.0,
0.0,
0.0,
0.16677339,
0.0,
0.0,
0.0,
0.007989913613567745,
0.028255713342252034,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.08231598,
0.174597189,
0.293043269,
0.0,
0.0
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
9197.66,
13079.82,
10458.34,
5199.85,
2090.75,
5112.339999999999,
7262.820000000001,
234.85000000000014,
171.54000000000008,
0.0,
1980.6799999999998,
0.0,
1704.6100000000001,
516.37,
868.05,
0.0,
0.0,
0.0,
0.0,
506.91,
0.0,
0.0,
0.0,
35.04348076126204,
127.73830624887898,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
257.64,
566.69,
987.01,
0.0,
0.0
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
156.06587377864435,
3678.7636146358536,
2086.994116068604,
1132.4162643420734,
148.64025532125078,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
483.0,
1014.0,
552.0,
465.0,
207.0,
414.0,
483.0,
55.200000000000045,
0.0,
99.72409090909093,
120.0,
124.41545454545451,
120.0,
0.0,
0.0,
94.68272727272722,
83.01681818181817,
75.86045454545456,
66.66681818181814,
0.0,
109.0704545454546,
109.96227272727276,
47.952272727272714,
11.233982308648535,
38.52740325013451,
161.62968357967037,
21.962728535423857,
519.5704951465664,
0.5004782113116364,
10.13011689299087,
36.109951963721926,
44.377460775206174,
0.0,
0.0,
0.0,
100.08954545454549,
80.85954545454547
],
"akku_soc_pro_stunde": [
80.0,
79.4714617768595,
79.4714617768595,
96.13812844352617,
96.13812844352617,
99.4714617768595,
99.4714617768595,
99.4714617768595,
99.4714617768595,
99.4714617768595,
99.4714617768595,
96.32360537190083,
99.65693870523415,
95.72968319559227,
99.0630165289256,
99.0630165289256,
99.0630165289256,
96.07429407713497,
93.45381370523414,
91.05922865013771,
88.95484676308537,
88.95484676308537,
85.51196625344349,
82.04093491735533,
80.52728994490354,
80.83934500903268,
81.90955065486975,
85.41748453961112,
85.56748624593055,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
96.84060778236915
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.875,
0.75,
1.0,
0.625,
0.375,
0.75,
0.875,
0.1,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 59110.8,
"initial_soc_percentage": 5
},
"start_solution": [
0.0,
0.0,
2.0,
0.0,
1.0,
1.0,
0.0,
2.0,
1.0,
1.0,
1.0,
0.0,
2.0,
0.0,
2.0,
0.0,
2.0,
2.0,
0.0,
2.0,
1.0,
2.0,
1.0,
2.0,
2.0,
2.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
1.0,
1.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
2.0,
0.0,
2.0,
1.0,
1.0,
6.0,
2.0,
1.0,
1.0,
6.0,
4.0,
6.0,
4.0,
2.0,
5.0,
0.0,
5.0,
4.0,
6.0,
3.0,
1.0,
4.0,
5.0,
3.0,
6.0,
4.0,
1.0,
4.0,
2.0,
2.0,
3.0,
5.0,
2.0,
0.0,
0.0,
4.0,
5.0,
0.0,
0.0,
6.0,
1.0,
1.0,
6.0,
0.0,
5.0,
2.0,
6.0,
3.0,
4.0,
5.0,
6.0,
2.0,
2.0,
14.0
],
"washingstart": 14
}
-818
View File
@@ -1,818 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
1,
1,
0,
0,
1
],
"eautocharge_hours_float": [
0.625,
0.375,
0.5,
1.0,
1.0,
0.75,
0.5,
0.375,
0.375,
0.625,
0.75,
0.875,
0.625,
0.625,
0.625,
1.0,
0.375,
0.625,
0.875,
0.0,
0.5,
0.0,
0.0,
0.5,
0.875,
0.625,
0.75,
0.5,
0.375,
0.375,
0.75,
0.625,
1.0,
0.375,
0.625,
0.625,
0.0,
0.5,
0.875,
0.375,
0.5,
0.875,
0.5,
0.875,
0.75,
0.625,
0.75,
0.0
],
"result": {
"Last_Wh_pro_Stunde": [
8919.07,
10240.91,
7875.5599999999995,
7687.03,
7718.67,
11664.82,
5149.22,
6347.78,
1129.12,
8678.71,
3550.98,
988.56,
912.38,
704.61,
516.37,
868.05,
5694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
6141.98,
1056.97,
992.46,
6155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
18.11,
33.405,
44.330000000000005,
55.254999999999995,
66.18,
83.66,
90.215,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 10674.660531928814,
"Gesamtbilanz_Euro": 14.366070195145795,
"Gesamteinnahmen_Euro": 0.0,
"Gesamtkosten_Euro": 14.366070195145795,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.81824412,
1.061242392,
0.49579402599999994,
0.399351386,
0.13127915000000007,
1.2316083,
0.259218932,
0.7558691399999999,
0.061530097476751734,
2.4510570300000003,
0.0,
0.0,
0.26650619799999997,
0.19588158,
0.13029273082161758,
0.28801899,
1.870021256,
0.199865757,
0.0,
0.0,
0.16677339,
0.0,
1.7663038380000002,
0.08545095,
0.007989913613567745,
1.134255713342252,
0.025392879919306634,
0.010682755832597498,
4.174095896658514e-14,
0.0003442778967139274,
0.0,
0.0,
0.04565364324294593,
0.0,
0.0,
0.293043269,
0.214398479,
0.0
],
"Netzbezug_Wh_pro_Stunde": [
3588.79,
4797.66,
2368.8199999999997,
2125.34,
714.2500000000003,
6145.75,
1179.3400000000001,
3329.8199999999997,
205.30563055305882,
7671.54,
0.0,
0.0,
912.38,
704.61,
385.0258003002884,
868.05,
5694.34,
608.79,
0.0,
0.0,
506.91,
0.0,
5806.39,
351.65,
35.04348076126204,
5127.738306248879,
121.32288542430308,
56.853410498124,
2.270998855635753e-10,
1.7179535764168035,
0.0,
0.0,
152.3311419517715,
0.0,
0.0,
987.01,
733.99,
0.0
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
1014.0,
1083.0,
945.0,
945.0,
479.4,
552.0,
207.0,
276.0,
73.03732433363291,
600.0,
440.6331818181816,
133.72909090909081,
0.0,
0.0,
17.910572686324315,
0.0,
600.0,
0.0,
75.86045454545456,
66.66681818181814,
0.0,
109.0704545454546,
600.0,
0.0,
11.233982308648535,
638.5274032501345,
145.08565374908358,
14.209990740225123,
538.2983999999728,
441.7178455708299,
260.56941082122324,
171.99990368477063,
41.441862965787436,
35.132727272727266,
77.27590909090907,
0.0,
0.0,
80.85954545454547
],
"akku_soc_pro_stunde": [
80.0,
61.06060606060606,
42.12121212121212,
23.18181818181818,
4.242424242424243,
0.0,
0.0,
0.0,
0.0,
2.0288145648231377,
18.695481231489804,
4.786605542784571,
0.5653589863107422,
0.5653589863107422,
0.5653589863107422,
0.0,
0.0,
16.666666666666664,
16.666666666666664,
14.272081611570247,
12.167699724517906,
12.167699724517906,
8.724819214876034,
25.391485881542703,
25.391485881542703,
25.703540945671826,
43.44041325817556,
47.47057030676122,
47.86529227176747,
62.81802560510005,
75.08796575984533,
82.04461281340734,
85.81933369454761,
86.97049655470836,
85.86150895140257,
83.42224414424004,
83.42224414424004,
83.42224414424004
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.75,
0.875,
0.625,
0.625,
0.625,
1.0,
0.375,
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 59373.0,
"initial_soc_percentage": 5
},
"start_solution": [
2.0,
2.0,
0.0,
0.0,
2.0,
0.0,
0.0,
2.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
0.0,
2.0,
1.0,
1.0,
0.0,
0.0,
1.0,
1.0,
2.0,
0.0,
1.0,
1.0,
0.0,
1.0,
2.0,
0.0,
0.0,
2.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
0.0,
1.0,
1.0,
0.0,
0.0,
1.0,
3.0,
1.0,
2.0,
6.0,
6.0,
4.0,
2.0,
1.0,
1.0,
3.0,
4.0,
5.0,
3.0,
3.0,
3.0,
6.0,
1.0,
3.0,
5.0,
0.0,
2.0,
0.0,
0.0,
2.0,
5.0,
3.0,
4.0,
2.0,
1.0,
1.0,
4.0,
3.0,
6.0,
1.0,
3.0,
3.0,
0.0,
2.0,
5.0,
1.0,
2.0,
5.0,
2.0,
5.0,
4.0,
3.0,
4.0,
0.0,
19.0
],
"washingstart": 19
}
-818
View File
@@ -1,818 +0,0 @@
{
"ac_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"dc_charge": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"discharge_allowed": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1
],
"eautocharge_hours_float": [
0.875,
0.75,
0.5,
1.0,
0.625,
0.625,
0.875,
0.625,
0.875,
0.875,
0.0,
1.0,
0.5,
0.625,
1.0,
0.75,
0.5,
0.625,
0.375,
0.5,
0.625,
0.625,
0.5,
0.625,
0.625,
0.0,
0.625,
0.5,
0.5,
1.0,
0.375,
0.625,
0.875,
0.5,
0.5,
0.75,
0.75,
0.75,
0.0,
0.875,
0.75,
1.0,
1.0,
0.75,
0.625,
0.875,
0.5,
0.875
],
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
11551.91,
6564.5599999999995,
7687.03,
14151.67,
11542.82,
6460.22,
7658.78,
5062.12,
1178.71,
1050.98,
988.56,
912.38,
704.61,
516.37,
868.05,
694.34,
608.79,
556.31,
488.89,
506.91,
804.89,
1141.98,
1056.97,
992.46,
1155.99,
827.01,
1257.98,
1232.67,
871.26,
860.88,
1158.03,
1222.72,
1221.04,
949.99,
987.01,
733.99,
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
5.0,
22.48,
31.22,
42.144999999999996,
59.62499999999999,
72.735,
81.475,
92.4,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955,
98.955
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 7647.623819992857,
"Gesamtbilanz_Euro": 7.824605715847156,
"Gesamteinnahmen_Euro": 0.0,
"Gesamtkosten_Euro": 7.824605715847156,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Kosten_Euro_pro_Stunde": [
0.027996119999999992,
1.351235592,
1.1423217259999998,
1.226111386,
1.4948178300000001,
1.2071595,
0.0,
1.0534661399999998,
0.0,
0.0,
0.0,
0.0,
0.0,
0.19588158,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01995551999999987,
0.08545095,
0.007989913613567745,
0.012219458233588571,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Netzbezug_Wh_pro_Stunde": [
122.78999999999996,
6108.66,
5457.82,
6525.34,
8132.85,
6023.75,
0.0,
4640.82,
0.0,
0.0,
0.0,
0.0,
0.0,
704.61,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
65.59999999999957,
351.65,
35.04348076126204,
55.24167375040041,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Verluste_Pro_Stunde": [
0.0,
1152.0,
276.0,
345.0,
552.0,
414.0,
615.5918181818183,
345.0,
632.3249999999998,
23.391818181818195,
99.72409090909093,
133.72909090909081,
124.41545454545451,
0.0,
70.41409090909087,
118.37045454545455,
94.68272727272722,
83.01681818181817,
75.86045454545456,
66.66681818181814,
69.12409090909085,
109.0704545454546,
101.01681818181828,
0.0,
11.233982308648535,
48.41330768174522,
161.62968357967037,
21.962728535423857,
538.2984000000038,
441.95211196761403,
260.56941082122324,
171.99990368477063,
62.214291413756285,
35.132727272727266,
77.27590909090907,
134.59227272727276,
100.08954545454549,
80.85954545454547
],
"akku_soc_pro_stunde": [
80.0,
80.0,
61.06060606060606,
61.06060606060606,
61.06060606060606,
61.06060606060606,
61.06060606060606,
50.341167355371894,
50.341167355371894,
36.91550447658402,
36.17712637741047,
33.0292699724518,
28.808023415977967,
24.88076790633609,
24.88076790633609,
22.658100895316807,
18.921659779614323,
15.932937327823693,
13.312456955922865,
10.917871900826448,
8.813490013774107,
6.63154269972452,
3.1886621900826473,
0.0,
0.0,
0.3120550641291261,
1.07020564583707,
4.578139530578446,
4.728141236897871,
19.68087457022947,
31.94341995234899,
38.90006700591099,
42.674787887051245,
43.17025540478875,
42.06126780148296,
39.622002994320425,
35.373509537020155,
32.214117319389295
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
"device_id": "ev1",
"hours": 48,
"charge_array": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.5,
0.625,
1.0,
0.75,
0.5,
0.625,
0.375,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"discharge_array": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"discharging_efficiency": 1.0,
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 59373.0,
"initial_soc_percentage": 5
},
"start_solution": [
0.0,
0.0,
2.0,
1.0,
0.0,
1.0,
2.0,
2.0,
1.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
0.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
5.0,
4.0,
2.0,
6.0,
3.0,
3.0,
5.0,
3.0,
5.0,
5.0,
0.0,
6.0,
2.0,
3.0,
6.0,
4.0,
2.0,
3.0,
1.0,
2.0,
3.0,
3.0,
2.0,
3.0,
3.0,
0.0,
3.0,
2.0,
2.0,
6.0,
1.0,
3.0,
5.0,
2.0,
2.0,
4.0,
4.0,
4.0,
0.0,
5.0,
4.0,
6.0,
6.0,
4.0,
3.0,
5.0,
2.0,
5.0,
14.0
],
"washingstart": 14
}
Generated
+276 -249
View File
@@ -62,6 +62,7 @@ dev = [
{ name = "myst-parser" },
{ name = "pandas-stubs" },
{ name = "pre-commit" },
{ name = "pypdf" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-cov" },
@@ -112,6 +113,7 @@ requires-dist = [
{ name = "pydantic", specifier = "==2.13.4" },
{ name = "pydantic-extra-types", specifier = "==2.11.2" },
{ name = "pydantic-settings", specifier = "==2.14.2" },
{ name = "pypdf", marker = "extra == 'dev'", specifier = "==6.14.2" },
{ name = "pytest", marker = "extra == 'dev'", specifier = "==9.1.1" },
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = "==1.4.0" },
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = "==7.1.0" },
@@ -145,11 +147,11 @@ wheels = [
[[package]]
name = "annotated-doc"
version = "0.0.4"
version = "0.0.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" }
sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" },
{ url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" },
]
[[package]]
@@ -176,77 +178,77 @@ wheels = [
[[package]]
name = "apsw"
version = "3.53.3.1"
version = "3.53.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/2a/ec1dfda955cda4b8d77b076553b87d428315bd3a17ea4286aa9dc40901fe/apsw-3.53.3.1.tar.gz", hash = "sha256:7684d24e77dc9e3b301ee5374a8a9501ad8a85b821ce85391260a2448dd02323", size = 1243718, upload-time = "2026-07-10T16:32:23.409Z" }
sdist = { url = "https://files.pythonhosted.org/packages/3b/a3/404d93429ad78385158b277ddd4929137eb279b047d892c24b8d75237119/apsw-3.53.4.0.tar.gz", hash = "sha256:4250fab667cc41c55170028ab095a9d4a4ae66363f4bc0720771c20519702625", size = 1247765, upload-time = "2026-07-26T17:02:32.28Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/81/61/41a09f915d2f8c8c8dd9925a45c130fa1213eaf74a0f555969d275042e93/apsw-3.53.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d9bf61d7abdd17bee3774d2cc2c07544bf04fffe8fee662e1c73598ed9de90b", size = 3272489, upload-time = "2026-07-10T16:30:31.773Z" },
{ url = "https://files.pythonhosted.org/packages/b6/63/5beba60f3bf645fbeb2aaa9cc1bf023f8651f13be24f2416d23b24594bbb/apsw-3.53.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:553ebc04cceb59ccaf8f601aeb9179ea0d55f8df29225c21442d2a762b50abf1", size = 3068584, upload-time = "2026-07-10T16:30:33.328Z" },
{ url = "https://files.pythonhosted.org/packages/af/db/245915afaa48e80e8d7d5d116f6beacf502712da98cfd008fbb17ba26496/apsw-3.53.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9a6fa83a0a8b01799b4ea42dc9940fc6821524c662fb926fe495e5004cec2b6d", size = 3489603, upload-time = "2026-07-10T16:30:35.047Z" },
{ url = "https://files.pythonhosted.org/packages/0c/f9/b04381832f56a27251fb0175172dc642bdf9cdc7f7f7e6ba62a68bc1e2a5/apsw-3.53.3.1-cp311-cp311-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:124fe7789ecec7149752c5e98ea0f5d63bc8c08d41faafbda400c240375b57f0", size = 3272699, upload-time = "2026-07-10T16:30:36.496Z" },
{ url = "https://files.pythonhosted.org/packages/13/1b/a47ec9ae1c353e348e5781a3e6c13de25114654a2664929dfdf4ce7c8ed2/apsw-3.53.3.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:c2f911bdb5a827d5d65d6f3e506d6fab55ca2bbc1969cbdfb0bff17d3c936847", size = 3888998, upload-time = "2026-07-10T16:30:38.164Z" },
{ url = "https://files.pythonhosted.org/packages/70/b2/37307c4c4f6130ee093db97191d1139d1280e4094f3168727820ee8ff59b/apsw-3.53.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f9135c7bc6bb2043375fb50503edc175ac11c6fbf4de25ede5807d928378129f", size = 3648680, upload-time = "2026-07-10T16:30:40.568Z" },
{ url = "https://files.pythonhosted.org/packages/84/c9/74bd2bc85448ed16a26f189d7f02098f3cc3aa2de9d7bc21e40c85129693/apsw-3.53.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3bea5d8a4fbd407c914fab0af6fc0a103a0b71f7f1c16a3d050487af90ee7edd", size = 3497886, upload-time = "2026-07-10T16:30:42.04Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b8/1c7b76779f3b64b896b37517249beffe164423f1c4ad667bf7b891731a5a/apsw-3.53.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:742edd743b03f6da4d08186d501507dc781013f9ec04c32216e3c1eb0e36a487", size = 3278323, upload-time = "2026-07-10T16:30:43.67Z" },
{ url = "https://files.pythonhosted.org/packages/12/68/13f1500cb77f5c093318bb1ec584c28c57d0672458903aed3669f589f9c4/apsw-3.53.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a8d9e38cb95e486f3f4e5ba43c632d5bd2d8a3c12c3fe9565c9dd15760f1e07c", size = 3907721, upload-time = "2026-07-10T16:30:45.095Z" },
{ url = "https://files.pythonhosted.org/packages/0e/51/8821b636403862ed9f7292c40ecb426b3e9463c66ca4ac8affb468bc453b/apsw-3.53.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:93bcee0bf0142abb552fc0ef4e8e2e634a0d98546af9457b2c7b0e71d65e0f3e", size = 3655451, upload-time = "2026-07-10T16:30:46.632Z" },
{ url = "https://files.pythonhosted.org/packages/25/32/d997f782d10327a4a48b41238abdfb2dad23053a56ba7e55cf3cc88db5ea/apsw-3.53.3.1-cp311-cp311-win32.whl", hash = "sha256:c36a0bf7823e53db4118bf7dfe39d363503ceb508cf601062fe91e6268c004e5", size = 2868741, upload-time = "2026-07-10T16:30:48.049Z" },
{ url = "https://files.pythonhosted.org/packages/3a/76/9e078db7f3d8b7a6790749155804f95ecf00f1450c315af7b031a27c6ea4/apsw-3.53.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:203c133e0435ad69066f8920b91d93b5ad20afa60814ccfa20bdffdd317a2c1c", size = 3260499, upload-time = "2026-07-10T16:30:49.825Z" },
{ url = "https://files.pythonhosted.org/packages/a8/e0/47c13c66d727556109a3569f0a8bcad0e86caea7a2e9a2bf79a2f0b29347/apsw-3.53.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:4a7e0ba1ec942a11edc1b03447832a5ad3332d32ac4e8635ca7d98a07722b6f2", size = 2868160, upload-time = "2026-07-10T16:30:51.274Z" },
{ url = "https://files.pythonhosted.org/packages/d9/ea/06e2f4372166990955822b9967d9f6342de37f66f632b629b5a906b8bfa2/apsw-3.53.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dbe5f966fbd2811caba537917ddc5cda00710eb8bf6e2d84ba993cc5b775a68e", size = 3271540, upload-time = "2026-07-10T16:30:52.839Z" },
{ url = "https://files.pythonhosted.org/packages/90/a0/7102083831244c08e08e1806caf167eac6439ac56bca0453406604896814/apsw-3.53.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d0561fe85559c32ca0bf4ec8d51289c4300dc79788da492f82325729a8e50ef", size = 3067549, upload-time = "2026-07-10T16:30:54.861Z" },
{ url = "https://files.pythonhosted.org/packages/dd/8f/0c3a6a0b0655158793a7ef855f4f6e9d076fea939322b4e66968c426e242/apsw-3.53.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2ccaad934046a63820f1bb3748d9f0889252aaad47c17022b57599f1d3ca24c3", size = 3480346, upload-time = "2026-07-10T16:30:56.584Z" },
{ url = "https://files.pythonhosted.org/packages/91/ac/e11a39fe22b175fef3018f6f68eb282e092b8c48a0976f8b535132a7ed4e/apsw-3.53.3.1-cp312-cp312-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f72e269032c9e66c2b86c2a68a524d54e5942d220ddf0e15c1363541be5cb3f", size = 3267797, upload-time = "2026-07-10T16:30:58.072Z" },
{ url = "https://files.pythonhosted.org/packages/ee/7b/790161e710f53fe1dfb8ae46b75b8862cf54447c4058b92382b9b94c9ded/apsw-3.53.3.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:d4a1211c154e7228254ea5f338d7efaf434c404975a64e746b10a83e35a775b3", size = 3879964, upload-time = "2026-07-10T16:30:59.512Z" },
{ url = "https://files.pythonhosted.org/packages/72/87/10dad311137cc6483b52a727c5556684b9d104d6c2f1642a18709e79a101/apsw-3.53.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7c5d4f736dcf9fe02c31fb3ce5d99268316537f1f808641ea09efa1b55bf1c2f", size = 3636959, upload-time = "2026-07-10T16:31:01.295Z" },
{ url = "https://files.pythonhosted.org/packages/82/29/4de0214db032b820d3df1c241c10f8f0f3e5633cff8f49d2e6249dc812b9/apsw-3.53.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c914f72fff9e9eee5363437e8c6830584463763d388d73315aedaf0a697162c", size = 3491023, upload-time = "2026-07-10T16:31:02.823Z" },
{ url = "https://files.pythonhosted.org/packages/d6/c9/2cfd4703f976c59b12a0ae56ab2988b26d01de1d2be483f6bdc4a7c81381/apsw-3.53.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8ff249ef948f696793f9e90c1f056181db670b116522c0257b313fa1f14bc3e6", size = 3276654, upload-time = "2026-07-10T16:31:04.207Z" },
{ url = "https://files.pythonhosted.org/packages/ef/14/c40f06a51835ed2630cbd93c109768590af369761c054dfe92b606145dc2/apsw-3.53.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2850122468691840f4165e87e922dd2d0df93abaa446fc53fd4e79e575a5b655", size = 3896547, upload-time = "2026-07-10T16:31:06.084Z" },
{ url = "https://files.pythonhosted.org/packages/11/69/aa792d1d15dbf18b7aed1cd596e6d226428093978a7f463dddb920ce51b7/apsw-3.53.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dfc32208563f9cef924a222011598b80ab4b50f326cac26ea79017d8d3cde48c", size = 3647566, upload-time = "2026-07-10T16:31:07.914Z" },
{ url = "https://files.pythonhosted.org/packages/89/45/860ee931ca14100770ef8202b8879919447256f97c8ec5e698e49a789774/apsw-3.53.3.1-cp312-cp312-win32.whl", hash = "sha256:b4f41bf8436c3b45e3c65b97a24df7328dae461b5fa580f16479cc8584a73472", size = 2868462, upload-time = "2026-07-10T16:31:09.34Z" },
{ url = "https://files.pythonhosted.org/packages/cf/58/dbc435be6e29d5f480ae5313d18ecf5530f9f14c06ec84fa8ad1b866adcc/apsw-3.53.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:9d398575194c5856c2543be29366c53044b920b46cfa0554130ca3e06428f515", size = 3258006, upload-time = "2026-07-10T16:31:11.274Z" },
{ url = "https://files.pythonhosted.org/packages/3f/7b/0de118dc9ec3eee0c672b43f4332893565fe61bfb73c1725f2691f20bc77/apsw-3.53.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:9bea63b524cfa3df2905d64e0a68c81d1bee4664e8034ef937ab0fc5bc541910", size = 2867313, upload-time = "2026-07-10T16:31:12.682Z" },
{ url = "https://files.pythonhosted.org/packages/91/a8/3377ef31ac0d94b5efd22a97ae9e558b0b6f440d573b2921947f9613b7ca/apsw-3.53.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:571ed8ebddcf5bbf5c8bd85b62463f4e21f5fee6a86bc4b0df0fececbd97247e", size = 3269180, upload-time = "2026-07-10T16:31:14.353Z" },
{ url = "https://files.pythonhosted.org/packages/2a/a2/505319294530cd2db21b962c6699e3909776250629a4695a50cac365b5c9/apsw-3.53.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db98126fccdedaf91e521a86ada3703f2a66d0ed4a6af727a8ddeb5b3e76db0d", size = 3064651, upload-time = "2026-07-10T16:31:16.02Z" },
{ url = "https://files.pythonhosted.org/packages/72/93/d4194de9e617bad8e2c9ee0b2f86d745f08160c6d2734a20e85217856a5c/apsw-3.53.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:0dc15a658720094b35485f7deaceae4fe35acf1b71f84ed1b032182efad83332", size = 3480557, upload-time = "2026-07-10T16:31:17.528Z" },
{ url = "https://files.pythonhosted.org/packages/40/d8/0b8c889219ec2d896a7f8e971bec670971608cff2d9d30088e970b90197f/apsw-3.53.3.1-cp313-cp313-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:33a3e077d0a884c14bee1888bb6765e1ce47e4b15aea7aa93e1413fa4612b9fb", size = 3269990, upload-time = "2026-07-10T16:31:19.169Z" },
{ url = "https://files.pythonhosted.org/packages/dc/fe/3a56dafc58542da094459ca31a9854fae29812e473b6eb362140ee428490/apsw-3.53.3.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:1843e7d0cf9f295eb814901af4ffede94331cbe976475f11975d6bab9b2253d0", size = 3873656, upload-time = "2026-07-10T16:31:20.799Z" },
{ url = "https://files.pythonhosted.org/packages/4a/bf/c78c0027998b676dbca06d0fe2d84e55cf4966f476cae22b2f7dd1ba38dc/apsw-3.53.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:396d6714df126fa8b8f615b10a3c6555a57d3ff7dba20a93dad27ae9c54ac3cb", size = 3642668, upload-time = "2026-07-10T16:31:22.445Z" },
{ url = "https://files.pythonhosted.org/packages/4a/f6/1bd97edbd78188be680a6e77850978fe76b790e3aabacf77b5d2c609b8c2/apsw-3.53.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:51eaf30e55565841757d2e0ec126b7891659a58dc24540f081b9370e20b3d50d", size = 3488793, upload-time = "2026-07-10T16:31:24.077Z" },
{ url = "https://files.pythonhosted.org/packages/ef/72/50e8e8e5b5d3ea2ee212827005cf541bab52d3b0b71144f00eff7ca3e5fe/apsw-3.53.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:095d16ccafe168056c1560ef22ab0554126ef60319ac66f033486c2d0b9e52a5", size = 3278993, upload-time = "2026-07-10T16:31:25.484Z" },
{ url = "https://files.pythonhosted.org/packages/a3/ef/e7e486aa107732140fa04fb520fc344d680b5668908a1d3a2c2a1521a744/apsw-3.53.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9c3a4ad302992dcbcda3ac15fed72aedd50263d44b649fb5088bd4c95c16c589", size = 3892083, upload-time = "2026-07-10T16:31:27.017Z" },
{ url = "https://files.pythonhosted.org/packages/6c/d8/b924d1e5e3166a882ccea169f521fa65bed6c566bd6bba094fe3eab490eb/apsw-3.53.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c8fceedd79fe94ff064630782211cce41760e4262ce0657aa9ad3f37ab7f451c", size = 3647261, upload-time = "2026-07-10T16:31:28.972Z" },
{ url = "https://files.pythonhosted.org/packages/cc/11/c8ceffd7cb17be2ee1e4dac546cc6119f11a7381e354a8d38bf336278b6e/apsw-3.53.3.1-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:153b9b61c8aeb614614d0aa975faf51b564b21174900a89f1b9be6b81a70913a", size = 1287735, upload-time = "2026-07-10T16:31:30.647Z" },
{ url = "https://files.pythonhosted.org/packages/fd/9a/81018a56e21aeb3886500147bb976768c3d2201be6eda6e6493eb9b34687/apsw-3.53.3.1-cp313-cp313-win32.whl", hash = "sha256:651e4724a8066b31a64af810cef1bf3b48141d8e01e2916adbd4a54fa7dc8d68", size = 2867376, upload-time = "2026-07-10T16:31:32.154Z" },
{ url = "https://files.pythonhosted.org/packages/18/88/a6651ae070478bd96e6bbb17ea7baac83fc25d60dfce5d114e6af2e5f430/apsw-3.53.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:db7bf119a66d7d8f5ac39a12393ae66fd0888f3190734094a12cc3dd3183a7ab", size = 3256103, upload-time = "2026-07-10T16:31:33.589Z" },
{ url = "https://files.pythonhosted.org/packages/9b/4e/c04a3322139e060b4d8dbba0f40e4bb88d7fb97b09155347b3e44f5b9c11/apsw-3.53.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:a6bf835864378dbaad030d33cb51911d33a6001652696791003f26262fcd23e6", size = 2865913, upload-time = "2026-07-10T16:31:35.123Z" },
{ url = "https://files.pythonhosted.org/packages/93/a8/b7bd647a1f735b8087de3ffb0e99b7dbd6a7782e596b02e16a59e4999e03/apsw-3.53.3.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:812316f207219acad5690c70a6d600532176f532d3910265c9ad3c9a5886b818", size = 3273332, upload-time = "2026-07-10T16:31:36.786Z" },
{ url = "https://files.pythonhosted.org/packages/43/99/32bc0425c6265d7d7ac9fae826e1087b4c18b20deb3b9c56c8ce517a72d8/apsw-3.53.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ad1fa6dad91167bee9b288ce0a1c7c0558035725de74247cc486e2f12d12ac5f", size = 3064955, upload-time = "2026-07-10T16:31:38.337Z" },
{ url = "https://files.pythonhosted.org/packages/c7/ac/a78e36d2f65a9ff3e82a58f1036585959bcc1f7dad0a6a2e675170c11c11/apsw-3.53.3.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:3f2567082005014407b8ac61c8463b0442717b3e87d340a8a1618f3f7d90ba2f", size = 3481452, upload-time = "2026-07-10T16:31:40.088Z" },
{ url = "https://files.pythonhosted.org/packages/4b/c8/f33adde9d43888736c33aa4f0ded9e608b27269e16487b85e4834a76ffc2/apsw-3.53.3.1-cp314-cp314-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6c0d24bdc5d5c5ad9046430f904d81b916a2c579c0dc392ca6aba8d793088758", size = 3268754, upload-time = "2026-07-10T16:31:41.707Z" },
{ url = "https://files.pythonhosted.org/packages/da/8f/87ab0a02b3f7523c7bf0afc322d03b325f60441e299828377a727b2db2f7/apsw-3.53.3.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:7286a7aeb4289434f3d192174b946dde69c31fcdbde447cd55fcf9540c378318", size = 3873968, upload-time = "2026-07-10T16:31:43.279Z" },
{ url = "https://files.pythonhosted.org/packages/03/08/1e51f630fb9767969cf5b2e5f240913597064df4831af798789c9e002006/apsw-3.53.3.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:3a07279328078fb9ef2f5609f39a673cd63966307d3bb553478b77b0f6a9c4e0", size = 3642823, upload-time = "2026-07-10T16:31:44.97Z" },
{ url = "https://files.pythonhosted.org/packages/65/56/8f16a60303c7cfffc9e4a2a9a96660a0bb29a0e8b2daf3e25f7b88611fad/apsw-3.53.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:affbb481b6fe565feb431cbfdc0b5290d162f5bb051570c77497d0ad252e8da9", size = 3490006, upload-time = "2026-07-10T16:31:46.787Z" },
{ url = "https://files.pythonhosted.org/packages/af/16/ee06a5247747e32a1b28257f2c7c501d34f376a7e6ed13f32e52afe2c819/apsw-3.53.3.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:fbd054520d28fe54a622b0b60e90c7320fc7f35c1fa157a5bbad098524a053d8", size = 3277186, upload-time = "2026-07-10T16:31:48.609Z" },
{ url = "https://files.pythonhosted.org/packages/b7/32/4e6a419bd2a67b9cf0b3b71bc267d4989df0bc18055336226e07bc7ac9d6/apsw-3.53.3.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:747f83a5801918548d131cc5921013ee757c8c9d02d465b7af8c4801b5948dd9", size = 3892041, upload-time = "2026-07-10T16:31:50.111Z" },
{ url = "https://files.pythonhosted.org/packages/87/c9/51f4b9345d042ada1e3ef996d6acdbd88b988fdc94f9d0e8d60a7fd2100a/apsw-3.53.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ab9ebb923106557cb047ad2deb785b0a7d06049568b8641c485f4c82cc942bda", size = 3647482, upload-time = "2026-07-10T16:31:51.927Z" },
{ url = "https://files.pythonhosted.org/packages/a7/45/93ea92d54192aead3ddba4f42a6d827f7c7d8de3d97a983f745ad1eec59a/apsw-3.53.3.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:e4950e2081de554ecab88ecf7308ac50c1dcd5dfd3d6123ffb0d5237f65ff69d", size = 2057919, upload-time = "2026-07-10T16:31:53.598Z" },
{ url = "https://files.pythonhosted.org/packages/0a/3f/921e3bb7a960beb363b8404fc8fecf5845c73a121b9f46fb3a4830ede534/apsw-3.53.3.1-cp314-cp314-win32.whl", hash = "sha256:bcf7eee33c6fa32574c951f5a23fe8eb1a9690ea90d1c972d603966a343b00bc", size = 2932950, upload-time = "2026-07-10T16:31:55.234Z" },
{ url = "https://files.pythonhosted.org/packages/8f/5a/6b7b9106d9fa0017830d7e14f5593ee3786572d8a5cfb27cf243b8d7ffb4/apsw-3.53.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:9ff7d9e888d5db192f6c58c32d2784177d86de31915936400971e515baf15576", size = 3339281, upload-time = "2026-07-10T16:31:57.38Z" },
{ url = "https://files.pythonhosted.org/packages/3a/bf/d6be2368091ed490f7fe537819f8056428c6d39a6b1015d979a0f2fd2a0c/apsw-3.53.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:e368521bea565fbd57ab426bb2be2d5dff14d8cdafb0baa6458769a1e776faa9", size = 2939544, upload-time = "2026-07-10T16:31:58.93Z" },
{ url = "https://files.pythonhosted.org/packages/86/45/f201b04e70674ad69e32f2a6d109fa6ab850fba5e0bd02b5341dba7e4ccb/apsw-3.53.3.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:fe4ce4f22cafa0acf293521e1d9d5e65c81cec7def5225c4feb7de2e992bb5d3", size = 3280322, upload-time = "2026-07-10T16:32:00.461Z" },
{ url = "https://files.pythonhosted.org/packages/6a/52/88486794cf1e0165dcb9fc177e39b3e761deee7beb5284495373aedc2496/apsw-3.53.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8a17cee2b62d3d97ebd3bcd990e31705592f196561e1b3e8a053315a97dc1ae0", size = 3076232, upload-time = "2026-07-10T16:32:02.383Z" },
{ url = "https://files.pythonhosted.org/packages/ac/47/9aa43af0d2c41501c14b0f71a6d89b2b80049cb366005e18c6dd63475a81/apsw-3.53.3.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3a9d4a3af69197224988d9b0b259d7debf411632c284a0a7387a834d3b1fbc33", size = 3454774, upload-time = "2026-07-10T16:32:04.121Z" },
{ url = "https://files.pythonhosted.org/packages/8b/a5/a44fda85bba494bfcf194e311b8f76b1f5bcb40c90b93462fb8843be9b0e/apsw-3.53.3.1-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f429900bf2be18a47ba710b5a1c25699a78fc591f72cb02b53ee4ddebb9bbd2", size = 3247305, upload-time = "2026-07-10T16:32:05.731Z" },
{ url = "https://files.pythonhosted.org/packages/0a/2c/dcbe09dacdfe7f9e1f041a8fb770348dbe7b5151f5be1c4911c3721b062e/apsw-3.53.3.1-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:0f352b9de362aa8b16d2abeabb91f72b07c66bd67b9579daa4ca68d6f6541071", size = 3844467, upload-time = "2026-07-10T16:32:07.405Z" },
{ url = "https://files.pythonhosted.org/packages/2c/40/53c59a2019f54e3f7f63b72215927739fa9ab690cde1950c828c990f654b/apsw-3.53.3.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:085849d26b775737c5bb8908f92313199e06007a291b5ac6c75197b295f31d24", size = 3617813, upload-time = "2026-07-10T16:32:09.276Z" },
{ url = "https://files.pythonhosted.org/packages/02/4d/c63cec22675e797a32a1c7bebad5e9f15bedef7e64717bf6ded29030dfad/apsw-3.53.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bdbf4a47b11ef22bf0aadfa6850422b033bd7973812fbefbe7d4823d13af4b3a", size = 3462436, upload-time = "2026-07-10T16:32:10.986Z" },
{ url = "https://files.pythonhosted.org/packages/ad/1c/6b6003c4900789e522a27b0464f911d810a4c0d09eafe23e3087cafdeb78/apsw-3.53.3.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:0d531f57a463d3aa190149369013483dfadd15f74d68a2f0d47dea1e99ee0a8f", size = 3254984, upload-time = "2026-07-10T16:32:13.078Z" },
{ url = "https://files.pythonhosted.org/packages/2f/67/56487885ea53724250b0125f4b71253f3499f1a37a480416fe1cb5f8e064/apsw-3.53.3.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ca4289629f3e9fd45a11dfd8c998f55f280f1946efb3f452740c6d384f96a709", size = 3862070, upload-time = "2026-07-10T16:32:14.982Z" },
{ url = "https://files.pythonhosted.org/packages/7b/0b/ee1f7dedeee7d73c0c94ffd2ac848f5f67e35605cbf8fcc643f6f18e902b/apsw-3.53.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6fc4312cd93a78599bab45bbe661b3907e95e115795ddbea8aaf43d2d5a6432e", size = 3623454, upload-time = "2026-07-10T16:32:16.838Z" },
{ url = "https://files.pythonhosted.org/packages/ec/66/a0f2532dd06637d30d0d43ff778646c6ff966a42960151301f16519c95d3/apsw-3.53.3.1-cp314-cp314t-win32.whl", hash = "sha256:1c5ab8bbea3df033f34def748f9a8d42a92d937502e300b1f288a6c62cf88171", size = 2938713, upload-time = "2026-07-10T16:32:18.474Z" },
{ url = "https://files.pythonhosted.org/packages/2d/b5/7372979ac8b239e573b3d98e603224f0328675662476766f5d8aaeaebcd6/apsw-3.53.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:3d3493f35c859f6eaa3bab88ff844c2d20ece21494b67a1949d1a7924dacc60f", size = 3345300, upload-time = "2026-07-10T16:32:20.053Z" },
{ url = "https://files.pythonhosted.org/packages/69/99/2a7190c33945ae37f9f9b45193674d75547748f2e472c0aecac844955c11/apsw-3.53.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0ae765e0d6f2aaa1c35f11a4cacc6055d89a965f9e531ab20a63193a09c3a86d", size = 2942462, upload-time = "2026-07-10T16:32:21.759Z" },
{ url = "https://files.pythonhosted.org/packages/6a/ff/2104f2185dc6ef7b938ef304391a69ed84f70e3d084b072e0cc6e30b1982/apsw-3.53.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:94fab7525b77af4230a4e406c6c8dcc0dcf25eac91a1975c75706e4806d28915", size = 3276362, upload-time = "2026-07-26T17:00:17.901Z" },
{ url = "https://files.pythonhosted.org/packages/d1/1e/6309acfb8a0c59c549c9254a25e576a5122bb0b427e0ec4749a41663102d/apsw-3.53.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:041b362eb1efbedae8eb869b51902590d4b44b0625c7d0e44b0b0b1e7ff79978", size = 3072437, upload-time = "2026-07-26T17:00:19.731Z" },
{ url = "https://files.pythonhosted.org/packages/af/f3/1909e2b2b30e1315ae27324ea272fc807eb6e3ca08930ac70ad29c6b58da/apsw-3.53.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:149fe6f761456ceb2b9f4c8b9c33dad9142544e6417267477b7a9d5b93da70e5", size = 3495567, upload-time = "2026-07-26T17:00:21.924Z" },
{ url = "https://files.pythonhosted.org/packages/4a/b3/a7940c3467d446058b9148104d1ec5f84143dc36ed83e708fda950101d0c/apsw-3.53.4.0-cp311-cp311-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95d2a5172d7b164c11a9b92c584bced9ddecbf963ad71432951b92b0de903d71", size = 3277157, upload-time = "2026-07-26T17:00:24.402Z" },
{ url = "https://files.pythonhosted.org/packages/49/c7/faa176008718cc8f28e0575f48c54fc76c64ed2e9986ed436493383030c8/apsw-3.53.4.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:a6a85e6b3f896bcb9625e9b321947fd50f0e84627dbf0541e46b2fad151137fc", size = 3889258, upload-time = "2026-07-26T17:00:26.23Z" },
{ url = "https://files.pythonhosted.org/packages/a6/cc/bbe97dc8d32f417c3cfc22b942b271ef41c5a04ee530873555bf1e7b737d/apsw-3.53.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cca0a8a4498a355326fb491d852187c2fd2031d3e61925e349ba297d3ab884f4", size = 3652275, upload-time = "2026-07-26T17:00:28.073Z" },
{ url = "https://files.pythonhosted.org/packages/95/e0/1084c69b5751f35398465234de0a6c43bcbd4ff65f347426d4ecbd47e10c/apsw-3.53.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:41bbbee759cd44b2053d0e8d071decca705116c085c9d0a15e8060f076510a3e", size = 3501963, upload-time = "2026-07-26T17:00:30.162Z" },
{ url = "https://files.pythonhosted.org/packages/1e/16/791cef08d0e42f2e1f005a0c95f2be3e8980a1c6626b45000eb3db608c70/apsw-3.53.4.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6f5370dbd4467fdbb8a4188604a85e235a5efdc16a8340a7c9cd38d3866a908b", size = 3285048, upload-time = "2026-07-26T17:00:31.961Z" },
{ url = "https://files.pythonhosted.org/packages/38/b1/511ff4cab157aeca41236fa1cabd954c583fc67e4c37011165bb7d272763/apsw-3.53.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b50af311ea4d32595bf403488e247093dfa470d267f0b1959cb252a716f5c9d1", size = 3911568, upload-time = "2026-07-26T17:00:33.839Z" },
{ url = "https://files.pythonhosted.org/packages/00/a2/f29bc46d1c49db331ec74c175046db40286b059598abe98565e0bb5ad0f7/apsw-3.53.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:44625dda9965e1f0a839f86191f9de14f34782789e4b3e9984609644bd5c00d2", size = 3662083, upload-time = "2026-07-26T17:00:36.373Z" },
{ url = "https://files.pythonhosted.org/packages/1e/44/7e6782e9a156e97b10d276e0bfac293da43d8388fcbf2633da1bf9da4f07/apsw-3.53.4.0-cp311-cp311-win32.whl", hash = "sha256:ac462dff754a62576872aba41921bad0f2a60b43e51811af54417e6cf01e3ce8", size = 2869944, upload-time = "2026-07-26T17:00:38.222Z" },
{ url = "https://files.pythonhosted.org/packages/8e/2f/da9f140adf3d8ead286f6d6fa86c2dfc07c1b32d3384476b7c5cea97de8a/apsw-3.53.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:371efde8c6cf0d278cb9e17848ddb637e5b40fa3f86bcfd57786cc26869608aa", size = 3262509, upload-time = "2026-07-26T17:00:40.277Z" },
{ url = "https://files.pythonhosted.org/packages/5d/9c/2a91da813cb737114743b8fa3ce55f0137b452b441028ea3b130d06e19b3/apsw-3.53.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:8a2956739873f76c1f8aa3fb0ec6933dddcc648524d3a8677a63c4dd4b7d7418", size = 2871335, upload-time = "2026-07-26T17:00:42.313Z" },
{ url = "https://files.pythonhosted.org/packages/11/28/73ec4710ba5e082d798fec2ceecf23bd982a02dbb2c4d587e8bac461e0cd/apsw-3.53.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8cfa9ad1dd459d453bc7bc0b2beb2aa27f326822f0301ce1a903be1e0ad004b2", size = 3274865, upload-time = "2026-07-26T17:00:44.616Z" },
{ url = "https://files.pythonhosted.org/packages/cb/c0/305bb71b2ea948a9d67c1c896a6beac39410784ae9fe7f56cb4f1a8f79c5/apsw-3.53.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:838dff7f0a360837dd5d480afbc818aeffa3decd83c81a39ac47cece7956fcee", size = 3071079, upload-time = "2026-07-26T17:00:46.421Z" },
{ url = "https://files.pythonhosted.org/packages/d9/bd/520cfc025a80c11fd7c2de0c2361ce4ec39dff822888585c2ba333110016/apsw-3.53.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:4760a026284318d5de6937a14add0d03b194ea60bf67fb51bdd28b541a249229", size = 3487559, upload-time = "2026-07-26T17:00:48.298Z" },
{ url = "https://files.pythonhosted.org/packages/28/d0/8047da77dd539c6572155ed27351429aacf3a805b5fbaf7c124ef251c4e7/apsw-3.53.4.0-cp312-cp312-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4a41a246474ef12a1d4f1b8b87866a4deb8384047df70f5867018a6603e7fac", size = 3271959, upload-time = "2026-07-26T17:00:50.42Z" },
{ url = "https://files.pythonhosted.org/packages/7f/47/32f062791b5959fd645d181deb22165f8ff7727dc3edb4042f2f2a7d1e22/apsw-3.53.4.0-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:8a5a722b4d544d2eddd559556424fa40b3206542591fa4563bb6a58432b362c6", size = 3885163, upload-time = "2026-07-26T17:00:52.31Z" },
{ url = "https://files.pythonhosted.org/packages/bc/20/c83561b62be054bc0d04216b7d1cb037c4d95078a8250a062a61bd1a6659/apsw-3.53.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6c47c64ca9c2fac2b476317210b6e8c04681fb718594c0806bd33e5d2b459dff", size = 3642941, upload-time = "2026-07-26T17:00:54.135Z" },
{ url = "https://files.pythonhosted.org/packages/00/8e/31ad0360475f5dd41d1290b2744e79dfdfd661a362943486193a32683f5d/apsw-3.53.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:30b107e27947d366f5b3300feb624b39338448211a4e5cd8ee0d752baa9481fa", size = 3495940, upload-time = "2026-07-26T17:00:56.238Z" },
{ url = "https://files.pythonhosted.org/packages/da/bd/52202d244f1f9cc122767222281afc61d444d01e0182567ea0e80b857882/apsw-3.53.4.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7718908b72f95f18091f723918eab4a4f0a3405a92d0a64a38371e2727e79e41", size = 3279799, upload-time = "2026-07-26T17:00:58.078Z" },
{ url = "https://files.pythonhosted.org/packages/aa/7e/54b5a69cb7673a3a2097152b6b70f11157efff76b3fb2453cbd328439147/apsw-3.53.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6f7b80f70d04e5f03b29a16db810b414c46e097434ba892741424c89db359c43", size = 3902688, upload-time = "2026-07-26T17:01:00.028Z" },
{ url = "https://files.pythonhosted.org/packages/7b/f2/ce4e0c6fc2d439c23afab00313de135fc645d73b4e4b59a1b98afb6d5176/apsw-3.53.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b729ec8df6cd0010f174a21c18e0315bc748800709176d3dd7e14d7a8aeeb6f", size = 3648627, upload-time = "2026-07-26T17:01:02.208Z" },
{ url = "https://files.pythonhosted.org/packages/18/eb/0fe9a1609822e157d916af4228975af564371e0e1614438569c15d8b4d92/apsw-3.53.4.0-cp312-cp312-win32.whl", hash = "sha256:0b162856ab66bdc7424b9d9c34e686d827a6fcea32363d649af2cf447bf27c36", size = 2869690, upload-time = "2026-07-26T17:01:03.979Z" },
{ url = "https://files.pythonhosted.org/packages/3b/20/68b4e3e7d6d5356f65c5ccd1fe536030cb93e2f4ad939d45142afbc86deb/apsw-3.53.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:88856d0bb0271fcb98706bb5b3c82a5e7d58f7ce649a4757fdcf8cf1e889e191", size = 3260322, upload-time = "2026-07-26T17:01:05.849Z" },
{ url = "https://files.pythonhosted.org/packages/f5/b2/377efb9671affd3c8aae77fe37a538cea62132ad367fa68ac8a3f9103ba6/apsw-3.53.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:ad5ead1a56415f298f31559c760587b2f24105904adfab72650ecc76c9886fa1", size = 2871089, upload-time = "2026-07-26T17:01:07.659Z" },
{ url = "https://files.pythonhosted.org/packages/8d/e4/a169c63cc6448598999acee33c112c2015e41b5a27374d16feed43e74ed1/apsw-3.53.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbb3cfe03751db6a2f29e938017e11851c93fddca1ac4f78287faceba4d24059", size = 3273128, upload-time = "2026-07-26T17:01:09.422Z" },
{ url = "https://files.pythonhosted.org/packages/c7/25/20e73a120820f81df1c7d31f39d0bbfe7b4a147250fa53875f25d4a554b4/apsw-3.53.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6ec42090ec4150ad35b9e70d6bc7ee15554c268ac495cfbf0761c6a3d46edc6f", size = 3068202, upload-time = "2026-07-26T17:01:11.443Z" },
{ url = "https://files.pythonhosted.org/packages/58/27/c791001d0380d9ed6fbb34e6975546fc0dbd6520aa88b25eba2c22033120/apsw-3.53.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:0b5ccae16a9efdeca6fdbbe91330e73530782b4d98ee1c20054ae0b72efdabf3", size = 3484996, upload-time = "2026-07-26T17:01:13.41Z" },
{ url = "https://files.pythonhosted.org/packages/ff/5f/5576c0b37dc21ac9ac98003b71fa846095df8b63120ea2699a78666cc923/apsw-3.53.4.0-cp313-cp313-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4855c9115f87548fe608553262e07def3b51633b9995e3301cd3254f9cba394b", size = 3273626, upload-time = "2026-07-26T17:01:15.324Z" },
{ url = "https://files.pythonhosted.org/packages/22/cc/9e9a5f58a567011da14f6422ca95dd039e16e1f898d3f87878ee28d90e52/apsw-3.53.4.0-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:950f12259890c3fed24219a5219bcf1d98dedcbf258eb43bda218b919466d143", size = 3878816, upload-time = "2026-07-26T17:01:17.817Z" },
{ url = "https://files.pythonhosted.org/packages/34/bd/96c6c932c8c13a1440c3a166bc53a24c967aef68af9ef687a08d9232fc41/apsw-3.53.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6c262ce950cbd831b52fffd0e39e5ca4bd6dc60ce048d0d6e44dae7204634a9", size = 3647879, upload-time = "2026-07-26T17:01:20.134Z" },
{ url = "https://files.pythonhosted.org/packages/63/28/43bf60a2e28f762a62a59e3e32feee9aa1a6ae89c0309bb9fcf1640edf5f/apsw-3.53.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c800584d288c8430fa242e9f5fccfd904c129e11821da6ca6f2180f98c30ceb9", size = 3491830, upload-time = "2026-07-26T17:01:22.023Z" },
{ url = "https://files.pythonhosted.org/packages/dc/46/c59d988953314fc032f6ba4450370a84f049fc3381cbfc98fd55aa01845c/apsw-3.53.4.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:943ab632e41663f4187f383497d280a6ca91114861f1b4fc37dbf8c84c392d4f", size = 3283430, upload-time = "2026-07-26T17:01:23.938Z" },
{ url = "https://files.pythonhosted.org/packages/ab/f8/9aed8933e27bca04a85ffe61dcbdab93cf81c9e123146aac4db30e941804/apsw-3.53.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9d46f4f9d45911f413fb21745c34a645984683442372dc45ae80c3c43c08808b", size = 3897090, upload-time = "2026-07-26T17:01:25.934Z" },
{ url = "https://files.pythonhosted.org/packages/0e/33/c0764bf546497decddb6799ec7eee4f4881746c1a9f671dddb8f763b955a/apsw-3.53.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bdebb5495c6cf734c4355c99c976d85a58dfeb08083e5b8be263ed7faef799de", size = 3651496, upload-time = "2026-07-26T17:01:28.03Z" },
{ url = "https://files.pythonhosted.org/packages/c6/15/2487f5f87c8a9907d27788226d81d9309089b27b71d0d20fffe61d5b11ab/apsw-3.53.4.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:36d6605ae4d3447385fa0e81d66f854dd88b18c853d85b22d0016e611a0c99bc", size = 1290543, upload-time = "2026-07-26T17:01:29.827Z" },
{ url = "https://files.pythonhosted.org/packages/e9/00/960c37c94b2ccd0bb076cc29d9e0d65cf11bc322abf5f32c437540cbd623/apsw-3.53.4.0-cp313-cp313-win32.whl", hash = "sha256:558be4a9ee48a9479732b011ea1fc068144ceb718223fa83ec20ba6ee930ccab", size = 2868522, upload-time = "2026-07-26T17:01:31.642Z" },
{ url = "https://files.pythonhosted.org/packages/36/d6/c2cccba0fc9569778edc2afd639a5f6a58966289968ae3496281f3a54d3a/apsw-3.53.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:ac1b011f3301c6fbe51c4ccc43ceaab74266adedaf00e7d96acbaa38f3377835", size = 3258302, upload-time = "2026-07-26T17:01:33.419Z" },
{ url = "https://files.pythonhosted.org/packages/a0/1c/fd4176c52fa00077d3c05d299e9525041f6b43f0f65481cdc0298e432756/apsw-3.53.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:a078375b48bfe1f6c49a8dfc9697c73c9bff0e1de30542099691f8f209896fba", size = 2870159, upload-time = "2026-07-26T17:01:35.415Z" },
{ url = "https://files.pythonhosted.org/packages/b1/91/45cab4c186e972d45a30afa3da012fcfceb98eb1dff1cc0f67b65619815b/apsw-3.53.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f3dd4186c80bdddfd4ba4cc1edd88f87c0c7cc03bf92f2b69e00c08958fe2d7d", size = 3276963, upload-time = "2026-07-26T17:01:37.272Z" },
{ url = "https://files.pythonhosted.org/packages/ef/8b/eaf670872391c36d805ddad114a22ed366af6f8d9e706b5d65db96e07855/apsw-3.53.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c4648b0954c021c2cd3f4498e70a9d0ba5bc46aaa2a737dc110a317e47df493d", size = 3068586, upload-time = "2026-07-26T17:01:39.141Z" },
{ url = "https://files.pythonhosted.org/packages/d3/d9/79ec37e57e3b7fed286ba7ae7136512efe32e9b65010b7d850c160615983/apsw-3.53.4.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:8665b7e10bb97262bc821444469c0ed60bd039f5a2236dacb362e160a4a66097", size = 3485943, upload-time = "2026-07-26T17:01:40.967Z" },
{ url = "https://files.pythonhosted.org/packages/d5/9a/891e4377a314ac0fbecd7bf57701fc5a8a3bede543112a09eab1f579a89c/apsw-3.53.4.0-cp314-cp314-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7bfe8f1eb0efbdb61005447e73affa6f9339f509bfbd565e9bee8f33ec5904ed", size = 3272853, upload-time = "2026-07-26T17:01:43.006Z" },
{ url = "https://files.pythonhosted.org/packages/28/cd/42cd9abcd5b957957b727a4f1b21232d498a3c4e35f594207a798e8b080c/apsw-3.53.4.0-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:6b6c56c56006bc9593fd701df59b9a851b6143d45f7f447e65490658e53e4e38", size = 3878935, upload-time = "2026-07-26T17:01:44.902Z" },
{ url = "https://files.pythonhosted.org/packages/14/5e/aeacd13a10cbdc0e25974b6415105fd6ce06a1e09c412345d98a830aa14f/apsw-3.53.4.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:979f69f2ade92a2afd2f67208217cf2ba174e237f7edc936ecd5af28340a463e", size = 3647954, upload-time = "2026-07-26T17:01:46.874Z" },
{ url = "https://files.pythonhosted.org/packages/8a/93/8e85352f7a9d78994398bfc26d8f963618fc9cdfda3e9d00c320b798775c/apsw-3.53.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:248060079ea0a8df3844f659e9c9ee41eb29ce7761b6022105c6968691e65259", size = 3492368, upload-time = "2026-07-26T17:01:49.063Z" },
{ url = "https://files.pythonhosted.org/packages/12/cf/c06c8bc7c05908f2f50034a880aff32aa9b2cf6cf73f9dfa875ae70050dc/apsw-3.53.4.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:62945882058589d3f10e588beca18cbe36aa91eaa4e9961ca74cfd7278a69c01", size = 3281281, upload-time = "2026-07-26T17:01:50.923Z" },
{ url = "https://files.pythonhosted.org/packages/eb/67/e526700aa56e4ea5644c838117dfd052c3e346ca27add8884dd600f30a3a/apsw-3.53.4.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:df343db6af8a650ca7fff0b06eb20f05c964332d0d1cf5706b7e7e6f849a8b3b", size = 3897081, upload-time = "2026-07-26T17:01:53.064Z" },
{ url = "https://files.pythonhosted.org/packages/5b/8b/2f75600f5d07024b843f7f24fa988e85feabf6c5fff69a21f89110ee8478/apsw-3.53.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d9e13967e93e2db2245ec7537ea3ba9e00808585cc6199a08dc649b702ebce01", size = 3651198, upload-time = "2026-07-26T17:01:55.396Z" },
{ url = "https://files.pythonhosted.org/packages/42/a3/e345e657733da9abac746f749c88332f3742e6ac13011d34c56f852ba7a3/apsw-3.53.4.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:d08a97ddbbdde8a6ed3e631e8d7ca5f867d930a0dff2e2d800b3fe7540430f2c", size = 2060960, upload-time = "2026-07-26T17:01:57.515Z" },
{ url = "https://files.pythonhosted.org/packages/12/f4/379cc0915a5a74033372f63631e62a38362e98b9d3487a5cbe4e6f25b3fc/apsw-3.53.4.0-cp314-cp314-win32.whl", hash = "sha256:94d8e664e1b9f89dbc8635d7c7a5acff85332bdd058496c0bbb1c111b4dbcfb4", size = 2934388, upload-time = "2026-07-26T17:01:59.428Z" },
{ url = "https://files.pythonhosted.org/packages/f6/4b/e96293894d6c50e85078533c691977abb8b400ddc3b7b51f92ff04abb6ca/apsw-3.53.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:13bd0c01cada861ce9cd4a09ff36c5a245185477c5fe6ce52d266c46e69f76e5", size = 3341532, upload-time = "2026-07-26T17:02:01.232Z" },
{ url = "https://files.pythonhosted.org/packages/6b/22/473ba189dfa18e08839e2dc8fa9eb5567ae1b4544bee798cc284fb483456/apsw-3.53.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:cdbea67df0482681970bb4cf668252e405572fc4b582e8cfd860b5a29fe75cf0", size = 2943661, upload-time = "2026-07-26T17:02:03.762Z" },
{ url = "https://files.pythonhosted.org/packages/19/34/2544374bfceed0ea366d00920357956ff955c3843d6098f09ac0162b61d8/apsw-3.53.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e2a194578d8f2508c6a73e18d640fdfe5b2b351946d99082ecb72d855e50ea0d", size = 3283551, upload-time = "2026-07-26T17:02:05.921Z" },
{ url = "https://files.pythonhosted.org/packages/17/7a/1c15f983b27506e68e361a7acb8ce3ab19e3ac91e28f56b208736c6b1000/apsw-3.53.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f0ecabb9e586d54d13edf4336af929a026b8c741aafdd0d98f252c6fc536d726", size = 3079475, upload-time = "2026-07-26T17:02:08.205Z" },
{ url = "https://files.pythonhosted.org/packages/47/48/7ecf4b60d37909cc190d4e88068fa8b39d3e2854033594b3c14b9a7b733c/apsw-3.53.4.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:647b97ceebfe805dc75df6dc513557b9ac0e513983bd234458ead0e0522fd2cc", size = 3459327, upload-time = "2026-07-26T17:02:10.073Z" },
{ url = "https://files.pythonhosted.org/packages/bd/a7/b3f19abe08c968549b9257d6063042c6e62f1edd0ba0b0c7323e340f4f2f/apsw-3.53.4.0-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1daf038c76267e1255baa870849f604f1bc59847083f46736574abd530dd4a39", size = 3251767, upload-time = "2026-07-26T17:02:11.954Z" },
{ url = "https://files.pythonhosted.org/packages/dd/44/b9091a5987aadbfef7b868b8db726e2e257e1f5e1f659530505484b682d9/apsw-3.53.4.0-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:8eb911c4c5fd03ed42b58153829aadde25196ef24d5438c3ff3009bb97210fd7", size = 3851612, upload-time = "2026-07-26T17:02:14.035Z" },
{ url = "https://files.pythonhosted.org/packages/d5/e1/e8363c0928a3b58aac1d1366a3c9af12c7b643d66520de17c51ee4ffdb98/apsw-3.53.4.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:997ea4a591459346ad69ed98fb7a627a01f49ea08d220a113cbb8caf34ca4e50", size = 3619428, upload-time = "2026-07-26T17:02:16.011Z" },
{ url = "https://files.pythonhosted.org/packages/24/e4/296804fb293fd56dbe71177335f3533c38fba6b02d13f9034e48ebd6bf12/apsw-3.53.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f3fb92964281dee49392081be15668fa11f9c638b01c2388517ce4ffff6c3311", size = 3466325, upload-time = "2026-07-26T17:02:18.35Z" },
{ url = "https://files.pythonhosted.org/packages/26/4e/e87612aa2801371f29b4340b8293cec65f2608ee47f62db99400f6a0eb8f/apsw-3.53.4.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:6fadc24dfd89a4e6a1ea47536bbab5034276ff50a18e1497095a7a3a2794e7c1", size = 3258161, upload-time = "2026-07-26T17:02:20.275Z" },
{ url = "https://files.pythonhosted.org/packages/f8/f8/0683aea08504cec093a2fc37219c27af99f19006bea201f1335c915e582d/apsw-3.53.4.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:7dcf83f5bf8ffacdd1ad5254322e157e426f73d8fcdafdae3e3cfc9f242f9e17", size = 3867595, upload-time = "2026-07-26T17:02:22.466Z" },
{ url = "https://files.pythonhosted.org/packages/b5/6f/354feb0e13501f911db790e1a6a50564a2996e36373a80d572803a2281fe/apsw-3.53.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6eda7f8e79e5729c6ca0e9aa84cb2826ce0aa63257324a3066c78c8fa46d1b66", size = 3626999, upload-time = "2026-07-26T17:02:24.579Z" },
{ url = "https://files.pythonhosted.org/packages/1c/91/e775345045b3e8de025506a7a4ec2f4a800a9dded6fdaa5d41becadbf8f0/apsw-3.53.4.0-cp314-cp314t-win32.whl", hash = "sha256:19c8fb1b23a0ee58c31c6241022f1fac080025c924eac0069be612d1c49ad7c7", size = 2939728, upload-time = "2026-07-26T17:02:26.461Z" },
{ url = "https://files.pythonhosted.org/packages/28/a0/be6f4d469d1811ed48b59b4f0fe77cbac8c313c01e8b279950d7eecec247/apsw-3.53.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8feaa19aeeac9acf984e5ade28478e44ae6c1cc3e03b423f8d66fdb4eb1a5bdc", size = 3347464, upload-time = "2026-07-26T17:02:28.394Z" },
{ url = "https://files.pythonhosted.org/packages/24/f9/a9ce9fb4a6d54fad8dc2303e20700a5056465ce9dc79e09014d1c5467ba3/apsw-3.53.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:7ed2b82e0b5d57c61c8f0cba91ce01d68a061cbea483a53b19f42ecc4ab6cb72", size = 2946837, upload-time = "2026-07-26T17:02:30.458Z" },
]
[[package]]
@@ -1010,11 +1012,11 @@ standard-no-fastapi-cloud-cli = [
[[package]]
name = "fastcore"
version = "2.1.5"
version = "2.1.16"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2c/83/81349cd1cb156b1737431ef6f3fc3065b4c2f94729bf2e10620c29c36699/fastcore-2.1.5.tar.gz", hash = "sha256:e029a2231e826c38bc02be4a179ab85737d8eeabe9c54d4f54a7ee77e721f1eb", size = 113991, upload-time = "2026-07-22T05:42:32.075Z" }
sdist = { url = "https://files.pythonhosted.org/packages/22/e1/62ffb49e24033c63ffef0d2fe9f415b0f1d0164eb6667512a3c245602a3f/fastcore-2.1.16.tar.gz", hash = "sha256:aeeeab05bb28913af04a682d7bb093dcb59f354145a69fa9498cb4a503cd2039", size = 131479, upload-time = "2026-07-31T02:45:44.49Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/d6/a660226b0770c5d4a39d5964a5e00745dc5ca25fa9d9e7948e911c30c3c3/fastcore-2.1.5-py3-none-any.whl", hash = "sha256:612a1084f039a4f65695713f62d411dfa5b9f5f4f8d767ff999b7f6c65a29bd7", size = 119006, upload-time = "2026-07-22T05:42:30.619Z" },
{ url = "https://files.pythonhosted.org/packages/d5/3b/dd7ca0fa89032745eb2b3d51aff3ba42b8c8f18e0d57682f24f973073260/fastcore-2.1.16-py3-none-any.whl", hash = "sha256:4a4a535af01b8792e34ad630086556ffdffc85af8f4c4accdde8cb2ab1e3edff", size = 137613, upload-time = "2026-07-31T02:45:42.934Z" },
]
[[package]]
@@ -1032,11 +1034,11 @@ wheels = [
[[package]]
name = "filelock"
version = "3.32.0"
version = "3.32.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c0/80/8232b582c4b318b817cf1274ba74976b07b34d35ef439b3eb948f98645a1/filelock-3.32.0.tar.gz", hash = "sha256:7be2ad23a14607ccc71808e68fe30848aeace7058ace17852f68e2a68e310402", size = 213757, upload-time = "2026-07-21T13:17:42.898Z" }
sdist = { url = "https://files.pythonhosted.org/packages/f6/57/3ba6e6cb097f85b855b00163d169f35365f44277df044dcf96d55b8f62a3/filelock-3.32.2.tar.gz", hash = "sha256:c33351e1f49cae33414acbc6d56784e6ecee82514ec90795da1161fc4836b5b8", size = 217172, upload-time = "2026-07-29T22:46:04.895Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/06/79/b4c714bef36bc4ec2beeae1e0c124f0223888cd8c6feb1cdc56038116920/filelock-3.32.0-py3-none-any.whl", hash = "sha256:d396bea984af47333ef05e50eae7eff88c84256de6112aea0ec48a233c064fe3", size = 97732, upload-time = "2026-07-21T13:17:41.55Z" },
{ url = "https://files.pythonhosted.org/packages/c1/e8/72f8cef9fdfeffe06213fe8508039396ee48daa0e3259457ed766173bfd6/filelock-3.32.2-py3-none-any.whl", hash = "sha256:87dd94cf281e586d135fa51132b8e3d9a598b316e90377a288663c9321036c82", size = 98830, upload-time = "2026-07-29T22:46:03.52Z" },
]
[[package]]
@@ -2379,14 +2381,14 @@ wheels = [
[[package]]
name = "prompt-toolkit"
version = "3.0.51"
version = "3.0.53"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "wcwidth" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" }
sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" },
{ url = "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl", hash = "sha256:01c0891d7f9237d5e339f7d3e42cdae80b7534abb1c7c0e3352efba6231492f2", size = 392288, upload-time = "2026-07-26T20:56:12.512Z" },
]
[[package]]
@@ -2605,6 +2607,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
]
[[package]]
name = "pypdf"
version = "6.14.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/03/72/7dfd5ff1c9c37de97a731701f51af091325f123d9d4270361c9c69e4431f/pypdf-6.14.2.tar.gz", hash = "sha256:7873f502fe4385e79539b21d872392dc0c4e3714327c15881cbc7fbfd1f95b25", size = 6491182, upload-time = "2026-06-23T14:18:30.859Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/e6/136aa8993a2ae7214e0b0ef2edaa0d2e08d1d4e4982635b08a835ff31ec8/pypdf-6.14.2-py3-none-any.whl", hash = "sha256:3f07891af76dc002657e04993ab9b4de81de29f9013b9761d0b7968bff12e946", size = 349514, upload-time = "2026-06-23T14:18:28.867Z" },
]
[[package]]
name = "pytest"
version = "9.1.1"
@@ -2727,11 +2738,11 @@ wheels = [
[[package]]
name = "pytz"
version = "2026.2"
version = "2026.3.post1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" }
sdist = { url = "https://files.pythonhosted.org/packages/fb/48/fb042503b6ca6cd271261dc559fd6432f7d8c713153e9ec5c591af4dfc1c/pytz-2026.3.post1.tar.gz", hash = "sha256:2211d3fcf9a797d3405cac96ac7f61d80e6a644f72a3309607282fe8a2010c5d", size = 319745, upload-time = "2026-07-25T15:12:07.385Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" },
{ url = "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl", hash = "sha256:dd95840dd199baea12d9cc096a1d452caa6596a1c1e4b5f3dbd1541855d5e815", size = 508283, upload-time = "2026-07-25T15:12:05.782Z" },
]
[[package]]
@@ -3441,7 +3452,7 @@ wheels = [
[[package]]
name = "virtualenv"
version = "21.7.0"
version = "21.7.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "distlib" },
@@ -3449,9 +3460,9 @@ dependencies = [
{ name = "platformdirs" },
{ name = "python-discovery" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fe/25/e367a7229b0914772ca8d81b41fde012d9feda68523b52644a571bb21ce8/virtualenv-21.7.0.tar.gz", hash = "sha256:7f9519b9432ff11b6e1a3e94061664efc2ff99ea21780e3cf4f6bd0a5da8b37c", size = 5527510, upload-time = "2026-07-21T13:12:14.109Z" }
sdist = { url = "https://files.pythonhosted.org/packages/ea/fa/18004e5cb15541ad2a68ff219c755233b012b12d4ec8663d06a258082bec/virtualenv-21.7.1.tar.gz", hash = "sha256:d0dbfaa5483487baea28d7210ef8d24c9d1bd0f10f449eeb215568825a9b334e", size = 5525237, upload-time = "2026-07-30T15:40:36.36Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a5/7a/ae29312b1e88a22e81f5d21fc11526d2a114089776c2550d2b205b6c2a47/virtualenv-21.7.0-py3-none-any.whl", hash = "sha256:a8370c1c5530fbabf955e40b8fbbc68a431648b10f9433faa587db30a06e51dd", size = 5507078, upload-time = "2026-07-21T13:12:12.136Z" },
{ url = "https://files.pythonhosted.org/packages/4b/a7/ded126c19495158a05c7202b3389139839d4cf78d622d453867778e0f7a8/virtualenv-21.7.1-py3-none-any.whl", hash = "sha256:6394973f990536e34c05157179146c020284c42fe01da1dfeb0ba16c345280d9", size = 5504576, upload-time = "2026-07-30T15:40:34.512Z" },
]
[[package]]
@@ -3569,101 +3580,117 @@ wheels = [
[[package]]
name = "websockets"
version = "16.1.1"
version = "17.0.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" }
sdist = { url = "https://files.pythonhosted.org/packages/f7/96/e01084f83a64bcb3a27994bd0cb0db68ff29d9c6707fae37ec19b18ba990/websockets-17.0.1.tar.gz", hash = "sha256:5baa9bc0dfbae8c507e51c8cf1b6d4628086f7a87bbd3a9952bd5f035451f1cc", size = 183298, upload-time = "2026-07-31T11:31:27.665Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2b/03/47debfe28e9d6d354be5d777b67fd44c359b9eb299a5d103500bd7cc3e37/websockets-16.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0fcf657e9f13ff4b177960ab2200237b12994232dfb6df16f1cfe1d4339f93c", size = 179566, upload-time = "2026-07-17T22:48:49.596Z" },
{ url = "https://files.pythonhosted.org/packages/72/93/31efa1ed78c17e5cfc229fd449e3966e1b9cc15753204cd585cc8dd01f4a/websockets-16.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b852788aa51764e2d8e4cf5493d559326bcae5e38d16ba25ffa322b034df272a", size = 177250, upload-time = "2026-07-17T22:48:50.942Z" },
{ url = "https://files.pythonhosted.org/packages/01/4a/542378ab3972b0c1cf1df3df3eff9591cea0d30c58c3aa3c4ddbc244e787/websockets-16.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1427fb4cf0d72f66333e2cacc3ff5f575bf2d7008166ce991a4a470b21d51a22", size = 177528, upload-time = "2026-07-17T22:48:52.59Z" },
{ url = "https://files.pythonhosted.org/packages/33/d9/162321f63c7eed558e9e1798ed7a1e34a4f6dab51f35419e4ed7a4907979/websockets-16.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:da4ca1a9d72f9030b3146b8d7022719a9f3d478f61efe6f7dd51d243f61c51b2", size = 186859, upload-time = "2026-07-17T22:48:53.915Z" },
{ url = "https://files.pythonhosted.org/packages/de/09/87df740f7430ce564bd52402e9c9458d4d0459cc7d2ee29e530c8204851b/websockets-16.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d7f0f8bdb25d2c632b72527325e4776430fd5bc61b9118de4e2b8ddb5f5b01", size = 188095, upload-time = "2026-07-17T22:48:55.384Z" },
{ url = "https://files.pythonhosted.org/packages/d2/12/3d2703af7cc095f3c81904c92208cc1ae79affbc67376944b50ee9301f73/websockets-16.1.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7dfcad78ea1492ee3a9ec765cb7f51bbc17d477107aaf6b22abf7b2558d1c5a0", size = 191385, upload-time = "2026-07-17T22:48:56.742Z" },
{ url = "https://files.pythonhosted.org/packages/1d/69/986aa0234a964a00f5149cfc46e136e96c8faad1c783474550f40d31aef4/websockets-16.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb9a0a6dc3d1b3986cb88091b6899f0396651e0f74e2c9766ab8d6ffc3842e29", size = 188653, upload-time = "2026-07-17T22:48:58.134Z" },
{ url = "https://files.pythonhosted.org/packages/35/6b/10f9d03e3970a69ba67bd3b46b87a929b586d0300fadbfe14f57c1f85490/websockets-16.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29dfa8114c4a620c69591c5973860f768eac29d3fd6904f37f34266cb219c512", size = 187426, upload-time = "2026-07-17T22:48:59.515Z" },
{ url = "https://files.pythonhosted.org/packages/56/db/bb3aad62bf63d8bb3f0634b2eabffcfb3677a34bd19492110ff6869cf703/websockets-16.1.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ff9417c0ada4d0f7d212f928303e5579bdf3ace4c802fa4afabb30995da58c3", size = 184882, upload-time = "2026-07-17T22:49:00.916Z" },
{ url = "https://files.pythonhosted.org/packages/6c/4c/c09a2ea9bfbeccce52fdc383e5f28af4bc8843338aabac28c81489af6120/websockets-16.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fe0b50da2d84535fb4f7b4bfa951280f97ce3d558a0443b541166d609e67b57", size = 187584, upload-time = "2026-07-17T22:49:02.283Z" },
{ url = "https://files.pythonhosted.org/packages/c7/8b/31bb4eb4d9eaacf1fdd39d115772a8aeaedfc19b5dc262e57ffbc8a9d42c/websockets-16.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34420aaa64440ebd51ac72ca8a45ef4626429438c9b02e633ae412ed43f925d3", size = 186174, upload-time = "2026-07-17T22:49:03.973Z" },
{ url = "https://files.pythonhosted.org/packages/2f/e4/dc02d725610a1ad49e193ef91a548194d71bdc6cdf27da83067dd1f73995/websockets-16.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a6a61aff018180c9c50b7b0da33bfd29d378af3497429c95006c589a23a11648", size = 187986, upload-time = "2026-07-17T22:49:05.553Z" },
{ url = "https://files.pythonhosted.org/packages/e0/73/30ed84c8bfd14c73d4af29d5ed9323c3073b48e0b7b23b67070f4e7fd59b/websockets-16.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:04fd29a0e2fe9414a95b00e92c67ae51bf900c50c0f8a4b2dafdad621f49ea1d", size = 185565, upload-time = "2026-07-17T22:49:06.959Z" },
{ url = "https://files.pythonhosted.org/packages/7d/d3/4be8d4959f51e31b4f8fc0ece12b45bd3b6c0d15ea23b9990d9c11fc805f/websockets-16.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5c31aa7e39ee3e8a358573257f1c0bb5c52430d1b637030dd9c8cc2c282926be", size = 186598, upload-time = "2026-07-17T22:49:08.293Z" },
{ url = "https://files.pythonhosted.org/packages/26/fa/abb38597a52d84ed9cfacadc7a0c6f2db282c0ab23cdf72b58a666a21227/websockets-16.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d14bfb217eb4701e850f1525c9d29d79c44794cdf1c299ead25f39f8c78dea81", size = 186834, upload-time = "2026-07-17T22:49:09.766Z" },
{ url = "https://files.pythonhosted.org/packages/59/80/1119ad08a228b90c4eb77fbe48df7836731a605f5f881ba701ca826a4a65/websockets-16.1.1-cp311-cp311-win32.whl", hash = "sha256:2e28e602bb13da44fbe518c1781a88e3b9d4c3d48d02c9bad83e546164336f57", size = 179940, upload-time = "2026-07-17T22:49:11.196Z" },
{ url = "https://files.pythonhosted.org/packages/71/b2/e511c1c6f64a95c2f3fc54bffda0e14eaa7e9442be605c29270f7589b918/websockets-16.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:7421fad442de870a8cbf2287d1cad7e706ece0dbfeba5e911df132cbdc1cb56a", size = 180239, upload-time = "2026-07-17T22:49:12.519Z" },
{ url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" },
{ url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" },
{ url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" },
{ url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" },
{ url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" },
{ url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" },
{ url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" },
{ url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" },
{ url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" },
{ url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" },
{ url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" },
{ url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" },
{ url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" },
{ url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" },
{ url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" },
{ url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" },
{ url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" },
{ url = "https://files.pythonhosted.org/packages/ce/fd/6ec6c6d2850aea25b1b2aa9901a016980bb87d01e89b3eb00470b1b5d471/websockets-16.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ab59169ace05dcb49a1d4118f0bde139557adf45091bd85747e36bf5de984dd1", size = 179587, upload-time = "2026-07-17T22:49:38.959Z" },
{ url = "https://files.pythonhosted.org/packages/5f/d8/1d299d2dd34087db39831a34cc645ef8a6f89d78efada6983093513cd81c/websockets-16.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5e3b7d601f6f84156b08cc4a5e541c2b50ad7b36cfc302b657a12477c904a5df", size = 177272, upload-time = "2026-07-17T22:49:40.293Z" },
{ url = "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cd2ca96a082a36964aca83e992f72abeb61b7306c1a6cba4c7d06a7b93750cac", size = 177530, upload-time = "2026-07-17T22:49:41.786Z" },
{ url = "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f5d497865f05bb222cab7016c6034542e84e5f29f49c6fd3f4939cda7197b5b8", size = 187197, upload-time = "2026-07-17T22:49:43.658Z" },
{ url = "https://files.pythonhosted.org/packages/0b/13/88137fbaf726ebe29d62c1117fa11fa2bbb6209dc79d4ad738efbe36a2aa/websockets-16.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bae954c382e013d5ea5b190d2830526bfa45ad121c326da0049b8c769f185db6", size = 188433, upload-time = "2026-07-17T22:49:45.147Z" },
{ url = "https://files.pythonhosted.org/packages/01/6d/46c2f2ce6751cb26f39293e1ecbf8544cb01321397cd476c2756b98c216d/websockets-16.1.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e09f753a169951eb4f28c2c774f71069304f66e7277e0f5a2892423599cfa854", size = 189868, upload-time = "2026-07-17T22:49:46.581Z" },
{ url = "https://files.pythonhosted.org/packages/29/2b/170a9e8097636cfde4dc3c592b6e00b18a44a2f5407606d96ca542dd5838/websockets-16.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:024193f8551a2b0eafbdd160911012c4e6c228c28430c84433253299a9e42d6a", size = 189059, upload-time = "2026-07-17T22:49:47.972Z" },
{ url = "https://files.pythonhosted.org/packages/a7/48/f0d4ebc9ab4b473b8861b9e20fdb663d515d42f7befdf62cdb60fee7a1ec/websockets-16.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aabe464bfd13bd25f4821faf111da6fefdc389f870265a53105580e45b0a2e49", size = 187814, upload-time = "2026-07-17T22:49:49.344Z" },
{ url = "https://files.pythonhosted.org/packages/d5/ba/39a41d3ae8e72696a9492581900611c5a91e2b07563b0bcd2523adea9854/websockets-16.1.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a28fcbc9b6baf54a2e23f8655f308e4ccc6afdd7266f8fe7954f320dcda0f785", size = 185229, upload-time = "2026-07-17T22:49:50.787Z" },
{ url = "https://files.pythonhosted.org/packages/3c/36/ac15b604f850d1907f0a85ed721cefe47cd45034b3620069b829746cccbe/websockets-16.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79eace538c6a97e96d0d03d4f9d314f9677f5ed85a8a984992ffd90b13cb8a56", size = 187874, upload-time = "2026-07-17T22:49:52.228Z" },
{ url = "https://files.pythonhosted.org/packages/a8/f3/3fbd5d71d59299c3770faa5884d4f45070236ca5a35ab3a61830812c409a/websockets-16.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:496af849a472b531f758dbd4d61338f5000538cb1a7b3d20d9d32a264517f509", size = 186469, upload-time = "2026-07-17T22:49:53.776Z" },
{ url = "https://files.pythonhosted.org/packages/b4/fc/dd90349bba58af2a53ef2ddd9c32716c81eb6d59a0687939fff561860878/websockets-16.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5283810d2646741a0d8da2aa733d6aefa0545809afccb2a5d105a26bc45125f1", size = 188347, upload-time = "2026-07-17T22:49:55.202Z" },
{ url = "https://files.pythonhosted.org/packages/4c/f3/f73ba86427682da59b78c11d77ba56d5b801c32e84afe79b274bbd6a9bb2/websockets-16.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4e3b680b1e0a27457e727a0d572fd81dffa87b6dbf8b228ab57da64f7d85aead", size = 185903, upload-time = "2026-07-17T22:49:56.75Z" },
{ url = "https://files.pythonhosted.org/packages/34/7c/f95eb20e80104173b3a0a092291f89ea4047ef6e608e0a57ca06eb14eecb/websockets-16.1.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69159730a823dde3ea8d08783e8d47ef135a6d7e8d44eb127e32b321c9db8e3e", size = 186855, upload-time = "2026-07-17T22:49:58.467Z" },
{ url = "https://files.pythonhosted.org/packages/b0/35/dd875b3e050ff232d60fa377707f890e369f74d134f1be32e8f68879747c/websockets-16.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ed5bb271084b46530ee2ddc0410537a9961152c5ccba2fc98c5276d992ccba87", size = 187140, upload-time = "2026-07-17T22:50:00.016Z" },
{ url = "https://files.pythonhosted.org/packages/e8/dc/5cbfcb41824502f6af93b8f3943a4d06c67c23c7d2e31eb18748c4a5b2a7/websockets-16.1.1-cp313-cp313-win32.whl", hash = "sha256:cfb70b4eb56cac4da0a83588f3ad50d46beb0690391082f3d4e2d488c70b68ea", size = 179928, upload-time = "2026-07-17T22:50:01.685Z" },
{ url = "https://files.pythonhosted.org/packages/b0/c1/71e5deb5b7f8f226997ab64908c184ac3105c0155ce2d486f318e5dd08a8/websockets-16.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9531d9cbeac99af6f038fb1bc351403531f7d634a2c2e10e2f7c854c6ed5b68", size = 180242, upload-time = "2026-07-17T22:50:03.117Z" },
{ url = "https://files.pythonhosted.org/packages/73/a2/ba78a164eeea4620df4a4df4bd2ed6017438c4655cc0f36f2c0bc0432355/websockets-16.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:443aefe96b7fdb132e2a70806cca1f2af49bb3f28e47abcd7c2e9dcf4d8fa1b8", size = 179635, upload-time = "2026-07-17T22:50:05.001Z" },
{ url = "https://files.pythonhosted.org/packages/b9/08/d26d7a7628cd4ac34cbbdb63ac80914ca842ed8e42938c40a53567806df3/websockets-16.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6456ff333092d509127d75a638cb411afae8ff17f092635015d1902efec8a293", size = 177320, upload-time = "2026-07-17T22:50:06.427Z" },
{ url = "https://files.pythonhosted.org/packages/0f/45/ebec83e6269536aa5932533c67b0af5c781f3e73fdbcd68672dcf43f4f44/websockets-16.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fce6c48559c86d1ac3632ccb1bebc7d5442fbe79bd9bb0e40379ee54be2a4051", size = 177544, upload-time = "2026-07-17T22:50:07.834Z" },
{ url = "https://files.pythonhosted.org/packages/c9/d5/abc614d2297f6c1c3e01e61260364457a47c25cc1cf6a879038902bc6aa8/websockets-16.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:92b820d345f7a3fc7b8163949ee92df910f290c3fc517b3d5301c78065adafe1", size = 187270, upload-time = "2026-07-17T22:50:09.275Z" },
{ url = "https://files.pythonhosted.org/packages/52/71/4c99af3b87dff1b2927981f6876607d4acb45338c665242168d3982f7758/websockets-16.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a606d9c24035242a3e256e9d5b77ed9cd6bccfcb7cf993e5ca3c0f6f68fb6a7", size = 188509, upload-time = "2026-07-17T22:50:10.722Z" },
{ url = "https://files.pythonhosted.org/packages/9b/b4/5c8ca14b0df7eb84ed0524165c5359150210140817a3312aee57bf62a1cf/websockets-16.1.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:414e596c75f74e0994084694189d7dc9229fb278e33064d6784b73ffbba3ca31", size = 189882, upload-time = "2026-07-17T22:50:12.293Z" },
{ url = "https://files.pythonhosted.org/packages/25/c1/bedfba9e70557129cb8083748d167bdcc01483dedf0f0df143676df05cbe/websockets-16.1.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:536676848fc5961aca9d20389951f59169508f765637a172403dc5434d722fa0", size = 189114, upload-time = "2026-07-17T22:50:13.789Z" },
{ url = "https://files.pythonhosted.org/packages/df/09/aa835b2787835aebd839114be5de51b797cb480b63ba42b26d34dfe147cb/websockets-16.1.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97fd3a0e8b53efa41970ac1dff3d8cf0d2884cadeb4caaf95db7ad1526926ee3", size = 187861, upload-time = "2026-07-17T22:50:15.179Z" },
{ url = "https://files.pythonhosted.org/packages/20/26/f6408330694dbc9830857d9d23bc14ac4f6875127a480cfdda8d5ca21198/websockets-16.1.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7b1b19636af86a3c7995d4d028dbe376f39b4bf31541146f9c123582a6c94562", size = 185286, upload-time = "2026-07-17T22:50:16.741Z" },
{ url = "https://files.pythonhosted.org/packages/17/9a/e0675e70dd8a80762cf35bb18799d3f290a4890ffe6439bc51d222796083/websockets-16.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:41c8e77f17294c0ac18008a7309b99b34ee72247ef10b6dff4c3f8b5ac29896b", size = 187935, upload-time = "2026-07-17T22:50:18.213Z" },
{ url = "https://files.pythonhosted.org/packages/33/c1/3234cfb86afde01b81e9bddcc6e534c440975d60a13991259e833069ab3e/websockets-16.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9f63bcef7f4b02b06b35fc01c93b96c43b5e88e1e8868676caacf493d5a31f3a", size = 186444, upload-time = "2026-07-17T22:50:19.67Z" },
{ url = "https://files.pythonhosted.org/packages/89/87/9c15206e1d778923d8daa9657de07aa62ea815e13448319c98458c37b281/websockets-16.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dab9eb87869da2d6ed3af3f3adf28414baae6ec9d4df355ffc18889132f3436c", size = 188409, upload-time = "2026-07-17T22:50:21.28Z" },
{ url = "https://files.pythonhosted.org/packages/f2/00/cf5de5c67676de2d3eef8b2a518f168f6796595447a5b7161ba0d012915c/websockets-16.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:43e3a9fdd7cbf7ba6040c31fae0faf84ca1474fef777c4e37912f1540f854499", size = 185958, upload-time = "2026-07-17T22:50:22.719Z" },
{ url = "https://files.pythonhosted.org/packages/62/c0/731b6ddede2e4136912ec4cff2cffbda35af73546be4762c3d7bd3bd79af/websockets-16.1.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:056ae37939ed7e9974f364f5864e76e49182622d8f9751ac1903c0d09b013985", size = 186911, upload-time = "2026-07-17T22:50:24.108Z" },
{ url = "https://files.pythonhosted.org/packages/8c/7f/39c634472c4469a24a7c09cecddffb08fac6d0e74f73881a94ee8a40a196/websockets-16.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0eadbbf2c30f01efa58e1f110eb6fa293261f6b0b1aa38f7f48707107690af9", size = 187204, upload-time = "2026-07-17T22:50:25.548Z" },
{ url = "https://files.pythonhosted.org/packages/26/89/9667c256c256dafcc62d21328ce7a40067da857969b68ee9af375b0aaf72/websockets-16.1.1-cp314-cp314-win32.whl", hash = "sha256:195c978b065fa40910582464f99d6b15c8b314c68e0546549a55ed83f4735328", size = 179603, upload-time = "2026-07-17T22:50:27.086Z" },
{ url = "https://files.pythonhosted.org/packages/bd/dd/1c099d6c0fc5deb6b46ccdbb6981fdb4b12c917869cb3952408409dc18db/websockets-16.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:4e8d01cc3bcae7bbf8167f944aeafefed590fae5693552bba9794a9df68371cc", size = 179948, upload-time = "2026-07-17T22:50:28.521Z" },
{ url = "https://files.pythonhosted.org/packages/35/25/9956b2d5e0529d5d23924f21bba1440d4c5c88a562e4f08550871ffa97a7/websockets-16.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0ffd3031ea8bda8d61762e84220186105ba3b748b3c8da2ae4f7816fac03e573", size = 179963, upload-time = "2026-07-17T22:50:29.982Z" },
{ url = "https://files.pythonhosted.org/packages/17/06/55ffc976c488b6aee9ea05761ff7c4e88e7c1fd82818c8ca7b556ad2f90c/websockets-16.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:84a2cef8deffbd9ab8ee0ea546a2a6a7030c28f44e6cdd4547dbfeb489eb8999", size = 177497, upload-time = "2026-07-17T22:50:31.396Z" },
{ url = "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3df13f73af9b3b38ab1195eb299ecb67a4330c911c97ae04043ff74085728abe", size = 177698, upload-time = "2026-07-17T22:50:32.829Z" },
{ url = "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:23253dd5bcae3f9aaee0a1d30967a8dbd52e5d3cff93a2e5b84df57b77d4750d", size = 187561, upload-time = "2026-07-17T22:50:34.24Z" },
{ url = "https://files.pythonhosted.org/packages/11/94/c3f330851806b9b02138b774d593478323e73c99238681b4b93efe64e02d/websockets-16.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1c5705e314449e3308872fe084b8571ce078ee4fc55a98a769bdefe5917392", size = 188732, upload-time = "2026-07-17T22:50:36.088Z" },
{ url = "https://files.pythonhosted.org/packages/d1/f2/eb2c450f052de334ae33cf200ece6e87b0e14d186807074e4eb1cd2cdea2/websockets-16.1.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69e52d175a0a7d1e13b4b67ad41c560b7d98e8c6f6126eb0bda496c784faf8c7", size = 190872, upload-time = "2026-07-17T22:50:38.008Z" },
{ url = "https://files.pythonhosted.org/packages/70/31/2ac8cecf3a74f7fed9132129fc3d90b3998a1554570c11a69b2a8c20332d/websockets-16.1.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1f79c89b5eb034d1722938a891916582f8f7f503f58ca22518a63c3f2cd18499", size = 189305, upload-time = "2026-07-17T22:50:39.53Z" },
{ url = "https://files.pythonhosted.org/packages/6a/cf/8ab19650d3c0d4562c92e70ab47c257c4aa5c6a713ed87fe63766b31fefc/websockets-16.1.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39f2a024af5c345ffe8fcf1ee18c049c024c94df393bb09b044a6917c77bde43", size = 188033, upload-time = "2026-07-17T22:50:40.912Z" },
{ url = "https://files.pythonhosted.org/packages/66/d7/a49a38a6127a4acb134fb1912b215d900cc657605cff32445bf519f3acc4/websockets-16.1.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:952303a7318d4cbe1011400839bb2051c9f84fa0a35923267f5daba34b15d458", size = 185748, upload-time = "2026-07-17T22:50:42.559Z" },
{ url = "https://files.pythonhosted.org/packages/95/3e/ad1fa40388c7f2e0bb2c7930d0090b6c5498594bd1cdaec18864df3d9e97/websockets-16.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:249116b4a76063d930a46391ad56e135c286e4562a18309029fc2c73f4ed4c62", size = 188285, upload-time = "2026-07-17T22:50:43.974Z" },
{ url = "https://files.pythonhosted.org/packages/35/b8/d5db28ca264b9104f82196f92dc8843e35fd391f763d42e4ad358f5bc97e/websockets-16.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:61922544a0587a13fd3f53e4c0e5e606510c7b0d9d22c8444e5fae22a06b38cb", size = 186777, upload-time = "2026-07-17T22:50:45.474Z" },
{ url = "https://files.pythonhosted.org/packages/42/9c/726cb39d0cc43ae848dce4aa2acb04eecc6738b1264ec6d700bf6bcfb9f8/websockets-16.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:46dcaa042cd1de6c59e7d9269fa63ff7572b6df40510600b678f0826b3c7af51", size = 188682, upload-time = "2026-07-17T22:50:46.973Z" },
{ url = "https://files.pythonhosted.org/packages/be/c7/1168704de8c2dd483edabe4a22cbe4465dd8be8dd95561d214f9fe092871/websockets-16.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:38565aca3e01ea8734e578fb2118dade0ecb0250533f29e22b8d1a7a196cf4d0", size = 186377, upload-time = "2026-07-17T22:50:48.413Z" },
{ url = "https://files.pythonhosted.org/packages/ca/40/f9ff2d630ffce4e7dfea0b2288e1caf9ebbf9ff8a9ec9396136ce8b94935/websockets-16.1.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:42f599f4d48c7e1a3338fdaac3acd075be3b3cf02d4b274f3bf2767aedd3d217", size = 187148, upload-time = "2026-07-17T22:50:49.845Z" },
{ url = "https://files.pythonhosted.org/packages/b5/71/e177c8299f78d7cbe2d14df228643c10c70c0e86e108e092056bbcc16e46/websockets-16.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcc04fedf83effaeb9cce98abc9469bb1b42ef85f03e01c8c1f4438ef7555737", size = 187578, upload-time = "2026-07-17T22:50:51.619Z" },
{ url = "https://files.pythonhosted.org/packages/49/b2/b6987faf330f5af5c787a2610124c2e8403d51724f9001ec4fff6311fe7a/websockets-16.1.1-cp314-cp314t-win32.whl", hash = "sha256:8483c2096363120eea8b07c06ae7304d520f686665fffd4811fad423930a65d7", size = 179729, upload-time = "2026-07-17T22:50:53.269Z" },
{ url = "https://files.pythonhosted.org/packages/a2/6e/fbac6ed878dd362fbad7d415fa4f84d38e3e33fed8cde45c64e783acf826/websockets-16.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bcce07e23e5769375158f5efdcdafa8d5cd014b93c6683865b840ed65b96f231", size = 180072, upload-time = "2026-07-17T22:50:54.969Z" },
{ url = "https://files.pythonhosted.org/packages/e1/ed/71fea6e141590cafc40b14dc5943b0845606bee87bdb52a21b6a73eb4311/websockets-16.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:820fb8450edddae3812fd58cbc08e2bf22812cb248ecb5f06dbb82119a56e869", size = 177185, upload-time = "2026-07-17T22:50:56.665Z" },
{ url = "https://files.pythonhosted.org/packages/01/ec/00e7eeca200facf9266a83e4cbbf1bed0e67fba1d4d45031d3e5b3d81b5c/websockets-16.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:125f22dbefaf1554fea66fc83851490edb284ce4f501d37ffed2752f418332d9", size = 177459, upload-time = "2026-07-17T22:50:58.197Z" },
{ url = "https://files.pythonhosted.org/packages/75/fd/5774c4b33f7c0d8f0c51809c8b3a93456c48e3543579262cfa64eb5f522e/websockets-16.1.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30bbe120437b5648a77d3519b7024ea09530e0b5b18d3698c5a0ae536fe0cc2e", size = 178294, upload-time = "2026-07-17T22:50:59.641Z" },
{ url = "https://files.pythonhosted.org/packages/37/c3/48e2c03d2bd79bb45948841c592d24156312dd5f58cdf8f549febe652fb6/websockets-16.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6b9dadbef0cccd9f4c4ee96b08898afa73e26803bbe0f6aeb5bb12b0074206d", size = 179190, upload-time = "2026-07-17T22:51:01.129Z" },
{ url = "https://files.pythonhosted.org/packages/2d/3f/73e511ecf2496ceac57dd4ed8388efe2bcf0769338a2dbf242c8366ae87e/websockets-16.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56cd5fc4f10a9ea8aa0804bddb7b42506cf9e136046f3b4c27de8fec9e2ecba5", size = 180330, upload-time = "2026-07-17T22:51:02.603Z" },
{ url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" },
{ url = "https://files.pythonhosted.org/packages/cb/54/b2bce5b754b91b727b852e78af6d7193d4fe985e420dc54e6c2abe161c1c/websockets-17.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c38515cb54902f7e97d0239e81ef46c4444f9475f4807fb9bbdb789b4089abcf", size = 212573, upload-time = "2026-07-31T11:29:04.803Z" },
{ url = "https://files.pythonhosted.org/packages/78/1b/eaefeb695b217d8c735fc377ab53c6b00bc9ed64a01a3f6f797096ac0ee8/websockets-17.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:70d438268e49f1a4bd096b6b6f7010f3ab48b5db2574dbf7d8c864c46ce7a06a", size = 210262, upload-time = "2026-07-31T11:29:06.298Z" },
{ url = "https://files.pythonhosted.org/packages/87/2d/68439a174c74969fb51619bbe9af9496826610883b828a2edd2f022c94fc/websockets-17.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0b52c76b8a870b141b7ca0705289452183ce7a523101954ccfe29a25986a673f", size = 210535, upload-time = "2026-07-31T11:29:07.553Z" },
{ url = "https://files.pythonhosted.org/packages/a4/ab/13a856b488dbac7fd3c5473e38098897cda0baa04e3ca3b34ec6c8a32b46/websockets-17.0.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b98860aefbd3d9bc8e3c7f0eefb83b11142b16110739c68cd33d3b4d6e84e536", size = 219602, upload-time = "2026-07-31T11:29:09.227Z" },
{ url = "https://files.pythonhosted.org/packages/45/a1/2b100e71aa1fe283ec8fb73f8b74a8576d855486a49117903b100dd3b78d/websockets-17.0.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d41e9845514754a42d1d83b2fca9d27fee2ca7b3b0bee6843ba5a9bb2b6e25ac", size = 219873, upload-time = "2026-07-31T11:29:10.362Z" },
{ url = "https://files.pythonhosted.org/packages/3b/71/92e6146d3588d145136c0e0e16d106bbb855bb5047e13ec3fdee39cce770/websockets-17.0.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9aac6081513f02eac3f8caace800dbfc5c608b69e4a7bef69e414eabfc95aa1", size = 221108, upload-time = "2026-07-31T11:29:11.708Z" },
{ url = "https://files.pythonhosted.org/packages/09/8d/357afa2ffd29686536109e7e3cb2a94f2d09e535df4cf3989393dc506a40/websockets-17.0.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b85b960a4507b0714c0a1246d031be9118d908ee974dc085257297a955205f1d", size = 224401, upload-time = "2026-07-31T11:29:12.959Z" },
{ url = "https://files.pythonhosted.org/packages/01/27/9efba1e7a8df48e405d017e67513c6b2a8f0b59c8500b820c47cd5f3dea9/websockets-17.0.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c356dbddab0a529ed7574f78f559d75a223735c321c28f6f587fbf02b11ed301", size = 221670, upload-time = "2026-07-31T11:29:14.199Z" },
{ url = "https://files.pythonhosted.org/packages/01/85/ab27d62103e8a150f3657e043e5fc711ad3e018c8cd8a715093e93d7640c/websockets-17.0.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5661f868ef191d33dfc6a0cc7c5b3d495f0cc8bb3f8b30d87bda8755c61c95f5", size = 220442, upload-time = "2026-07-31T11:29:15.417Z" },
{ url = "https://files.pythonhosted.org/packages/6d/04/289e00b8001b622b0c397a6901fcc4aa8f34a6d2ed42be17f2704f2faae1/websockets-17.0.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2fa2cb465a131c347ba6717a78c887746e73edb1c131d01c982d6ef0d68b82e0", size = 217760, upload-time = "2026-07-31T11:29:16.772Z" },
{ url = "https://files.pythonhosted.org/packages/2f/70/0fe58cdac988dfc0066786cc07b09dfd72b48b0c01e5de667721192b2e6e/websockets-17.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55383d8177b3c99fd873ee5db0e0193f4c1dd4a3feaccf1a4a03c1b7cf539cac", size = 220597, upload-time = "2026-07-31T11:29:18.075Z" },
{ url = "https://files.pythonhosted.org/packages/d5/76/d3eaf120710d1a791d1c7a4963f0b50a589df8ba675394fd2a97dfea3746/websockets-17.0.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:038cfad5d5417f8bb09295abe986029a26d22f34bda622ccc79b670efd4dab56", size = 219187, upload-time = "2026-07-31T11:29:19.468Z" },
{ url = "https://files.pythonhosted.org/packages/e6/00/4e9ae886bdb1647537176ca33fca66d79dddb3773d213ac98ddc6bba9ab4/websockets-17.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:15920057a6b723f84734f0641403bca163a4b176e5af809ee4f0c4a1e75e9fed", size = 219955, upload-time = "2026-07-31T11:29:20.641Z" },
{ url = "https://files.pythonhosted.org/packages/7c/67/cd7cc6849a86cf8c9979c0c570b6b6ccee75d2872854238d8d54e77be6ec/websockets-17.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5508f38c98ac29def9e747b87543b008a58b075df6da70b2cf2e0b47073d33bb", size = 221002, upload-time = "2026-07-31T11:29:21.753Z" },
{ url = "https://files.pythonhosted.org/packages/de/5c/4d14eaf7b2f1448d1af24c1641f04eb74c1632a5802952aac4b7e068b8e7/websockets-17.0.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a68e604c6d1b0338e46652e2688cbce8096ad9c03548b075fda9e2ea19a9b7dd", size = 218579, upload-time = "2026-07-31T11:29:22.888Z" },
{ url = "https://files.pythonhosted.org/packages/15/67/ff8bc4b8a6ec235ed8985de12fecc59ad2cd68cc8fc79b97deaa42e412ac/websockets-17.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8af570fc29cd998a921c7131c8ac81d9434466d6d25300cb12a690fb56a8a08", size = 219612, upload-time = "2026-07-31T11:29:24.052Z" },
{ url = "https://files.pythonhosted.org/packages/91/eb/103d81d655bab3ffd5c7d5d4b08f92c374499decd1d4be6035ce715b385b/websockets-17.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:246927ae9ae06ca0d42a483a4bdb80d4862e1ee5b4cab37c354a5e1ad8356448", size = 219846, upload-time = "2026-07-31T11:29:25.421Z" },
{ url = "https://files.pythonhosted.org/packages/b8/1e/3495161b1827941258545604fdf72e3e053d03f25bb61752228a784c26a1/websockets-17.0.1-cp311-cp311-win32.whl", hash = "sha256:1d4cf7e8e5b8b1fa40758ac7524843a00237b124ab217e227542cafcfeb7a946", size = 213046, upload-time = "2026-07-31T11:29:27.094Z" },
{ url = "https://files.pythonhosted.org/packages/7b/b1/ba0ce59681db38c320a6d485f95a497ddea20356d9a9e8e70615ddd867b9/websockets-17.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:02f0b037a737d0cb0c33866c97bcd1a0b73170dfbf42d69d8fb86f51002fd5ae", size = 213344, upload-time = "2026-07-31T11:29:28.28Z" },
{ url = "https://files.pythonhosted.org/packages/83/9e/abfdde9cbd57f0b5867a70e3426ac63341e1a21557b273c39bb6d2ccf8b9/websockets-17.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:1bdd8c4be420905dd732e00dcd669852d8128cc723efa585a0c0e51adb00a28a", size = 213277, upload-time = "2026-07-31T11:29:29.504Z" },
{ url = "https://files.pythonhosted.org/packages/50/ff/6199a52d864215750af8668d84b0274775011a90052081f5a9495807a92b/websockets-17.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:10f461191125c63902ea7394ae9e752b1b5785641850c1d365bb30b0f88bc53f", size = 212603, upload-time = "2026-07-31T11:29:30.771Z" },
{ url = "https://files.pythonhosted.org/packages/54/7e/439a962bcada88dcf586da77a1b2385f91e2d2910e9359540934c827156b/websockets-17.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cffc84ddec6da7f447677266fee2a3c40ecc78172f00752aa1150b8a8d65df1d", size = 210286, upload-time = "2026-07-31T11:29:32.157Z" },
{ url = "https://files.pythonhosted.org/packages/d9/82/123660edc759c225626b3b91952c7625f85c77a8362acbc35a4623120f7d/websockets-17.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c23e532c8a2325a1e7486de8763a60dc43e83f01bcaeca07e3ba79652c156db1", size = 210549, upload-time = "2026-07-31T11:29:33.388Z" },
{ url = "https://files.pythonhosted.org/packages/cd/2f/2940e57080cf56f28190287516400126d5a76b52b9a61dc10ba6f6400dbe/websockets-17.0.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c09e097d0e46e3c289bedab9a475ae344b70c30ff5646e46af22b4e6fdc97b21", size = 219874, upload-time = "2026-07-31T11:29:34.608Z" },
{ url = "https://files.pythonhosted.org/packages/42/28/9ec976c16d63cc51c28dfec74b66854048c0b8b6579946e902f91b69e8bf/websockets-17.0.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f47b0815af3948ec6a440b3afa02f05b18cc0939549e91b5c677b5d9c2c8472a", size = 220150, upload-time = "2026-07-31T11:29:35.831Z" },
{ url = "https://files.pythonhosted.org/packages/f4/a4/850c699a16bbc451723856360c59bd997bec075e637154f3fa96e80d5760/websockets-17.0.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8848c207049ad49d318e5f64a3d4d7bb189f8328d0d98e65647788f2a085785c", size = 221389, upload-time = "2026-07-31T11:29:37.189Z" },
{ url = "https://files.pythonhosted.org/packages/47/e1/f60a891c1a4b3420d5052333a84eb7241e1fb4a71866dec1562f5fa30027/websockets-17.0.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2604de7228506b13a44a256a9d223943340c0e725af5d367dc068e192b027761", size = 224169, upload-time = "2026-07-31T11:29:38.61Z" },
{ url = "https://files.pythonhosted.org/packages/26/fb/e2a893be6fae4fddfe50ddc3035a331d3f381103d5467b7900026bdb3a64/websockets-17.0.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07abc3bd196a48af476a82fd47f3f79a6a3f70937a9f930cef703cfa0c9d83b6", size = 222025, upload-time = "2026-07-31T11:29:39.897Z" },
{ url = "https://files.pythonhosted.org/packages/d9/72/e3144b2d79276fab9798ed7d4aea2f0847434f186800b6f56a1eddcb3114/websockets-17.0.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:769ce7e2acfd9a89f2bed3a9c0da229459516bbc00bd4c9e2ca492c613ae4861", size = 220779, upload-time = "2026-07-31T11:29:41.084Z" },
{ url = "https://files.pythonhosted.org/packages/c0/5e/69c02174fbcf1c40c6adc45d3c316a401558392fe7bab8969ef8c46f1689/websockets-17.0.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07d78a509c3333f5908c83d7f78144ea68a6c9ec28110f5c54d81d8fcdc262c4", size = 218053, upload-time = "2026-07-31T11:29:42.322Z" },
{ url = "https://files.pythonhosted.org/packages/b3/09/7574778b095b99cfa0856583462f56568df784f9b41485145169b2ec9c64/websockets-17.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ffad64ce7ad3703d652a3fd9af26238377d24ce52c6ad8ff35d26d82f61f493f", size = 220825, upload-time = "2026-07-31T11:29:43.553Z" },
{ url = "https://files.pythonhosted.org/packages/c5/e6/f46571f38765dbc4cbc0d0b47de8db65768006dbbd4340e6f5f51bc1d895/websockets-17.0.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e95e321d0d763f2b6633512605f6112ebd70d5746f3ce05c941909d4a25233f2", size = 219427, upload-time = "2026-07-31T11:29:44.731Z" },
{ url = "https://files.pythonhosted.org/packages/9d/31/6ff1fee057bd7e9dd5237fc064a749615378d003aa045b5bfc2d12b2f4f7/websockets-17.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cd526c8228e759c1006c4b7c9ac71dc4e925ced1a6a6a5a8e94643709738f63e", size = 220198, upload-time = "2026-07-31T11:29:45.997Z" },
{ url = "https://files.pythonhosted.org/packages/7a/4f/d41847227a44b9ad87c3d5a9fddbfad8b7c4d6032878d8460d9d37c2d44f/websockets-17.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8cd3369e42c0246afaf9d669cfc19797e3a49e8c0a639544459c57597108b966", size = 221304, upload-time = "2026-07-31T11:29:47.314Z" },
{ url = "https://files.pythonhosted.org/packages/63/30/21a7e326c6ad2eb526cd5b816383d59cdeb28b8805b65a543c3cfbd8e8ce/websockets-17.0.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b580794e926cab7ff42ee4371ef14e0b22cb2bb722a607f77769136468f49a3f", size = 218858, upload-time = "2026-07-31T11:29:48.587Z" },
{ url = "https://files.pythonhosted.org/packages/2d/48/55b0331cd5bec9ce29748f79edc00075805450a47011d0c8e3b1c61dbf04/websockets-17.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5033ffe6804dd53afafa7d08e8c3eef2d2431f34d58ca30507a8442dd04a033a", size = 219840, upload-time = "2026-07-31T11:29:49.791Z" },
{ url = "https://files.pythonhosted.org/packages/78/6e/2e8bc06e546f49b32a58a2bc2957902d1809ecc37552d3d7ccd6639a126e/websockets-17.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6db9e5bf3649ab506c6ae8a3ac85a00fb1ae3816d75962771b2df8adbc5d40d2", size = 220116, upload-time = "2026-07-31T11:29:51.026Z" },
{ url = "https://files.pythonhosted.org/packages/b0/ad/4bac01fa41aca54307157b9c9f68b066a6bb51fb18716ba618078a67b283/websockets-17.0.1-cp312-cp312-win32.whl", hash = "sha256:bc0bca48ba24c6c866847fd20478a51dd547fa0ad258dab9615c414ec534bbc0", size = 213050, upload-time = "2026-07-31T11:29:52.328Z" },
{ url = "https://files.pythonhosted.org/packages/82/d8/c3a78cccc74a554780e9e76e323d5cde891048627025f0f82623e22dc3df/websockets-17.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:2b3f3020171202b135ca078e20434977c6b2b02af647130d6980c9e39b9462e3", size = 213348, upload-time = "2026-07-31T11:29:53.891Z" },
{ url = "https://files.pythonhosted.org/packages/7b/25/e1b8824bd632c8a5a62d504b61e9e35e470b67e4be0206f5c28f90c7f86d/websockets-17.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:41d6aa06b5ab832aee72fedf47a149535b121ac900b6bb4d3fe14712afac9a79", size = 213276, upload-time = "2026-07-31T11:29:55.299Z" },
{ url = "https://files.pythonhosted.org/packages/ba/a8/79c577bc2f874ee22f6f5ccdab97ba9ce6b96806be3fcc3a6d8490f88a21/websockets-17.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:55b12e47dcee83673a40d07686cfb6f9d6dfc285976ade9463f61d2bef3fad22", size = 212593, upload-time = "2026-07-31T11:29:56.518Z" },
{ url = "https://files.pythonhosted.org/packages/db/99/e1cfaf419bb3b2fcfd6792a846f1d936293132b0b9a56530ced016c83c7b/websockets-17.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c1c118a6b0e25bfc9a6802075d748fa6321714ffbdf3c88d29d9a0e3c7386c75", size = 210280, upload-time = "2026-07-31T11:29:57.768Z" },
{ url = "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:734d20364dc2cfe03674883cafcf580b6e431c5ce42b476312b9285310230cf9", size = 210538, upload-time = "2026-07-31T11:29:59.021Z" },
{ url = "https://files.pythonhosted.org/packages/87/32/fbf2d132f63ba3e67f675bccf333469786a24e0418969ce1d8e6ff9e6f02/websockets-17.0.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9493314a99e599163c854fb5900ad7f7ea38c5cb9d9103aa30b3c6b8181c01fa", size = 219925, upload-time = "2026-07-31T11:30:00.298Z" },
{ url = "https://files.pythonhosted.org/packages/16/50/64eee3d25a47fe744a9490e0627cc373dca096755db740f91c28bd61cd35/websockets-17.0.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:18ded646ce98cdd3c0235825b3252f1df55765ba49b616bb10282f758667b4d0", size = 220206, upload-time = "2026-07-31T11:30:01.52Z" },
{ url = "https://files.pythonhosted.org/packages/15/56/10ed4bc4dd75f204e3c62bd4898e44a8742a27773c80b188cfa7888aad2d/websockets-17.0.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1bec5d6a19f5fbe87e4940739cfc65e7bb53d8b353e1029b8037a1653b321bc", size = 221445, upload-time = "2026-07-31T11:30:02.788Z" },
{ url = "https://files.pythonhosted.org/packages/bf/be/bb14328614c068ab09569962fbf218fc00413ce3febc6d2684c764b6f37e/websockets-17.0.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:872273e629ca7e3d35f16a2dc6ede84e1d5c831e616b8277de6e4f83114e7c58", size = 222887, upload-time = "2026-07-31T11:30:03.943Z" },
{ url = "https://files.pythonhosted.org/packages/32/1b/4cb0eec2fee310007104687493175af190019f705940c864f9c523fe9f6f/websockets-17.0.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1df81d174c1561292de9e40b141cafc04f69077272f6c352afe1d743e20810df", size = 222072, upload-time = "2026-07-31T11:30:05.258Z" },
{ url = "https://files.pythonhosted.org/packages/6c/9c/14e6391de777ddb39c439c450deb551406d445e25a5877d6fa25c49d4544/websockets-17.0.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:759adeb5b0c5775b563254ec63b5b79089fc0045b479143a0b1b8c0ebaae1253", size = 220826, upload-time = "2026-07-31T11:30:06.53Z" },
{ url = "https://files.pythonhosted.org/packages/cb/57/96e94e384442247bbed5d3ab67381c7257355c2d66b62c3ad33a17f5d385/websockets-17.0.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1d99db29b5444e3982f1ce2ba8a833508ad44b2f1fbd0bd99e81d825c0b461", size = 218107, upload-time = "2026-07-31T11:30:07.766Z" },
{ url = "https://files.pythonhosted.org/packages/c0/8c/9c9dedd14c3919435df9b35cdee7111268c751252b87652f3a6a4f56e760/websockets-17.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:02ed63bf26dda9fa27df730a41f6664586c4ee05972c8fb667ce1725b3fd13d3", size = 220889, upload-time = "2026-07-31T11:30:09.035Z" },
{ url = "https://files.pythonhosted.org/packages/94/4d/ca73c2ac82c00f50c529784bacb323e42da4816333211bc1543d90c9cf11/websockets-17.0.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:eab6de8a98b9a7772cf686d00b4de439fc7efb8ab05ae106ef227291d06f87c5", size = 219486, upload-time = "2026-07-31T11:30:10.289Z" },
{ url = "https://files.pythonhosted.org/packages/5b/da/fb37ac09dcd7c69dd73bac979ed393df35f78a3c232e293d1ff3bd586d24/websockets-17.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2a855b6dfe21c4d3420be265ae031829ba8ba0be0ea350d9f7c3ef30ae63ebe2", size = 220258, upload-time = "2026-07-31T11:30:11.605Z" },
{ url = "https://files.pythonhosted.org/packages/fc/04/9693f191d968a93f37326a17301a101d49580889c688f466699f89ecdee1/websockets-17.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7002d5f9e1c3ddd991cdfdbfee18cc8c8b196b2445022892badacd6cb338bbbc", size = 221358, upload-time = "2026-07-31T11:30:12.858Z" },
{ url = "https://files.pythonhosted.org/packages/cf/29/ad0d85c01db5dcf22898d51648bd2c25af0dd0a4a41c550b11acddeeeba7/websockets-17.0.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c395bda8e7d8f51a02e80261fb57127979e5c472675d9a96b2860619ad47da48", size = 218921, upload-time = "2026-07-31T11:30:14.064Z" },
{ url = "https://files.pythonhosted.org/packages/18/3b/bf8e855e495dcca63f2b8aa019cf2ada3160e1fa66d833c7417f3b1f7f38/websockets-17.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aadc298969ad229d8e3029fc5cc751fdad286696230f9cf014e90ff9cd8e6ea0", size = 219871, upload-time = "2026-07-31T11:30:15.358Z" },
{ url = "https://files.pythonhosted.org/packages/3b/db/c7abd6639a93a40279cd1ddc57e09e1c4f8381c4cfccdb775aa5aac9770a/websockets-17.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f11a398d8170b7ac5000baf7f258dcda579ef3ea744e0cc6a165e0dfbc0d3198", size = 220154, upload-time = "2026-07-31T11:30:16.96Z" },
{ url = "https://files.pythonhosted.org/packages/f6/2a/25a9f8f2e5a6ef34e911d2f55d9f756bdeb92b4c28cfb77b8430bbc73cb1/websockets-17.0.1-cp313-cp313-win32.whl", hash = "sha256:846a4a8b0833e3cad57523d9e3bd50ec8ea05ab9d06c582f82a1340ba096af5f", size = 213038, upload-time = "2026-07-31T11:30:18.434Z" },
{ url = "https://files.pythonhosted.org/packages/81/2f/ea1380f72bb11b64fc5bc7ae0d42de5bbf3e6dc13b965706b2a1d4e17cdf/websockets-17.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:409d93efcaa14f7a99592c5baaef5ec6ca94fba0f5aec1a86f693977c69c9c1c", size = 213348, upload-time = "2026-07-31T11:30:19.693Z" },
{ url = "https://files.pythonhosted.org/packages/e6/c7/b956ed9151c3c74530ebc62d716fbfdbde7507a6acc6423a64f9ecfb6b8a/websockets-17.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:90246fa9e6cb192a778ce6ce024057ec54317a894db7899c922dcdc1f4cbf6a5", size = 213282, upload-time = "2026-07-31T11:30:21.045Z" },
{ url = "https://files.pythonhosted.org/packages/98/dc/cadab608924ac605647031472fb1f8792d7d4ea07565ba1899ec42028e0d/websockets-17.0.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:53b90c00bc6201ab6695c7ff51a04d0e425514c37515e9eeecd2c1b978ac6c0e", size = 212640, upload-time = "2026-07-31T11:30:22.436Z" },
{ url = "https://files.pythonhosted.org/packages/16/7a/b034d13ca181211bbd58bb50835cb196a7784cd505b5a2079d4d03374f9f/websockets-17.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5f33a649bfcb8312524173cc4bbafa7dbb236e18eee9aa31a1d324ca0ddda28c", size = 210332, upload-time = "2026-07-31T11:30:23.608Z" },
{ url = "https://files.pythonhosted.org/packages/2f/4d/943ede39b53744768edf1ed84a3f9401527388228a3d6c1249c02c3d6bd7/websockets-17.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cddc675ec31bca65473321f9a9794e488b43b3b8de5d02c8ef4810c5d5792163", size = 210546, upload-time = "2026-07-31T11:30:24.932Z" },
{ url = "https://files.pythonhosted.org/packages/cf/e3/88dc159d2ae66743c669443246243f28d873b0c5e58271b8cc1ca0440334/websockets-17.0.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b3ff0ad440ad52dda64138f16895f66403f40192365e39b1010e889f289746b0", size = 219928, upload-time = "2026-07-31T11:30:26.221Z" },
{ url = "https://files.pythonhosted.org/packages/fe/f2/ff27eaefa15851a5cf7f004ab827a022bf2d6632cb520f89cb100db7e84b/websockets-17.0.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:72d7f2a5aeb4e82daa4ee18f125b4277f427033359be5c745ad709608446cc2c", size = 220279, upload-time = "2026-07-31T11:30:27.49Z" },
{ url = "https://files.pythonhosted.org/packages/19/2e/a5166149f363d2449c1cb2dde6486a245521979509d53b87a09f3e79662b/websockets-17.0.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6fd88365da261c53d3e943fb37e0d0721b9cde119f6b2e3fc84369b6ab234d63", size = 221525, upload-time = "2026-07-31T11:30:28.872Z" },
{ url = "https://files.pythonhosted.org/packages/9b/b5/f46931269b3ff3bde65d27c65ddb22f9bb8ce92ac2c6c4df0910128f6219/websockets-17.0.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ab9f962a5b64a5c3c845d556b7dc4e6fb683f7b67179f8205e814bb2e0213ffe", size = 222897, upload-time = "2026-07-31T11:30:30.164Z" },
{ url = "https://files.pythonhosted.org/packages/42/f4/deccf3439f35df953ec35e13fe07986821c5f1ab5785d69614283bdb9034/websockets-17.0.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c07f145d0b9e90cbd96035f31fb79199aef4da1872854e36ebeb258e3d57594", size = 222129, upload-time = "2026-07-31T11:30:31.489Z" },
{ url = "https://files.pythonhosted.org/packages/35/a5/e1b57a59da92ade37fd021567a17b518ea8267b28e5530075844cdb525fe/websockets-17.0.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9f7747d3daa41a11f25f7cca5dc988fc51da97b311bed4c9d843860f79779283", size = 220875, upload-time = "2026-07-31T11:30:32.805Z" },
{ url = "https://files.pythonhosted.org/packages/f0/30/e7d0889c790a854156de424575fd67af79ddbaed9ff3157ae863dfd1c1dc/websockets-17.0.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2abb1ba0a5133b7d2ef3c1c9f4b0c1e8a101012dce0b594ab2b2888d9a64820e", size = 218160, upload-time = "2026-07-31T11:30:34.512Z" },
{ url = "https://files.pythonhosted.org/packages/09/2e/43db785d6ed9ae7594fae7b62bbc9cb4dfee2b015e06a1005f1e5ce283b6/websockets-17.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f3fd9a1f87f8f0f3f8e9f9bd0195f7516562d13f5b178db8c5784d1f60b60bed", size = 220951, upload-time = "2026-07-31T11:30:35.806Z" },
{ url = "https://files.pythonhosted.org/packages/eb/f5/4ac3cab3d5e8a830657a822f64a8910e3803229c6783e59c3fd9a3487427/websockets-17.0.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2bc14b481e05e331811108daa1aeb41a5e237a5564ef2f02ec5a356a0f102f78", size = 219460, upload-time = "2026-07-31T11:30:37.273Z" },
{ url = "https://files.pythonhosted.org/packages/03/0e/c3a4020673ffc17c82cf1a467835038a196a555d3b4f2a50f0f063cf8ccc/websockets-17.0.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:57d2ee9b24b404ce75f3814f92073c0ed88106c950148d2427fe8d25ca254d1f", size = 220248, upload-time = "2026-07-31T11:30:38.527Z" },
{ url = "https://files.pythonhosted.org/packages/7d/87/e47a6a278cc1dfade38444c893ce18322943c25d4b780a74450d9d164be1/websockets-17.0.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1b363bfd72a52c0658a3154a4cff219f15a474b35a235057d38853bf151acce7", size = 221421, upload-time = "2026-07-31T11:30:39.879Z" },
{ url = "https://files.pythonhosted.org/packages/da/8f/473d5fc4e3836e375b0233c6ef26777e6e5e3f7bfc84ccd524eae4090ed5/websockets-17.0.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:10b1587c599fa0f2c89154587c80e0fda98ade6c9fa8c0260a2823fb1800b685", size = 218975, upload-time = "2026-07-31T11:30:41.192Z" },
{ url = "https://files.pythonhosted.org/packages/d4/b9/819ec2dcdf69031d7e9cab11247f3a6ff9bbc8c7c53ada1dbcb9055b227b/websockets-17.0.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d7d72843691f50b91127c50688df10cb72ec6f4c4b1d7e2c11ab33b16acf8e51", size = 219925, upload-time = "2026-07-31T11:30:42.524Z" },
{ url = "https://files.pythonhosted.org/packages/85/b9/6c0da301f6118502e079cf92f4e864adf28e56b3f8c0f6085076ced7b876/websockets-17.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90973a3a00f23afdfd1c9b06fb84289bf0220f247ef8a62501a1967c7af54f7b", size = 220218, upload-time = "2026-07-31T11:30:44.04Z" },
{ url = "https://files.pythonhosted.org/packages/55/f9/cba32dc9dd856565263d6272f594255bd0e2781deb8cd982c026a54760ad/websockets-17.0.1-cp314-cp314-win32.whl", hash = "sha256:599b03beb77633bffc095334338fad79cafc2b01fbd58953838130a9ae967d7b", size = 212626, upload-time = "2026-07-31T11:30:45.579Z" },
{ url = "https://files.pythonhosted.org/packages/fa/95/91cdd8c192287d7ea741f37cf7d64fdc1a14410f06f73805e428a1a590af/websockets-17.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:81ce19c6046ace11da7001781be7317bb1dc389f399af4b2ed962190f76f9add", size = 212969, upload-time = "2026-07-31T11:30:46.983Z" },
{ url = "https://files.pythonhosted.org/packages/8e/fd/8c98a1e431960661c5769ab1a4dd66494e87ab02d791cc79e51e0d9a289f/websockets-17.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:efe0ae052a8d023b87198921e8a7ce1dc7768816bcd2fbc20df171ac73a04891", size = 212850, upload-time = "2026-07-31T11:30:48.304Z" },
{ url = "https://files.pythonhosted.org/packages/13/c1/142f5186ee7dc3beee0426b998a79e223e067b7689afcaa95890d64aa800/websockets-17.0.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ab56439c9f74c52770690c7b2f616b3bf775cb3920453ee355ac765c032d8bbf", size = 212967, upload-time = "2026-07-31T11:30:49.688Z" },
{ url = "https://files.pythonhosted.org/packages/02/de/4b03ed316c9dee180365286c298219809ff247be39beeaaf9958b21167ab/websockets-17.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:20a92f78ac8250984ed459faa9ca48c285adbfc0038ddc3fdac6046990a9c9ed", size = 210504, upload-time = "2026-07-31T11:30:50.987Z" },
{ url = "https://files.pythonhosted.org/packages/cd/d8/ad2b3e8f867e1e8cac3077e2f33ffb60b71bd763d6cfc71bd916f113c3bf/websockets-17.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6a434e59962a4fb9016bea327e1d14d6cd67670ecfb8942b4f4a0c24036634ce", size = 210702, upload-time = "2026-07-31T11:30:52.261Z" },
{ url = "https://files.pythonhosted.org/packages/48/18/7a77a82ce9d6f831c07b176da3942f7e71acd0f115f3ecdb1d00a040eb01/websockets-17.0.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2503c7e2a5049a12d5dac917a46d5d52591283a766165b8176bb167560421b38", size = 220290, upload-time = "2026-07-31T11:30:53.582Z" },
{ url = "https://files.pythonhosted.org/packages/f5/af/43c3e3c3ea7ba4693c2181743f3221957df28bededadcbd9fc8a0661bde0/websockets-17.0.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:28012a54510fe8301bb893ef143cec30a2780a2d3bc20b7bbdf4379d7a63945d", size = 220573, upload-time = "2026-07-31T11:30:54.966Z" },
{ url = "https://files.pythonhosted.org/packages/1f/bd/ed48eca15725743ee7e2dc172e15c61de29e85ec98dace7b14257f366836/websockets-17.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22bd00f8bae2bccdb5dbe41e20f58ba44ca9fff0b4b561aaf39099c35da762ed", size = 221747, upload-time = "2026-07-31T11:30:56.762Z" },
{ url = "https://files.pythonhosted.org/packages/99/50/838deb7937a8225c4925dd4a977eafea473fabf444178a99de0bc7e92bb0/websockets-17.0.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e98ec9ec61cce5bc4b8b218322ad090b0994eb060bb04da704c62ef0a3d864e6", size = 223891, upload-time = "2026-07-31T11:30:58.127Z" },
{ url = "https://files.pythonhosted.org/packages/f8/e9/657fb70c6eb6bcd01adfa5d2b06496e9911e1c1a8813d353b8c00f7591cd/websockets-17.0.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8e387adb0c692c6b5571bdeafc8ac9d1901ea30f10309134780b16ecd35e6605", size = 222317, upload-time = "2026-07-31T11:30:59.416Z" },
{ url = "https://files.pythonhosted.org/packages/07/4c/82cb722afa5428fed981331210c4c07600570db01bb1620579f655b5adaf/websockets-17.0.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bd1470d2c53fe53269bf5619da7725d30dd9b9693f1689f7a85eab8dea734442", size = 221047, upload-time = "2026-07-31T11:31:00.757Z" },
{ url = "https://files.pythonhosted.org/packages/90/84/bd6d67d6bc65f0de0cb50de55dab42f256a9876a351c4736522eb168fda0/websockets-17.0.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:884af729b8ab50486acd94d9768c2b60914bf39b579ebba0a5cb73bfdfd61fd2", size = 218626, upload-time = "2026-07-31T11:31:02.48Z" },
{ url = "https://files.pythonhosted.org/packages/96/cb/6a372c8553976f0d8f97f5115826ed47e34b3be6b8bf0d0249af249a7416/websockets-17.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a60fa1a25cca1bcc2bf87b8d6be37a741f0a3239fb5e9cfb7a37173b68ffcf87", size = 221299, upload-time = "2026-07-31T11:31:03.795Z" },
{ url = "https://files.pythonhosted.org/packages/bc/31/f966e8472337974f74d788b3ef6c6f3b8b9a5f201efd16a843c91d269fa5/websockets-17.0.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:e8208f2729cba030ff872a92064c97584eeb9502f53d32a05a0f05d5a17ca6c6", size = 219789, upload-time = "2026-07-31T11:31:05.08Z" },
{ url = "https://files.pythonhosted.org/packages/57/34/404e83a6cc7b0efcac810b7041bffd72ff76900e6fd0aa45a26c92fb2ffe/websockets-17.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:54cdcaa56f5d3eafd57058f0fa4a3de93a310b43a3c4699f06efc4c0bd054a5a", size = 220678, upload-time = "2026-07-31T11:31:06.635Z" },
{ url = "https://files.pythonhosted.org/packages/e5/70/8946188c2a68d67251859b589a3634918cf7867bf0b891347a5ecaa43d30/websockets-17.0.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4d41c0a1d47a478bc432b3b9068097bee1ce0c5b19327ea6f75c2ab34ab1f2fb", size = 221697, upload-time = "2026-07-31T11:31:08.023Z" },
{ url = "https://files.pythonhosted.org/packages/04/16/ee73fc2083a2938ac6209f4ec804960496835b20a0068dbcfe8424957c04/websockets-17.0.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f991247276797d0c61ab7770bc9791eadc16f683b4d83517f624932adc1a8bab", size = 219390, upload-time = "2026-07-31T11:31:09.378Z" },
{ url = "https://files.pythonhosted.org/packages/94/6a/d5f88033c69932af6cdaa72da62516ade47c257e3bf69f4c0ba5f40e12a2/websockets-17.0.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:733e3cc7171fa1b899edbe725ef9382d0e960657dc1fd933f3281ae910c01dab", size = 220161, upload-time = "2026-07-31T11:31:10.915Z" },
{ url = "https://files.pythonhosted.org/packages/e1/2e/6183dd2c0370287ecf4afe0bb33aca364208e5e7b0e1a286adcaecc0c78b/websockets-17.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:810cb3fb5fa6e447216f4e82d9a85cb8aed0929ae3538153ddfe8a6e3121a58d", size = 220591, upload-time = "2026-07-31T11:31:12.289Z" },
{ url = "https://files.pythonhosted.org/packages/26/93/70f6516d85b9744f7eac224c4b1b9ef4e84133f80b53be02080cb1c3e663/websockets-17.0.1-cp314-cp314t-win32.whl", hash = "sha256:17ac37716c0244e82c9e384c41653c090b1864c6610224ca3857e7f7b58fce10", size = 212755, upload-time = "2026-07-31T11:31:13.883Z" },
{ url = "https://files.pythonhosted.org/packages/f1/2c/9d9c1da5a7ea9af307b386d25f64d1dead4729644198d2b92e36db5dfd41/websockets-17.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bb31f42ea095ea826463c770829aa188a86c9a5c976b1467cbbf583c811de833", size = 213094, upload-time = "2026-07-31T11:31:15.367Z" },
{ url = "https://files.pythonhosted.org/packages/5b/24/a585e7573e128070605d003b5544729bcd58d9756c7e99d550818ca4b916/websockets-17.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:dbfae8e75b342e31fc6fd1a8bbb393b7cbb91d6cfd581650300a94381e7b7e2b", size = 213009, upload-time = "2026-07-31T11:31:16.776Z" },
{ url = "https://files.pythonhosted.org/packages/51/77/63b4abd29f15107d856f010de6f35434faa7c49ef89151e051d2807a9c40/websockets-17.0.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:49266e4488309b38783257293a38298942b9a03aa106fcb45195377a77c0c1e2", size = 210194, upload-time = "2026-07-31T11:31:18.046Z" },
{ url = "https://files.pythonhosted.org/packages/ef/ab/6160542ee644f72b865af13ddfff23740c95595b237e16312262cafdb641/websockets-17.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d69fd559f9f0e8a52d2fce6f04ee143f86e70df0a189cd95164eddac599e810f", size = 210465, upload-time = "2026-07-31T11:31:19.333Z" },
{ url = "https://files.pythonhosted.org/packages/53/1a/d4437d3cb0691eeac2c6064e21c83a9eeda04f6ef0261abfc0dde708590d/websockets-17.0.1-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a39ce3a7b0e6059be093213d637963101380157bcbad355916738fafb490698d", size = 211417, upload-time = "2026-07-31T11:31:20.687Z" },
{ url = "https://files.pythonhosted.org/packages/88/28/2d671e23a20359a1cc142848384659813b49028d46cb0acdc28e81ac59b5/websockets-17.0.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2437d4ca208cc0f246d3a2297ae7474b4ba18261aaf5b9c79c84c031ecf348e1", size = 211309, upload-time = "2026-07-31T11:31:21.969Z" },
{ url = "https://files.pythonhosted.org/packages/02/52/b85a676b161991e5c0d884252376435f60510789e7740e3da73489d22a6e/websockets-17.0.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6740be6d1bab69f08ab52cb15b08f76c143b6fe61c580ba62bd929f3ab7a1d42", size = 212203, upload-time = "2026-07-31T11:31:23.38Z" },
{ url = "https://files.pythonhosted.org/packages/bf/e3/91e297e41381d9131f3142a9c1a50389fd96b98125ce9b81526fa4e14b9f/websockets-17.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:afbce6e3f0fac32dc87c2a0d84869d1a706460d64f39f3889386413e6e4d3d26", size = 213434, upload-time = "2026-07-31T11:31:24.707Z" },
{ url = "https://files.pythonhosted.org/packages/09/ce/3929538b2b9918f5eee623fbf3346893973191f6df93f19bbda097bd7bb7/websockets-17.0.1-py3-none-any.whl", hash = "sha256:c6be9cba65c65cc76dfa3d4619e359ff02a4476c74e179b215236c11a0b32345", size = 206718, upload-time = "2026-07-31T11:31:26.037Z" },
]
[[package]]
@@ -3677,77 +3704,77 @@ wheels = [
[[package]]
name = "wrapt"
version = "2.2.2"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/fe/a4/282c8e64300a59fc834518a54bf0afabb4ff9218b5fa76958b450459a844/wrapt-2.2.2.tar.gz", hash = "sha256:0788e321027c999bf221b667bd4a54aaefd1a36283749a860ac3eb77daed0302", size = 129068, upload-time = "2026-06-20T23:49:44.49Z" }
sdist = { url = "https://files.pythonhosted.org/packages/2b/b0/c1f5a970721f06b85c0cd5142e0ff8fe067708abd779b0c4f4be7d61d09f/wrapt-2.3.0.tar.gz", hash = "sha256:681a2d0eefd721998f90642762b8e75c2159ec531b20ad5e437245ea7b06a107", size = 131509, upload-time = "2026-07-28T06:06:14.895Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/27/15/0c2d55168707465abfc41f33c0b23d792a5fa9b65c26983606940900a120/wrapt-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f1a2ff355ece6a111ca7a20dc86df6659c9205d3fcee674ca34f2a2854fd4e73", size = 80782, upload-time = "2026-06-20T23:47:44.367Z" },
{ url = "https://files.pythonhosted.org/packages/7d/b5/5c0b093eb48f8a062ef6267d3cb36e9bb1b88440181f6545a383c60efdf8/wrapt-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55b9a899e6fff5444f229d30aa6e9ac92d2216d9d60f33c771b5d76a760d5f8e", size = 81678, upload-time = "2026-06-20T23:47:45.857Z" },
{ url = "https://files.pythonhosted.org/packages/34/f3/de70937472dd3e8a4e6811192f9c6075efdffd4a2cd9b4596bf160f89668/wrapt-2.2.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a2d78c363f97d8bd718ee40432c66395685e9e98528ccaa423c3355d1715a26d", size = 159671, upload-time = "2026-06-20T23:47:47.345Z" },
{ url = "https://files.pythonhosted.org/packages/a5/ec/40aed2330e7f02ecf74386ffcfef9ccb7108c6a430f15b6a252b663b1bed/wrapt-2.2.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d619e1eed9bd4f6ed9f24cd61971aa086fa86505289628d464bcf8a2c2e3f328", size = 160785, upload-time = "2026-06-20T23:47:48.759Z" },
{ url = "https://files.pythonhosted.org/packages/45/04/aa5309beed5344b00220ae6b3b24055852192656194c27947bee1736306a/wrapt-2.2.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:518b0c5e323511ec56a38894802ddd5e1222626484e68efe63f201854ad788e5", size = 153699, upload-time = "2026-06-20T23:47:50.177Z" },
{ url = "https://files.pythonhosted.org/packages/01/df/2def7e99d1fe87eea413f95f671924cdddcb08823b1ffd212748dfa6d062/wrapt-2.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4bccea5cdecffa9dd70e343741f0e41e0a16619313d04b72f78bb525162ebcd0", size = 159695, upload-time = "2026-06-20T23:47:51.602Z" },
{ url = "https://files.pythonhosted.org/packages/c7/f6/a906d01a2ce12157bad2404957b3e2140da354b8a70b2fa48bbf282871c0/wrapt-2.2.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:209112cafd963710a05d199aae431d79a28bc76eb8e6d1bbbb8ad24340722cae", size = 152813, upload-time = "2026-06-20T23:47:53.03Z" },
{ url = "https://files.pythonhosted.org/packages/02/49/bc0086292d239575b4c08f4cf8a4079fa58abbad58ec23abf84833a283ed/wrapt-2.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e5a5290e4bf2f332fc29ce72ffb9a2fff678aaac047e2e9f5f7165cd7792e099", size = 158809, upload-time = "2026-06-20T23:47:54.391Z" },
{ url = "https://files.pythonhosted.org/packages/55/83/8fbd034de1f3e907edaa18786d5dd8f6932874edee0826c7cecb5cab03a1/wrapt-2.2.2-cp311-cp311-win32.whl", hash = "sha256:5499236ad1dc116012e2a5dd943f3f31af12fce452128e2bbcbd55a7d3d4d14c", size = 77414, upload-time = "2026-06-20T23:47:55.882Z" },
{ url = "https://files.pythonhosted.org/packages/7e/9c/23695baa331c6de4e874c3d78b8e0bed92e1d2a274e665b29858f6841672/wrapt-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:8636809939152be6ae20a6cef0fed9fe60f411b47847d0426a826884b469e971", size = 80368, upload-time = "2026-06-20T23:47:57.237Z" },
{ url = "https://files.pythonhosted.org/packages/08/49/40cefc342bf89b234a4490d741290fce781774b831aefb39c25471da96c9/wrapt-2.2.2-cp311-cp311-win_arm64.whl", hash = "sha256:5d0a142f7af07caeb5e5da87493162a7b8efa19ba919e550a746f7446e13fb30", size = 79489, upload-time = "2026-06-20T23:47:58.56Z" },
{ url = "https://files.pythonhosted.org/packages/2a/85/180b40628b23772692a0c76e8030114e1c0ae068470ed531919f0a5f2a4a/wrapt-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8417fd3c674d3c8023d080292d29301531a12daf8bd938dd419710dd2f464f2b", size = 81484, upload-time = "2026-06-20T23:47:59.924Z" },
{ url = "https://files.pythonhosted.org/packages/94/f2/21c90f2a16689702e2aaff45795b11018dff2c9b1242bac10d225483f676/wrapt-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e7070c7472582e31af3dfc2622b2381a0df7435110a9388ed8db5ffbce67efb", size = 82151, upload-time = "2026-06-20T23:48:01.303Z" },
{ url = "https://files.pythonhosted.org/packages/5f/b3/7e6e9fcf4fe7e1b69a49fe6cc5a44e8224bab6283c5233c97e132f14908e/wrapt-2.2.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2e096c9d39a59b35b63c9aacfbbbec2088ff51ff1fc31051acc60a07f42f273a", size = 169828, upload-time = "2026-06-20T23:48:02.719Z" },
{ url = "https://files.pythonhosted.org/packages/0b/43/894f132d857ed5a9904d937baf368badcbe5ea9e436e2f1930fe21c9f1f0/wrapt-2.2.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d1a6050405bf334be33bf66296f113563622972a34900ae6fa60fd283a1a900", size = 171544, upload-time = "2026-06-20T23:48:04.266Z" },
{ url = "https://files.pythonhosted.org/packages/29/de/3c833e03725b477e9ea34028224dd21a48781830101e4e036f77e8b6b102/wrapt-2.2.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10adb01371408c6de504a6658b9886480f1a4919a83752748a387a504a21df79", size = 160663, upload-time = "2026-06-20T23:48:05.708Z" },
{ url = "https://files.pythonhosted.org/packages/33/be/27edce350b24e3054d9d047f65f16d4c4d4c1f3f31c4278a1f8a95c723c8/wrapt-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3442eee2a5798f9b451f1b2cd7518ce8b7e28a2a364696c414460a0e295c012a", size = 169387, upload-time = "2026-06-20T23:48:07.243Z" },
{ url = "https://files.pythonhosted.org/packages/e2/c4/9fd9679af8bf38e146652c7f47b6b352c3e5795b4ad1c0b7f94e15ac2aa7/wrapt-2.2.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6c99012a22f735a85eed7c4b86a3e99c30fdd57d9e115b2b45f796264b58d0bf", size = 158849, upload-time = "2026-06-20T23:48:08.91Z" },
{ url = "https://files.pythonhosted.org/packages/bc/c2/aa6c0c2206803068c6859dabe01f8c84c43744da93d4c67b8946d21655ee/wrapt-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b686cfc008776a3952d6213cb296ed7f45d782a8453936406faa89eac0835ab", size = 168147, upload-time = "2026-06-20T23:48:10.374Z" },
{ url = "https://files.pythonhosted.org/packages/42/63/3eb25da41049d20ae18fcab2dd8b056e02387c4bfa626cbdfb7c3b872e4f/wrapt-2.2.2-cp312-cp312-win32.whl", hash = "sha256:ef2cce266b5b0b07e19fa82e59673b81142b7a3607c8ed1254113d048ed668da", size = 77734, upload-time = "2026-06-20T23:48:11.769Z" },
{ url = "https://files.pythonhosted.org/packages/da/09/0390e008a305360948fa9ce69507d041ac12cb2ee5d28e34467e2ee79391/wrapt-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:abf8c20a2d72ee69e16328b3c91342c446e723bfe48bfcc4dded3b9722ac027f", size = 80585, upload-time = "2026-06-20T23:48:13.117Z" },
{ url = "https://files.pythonhosted.org/packages/d3/b3/84c445c66969f2d3457276b183a48c91097d59bbef9af6c075366b0f8c36/wrapt-2.2.2-cp312-cp312-win_arm64.whl", hash = "sha256:c6c64c5d02578bc4c4bca4f0aef1504de933c1d5b4ac2710b9131111459506c8", size = 79553, upload-time = "2026-06-20T23:48:14.5Z" },
{ url = "https://files.pythonhosted.org/packages/43/fc/f32f4b22c6511173c11d9e541ab4e7d8467a0f1b3455acaf784115d31ff8/wrapt-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9e8b648270c613720a202d9a45ebabc33261b22c3a839b115ac5bce8c0bb0d69", size = 81296, upload-time = "2026-06-20T23:48:15.881Z" },
{ url = "https://files.pythonhosted.org/packages/72/06/4d117d5d77a9344776c0248b24dae3d3dd2f58e5f765fa08cf887072e719/wrapt-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6fb7e94e8fe3e4c3067bb1653a91cce7c5e83acc119fdd41501b1bf74654617", size = 81841, upload-time = "2026-06-20T23:48:17.262Z" },
{ url = "https://files.pythonhosted.org/packages/15/ff/63ad96f98eb58a742b1a20d80f21da88924405910149950b912368150468/wrapt-2.2.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb18fc51e813df0d9c98049e3bf2298a5495a648602040e21fa3c7329371159e", size = 167882, upload-time = "2026-06-20T23:48:18.764Z" },
{ url = "https://files.pythonhosted.org/packages/20/1f/8bb62d8933df7acf3247194e6e9fc68edf9d2fa203252c89c94b319dd472/wrapt-2.2.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94b00b00f806eb3ef2abe9049ed45994a81ee9284884d96e6b8314927c6cea3d", size = 167411, upload-time = "2026-06-20T23:48:20.315Z" },
{ url = "https://files.pythonhosted.org/packages/17/09/8789dcb09ee1de715727db7521aabbb68ffa68dfade3a49468440cfced49/wrapt-2.2.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:62415fd095bc590b842b6d092f2b5d9ccbaeb7e0b28535c03dcea2718b48636b", size = 158607, upload-time = "2026-06-20T23:48:21.728Z" },
{ url = "https://files.pythonhosted.org/packages/9c/20/66e02562d53ee67d841f175e38e3c993c2d78a3e104c576cad61c028b43c/wrapt-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a41e758d80dc0ab8c210f641ac892009d356cf1f955d97db544c8dd317b4d14c", size = 166367, upload-time = "2026-06-20T23:48:23.177Z" },
{ url = "https://files.pythonhosted.org/packages/bd/a3/832ac4e41222fb263b3042d42c2f08d305db7d0f0c9b1d3a271a9eede8f6/wrapt-2.2.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:b84cd4058001c9727b0e9980b7a9e66325b5ca748b1b578e822cade1bc6b304f", size = 157176, upload-time = "2026-06-20T23:48:24.711Z" },
{ url = "https://files.pythonhosted.org/packages/b7/01/1bd5e4d2df9c0178989ac8da9186543465388588ee2ef153e2591accebef/wrapt-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:26fc73a1b15e0946d2942b9a4426d162b51676338327dc067ccd8d2d76385f94", size = 167025, upload-time = "2026-06-20T23:48:26.118Z" },
{ url = "https://files.pythonhosted.org/packages/1c/69/583ed25291ab53e1ec117135fb1c33425e2f46d2bc8f29c17f7a94cf4274/wrapt-2.2.2-cp313-cp313-win32.whl", hash = "sha256:3c4095803491f6ef72128914c28ec05bbad9758433bb35f6715a3e9c8e46fb2d", size = 77605, upload-time = "2026-06-20T23:48:27.643Z" },
{ url = "https://files.pythonhosted.org/packages/29/68/e69fc6d06e1523c68e0d00f95c9aed1158ce9908ee41603f7f2eae3d5db6/wrapt-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:2cb07f414fab25dbe6b5c7398e1491423a5c81a6209533639969a6c928d474a4", size = 80508, upload-time = "2026-06-20T23:48:29.013Z" },
{ url = "https://files.pythonhosted.org/packages/55/21/fe7a393d9e5dc0923bed8f5d857e9dcff210f1fa0888c02cc8f3ffaa55aa/wrapt-2.2.2-cp313-cp313-win_arm64.whl", hash = "sha256:1fc7691f070220215cccb2a20836b9adbaecb8ff22ad47abe63de5f110994fac", size = 79565, upload-time = "2026-06-20T23:48:30.429Z" },
{ url = "https://files.pythonhosted.org/packages/b6/e5/c120d13bf5091164f68c3c1657e84f16f57e71d978421b626393ac5bd7eb/wrapt-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ec8f83949028366531383603139403cac7a826e4011955813cdd640017845ce5", size = 83264, upload-time = "2026-06-20T23:48:31.807Z" },
{ url = "https://files.pythonhosted.org/packages/d3/b0/d4a1eb97e0e286625bdf21bc7f702637f9607787ffbbdb5ec14d50c79dbf/wrapt-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b481fb0c40d9fd90a5809911208da700987d373a20a4709dc9e3944af7a6bec", size = 83791, upload-time = "2026-06-20T23:48:33.482Z" },
{ url = "https://files.pythonhosted.org/packages/18/1e/f060df47755e87b57684cee7bfc1362b204df55fac96ffebc0631b697b79/wrapt-2.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0065a3b657cec06813b4241d2462ccec287f6863103d7445b725fb3a889736f9", size = 203399, upload-time = "2026-06-20T23:48:34.97Z" },
{ url = "https://files.pythonhosted.org/packages/c4/de/2316a757a1abb6453700b79d83e532146dcef2611348282d4d8889792161/wrapt-2.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30f7424af5c5c345b7f26490e097f74a2ef45b3d08b664dc33571aee3bd3b56c", size = 210461, upload-time = "2026-06-20T23:48:36.569Z" },
{ url = "https://files.pythonhosted.org/packages/ed/29/d1160785ae18ca2495a6d82a21154103d74f656c9fd457fb35f6b11b965a/wrapt-2.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07fdcb012821859168641acf68afad61ef9783cf37100af85f152550e9677194", size = 195313, upload-time = "2026-06-20T23:48:38.175Z" },
{ url = "https://files.pythonhosted.org/packages/f5/2d/7caa9598ae61a9cf0989cc501739cbeeb7d650ab3193cca1407b9af0c6ab/wrapt-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f90038ab58fafb584801ca62d72384d7d5225d93c76f7b773c22fae545bd8066", size = 206116, upload-time = "2026-06-20T23:48:39.804Z" },
{ url = "https://files.pythonhosted.org/packages/ac/02/281ea1088b8650d865f311b35cf86fd21df89128e2909714f1161e01c9d0/wrapt-2.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c5d7825491bfa2d08b97e9557768987952c7b9ae687d06c3320b40a37ccb7f20", size = 192668, upload-time = "2026-06-20T23:48:41.346Z" },
{ url = "https://files.pythonhosted.org/packages/be/7d/976e2d5b4b5c5babda40974edd54d0a5585cb60132ed86b46f4b80239b16/wrapt-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ad520e6daa9bbf136f14de735474dbec7dcc0891f718e1d274ce8dc92e645af", size = 198891, upload-time = "2026-06-20T23:48:43.056Z" },
{ url = "https://files.pythonhosted.org/packages/59/b7/e47651797c097f75a37e2ce86dcf04048ff576f3a674f7c558df7b5e9622/wrapt-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:25904acb9475f46c24fe0423dbc8fda8cc5fbc282ab3dc6e72e919748c53f4e9", size = 78537, upload-time = "2026-06-20T23:48:44.509Z" },
{ url = "https://files.pythonhosted.org/packages/d1/6f/9fa5d59fb06d890defb5a8f727ce6a14d2932c8760153f96956628559fee/wrapt-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:305d4c247d61c4115794a169141823c62f719525ddb90b23aa332741c77d2c28", size = 82005, upload-time = "2026-06-20T23:48:46.391Z" },
{ url = "https://files.pythonhosted.org/packages/15/80/4c7bd9873d1f9f7d138d93556b500469dbe24f42710b877519c2b9eb380d/wrapt-2.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c20279cd1a29800815d7b2d6338b60a6c6e78263f9d6e62e0eda251ba9cae2d0", size = 80762, upload-time = "2026-06-20T23:48:47.964Z" },
{ url = "https://files.pythonhosted.org/packages/24/05/7fd9c3f83b2c74cbfc572a0b88aa37431e04bd8aed70d2c0efd3464206de/wrapt-2.2.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0e64826f920c42d9d9f87e8cc09ffae66c51ede12d59061a5a426deb9aa71745", size = 81341, upload-time = "2026-06-20T23:48:49.39Z" },
{ url = "https://files.pythonhosted.org/packages/4b/68/1bfa43100dd90d4ef74a05897b86275cf57e1313ca14aae2545bc9f872c9/wrapt-2.2.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dcaa5e1451bd8751d7bd1568dfa3321c78092a52a7ecb5d1a0f18a5791e1fd00", size = 81921, upload-time = "2026-06-20T23:48:50.986Z" },
{ url = "https://files.pythonhosted.org/packages/74/eb/df7b7f0b631dbbc750f39be27d8b55f65777d8ac86da80e12be41a644c4b/wrapt-2.2.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0abfd648dac9ac9c5b3aa9b523d27f1789046640b58dcd5652a720ddb325e1fc", size = 167713, upload-time = "2026-06-20T23:48:52.598Z" },
{ url = "https://files.pythonhosted.org/packages/4d/9a/d1bd36f6d088c8e652a9383cabbd49af30b8c576302a7eccddbab6963e3f/wrapt-2.2.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f4bfd8d1eb438153eff8b8cfe87f032ba65731e1ce06138b5090f745a33f6f95", size = 166779, upload-time = "2026-06-20T23:48:54.33Z" },
{ url = "https://files.pythonhosted.org/packages/4c/ae/24ffacd4187fac2740a1972093929e836dea092d42c87d728cd98fee11a6/wrapt-2.2.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c427c9d06d859848a69f0d928fe28b5c33a941b2265d10a0e1f15cd244f1ee33", size = 158407, upload-time = "2026-06-20T23:48:55.944Z" },
{ url = "https://files.pythonhosted.org/packages/a3/ed/974427668249a356051e8d67d47fa54ef6c777f0fcf3bae9d292c047d4b6/wrapt-2.2.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4250b43d1a129d947e083c4dc6baf333c9bb34edd26f912d5b0457841fc858ab", size = 166594, upload-time = "2026-06-20T23:48:57.617Z" },
{ url = "https://files.pythonhosted.org/packages/fb/5f/e1d7c6e4523f78db2fbd7826babd0348da1d5e0834c4f918b9ab5757dfae/wrapt-2.2.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:173e5bb5ca350a6e0abab60b7ec7cdd7992a814cb14b4de670a28f067f105663", size = 157068, upload-time = "2026-06-20T23:48:59.171Z" },
{ url = "https://files.pythonhosted.org/packages/1e/c1/7ebd1027f00700c0b0233b20aceef2b4784294ed64971424c4a78e069e34/wrapt-2.2.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:aa14b01804bce36c6d63d7b6a4f55df390f29f8648cc13a1f40b166f4d54680d", size = 166470, upload-time = "2026-06-20T23:49:00.737Z" },
{ url = "https://files.pythonhosted.org/packages/99/eb/974e471a6a978b8180186b8a9dc5ae3361ce269a967190b709b8ce17abfb/wrapt-2.2.2-cp314-cp314-win32.whl", hash = "sha256:58f9f8d637c9a6e245c6ef5b109b67ec187d2faed23d1405656b51d96e0a5b56", size = 78062, upload-time = "2026-06-20T23:49:02.327Z" },
{ url = "https://files.pythonhosted.org/packages/49/ec/e1281156cdc7a66693838ad7a0865ad641c74abd337a957d668b575aaffb/wrapt-2.2.2-cp314-cp314-win_amd64.whl", hash = "sha256:385cb1866f20479e83299af585375bfa0a4b0c6c9907a981483ea782ea8ae406", size = 80832, upload-time = "2026-06-20T23:49:03.837Z" },
{ url = "https://files.pythonhosted.org/packages/45/7d/1b6b5ddd94005a2dac97a4490c9838f3154977850d633abcb65b30089437/wrapt-2.2.2-cp314-cp314-win_arm64.whl", hash = "sha256:8ffbeaea6771a6eba6e6eeb09767864995726bc8240bb54baf88a9bb1db34d5c", size = 80029, upload-time = "2026-06-20T23:49:05.237Z" },
{ url = "https://files.pythonhosted.org/packages/b0/33/9ebcf8aafe91c601127cbd93708c16aa8f688f34a10bf004046803ecdc4f/wrapt-2.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:09f811d43f6f33ec7515f0be76b159569f4057ab54d3e079c3204dddb90afa2a", size = 83357, upload-time = "2026-06-20T23:49:06.632Z" },
{ url = "https://files.pythonhosted.org/packages/39/38/ec45b635153327b52e52732a0ea980e5f00b7efba65f9e018828f1e69daa/wrapt-2.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a795d3c06e5fbf9ea2f13196180b77aeab1b4685917256ee0d014cc163d90063", size = 83794, upload-time = "2026-06-20T23:49:08.098Z" },
{ url = "https://files.pythonhosted.org/packages/4e/ea/1a89e6d3b7a83c3affe5c09cde77792c947e63e4bc85ad84cd5bb9abb0d8/wrapt-2.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:45c2f2768e790c9f8db90f239ef23a2af8e7570f25a35619ef902df4a738447f", size = 203362, upload-time = "2026-06-20T23:49:09.811Z" },
{ url = "https://files.pythonhosted.org/packages/19/d8/3b58763d9863b5a73771c0d97110f9595d248db454009e07e1535ee905a4/wrapt-2.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbf00ee0cb55ec24e2b0995a71942b85b21a066db8f3f46e1dbfdb9433ffba81", size = 210449, upload-time = "2026-06-20T23:49:11.521Z" },
{ url = "https://files.pythonhosted.org/packages/2d/6f/17fd9e053103d8be148d20d5d7505facc72d5fe1f9127973904ceaed79cf/wrapt-2.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2252f77663651b89255895f58cc6ac08fcb206d4371813e5af61bb62d4f7689c", size = 195349, upload-time = "2026-06-20T23:49:13.346Z" },
{ url = "https://files.pythonhosted.org/packages/ef/04/d0d1ccaaa12cb7dccf28a23f0279a608ba498f71e81d949d5ed54bcfd5c1/wrapt-2.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2cd7181ab1c31192ff5219269830744b5a62020b3a6d433588c4f1c95b8f8bff", size = 206099, upload-time = "2026-06-20T23:49:15.051Z" },
{ url = "https://files.pythonhosted.org/packages/44/b3/e8aa07b619890a2aa6cde1931b1887abb08820721b564a5f80b7ca3f3aa0/wrapt-2.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6fe35fd51b74867d8b80174c277bd6bbf6a73e443f908129dc531c4b688a20d5", size = 192728, upload-time = "2026-06-20T23:49:16.854Z" },
{ url = "https://files.pythonhosted.org/packages/b7/f0/1819fb50f0d3c9bd758d8a83b56f1b470dee8b5b8eac8702b7c137cea9d4/wrapt-2.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:11d95fc2fbad3163596c39d440e6f21ca9fccece74b56e30a37ac2fca786a07c", size = 198842, upload-time = "2026-06-20T23:49:18.504Z" },
{ url = "https://files.pythonhosted.org/packages/67/7c/e88313f16a99930b899ef970d91c281544a470749a359decad994483bbda/wrapt-2.2.2-cp314-cp314t-win32.whl", hash = "sha256:d8a15813215f33fa83667bfc978b300e35669ea8bb424e970a1426bcb7bc6cca", size = 79059, upload-time = "2026-06-20T23:49:20.107Z" },
{ url = "https://files.pythonhosted.org/packages/a0/4f/ac12fda57a55068a094ec42851fb0a40e8489d8941863d517452de62e507/wrapt-2.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d09db0f7e8357060d3c38fc22a018aba683a796bf184360fd1a58f6fc180dc77", size = 82462, upload-time = "2026-06-20T23:49:21.631Z" },
{ url = "https://files.pythonhosted.org/packages/48/a7/df732dac86d9b2027c56bd163dbc883e037b16c3469614752e148d219c61/wrapt-2.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:f32fe639c39561ccc187bcae17e9271be0eb45f1c2952510d2f29b33ab577347", size = 81182, upload-time = "2026-06-20T23:49:23.199Z" },
{ url = "https://files.pythonhosted.org/packages/6e/d2/6317eb6d4554855bbf12d61857774af34747bf88a42c19bf306de67e2fa3/wrapt-2.2.2-py3-none-any.whl", hash = "sha256:5bad217350f19ce99ca5b5e71d406765ea86fe541628426772b657375ee1c048", size = 61460, upload-time = "2026-06-20T23:49:42.966Z" },
{ url = "https://files.pythonhosted.org/packages/00/b8/9182e4c618a847be0baccb68e4602b070d0fa22c782cf058f4bc66b32709/wrapt-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ab559e1b2551d23d54db2a0001c6d73bad022a254639561c5f6c382a9d6c2fe", size = 81427, upload-time = "2026-07-28T06:04:20.106Z" },
{ url = "https://files.pythonhosted.org/packages/84/ca/613cefd9c5977366b1587e61c0b428176d382e6d75b454084c5e58503042/wrapt-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bff9a671bc00709cab5a7f745c592b5671873449db0ee2a569af994f16b29a4d", size = 82360, upload-time = "2026-07-28T06:04:21.613Z" },
{ url = "https://files.pythonhosted.org/packages/71/71/4cd2151a236f44a6e2dd4ed8011838d7ba0be3d656c8bafdfc65a2ed1917/wrapt-2.3.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fc648a335d7e01adb3640b25f02fd0ea05886cf04d0af7f4ee902bc7b5e466e8", size = 161700, upload-time = "2026-07-28T06:04:22.723Z" },
{ url = "https://files.pythonhosted.org/packages/49/2c/bc508fee75eb2919ed69769800b09968e4aab16897f909a23f39c81e323f/wrapt-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0077f3d65541925fa83002f967b22ad6550d24813ac64cb905f717194128d9c", size = 162922, upload-time = "2026-07-28T06:04:24.177Z" },
{ url = "https://files.pythonhosted.org/packages/4d/e5/04f34d38e66d857dfc2fc4088d60e70c0e422467822defa49b2b4a26e17b/wrapt-2.3.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9790ea25190a4e0fe4cdf4eeb868e9d75f8a024a70a5b6bf9c348a3a2b72e731", size = 156125, upload-time = "2026-07-28T06:04:25.58Z" },
{ url = "https://files.pythonhosted.org/packages/23/41/c35940ea1c423f129ebe4361db853bc80d4def6326242e1206fa15bf94f4/wrapt-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:816877aa749253149f9ecfd2635d4d948ecfa338e1a0311d187b1acb1bb8a3eb", size = 162039, upload-time = "2026-07-28T06:04:27.154Z" },
{ url = "https://files.pythonhosted.org/packages/0e/60/9bda34c3d7d182aa703fe35339ae0ed4c4dad5e5c587f93890143e1f87fb/wrapt-2.3.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d1c2c1b808600d2ea808e6360910a60ed5f409a4011655e10f9164ba0a414a6", size = 155110, upload-time = "2026-07-28T06:04:28.497Z" },
{ url = "https://files.pythonhosted.org/packages/e8/ba/60bfd9b1a751f4fcb2d603668fc272d651ccdd339a56acf8c40ad21a0293/wrapt-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5ba1e5e08ddc46130e9682b2c249f2d1dd39bda9106ed4bd401b7519f18f41bd", size = 161089, upload-time = "2026-07-28T06:04:29.959Z" },
{ url = "https://files.pythonhosted.org/packages/0f/32/2bd358c6f4f1305c813479d1e9ba746bebdd794f4a20107ab2b3ee0cbd45/wrapt-2.3.0-cp311-cp311-win32.whl", hash = "sha256:45c9279b373d15649dfa2c2077cb3408ea1a6d3125afbdab9d6b809a66f68e14", size = 78030, upload-time = "2026-07-28T06:04:31.241Z" },
{ url = "https://files.pythonhosted.org/packages/4a/62/ecc969b13b141fef89b888c9760821cb01a86ac8fc953911592c8e1e1522/wrapt-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:195b1842b4122fb54e3cd3dd5b2b4aa49302a5a61da901df0481f5c97aedde84", size = 80944, upload-time = "2026-07-28T06:04:32.655Z" },
{ url = "https://files.pythonhosted.org/packages/c4/3d/9278ada8a2b3f24372b630361e84e9a7de7abc3784634860c26d1c37785a/wrapt-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:6db604ef0c67bdb2042ecdfd7b7f037cf09733557ca42360d1018285634f7b98", size = 80074, upload-time = "2026-07-28T06:04:33.811Z" },
{ url = "https://files.pythonhosted.org/packages/5b/4a/d17a0fad1bf1c5f2c887ff71fef75654141b0880bff71d157d955b5bec3a/wrapt-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a45ffae742ce91a16e11cb6c7cd71e7f9994f3cbd283b962ab093f5c6dcf525", size = 82139, upload-time = "2026-07-28T06:04:35.082Z" },
{ url = "https://files.pythonhosted.org/packages/6e/55/51b92daaf6defb57f4dc56bdcce985400f75c6984a03ca5e78ccac717028/wrapt-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:69e477046f2237ef0bc6547544ee73008dc764ca26eff44f09e976d221b34d5d", size = 82723, upload-time = "2026-07-28T06:04:36.502Z" },
{ url = "https://files.pythonhosted.org/packages/28/7f/cfd9bc4b1f5e424eeea83d0493e43f3b1b02707ce8e50c47945873982bd5/wrapt-2.3.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d221a6e6ddd302b8397433184e96b59f259f50024b854db1c411a881586b6b8", size = 172381, upload-time = "2026-07-28T06:04:37.674Z" },
{ url = "https://files.pythonhosted.org/packages/cb/89/ff7814f6eb6856b479946117d1138a2fbb46cdb6b1f379db359056c69743/wrapt-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:392158c9a7f2ab1b8699418bfc0fe6f83548788c418b27d7bf2019ad3405cebb", size = 174120, upload-time = "2026-07-28T06:04:38.987Z" },
{ url = "https://files.pythonhosted.org/packages/12/1e/8eded8615d39e3ce81f626937a3a87b280a2a86239a2bf14a4b4bb345034/wrapt-2.3.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e5301c35cf75655eb33498f2bd6ae8703ca19940e3167dc9cdf740c712a39c60", size = 163035, upload-time = "2026-07-28T06:04:40.361Z" },
{ url = "https://files.pythonhosted.org/packages/35/ea/a0af2d9da62897af2a055484920de05dade30d2ba2c0d65cbdea875d3d8b/wrapt-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:418f54bb09d1762db02c7009b4051149893af3153a87f92d70356703c11eea02", size = 171887, upload-time = "2026-07-28T06:04:41.614Z" },
{ url = "https://files.pythonhosted.org/packages/7e/dd/63cd4c864c65ef4906df64bd2d378f4a62b54f28063f282dfb3bf93caead/wrapt-2.3.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1598becd30f8f2777d18564064eb4f4dbe1ab0e05a8f09786d0ef505ac782bf3", size = 161113, upload-time = "2026-07-28T06:04:42.864Z" },
{ url = "https://files.pythonhosted.org/packages/ca/ee/82f1fc9e431b5c2c5a6d201aa865dbeae3984c311c6d11a185f0c8367cf6/wrapt-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3da470536bf9645143323dd41b32db55c6f4304ad382094c1a1da8a92061e10d", size = 170530, upload-time = "2026-07-28T06:04:44.212Z" },
{ url = "https://files.pythonhosted.org/packages/37/a5/5dc590e863a419930d988f8b7ca3e75a6befcfb10b6003b3a152f3d5f732/wrapt-2.3.0-cp312-cp312-win32.whl", hash = "sha256:fb8e2e6704a1e0b1b989546c69e2688371ef4a07fa5f61bde3eb6211186f5ac1", size = 78323, upload-time = "2026-07-28T06:04:45.484Z" },
{ url = "https://files.pythonhosted.org/packages/51/f9/4a6925a07951df56394f7e6ebe14f69f1c5ef9d87aa63e0839acf15aa63a/wrapt-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:cdc021cb0b62471d6aac7f2bd92f3b4658073775f9ee7fcd325c511129e7bcc8", size = 81180, upload-time = "2026-07-28T06:04:47.021Z" },
{ url = "https://files.pythonhosted.org/packages/a8/4f/8b5de0395b2a72216751d41c9861df6facaeb611b619d8810ed2b3b23eb2/wrapt-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:67bfe2485f50368c3fcd2275fc1fd100e350d601e0058921a7c82678a465aeab", size = 80155, upload-time = "2026-07-28T06:04:48.373Z" },
{ url = "https://files.pythonhosted.org/packages/8e/6e/0f88a072483e76b881e3fdcd6b6ffb4a5791002514fe541e72b1b73c859a/wrapt-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d3fb71e65b001adfc42684522eeccd9c21d8ba679945abc993439567b66e59f", size = 81960, upload-time = "2026-07-28T06:04:49.622Z" },
{ url = "https://files.pythonhosted.org/packages/d7/ff/b7e2776e7c294075eb712cc9ef573d1b818f393006d09787262b8fc871c4/wrapt-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51a7a4181c1295774812271fbcd7c909df372bc25579d4ed9eb875caaf0ae86f", size = 82435, upload-time = "2026-07-28T06:04:50.9Z" },
{ url = "https://files.pythonhosted.org/packages/d8/90/343bb5d0f1f9669bc252a6073f085b4abf862511bd5c9c9eaec754341f1d/wrapt-2.3.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9045917809c63fdf7abe3a2ceaed3d670b8ee4500ddd9291192d30aeb34467c5", size = 170350, upload-time = "2026-07-28T06:04:52.187Z" },
{ url = "https://files.pythonhosted.org/packages/59/f8/13b79a392930bd0dd6b86cbfbfe1c40944110456e1dc6d809e5c46ece904/wrapt-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54ca1d5573f69b5fe1d74f1f65799c68015e82f685efec9fd8cfa40a094c44d0", size = 170022, upload-time = "2026-07-28T06:04:53.599Z" },
{ url = "https://files.pythonhosted.org/packages/b2/fc/4f1b6918f5290db959d6e0c07f77385d87cede29c39c9cf8f145e9c82954/wrapt-2.3.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:242b60c21e30866e6a2fa606c612b47c553fa60c0eaeeeb7797fb842ac0ce609", size = 161043, upload-time = "2026-07-28T06:04:54.936Z" },
{ url = "https://files.pythonhosted.org/packages/01/e1/45d3cf74414780bdff6d0380467e003f6eb0f028b6c9403db868dbc7209c/wrapt-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3f3d7ec0a51fbfe00d3aef047641ff2c58b25565b4717fc1f90e050be01cba8", size = 168576, upload-time = "2026-07-28T06:04:56.261Z" },
{ url = "https://files.pythonhosted.org/packages/f3/73/2fa58dd97f191c997755e2c6d569a68f0c433db4e4b36099bdd7227b6cac/wrapt-2.3.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:261f53870cd4fb2bf38f9f972c56c728fd224cb7c65721307de59d9e7e6741ae", size = 159140, upload-time = "2026-07-28T06:04:57.754Z" },
{ url = "https://files.pythonhosted.org/packages/29/a8/08a56e2000a8816d449dcbad8c8b081697acbbd490821ceca0f9d8e8d20c/wrapt-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8159ec0b0cb7608175eb150de94c19e34f4d47ac655f5ca9baf45df6b688ffd3", size = 169263, upload-time = "2026-07-28T06:04:59.161Z" },
{ url = "https://files.pythonhosted.org/packages/9e/d4/354e1725e35a73b2af4fa70a3e024c7a5d1bf1802dfb862dcb668aae0253/wrapt-2.3.0-cp313-cp313-win32.whl", hash = "sha256:10461884b3014fbfc8eb7d09a93c5f246363e6711d9d881f95eb8c27fdef049f", size = 78241, upload-time = "2026-07-28T06:05:00.507Z" },
{ url = "https://files.pythonhosted.org/packages/6c/7e/34c87fa2174848dfee820322aaa318bab08913998ccecc8d2f57b4ad4639/wrapt-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:ac870cc97b73bb00ac353329e9559a4bebc47c4c86792ed9b23b58c15b6ad838", size = 81113, upload-time = "2026-07-28T06:05:01.839Z" },
{ url = "https://files.pythonhosted.org/packages/11/86/fcc9a530579e008c9478bb565a6cdfbfd33536660f069c8b91a6607c5050/wrapt-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:a65e8db2b4e90c2e7ade931086351c98ef420bf7a94ee08c95ac8a3cbbc43579", size = 80182, upload-time = "2026-07-28T06:05:03.152Z" },
{ url = "https://files.pythonhosted.org/packages/96/50/3864848b95b28ef73e17551fc8dccbff2628a834f52cf26a57f9c419fb83/wrapt-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:fd1f2f557dd3491fe75905e578f4db967393d40d1a8f468edc4d40ac7f2d5944", size = 83921, upload-time = "2026-07-28T06:05:04.476Z" },
{ url = "https://files.pythonhosted.org/packages/3b/4c/3d1921a60c3e8c71c540ff136e6a47a1fbccf7f671e818394889f7871d9c/wrapt-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9f5d2aec29dfc76c37e23897dee92766a3fd4f3bff3ae7fc9c6b4bf37d8c1360", size = 84412, upload-time = "2026-07-28T06:05:05.921Z" },
{ url = "https://files.pythonhosted.org/packages/fa/1a/4a796ff7adb26ada6d4b758c94d47a38320b085e7099afc088efbbcdb006/wrapt-2.3.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:646d20d413ffcd1b0a2f700076e2d0252d872dcb7754860a73e45a59ea883614", size = 207168, upload-time = "2026-07-28T06:05:07.256Z" },
{ url = "https://files.pythonhosted.org/packages/1d/3e/d7777776806c579b761bac2f91721dda9f04c7a1b380213c5935cc750ae6/wrapt-2.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:379f670f45b7bb8993edd9f6fc36c6cc65edb81cffa0b504be34acb0303fff0a", size = 214351, upload-time = "2026-07-28T06:05:08.945Z" },
{ url = "https://files.pythonhosted.org/packages/63/27/2d64d394df7bf181955b3bb562bf33c4492fb4be113f53071106d43ad8b5/wrapt-2.3.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6208f302f110295d64b22a7ac96500c791bf492dce4366e622e4912b077c9687", size = 199020, upload-time = "2026-07-28T06:05:10.418Z" },
{ url = "https://files.pythonhosted.org/packages/3e/3d/fb31d3db7d9834d265fb1a27a2adf0ddf51557c67458c97b22439ad6ae3d/wrapt-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ed635a9ca4f3a5a2b900c10c69e823373bc00ebc114b459383596d3487da3570", size = 209969, upload-time = "2026-07-28T06:05:11.983Z" },
{ url = "https://files.pythonhosted.org/packages/1f/d1/8724b5da582e62070dc9bf4d8bf1972f317297eefd7ba1f2b5c6393ccf6c/wrapt-2.3.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:e3b9eaa742ae7a0aaaaad4ca4b69469d757af2d6e6663ef1dadc47adec0aeb41", size = 196324, upload-time = "2026-07-28T06:05:13.557Z" },
{ url = "https://files.pythonhosted.org/packages/0d/5c/3d9ef411149543016ee6bcf3af707f787cebd946527452b94bf122e9b7b4/wrapt-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d0f7284f88f4833705132d06d3b425a43095c2cbd07c58166aac3ab646ba12a4", size = 202610, upload-time = "2026-07-28T06:05:15.048Z" },
{ url = "https://files.pythonhosted.org/packages/13/9b/4fc042ceb757866dd4a5fc057b3b736f2b360d3703ce9f830d83dc9226e0/wrapt-2.3.0-cp313-cp313t-win32.whl", hash = "sha256:7ebb274aba688b043429eb1500ff8a76ce0cb8ac0812ca3e301f06247b8722b3", size = 79178, upload-time = "2026-07-28T06:05:16.469Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ff/b94878f8eed809ca042685276bcea9f24e8c2ca7c9653bb80bbb920a68a5/wrapt-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:c4bded758ad6f03b965830944a2f0bc5b2eb3767fe5a7310134315d1a6610e98", size = 82634, upload-time = "2026-07-28T06:05:18.026Z" },
{ url = "https://files.pythonhosted.org/packages/80/fb/663e1de5332a71685a729754312d327d4cada767c36e1c5a2db4c8de49e6/wrapt-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:d2cc64539da63e39ffb9c7ede849b6e8ddaaf7b3876b5cfb04efd85a5f3f4eb6", size = 81387, upload-time = "2026-07-28T06:05:19.417Z" },
{ url = "https://files.pythonhosted.org/packages/58/10/b073beaea89bc0d3670a75ff51139430a54b6af7ba7796507730634536dd/wrapt-2.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ea52a0d0f08c584943d5764be0e84efa912c8da23c23e1e285ff2f5641c18fcc", size = 81978, upload-time = "2026-07-28T06:05:21.133Z" },
{ url = "https://files.pythonhosted.org/packages/b3/31/0916d9cebf848ed3f1a0c1888faee421747df77331e4db2bc527a9a85988/wrapt-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd85b0aa88efdb189d6ae2f35f4526943a8f091c38599c9c31478241c819e6a1", size = 82518, upload-time = "2026-07-28T06:05:22.562Z" },
{ url = "https://files.pythonhosted.org/packages/f5/73/31c1bf0f3384062751c2094dadb314916d70aa9b6bfd26d994b4a7b393fa/wrapt-2.3.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:141ed6211286a9660d8d6702de598b43f0934b4f0eda16393f100a80f501d945", size = 170187, upload-time = "2026-07-28T06:05:23.904Z" },
{ url = "https://files.pythonhosted.org/packages/ed/25/fce087d54b79b8905f3c3c9dd5f454bbd8d8acb80b960c4a6aee5b4659b3/wrapt-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e49885a62ec4ee854d1b9e6371fda6afd219917225752abf729a3f36d4df9a5", size = 169288, upload-time = "2026-07-28T06:05:25.378Z" },
{ url = "https://files.pythonhosted.org/packages/c7/30/0d09e6dddc6b7a7230ac77f50254b5980ab4fcd22976f72f8cc8a0404458/wrapt-2.3.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d6159c9b2fefec02314e1332dbbbfaf960e369dfd26bcf7f8b258b5732065b3", size = 160932, upload-time = "2026-07-28T06:05:27.022Z" },
{ url = "https://files.pythonhosted.org/packages/2c/ca/0913af0d2ec0c43865d32d615f518fea66c13c5c930e489e9b0de248e9a8/wrapt-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24da48596326ef8e448cfa837b454f638713d3531262375f00e5a9681682fc07", size = 169017, upload-time = "2026-07-28T06:05:28.501Z" },
{ url = "https://files.pythonhosted.org/packages/c3/f2/3d1e47ea81b822210f5df1bf942fd90780a75c055243d569b664529dea88/wrapt-2.3.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cd3a2edf0427013736b8127955cec62608c56e53ea47e82812ea32059cda407f", size = 159065, upload-time = "2026-07-28T06:05:30.01Z" },
{ url = "https://files.pythonhosted.org/packages/43/a5/ef2066ced8e5fca204e2b361e9708e36555b40949c583d997ea3b590817d/wrapt-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0df3bff4e7ce45759f33fd39335fe2f60477bb9ecf7b8aa41e7d07ee36a23", size = 168821, upload-time = "2026-07-28T06:05:31.649Z" },
{ url = "https://files.pythonhosted.org/packages/d5/e1/016104650d4e572fa91506eb396b3dd8efbccc9284fdc1c9479c3d21db28/wrapt-2.3.0-cp314-cp314-win32.whl", hash = "sha256:2935d5454b3f179a29b12cf390ee47246740ba2c3a7545b1b46ba31a5f2a4a0b", size = 78700, upload-time = "2026-07-28T06:05:33.391Z" },
{ url = "https://files.pythonhosted.org/packages/3d/97/6fdc20a9f2ca304748b3f0819cbf377d55260562777bf0b615431bc3c181/wrapt-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:cc2cea812e5cb179a796b766747e7d3b21088760d8deb95676d482b8c8e6fa7d", size = 81422, upload-time = "2026-07-28T06:05:34.774Z" },
{ url = "https://files.pythonhosted.org/packages/5e/a4/9cbd53bf05746bea2c392af39cb052427a8ec95cbd494d930733d8f44681/wrapt-2.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:22cc5c0a717bd4da87018ae0bffd4c19c6fb679d3ff357216ba566ab26c76cab", size = 80639, upload-time = "2026-07-28T06:05:36.228Z" },
{ url = "https://files.pythonhosted.org/packages/43/bb/6c5e4a0f66ea0d2b2dd267e8dd05a0014eea56840b3c8595d40b0a5d1f91/wrapt-2.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a6b5984cd65dd639546f0eb4b8eacf1c31cb2fe9fb5c27bffe240987cdb2cf84", size = 84030, upload-time = "2026-07-28T06:05:37.714Z" },
{ url = "https://files.pythonhosted.org/packages/6a/eb/a1aedf03283bc9cbf8a1783995ddc54e3c5a86878f19002d2c428494f4c5/wrapt-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c88abcf53daef80e01a75c7530e727fa6e2c1888fe83e3dcdba4c96216a1f5c7", size = 84419, upload-time = "2026-07-28T06:05:39.131Z" },
{ url = "https://files.pythonhosted.org/packages/63/61/50d511c0dc5105563849e86daa3e16ac7feef699f79fb05af45ea70107d5/wrapt-2.3.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:85de890ff968196e92dd1ae73a9fb8970495e7650a457b1c9ef0ac3dd550bce2", size = 207171, upload-time = "2026-07-28T06:05:40.69Z" },
{ url = "https://files.pythonhosted.org/packages/3f/59/9b538cf7795217e810699d16bc88b96a830d9b5c403eb2ec2db6b5f2ae81/wrapt-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50f416b74d092bb9f41b424e90dd457f365f7ba4b11de62a23679769a21bd85c", size = 214329, upload-time = "2026-07-28T06:05:42.287Z" },
{ url = "https://files.pythonhosted.org/packages/b3/28/9935d62b1499e5c8b3d191e99ba4eb31ca237a0b699142011a837e9dc7ea/wrapt-2.3.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39febbee6d77301d31da6996b152ce52452da7c7ef72aba10c2fa976dff9c295", size = 199079, upload-time = "2026-07-28T06:05:43.958Z" },
{ url = "https://files.pythonhosted.org/packages/2b/01/4446b80fa2ffa47a3449b250d004ba1c1937f07f64a179608fec735df866/wrapt-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:93513bec052c6cd987f9f580c3df068c8bc4ebae6543736be3ca7ec5959cafcd", size = 209992, upload-time = "2026-07-28T06:05:45.677Z" },
{ url = "https://files.pythonhosted.org/packages/d4/07/56f26c9f9979586a021e8148747004aba4498f49458c90b0502969b904e1/wrapt-2.3.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:729126e667da34d251b8ebf8a45ef0c5ddadc21542b3d6e1abf4259ece6508df", size = 196334, upload-time = "2026-07-28T06:05:47.608Z" },
{ url = "https://files.pythonhosted.org/packages/8b/41/6d7bcc895b0f28b2250e10908f060687b9165429dcd7f22ddb3d4c031b74/wrapt-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:626b69db2021aa01671ec7bbc9740e558522bd44c18cf2ce69bf3d666a014109", size = 202644, upload-time = "2026-07-28T06:05:49.183Z" },
{ url = "https://files.pythonhosted.org/packages/cd/25/7860927edba06b758b8852a6f02e832be715563c67a6795d94350bc81099/wrapt-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:629d73378082c00a8173031f9fb30a3ac6abbc894a5bfdfae71fabc60642d501", size = 79685, upload-time = "2026-07-28T06:05:50.976Z" },
{ url = "https://files.pythonhosted.org/packages/c4/0f/270bafe92fde3b069a39bc01e39ee79340895b335640df861d43d2a51885/wrapt-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:42869085687f0aefd57c0f636c3f9354f8ffb321a8ba9cb52d19beb796e561c5", size = 83104, upload-time = "2026-07-28T06:05:52.405Z" },
{ url = "https://files.pythonhosted.org/packages/55/b3/af176d79a8515a8a720eccdad9a96f6e31a30abf2865430c8c42adf2fd13/wrapt-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b1e5aa486e269b00ed35e64771c7d0ab8096cfd2643405ca8cd60ebedc099a51", size = 81774, upload-time = "2026-07-28T06:05:53.902Z" },
{ url = "https://files.pythonhosted.org/packages/00/39/3daf9f47be208606586de4568ba6713db53ebc8fd7a575aea1fe57983b69/wrapt-2.3.0-py3-none-any.whl", hash = "sha256:d8c7ed08477429752b8c44991f40ad7838b18332a160698740a6bfbc10d998a2", size = 61866, upload-time = "2026-07-28T06:06:12.9Z" },
]
[[package]]