hive-nectar 0.0.6__py3-none-any.whl → 0.0.9__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 hive-nectar might be problematic. Click here for more details.

Files changed (56) hide show
  1. {hive_nectar-0.0.6.dist-info → hive_nectar-0.0.9.dist-info}/METADATA +5 -3
  2. hive_nectar-0.0.9.dist-info/RECORD +91 -0
  3. nectar/__init__.py +1 -0
  4. nectar/account.py +44 -48
  5. nectar/amount.py +6 -11
  6. nectar/block.py +8 -9
  7. nectar/blockchain.py +4 -5
  8. nectar/blockchaininstance.py +4 -4
  9. nectar/blockchainobject.py +5 -6
  10. nectar/blurt.py +3 -4
  11. nectar/cli.py +14 -14
  12. nectar/comment.py +10 -11
  13. nectar/community.py +527 -181
  14. nectar/conveyor.py +3 -4
  15. nectar/exceptions.py +30 -24
  16. nectar/hive.py +3 -4
  17. nectar/hivesigner.py +2 -2
  18. nectar/imageuploader.py +2 -3
  19. nectar/nodelist.py +83 -7
  20. nectar/price.py +6 -13
  21. nectar/rc.py +1 -2
  22. nectar/steem.py +3 -4
  23. nectar/storage.py +3 -4
  24. nectar/transactionbuilder.py +12 -3
  25. nectar/version.py +1 -1
  26. nectar/vote.py +8 -9
  27. nectar/wallet.py +1 -1
  28. nectarapi/__init__.py +1 -0
  29. nectarapi/exceptions.py +20 -14
  30. nectarapi/version.py +1 -1
  31. nectarbase/__init__.py +1 -0
  32. nectarbase/ledgertransactions.py +2 -3
  33. nectarbase/memo.py +9 -10
  34. nectarbase/objects.py +4 -5
  35. nectarbase/operations.py +3 -7
  36. nectarbase/version.py +1 -1
  37. nectargraphenebase/__init__.py +1 -1
  38. nectargraphenebase/account.py +16 -37
  39. nectargraphenebase/base58.py +5 -8
  40. nectargraphenebase/bip32.py +5 -11
  41. nectargraphenebase/bip38.py +6 -7
  42. nectargraphenebase/ecdsasig.py +32 -37
  43. nectargraphenebase/objects.py +6 -7
  44. nectargraphenebase/operations.py +2 -0
  45. nectargraphenebase/signedtransactions.py +10 -9
  46. nectargraphenebase/types.py +9 -19
  47. nectargraphenebase/unsignedtransactions.py +21 -28
  48. nectargraphenebase/version.py +1 -1
  49. nectarstorage/__init__.py +21 -1
  50. nectarstorage/masterpassword.py +2 -3
  51. nectarstorage/sqlite.py +1 -1
  52. hive_nectar-0.0.6.dist-info/RECORD +0 -92
  53. nectargraphenebase/py23.py +0 -38
  54. {hive_nectar-0.0.6.dist-info → hive_nectar-0.0.9.dist-info}/WHEEL +0 -0
  55. {hive_nectar-0.0.6.dist-info → hive_nectar-0.0.9.dist-info}/entry_points.txt +0 -0
  56. {hive_nectar-0.0.6.dist-info → hive_nectar-0.0.9.dist-info}/licenses/LICENSE.txt +0 -0
nectar/conveyor.py CHANGED
@@ -10,7 +10,6 @@ from datetime import datetime, timezone
10
10
  import requests
11
11
 
12
12
  from nectargraphenebase.ecdsasig import sign_message
13
- from nectargraphenebase.py23 import py23_bytes
14
13
 
15
14
  from .account import Account
16
15
  from .instance import shared_blockchain_instance
@@ -64,7 +63,7 @@ class Conveyor(object):
64
63
  self.id = 0
65
64
  self.ENCODING = "utf-8"
66
65
  self.TIMEFORMAT = "%Y-%m-%dT%H:%M:%S.%f"
