Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.1] - 2025-07-22
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Support explicitly requesting published GRDF consumption readings.

### Fixed

- Parse published readings whose `journeeGaziere` field is empty by using the last day of their reporting period.

## [1.3.1] - 2025-07-22

### Fixed

Expand Down
1 change: 1 addition & 0 deletions pygazpar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pygazpar.api_client import ConsumptionType # noqa: F401
from pygazpar.client import Client # noqa: F401
from pygazpar.datasource import ( # noqa: F401
ExcelFileDataSource,
Expand Down
12 changes: 11 additions & 1 deletion pygazpar/datasource.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ class JsonWebDataSource(WebDataSource): # pylint: disable=too-few-public-method

OUTPUT_DATE_FORMAT = "%d/%m/%Y"

# ------------------------------------------------------
def __init__(
self,
username: str,
password: str,
consumption_type: ConsumptionType = ConsumptionType.INFORMATIVE,
):
super().__init__(username, password)
self.__consumption_type = consumption_type

# ------------------------------------------------------
def _loadFromSession(
self, pceIdentifier: str, startDate: date, endDate: date, frequencies: Optional[list[Frequency]] = None
Expand All @@ -256,7 +266,7 @@ def _loadFromSession(
Frequency.YEARLY: FrequencyConverter.computeYearly,
}

data = self._api_client.get_pce_consumption(ConsumptionType.INFORMATIVE, startDate, endDate, [pceIdentifier])
data = self._api_client.get_pce_consumption(self.__consumption_type, startDate, endDate, [pceIdentifier])

Logger.debug("Json meter data: %s", data)

Expand Down
14 changes: 11 additions & 3 deletions pygazpar/jsonparser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import logging
from datetime import datetime
from datetime import datetime, timedelta
from typing import Any

from pygazpar.enum import PropertyName
Expand Down Expand Up @@ -29,13 +29,21 @@ def parse(jsonStr: str, temperaturesStr: str, pceIdentifier: str) -> list[dict[s
data_timestamp = datetime.now().isoformat()

for releve in data[pceIdentifier]["releves"]:
reading_date = releve["journeeGaziere"]
if reading_date is None:
end_date = releve.get("dateFinReleve")
if end_date is None:
Logger.warning("Reading ignored because it has no end date")
continue
reading_date = (datetime.fromisoformat(end_date) - timedelta(days=1)).strftime(INPUT_DATE_FORMAT)

temperature = releve["temperature"]
if temperature is None and temperatures is not None and len(temperatures) > 0:
temperature = temperatures.get(releve["journeeGaziere"])
temperature = temperatures.get(reading_date)

item = {}
item[PropertyName.TIME_PERIOD.value] = datetime.strftime(
datetime.strptime(releve["journeeGaziere"], INPUT_DATE_FORMAT), OUTPUT_DATE_FORMAT
datetime.strptime(reading_date, INPUT_DATE_FORMAT), OUTPUT_DATE_FORMAT
)
item[PropertyName.START_INDEX.value] = releve["indexDebut"]
item[PropertyName.END_INDEX.value] = releve["indexFin"]
Expand Down
91 changes: 91 additions & 0 deletions tests/test_jsonparser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import json
from datetime import date
from unittest.mock import Mock

from pygazpar.api_client import ConsumptionType
from pygazpar.datasource import JsonWebDataSource
from pygazpar.enum import PropertyName
from pygazpar.jsonparser import JsonParser


class TestJsonParser:

# ------------------------------------------------------
def test_informative_readings_use_gas_day(self):
pce_identifier = "22423299474865"
data = {
pce_identifier: {
"releves": [
{
"journeeGaziere": "2026-07-23",
"dateFinReleve": "2026-07-24T06:00:00+02:00",
"indexDebut": 2159,
"indexFin": 2160,
"volumeBrutConsomme": 0.28,
"energieConsomme": 3.16,
"coeffConversion": 11.29,
"temperature": 24.29,
"qualificationReleve": "Mesuré",
}
]
}
}

readings = JsonParser.parse(json.dumps(data), "null", pce_identifier)

assert readings[0][PropertyName.TIME_PERIOD.value] == "23/07/2026"

# ------------------------------------------------------
def test_published_readings_use_last_day_of_period(self):
pce_identifier = "22423299474865"

with open("tests/resources/donnees_publiees.json", encoding="utf-8") as consumption_file:
readings = JsonParser.parse(consumption_file.read(), "null", pce_identifier)

assert len(readings) == 87
assert readings[0][PropertyName.TIME_PERIOD.value] == "08/04/2018"
assert readings[0][PropertyName.ENERGY.value] == 22417
assert readings[-1][PropertyName.TIME_PERIOD.value] == "02/11/2022"

# ------------------------------------------------------
def test_readings_without_any_date_are_ignored(self):
pce_identifier = "22423299474865"
data = {
pce_identifier: {
"releves": [
{
"journeeGaziere": None,
"dateFinReleve": None,
"temperature": None,
}
]
}
}

readings = JsonParser.parse(json.dumps(data), "null", pce_identifier)

assert readings == []


class TestJsonWebDataSource:

# ------------------------------------------------------
def test_requested_consumption_type_is_forwarded_to_api(self):
data_source = JsonWebDataSource("user@example.com", "password", ConsumptionType.PUBLISHED)
api_client = Mock()
api_client.get_pce_consumption.return_value = {}
api_client.get_pce_meteo.return_value = None
data_source._api_client = api_client # pylint: disable=protected-access

data_source._loadFromSession( # pylint: disable=protected-access
"22423299474865",
date(2023, 7, 27),
date(2026, 7, 25),
)

api_client.get_pce_consumption.assert_called_once_with(
ConsumptionType.PUBLISHED,
date(2023, 7, 27),
date(2026, 7, 25),
["22423299474865"],
)
Loading