hive-nectar 0.0.2__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 (86) hide show
  1. hive_nectar-0.0.2.dist-info/METADATA +182 -0
  2. hive_nectar-0.0.2.dist-info/RECORD +86 -0
  3. hive_nectar-0.0.2.dist-info/WHEEL +4 -0
  4. hive_nectar-0.0.2.dist-info/entry_points.txt +2 -0
  5. hive_nectar-0.0.2.dist-info/licenses/LICENSE.txt +23 -0
  6. nectar/__init__.py +32 -0
  7. nectar/account.py +4371 -0
  8. nectar/amount.py +475 -0
  9. nectar/asciichart.py +270 -0
  10. nectar/asset.py +82 -0
  11. nectar/block.py +446 -0
  12. nectar/blockchain.py +1178 -0
  13. nectar/blockchaininstance.py +2284 -0
  14. nectar/blockchainobject.py +221 -0
  15. nectar/blurt.py +563 -0
  16. nectar/cli.py +6285 -0
  17. nectar/comment.py +1217 -0
  18. nectar/community.py +513 -0
  19. nectar/constants.py +111 -0
  20. nectar/conveyor.py +309 -0
  21. nectar/discussions.py +1709 -0
  22. nectar/exceptions.py +149 -0
  23. nectar/hive.py +546 -0
  24. nectar/hivesigner.py +420 -0
  25. nectar/imageuploader.py +72 -0
  26. nectar/instance.py +129 -0
  27. nectar/market.py +1013 -0
  28. nectar/memo.py +449 -0
  29. nectar/message.py +357 -0
  30. nectar/nodelist.py +444 -0
  31. nectar/price.py +557 -0
  32. nectar/profile.py +65 -0
  33. nectar/rc.py +308 -0
  34. nectar/snapshot.py +726 -0
  35. nectar/steem.py +582 -0
  36. nectar/storage.py +53 -0
  37. nectar/transactionbuilder.py +622 -0
  38. nectar/utils.py +545 -0
  39. nectar/version.py +2 -0
  40. nectar/vote.py +557 -0
  41. nectar/wallet.py +472 -0
  42. nectar/witness.py +617 -0
  43. nectarapi/__init__.py +11 -0
  44. nectarapi/exceptions.py +123 -0
  45. nectarapi/graphenerpc.py +589 -0
  46. nectarapi/node.py +178 -0
  47. nectarapi/noderpc.py +229 -0
  48. nectarapi/rpcutils.py +97 -0
  49. nectarapi/version.py +2 -0
  50. nectarbase/__init__.py +14 -0
  51. nectarbase/ledgertransactions.py +75 -0
  52. nectarbase/memo.py +243 -0
  53. nectarbase/objects.py +429 -0
  54. nectarbase/objecttypes.py +22 -0
  55. nectarbase/operationids.py +102 -0
  56. nectarbase/operations.py +1297 -0
  57. nectarbase/signedtransactions.py +48 -0
  58. nectarbase/transactions.py +11 -0
  59. nectarbase/version.py +2 -0
  60. nectargrapheneapi/__init__.py +6 -0
  61. nectargraphenebase/__init__.py +27 -0
  62. nectargraphenebase/account.py +846 -0
  63. nectargraphenebase/aes.py +52 -0
  64. nectargraphenebase/base58.py +192 -0
  65. nectargraphenebase/bip32.py +494 -0
  66. nectargraphenebase/bip38.py +134 -0
  67. nectargraphenebase/chains.py +149 -0
  68. nectargraphenebase/dictionary.py +3 -0
  69. nectargraphenebase/ecdsasig.py +326 -0
  70. nectargraphenebase/objects.py +123 -0
  71. nectargraphenebase/objecttypes.py +6 -0
  72. nectargraphenebase/operationids.py +3 -0
  73. nectargraphenebase/operations.py +23 -0
  74. nectargraphenebase/prefix.py +11 -0
  75. nectargraphenebase/py23.py +38 -0
  76. nectargraphenebase/signedtransactions.py +201 -0
  77. nectargraphenebase/types.py +419 -0
  78. nectargraphenebase/unsignedtransactions.py +283 -0
  79. nectargraphenebase/version.py +2 -0
  80. nectarstorage/__init__.py +38 -0
  81. nectarstorage/base.py +306 -0
  82. nectarstorage/exceptions.py +16 -0
  83. nectarstorage/interfaces.py +237 -0
  84. nectarstorage/masterpassword.py +239 -0
  85. nectarstorage/ram.py +30 -0
  86. nectarstorage/sqlite.py +334 -0
