e-data 1.2.17__tar.gz → 1.2.19__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 (25) hide show
  1. {e-data-1.2.17/e_data.egg-info → e_data-1.2.19}/PKG-INFO +9 -1
  2. {e-data-1.2.17 → e_data-1.2.19/e_data.egg-info}/PKG-INFO +9 -1
  3. {e-data-1.2.17 → e_data-1.2.19}/edata/connectors/datadis.py +83 -61
  4. {e-data-1.2.17 → e_data-1.2.19}/edata/definitions.py +1 -3
  5. {e-data-1.2.17 → e_data-1.2.19}/edata/helpers.py +73 -75
  6. {e-data-1.2.17 → e_data-1.2.19}/setup.py +1 -1
  7. {e-data-1.2.17 → e_data-1.2.19}/LICENSE +0 -0
  8. {e-data-1.2.17 → e_data-1.2.19}/MANIFEST.in +0 -0
  9. {e-data-1.2.17 → e_data-1.2.19}/README.md +0 -0
  10. {e-data-1.2.17 → e_data-1.2.19}/e_data.egg-info/SOURCES.txt +0 -0
  11. {e-data-1.2.17 → e_data-1.2.19}/e_data.egg-info/dependency_links.txt +0 -0
  12. {e-data-1.2.17 → e_data-1.2.19}/e_data.egg-info/requires.txt +0 -0
  13. {e-data-1.2.17 → e_data-1.2.19}/e_data.egg-info/top_level.txt +0 -0
  14. {e-data-1.2.17 → e_data-1.2.19}/edata/__init__.py +0 -0
  15. {e-data-1.2.17 → e_data-1.2.19}/edata/connectors/__init__.py +0 -0
  16. {e-data-1.2.17 → e_data-1.2.19}/edata/connectors/redata.py +0 -0
  17. {e-data-1.2.17 → e_data-1.2.19}/edata/const.py +0 -0
  18. {e-data-1.2.17 → e_data-1.2.19}/edata/processors/__init__.py +0 -0
  19. {e-data-1.2.17 → e_data-1.2.19}/edata/processors/base.py +0 -0
  20. {e-data-1.2.17 → e_data-1.2.19}/edata/processors/billing.py +0 -0
  21. {e-data-1.2.17 → e_data-1.2.19}/edata/processors/consumption.py +0 -0
  22. {e-data-1.2.17 → e_data-1.2.19}/edata/processors/maximeter.py +0 -0
  23. {e-data-1.2.17 → e_data-1.2.19}/edata/processors/utils.py +0 -0
  24. {e-data-1.2.17 → e_data-1.2.19}/edata/storage.py +0 -0
  25. {e-data-1.2.17 → e_data-1.2.19}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: e-data
3
- Version: 1.2.17
3
+ Version: 1.2.19
4
4
  Summary: Python library for managing spanish energy data from various web providers
5
5
  Home-page: https://github.com/uvejota/python-edata
6
6
  Author: VMG
@@ -18,6 +18,14 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
18
18
  Requires-Python: >=3.6.0
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
+ Requires-Dist: dateparser>=1.1.2
22
+ Requires-Dist: freezegun>=1.2.1
23
+ Requires-Dist: holidays>=0.14.2
24
+ Requires-Dist: pytest>=7.1.2
25
+ Requires-Dist: python_dateutil>=2.8.2
26
+ Requires-Dist: requests>=2.28.1
27
+ Requires-Dist: voluptuous>=0.13.1
28
+ Requires-Dist: Jinja2>=3.1.2
21
29
 
22
30
 
