chellow 1712909617.0.0__py3-none-any.whl → 1712929217.0.0__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.

Potentially problematic release.


This version of chellow might be problematic. Click here for more details.

chellow/e/hh_importer.py CHANGED
@@ -8,13 +8,13 @@ import traceback
8
8
  from collections import defaultdict, deque
9
9
  from datetime import datetime as Datetime, timedelta as Timedelta
10
10
  from decimal import Decimal
11
- from io import TextIOWrapper
11
+ from io import StringIO, TextIOWrapper
12
+ from pathlib import Path
12
13
 
13
14
  import jinja2
14
15
 
15
- import paramiko
16
+ from paramiko import AutoAddPolicy, RSAKey, SFTPError, SSHClient
16
17
 
17
- import pysftp
18
18
 
19
19
  import requests
20
20
 
@@ -174,7 +174,7 @@ class HhImportTask(threading.Thread):
174
174
  self.log(f"Problem {e}")
175
175
  sess.rollback()
176
176
  self.is_error = True
177
- except Exception:
177
+ except BaseException:
178
178
  self.log(f"Unknown Exception {traceback.format_exc()}")
179
179
  sess.rollback()
180
180
  self.is_error = True
@@ -231,19 +231,19 @@ class HhImportTask(threading.Thread):
231
231
  fl = None
232
232
 
233
233
  for directory in directories:
234
- self.log("Checking the directory '" + directory + "'.")
234
+ self.log(f"Checking the directory '{directory}'.")
235
235
  try:
236
236
  last_import_key = last_import_keys[directory]
237
237
  except KeyError:
238
238
  last_import_key = last_import_keys[directory] = ""
239
239
 
240
240
  dir_path = home_path + "/" + directory
241
- ftp.cwd(dir_path)
241
+ ftp.chdir(dir_path)
242
242
  files = []
243
- for fname in ftp.nlst():
243
+ for fname in ftp.listdir():
244
244
  fpath = dir_path + "/" + fname
245
245
  try:
246
- ftp.cwd(fpath)
246
+ ftp.chdir(fpath)
247
247
  continue # directory
248
248
  except ftplib.error_perm:
249
249
  pass
@@ -266,7 +266,7 @@ class HhImportTask(threading.Thread):
266
266
  key, fpath = fl
267
267
  self.log(f"Attempting to download {fpath} with key {key}.")
268
268
  f = tempfile.TemporaryFile()
269
- ftp.retrbinary("RETR " + fpath, f.write)
269
+ ftp.retrbinary(f"RETR {fpath}", f.write)
270
270
  self.log("File downloaded successfully.")
271
271
  ftp.quit()
272
272
  self.log("Logged out.")
@@ -290,25 +290,30 @@ class HhImportTask(threading.Thread):
290
290
  contract = Contract.get_dc_by_id(sess, self.contract_id)
291
291
  contract.update_state(state)
292
292
  sess.commit()
293
- self.log("Finished loading '" + fpath)
293
+ self.log(f"Finished loading '{fpath}'")
294
294
  return True
295
295
 
296
296
  def sftp_handler(self, sess, properties, contract):
297
- host_name = properties["hostname"]
298
- user_name = properties["username"]
299
- password = properties["password"]
300
- try:
301
- port = properties["port"]
302
- except KeyError:
303
- port = None
297
+ hostname = properties["hostname"]
298
+ username = properties["username"]
299
+ password = properties.get("password")
300
+ private_key = properties.get("private_key")
301
+ pkey = None
302
+ if private_key is not None:
303
+ pkf = StringIO.StringIO(private_key)
304
+ pkf.seek(0)
305
+ pkey = RSAKey.from_private_key(pkf)
306
+
307
+ port = properties.get("port", 22)
304
308
  file_type = properties["file_type"]
305
309
  directories = properties["directories"]
310
+ known_hosts = properties["known_hosts"].strip()
306
311
  state = contract.make_state()
307
312
 
308
313
  try:
309
314
  last_import_keys = state["last_import_keys"]
310
315
  except KeyError:
311
- last_import_keys = state["last_import_keys"] = []
316
+ last_import_keys = state["last_import_keys"] = {}
312
317
 
313
318
  ct_now = ct_datetime_now()
314
319
  try:
@@ -323,36 +328,60 @@ class HhImportTask(threading.Thread):
323
328
  latest_imports = state["latest_imports"] = []
324
329
 
325
330
  sess.rollback()