67
- self.K = hashlib.sha256(py23_bytes("steem_jsonrpc_auth", self.ENCODING)).digest()
66
+ self.K = hashlib.sha256(bytes("steem_jsonrpc_auth", self.ENCODING)).digest()
68
67
 
69
68
  def prehash_message(self, timestamp, account, method, params, nonce):
70
69
  """Prepare a hash for the Conveyor API request with SHA256 according
@@ -78,7 +77,7 @@ class Conveyor(object):
78
77
  :param bytes nonce: random 8 bytes
79
78
 
80
79
  """
81
- first = hashlib.sha256(py23_bytes(timestamp + account + method + params, self.ENCODING))
80
+ first = hashlib.sha256(bytes(timestamp + account + method + params, self.ENCODING))
82
81
  return self.K + first.digest() + nonce
83
82
 
84
83
  def _request(self, account, method, params, key):
@@ -91,7 +90,7 @@ class Conveyor(object):
91
90
  :param str key: Steem posting key for signing
92
91
 
93
92
  """
94
- params_bytes = py23_bytes(json.dumps(params), self.ENCODING)
93
+ params_bytes = bytes(json.dumps(params), self.ENCODING)
95
94
  params_enc = base64.b64encode(params_bytes).decode(self.ENCODING)
96
95
  timestamp = datetime.now(timezone.utc).strftime(self.TIMEFORMAT)[:-3] + "Z"
97
96
  nonce_int = random.getrandbits(64)
nectar/exceptions.py CHANGED
@@ -1,7 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
 
4
- class WalletExists(Exception):
4
+ class NectarException(Exception):
5
+ """Base exception for all Nectar-related errors"""
6
+
7
+ pass
8
+
9
+
10
+ class WalletExists(NectarException):
5
11
  """A wallet has already been created and requires a password to be
6
12
  unlocked by means of :func:`nectar.wallet.Wallet.unlock`.
7
13
  """
@@ -9,85 +15,85 @@ class WalletExists(Exception):
9
15
  pass
10
16
 
11
17
 
12
- class RPCConnectionRequired(Exception):
18
+ class RPCConnectionRequired(NectarException):
13
19
  """An RPC connection is required"""
14
20
 
15
21
  pass
16
22
 
17
23
 
18
- class InvalidMemoKeyException(Exception):
24
+ class InvalidMemoKeyException(NectarException):
19
25
  """Memo key in message is invalid"""
20
26
 
21
27
  pass
22
28
 
23
29
 
24
- class WrongMemoKey(Exception):
30
+ class WrongMemoKey(NectarException):
25
31
  """The memo provided is not equal the one on the blockchain"""
26
32
 
27
33
  pass
28
34
 
29
35
 
30
- class OfflineHasNoRPCException(Exception):
36
+ class OfflineHasNoRPCException(NectarException):
31
37
  """When in offline mode, we don't have RPC"""
32
38
 
33
39
  pass
34
40
 
35
41
 
36
- class AccountExistsException(Exception):
42
+ class AccountExistsException(NectarException):
37
43
  """The requested account already exists"""
38
44
 
39
45
  pass
40
46
 
41
47
 
42
- class AccountDoesNotExistsException(Exception):
48
+ class AccountDoesNotExistsException(NectarException):
43
49
  """The account does not exist"""
44
50
 
45
51
  pass
46
52
 
47
53
 
48
- class AssetDoesNotExistsException(Exception):
54
+ class AssetDoesNotExistsException(NectarException):
49
55
  """The asset does not exist"""
50
56
 
51
57
  pass
52
58
 
53
59
 
54
- class InvalidAssetException(Exception):
60
+ class InvalidAssetException(NectarException):
55
61
  """An invalid asset has been provided"""
56
62
 
57
63
  pass
58
64
 
59
65
 
60
- class InsufficientAuthorityError(Exception):
66
+ class InsufficientAuthorityError(NectarException):
61
67
  """The transaction requires signature of a higher authority"""
62
68
 
63
69
  pass
64
70
 
65
71
 
66
- class VotingInvalidOnArchivedPost(Exception):
72
+ class VotingInvalidOnArchivedPost(NectarException):
67
73
  """The transaction requires signature of a higher authority"""
68
74
 
69
75
  pass
70
76
 
71
77
 
72
- class MissingKeyError(Exception):
78
+ class MissingKeyError(NectarException):
73
79
  """A required key couldn't be found in the wallet"""
74
80
 
75
81
  pass
76
82
 
77
83
 
78
- class InvalidWifError(Exception):
84
+ class InvalidWifError(NectarException):
79
85
  """The provided private Key has an invalid format"""
80
86
 
81
87
  pass
82
88
 
83
89
 
84
- class BlockDoesNotExistsException(Exception):
90
+ class BlockDoesNotExistsException(NectarException):
85
91
  """The block does not exist"""
86
92
 
87
93
  pass
88
94
 
89
95
 
90
- class NoWalletException(Exception):
96
+ class NoWalletException(NectarException):
91
97
  """No Wallet could be found, please use :func:`nectar.wallet.Wallet.create` to
92
98
  create a new wallet
93
99
  """
@@ -95,55 +101,55 @@ class NoWalletException(Exception):
95
101
  pass
96
102
 
97
103
 
98
- class WitnessDoesNotExistsException(Exception):
104
+ class WitnessDoesNotExistsException(NectarException):
99
105
  """The witness does not exist"""
100
106
 
101
107
  pass
102
108
 
103
109
 
104
- class ContentDoesNotExistsException(Exception):
110
+ class ContentDoesNotExistsException(NectarException):
105
111
  """The content does not exist"""
106
112
 
107
113
  pass
108
114
 
109
115
 
110
- class VoteDoesNotExistsException(Exception):
116
+ class VoteDoesNotExistsException(NectarException):
111
117
  """The vote does not exist"""
112
118
 
113
119
  pass
114
120
 
115
121
 
116
- class WrongMasterPasswordException(Exception):
122
+ class WrongMasterPasswordException(NectarException):
117
123
  """The password provided could not properly unlock the wallet"""
118
124
 
119
125
  pass
120
126
 
121
127
 
122
- class VestingBalanceDoesNotExistsException(Exception):
128
+ class VestingBalanceDoesNotExistsException(NectarException):
123
129
  """Vesting Balance does not exist"""
124
130
 
125
131
  pass
126
132
 
127
133
 
128
- class InvalidMessageSignature(Exception):
134
+ class InvalidMessageSignature(NectarException):
129
135
  """The message signature does not fit the message"""
130
136
 
131
137
  pass
132
138
 
133
139
 
134
- class NoWriteAccess(Exception):
140
+ class NoWriteAccess(NectarException):
135
141
  """Cannot store to sqlite3 database due to missing write access"""
136
142
 
137
143
  pass
138
144
 
139
145
 
140
- class BatchedCallsNotSupported(Exception):
146
+ class BatchedCallsNotSupported(NectarException):
141
147
  """Batch calls do not work"""
142
148
 
143
149
  pass
144
150
 
145
151
 
146
- class BlockWaitTimeExceeded(Exception):
152
+ class BlockWaitTimeExceeded(NectarException):
147
153
  """Wait time for new block exceeded"""
148
154
 
149
155
  pass
nectar/hive.py CHANGED
@@ -6,7 +6,6 @@ from datetime import date, datetime, timezone
6
6
  from nectar.blockchaininstance import BlockChainInstance
7
7
  from nectar.constants import STEEM_100_PERCENT
8
8
  from nectargraphenebase.chains import known_chains
9
- from nectargraphenebase.py23 import string_types
10
9
 
11
10
  from .amount import Amount
12
11
  from .utils import formatToTimeStamp
@@ -124,7 +123,7 @@ class Hive(BlockChainInstance):
124
123
  return known_chains["HIVE"]
125
124
  try:
126
125
  return self.rpc.get_network(props=config)
127
- except:
126
+ except Exception:
128
127
  return known_chains["HIVE"]
129
128
 