23
31
  [![Downloads](https://pepy.tech/badge/e-data)](https://pepy.tech/project/e-data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: e-data
3
- Version: 1.2.17
3
+ Version: 1.2.19
4
4
  Summary: Python library for managing spanish energy data from various web providers
5
5
  Home-page: https://github.com/uvejota/python-edata
6
6
  Author: VMG
@@ -18,6 +18,14 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
18
18
  Requires-Python: >=3.6.0
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
+ Requires-Dist: dateparser>=1.1.2
22
+ Requires-Dist: freezegun>=1.2.1
23
+ Requires-Dist: holidays>=0.14.2
24
+ Requires-Dist: pytest>=7.1.2
25
+ Requires-Dist: python_dateutil>=2.8.2
26
+ Requires-Dist: requests>=2.28.1
27
+ Requires-Dist: voluptuous>=0.13.1
28
+ Requires-Dist: Jinja2>=3.1.2
21
29
 
22
30
 
23
31
  [![Downloads](https://pepy.tech/badge/e-data)](https://pepy.tech/project/e-data)
@@ -4,17 +4,17 @@ To fetch data from datadis.es private API.
4
4
  There a few issues that are workarounded:
5
5
  - You have to wait 24h between two identical requests.
6
6
  - Datadis server does not like ranges greater than 1 month.
7
- - TODO: gzip header checksum errors under weird circumstances
8
7
  """
9
8
 
10
9
  import contextlib
10
+ from datetime import datetime, timedelta
11
11
  import hashlib
12
12
  import json
13
13
  import logging
14
- from datetime import datetime, timedelta
15
14
  import os
16
- from dateutil.relativedelta import relativedelta
17
15
 
16
+ from dateutil.relativedelta import relativedelta
17
+ from filelock import FileLock
18
18
  import requests
19
19
 
20
20
  from ..definitions import ConsumptionData, ContractData, MaxPowerData, SupplyData
@@ -104,50 +104,60 @@ class DatadisConnector:
104
104
  self._recent_queries_file = DEFAULT_RECENT_QUERIES_FILE
105
105
  self._recent_queries_cache_file = DEFAULT_RECENT_QUERIES_CACHE
106
106
  self._warned_queries = []
107
+ self._load_recent_cache()
108
+
109
+ def _load_recent_cache(self) -> None:
110
+ """Load caches."""
107
111
 
108
- # load caches (to avoid query spam if the program restarts)
109
112
  with contextlib.suppress(FileNotFoundError):
110
113
  with open(self._recent_queries_file, encoding="utf8") as dst_file:
111
- self._recent_queries = json.load(dst_file)
112
- for query in self._recent_queries:
113
- self._recent_queries[query] = datetime.fromisoformat(
114
- self._recent_queries[query]
114
+ recent_queries = json.load(dst_file)
115
+ for query in recent_queries:
116
+ recent_queries[query] = datetime.fromisoformat(
117
+ recent_queries[query]
115
118
  )
119
+ self._recent_queries.update(recent_queries)
120
+
116
121
  with open(self._recent_queries_cache_file, encoding="utf8") as dst_file:
117
- self._recent_cache = json.load(dst_file)
122
+ self._recent_cache.update(json.load(dst_file))
118
123
 
119
124
  def _update_recent_queries(self, query: str, data: dict | None = None) -> None:
120
125
  """Cache a successful query to avoid exceeding query limits."""
121
126
 
122
- # identify the query by a md5 hash
123
- hash_query = hashlib.md5(query.encode()).hexdigest()
124
- # prepare key (hash) and values (timestamp and response)
125
- self._recent_queries[hash_query] = datetime.now()
126
- if data is not None:
127
- self._recent_cache[hash_query] = data
128
-
129
- # purge old cache
130
- to_delete = []
131
- for _query in self._recent_queries:
132
- if (datetime.now() - self._recent_queries[_query]) > QUERY_LIMIT:
133
- to_delete.append(_query)
134
-
135
- for key in to_delete:
136
- with contextlib.suppress(KeyError):
137
- self._recent_queries.pop(key, None)
138
- self._recent_cache.pop(key, None)
139
-
140
- # dump current cache to disk
141
- try:
142
- with open(self._recent_queries_file, "w", encoding="utf8") as dst_file:
143
- json.dump(utils.serialize_dict(self._recent_queries), dst_file)
127
+ with FileLock(self._recent_queries_file + ".lock"):
128
+ self._load_recent_cache()
129
+ # identify the query by a md5 hash
130
+ hash_query = hashlib.md5(query.encode()).hexdigest()
131
+ # prepare key (hash) and values (timestamp and response)
132
+ self._recent_queries[hash_query] = datetime.now()
144
133
  if data is not None:
145
- with open(
146
- self._recent_queries_cache_file, "w", encoding="utf8"
147
- ) as dst_file:
148
- json.dump(self._recent_cache, dst_file)
149
- except Exception as e:
150
- _LOGGER.warning("Unknown error while updating cache: %s", e)
134
+ self._recent_cache[hash_query] = data
135
+
136
+ # purge old cache
137
+ to_delete = [
138
+ x
139
+ for x in self._recent_queries
140
+ if (datetime.now() - self._recent_queries[x]) > QUERY_LIMIT
141
+ ]
142
+
143
+ for key in to_delete:
144
+ with contextlib.suppress(KeyError):
145
+ self._recent_queries.pop(key, None)
146
+ self._recent_cache.pop(key, None)
147
+
148
+ # dump current cache to disk
149
+ try:
150
+ with open(self._recent_queries_file, "w", encoding="utf8") as dst_file:
151
+ json.dump(utils.serialize_dict(self._recent_queries), dst_file)
152
+ if data is not None:
153
+ with open(
154
+ self._recent_queries_cache_file, "w", encoding="utf8"
155
+ ) as dst_file:
156
+ json.dump(self._recent_cache, dst_file)
157
+ _LOGGER.debug("Local cache updated")
158
+
159
+ except Exception as e:
160
+ _LOGGER.warning("Unknown error while updating cache: %s", e)
151
161
 
152
162
  def _is_recent_query(self, query: str) -> bool:
153
163
  """Check if a query has been done recently to avoid exceeding query limits."""
@@ -160,7 +170,7 @@ class DatadisConnector:
160
170
  def _get_cache_for_query(self, query: str) -> dict:
161
171
  """Return cached response for a query."""
162
172
  hash_query = hashlib.md5(query.encode()).hexdigest()
163
-
173
+ _LOGGER.info("Serving '%s' from cache", query)
164
174
  return self._recent_cache.get(hash_query, None)
165
175
 
166
176
  def _get_token(self):
@@ -243,13 +253,15 @@ class DatadisConnector:
243
253
  _LOGGER.info("Got 200 OK at %s", url + params)
244
254
  if reply.json():
245
255
  response = reply.json()
246
- self._update_recent_queries(url + params, response)
256
+ if not ignore_recent_queries:
257
+ self._update_recent_queries(url + params, response)
247
258
  else:
248
259
  # this mostly happens when datadis provides an empty response
249
260
  _LOGGER.info(
250
261
  "Datadis returned an empty response at %s", url + params
251
262
  )
252
- self._update_recent_queries(url + params)
263
+ if not ignore_recent_queries:
264
+ self._update_recent_queries(url + params)
253
265
  elif reply.status_code == 401 and not refresh_token:
254
266
  # we're here if we were unauthorized so we will refresh the token
255
267
  response = self._get(
@@ -266,7 +278,8 @@ class DatadisConnector:
266
278
  reply.text,
267
279
  url + params,
268
280
  )
269
- self._update_recent_queries(url + params)
281
+ if not ignore_recent_queries:
282
+ self._update_recent_queries(url + params)
270
283
  elif is_retry:
271
284
  # otherwise, if this was a retried request... warn the user
272
285
  if (url + params) not in self._warned_queries:
@@ -278,7 +291,8 @@ class DatadisConnector:
278
291
  "Query temporary disabled",
279
292
  "Future 500 code errors for this query will be silenced until restart",
280
293
  )
281
- self._update_recent_queries(url + params)
294
+ if not ignore_recent_queries:
295
+ self._update_recent_queries(url + params)
282
296
  self._warned_queries.append(url + params)
283
297
  else:
284
298
  # finally, retry since an unexpected error took place (mostly 500 errors - server fault)
@@ -302,7 +316,7 @@ class DatadisConnector:
302
316
 
303
317
  # Request the resource
304
318
  response = self._get(
305
- URL_GET_SUPPLIES, request_data=data, ignore_recent_queries=False
319
+ URL_GET_SUPPLIES, request_data=data, ignore_recent_queries=True
306
320
  )
307
321
 
308
322
  # Response is a list of serialized supplies.
@@ -318,23 +332,27 @@ class DatadisConnector:
318
332
  SupplyData(
319
333
  cups=i["cups"], # the supply identifier
320
334
  date_start=datetime.strptime(
321
- i["validDateFrom"]
322
- if i["validDateFrom"] != ""
323
- else "1970/01/01",
335
+ (
336
+ i["validDateFrom"]
337
+ if i["validDateFrom"] != ""
338
+ else "1970/01/01"
339
+ ),
324
340
  "%Y/%m/%d",
325
341
  ), # start date of the supply. 1970/01/01 if unset.
326
342
  date_end=datetime.strptime(
327
- i["validDateTo"]
328
- if i["validDateTo"] != ""
329
- else tomorrow_str,
343
+ (
344
+ i["validDateTo"]
345
+ if i["validDateTo"] != ""
346
+ else tomorrow_str
347
+ ),
330
348
  "%Y/%m/%d",
331
349
  ), # end date of the supply, tomorrow if unset
332
350
  # the following parameters are not crucial, so they can be none
333
- address=i["address"] if "address" in i else None,
334
- postal_code=i["postalCode"] if "postalCode" in i else None,
335
- province=i["province"] if "province" in i else None,
336
- municipality=i["municipality"] if "municipality" in i else None,
337
- distributor=i["distributor"] if "distributor" in i else None,
351
+ address=i.get("address", None),
352
+ postal_code=i.get("postalCode", None),
353
+ province=i.get("province", None),
354
+ municipality=i.get("municipality", None),
355
+ distributor=i.get("distributor", None),
338
356
  # these two are mandatory, we will use them to fetch contracts data
339
357
  pointType=i["pointType"],
340
358
  distributorCode=i["distributorCode"],
@@ -355,7 +373,7 @@ class DatadisConnector:
355
373
  if authorized_nif is not None:
356
374
  data["authorizedNif"] = authorized_nif
357
375
  response = self._get(
358
- URL_GET_CONTRACT_DETAIL, request_data=data, ignore_recent_queries=False
376
+ URL_GET_CONTRACT_DETAIL, request_data=data, ignore_recent_queries=True
359
377
  )
360
378
  contracts = []
361
379
  tomorrow_str = (datetime.today() + timedelta(days=1)).strftime("%Y/%m/%d")
@@ -373,12 +391,16 @@ class DatadisConnector:
373
391
  ),
374
392
  marketer=i["marketer"],
375
393
  distributorCode=distributor_code,
376
- power_p1=i["contractedPowerkW"][0]
377
- if isinstance(i["contractedPowerkW"], list)
378
- else None,
379
- power_p2=i["contractedPowerkW"][1]
380
- if (len(i["contractedPowerkW"]) > 1)
381
- else None,
394
+ power_p1=(
395
+ i["contractedPowerkW"][0]
396
+ if isinstance(i["contractedPowerkW"], list)
397
+ else None
398
+ ),
399
+ power_p2=(
400
+ i["contractedPowerkW"][1]
401
+ if (len(i["contractedPowerkW"]) > 1)
402
+ else None
403
+ ),
382
404
  )
383
405
  )
384
406
  else:
@@ -71,9 +71,7 @@ DEFAULT_BILLING_SURPLUS_FORMULA = (
71
71
 
72
72
  # Sum energy and power terms, and substract surplus until 0.
73
73
  # An alternative would be "[(energy_term + power_term - surplus_term), 0]|max + others_term"
74
- DEFAULT_BILLING_MAIN_FORMULA = (
75
- "[(energy_term - surplus_term), 0]|max + power_term + others_term"
76
- )
74
+ DEFAULT_BILLING_MAIN_FORMULA = "energy_term + power_term + others_term"
77
75
 
78
76
 
79
77
  class SupplyData(TypedDict):
@@ -22,6 +22,12 @@ from .storage import check_storage_integrity, dump_storage, load_storage
22
22
  _LOGGER = logging.getLogger(__name__)
23
23
 
24
24
 
25
+ def acups(cups):
26
+ """Print an abbreviated and anonymized CUPS."""
27
+
28
+ return cups[-5:]
29
+
30
+
25
31
  class EdataHelper:
26
32
  """Main EdataHelper class."""
27
33
 
@@ -53,7 +59,7 @@ class EdataHelper:
53
59
  self.attributes = {}
54
60
  self._storage_dir = storage_dir_path
55
61
  self._cups = cups
56
- self._scups = cups[-5:]
62
+ self._scups = acups(cups)
57
63
  self._authorized_nif = datadis_authorized_nif
58
64
  self.last_update = {x: datetime(1970, 1, 1) for x in self.data}
59
65
  self._date_from = datetime(1970, 1, 1)
@@ -74,9 +80,11 @@ class EdataHelper:
74
80
  self.datadis_api = DatadisConnector(
75
81
  datadis_username,
76
82
  datadis_password,
77
- storage_path=os.path.join(storage_dir_path, const.PROG_NAME)
78
- if storage_dir_path is not None
79
- else None,
83
+ storage_path=(
84
+ os.path.join(storage_dir_path, const.PROG_NAME)
85
+ if storage_dir_path is not None
86
+ else None
87
+ ),
80
88
  )
81
89
  self.redata_api = REDataConnector()
82
90
 
@@ -111,7 +119,7 @@ class EdataHelper:
111
119
  date_to: datetime = datetime.today(),
112
120
  incremental_update: bool = True,
113
121
  ):
114
- """Synchronous update."""
122
+ """Update synchronously."""
115
123
 
116
124
  _LOGGER.info(
117
125
  "%s: update triggered",
@@ -136,9 +144,9 @@ class EdataHelper:
136
144
  dump_storage(self._cups, self.data, self._storage_dir)
137
145
 
138
146
  def update_supplies(self):
139
- """Synchronous data update of supplies."""
147
+ """Update supplies."""
140
148
 
141
- _LOGGER.info("%s: supplies update triggered", self._scups)
149
+ _LOGGER.debug("%s: supplies update triggered", self._scups)
142
150
  if datetime.today().date() != self.last_update["supplies"].date():
143
151
  # if supplies haven't been updated today
144
152
  supplies = self.datadis_api.get_supplies(
@@ -153,9 +161,9 @@ class EdataHelper:
153
161
  _LOGGER.info("%s: supplies are already updated (skipping)", self._scups)
154
162
 
155
163
  def update_contracts(self, cups: str, distributor_code: str):
156
- """Synchronous data update of contracts."""
164
+ """Update contracts."""
157
165
 
158
- _LOGGER.info("%s: contracts update triggered", self._scups)
166
+ _LOGGER.debug("%s: contracts update triggered", self._scups)
159
167
  if datetime.today().date() != self.last_update["contracts"].date():
160
168
  # if contracts haven't been updated today
161
169
  contracts = self.datadis_api.get_contract_detail(
@@ -180,9 +188,9 @@ class EdataHelper:
180
188
  measurement_type: str,
181
189
  point_type: int,
182
190
  ):
183
- """Synchronous data update of consumptions."""
191
+ """Update consumptions."""
184
192
 
185
- _LOGGER.info("%s: consumptions update triggered", self._scups)
193
+ _LOGGER.debug("%s: consumptions update triggered", self._scups)
186
194
  if (datetime.now() - self.last_update["consumptions"]) > self.UPDATE_INTERVAL:
187
195
  consumptions = self.datadis_api.get_consumption_data(
188
196
  cups,
@@ -194,22 +202,23 @@ class EdataHelper:
194
202
  authorized_nif=self._authorized_nif,
195
203
  )
196
204
  if len(consumptions) > 0:
205
+ _LOGGER.info(
206
+ "%s: got consumptions from %s to %s",
207
+ self._scups,
208
+ consumptions[0]["datetime"].isoformat(),
209
+ consumptions[-1]["datetime"].isoformat(),
210
+ )
197
211
  self.data["consumptions"] = utils.extend_by_key(
198
212
  self.data["consumptions"], consumptions, "datetime"
199
213
  )
200
214
  self.last_update["consumptions"] = datetime.now()
201
- _LOGGER.info(
202
- "%s: consumptions update succeeded (%s new records)",
203
- self._scups,
204
- len(consumptions),
205
- )
206
215
  else:
207
216
  _LOGGER.info("%s: consumptions are already updated (skipping)", self._scups)
208
217
 
209
218
  def update_maximeter(self, cups, distributor_code, start_date, end_date):
210
- """Synchronous data update of maximeter."""
219
+ """Update maximeter."""
211
220
 
212
- _LOGGER.info("%s: maximeter update triggered", self._scups)
221
+ _LOGGER.debug("%s: maximeter update triggered", self._scups)
213
222
  if (datetime.now() - self.last_update["maximeter"]) > self.UPDATE_INTERVAL:
214
223
  maximeter = self.datadis_api.get_max_power(
215
224
  cups,
@@ -219,15 +228,14 @@ class EdataHelper:
219
228
  authorized_nif=self._authorized_nif,
220
229
  )
221
230
  if len(maximeter) > 0:
231
+ _LOGGER.info(
232
+ "%s: maximeter update succeeded",
233
+ self._scups,
234
+ )
222
235
  self.data["maximeter"] = utils.extend_by_key(
223
236
  self.data["maximeter"], maximeter, "datetime"
224
237
  )
225
238
  self.last_update["maximeter"] = datetime.now()
226
- _LOGGER.info(
227
- "%s: maximeter update succeeded (%s new records)",
228
- self._scups,
229
- len(maximeter),
230
- )
231
239
  else:
232
240
  _LOGGER.info("%s: maximeter is already updated (skipping)", self._scups)
233
241
 
@@ -237,7 +245,7 @@ class EdataHelper:
237
245
  date_from: datetime = datetime(1970, 1, 1),
238
246
  date_to: datetime = datetime.today(),
239
247
  ):
240
- """Synchronous data update."""
248
+ """Update all data from Datadis."""
241
249
 
242
250
  _LOGGER.info(
243
251
  "%s: datadis update triggered (from %s to %s)",
@@ -262,15 +270,22 @@ class EdataHelper:
262
270
  if supply is None:
263
271
  # return if specified cups seems not valid
264
272
  _LOGGER.error(
265
- "%s: CUPS not found, please check configured CUPS", self._scups
273
+ "%s: CUPS not found. Got: %s",
274
+ self._scups,
275
+ [acups(x["cups"]) for x in self.data["supplies"]],
266
276
  )
267
277
  return False
278
+ _LOGGER.info("%s: CUPS found in account", self._scups)
268
279
 
269
280
  # get some supply-related data
270
281
  supply_date_start = supply["date_start"]
271
282
  distributor_code = supply["distributorCode"]
272
283
  point_type = supply["pointType"]
273
284
 
285
+ _LOGGER.info(
286
+ "%s: CUPS start date is %s", self._scups, supply_date_start.isoformat()
287
+ )
288
+
274
289
  # update contracts to get valid periods
275
290
  self.update_contracts(cups, distributor_code)
276
291
  if len(self.data["contracts"]) == 0:
@@ -280,7 +295,7 @@ class EdataHelper:
280
295
  )
281
296
  return False
282
297
 
283
- # filter consumptions and maximeter, and look for gaps
298
+ # filter consumptions and maximeter, and log gaps
284
299
  def sort_and_filter(dt_from, dt_to):
285
300
  self.data["consumptions"], miss_cons = utils.extract_dt_ranges(
286
301
  self.data["consumptions"],
@@ -316,64 +331,47 @@ class EdataHelper:
316
331
  ),
317
332
  )
318
333
 
319
- oldest_contract = datetime.today()
320
- for contract in self.data["contracts"]:
321
- # register oldest contract
322
- if contract["date_start"] < oldest_contract:
323
- oldest_contract = contract["date_start"]
324
-
325
- # update consumptions
326
- for gap in [
327
- x
328
- for x in miss_cons
329
- if not (
330
- x["to"] < contract["date_start"] or x["from"] > contract["date_end"]
331
- )
332
- ]:
334
+ # update consumptions
335
+ for gap in miss_cons:
336
+ if not (
337
+ gap["to"] < supply["date_start"] or gap["from"] > supply["date_end"]
338
+ ):
333
339
  # fetch consumptions for each consumptions gap in valid periods
340
+ start = max([gap["from"] + timedelta(hours=1), supply["date_start"]])
341
+ end = min([gap["to"], supply["date_end"]])
342
+ _LOGGER.info(
343
+ "%s: request consumptions from %s to %s",
344
+ self._scups,
345
+ start.isoformat(),
346
+ end.isoformat(),
347
+ )
334
348
  self.update_consumptions(
335
349
  cups,
336
350
  distributor_code,
337
- max([gap["from"] + timedelta(hours=1), contract["date_start"]]),
338
- min([gap["to"], contract["date_end"]]),
351
+ start,
352
+ end,
339
353
  "0",
340
354
  point_type,
341
355
  )
342
356
 
343
- # update maximeter
344
- for gap in [
345
- x
346
- for x in miss_maxim
347
- if not (
348
- date_to < contract["date_start"] or date_from > contract["date_end"]
349
- )
350
- ]:
357
+ # update maximeter
358
+ for gap in miss_maxim:
359
+ if not (date_to < supply["date_start"] or date_from > supply["date_end"]):
351
360
  # fetch maximeter for each maximeter gap in valid periods
352
361
  start = max(
353
- [gap["from"], contract["date_start"] + relativedelta(months=1)]
362
+ [gap["from"], supply["date_start"] + relativedelta(months=1)]
354
363
  )
355
- end = min([gap["to"], contract["date_end"]])
364
+ end = min([gap["to"], supply["date_end"]])
356
365
  start = min([start, end])
366
+ _LOGGER.info(
367
+ "%s: request maximeter from %s to %s",
368
+ self._scups,
369
+ start.isoformat(),
370
+ end.isoformat(),
371
+ )
357
372
  self.update_maximeter(cups, distributor_code, start, end)
358
373
 
359
- # safe check periods in non-registered contracts
360
- if oldest_contract != supply_date_start and oldest_contract > max(
361
- [date_from, supply_date_start]
362
- ):
363
- _LOGGER.info(
364
- "%s: supplies and contract start date do not match, exploring non-registered contracts",
365
- self._scups,
366
- )
367
- start = max([supply_date_start, date_from])
368
- self.update_consumptions(
369
- cups, distributor_code, start, oldest_contract, "0", point_type
370
- )
371
- self.update_maximeter(cups, distributor_code, start, oldest_contract)
372
- miss_cons, miss_maxim = sort_and_filter(start, date_to)
373
- else:
374
- miss_cons, miss_maxim = sort_and_filter(
375
- max([date_from, oldest_contract]), date_to
376
- )
374
+ miss_cons, miss_maxim = sort_and_filter(date_from, date_to)
377
375
 
378
376
  return True
379
377
 
@@ -679,11 +677,11 @@ class EdataHelper:
679
677
  for x in self.data["consumptions"]
680
678
  if x["datetime"] >= new_data_from
681
679
  ],
682
- prices=[
683
- x for x in self.data["pvpc"] if x["datetime"] >= new_data_from
684
- ]
685
- if self.is_pvpc
686
- else None,
680
+ prices=(
681
+ [x for x in self.data["pvpc"] if x["datetime"] >= new_data_from]
682
+ if self.is_pvpc
683
+ else None
684
+ ),
687
685
  rules=self.pricing_rules,
688
686
  )
689
687
  )
@@ -20,7 +20,7 @@ URL = "https://github.com/uvejota/python-edata"
20
20
  EMAIL = "vmayorg@outlook.es"
21
21
  AUTHOR = "VMG"
22
22
  REQUIRES_PYTHON = ">=3.6.0"
23
- VERSION = "1.2.17"
23
+ VERSION = "1.2.19"
24
24
 
25
25
  # What packages are required for this module to be executed?
26
26
  REQUIRED = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes