Hydro-Quebec-API-Wrapper 4.1.0__tar.gz → 4.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.gitlab-ci.yml +3 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.pre-commit-config.yaml +3 -3
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/Hydro_Quebec_API_Wrapper.egg-info/PKG-INFO +1 -1
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/PKG-INFO +1 -1
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_dpc.py +81 -19
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/client.py +7 -3
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/consts.py +2 -2
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/__init__.py +2 -2
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/consump.py +6 -19
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/dpc.py +31 -10
- hydro_quebec_api_wrapper-4.2.1/hydroqc/types/dt.py +29 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/test_requirements.txt +5 -5
- hydro_quebec_api_wrapper-4.1.0/hydroqc/types/dt.py +0 -15
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.coveragerc +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.devcontainer/Dockerfile +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.devcontainer/devcontainer.json +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.flake8 +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.gitignore +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.pylintrc +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/Hydro_Quebec_API_Wrapper.egg-info/SOURCES.txt +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/Hydro_Quebec_API_Wrapper.egg-info/dependency_links.txt +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/Hydro_Quebec_API_Wrapper.egg-info/entry_points.txt +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/Hydro_Quebec_API_Wrapper.egg-info/requires.txt +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/Hydro_Quebec_API_Wrapper.egg-info/top_level.txt +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/LICENSE +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/MANIFEST.in +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/README.md +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/config.default.yaml +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/conflict_test_requirements.txt +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/Makefile +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/make.bat +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/_static/custom.css +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/_static/hydroqc-logo-128.png +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/_static/hydroqc-logo.svg +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/conf.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/external/description-des-codes-interruption.pdf +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/index.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.contract.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.hydro_api.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.peak.cpc.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.peak.dpc.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.peak.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.types.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/modules.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/todo.rst +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/examples/hydro.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/account.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/consts.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/common.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_d.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_d_cpc.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_dt.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_m.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_m_gdp.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_residential.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/outage.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/customer.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/diagnostic.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/error.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/cache.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/logger.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/basepeak.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/basepeakhandler.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/consts.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/consts.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/handler.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/peak.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/consts.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/handler.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/peak.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/public_client.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/py.typed +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/timerange.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/account.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/common.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/contract.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/cpc.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/types/outage.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/utils.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/webuser.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/logo/hydroqc-logo-128.png +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/logo/hydroqc-logo.svg +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/pyproject.toml +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/renovate.json5 +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/setup.cfg +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/__init__.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/conftest.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_common.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_d.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_d_cpc.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_dpc.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_dt.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_m.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_m_gdp.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/test_basic.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/test_timerange.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/tools.py +0 -0
- {hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tox.ini +0 -0
|
@@ -314,6 +314,9 @@ package:
|
|
|
314
314
|
# Disable if it's a tag pipeline
|
|
315
315
|
- if: "$CI_COMMIT_TAG"
|
|
316
316
|
when: never
|
|
317
|
+
# Disable if it's a scheduled pipeline
|
|
318
|
+
- if: "$CI_PIPELINE_SOURCE == 'schedule'"
|
|
319
|
+
when: never
|
|
317
320
|
# Enabled for main branch
|
|
318
321
|
- if: "$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH"
|
|
319
322
|
when: on_success
|
|
@@ -16,7 +16,7 @@ repos:
|
|
|
16
16
|
- id: check-ast
|
|
17
17
|
|
|
18
18
|
- repo: https://github.com/psf/black
|
|
19
|
-
rev: 25.
|
|
19
|
+
rev: 25.11.0
|
|
20
20
|
hooks:
|
|
21
21
|
- id: black
|
|
22
22
|
language_version: python3
|
|
@@ -47,9 +47,9 @@ repos:
|
|
|
47
47
|
additional_dependencies:
|
|
48
48
|
- "types-pytz==2025.2.0.20251108"
|
|
49
49
|
- "types-PyYAML==6.0.12.20250915"
|
|
50
|
-
- "types-python-dateutil==2.9.0.
|
|
50
|
+
- "types-python-dateutil==2.9.0.20251115"
|
|
51
51
|
- "pytest-stub==1.1.0"
|
|
52
52
|
- "aiohttp==3.13.2"
|
|
53
53
|
- "aiocache==0.12.3"
|
|
54
54
|
- "pkce==1.0.3"
|
|
55
|
-
- "pytest-asyncio==1.
|
|
55
|
+
- "pytest-asyncio==1.3.0"
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_dpc.py
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Hydroquebec contract module."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
-
from datetime import date
|
|
4
|
+
from datetime import date, datetime
|
|
5
|
+
from enum import Enum
|
|
5
6
|
|
|
6
7
|
from hydroqc.contract.common import check_period_data_present
|
|
7
8
|
from hydroqc.contract.contract_residential import ContractResidential
|
|
@@ -10,12 +11,21 @@ from hydroqc.peak.dpc.handler import DPCPeakHandler
|
|
|
10
11
|
from hydroqc.types import DPCDataTyping
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
class WinterState(str, Enum):
|
|
15
|
+
"""Winter period state."""
|
|
16
|
+
|
|
17
|
+
CURRENT = "C" # Current/Active (within winter period)
|
|
18
|
+
FINISHED = "F" # Finished (past winter period)
|
|
19
|
+
|
|
20
|
+
|
|
13
21
|
def check_dpc_data_present(
|
|
14
|
-
method: Callable[..., None | str | bool | float | date],
|
|
15
|
-
) -> Callable[..., None | str | bool | float | date]:
|
|
22
|
+
method: Callable[..., None | str | bool | float | int | date | WinterState],
|
|
23
|
+
) -> Callable[..., None | str | bool | float | int | date | WinterState]:
|
|
16
24
|
"""Check if contractDPC's data are present."""
|
|
17
25
|
|
|
18
|
-
def wrapper(
|
|
26
|
+
def wrapper(
|
|
27
|
+
contract: "ContractDPC",
|
|
28
|
+
) -> None | str | bool | float | int | date | WinterState:
|
|
19
29
|
if not hasattr(contract, "_dpc_data"):
|
|
20
30
|
contract._logger.warning("You need to call get_dpc_data method first")
|
|
21
31
|
return None
|
|
@@ -26,6 +36,20 @@ def check_dpc_data_present(
|
|
|
26
36
|
"Maybe you did a rate change recently. "
|
|
27
37
|
"This message should disappear at the beginning of the next bill period."
|
|
28
38
|
)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
# Check if winter period data is available
|
|
42
|
+
if (
|
|
43
|
+
"periodesHiver" not in contract._dpc_data
|
|
44
|
+
or not contract._dpc_data.get("periodesHiver")
|
|
45
|
+
or len(contract._dpc_data["periodesHiver"]) == 0
|
|
46
|
+
):
|
|
47
|
+
contract._logger.info(
|
|
48
|
+
"DPC data is empty or incomplete. "
|
|
49
|
+
"This may occur outside the winter period or during a rate transition."
|
|
50
|
+
)
|
|
51
|
+
return None
|
|
52
|
+
|
|
29
53
|
return method(contract)
|
|
30
54
|
|
|
31
55
|
return wrapper
|
|
@@ -86,6 +110,19 @@ class ContractDPC(ContractResidential):
|
|
|
86
110
|
)
|
|
87
111
|
return self._dpc_data
|
|
88
112
|
|
|
113
|
+
def _get_dpc_field(self, field_name: str) -> str | float | int:
|
|
114
|
+
"""Get DPC field from periodesHiver data.
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
KeyError: If the required field is not present in the API response.
|
|
118
|
+
"""
|
|
119
|
+
winter_period = self._dpc_data["periodesHiver"][0]
|
|
120
|
+
if field_name not in winter_period:
|
|
121
|
+
raise KeyError(
|
|
122
|
+
f"Required field '{field_name}' not found in DPC periodesHiver data"
|
|
123
|
+
)
|
|
124
|
+
return winter_period[field_name] # type: ignore
|
|
125
|
+
|
|
89
126
|
@property
|
|
90
127
|
@check_period_data_present
|
|
91
128
|
def cp_lower_price_consumption(self) -> float:
|
|
@@ -111,44 +148,69 @@ class ContractDPC(ContractResidential):
|
|
|
111
148
|
@check_dpc_data_present
|
|
112
149
|
def last_update_date(self) -> date:
|
|
113
150
|
"""DPC data last update."""
|
|
114
|
-
|
|
151
|
+
date_str = str(self._get_dpc_field("dateMaj"))
|
|
152
|
+
# Handle ISO format with timezone
|
|
153
|
+
if "T" in date_str:
|
|
154
|
+
return date.fromisoformat(date_str.split("T", maxsplit=1)[0])
|
|
155
|
+
return date.fromisoformat(date_str)
|
|
115
156
|
|
|
116
157
|
@property
|
|
117
158
|
@check_dpc_data_present
|
|
118
159
|
def critical_called_hours(self) -> int:
|
|
119
160
|
"""Get number of critical hours."""
|
|
120
|
-
return int(self.
|
|
161
|
+
return int(self._get_dpc_field("hrsCritiquesAppelees"))
|
|
121
162
|
|
|
122
163
|
@property
|
|
123
164
|
@check_dpc_data_present
|
|
124
165
|
def max_critical_called_hours(self) -> int:
|
|
125
166
|
"""Get max number of critical hours."""
|
|
126
|
-
return int(self.
|
|
167
|
+
return int(self._get_dpc_field("hrsCritiquesAppeleesMax"))
|
|
127
168
|
|
|
128
169
|
@property
|
|
129
170
|
@check_dpc_data_present
|
|
130
|
-
def amount_saved_vs_base_rate(self) -> float:
|
|
131
|
-
"""Amount saved or not versus the base rate.
|
|
132
|
-
|
|
171
|
+
def amount_saved_vs_base_rate(self) -> float | None:
|
|
172
|
+
"""Amount saved or not versus the base rate.
|
|
173
|
+
|
|
174
|
+
Returns None if comparison data is not yet available (e.g., first year on Flex D).
|
|
175
|
+
"""
|
|
176
|
+
try:
|
|
177
|
+
return float(self._get_dpc_field("montantEconPerteVSTarifBase"))
|
|
178
|
+
except KeyError:
|
|
179
|
+
return None
|
|
133
180
|
|
|
134
181
|
@property
|
|
135
182
|
@check_dpc_data_present
|
|
136
183
|
def winter_total_days(self) -> int:
|
|
137
|
-
"""Get number of winter days."""
|
|
138
|
-
|
|
184
|
+
"""Get number of winter days (calculated from period dates)."""
|
|
185
|
+
winter = self._dpc_data["periodesHiver"][0]
|
|
186
|
+
start = datetime.fromisoformat(winter["dateDebut"].replace("Z", "+00:00"))
|
|
187
|
+
end = datetime.fromisoformat(winter["dateFin"].replace("Z", "+00:00"))
|
|
188
|
+
return (end - start).days
|
|
139
189
|
|
|
140
190
|
@property
|
|
141
191
|
@check_dpc_data_present
|
|
142
192
|
def winter_total_days_last_update(self) -> int:
|
|
143
|
-
"""Get number of days since winter starts."""
|
|
144
|
-
|
|
193
|
+
"""Get number of days since winter starts (calculated from dates)."""
|
|
194
|
+
winter = self._dpc_data["periodesHiver"][0]
|
|
195
|
+
start = datetime.fromisoformat(winter["dateDebut"].replace("Z", "+00:00"))
|
|
196
|
+
update = datetime.fromisoformat(winter["dateMaj"].replace("Z", "+00:00"))
|
|
197
|
+
return (update - start).days
|
|
145
198
|
|
|
146
199
|
@property
|
|
147
200
|
@check_dpc_data_present
|
|
148
|
-
def winter_state(self) ->
|
|
149
|
-
"""Get winter state.
|
|
201
|
+
def winter_state(self) -> WinterState:
|
|
202
|
+
"""Get winter state (computed from dates).
|
|
150
203
|
|
|
151
|
-
|
|
152
|
-
|
|
204
|
+
Returns:
|
|
205
|
+
WinterState.CURRENT: Within winter period
|
|
206
|
+
WinterState.FINISHED: Past winter period
|
|
153
207
|
"""
|
|
154
|
-
|
|
208
|
+
winter = self._dpc_data["periodesHiver"][0]
|
|
209
|
+
now = datetime.now(
|
|
210
|
+
datetime.fromisoformat(winter["dateDebut"].replace("Z", "+00:00")).tzinfo
|
|
211
|
+
)
|
|
212
|
+
start = datetime.fromisoformat(winter["dateDebut"].replace("Z", "+00:00"))
|
|
213
|
+
end = datetime.fromisoformat(winter["dateFin"].replace("Z", "+00:00"))
|
|
214
|
+
if start <= now <= end:
|
|
215
|
+
return WinterState.CURRENT
|
|
216
|
+
return WinterState.FINISHED
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/client.py
RENAMED
|
@@ -862,12 +862,16 @@ class HydroClient:
|
|
|
862
862
|
) -> DPCDataTyping:
|
|
863
863
|
"""Fetch FlexD data of the current year.
|
|
864
864
|
|
|
865
|
-
API URL: https://cl
|
|
866
|
-
|
|
865
|
+
API URL: https://services-cl.solutions.hydroquebec.com/wsapi/web/prive/api/
|
|
866
|
+
v3_0/tarificationDynamique/tarifPointeCritique
|
|
867
867
|
|
|
868
868
|
"""
|
|
869
869
|
await self._select_contract(applicant_id, customer_id, contract_id)
|
|
870
|
-
|
|
870
|
+
headers = await self._get_customer_http_headers(applicant_id, customer_id)
|
|
871
|
+
params = {"noContrat": contract_id}
|
|
872
|
+
api_call_response = await self.http_request(
|
|
873
|
+
FLEXD_DATA_URL, "get", params=params, headers=headers
|
|
874
|
+
)
|
|
871
875
|
# We can not use res.json() because the response header are not application/json
|
|
872
876
|
data: DPCDataTyping = self._load_json(await api_call_response.text())
|
|
873
877
|
return data
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/consts.py
RENAMED
|
@@ -57,8 +57,8 @@ OPEN_DATA_PEAK_URL = (
|
|
|
57
57
|
RELATION_URL = f"{HOST_SERVICES}/wsapi/web/prive/api/v1_0/relations"
|
|
58
58
|
|
|
59
59
|
FLEXD_DATA_URL = (
|
|
60
|
-
f"{HOST_SERVICES}/
|
|
61
|
-
"
|
|
60
|
+
f"{HOST_SERVICES}/wsapi/web/prive/api/v3_0/"
|
|
61
|
+
"tarificationDynamique/tarifPointeCritique"
|
|
62
62
|
)
|
|
63
63
|
FLEXD_PEAK_URL = f"{HOST_SERVICES}/conso/portraitweb/api/v3_0/conso"
|
|
64
64
|
CONSO_CSV_URL = (
|
|
@@ -17,13 +17,13 @@ from hydroqc.types.consump import (
|
|
|
17
17
|
ConsumpDailyTyping,
|
|
18
18
|
ConsumpHourlyTyping,
|
|
19
19
|
ConsumpMonthlyTyping,
|
|
20
|
-
DPCDataTyping,
|
|
21
20
|
DPCPeakDataTyping,
|
|
22
21
|
DPCPeakListDataTyping,
|
|
23
|
-
DTDataTyping,
|
|
24
22
|
)
|
|
25
23
|
from hydroqc.types.contract import ContractTyping, ListContractsTyping
|
|
26
24
|
from hydroqc.types.cpc import CPCDataTyping, CriticalPeakDataTyping, PeriodDataTyping
|
|
25
|
+
from hydroqc.types.dpc import DPCDataTyping
|
|
26
|
+
from hydroqc.types.dt import DTDataTyping
|
|
27
27
|
from hydroqc.types.outage import (
|
|
28
28
|
OutageCause,
|
|
29
29
|
OutageCode,
|
|
@@ -155,8 +155,12 @@ class ConsumpAnnualTyping(TypedDict, total=True):
|
|
|
155
155
|
results: list[ConsumpAnnualResultsTyping]
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
class DPCDataResultsTyping(TypedDict, total=
|
|
159
|
-
"""FlexD data json sub output format.
|
|
158
|
+
class DPCDataResultsTyping(TypedDict, total=False):
|
|
159
|
+
"""FlexD data json sub output format.
|
|
160
|
+
|
|
161
|
+
Note: montantEconPerteVSTarifBase may not be available in the first year of Flex D
|
|
162
|
+
as it requires comparison data from previous Rate D billing.
|
|
163
|
+
"""
|
|
160
164
|
|
|
161
165
|
dateDebut: str
|
|
162
166
|
dateFin: str
|
|
@@ -169,23 +173,6 @@ class DPCDataResultsTyping(TypedDict, total=True):
|
|
|
169
173
|
etatHiver: str
|
|
170
174
|
|
|
171
175
|
|
|
172
|
-
class DPCDataTyping(TypedDict, total=True):
|
|
173
|
-
"""FlexD data json output format."""
|
|
174
|
-
|
|
175
|
-
success: bool
|
|
176
|
-
results: list[DPCDataResultsTyping]
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
DTDataResultsTyping = DPCDataResultsTyping
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
class DTDataTyping(TypedDict, total=True):
|
|
183
|
-
"""FlexD data json output format."""
|
|
184
|
-
|
|
185
|
-
success: bool
|
|
186
|
-
results: list[DTDataResultsTyping]
|
|
187
|
-
|
|
188
|
-
|
|
189
176
|
class DPCPeakDataTyping(TypedDict, total=True):
|
|
190
177
|
"""DPC Peak data json output format."""
|
|
191
178
|
|
|
@@ -4,25 +4,46 @@
|
|
|
4
4
|
from typing import TypedDict
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class
|
|
8
|
-
"""FlexD data
|
|
7
|
+
class DPCPeriodeHiverTyping(TypedDict, total=False):
|
|
8
|
+
"""FlexD winter period data (API v3_0 format).
|
|
9
|
+
|
|
10
|
+
Note: montantEconPerteVSTarifBase may not be available in the first year of Flex D
|
|
11
|
+
as it requires comparison data from previous Rate D billing.
|
|
12
|
+
"""
|
|
9
13
|
|
|
10
14
|
dateDebut: str
|
|
11
15
|
dateFin: str
|
|
12
|
-
|
|
16
|
+
dateMaj: str
|
|
13
17
|
hrsCritiquesAppelees: str
|
|
14
18
|
hrsCritiquesAppeleesMax: str
|
|
15
19
|
montantEconPerteVSTarifBase: float
|
|
16
|
-
nbJoursTotauxHiver: int
|
|
17
|
-
nbJoursDernMaj: int
|
|
18
|
-
etatHiver: str
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class
|
|
22
|
-
"""FlexD data
|
|
22
|
+
class DPCEvenementPointeTyping(TypedDict, total=True):
|
|
23
|
+
"""FlexD peak event data (API v3_0 format)."""
|
|
24
|
+
|
|
25
|
+
dateEvenement: str
|
|
26
|
+
heureDebut: str
|
|
27
|
+
heureFin: str
|
|
28
|
+
consoReelle: float
|
|
29
|
+
codeConso: str
|
|
30
|
+
indFacture: bool
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class DPCEvenementsPointeWrapperTyping(TypedDict, total=True):
|
|
34
|
+
"""FlexD peak events wrapper (API v3_0 format)."""
|
|
35
|
+
|
|
36
|
+
dateDebutPeriodeHiver: str
|
|
37
|
+
dateFinPeriodeHiver: str
|
|
38
|
+
evenementsPointe: list[DPCEvenementPointeTyping]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DPCDataTyping(TypedDict, total=False):
|
|
42
|
+
"""FlexD data json output format (API v3_0)."""
|
|
23
43
|
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
dateTestAffichageWeb: str
|
|
45
|
+
periodesHiver: list[DPCPeriodeHiverTyping]
|
|
46
|
+
evenementsPointe: list[DPCEvenementsPointeWrapperTyping]
|
|
26
47
|
|
|
27
48
|
|
|
28
49
|
class DPCPeakDataTyping(TypedDict, total=True):
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Hydroqc custom types."""
|
|
2
|
+
|
|
3
|
+
# pylint: disable=invalid-name
|
|
4
|
+
from typing import TypedDict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DTDataResultsTyping(TypedDict, total=False):
|
|
8
|
+
"""DT winter period data (legacy format).
|
|
9
|
+
|
|
10
|
+
Note: montantEconPerteVSTarifBase may not be available when comparison
|
|
11
|
+
data from previous billing is unavailable.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
dateDebut: str
|
|
15
|
+
dateFin: str
|
|
16
|
+
dateDernMaj: str
|
|
17
|
+
hrsCritiquesAppelee: str
|
|
18
|
+
hrsCritiquesAppeleesMax: str
|
|
19
|
+
montantEconPerteVSTarifBase: float
|
|
20
|
+
nbJoursTotauxHiver: int
|
|
21
|
+
nbJoursDernMaj: int
|
|
22
|
+
etatHiver: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DTDataTyping(TypedDict, total=True):
|
|
26
|
+
"""FlexD data json output format."""
|
|
27
|
+
|
|
28
|
+
success: bool
|
|
29
|
+
results: list[DTDataResultsTyping]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
flake8==7.3.0
|
|
2
2
|
pydocstyle==6.3.0
|
|
3
3
|
parameterized==0.9.0
|
|
4
|
-
pylint==4.0.
|
|
5
|
-
pytest==
|
|
4
|
+
pylint==4.0.3
|
|
5
|
+
pytest==9.0.1
|
|
6
6
|
pytest-cov==7.0.0
|
|
7
|
-
pytest-asyncio==1.
|
|
8
|
-
black==25.
|
|
7
|
+
pytest-asyncio==1.3.0
|
|
8
|
+
black==25.11.0
|
|
9
9
|
mypy==1.18.2
|
|
10
10
|
types-pytz==2025.2.0.20251108
|
|
11
11
|
types-PyYAML==6.0.12.20250915
|
|
12
|
-
types-python-dateutil==2.9.0.
|
|
12
|
+
types-python-dateutil==2.9.0.20251115
|
|
13
13
|
pyright==1.1.407
|
|
14
14
|
lxml==6.0.2
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""Hydroqc custom types."""
|
|
2
|
-
|
|
3
|
-
# pylint: disable=invalid-name
|
|
4
|
-
from typing import TypedDict
|
|
5
|
-
|
|
6
|
-
from hydroqc.types.dpc import DPCDataResultsTyping
|
|
7
|
-
|
|
8
|
-
DTDataResultsTyping = DPCDataResultsTyping
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class DTDataTyping(TypedDict, total=True):
|
|
12
|
-
"""FlexD data json output format."""
|
|
13
|
-
|
|
14
|
-
success: bool
|
|
15
|
-
results: list[DTDataResultsTyping]
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/.devcontainer/devcontainer.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/conflict_test_requirements.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/_static/custom.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/hydroqc.rst
RENAMED
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/docs/source/reference/modules.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/__init__.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/common.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_d.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_d_cpc.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_dt.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_m.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/contract_m_gdp.py
RENAMED
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/contract/outage.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/__init__.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/hydro_api/cache.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/basepeakhandler.py
RENAMED
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/__init__.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/consts.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/cpc/handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/__init__.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/consts.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/hydroqc/peak/dpc/handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_d.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_d_cpc.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_dpc.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_dt.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_m.py
RENAMED
|
File without changes
|
{hydro_quebec_api_wrapper-4.1.0 → hydro_quebec_api_wrapper-4.2.1}/tests/subtest_contract_m_gdp.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|