130
129
  def rshares_to_token_backed_dollar(
@@ -362,7 +361,7 @@ class Hive(BlockChainInstance):
362
361
  """
363
362
  if isinstance(hbd, Amount):
364
363
  hbd = Amount(hbd, blockchain_instance=self)
365
- elif isinstance(hbd, string_types):
364
+ elif isinstance(hbd, str):
366
365
  hbd = Amount(hbd, blockchain_instance=self)
367
366
  else:
368
367
  hbd = Amount(hbd, self.hbd_symbol, blockchain_instance=self)
@@ -486,7 +485,7 @@ class Hive(BlockChainInstance):
486
485
  """
487
486
  if isinstance(hbd, Amount):
488
487
  hbd = Amount(hbd, blockchain_instance=self)
489
- elif isinstance(hbd, string_types):
488
+ elif isinstance(hbd, str):
490
489
  hbd = Amount(hbd, blockchain_instance=self)
491
490
  else:
492
491
  hbd = Amount(hbd, self.hbd_symbol, blockchain_instance=self)
nectar/hivesigner.py CHANGED
@@ -33,7 +33,7 @@ class HiveSigner(object):
33
33
  from nectar import Steem
34
34
  from nectar.HiveSigner import HiveSigner
35
35
  from nectar.comment import Comment
36
- hs = HiveSigner(client_id="nectar.app")
36
+ hs = HiveSigner(client_id="nectarflower")
37
37
  steem = Steem(HiveSigner=hs)
38
38
  steem.wallet.unlock("supersecret-passphrase")
39
39
  post = Comment("author/permlink", blockchain_instance=steem)
@@ -377,7 +377,7 @@ class HiveSigner(object):
377
377
  try:
378
378
  amount = Amount(value, blockchain_instance=self.blockchain)
379
379
  params[key] = str(amount)
380
- except:
380
+ except Exception:
381
381
  amount = None
382
382
  elif isinstance(value, bool):
383
383
  if value:
nectar/imageuploader.py CHANGED
@@ -6,7 +6,6 @@ import requests
6
6
 
7
7
  from nectar.account import Account
8
8
  from nectargraphenebase.ecdsasig import sign_message
9
- from nectargraphenebase.py23 import py23_bytes, string_types
10
9
 
11
10
  from .instance import shared_blockchain_instance
12
11
 
@@ -55,14 +54,14 @@ class ImageUploader(object):
55
54
  for authority in account["posting"]["key_auths"]:
56
55
  posting_wif = self.steem.wallet.getPrivateKeyForPublicKey(authority[0])
57
56
 
58
- if isinstance(image, string_types):
57
+ if isinstance(image, str):
59
58
  image_data = open(image, "rb").read()
60
59
  elif isinstance(image, io.BytesIO):
61
60
  image_data = image.read()
62
61
  else:
63
62
  image_data = image
64
63
 
65
- message = py23_bytes(self.challenge, "ascii") + image_data
64
+ message = bytes(self.challenge, "ascii") + image_data
66
65
  signature = sign_message(message, posting_wif)
67
66
  signature_in_hex = hexlify(signature).decode("ascii")
68
67
 
nectar/nodelist.py CHANGED
@@ -243,7 +243,12 @@ class NodeList(list):
243
243
  cnt += 1
244
244
  try:
245
245
  account = Account("nectarflower", blockchain_instance=steem)
246
- metadata = json.loads(account["posting_json_metadata"])
246
+ # Metadata is stored in the account's json_metadata field (not posting_json_metadata)
247
+ raw_meta = account.get("json_metadata") or ""
248
+ try:
249
+ metadata = json.loads(raw_meta) if raw_meta else None
250
+ except Exception:
251
+ metadata = None
247
252
  except Exception as e:
248
253
  log.warning(f"Error fetching metadata (attempt {cnt}): {str(e)}")
249
254
  steem.rpc.next()
@@ -257,10 +262,30 @@ class NodeList(list):
257
262
  report = metadata.get("report", [])
258
263
  failing_nodes = metadata.get("failing_nodes", {})
259
264
  parameter = metadata.get("parameter", {})
260
- benchmarks = parameter.get("benchmarks", {})
261
-
262
- # Convert benchmarks dict to list of benchmark names
263
- benchmark_names = list(benchmarks.keys())
265
+ benchmarks = parameter.get("benchmarks")
266
+
267
+ # Determine benchmark names. If not explicitly provided in metadata parameters, derive them
268
+ # by inspecting the keys of the report entries and filtering out the non-benchmark fields.
269
+ if benchmarks and isinstance(benchmarks, dict):
270
+ benchmark_names: list[str] = list(benchmarks.keys())
271
+ else:
272
+ benchmark_names = []
273
+ # Common non-benchmark keys present in every report entry
274
+ _skip_keys = {
275
+ "node",
276
+ "version",
277
+ "hive",
278
+ "weighted_score",
279
+ "tests_completed",
280
+ }
281
+ # Collect benchmark names dynamically from the report section
282
+ for _entry in report:
283
+ if isinstance(_entry, dict):
284
+ for _k in _entry.keys():
285
+ if _k not in _skip_keys and _k not in benchmark_names:
286
+ benchmark_names.append(_k)
287
+ # Sort for deterministic ordering
288
+ benchmark_names.sort()
264
289
 
265
290
  if weights is None:
266
291
  weights_dict = {}
@@ -294,6 +319,7 @@ class NodeList(list):
294
319
 
295
320
  for node in self:
296
321
  new_node = node.copy()
322
+ node_was_updated = False
297
323
 
298
324
  # Check against report data
299
325
  for report_node in report:
@@ -319,17 +345,67 @@ class NodeList(list):
319
345
  weighted_score = score * weights_dict.get(benchmark, 0)
320
346
  scores.append(weighted_score)
321
347
 
322
- sum_score = sum(scores)
323
- new_node["score"] = sum_score
348
+ # Prefer the pre-computed weighted_score from the metadata if present; fall back to
349
+ # the locally calculated score otherwise.
350
+ if "weighted_score" in report_node and isinstance(report_node["weighted_score"], (int, float)):
351
+ new_node["score"] = report_node["weighted_score"]
352
+ else:
353
+ sum_score = sum(scores)
354
+ new_node["score"] = sum_score
355
+ node_was_updated = True
324
356
  break
325
357
 
326
358
  # Check if node is in failing nodes list
327
359
  if node["url"] in failing_nodes:
328
360
  failing_count += 1
329
361
  new_node["score"] = -1
362
+ elif not node_was_updated:
363
+ # If node wasn't part of the metadata report, reset its score so it
364
+ # doesn't overshadow the authoritative ordering
365
+ new_node["score"] = 0
330
366
 
331
367
  new_nodes.append(new_node)
332
368
 
369
+ # ------------------------------------------------------------
370
+ # Ensure that all nodes present in the metadata are included
371
+ # in the final list, even if they were not part of the default
372
+ # hard-coded set.
373
+ # ------------------------------------------------------------
374
+ existing_urls: set[str] = {n["url"] for n in new_nodes}
375
+
376
+ # Add nodes found in the report section
377
+ for report_node in report:
378
+ url = report_node.get("node")
379
+ if not url or url in existing_urls:
380
+ continue
381
+ new_entry = {
382
+ "url": url,
383
+ "version": report_node.get("version", "0.0.0"),
384
+ "type": "appbase",
385
+ "owner": report_node.get("owner", "unknown"),
386
+ "hive": report_node.get("hive", True),
387
+ "score": report_node.get("weighted_score", 0),
388
+ }
389
+ new_nodes.append(new_entry)
390
+ existing_urls.add(url)
391
+
392
+ # Add nodes listed as failing but missing
393
+ for url in failing_nodes.keys():
394
+ if url in existing_urls:
395
+ continue
396
+ new_nodes.append(
397
+ {
398
+ "url": url,
399
+ "version": "unknown",
400
+ "type": "appbase",
401
+ "owner": "unknown",
402
+ "hive": True,
403
+ "score": -1,
404
+ }
405
+ )
406
+ existing_urls.add(url)
407
+
408
+ # Re-initialise internal list
333
409
  super(NodeList, self).__init__(new_nodes)
334
410
 
335
411
  def get_nodes(
nectar/price.py CHANGED
@@ -3,7 +3,6 @@ from decimal import Decimal
3
3
  from fractions import Fraction
4
4
 
5
5
  from nectar.instance import shared_blockchain_instance
6
- from nectargraphenebase.py23 import integer_types, string_types
7
6
 
8
7
  from .amount import Amount
9
8
  from .asset import Asset
@@ -97,7 +96,7 @@ class Price(dict):
97
96
  self.blockchain = blockchain_instance or shared_blockchain_instance()
98
97
  if price == "":
99
98
  price = None
100
- if price is not None and isinstance(price, string_types) and not base and not quote:
99
+ if price is not None and isinstance(price, str) and not base and not quote:
101
100
  price, assets = price.split(" ")
102
101
  base_symbol, quote_symbol = assets_from_string(assets)
103
102
  base = Asset(base_symbol, blockchain_instance=self.blockchain)
@@ -131,9 +130,7 @@ class Price(dict):
131
130
  amount=frac.numerator, asset=base, blockchain_instance=self.blockchain
132
131
  )
133
132
 
134
- elif (
135
- price is not None and isinstance(base, string_types) and isinstance(quote, string_types)
136
- ):
133
+ elif price is not None and isinstance(base, str) and isinstance(quote, str):
137
134
  base = Asset(base, blockchain_instance=self.blockchain)
138
135
  quote = Asset(quote, blockchain_instance=self.blockchain)
139
136
  frac = Fraction(float(price)).limit_denominator(10 ** base["precision"])
@@ -144,12 +141,10 @@ class Price(dict):
144
141
  amount=frac.numerator, asset=base, blockchain_instance=self.blockchain
145
142
  )
