diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3233c79..a89b8ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.10" - "3.11" - "3.12" os: diff --git a/poetry.lock b/poetry.lock index a09ea3d..9956db1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -87,7 +87,6 @@ files = [ [package.dependencies] aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" @@ -126,24 +125,13 @@ frozenlist = ">=1.1.0" [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.15" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" -files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, -] - -[[package]] -name = "async-timeout" -version = "4.0.3" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "alabaster-0.7.15-py3-none-any.whl", hash = "sha256:d99c6fd0f7a86fca68ecc5231c9de45227991c10ee6facfb894cf6afb953b142"}, + {file = "alabaster-0.7.15.tar.gz", hash = "sha256:0127f4b1db0afc914883f930e3d40763131aebac295522fc4a04d9e77c703705"}, ] [[package]] @@ -393,9 +381,6 @@ files = [ {file = "coverage-7.4.0.tar.gz", hash = "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e"}, ] -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - [package.extras] toml = ["tomli"] @@ -428,20 +413,6 @@ files = [ {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, ] -[[package]] -name = "exceptiongroup" -version = "1.2.0" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "frozenlist" version = "1.4.1" @@ -910,11 +881,9 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -1271,17 +1240,6 @@ Sphinx = ">=5" lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "tornado" version = "6.4" @@ -1458,5 +1416,5 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" -python-versions = "^3.10" -content-hash = "8dcba47955130ad23a5873912199b0dd49df049c7b9edfa15461ad82efc2536a" +python-versions = "^3.11" +content-hash = "3d5e5b0bb9dc9a3082700bd11a0f25dc08e5658c0b9ff2bcc41682baf714583a" diff --git a/pyproject.toml b/pyproject.toml index 5918d91..51ebb32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "pyomie" version = "0.1.0" description = "A client for OMIE - Spain and Portugal electricity market data" -authors = ["Luis Miranda "] +authors = ["Luis Miranda "] license = "Apache Software License 2.0" readme = "README.md" repository = "https://github.com/luuuis/pyomie" @@ -17,6 +17,7 @@ classifiers = [ packages = [ { include = "pyomie", from = "src" }, ] +keywords = ["omie", "electricity", "spain", "portugal", "MIBEL"] [tool.poetry.urls] "Bug Tracker" = "https://github.com/luuuis/pyomie/issues" @@ -26,7 +27,7 @@ packages = [ pyomie = "pyomie.cli:app" [tool.poetry.dependencies] -python = "^3.10" +python = "^3.11" rich = ">=10" typer = {extras = ["all"], version = "^0.9.0"} aiohttp = "^3.9.1" diff --git a/src/pyomie/cli.py b/src/pyomie/cli.py index 238b445..8af7786 100644 --- a/src/pyomie/cli.py +++ b/src/pyomie/cli.py @@ -4,7 +4,7 @@ import datetime as dt import json import sys -from typing import Awaitable, Callable +from typing import Awaitable, Callable, NamedTuple, TypeVar import aiohttp import typer @@ -13,12 +13,14 @@ from pyomie.main import adjustment_price, spot_price from pyomie.model import OMIEResults +_NamedTupleT = TypeVar("_NamedTupleT", bound=NamedTuple) + app = typer.Typer() _DATE_DEFAULT = "today's date" -def _parse_iso8601_date(a_date: str) -> dt.date: +def _parse_date_arg(a_date: str) -> dt.date: if a_date is _DATE_DEFAULT: return dt.date.today() else: @@ -30,14 +32,14 @@ def spot( date: dt.date = typer.Argument( # noqa: B008 default=_DATE_DEFAULT, help="Date to fetch in YYYY-MM-DD format", - parser=_parse_iso8601_date, + parser=_parse_date_arg, ), csv: bool = typer.Option( default=False, help="Print the CSV as returned by OMIE, without parsing." ), ) -> None: """Fetches the OMIE spot price data.""" - _sync_fetch_and_print(spot_price, date, csv) + _fetch_and_print(spot_price, date, csv) @app.command() @@ -45,29 +47,33 @@ def adjustment( date: dt.date = typer.Argument( # noqa: B008 default=_DATE_DEFAULT, help="Date to fetch in YYYY-MM-DD format", - parser=_parse_iso8601_date, + parser=_parse_date_arg, ), csv: bool = typer.Option( default=False, help="Print the CSV as returned by OMIE, without parsing." ), ) -> None: """Fetches the OMIE adjustment mechanism data.""" - _sync_fetch_and_print(adjustment_price, date, csv) + _fetch_and_print(adjustment_price, date, csv) -def _sync_fetch_and_print( +def _fetch_and_print( fetch_omie_data: Callable[ - [ClientSession, dt.date], Awaitable[tuple[OMIEResults, str] | None] + [ClientSession, dt.date], Awaitable[OMIEResults[_NamedTupleT] | None] ], market_date: dt.date, - raw: bool, + print_raw: bool, ) -> None: async def fetch_and_print() -> None: async with aiohttp.ClientSession() as session: fetched_data = await fetch_omie_data(session, market_date) if fetched_data: - parsed, unparsed = fetched_data - sys.stdout.write(unparsed if raw else json.dumps(parsed.contents)) + # noinspection PyProtectedMember + sys.stdout.write( + fetched_data.raw + if print_raw + else json.dumps(fetched_data.contents._asdict()) + ) asyncio.get_event_loop().run_until_complete(fetch_and_print()) diff --git a/src/pyomie/main.py b/src/pyomie/main.py index 07a950a..6fc2a4f 100644 --- a/src/pyomie/main.py +++ b/src/pyomie/main.py @@ -3,17 +3,25 @@ import csv import datetime as dt import logging -from typing import Callable, NamedTuple +from typing import Callable, NamedTuple, TypeVar from aiohttp import ClientSession -from pyomie.model import OMIEResults +from pyomie.model import ( + AdjustmentData, + OMIEDataSeries, + OMIEResults, + SpotData, +) DEFAULT_TIMEOUT = dt.timedelta(seconds=10) _LOGGER = logging.getLogger(__name__) -_HOURS = list(range(25)) + +_DataT = TypeVar("_DataT") + +_HOURS = list(range(1, 26)) #: Max number of hours in a day (on the day that DST ends). ADJUSTMENT_END_DATE = dt.date(2024, 1, 1) @@ -30,7 +38,6 @@ # | 02:30 | Intraday 4 | X | X | | | # | 05:30 | Intraday 5 | X | X | | | # | 10:30 | Intraday 6 | X | X | | | -# | 13:30 | Day-ahead | | | X | X | # | 16:30 | Intraday 1 | | | X | X | # | 18:30 | Intraday 2 | X | X | X | X | # | 22:30 | Intraday 3 | | | X | X | @@ -40,17 +47,32 @@ # - https://www.omie.es/en/mercado-de-electricidad # - https://www.omie.es/sites/default/files/inline-files/intraday_and_continuous_markets.pdf -DateFactory = Callable[ - [], dt.date -] #: Used by the coordinator to work out the market date to fetch. +DateFactory = Callable[[], dt.date] +#: Used by the coordinator to work out the market date to fetch. + +OMIEDataT = TypeVar("OMIEDataT") +#: Generic data contained within an OMIE result + + +class OMIEDayResult(NamedTuple): + """Data pertaining to a single day exposed in OMIE APIs.""" + + url: str + """URL where the data was obtained""" + market_date: dt.date + """The date that these results pertain to.""" + header: str + """File header.""" + series: OMIEDataSeries + """Series data for the given day.""" -async def _fetch_to_dict( +async def _fetch_and_make_results( session: ClientSession, source: str, market_date: dt.date, - short_names: dict[str, str], -) -> tuple[OMIEResults, str] | None: + make_result: Callable[[OMIEDayResult], OMIEDataT], +) -> OMIEResults[OMIEDataT] | None: async with await session.get( source, timeout=DEFAULT_TIMEOUT.total_seconds() ) as resp: @@ -64,97 +86,60 @@ async def _fetch_to_dict( reader = csv.reader(csv_data, delimiter=";", skipinitialspace=True) rows = list(reader) - hourly_values = { - row[0]: [ - _to_float(row[h + 1]) - for h in _HOURS - if len(row) > h + 1 and row[h + 1] != "" - ] + day_series: OMIEDataSeries = { + row[0]: [_to_float(row[h]) for h in _HOURS if len(row) > h and row[h]] for row in rows } - fetched = dt.datetime.now(dt.timezone.utc) - file_data = { - "header": header, - "market_date": market_date.isoformat(), - "source": source, - } + omie_meta = OMIEDayResult( + header=header, + market_date=market_date, + url=source, + series=day_series, + ) - for k in hourly_values: - hourly = hourly_values[k] - if k in short_names: - key = short_names[k] - file_data.update({f"{key}": hourly}) - else: - if k: - # unknown rows, do not process - file_data.update({k: hourly}) - - return ( - OMIEResults( - updated_at=fetched, market_date=market_date, contents=file_data - ), - response_text, + return OMIEResults( + updated_at=dt.datetime.now(dt.timezone.utc), + market_date=market_date, + contents=make_result(omie_meta), + raw=response_text, ) async def spot_price( client_session: ClientSession, market_date: dt.date -) -> tuple[OMIEResults, str] | None: +) -> OMIEResults[SpotData] | None: """ Fetches the marginal price data for a given date. :param client_session: the HTTP session to use :param market_date: the date to fetch data for - :return: an optional tuple containing the parsed and unparsed results + :return: the SpotData or None """ dc = DateComponents.decompose(market_date) source = f"https://www.omie.es/sites/default/files/dados/AGNO_{dc.yy}/MES_{dc.MM}/TXT/INT_PBC_EV_H_1_{dc.dd_MM_yy}_{dc.dd_MM_yy}.TXT" - return await _fetch_to_dict( - client_session, - source, - dc.date, - { - "Energía total con bilaterales del mercado Ibérico (MWh)": "energy_with_bilaterals_es_pt", # noqa: E501 - "Energía total de compra sistema español (MWh)": "energy_purchases_es", - "Energía total de compra sistema portugués (MWh)": "energy_purchases_pt", - "Energía total de venta sistema español (MWh)": "energy_sales_es", - "Energía total de venta sistema portugués (MWh)": "energy_sales_pt", - "Energía total del mercado Ibérico (MWh)": "energy_es_pt", - "Exportación de España a Portugal (MWh)": "energy_export_es_to_pt", - "Importación de España desde Portugal (MWh)": "energy_import_es_from_pt", - "Precio marginal en el sistema español (EUR/MWh)": "spot_price_es", - "Precio marginal en el sistema portugués (EUR/MWh)": "spot_price_pt", - }, + return await _fetch_and_make_results( + client_session, source, dc.date, _make_spot_data ) async def adjustment_price( client_session: ClientSession, market_date: dt.date -) -> tuple[OMIEResults, str] | None: +) -> OMIEResults[AdjustmentData] | None: """ Fetches the adjustment mechanism data for a given date. :param client_session: the HTTP session to use :param market_date: the date to fetch data for - :return: an optional tuple containing the parsed and unparsed results + :return: the AdjustmentData or None """ if market_date < ADJUSTMENT_END_DATE: dc = DateComponents.decompose(market_date) source = f"https://www.omie.es/sites/default/files/dados/AGNO_{dc.yy}/MES_{dc.MM}/TXT/INT_MAJ_EV_H_{dc.dd_MM_yy}_{dc.dd_MM_yy}.TXT" - return await _fetch_to_dict( - client_session, - source, - market_date, - { - "Precio de ajuste en el sistema español (EUR/MWh)": "adjustment_price_es", # noqa: E501 - "Precio de ajuste en el sistema portugués (EUR/MWh)": "adjustment_price_pt", # noqa: E501 - "Energía horaria sujeta al MAJ a los consumidores MIBEL (MWh)": "adjustment_energy", # noqa: E501 - "Energía horaria sujeta al mecanismo de ajuste a los consumidores MIBEL (MWh)": "adjustment_energy", # noqa: E501 - "Cuantía unitaria del ajuste (EUR/MWh)": "adjustment_unit_price", - }, + return await _fetch_and_make_results( + client_session, source, market_date, _make_adjustment_data ) else: @@ -162,8 +147,42 @@ async def adjustment_price( return None -def _to_float(n: str) -> float | None: - return n if n is None else float(n.replace(",", ".")) +def _to_float(n: str) -> float: + return float(n.replace(",", ".")) + + +def _make_spot_data(res: OMIEDayResult) -> SpotData: + s = res.series + return SpotData( + header=res.header, + market_date=res.market_date.isoformat(), + url=res.url, + energy_total_es_pt=s["Energía total con bilaterales del mercado Ibérico (MWh)"], + energy_purchases_es=s["Energía total de compra sistema español (MWh)"], + energy_purchases_pt=s["Energía total de compra sistema portugués (MWh)"], + energy_sales_es=s["Energía total de venta sistema español (MWh)"], + energy_sales_pt=s["Energía total de venta sistema portugués (MWh)"], + energy_es_pt=s["Energía total del mercado Ibérico (MWh)"], + energy_export_es_to_pt=s["Exportación de España a Portugal (MWh)"], + energy_import_es_from_pt=s["Importación de España desde Portugal (MWh)"], + spot_price_es=s["Precio marginal en el sistema español (EUR/MWh)"], + spot_price_pt=s["Precio marginal en el sistema portugués (EUR/MWh)"], + ) + + +def _make_adjustment_data(res: OMIEDayResult) -> AdjustmentData: + s = res.series + return AdjustmentData( + header=res.header, + market_date=res.market_date.isoformat(), + url=res.url, + adjustment_price_es=s["Precio de ajuste en el sistema español (EUR/MWh)"], + adjustment_price_pt=s["Precio de ajuste en el sistema portugués (EUR/MWh)"], + adjustment_energy=s[ + "Energía horaria sujeta al mecanismo de ajuste a los consumidores MIBEL (MWh)" # noqa: E501 + ], + adjustment_unit_price=s["Cuantía unitaria del ajuste (EUR/MWh)"], + ) class DateComponents(NamedTuple): diff --git a/src/pyomie/model.py b/src/pyomie/model.py index 5be9296..bfcc287 100644 --- a/src/pyomie/model.py +++ b/src/pyomie/model.py @@ -2,15 +2,61 @@ import logging from datetime import date, datetime -from typing import NamedTuple, Union +from typing import Generic, NamedTuple, TypeVar _LOGGER = logging.getLogger(__name__) -OMIEFile = dict[str, Union[float, list[float]]] -#: A dict parsed from one of the OMIE CSV file. +OMIEDayHours = list[float] +#: A sequence of hourly values relating to a single day. +OMIEDataSeries = dict[str, OMIEDayHours] +#: A dict containing hourly data for several data series. -class OMIEResults(NamedTuple): +_DataT = TypeVar("_DataT") + + +#: TypeVar used for generic named tuples + + +class SpotData(NamedTuple): + """OMIE marginal price market results for a given date.""" + + url: str + """URL where the data was obtained""" + market_date: str + """The date that these results pertain to.""" + header: str + """File header.""" + + energy_total_es_pt: OMIEDayHours + energy_purchases_es: OMIEDayHours + energy_purchases_pt: OMIEDayHours + energy_sales_es: OMIEDayHours + energy_sales_pt: OMIEDayHours + energy_es_pt: OMIEDayHours + energy_export_es_to_pt: OMIEDayHours + energy_import_es_from_pt: OMIEDayHours + spot_price_es: OMIEDayHours + spot_price_pt: OMIEDayHours + + +class AdjustmentData(NamedTuple): + """OMIE marginal price (spot) market results for a given date.""" + + url: str + """URL where the data was obtained""" + market_date: str + """The date that these results pertain to.""" + header: str + """File header.""" + + adjustment_price_es: OMIEDayHours + adjustment_price_pt: OMIEDayHours + adjustment_energy: OMIEDayHours + adjustment_unit_price: OMIEDayHours + + +class OMIEResults(NamedTuple, Generic[_DataT]): """OMIE market results for a given date.""" updated_at: datetime @@ -19,5 +65,8 @@ class OMIEResults(NamedTuple): market_date: date """The day that the data relates to.""" - contents: OMIEFile - """Data fetched from OMIE.""" + contents: _DataT + """The data fetched from OMIE.""" + + raw: str + """The raw text as returned from OMIE.""" diff --git a/src/pyomie/util.py b/src/pyomie/util.py new file mode 100644 index 0000000..ee5fbc6 --- /dev/null +++ b/src/pyomie/util.py @@ -0,0 +1,35 @@ +import datetime as dt + +from zoneinfo import ZoneInfo + +from pyomie.model import OMIEDayHours + +_CET = ZoneInfo("CET") + + +def localize_hourly_data( + date: dt.date, + hourly_data: OMIEDayHours, +) -> dict[str, float]: + """ + Localize incoming hourly data to the CET timezone. + + This is especially useful on days that are DST boundaries and + that may have 23 or 25 hours. + + :param date: the date that the values relate to + :param hourly_data: the hourly values + :return: a dict containing the hourly values indexed by their starting + time (ISO8601 formatted) + """ + hours_in_day = len( + hourly_data + ) # between 23 and 25 (inclusive) due to DST changeover + midnight = dt.datetime(date.year, date.month, date.day, tzinfo=_CET).astimezone( + dt.timezone.utc + ) + + return { + (midnight + dt.timedelta(hours=h)).astimezone(_CET).isoformat(): hourly_data[h] + for h in range(hours_in_day) + } diff --git a/tests/fixture/INT_MAJ_EV_H_15_06_2023_15_06_2023.json b/tests/fixture/INT_MAJ_EV_H_15_06_2023_15_06_2023.json index b0685b4..32834aa 100644 --- a/tests/fixture/INT_MAJ_EV_H_15_06_2023_15_06_2023.json +++ b/tests/fixture/INT_MAJ_EV_H_15_06_2023_15_06_2023.json @@ -1,7 +1,7 @@ { "header": "OMIE - Mercado de electricidad;Fecha Emisi\u00f3n :15/06/2023 - 22:22;;15/06/2023;Precio definitivo horario del mecanismo de ajuste a los consumidores en el mercado (EUR/MWh);;;;", "market_date": "2023-06-15", - "source": "https://www.omie.es/sites/default/files/dados/AGNO_2023/MES_06/TXT/INT_MAJ_EV_H_15_06_2023_15_06_2023.TXT", + "url": "https://www.omie.es/sites/default/files/dados/AGNO_2023/MES_06/TXT/INT_MAJ_EV_H_15_06_2023_15_06_2023.TXT", "adjustment_price_es": [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 diff --git a/tests/fixture/INT_PBC_EV_H_1_07_01_2024_07_01_2024.json b/tests/fixture/INT_PBC_EV_H_1_07_01_2024_07_01_2024.json index 68a1118..3994753 100644 --- a/tests/fixture/INT_PBC_EV_H_1_07_01_2024_07_01_2024.json +++ b/tests/fixture/INT_PBC_EV_H_1_07_01_2024_07_01_2024.json @@ -1,7 +1,7 @@ { "header": "OMIE - Mercado de electricidad;Fecha Emisi\u00f3n :06/01/2024 - 13:21;;07/01/2024;Precio del mercado diario (EUR/MWh);;;;", "market_date": "2024-01-07", - "source": "https://www.omie.es/sites/default/files/dados/AGNO_2024/MES_01/TXT/INT_PBC_EV_H_1_07_01_2024_07_01_2024.TXT", + "url": "https://www.omie.es/sites/default/files/dados/AGNO_2024/MES_01/TXT/INT_PBC_EV_H_1_07_01_2024_07_01_2024.TXT", "spot_price_es": [ 84.08, 79.82, 76.76, 73.46, 71.86, 72.08, 74.9, 77.69, 81.79, 84.86, 61.0, 55.87, 50.6, 51.77, 49.98, 45.57, 60.0, 92.05, 104.85, 103.55, 100.5, 95.89, @@ -37,7 +37,7 @@ 15637.3, 16854.1, 18681.1, 23273.0, 24522.0, 24949.3, 25065.6, 24758.7, 19887.3, 18835.1, 20790.3, 22770.8, 23735.8, 23485.1, 21709.4, 19401.4 ], - "energy_with_bilaterals_es_pt": [ + "energy_total_es_pt": [ 29933.5, 27437.9, 25827.5, 24863.3, 24425.9, 24388.9, 24845.6, 25652.6, 27053.5, 29414.4, 32252.6, 34687.0, 35669.2, 36180.9, 36383.9, 35889.5, 33422.8, 32243.6, 34787.7, 37137.1, 38089.7, 37713.6, 35389.3, 32367.8 diff --git a/tests/test_main.py b/tests/test_main.py index 912cc48..8c4cdf6 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -39,12 +39,13 @@ async def test_spot_price_24h_day(): result = await spot_price(session, dt.date(2024, 1, 7)) assert result is not None - parsed, raw = result if result else (None, None) fixture_contents = json.loads( read_file("INT_PBC_EV_H_1_07_01_2024_07_01_2024.json") ) - diff = DeepDiff(t1=fixture_contents, t2=parsed.contents, ignore_order=True) + diff = DeepDiff( + t1=fixture_contents, t2=result.contents._asdict(), ignore_order=True + ) assert str(diff) == "{}" @@ -84,10 +85,11 @@ async def test_adjustment_price_24h_day(): result = await adjustment_price(session, dt.date(2023, 6, 15)) assert result is not None - parsed, raw = result fixture_contents = json.loads( read_file("INT_MAJ_EV_H_15_06_2023_15_06_2023.json") ) - diff = DeepDiff(t1=fixture_contents, t2=parsed.contents, ignore_order=True) + diff = DeepDiff( + t1=fixture_contents, t2=result.contents._asdict(), ignore_order=True + ) assert str(diff) == "{}"