myelectricaldatapy 2.2.6__tar.gz → 2.2.7__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.
Files changed (45) hide show
  1. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/PKG-INFO +1 -1
  2. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/myelectricaldata.py +1 -9
  3. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/mypdl.py +7 -1
  4. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/PKG-INFO +1 -1
  5. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/scm_version.json +2 -2
  6. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/test_load_data.py +28 -0
  7. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.devcontainer/devcontainer-lock.json +0 -0
  8. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.devcontainer/devcontainer.json +0 -0
  9. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.github/dependabot.yml +0 -0
  10. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.github/workflows/auto-approve.yml +0 -0
  11. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.github/workflows/python-lint.yml +0 -0
  12. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.github/workflows/python-publish.yml +0 -0
  13. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.github/workflows/release.yml +0 -0
  14. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.gitignore +0 -0
  15. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.pre-commit-config.yaml +0 -0
  16. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/.vscode/settings.json +0 -0
  17. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/LICENSE +0 -0
  18. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/README.md +0 -0
  19. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/_secrets.yaml +0 -0
  20. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/example.py +0 -0
  21. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/__init__.py +0 -0
  22. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/analytics.py +0 -0
  23. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/auth.py +0 -0
  24. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/const.py +0 -0
  25. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/exceptions.py +0 -0
  26. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy/py.typed +0 -0
  27. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/SOURCES.txt +0 -0
  28. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/dependency_links.txt +0 -0
  29. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/requires.txt +0 -0
  30. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/scm_file_list.json +0 -0
  31. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/myelectricaldatapy.egg-info/top_level.txt +0 -0
  32. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/pyproject.toml +0 -0
  33. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/setup.cfg +0 -0
  34. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/__init__.py +0 -0
  35. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/conftest.py +0 -0
  36. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/consts.py +0 -0
  37. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/access.json +0 -0
  38. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/address.json +0 -0
  39. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/contract.json +0 -0
  40. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/daily.json +0 -0
  41. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/detail.json +0 -0
  42. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/ecowatt.json +0 -0
  43. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/invalid_access.json +0 -0
  44. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/fixtures/tempo.json +0 -0
  45. {myelectricaldatapy-2.2.6 → myelectricaldatapy-2.2.7}/tests/test_analytics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: myelectricaldatapy
3
- Version: 2.2.6
3
+ Version: 2.2.7
4
4
  Summary: Fetch Linky data from myelectricaldata.fr
5
5
  Author-email: Cyr-ius <cyr-ius@ipocus.net>
6
6
  License-Expression: GPL-3.0-or-later
@@ -28,7 +28,6 @@ class Enedis:
28
28
  self.auth = EnedisAuth(session, token, timeout)
29
29
  self.async_request = self.auth.async_request
30
30
  self.offpeaks: list[str] = []
31
- self.dt_offpeak: list[dt] = []
32
31
  self.last_access: date | None = None
33
32
 
34
33
  async def async_fetch_datas(
@@ -69,13 +68,6 @@ class Enedis:
69
68
  contract = usage_point.get("contracts", {})
70
69
  if offpeak_hours := contract.get("offpeak_hours"):
71
70
  self.offpeaks = re.findall("(?:(\\w+)-(\\w+))+", offpeak_hours)
72
- self.dt_offpeak = [
73
- ( # type: ignore
74
- dt.strptime(offpeak[0], "%HH%M"),
75
- dt.strptime(offpeak[1], "%HH%M"),
76
- )
77
- for offpeak in self.offpeaks
78
- ]
79
71
  return contract
80
72
 
81
73
  async def async_get_contracts(self, pdl: str) -> Any:
@@ -137,7 +129,7 @@ class Enedis:
137
129
  for range_time in self.offpeaks:
138
130
  starting = dt.strptime(range_time[0], "%HH%M").time()
139
131
  ending = dt.strptime(range_time[1], "%HH%M").time()
140
- if ending <= start_time > starting:
132
+ if starting < start_time <= ending:
141
133
  return True
142
134
  return False
143
135
 
@@ -182,13 +182,19 @@ class EnedisByPDL:
182
182
  start = dt.now() - timedelta(days=1095)
183
183
  end = dt.now() + timedelta(days=1)
184
184
  if force_refresh or self.last_access.date() != dt.now().date():
185
+ self.access = {}
185
186
  self.contract = {}
186
187
  self.address = {}
187
188
  self.ecowatt = {}
188
189
  self.max_power = {}
189
190
  self.has_collected = False
190
191
  try:
191
- self.access = await self._api.async_valid_access(self.pdl)
192
+ if not self.access:
193
+ # Quota is scarce (ex: 50 calls/day on Enedis API), so the
194
+ # access/quota check is only refreshed once a day (or on
195
+ # force_refresh) instead of on every update cycle.
196
+ self.access = await self._api.async_valid_access(self.pdl)
197
+
192
198
  if self.access.get("quota_reached", False):
193
199
  detail = self.access.get("information", "Quota reached")
194
200
  raise LimitReached(409, {"detail": detail})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: myelectricaldatapy
3
- Version: 2.2.6
3
+ Version: 2.2.7
4
4
  Summary: Fetch Linky data from myelectricaldata.fr
5
5
  Author-email: Cyr-ius <cyr-ius@ipocus.net>
6
6
  License-Expression: GPL-3.0-or-later
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "2.2.6",
2
+ "tag": "2.2.7",
3
3
  "distance": 0,
4
- "node": "g6f55b171aa349b3761c549bb0342eea8d5fd98e7",
4
+ "node": "g3fb21c9929da8ebafc38ec5cfef31d7ccd6ac826",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-16"
@@ -54,6 +54,34 @@ async def test_tempoday(mock_enedis: Mock) -> None: # pylint: disable=unused-ar
54
54
  assert mypdl.tempo_day == "blue"
55
55
 
56
56
 
57
+ @freeze_time("2023-03-01")
58
+ async def test_check_offpeak(mock_contract) -> None:
59
+ """Test off-peak hour detection against the real contract's schedule.
60
+
61
+ contract.json's offpeak_hours is "HC (1H30-8H00;12H30-14H00)". Patches
62
+ the HTTP layer (not async_get_contract itself) so the real parsing in
63
+ Enedis.async_get_contract runs and populates self.offpeaks.
64
+ """
65
+ with patch.object(
66
+ myelectricaldatapy.auth.EnedisAuth,
67
+ "async_request",
68
+ return_value=mock_contract,
69
+ ):
70
+ api = Enedis(token=TOKEN, session=ClientSession())
71
+ assert await api.async_has_offpeak(PDL) is True
72
+
73
+ # 03:00 falls inside the 01:30-08:00 off-peak window
74
+ assert await api.async_check_offpeak(PDL, dt(2023, 3, 1, 3, 0)) is True
75
+ # exactly on the lower bound is excluded (start, end] convention
76
+ assert await api.async_check_offpeak(PDL, dt(2023, 3, 1, 1, 30)) is False
77
+ # exactly on the upper bound is included
78
+ assert await api.async_check_offpeak(PDL, dt(2023, 3, 1, 8, 0)) is True
79
+ # standard hours, not off-peak
80
+ assert await api.async_check_offpeak(PDL, dt(2023, 3, 1, 10, 0)) is False
81
+ # second window 12:30-14:00
82
+ assert await api.async_check_offpeak(PDL, dt(2023, 3, 1, 13, 0)) is True
83
+
84
+
57
85
  async def test_valid_access(mock_enedis: Mock) -> None: # pylint: disable=unused-argument
58
86
  """Test access."""
59
87
  api = Enedis(token=TOKEN, session=ClientSession())