146
143
 
147
- elif price is None and isinstance(base, string_types) and isinstance(quote, string_types):
144
+ elif price is None and isinstance(base, str) and isinstance(quote, str):
148
145
  self["quote"] = Amount(quote, blockchain_instance=self.blockchain)
149
146
  self["base"] = Amount(base, blockchain_instance=self.blockchain)
150
- elif (
151
- price is not None and isinstance(price, string_types) and isinstance(base, string_types)
152
- ):
147
+ elif price is not None and isinstance(price, str) and isinstance(base, str):
153
148
  self["quote"] = Amount(price, blockchain_instance=self.blockchain)
154
149
  self["base"] = Amount(base, blockchain_instance=self.blockchain)
155
150
  # len(args) > 1
@@ -163,10 +158,8 @@ class Price(dict):
163
158
  self["base"] = base
164
159
 
165
160
  elif (
166
- isinstance(price, float)
167
- or isinstance(price, integer_types)
168
- or isinstance(price, Decimal)
169
- ) and isinstance(base, string_types):
161
+ isinstance(price, float) or isinstance(price, int) or isinstance(price, Decimal)
162
+ ) and isinstance(base, str):
170
163
  base_symbol, quote_symbol = assets_from_string(base)
171
164
  base = Asset(base_symbol, blockchain_instance=self.blockchain)
