Hydro-Quebec-API-Wrapper 3.2.0__tar.gz → 4.0.0__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-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.gitlab-ci.yml +5 -5
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.pre-commit-config.yaml +7 -6
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/Hydro_Quebec_API_Wrapper.egg-info/PKG-INFO +4 -4
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/Hydro_Quebec_API_Wrapper.egg-info/SOURCES.txt +4 -0
- hydro_quebec_api_wrapper-4.0.0/Hydro_Quebec_API_Wrapper.egg-info/requires.txt +5 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/PKG-INFO +4 -4
- hydro_quebec_api_wrapper-4.0.0/conflict_test_requirements.txt +1 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/diagnostic.py +48 -5
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/hydro_api/client.py +40 -8
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/hydro_api/consts.py +6 -0
- hydro_quebec_api_wrapper-4.0.0/hydroqc/peak/basepeak.py +67 -0
- hydro_quebec_api_wrapper-3.2.0/hydroqc/peak/dpc/handler.py → hydro_quebec_api_wrapper-4.0.0/hydroqc/peak/basepeakhandler.py +113 -107
- hydro_quebec_api_wrapper-4.0.0/hydroqc/peak/consts.py +3 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/cpc/handler.py +74 -178
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/cpc/peak.py +13 -84
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/dpc/consts.py +0 -1
- hydro_quebec_api_wrapper-4.0.0/hydroqc/peak/dpc/handler.py +108 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/dpc/peak.py +7 -21
- hydro_quebec_api_wrapper-4.0.0/hydroqc/public_client.py +79 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/__init__.py +8 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/common.py +32 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/webuser.py +7 -4
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/pyproject.toml +5 -2
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/setup.cfg +3 -3
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/test_requirements.txt +8 -8
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_common.py +17 -46
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_contract_d.py +1 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_contract_d_cpc.py +19 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_contract_dpc.py +9 -4
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_contract_dt.py +1 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_contract_m.py +1 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/subtest_contract_m_gdp.py +1 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/test_timerange.py +13 -5
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/tools.py +2 -2
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tox.ini +1 -1
- hydro_quebec_api_wrapper-3.2.0/Hydro_Quebec_API_Wrapper.egg-info/requires.txt +0 -5
- hydro_quebec_api_wrapper-3.2.0/conflict_test_requirements.txt +0 -1
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.coveragerc +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.devcontainer/devcontainer.json +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.flake8 +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.gitignore +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/.pylintrc +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/Hydro_Quebec_API_Wrapper.egg-info/dependency_links.txt +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/Hydro_Quebec_API_Wrapper.egg-info/entry_points.txt +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/Hydro_Quebec_API_Wrapper.egg-info/top_level.txt +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/LICENSE +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/MANIFEST.in +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/README.md +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/config.default.yaml +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/Makefile +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/make.bat +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/_static/custom.css +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/_static/hydroqc-logo-128.png +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/_static/hydroqc-logo.svg +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/conf.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/external/description-des-codes-interruption.pdf +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/index.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.contract.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.hydro_api.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.peak.cpc.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.peak.dpc.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.peak.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/hydroqc.types.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/reference/modules.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/docs/source/todo.rst +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/examples/hydro.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/account.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/consts.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/common.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_d.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_d_cpc.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_dpc.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_dt.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_m.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_m_gdp.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/contract_residential.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/contract/outage.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/customer.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/error.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/hydro_api/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/hydro_api/cache.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/logger.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/cpc/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/cpc/consts.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/peak/dpc/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/py.typed +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/timerange.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/account.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/consump.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/contract.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/cpc.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/dpc.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/dt.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/types/outage.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/utils.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/logo/hydroqc-logo-128.png +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/logo/hydroqc-logo.svg +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/renovate.json5 +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/__init__.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/conftest.py +0 -0
- {hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/tests/test_basic.py +0 -0
|
@@ -31,7 +31,7 @@ test:
|
|
|
31
31
|
stage: test
|
|
32
32
|
tags:
|
|
33
33
|
- hydroqc
|
|
34
|
-
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:
|
|
34
|
+
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:d8985672e512080c541beeab0da37aa166a41b24ab9f0cf86bed4944cd743fae
|
|
35
35
|
script:
|
|
36
36
|
- tox -e pylint,flake8,pydocstyle,typing,black,deps-conflict --parallel auto
|
|
37
37
|
- cat mypy-txt-report/index.txt
|
|
@@ -70,7 +70,7 @@ test:
|
|
|
70
70
|
# Run on shared runners to lighten the load on the private runners
|
|
71
71
|
# tags:
|
|
72
72
|
# - hydroqc
|
|
73
|
-
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:
|
|
73
|
+
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:d8985672e512080c541beeab0da37aa166a41b24ab9f0cf86bed4944cd743fae
|
|
74
74
|
script:
|
|
75
75
|
- >
|
|
76
76
|
OUTPUT=$(curl
|
|
@@ -257,7 +257,7 @@ private_tests_done:
|
|
|
257
257
|
stage: private_tests_done
|
|
258
258
|
tags:
|
|
259
259
|
- hydroqc
|
|
260
|
-
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:
|
|
260
|
+
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:d8985672e512080c541beeab0da37aa166a41b24ab9f0cf86bed4944cd743fae
|
|
261
261
|
script:
|
|
262
262
|
#- apt-get update && apt-get install --no-install-recommends -y python3.10 python3-venv python3-pip --no-install-recommends git
|
|
263
263
|
- echo "Private Tests done"
|
|
@@ -299,7 +299,7 @@ package:
|
|
|
299
299
|
stage: test
|
|
300
300
|
tags:
|
|
301
301
|
- hydroqc
|
|
302
|
-
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:
|
|
302
|
+
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:d8985672e512080c541beeab0da37aa166a41b24ab9f0cf86bed4944cd743fae
|
|
303
303
|
script:
|
|
304
304
|
# Build a package with a version based on the commmit short sha
|
|
305
305
|
- pip install --upgrade pip
|
|
@@ -329,7 +329,7 @@ promote2pypi:
|
|
|
329
329
|
stage: pypi
|
|
330
330
|
tags:
|
|
331
331
|
- hydroqc
|
|
332
|
-
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:
|
|
332
|
+
image: registry.gitlab.com/hydroqc/hydroqc-base-container/3.12@sha256:d8985672e512080c541beeab0da37aa166a41b24ab9f0cf86bed4944cd743fae
|
|
333
333
|
script:
|
|
334
334
|
# TODO: try to pull the good package from gitlab pypi repo
|
|
335
335
|
# then change the version (promote)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
repos:
|
|
2
2
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
-
rev:
|
|
3
|
+
rev: v5.0.0
|
|
4
4
|
hooks:
|
|
5
5
|
- id: trailing-whitespace
|
|
6
6
|
- id: end-of-file-fixer
|
|
@@ -16,13 +16,13 @@ repos:
|
|
|
16
16
|
- id: check-ast
|
|
17
17
|
|
|
18
18
|
- repo: https://github.com/psf/black
|
|
19
|
-
rev: 24.
|
|
19
|
+
rev: 24.10.0
|
|
20
20
|
hooks:
|
|
21
21
|
- id: black
|
|
22
22
|
language_version: python3
|
|
23
23
|
|
|
24
24
|
- repo: https://github.com/PyCQA/flake8/
|
|
25
|
-
rev: 7.
|
|
25
|
+
rev: 7.1.1
|
|
26
26
|
hooks:
|
|
27
27
|
- id: flake8
|
|
28
28
|
additional_dependencies: [flake8-docstrings]
|
|
@@ -35,12 +35,12 @@ repos:
|
|
|
35
35
|
# additional_dependencies: [toml]
|
|
36
36
|
|
|
37
37
|
- repo: https://github.com/PyCQA/doc8
|
|
38
|
-
rev: v1.1.
|
|
38
|
+
rev: v1.1.2
|
|
39
39
|
hooks:
|
|
40
40
|
- id: doc8
|
|
41
41
|
|
|
42
42
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
43
|
-
rev: v1.
|
|
43
|
+
rev: v1.14.1
|
|
44
44
|
hooks:
|
|
45
45
|
- id: mypy
|
|
46
46
|
args: [--strict, --pretty, --show-error-codes]
|
|
@@ -49,6 +49,7 @@ repos:
|
|
|
49
49
|
- "types-PyYAML==6.0.12.20240311"
|
|
50
50
|
- "types-python-dateutil==2.9.0.20240316"
|
|
51
51
|
- "pytest-stub==1.1.0"
|
|
52
|
-
- "aiohttp==3.
|
|
52
|
+
- "aiohttp==3.10.10"
|
|
53
53
|
- "aiocache==0.12.2"
|
|
54
54
|
- "pkce==1.0.3"
|
|
55
|
+
- "pytest-asyncio==0.25.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: Hydro-Quebec-API-Wrapper
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: A wrapper library to access hydro quebec API and more
|
|
5
5
|
Home-page: https://hydroqc.ca
|
|
6
6
|
Author-email: Hydroqc Team <info@hydroqc.ca>
|
|
@@ -15,10 +15,10 @@ Classifier: Operating System :: OS Independent
|
|
|
15
15
|
Requires-Python: >=3.10.0
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: aiohttp==3.
|
|
18
|
+
Requires-Dist: aiohttp==3.10.10
|
|
19
19
|
Requires-Dist: python-dateutil==2.9.0.post0
|
|
20
|
-
Requires-Dist: pytz==2024.
|
|
21
|
-
Requires-Dist: aiocache==0.12.
|
|
20
|
+
Requires-Dist: pytz==2024.2
|
|
21
|
+
Requires-Dist: aiocache==0.12.3
|
|
22
22
|
Requires-Dist: pkce==1.0.3
|
|
23
23
|
|
|
24
24
|
# HydroQC - Hydro Quebec API wrapper
|
|
@@ -46,6 +46,7 @@ hydroqc/customer.py
|
|
|
46
46
|
hydroqc/diagnostic.py
|
|
47
47
|
hydroqc/error.py
|
|
48
48
|
hydroqc/logger.py
|
|
49
|
+
hydroqc/public_client.py
|
|
49
50
|
hydroqc/py.typed
|
|
50
51
|
hydroqc/timerange.py
|
|
51
52
|
hydroqc/utils.py
|
|
@@ -65,6 +66,9 @@ hydroqc/hydro_api/cache.py
|
|
|
65
66
|
hydroqc/hydro_api/client.py
|
|
66
67
|
hydroqc/hydro_api/consts.py
|
|
67
68
|
hydroqc/peak/__init__.py
|
|
69
|
+
hydroqc/peak/basepeak.py
|
|
70
|
+
hydroqc/peak/basepeakhandler.py
|
|
71
|
+
hydroqc/peak/consts.py
|
|
68
72
|
hydroqc/peak/cpc/__init__.py
|
|
69
73
|
hydroqc/peak/cpc/consts.py
|
|
70
74
|
hydroqc/peak/cpc/handler.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: Hydro-Quebec-API-Wrapper
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: A wrapper library to access hydro quebec API and more
|
|
5
5
|
Home-page: https://hydroqc.ca
|
|
6
6
|
Author-email: Hydroqc Team <info@hydroqc.ca>
|
|
@@ -15,10 +15,10 @@ Classifier: Operating System :: OS Independent
|
|
|
15
15
|
Requires-Python: >=3.10.0
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: aiohttp==3.
|
|
18
|
+
Requires-Dist: aiohttp==3.10.10
|
|
19
19
|
Requires-Dist: python-dateutil==2.9.0.post0
|
|
20
|
-
Requires-Dist: pytz==2024.
|
|
21
|
-
Requires-Dist: aiocache==0.12.
|
|
20
|
+
Requires-Dist: pytz==2024.2
|
|
21
|
+
Requires-Dist: aiocache==0.12.3
|
|
22
22
|
Requires-Dist: pkce==1.0.3
|
|
23
23
|
|
|
24
24
|
# HydroQC - Hydro Quebec API wrapper
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mqtt-hass-base==4.4.0
|
|
@@ -20,6 +20,7 @@ from dateutil.relativedelta import relativedelta
|
|
|
20
20
|
from hydroqc.contract import ContractDCPC, ContractDPC, ContractM
|
|
21
21
|
from hydroqc.error import HydroQcError
|
|
22
22
|
from hydroqc.logger import get_logger
|
|
23
|
+
from hydroqc.public_client import PublicClient
|
|
23
24
|
from hydroqc.webuser import WebUser
|
|
24
25
|
|
|
25
26
|
LOG_LEVEL = (
|
|
@@ -39,10 +40,12 @@ class Diagnostic:
|
|
|
39
40
|
"""Contructor."""
|
|
40
41
|
# Get base settings
|
|
41
42
|
self.diagnostic_folder = cli_settings.output_folder
|
|
43
|
+
self.diagnostic_folder_public = os.path.join(self.diagnostic_folder, "public")
|
|
42
44
|
# Prepare output folder
|
|
43
45
|
if os.path.exists(self.diagnostic_folder):
|
|
44
46
|
shutil.rmtree(self.diagnostic_folder)
|
|
45
47
|
os.makedirs(self.diagnostic_folder)
|
|
48
|
+
os.makedirs(self.diagnostic_folder_public)
|
|
46
49
|
# Prepare logger
|
|
47
50
|
self._log_file = os.path.join(self.diagnostic_folder, "diagnostic.log")
|
|
48
51
|
log_level = cli_settings.log_level
|
|
@@ -51,6 +54,7 @@ class Diagnostic:
|
|
|
51
54
|
file_handler.setFormatter(self.logger.handlers[0].formatter)
|
|
52
55
|
file_handler.setLevel(self.logger.level)
|
|
53
56
|
self.logger.addHandler(file_handler)
|
|
57
|
+
self.logger_public = self.logger.getChild("public")
|
|
54
58
|
http_log_level = cli_settings.http_log_level
|
|
55
59
|
|
|
56
60
|
# Get settings
|
|
@@ -69,6 +73,15 @@ class Diagnostic:
|
|
|
69
73
|
log_file=self._log_file,
|
|
70
74
|
diag_folder=self.diagnostic_folder,
|
|
71
75
|
)
|
|
76
|
+
self.public_client = PublicClient(
|
|
77
|
+
rate_code="DPC",
|
|
78
|
+
# rate_option_code="CPC",
|
|
79
|
+
verify_ssl=True,
|
|
80
|
+
log_level=log_level,
|
|
81
|
+
http_log_level=http_log_level,
|
|
82
|
+
log_file=self._log_file,
|
|
83
|
+
diag_folder=self.diagnostic_folder_public,
|
|
84
|
+
)
|
|
72
85
|
|
|
73
86
|
def zip(self) -> None:
|
|
74
87
|
"""Archive all generated files."""
|
|
@@ -87,6 +100,11 @@ class Diagnostic:
|
|
|
87
100
|
"""Get diagnostic http ID."""
|
|
88
101
|
return self.webuser._hydro_client._diag_id
|
|
89
102
|
|
|
103
|
+
@property
|
|
104
|
+
def public_diag_id(self) -> int:
|
|
105
|
+
"""Get diagnostic http ID."""
|
|
106
|
+
return self.public_client._hydro_client._diag_id
|
|
107
|
+
|
|
90
108
|
async def run(self) -> None: # pylint: disable=too-many-statements
|
|
91
109
|
"""Run diagnostic."""
|
|
92
110
|
today = datetime.date.today()
|
|
@@ -94,6 +112,24 @@ class Diagnostic:
|
|
|
94
112
|
day_2 = today - datetime.timedelta(days=2)
|
|
95
113
|
|
|
96
114
|
try:
|
|
115
|
+
self.logger_public.info(
|
|
116
|
+
"%02d - Checking HQ portal status", self.public_diag_id
|
|
117
|
+
)
|
|
118
|
+
hq_status = await self.public_client.check_hq_portal_status()
|
|
119
|
+
self.logger_public.info(
|
|
120
|
+
"%02d - HQ portal available: %s", self.public_diag_id - 1, hq_status
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
self.logger_public.info(
|
|
124
|
+
"%02d - Fetch peak using open data", self.public_diag_id
|
|
125
|
+
)
|
|
126
|
+
await self.public_client.fetch_peak_data()
|
|
127
|
+
self.logger_public.info(
|
|
128
|
+
"%02d - Peak found: %s",
|
|
129
|
+
self.public_diag_id - 1,
|
|
130
|
+
len(self.public_client.peaks),
|
|
131
|
+
)
|
|
132
|
+
|
|
97
133
|
self.logger.info("%02d - Checking HQ portal status", self.diag_id)
|
|
98
134
|
hq_status = await self.webuser.check_hq_portal_status()
|
|
99
135
|
self.logger.info(
|
|
@@ -267,6 +303,10 @@ class Diagnostic:
|
|
|
267
303
|
await contract_dcpc.peak_handler.refresh_data()
|
|
268
304
|
self.logger.info("%02d - Got cpc data", self.diag_id - 1)
|
|
269
305
|
|
|
306
|
+
self.logger.info("%02d - Trying to get opn data", self.diag_id)
|
|
307
|
+
await contract_dcpc.peak_handler.refresh_open_data()
|
|
308
|
+
self.logger.info("%02d - Got open data", self.diag_id - 1)
|
|
309
|
+
|
|
270
310
|
# DCP/FlexD
|
|
271
311
|
elif self.contract.rate == "DPC":
|
|
272
312
|
self.logger.info("%02d - Trying to get flexD data", self.diag_id)
|
|
@@ -289,6 +329,10 @@ class Diagnostic:
|
|
|
289
329
|
await contract_dpc.peak_handler.refresh_data()
|
|
290
330
|
self.logger.info("%02d - Got flexD data", self.diag_id - 1)
|
|
291
331
|
|
|
332
|
+
self.logger.info("%02d - Trying to get opn data", self.diag_id)
|
|
333
|
+
await contract_dcpc.peak_handler.refresh_open_data()
|
|
334
|
+
self.logger.info("%02d - Got open data", self.diag_id - 1)
|
|
335
|
+
|
|
292
336
|
# DT
|
|
293
337
|
if self.contract.rate == "DT":
|
|
294
338
|
low_price = contract_dpc.cp_lower_price_consumption
|
|
@@ -330,6 +374,9 @@ class Diagnostic:
|
|
|
330
374
|
traceback.print_exception(exp, file=fhtb)
|
|
331
375
|
fhtb.seek(0)
|
|
332
376
|
self.logger.error(fhtb.read())
|
|
377
|
+
finally:
|
|
378
|
+
await self.webuser.close_session()
|
|
379
|
+
await self.public_client.close_session()
|
|
333
380
|
|
|
334
381
|
|
|
335
382
|
def parse_args() -> argparse.Namespace:
|
|
@@ -380,14 +427,10 @@ def main() -> None:
|
|
|
380
427
|
"""Run diagnostic."""
|
|
381
428
|
cli_settings = parse_args()
|
|
382
429
|
|
|
383
|
-
loop = asyncio.get_event_loop()
|
|
384
430
|
diag = Diagnostic(cli_settings)
|
|
385
431
|
|
|
386
432
|
# Fetch data
|
|
387
|
-
|
|
388
|
-
close_fut = asyncio.gather(diag.webuser.close_session())
|
|
389
|
-
loop.run_until_complete(close_fut)
|
|
390
|
-
loop.close()
|
|
433
|
+
asyncio.run(diag.run())
|
|
391
434
|
# zip
|
|
392
435
|
diag.zip()
|
|
393
436
|
|
{hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/hydro_api/client.py
RENAMED
|
@@ -14,11 +14,11 @@ from datetime import date, datetime, timedelta
|
|
|
14
14
|
from importlib.metadata import PackageNotFoundError, version
|
|
15
15
|
from io import StringIO
|
|
16
16
|
from json import dumps as json_dumps
|
|
17
|
-
from typing import Any
|
|
18
|
-
from pkce import generate_pkce_pair
|
|
17
|
+
from typing import Any, cast
|
|
19
18
|
|
|
20
19
|
import aiohttp
|
|
21
20
|
import yarl
|
|
21
|
+
from pkce import generate_pkce_pair
|
|
22
22
|
|
|
23
23
|
from hydroqc.error import HydroQcError, HydroQcHTTPError
|
|
24
24
|
from hydroqc.hydro_api.cache import CCached
|
|
@@ -43,6 +43,7 @@ from hydroqc.hydro_api.consts import (
|
|
|
43
43
|
HOURLY_CONSUMPTION_API_URL,
|
|
44
44
|
IS_HYDRO_PORTAL_UP_URL,
|
|
45
45
|
MONTHLY_DATA_URL,
|
|
46
|
+
OPEN_DATA_PEAK_URL,
|
|
46
47
|
OUTAGES,
|
|
47
48
|
PERIOD_DATA_URL,
|
|
48
49
|
PORTRAIT_URL,
|
|
@@ -67,6 +68,8 @@ from hydroqc.types import (
|
|
|
67
68
|
InfoAccountTyping,
|
|
68
69
|
ListAccountsContractsTyping,
|
|
69
70
|
ListContractsTyping,
|
|
71
|
+
OpenDataPeakEvent,
|
|
72
|
+
OpenDataPeakEventOffer,
|
|
70
73
|
OutageListTyping,
|
|
71
74
|
PeriodDataTyping,
|
|
72
75
|
)
|
|
@@ -76,6 +79,8 @@ from hydroqc.utils import EST_TIMEZONE
|
|
|
76
79
|
class HydroClient:
|
|
77
80
|
"""HydroQc HTTP Client."""
|
|
78
81
|
|
|
82
|
+
_cookie_jar: aiohttp.CookieJar
|
|
83
|
+
|
|
79
84
|
def __init__(
|
|
80
85
|
self,
|
|
81
86
|
username: str,
|
|
@@ -91,7 +96,6 @@ class HydroClient:
|
|
|
91
96
|
self.password: str = password
|
|
92
97
|
self._timeout: int = timeout
|
|
93
98
|
self._session: aiohttp.ClientSession | None = session
|
|
94
|
-
self._cookie_jar: aiohttp.CookieJar = aiohttp.CookieJar()
|
|
95
99
|
self._verify_ssl: bool = verify_ssl
|
|
96
100
|
|
|
97
101
|
# OAuth handling variables
|
|
@@ -119,7 +123,7 @@ class HydroClient:
|
|
|
119
123
|
self.refresh_token = ""
|
|
120
124
|
self.refresh_token_expiry = datetime.now()
|
|
121
125
|
self.web_session_expiry = datetime.now()
|
|
122
|
-
self._cookie_jar = aiohttp.CookieJar()
|
|
126
|
+
# self._cookie_jar = aiohttp.CookieJar()
|
|
123
127
|
self._selected_customer = ""
|
|
124
128
|
self._selected_contract = ""
|
|
125
129
|
|
|
@@ -234,16 +238,20 @@ class HydroClient:
|
|
|
234
238
|
self._logger.debug("JSON received : ", data)
|
|
235
239
|
raise HydroQcHTTPError("Bad JSON format") from exp
|
|
236
240
|
|
|
237
|
-
def get_token_data(self) -> IDTokenTyping:
|
|
241
|
+
def get_token_data(self) -> IDTokenTyping | None:
|
|
238
242
|
"""Decode id token data."""
|
|
243
|
+
if not self._id_token:
|
|
244
|
+
return None
|
|
239
245
|
raw_token_data = self._id_token.split(".")[1]
|
|
240
246
|
# In some cases padding get lost, adding it to avoid issues with base64 decode
|
|
241
247
|
raw_token_data += "=" * ((4 - len(raw_token_data) % 4) % 4)
|
|
242
248
|
token_data: IDTokenTyping = self._load_json(base64.b64decode(raw_token_data))
|
|
243
249
|
return token_data
|
|
244
250
|
|
|
245
|
-
def _get_httpsession(self) -> None:
|
|
251
|
+
async def _get_httpsession(self) -> None:
|
|
246
252
|
"""Set http session."""
|
|
253
|
+
if not hasattr(self, "_cookie_jar"):
|
|
254
|
+
self._cookie_jar = aiohttp.CookieJar()
|
|
247
255
|
if self._session is None:
|
|
248
256
|
self._logger.debug("Creating new http session")
|
|
249
257
|
self._session = aiohttp.ClientSession(
|
|
@@ -276,7 +284,7 @@ class HydroClient:
|
|
|
276
284
|
async def check_portal_status(self) -> bool:
|
|
277
285
|
"""Check if Hydro Quebec portal is UP."""
|
|
278
286
|
# Get http session
|
|
279
|
-
self._get_httpsession()
|
|
287
|
+
await self._get_httpsession()
|
|
280
288
|
self._logger.info("Checking if the Hydro Quebec portal is UP")
|
|
281
289
|
api_call_response = await self.http_request(
|
|
282
290
|
IS_HYDRO_PORTAL_UP_URL,
|
|
@@ -301,7 +309,7 @@ class HydroClient:
|
|
|
301
309
|
code_verifier, code_challenge = generate_pkce_pair()
|
|
302
310
|
|
|
303
311
|
# Get http session
|
|
304
|
-
self._get_httpsession()
|
|
312
|
+
await self._get_httpsession()
|
|
305
313
|
|
|
306
314
|
url = f"{AUTHORIZE_URL}"
|
|
307
315
|
headers = {
|
|
@@ -912,3 +920,27 @@ class HydroClient:
|
|
|
912
920
|
return content
|
|
913
921
|
data_csv: Iterator[Any] = csv.reader(content, delimiter=";")
|
|
914
922
|
return data_csv
|
|
923
|
+
|
|
924
|
+
@CCached(ttl=300)
|
|
925
|
+
async def get_open_data_peaks(
|
|
926
|
+
self,
|
|
927
|
+
offer: OpenDataPeakEventOffer | None = None,
|
|
928
|
+
) -> list[OpenDataPeakEvent]:
|
|
929
|
+
"""Get the list of peak event from open data url."""
|
|
930
|
+
await self._get_httpsession()
|
|
931
|
+
res = await self.http_request(OPEN_DATA_PEAK_URL, "get")
|
|
932
|
+
content = await res.text()
|
|
933
|
+
try:
|
|
934
|
+
raw_res_json = json.loads(content)
|
|
935
|
+
except json.JSONDecodeError:
|
|
936
|
+
# Try to clean up json removing comments
|
|
937
|
+
cleaned_json = ""
|
|
938
|
+
res_text = await res.text()
|
|
939
|
+
for line in res_text.splitlines():
|
|
940
|
+
if not line.startswith("/") and not line.startswith("#"):
|
|
941
|
+
cleaned_json += line
|
|
942
|
+
raw_res_json = json.loads(cleaned_json)
|
|
943
|
+
res_json = cast(list[OpenDataPeakEvent], raw_res_json.get("evenements", []))
|
|
944
|
+
if not offer:
|
|
945
|
+
return res_json
|
|
946
|
+
return [e for e in res_json if e["offre"] == offer]
|
{hydro_quebec_api_wrapper-3.2.0 → hydro_quebec_api_wrapper-4.0.0}/hydroqc/hydro_api/consts.py
RENAMED
|
@@ -15,6 +15,7 @@ HOST_SERVICES = "https://services-cl.solutions.hydroquebec.com"
|
|
|
15
15
|
# HOST_SPRING = "https://cl-ec-lsw.solutions.hydroquebec.com"
|
|
16
16
|
HOST_RB_SOL = "https://rb.solutions.hydroquebec.com"
|
|
17
17
|
HOST_OUTAGES = "https://services-bs.solutions.hydroquebec.com"
|
|
18
|
+
HOST_OPEN_DATA = "https://donnees.solutions.hydroquebec.com"
|
|
18
19
|
|
|
19
20
|
# Azure B2C
|
|
20
21
|
AZB2C_TENANT_ID = "32bf9b91-0a36-4385-b231-d9a8fa3b05ab"
|
|
@@ -47,6 +48,11 @@ SECURITY_URL = f"{HOST_SESSION}/config/security.json"
|
|
|
47
48
|
SESSION_REFRESH_URL = f"{HOST_SESSION}/oauth2/callback/silent-refresh"
|
|
48
49
|
LOGIN_URL_6 = f"{HOST_SERVICES}/wsapi/web/prive/api/v3_0/conversion/codeAcces"
|
|
49
50
|
|
|
51
|
+
# OPEN DATA PEAK URL
|
|
52
|
+
OPEN_DATA_PEAK_URL = (
|
|
53
|
+
f"{HOST_OPEN_DATA}/donnees-ouvertes/data/json/pointeshivernales.json"
|
|
54
|
+
)
|
|
55
|
+
|
|
50
56
|
# Initialization uri
|
|
51
57
|
RELATION_URL = f"{HOST_SERVICES}/wsapi/web/prive/api/v1_0/relations"
|
|
52
58
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Base Peak module."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
|
|
5
|
+
from hydroqc.error import HydroQcCPCPeakError
|
|
6
|
+
from hydroqc.timerange import TimeRange
|
|
7
|
+
from hydroqc.utils import EST_TIMEZONE
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BasePeak(TimeRange):
|
|
11
|
+
"""Base peak class."""
|
|
12
|
+
|
|
13
|
+
_start_date: datetime.datetime
|
|
14
|
+
_end_date: datetime.datetime
|
|
15
|
+
|
|
16
|
+
def __init__(self, start_date: datetime.datetime, end_date: datetime.datetime):
|
|
17
|
+
"""Build base peak."""
|
|
18
|
+
if not start_date.tzinfo:
|
|
19
|
+
self._start_date = start_date.astimezone(EST_TIMEZONE)
|
|
20
|
+
else:
|
|
21
|
+
self._start_date = start_date
|
|
22
|
+
if not end_date.tzinfo:
|
|
23
|
+
self._end_date = end_date.astimezone(EST_TIMEZONE)
|
|
24
|
+
else:
|
|
25
|
+
self._end_date = end_date
|
|
26
|
+
|
|
27
|
+
super().__init__(self.start_date, self.end_date, is_critical=False)
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def is_morning(self) -> bool:
|
|
31
|
+
"""Return True if it's a morning peak."""
|
|
32
|
+
return self._start_date.hour < 12
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def is_evening(self) -> bool:
|
|
36
|
+
"""Return True if it's a evening peak."""
|
|
37
|
+
return self._start_date.hour > 12
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def day(self) -> datetime.date:
|
|
41
|
+
"""Get the day, without time, of the peak."""
|
|
42
|
+
return self._start_date.date()
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def date(self) -> datetime.date:
|
|
46
|
+
"""DEPRECATED - Get the day, without time, of the peak."""
|
|
47
|
+
return self.day
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def start_date(self) -> datetime.datetime:
|
|
51
|
+
"""Get the start date of the peak."""
|
|
52
|
+
return self._start_date
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def end_date(self) -> datetime.datetime:
|
|
56
|
+
"""Get the end date of the peak."""
|
|
57
|
+
return self._end_date
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def morning_evening(self) -> str:
|
|
61
|
+
"""Return evening or morning peak value."""
|
|
62
|
+
if self.is_morning:
|
|
63
|
+
return "morning"
|
|
64
|
+
if self.is_evening:
|
|
65
|
+
return "evening"
|
|
66
|
+
msg = "Can not determine if is morning or evening peak"
|
|
67
|
+
raise HydroQcCPCPeakError(msg)
|