326
- self.log(f"Connecting to sftp server at {host_name}:{port}.")
327
- cnopts = pysftp.CnOpts()
328
- cnopts.hostkeys = None
329
- ftp = pysftp.Connection(
330
- host_name, username=user_name, password=password, cnopts=cnopts
331
+ self.log(f"Connecting to sftp server at {hostname}:{port}.")
332
+
333
+ client = SSHClient()
334
+ client.set_missing_host_key_policy(AutoAddPolicy)
335
+
336
+ client.connect(
337
+ hostname,
338
+ port=port,
339
+ username=username,
340
+ password=password,
341
+ pkey=pkey,
342
+ key_filename=None,
343
+ timeout=120,
344
+ banner_timeout=120,
345
+ auth_timeout=120,
346
+ channel_timeout=120,
347
+ look_for_keys=False,
331
348
  )
332
- ftp.timeout = 120
333
- home_path = ftp.pwd
349
+ host_keys = client.get_host_keys()
350
+ with tempfile.TemporaryDirectory() as tempdir:
351
+ td = Path(tempdir)
352
+ hfname = td / "hosts"
353
+ host_keys.save(hfname)
354
+ with hfname.open() as hf:
355
+ host_keys_str = hf.read().strip()
356
+
357
+ if host_keys_str != known_hosts:
358
+ raise BadRequest(
359
+ f"The returned host keys {host_keys_str} don't match the known "
360
+ f"hosts {known_hosts} property"
361
+ )
362
+
363
+ ftp = client.open_sftp()
334
364
 
335
365
  f = None
336
366
 
337
367
  for directory in directories:
338
- self.log("Checking the directory '" + directory + "'.")
368
+ self.log(f"Checking the directory '{directory}'.")
339
369
  try:
340
370
  last_import_key = last_import_keys[directory]
341
371
  except KeyError:
342
372
  last_import_key = last_import_keys[directory] = ""
343
373
 
344
- dir_path = home_path + "/" + directory
345
- ftp.cwd(dir_path)
374
+ ftp.chdir(directory)
346
375
  files = []
347
376
  for attr in ftp.listdir_attr():
348
- fpath = dir_path + "/" + attr.filename
377
+ fpath = f"{directory}/{attr.filename}"
349
378
  try:
350
- ftp.cwd(fpath)
379
+ ftp.chdir(fpath)
351
380
  continue # directory
352
- except paramiko.SFTPError:
381
+ except SFTPError:
353
382
  pass
354
383
 
355
- key = str(attr.st_mtime) + "_" + attr.filename
384
+ key = f"{attr.st_mtime}_{attr.filename}"
356
385
  if key > last_import_key:
357
386
  files.append((key, fpath))
358
387
 
@@ -364,6 +393,7 @@ class HhImportTask(threading.Thread):
364
393
  if f is None:
365
394
  self.log("No new files found.")
366
395
  ftp.close()
396
+ client.close()
367
397
  self.log("Logged out.")
368
398
  return False
369
399
  else:
chellow/e/views.py CHANGED
@@ -1093,13 +1093,28 @@ def dc_contract_properties_edit_get(dc_contract_id):
1093
1093
  return render_template("dc_contract_properties_edit.html", dc_contract=dc_contract)
1094
1094
 
1095
1095
 
1096
- @e.route("/dc_contracts/<int:contract_id>/properties/edit", methods=["POST"])
1097
- def dc_contract_properties_edit_post(contract_id):
1098
- contract = Contract.get_dc_by_id(g.sess, contract_id)
1099
- properties = req_zish("properties")
1100
- contract.update(contract.name, contract.party, contract.charge_script, properties)
1101
- g.sess.commit()
1102
- return chellow_redirect(f"/dc_contracts/{contract.id}/properties", 303)
1096
+ @e.route("/dc_contracts/<int:dc_contract_id>/properties/edit", methods=["POST"])
1097
+ def dc_contract_properties_edit_post(dc_contract_id):
1098
+ dc_contract = None
1099
+ try:
1100
+ dc_contract = Contract.get_dc_by_id(g.sess, dc_contract_id)
1101
+ properties = req_zish("properties")
1102
+ dc_contract.update(
1103
+ dc_contract.name, dc_contract.party, dc_contract.charge_script, properties
1104
+ )
1105
+ g.sess.commit()
1106
+ return chellow_redirect(f"/dc_contracts/{dc_contract.id}/properties", 303)
1107
+ except BadRequest as e:
1108
+ flash(e.description)
1109
+ if dc_contract is None:
1110
+ raise e
1111
+ else:
1112
+ return make_response(
1113
+ render_template(
1114
+ "dc_contract_properties_edit.html", dc_contract=dc_contract
1115
+ ),
1116
+ 400,
1117
+ )
1103
1118
 
1104
1119
 
1105
1120
  @e.route("/dc_contracts/<int:dc_contract_id>/edit")
@@ -6,7 +6,7 @@
6
6
 
7
7
  {% block nav %}
8
8
  <a href="/e/dc_contracts">DC Contracts</a> &raquo;
9
- <a href="/e/dc_contracts/{{dc_contract.id}}">dc_contract.name</a> &raquo;
9
+ <a href="/e/dc_contracts/{{dc_contract.id}}">{{dc_contract.name}}</a> &raquo;
10
10
  Properties [<a href="/e/dc_contracts/{{dc_contract.id}}/properties/edit">edit</a>]
11
11
  {% endblock %}
12
12
 
@@ -18,7 +18,7 @@
18
18
  <legend>Update Properties</legend>
19
19
 
20
20
  <label>Properties</label>
21
- {{ input_textarea('properties', dc_contract.properties, 40, 80) }}
21
+ {{ input_textarea('properties', dc_contract.properties, 40, 80, show_pos=True) }}
22
22
 
23
23
  <input type="submit" value="Update">
24
24
  </fieldset>
@@ -35,10 +35,11 @@
35
35
  "file_type": ".df2",
36
36
  "hostname": "example.com",
37
37
  "username": "username",
38
- "password": "password",
39
- "directories": ["downloads1", "downloads2"]
40
- "mpan_map": { \\ Optional
41
- "99 0993 2821 985": null, \\ Ignore MPAN
38
+ "password": "password", /* Remove if using private key */
39
+ "private_key": "private_key", /* Remove if using password */
40
+ "directories": ["downloads1", "downloads2"],
41
+ "mpan_map": { /* Optional */
42
+ "99 0993 2821 985": null, /* Ignore MPAN */
42
43
  },
43
44
  }
44
45
  </pre>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: chellow
3
- Version: 1712909617.0.0
3
+ Version: 1712929217.0.0
4
4
  Summary: Web Application for checking UK energy bills.
5
5
  Project-URL: Homepage, https://github.com/WessexWater/chellow
6
6
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -11,13 +11,13 @@ Requires-Dist: flask-restx==1.2.0
11
11
  Requires-Dist: flask==2.3.3
12
12
  Requires-Dist: odio==0.0.22
13
13
  Requires-Dist: openpyxl==3.1.2
14
+ Requires-Dist: paramiko==3.4.0
14
15
  Requires-Dist: pep3143daemon==0.0.6
15
16
  Requires-Dist: pg8000==1.31.1
16
17
  Requires-Dist: pip>=9.0.1
17
18
  Requires-Dist: psutil==5.9.5
18
19
  Requires-Dist: pympler==1.0.1
19
20
  Requires-Dist: pypdf==3.17.0
20
- Requires-Dist: pysftp==0.2.9
21
21
  Requires-Dist: python-dateutil==2.8.2
22
22
  Requires-Dist: pytz==2022.6
23
23
  Requires-Dist: requests==2.31.0
@@ -24,7 +24,7 @@ chellow/e/dno_rate_parser.py,sha256=5MYEbcYngh7n6Szn2h9zLTwQKXH-WHKy6c80PYwNLLQ,
24
24
  chellow/e/duos.py,sha256=ISTcNqe9KNjVNM2Qs8IBoQxnmSXOt5W_G7tZxp4T78M,28870
25
25
  chellow/e/elexon.py,sha256=ALhXS9Es7PV0z9ukPbIramn3cf3iLyFi-PMWPSm5iOs,5487
26
26
  chellow/e/energy_management.py,sha256=aXC2qlGt3FAODlNl_frWzVYAQrJLP8FFOiNX3m-QE_Y,12388
27
- chellow/e/hh_importer.py,sha256=nhmlWDNBm8U4salBud8ivdaDGF1lkY82NqQCrGuPYRI,20483
27
+ chellow/e/hh_importer.py,sha256=QBKdnT3Z4A6fsGqODE9bBGVdWde6Hu8OJfkXVhShQz0,21485
28
28
  chellow/e/hh_parser_bg_csv.py,sha256=W5SU2MSpa8BGA0VJw1JXF-IwbCNLFy8fe35yxLZ7gEw,2453
29
29
  chellow/e/hh_parser_df2.py,sha256=ynNNRMpLm9qs23tJjfm0vGSaAduXfPMw_7-WfQHXliQ,4209
30
30
  chellow/e/hh_parser_simple_csv.py,sha256=RN4QOLvTQeoPrpvXvQ9hkOBZnR5piybLfjCiSJdjpjs,2112
@@ -38,7 +38,7 @@ chellow/e/system_price.py,sha256=3cPWohHmmBI9v7fENLBzXQkpAeC3r0s5xV29Nmr6k_E,583
38
38
  chellow/e/tlms.py,sha256=kHAy2A2d1Mma7x4GdNDyrzscJd5DpJtDBYiZEg241Dw,8538
39
39
  chellow/e/tnuos.py,sha256=KoMPJDIXfE4zwhSDuywGF1ooxjTYLVjtF7BkSFm6X24,4158
40
40
  chellow/e/triad.py,sha256=S6LEMHvUKhAZe0-yfLIRciYDZ8IKMn1jh1TmmsbQD3s,13588
41
- chellow/e/views.py,sha256=EdNlMI-cutMhWiog_PUBOW1jWu-u4MLOCHxv1uyIGVQ,213550
41
+ chellow/e/views.py,sha256=8Rmm6XuNGXACFSSX_LpomyTC4oS2-nljRlisjEyUVJ4,213975
42
42
  chellow/e/bill_parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  chellow/e/bill_parsers/activity_mop_stark_xlsx.py,sha256=UgWXDPzQkQghyj_lfgBqoSJpHB-t-qOdSaB8qY6GLog,4071
44
44
  chellow/e/bill_parsers/annual_mop_stark_xlsx.py,sha256=-HMoIfa_utXYKA44RuC0Xqv3vd2HLeQU_4P0iBUd3WA,4219
@@ -187,8 +187,8 @@ chellow/templates/e/dc_contract.html,sha256=b6DLDrGdzN9Rri56pFvfpE7QZKYXGHib2veY
187
187
  chellow/templates/e/dc_contract_edit.html,sha256=YraU0_MTBjmzBCMdsuvtIYm7K58hnDly5wUZ-6n8XzY,2148
188
188
  chellow/templates/e/dc_contract_hh_import.html,sha256=UODiBFNohb60MjH1w-9JW1JE0O9GR2uKPGw-lD7Da5g,848
189
189
  chellow/templates/e/dc_contract_hh_imports.html,sha256=eXFDGyzSgag4JRism81_p5yTzQOjCIXaVkQ8tl3dDcM,8172
190
- chellow/templates/e/dc_contract_properties.html,sha256=fOHCBeAI7k9yi9vBCtaYDpYRB9zk1WuMaO1pnNCMxes,451
191
- chellow/templates/e/dc_contract_properties_edit.html,sha256=852aWHaDsIa_VZdn9sLQzjP7ynueXa0CKL4ZHaOBmmM,1585
190
+ chellow/templates/e/dc_contract_properties.html,sha256=2EmA91gYWZcTOHQ3PxXQrpTOb8dm0OGjwRWsW6qNI9s,455
191
+ chellow/templates/e/dc_contract_properties_edit.html,sha256=TGYcHTlWbk5WmjZPkdbHhRVZcOpEfhowCp2penZcGiE,1704
192
192
  chellow/templates/e/dc_contracts.html,sha256=v8czpEcMzndngfWNXIKXib6Xrz9OwJjQAmNQNrQ6Y08,1705
193
193
  chellow/templates/e/dc_contracts_add.html,sha256=2lrGrNqAoKp16OiMoNDNlJxBMW3QdSPfgEFheSg826s,710
194
194
  chellow/templates/e/dc_rate_script.html,sha256=gfKUHV2IMsTQT-cYfjl4aiEBqGEWSj3uW22UZpoyGq4,1219
@@ -363,6 +363,6 @@ chellow/templates/g/supply_note_edit.html,sha256=6UQf_qbhFDys3cVsTp-c7ABWZpggW9R
363
363
  chellow/templates/g/supply_notes.html,sha256=WR3YwGh_qqTklSJ7JqWX6BKBc9rk_jMff4RiWZiF2CM,936
364
364
  chellow/templates/g/unit.html,sha256=KouNVU0-i84afANkLQ_heJ0uDfJ9H5A05PuLqb8iCN8,438
365
365
  chellow/templates/g/units.html,sha256=p5Nd-lAIboKPEOO6N451hx1bcKxMg4BDODnZ-43MmJc,441
366
- chellow-1712909617.0.0.dist-info/METADATA,sha256=qV7hEsZpgKlO6cp3iu5A8YJhHVmh28JRt1sVz42GH64,12203
367
- chellow-1712909617.0.0.dist-info/WHEEL,sha256=as-1oFTWSeWBgyzh0O_qF439xqBe6AbBgt4MfYe5zwY,87
368
- chellow-1712909617.0.0.dist-info/RECORD,,
366
+ chellow-1712929217.0.0.dist-info/METADATA,sha256=y7dYnKInV3Z2jmy6Z1aKrqsJ-hwDU4ncat88dfZKzmo,12205
367
+ chellow-1712929217.0.0.dist-info/WHEEL,sha256=as-1oFTWSeWBgyzh0O_qF439xqBe6AbBgt4MfYe5zwY,87
368
+ chellow-1712929217.0.0.dist-info/RECORD,,