172
165
  quote = Asset(quote_symbol, blockchain_instance=self.blockchain)
nectar/rc.py CHANGED
@@ -9,7 +9,6 @@ from nectar.constants import (
9
9
  from nectarbase import operations
10
10
  from nectarbase.objects import Operation
11
11
  from nectarbase.signedtransactions import Signed_Transaction
12
- from nectargraphenebase.py23 import py23_bytes
13
12
 
14
13
  from .instance import shared_blockchain_instance
15
14
 
@@ -38,7 +37,7 @@ class RC(object):
38
37
  operations=ops,
39
38
  )
40
39
  tx = tx.sign([wif], chain=prefix)
41
- txWire = hexlify(py23_bytes(tx)).decode("ascii")
40
+ txWire = hexlify(bytes(tx)).decode("ascii")
42
41
  tx_size = len(txWire)
43
42
  return tx_size
44
43
 
nectar/steem.py CHANGED
@@ -6,7 +6,6 @@ from datetime import date, datetime, timezone
6
6
  from nectar.blockchaininstance import BlockChainInstance
7
7
  from nectar.constants import STEEM_100_PERCENT, STEEM_VOTE_REGENERATION_SECONDS
8
8
  from nectargraphenebase.chains import known_chains
9
- from nectargraphenebase.py23 import string_types
10
9
 
