Hydro-Quebec-API-Wrapper 4.2.2__py3-none-any.whl → 4.2.3__py3-none-any.whl
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.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/METADATA +1 -1
- {hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/RECORD +8 -8
- hydroqc/contract/contract_dpc.py +12 -20
- hydroqc/hydro_api/client.py +24 -20
- {hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/WHEEL +0 -0
- {hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/entry_points.txt +0 -0
- {hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/licenses/LICENSE +0 -0
- {hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/top_level.txt +0 -0
{hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/RECORD
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
hydro_quebec_api_wrapper-4.2.
|
|
1
|
+
hydro_quebec_api_wrapper-4.2.3.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
2
2
|
hydroqc/__init__.py,sha256=sFhCh7-LWoISCQuAtdrLQOmj2x5wjHBGbAAPg4SN6Pc,40
|
|
3
3
|
hydroqc/account.py,sha256=84PO2npB_VG8cEzGIbmXj9sD1whG8qynkiGd-yEYddM,3375
|
|
4
4
|
hydroqc/consts.py,sha256=a9dWq5i6t5VedYosUbP8zIuG2q5TPw4ruT0jOaC8Yo8,209
|
|
@@ -15,7 +15,7 @@ hydroqc/contract/__init__.py,sha256=uqxjOgyhpKFd-n_umxdaW5FB_DkJJaettWnEFC0nRYc,
|
|
|
15
15
|
hydroqc/contract/common.py,sha256=xVw9z_Yjqp95SGCPNAfJVABvgp_C-KM51VTBEU9wjeM,15705
|
|
16
16
|
hydroqc/contract/contract_d.py,sha256=6jPYTCjFq8zonfbXPrEujDVz58n5RUEuq54VCGqph6o,856
|
|
17
17
|
hydroqc/contract/contract_d_cpc.py,sha256=-Y2S4MkzAfsbf_L2jCKfU7OD-nbzgoEpyT3SWh0U0tQ,1418
|
|
18
|
-
hydroqc/contract/contract_dpc.py,sha256=
|
|
18
|
+
hydroqc/contract/contract_dpc.py,sha256=6XMj2gq4oWvfekwqHvbnivWhL5pk7HTP4F2wOfdKi3A,7271
|
|
19
19
|
hydroqc/contract/contract_dt.py,sha256=TSKf2oh-MlG8A42xVUCCyf7oezlWTFoyATF9xlQn2JE,1687
|
|
20
20
|
hydroqc/contract/contract_m.py,sha256=2hSSb9Tw2eZu7PV1XicfTFKLCRiffq72NfOYiVz8QMk,2108
|
|
21
21
|
hydroqc/contract/contract_m_gdp.py,sha256=y8seZHmjkkul0TZ5Epxuxc4g0JVbs9o8KjL_y1gIldU,801
|
|
@@ -23,7 +23,7 @@ hydroqc/contract/contract_residential.py,sha256=v88mWvJsJP7FsY5cHmr0ZYYT_S-6xtSk
|
|
|
23
23
|
hydroqc/contract/outage.py,sha256=K5XX0enSKMVpL-JCkWsykuKUw-5_GcSJLzcSR1SqQDk,3979
|
|
24
24
|
hydroqc/hydro_api/__init__.py,sha256=bIIjTkhQcXG7kn4cQr_Q6tFSKGjAx-AXLjMMlRCjclY,32
|
|
25
25
|
hydroqc/hydro_api/cache.py,sha256=mC3UO246V5zJ1p89nUb5EzQon_4tQGUgFMZKy4YY8I8,912
|
|
26
|
-
hydroqc/hydro_api/client.py,sha256=
|
|
26
|
+
hydroqc/hydro_api/client.py,sha256=hZLddlsN5_H-jBL7Tt5w1ASofC9Yza9_kWHL116zVXI,36958
|
|
27
27
|
hydroqc/hydro_api/consts.py,sha256=XDNOjZVpC-Z7rsOL4GDgfexb7m8zc7HiafiKGiFvoUI,4607
|
|
28
28
|
hydroqc/peak/__init__.py,sha256=ye2KbWXhJEHZnBDaFylWioy3W-mzJw_lDplsJNAapNs,19
|
|
29
29
|
hydroqc/peak/basepeak.py,sha256=DMXjZXyNRHWnuhB0Vp3ZINGhNQngG7AU15cDLajmC7M,1954
|
|
@@ -46,8 +46,8 @@ hydroqc/types/cpc.py,sha256=ghmtBTT1FKuqVodJJ0kCtUbYNTLCOrngxgcrzjJYvok,2116
|
|
|
46
46
|
hydroqc/types/dpc.py,sha256=mwA5T9fGcNTA-kb_f25wq2ALJCwa5lKABOS73L6znY0,1981
|
|
47
47
|
hydroqc/types/dt.py,sha256=rEXDgNewhlOsRbso0Shlq69TvJFoT56EGYOAjTFZU80,693
|
|
48
48
|
hydroqc/types/outage.py,sha256=XTsNyu8mmxUx44XWvOOUHKSoijp-lgbXwQroiqm9S0o,3932
|
|
49
|
-
hydro_quebec_api_wrapper-4.2.
|
|
50
|
-
hydro_quebec_api_wrapper-4.2.
|
|
51
|
-
hydro_quebec_api_wrapper-4.2.
|
|
52
|
-
hydro_quebec_api_wrapper-4.2.
|
|
53
|
-
hydro_quebec_api_wrapper-4.2.
|
|
49
|
+
hydro_quebec_api_wrapper-4.2.3.dist-info/METADATA,sha256=LlGJNtk6_0JhAKXOWd7sz8gxaUjNY_vg70EA7mho2g4,7948
|
|
50
|
+
hydro_quebec_api_wrapper-4.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
51
|
+
hydro_quebec_api_wrapper-4.2.3.dist-info/entry_points.txt,sha256=G2YKkCH9rFt2dXbFyHINBp4bmqY2HTEIaf7F1CwbC_k,57
|
|
52
|
+
hydro_quebec_api_wrapper-4.2.3.dist-info/top_level.txt,sha256=YAcYLnu5YYkbxt1psUoBfo_opl-lAZKq0A7B3IN_P6M,8
|
|
53
|
+
hydro_quebec_api_wrapper-4.2.3.dist-info/RECORD,,
|
hydroqc/contract/contract_dpc.py
CHANGED
|
@@ -21,7 +21,10 @@ class WinterState(str, Enum):
|
|
|
21
21
|
def check_dpc_data_present(
|
|
22
22
|
method: Callable[..., None | str | bool | float | int | date | WinterState],
|
|
23
23
|
) -> Callable[..., None | str | bool | float | int | date | WinterState]:
|
|
24
|
-
"""Check if contractDPC's data are present.
|
|
24
|
+
"""Check if contractDPC's data are present.
|
|
25
|
+
|
|
26
|
+
Returns None if data is not available or incomplete.
|
|
27
|
+
"""
|
|
25
28
|
|
|
26
29
|
def wrapper(
|
|
27
30
|
contract: "ContractDPC",
|
|
@@ -110,19 +113,6 @@ class ContractDPC(ContractResidential):
|
|
|
110
113
|
)
|
|
111
114
|
return self._dpc_data
|
|
112
115
|
|
|
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
|
-
|
|
126
116
|
@property
|
|
127
117
|
@check_period_data_present
|
|
128
118
|
def cp_lower_price_consumption(self) -> float:
|
|
@@ -148,7 +138,7 @@ class ContractDPC(ContractResidential):
|
|
|
148
138
|
@check_dpc_data_present
|
|
149
139
|
def last_update_date(self) -> date:
|
|
150
140
|
"""DPC data last update."""
|
|
151
|
-
date_str = str(self.
|
|
141
|
+
date_str = str(self._dpc_data["periodesHiver"][0]["dateMaj"])
|
|
152
142
|
# Handle ISO format with timezone
|
|
153
143
|
if "T" in date_str:
|
|
154
144
|
return date.fromisoformat(date_str.split("T", maxsplit=1)[0])
|
|
@@ -158,13 +148,13 @@ class ContractDPC(ContractResidential):
|
|
|
158
148
|
@check_dpc_data_present
|
|
159
149
|
def critical_called_hours(self) -> int:
|
|
160
150
|
"""Get number of critical hours."""
|
|
161
|
-
return int(self.
|
|
151
|
+
return int(self._dpc_data["periodesHiver"][0]["hrsCritiquesAppelees"])
|
|
162
152
|
|
|
163
153
|
@property
|
|
164
154
|
@check_dpc_data_present
|
|
165
155
|
def max_critical_called_hours(self) -> int:
|
|
166
156
|
"""Get max number of critical hours."""
|
|
167
|
-
return int(self.
|
|
157
|
+
return int(self._dpc_data["periodesHiver"][0]["hrsCritiquesAppeleesMax"])
|
|
168
158
|
|
|
169
159
|
@property
|
|
170
160
|
@check_dpc_data_present
|
|
@@ -173,10 +163,12 @@ class ContractDPC(ContractResidential):
|
|
|
173
163
|
|
|
174
164
|
Returns None if comparison data is not yet available (e.g., first year on Flex D).
|
|
175
165
|
"""
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
166
|
+
if (
|
|
167
|
+
self._dpc_data["periodesHiver"][0].get("montantEconPerteVSTarifBase")
|
|
168
|
+
is None
|
|
169
|
+
):
|
|
179
170
|
return None
|
|
171
|
+
return float(self._dpc_data["periodesHiver"][0]["montantEconPerteVSTarifBase"])
|
|
180
172
|
|
|
181
173
|
@property
|
|
182
174
|
@check_dpc_data_present
|
hydroqc/hydro_api/client.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""HydroQc Client Module."""
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import base64
|
|
4
5
|
import csv
|
|
5
6
|
import json
|
|
@@ -7,7 +8,6 @@ import logging
|
|
|
7
8
|
import os
|
|
8
9
|
import platform
|
|
9
10
|
import re
|
|
10
|
-
import ssl
|
|
11
11
|
import uuid
|
|
12
12
|
from collections.abc import Iterator
|
|
13
13
|
from datetime import date, datetime, timedelta
|
|
@@ -114,6 +114,8 @@ class HydroClient:
|
|
|
114
114
|
self.guid: str = str(uuid.uuid1())
|
|
115
115
|
self._logger: logging.Logger = get_logger("httpclient", log_level)
|
|
116
116
|
self._logger.debug("HydroQc initialized")
|
|
117
|
+
# Cache for blocking operations (initialized lazily)
|
|
118
|
+
self._cached_version: str | None = None
|
|
117
119
|
self.reset()
|
|
118
120
|
|
|
119
121
|
def reset(self) -> None:
|
|
@@ -128,20 +130,27 @@ class HydroClient:
|
|
|
128
130
|
self._selected_customer = ""
|
|
129
131
|
self._selected_contract = ""
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
def user_agent(self) -> str:
|
|
133
|
+
async def _get_user_agent(self) -> str:
|
|
133
134
|
"""Get http client user_agent."""
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
if self._cached_version is None:
|
|
136
|
+
# Run blocking version lookup in executor to avoid blocking event loop
|
|
137
|
+
loop = asyncio.get_event_loop()
|
|
138
|
+
try:
|
|
139
|
+
self._cached_version = await loop.run_in_executor(
|
|
140
|
+
None, version, "Hydro_Quebec_API_Wrapper"
|
|
141
|
+
)
|
|
142
|
+
except PackageNotFoundError:
|
|
143
|
+
# package is not installed
|
|
144
|
+
self._logger.warning(
|
|
145
|
+
"Python package `Hydro_Quebec_API_Wrapper` is not installed. "
|
|
146
|
+
"Install it using pip"
|
|
147
|
+
)
|
|
148
|
+
self._cached_version = "unkwown"
|
|
143
149
|
os_name = platform.system()
|
|
144
|
-
return
|
|
150
|
+
return (
|
|
151
|
+
f"Hydroqc/{self._cached_version} "
|
|
152
|
+
f"(dev@hydroqc.ca; https://gitlab.com/hydroqc) {os_name}"
|
|
153
|
+
)
|
|
145
154
|
|
|
146
155
|
async def http_request(
|
|
147
156
|
self,
|
|
@@ -163,15 +172,10 @@ class HydroClient:
|
|
|
163
172
|
data = {}
|
|
164
173
|
if headers is None:
|
|
165
174
|
headers = {}
|
|
166
|
-
headers["User-Agent"] = self.
|
|
175
|
+
headers["User-Agent"] = await self._get_user_agent()
|
|
167
176
|
if verify_ssl is None:
|
|
168
177
|
verify_ssl = self._verify_ssl
|
|
169
178
|
|
|
170
|
-
ssl_context: ssl.SSLContext | None = None
|
|
171
|
-
if verify_ssl:
|
|
172
|
-
ssl_context = ssl.create_default_context()
|
|
173
|
-
ssl_context.set_ciphers("DEFAULT") # Needed for python3.10
|
|
174
|
-
|
|
175
179
|
# Query Diagnostic
|
|
176
180
|
if self._diag_folder is not None:
|
|
177
181
|
cleaned_url = url.replace("/", "_").replace(":", "").split("#", 1)[0]
|
|
@@ -205,7 +209,7 @@ class HydroClient:
|
|
|
205
209
|
params=params,
|
|
206
210
|
data=data,
|
|
207
211
|
allow_redirects=allow_redirects,
|
|
208
|
-
ssl=
|
|
212
|
+
ssl=verify_ssl,
|
|
209
213
|
headers=headers,
|
|
210
214
|
)
|
|
211
215
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hydro_quebec_api_wrapper-4.2.2.dist-info → hydro_quebec_api_wrapper-4.2.3.dist-info}/top_level.txt
RENAMED
|
File without changes
|