nectar/block.py ADDED
@@ -0,0 +1,446 @@
1
+ # -*- coding: utf-8 -*-
2
+ import json
3
+ from datetime import date, datetime
4
+
5
+ from nectar.instance import shared_blockchain_instance
6
+ from nectarapi.exceptions import ApiNotSupported
7
+ from nectargraphenebase.py23 import string_types
8
+
9
+ from .blockchainobject import BlockchainObject
10
+ from .exceptions import BlockDoesNotExistsException
11
+ from .utils import formatTimeString
12
+
13
+
14
+ class Block(BlockchainObject):
15
+ """Read a single block from the chain
16
+
17
+ :param int block: block number
18
+ :param Steem steem_instance: Steem
19
+ instance
20
+ :param bool lazy: Use lazy loading
21
+ :param bool only_ops: Includes only operations, when set to True (default: False)
22
+ :param bool only_virtual_ops: Includes only virtual operations (default: False)
23
+
24
+ Instances of this class are dictionaries that come with additional
25
+ methods (see below) that allow dealing with a block and its
26
+ corresponding functions.
27
+
28
+ When only_virtual_ops is set to True, only_ops is always set to True.
29
+
30
+ In addition to the block data, the block number is stored as self["id"] or self.identifier.
31
+
32
+ .. code-block:: python
33
+
34
+ >>> from nectar.block import Block
35
+ >>> block = Block(1)
36
+ >>> print(block)
37
+ <Block 1>
38
+
39
+ .. note:: This class comes with its own caching function to reduce the
40
+ load on the API server. Instances of this class can be
41
+ refreshed with ``Account.refresh()``.
42
+
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ block,
48
+ only_ops=False,
49
+ only_virtual_ops=False,
50
+ full=True,
51
+ lazy=False,
52
+ blockchain_instance=None,
53
+ **kwargs,
54
+ ):
55
+ """Initilize a block
56
+
57
+ :param int block: block number
58
+ :param Steem steem_instance: Steem
59
+ instance
60
+ :param bool lazy: Use lazy loading
61
+ :param bool only_ops: Includes only operations, when set to True (default: False)
62
+ :param bool only_virtual_ops: Includes only virtual operations (default: False)
63
+
64
+ """
65
+ self.full = full
66
+ self.lazy = lazy
67
+ self.only_ops = only_ops
68
+ self.only_virtual_ops = only_virtual_ops
69
+ if isinstance(block, float):
70
+ block = int(block)
71
+ elif isinstance(block, dict):
72
+ block = self._parse_json_data(block)
73
+ super(Block, self).__init__(
74
+ block, lazy=lazy, full=full, blockchain_instance=blockchain_instance, **kwargs
75
+ )
76
+ if self.identifier is None:
77
+ self.identifier = self.block_num
78
+
79
+ def _parse_json_data(self, block):
80
+ parse_times = [
81
+ "timestamp",
82
+ ]
83
+ for p in parse_times:
84
+ if p in block and isinstance(block.get(p), string_types):
85
+ block[p] = formatTimeString(block.get(p, "1970-01-01T00:00:00"))
86
+ if "transactions" in block:
87
+ for i in range(len(block["transactions"])):
88
+ if "expiration" in block["transactions"][i] and isinstance(
89
+ block["transactions"][i]["expiration"], string_types
90
+ ):
91
+ block["transactions"][i]["expiration"] = formatTimeString(
92
+ block["transactions"][i]["expiration"]
93
+ )
94
+ elif "operations" in block:
95
+ for i in range(len(block["operations"])):
96
+ if "timestamp" in block["operations"][i] and isinstance(
97
+ block["operations"][i]["timestamp"], string_types
98
+ ):
99
+ block["operations"][i]["timestamp"] = formatTimeString(
100
+ block["operations"][i]["timestamp"]
101
+ )
102
+ return block
103
+
104
+ def json(self):
105
+ output = self.copy()
106
+ parse_times = [
107
+ "timestamp",
108
+ ]
109
+ for p in parse_times:
110
+ if p in output:
111
+ p_date = output.get(p, datetime(1970, 1, 1, 0, 0))
112
+ if isinstance(p_date, (datetime, date)):
113
+ output[p] = formatTimeString(p_date)
114
+ else:
115
+ output[p] = p_date
116
+
117
+ if "transactions" in output:
118
+ for i in range(len(output["transactions"])):
119
+ if "expiration" in output["transactions"][i] and isinstance(
120
+ output["transactions"][i]["expiration"], (datetime, date)
121
+ ):
122
+ output["transactions"][i]["expiration"] = formatTimeString(
123
+ output["transactions"][i]["expiration"]
124
+ )
125
+ elif "operations" in output:
126
+ for i in range(len(output["operations"])):
127
+ if "timestamp" in output["operations"][i] and isinstance(
128
+ output["operations"][i]["timestamp"], (datetime, date)
129
+ ):
130
+ output["operations"][i]["timestamp"] = formatTimeString(
131
+ output["operations"][i]["timestamp"]
132
+ )
133
+
134
+ ret = json.loads(str(json.dumps(output)))
135
+ output = self._parse_json_data(output)
136
+ return ret
137
+
138
+ def refresh(self):
139
+ """Even though blocks never change, you freshly obtain its contents
140
+ from an API with this method
141
+ """
142
+ if self.identifier is None:
143
+ return
144
+ if not self.blockchain.is_connected():
145
+ return
146
+ self.blockchain.rpc.set_next_node_on_empty_reply(False)
147
+ if self.only_ops or self.only_virtual_ops:
148
+ if self.blockchain.rpc.get_use_appbase():
149
+ try:
150
+ ops_ops = self.blockchain.rpc.get_ops_in_block(
151
+ {"block_num": self.identifier, "only_virtual": self.only_virtual_ops},
152
+ api="account_history",
153
+ )
154
+ if ops_ops is None:
155
+ ops = None
156
+ else:
157
+ ops = ops_ops["ops"]
158
+ except ApiNotSupported:
159
+ ops = self.blockchain.rpc.get_ops_in_block(
160
+ self.identifier, self.only_virtual_ops, api="condenser"
161
+ )
162
+ else:
163
+ ops = self.blockchain.rpc.get_ops_in_block(self.identifier, self.only_virtual_ops)
164
+ if bool(ops):
165
+ block = {
166
+ "block": ops[0]["block"],
167
+ "timestamp": ops[0]["timestamp"],
168
+ "operations": ops,
169
+ }
170
+ else:
171
+ block = {
172
+ "block": self.identifier,
173
+ "timestamp": "1970-01-01T00:00:00",
174
+ "operations": [],
175
+ }
176
+ else:
177
+ if self.blockchain.rpc.get_use_appbase():
178
+ try:
179
+ block = self.blockchain.rpc.get_block(
180
+ {"block_num": self.identifier}, api="block"
181
+ )
182
+ if block and "block" in block:
183
+ block = block["block"]
184
+ except ApiNotSupported:
185
+ block = self.blockchain.rpc.get_block(self.identifier, api="condenser")
186
+ else:
187
+ block = self.blockchain.rpc.get_block(self.identifier)
188
+ if not block:
189
+ raise BlockDoesNotExistsException(
190
+ "output: %s of identifier %s" % (str(block), str(self.identifier))
191
+ )
192
+ block = self._parse_json_data(block)
193
+ super(Block, self).__init__(
194
+ block, lazy=self.lazy, full=self.full, blockchain_instance=self.blockchain
195
+ )
196
+
197
+ @property
198
+ def block_num(self):
199
+ """Returns the block number"""
200
+ if "block_id" in self:
201
+ return int(self["block_id"][:8], base=16)
202
+ elif "block" in self:
203
+ return int(self["block"])
204
+ else:
205
+ return None
206
+
207
+ def time(self):
208
+ """Return a datetime instance for the timestamp of this block"""
209
+ return self["timestamp"]
210
+
211
+ @property
212
+ def transactions(self):
213
+ """Returns all transactions as list"""
214
+ if self.only_ops or self.only_virtual_ops:
215
+ return list()
216
+ trxs = []
217
+ if "transactions" not in self:
218
+ return []
219
+ trx_id = 0
220
+ for trx in self["transactions"]:
221
+ trx_new = {"transaction_id": self["transaction_ids"][trx_id]}
222
+ trx_new.update(trx.copy())
223
+ trx_new.update({"block_num": self.block_num, "transaction_num": trx_id})
224
+ trxs.append(trx_new)
225
+ trx_id += 1
226
+ return trxs
227
+
228
+ @property
229
+ def operations(self):
230
+ """Returns all block operations as list"""
231
+ if self.only_ops or self.only_virtual_ops:
232
+ return self["operations"]
233
+ ops = []
234
+ trxs = []
235
+ if "transactions" in self:
236
+ trxs = self["transactions"]
237
+ for tx in trxs:
238
+ if "operations" not in tx:
239
+ continue
240
+ for op in tx["operations"]:
241
+ # Replace opid by op name
242
+ # op[0] = getOperationNameForId(op[0])
243
+ if isinstance(op, list):
244
+ ops.append(list(op))
245
+ else:
246
+ ops.append(op.copy())
247
+ return ops
248
+
249
+ @property
250
+ def json_transactions(self):
251
+ """Returns all transactions as list, all dates are strings."""
252
+ if self.only_ops or self.only_virtual_ops:
253
+ return list()
254
+ trxs = []
255
+ if "transactions" not in self:
256
+ return []
257
+ trx_id = 0
258
+ for trx in self["transactions"]:
259
+ trx_new = {"transaction_id": self["transaction_ids"][trx_id]}
260
+ trx_new.update(trx.copy())
261
+ trx_new.update({"block_num": self.block_num, "transaction_num": trx_id})
262
+ if "expiration" in trx:
263
+ p_date = trx.get("expiration", datetime(1970, 1, 1, 0, 0))
264
+ if isinstance(p_date, (datetime, date)):
265
+ trx_new.update({"expiration": formatTimeString(p_date)})
266
+
267
+ trxs.append(trx_new)
268
+ trx_id += 1
269
+ return trxs
270
+
271
+ @property
272
+ def json_operations(self):
273
+ """Returns all block operations as list, all dates are strings."""
274
+ if self.only_ops or self.only_virtual_ops:
275
+ return self["operations"]
276
+ ops = []
277
+ for tx in self["transactions"]:
278
+ for op in tx["operations"]:
279
+ if "operations" not in tx:
280
+ continue
281
+ # Replace opid by op name
282
+ # op[0] = getOperationNameForId(op[0])
283
+ if isinstance(op, list):
284
+ op_new = list(op)
285
+ else:
286
+ op_new = op.copy()
287
+ if "timestamp" in op:
288
+ p_date = op.get("timestamp", datetime(1970, 1, 1, 0, 0))
289
+ if isinstance(p_date, (datetime, date)):
290
+ op_new.update({"timestamp": formatTimeString(p_date)})
291
+ ops.append(op_new)
292
+ return ops
293
+
294
+ def ops_statistics(self, add_to_ops_stat=None):
295
+ """Returns a statistic with the occurrence of the different operation types"""
296
+ if add_to_ops_stat is None:
297
+ import nectarbase.operationids
298
+
299
+ ops_stat = nectarbase.operationids.operations.copy()
300
+ for key in ops_stat:
301
+ ops_stat[key] = 0
302
+ else:
303
+ ops_stat = add_to_ops_stat.copy()
304
+ for op in self.operations:
305
+ if "op" in op:
306
+ op = op["op"]
307
+ if isinstance(op, dict) and "type" in op:
308
+ op_type = op["type"]
309
+ if len(op_type) > 10 and op_type[len(op_type) - 10 :] == "_operation":
310
+ op_type = op_type[:-10]
311
+ else:
312
+ op_type = op[0]
313
+ ops_stat[op_type] += 1
314
+ return ops_stat
315
+
316
+
317
+ class BlockHeader(BlockchainObject):
318
+ """Read a single block header from the chain
319
+
320
+ :param int block: block number
321
+ :param Steem steem_instance: Steem
322
+ instance
323
+ :param bool lazy: Use lazy loading
324
+
325
+ In addition to the block data, the block number is stored as self["id"] or self.identifier.
326
+
327
+ .. code-block:: python
328
+
329
+ >>> from nectar.block import BlockHeader
330
+ >>> block = BlockHeader(1)
331
+ >>> print(block)
332
+ <BlockHeader 1>
333
+
334
+ """
335
+
336
+ def __init__(self, block, full=True, lazy=False, blockchain_instance=None, **kwargs):
337
+ """Initilize a block
338
+
339
+ :param int block: block number
340
+ :param Steem steem_instance: Steem
341
+ instance
342
+ :param bool lazy: Use lazy loading
343
+
344
+ """
345
+ self.full = full
346
+ self.lazy = lazy
347
+ if isinstance(block, float):
348
+ block = int(block)
349
+ super(BlockHeader, self).__init__(
350
+ block, lazy=lazy, full=full, blockchain_instance=blockchain_instance, **kwargs
351
+ )
352
+
353
+ def refresh(self):
354
+ """Even though blocks never change, you freshly obtain its contents
355
+ from an API with this method
356
+ """
357
+ if not self.blockchain.is_connected():
358
+ return None
359
+ self.blockchain.rpc.set_next_node_on_empty_reply(False)
360
+ if self.blockchain.rpc.get_use_appbase():
361
+ block = self.blockchain.rpc.get_block_header(
362
+ {"block_num": self.identifier}, api="block"
363
+ )
364
+ if block is not None and "header" in block:
365
+ block = block["header"]
366
+ else:
367
+ block = self.blockchain.rpc.get_block_header(self.identifier)
368
+ if not block:
369
+ raise BlockDoesNotExistsException(str(self.identifier))
370
+ block = self._parse_json_data(block)
371
+ super(BlockHeader, self).__init__(
372
+ block, lazy=self.lazy, full=self.full, blockchain_instance=self.blockchain
373
+ )
374
+
375
+ def time(self):
376
+ """Return a datetime instance for the timestamp of this block"""
377
+ return self["timestamp"]
378
+
379
+ @property
380
+ def block_num(self):
381
+ """Returns the block number"""
382
+ return self.identifier
383
+
384
+ def _parse_json_data(self, block):
385
+ parse_times = [
386
+ "timestamp",
387
+ ]
388
+ for p in parse_times:
389
+ if p in block and isinstance(block.get(p), string_types):
390
+ block[p] = formatTimeString(block.get(p, "1970-01-01T00:00:00"))
391
+ return block
392
+
393
+ def json(self):
394
+ output = self.copy()
395
+ parse_times = [
396
+ "timestamp",
397
+ ]
398
+ for p in parse_times:
399
+ if p in output:
400
+ p_date = output.get(p, datetime(1970, 1, 1, 0, 0))
401
+ if isinstance(p_date, (datetime, date)):
402
+ output[p] = formatTimeString(p_date)
403
+ else:
404
+ output[p] = p_date
405
+ return json.loads(str(json.dumps(output)))
406
+
407
+
408
+ class Blocks(list):
409
+ """Obtain a list of blocks
410
+
411
+ :param list name_list: list of accounts to fetch
412
+ :param int count: (optional) maximum number of accounts
413
+ to fetch per call, defaults to 100
414
+ :param Steem/Hive blockchain_instance: Steem() or Hive() instance to use when
415
+ accessing a RPCcreator = Account(creator, blockchain_instance=self)
416
+ """
417
+
418
+ def __init__(
419
+ self,
420
+ starting_block_num,
421
+ count=1000,
422
+ lazy=False,
423
+ full=True,
424
+ blockchain_instance=None,
425
+ **kwargs,
426
+ ):
427
+ if blockchain_instance is None:
428
+ if kwargs.get("steem_instance"):
429
+ blockchain_instance = kwargs["steem_instance"]
430
+ elif kwargs.get("hive_instance"):
431
+ blockchain_instance = kwargs["hive_instance"]
432
+ self.blockchain = blockchain_instance or shared_blockchain_instance()
433
+
434
+ if not self.blockchain.is_connected():
435
+ return
436
+ blocks = []
437
+
438
+ self.blockchain.rpc.set_next_node_on_empty_reply(False)
439
+
440
+ blocks = self.blockchain.rpc.get_block_range(
441
+ {"starting_block_num": starting_block_num, "count": count}, api="block"
442
+ )["blocks"]
443
+
444
+ super(Blocks, self).__init__(
445
+ [Block(x, lazy=lazy, full=full, blockchain_instance=self.blockchain) for x in blocks]
446
+ )