11
10
  from .amount import Amount
12
11
  from .utils import formatToTimeStamp
@@ -124,7 +123,7 @@ class Steem(BlockChainInstance):
124
123
  return known_chains["STEEM"]
125
124
  try:
126
125
  return self.rpc.get_network(props=config)
127
- except:
126
+ except Exception:
128
127
  return known_chains["STEEM"]
129
128
 
130
129
  def rshares_to_token_backed_dollar(
@@ -393,7 +392,7 @@ class Steem(BlockChainInstance):
393
392
  """
394
393
  if isinstance(sbd, Amount):
395
394
  sbd = Amount(sbd, blockchain_instance=self)
396
- elif isinstance(sbd, string_types):
395
+ elif isinstance(sbd, str):
397
396
  sbd = Amount(sbd, blockchain_instance=self)
398
397
  else:
399
398
  sbd = Amount(sbd, self.sbd_symbol, blockchain_instance=self)
@@ -517,7 +516,7 @@ class Steem(BlockChainInstance):
517
516
  """
518
517
  if isinstance(sbd, Amount):
519
518
  sbd = Amount(sbd, blockchain_instance=self)
520
- elif isinstance(sbd, string_types):
519
+ elif isinstance(sbd, str):
521
520
  sbd = Amount(sbd, blockchain_instance=self)
522
521
  else:
523
522
  sbd = Amount(sbd, self.sbd_symbol, blockchain_instance=self)
nectar/storage.py CHANGED
@@ -1,15 +1,14 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import logging
3
3
 
4
+ from nectarstorage import SqliteConfigurationStore, SqliteEncryptedKeyStore
5
+
4
6
  from .nodelist import NodeList
5
7
 
6
8
  log = logging.getLogger(__name__)
7
9
  log.setLevel(logging.DEBUG)
8
10
  log.addHandler(logging.StreamHandler())
9
- from nectarstorage import (
10
- SqliteConfigurationStore,
11
- SqliteEncryptedKeyStore,
12
- )
11
+
13
12
 
14
13
  timeformat = "%Y%m%d-%H%M%S"
15
14
 
@@ -279,7 +279,7 @@ class TransactionBuilder(dict):
279
279
  try:
280
280
  PrivateKey(wif, prefix=self.blockchain.prefix)
281
281
  self.wifs.add(wif)
282
- except:
282
+ except Exception:
283
283
  raise InvalidWifError
284
284
 
285
285
  def clearWifs(self):
@@ -427,7 +427,7 @@ class TransactionBuilder(dict):
427
427
  # try:
428
428
  # ledgertx = Ledger_Transaction(**self.json(with_prefix=True))
429
429
  # ledgertx.add_custom_chains(self.blockchain.custom_chains)
430
- # except:
430
+ # except Exception:
431
431
  # raise ValueError("Invalid TransactionBuilder Format")
432
432
  # ledgertx.sign(self.path, chain=self.blockchain.chain_params)
433
433
  self.ledgertx.sign(self.path, chain=self.blockchain.chain_params)
@@ -438,7 +438,16 @@ class TransactionBuilder(dict):
438
438
  raise MissingKeyError
439
439
 
440
440
  self.tx.sign(self.wifs, chain=self.blockchain.chain_params)
441
- self["signatures"].extend(self.tx.json().get("signatures"))
441
+ # Defensive: ensure self["signatures"] is a list before extend
442
+ if isinstance(self["signatures"], str):
443
+ log.warning(
444
+ "self['signatures'] was a string, converting to list to avoid AttributeError."
445
+ )
446
+ self["signatures"] = [self["signatures"]]
447
+ sigs = self.tx.json().get("signatures")
448
+ if isinstance(sigs, str):
449
+ sigs = [sigs]
450
+ self["signatures"].extend(sigs)
442
451
  return self.tx
443
452
 
444
453
  def verify_authority(self):
nectar/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """THIS FILE IS GENERATED FROM nectar PYPROJECT.TOML."""
2
2
 
3
- version = "0.0.6"
3
+ version = "0.0.9"
nectar/vote.py CHANGED
@@ -5,7 +5,6 @@ from datetime import date, datetime, timezone
5
5
  from prettytable import PrettyTable
6
6
 
7
7
  from nectarapi.exceptions import InvalidParameters, UnknownKey
8
- from nectargraphenebase.py23 import integer_types, string_types
9
8
 
10
9
  from .account import Account
11
10
  from .blockchainobject import BlockchainObject
@@ -42,7 +41,7 @@ class Vote(BlockchainObject):
42
41
  elif kwargs.get("hive_instance"):
43
42
  blockchain_instance = kwargs["hive_instance"]
44
43
  self.blockchain = blockchain_instance or shared_blockchain_instance()
45
- if isinstance(voter, string_types) and authorperm is not None:
44
+ if isinstance(voter, str) and authorperm is not None:
46
45
  [author, permlink] = resolve_authorperm(authorperm)
47
46
  self["voter"] = voter
48
47
  self["author"] = author
@@ -138,20 +137,20 @@ class Vote(BlockchainObject):
138
137
  "reputation",
139
138
  ]
140
139
  for p in parse_int:
141
- if p in vote and isinstance(vote.get(p), string_types):
140
+ if p in vote and isinstance(vote.get(p), str):
142
141
  vote[p] = int(vote.get(p, "0"))
143
142
 
144
- if "time" in vote and isinstance(vote.get("time"), string_types) and vote.get("time") != "":
143
+ if "time" in vote and isinstance(vote.get("time"), str) and vote.get("time") != "":
145
144
  vote["time"] = formatTimeString(vote.get("time", "1970-01-01T00:00:00"))
146
145
  elif (
147
146
  "timestamp" in vote
148
- and isinstance(vote.get("timestamp"), string_types)
147
+ and isinstance(vote.get("timestamp"), str)
149
148
  and vote.get("timestamp") != ""
150
149
  ):
151
150
  vote["time"] = formatTimeString(vote.get("timestamp", "1970-01-01T00:00:00"))
152
151
  elif (
153
152
  "last_update" in vote
154
- and isinstance(vote.get("last_update"), string_types)
153
+ and isinstance(vote.get("last_update"), str)
155
154
  and vote.get("last_update") != ""
156
155
  ):
157
156
  vote["last_update"] = formatTimeString(vote.get("last_update", "1970-01-01T00:00:00"))
@@ -178,7 +177,7 @@ class Vote(BlockchainObject):
178
177
  "reputation",
179
178
  ]
180
179
  for p in parse_int:
181
- if p in output and isinstance(output[p], integer_types):
180
+ if p in output and isinstance(output[p], int):
182
181
  output[p] = str(output[p])
183
182
  return json.loads(str(json.dumps(output)))
184
183
 
@@ -456,7 +455,7 @@ class ActiveVotes(VotesObject):
456
455
  authorperm["author"], authorperm["permlink"], api="condenser"
457
456
  )
458
457
  authorperm = authorperm["authorperm"]
459
- elif isinstance(authorperm, string_types):
458
+ elif isinstance(authorperm, str):
460
459
  [author, permlink] = resolve_authorperm(authorperm)
461
460
  if self.blockchain.rpc.get_use_appbase():
462
461
  self.blockchain.rpc.set_next_node_on_empty_reply(False)
@@ -534,7 +533,7 @@ class AccountVotes(VotesObject):
534
533
  time = x.get("last_update", "")
535
534
  if time != "":
536
535
  x["time"] = time
537
- if time != "" and isinstance(time, string_types):
536
+ if time != "" and isinstance(time, str):
538
537
  d_time = formatTimeString(time)
539
538
  elif isinstance(time, datetime):
540
539
  d_time = time
nectar/wallet.py CHANGED
@@ -409,7 +409,7 @@ class Wallet(object):
409
409
  else:
410
410
  try:
411
411
  account = Account(name, blockchain_instance=self.blockchain)
412
- except:
412
+ except Exception:
413
413
  return
414
414
  return {
415
415
  "name": account["name"],