hive-nectar 0.0.11__py3-none-any.whl → 0.1.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 hive-nectar might be problematic. Click here for more details.
- {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.0.dist-info}/METADATA +10 -11
- hive_nectar-0.1.0.dist-info/RECORD +88 -0
- nectar/__init__.py +1 -4
- nectar/account.py +791 -685
- nectar/amount.py +82 -21
- nectar/asset.py +1 -2
- nectar/block.py +34 -22
- nectar/blockchain.py +111 -143
- nectar/blockchaininstance.py +396 -247
- nectar/blockchainobject.py +33 -5
- nectar/cli.py +1058 -1349
- nectar/comment.py +313 -181
- nectar/community.py +39 -43
- nectar/constants.py +1 -14
- nectar/discussions.py +793 -139
- nectar/hive.py +137 -77
- nectar/hivesigner.py +106 -68
- nectar/imageuploader.py +33 -23
- nectar/instance.py +31 -79
- nectar/market.py +128 -264
- nectar/memo.py +40 -13
- nectar/message.py +23 -10
- nectar/nodelist.py +115 -81
- nectar/price.py +80 -61
- nectar/profile.py +6 -3
- nectar/rc.py +45 -25
- nectar/snapshot.py +285 -163
- nectar/storage.py +16 -5
- nectar/transactionbuilder.py +132 -41
- nectar/utils.py +37 -17
- nectar/version.py +1 -1
- nectar/vote.py +171 -30
- nectar/wallet.py +26 -19
- nectar/witness.py +153 -54
- nectarapi/graphenerpc.py +147 -133
- nectarapi/noderpc.py +12 -6
- nectarapi/rpcutils.py +12 -6
- nectarapi/version.py +1 -1
- nectarbase/ledgertransactions.py +24 -1
- nectarbase/objects.py +17 -6
- nectarbase/operations.py +160 -90
- nectarbase/signedtransactions.py +38 -2
- nectarbase/version.py +1 -1
- nectargraphenebase/account.py +295 -17
- nectargraphenebase/chains.py +0 -135
- nectargraphenebase/ecdsasig.py +152 -176
- nectargraphenebase/types.py +18 -4
- nectargraphenebase/unsignedtransactions.py +1 -1
- nectargraphenebase/version.py +1 -1
- hive_nectar-0.0.11.dist-info/RECORD +0 -91
- nectar/blurt.py +0 -562
- nectar/conveyor.py +0 -308
- nectar/steem.py +0 -581
- {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.0.dist-info}/WHEEL +0 -0
- {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.0.dist-info}/entry_points.txt +0 -0
- {hive_nectar-0.0.11.dist-info → hive_nectar-0.1.0.dist-info}/licenses/LICENSE.txt +0 -0
nectar/message.py
CHANGED
|
@@ -50,11 +50,17 @@ timestamp={meta[timestamp]}
|
|
|
50
50
|
{MESSAGE_SPLIT[3]}"""
|
|
51
51
|
|
|
52
52
|
def __init__(self, message, blockchain_instance=None, *args, **kwargs):
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
"""
|
|
54
|
+
Initialize the message handler, normalize line endings, and set up signing context.
|
|
55
|
+
|
|
56
|
+
Parameters:
|
|
57
|
+
message (str): The raw message text to be signed or verified. Line endings are normalized to LF.
|
|
58
|
+
|
|
59
|
+
Description:
|
|
60
|
+
- Assigns self.blockchain to the provided blockchain_instance or to shared_blockchain_instance() when none is given.
|
|
61
|
+
- Normalizes CRLF ("\r\n") to LF ("\n") and stores the result in self.message.
|
|
62
|
+
- Initializes signing/verification context attributes: signed_by_account, signed_by_name, meta, and plain_message to None.
|
|
63
|
+
"""
|
|
58
64
|
self.blockchain = blockchain_instance or shared_blockchain_instance()
|
|
59
65
|
self.message = message.replace("\r\n", "\n")
|
|
60
66
|
self.signed_by_account = None
|
|
@@ -183,11 +189,18 @@ class MessageV2(object):
|
|
|
183
189
|
"""Allow to sign and verify Messages that are sigend with a private key"""
|
|
184
190
|
|
|
185
191
|
def __init__(self, message, blockchain_instance=None, *args, **kwargs):
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
192
|
+
"""
|
|
193
|
+
Initialize the message handler and set up default signing context.
|
|
194
|
+
|
|
195
|
+
Parameters:
|
|
196
|
+
message (str): The raw message text to be signed or verified.
|
|
197
|
+
|
|
198
|
+
Description:
|
|
199
|
+
Stores the provided message and sets up the signing context attributes
|
|
200
|
+
(signed_by_account, signed_by_name, meta, plain_message) to None.
|
|
201
|
+
If no blockchain instance is supplied, assigns a shared blockchain instance
|
|
202
|
+
via shared_blockchain_instance().
|
|
203
|
+
"""
|
|
191
204
|
self.blockchain = blockchain_instance or shared_blockchain_instance()
|
|
192
205
|
|
|
193
206
|
self.message = message
|
nectar/nodelist.py
CHANGED
|
@@ -10,12 +10,24 @@ log = logging.getLogger(__name__)
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def node_answer_time(node):
|
|
13
|
+
"""
|
|
14
|
+
Measure the RPC/network response time to a Hive node.
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
node (str): Node endpoint (URL or host) to ping.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
float: Elapsed time in seconds for a single `get_network` call. Returns float('inf') if an error occurred while contacting the node.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
KeyboardInterrupt: Re-raised if the operation is interrupted by the user.
|
|
24
|
+
"""
|
|
13
25
|
try:
|
|
14
26
|
from nectar.blockchaininstance import BlockChainInstance
|
|
15
27
|
|
|
16
|
-
|
|
28
|
+
hv_local = BlockChainInstance(node=node, num_retries=2, num_retries_call=2, timeout=10)
|
|
17
29
|
start = timer()
|
|
18
|
-
|
|
30
|
+
hv_local.get_network(use_stored_data=False)
|
|
19
31
|
stop = timer()
|
|
20
32
|
rpc_answer_time = stop - start
|
|
21
33
|
except KeyboardInterrupt:
|
|
@@ -27,7 +39,7 @@ def node_answer_time(node):
|
|
|
27
39
|
|
|
28
40
|
|
|
29
41
|
class NodeList(list):
|
|
30
|
-
"""Returns
|
|
42
|
+
"""Returns Hive nodes as list
|
|
31
43
|
|
|
32
44
|
.. code-block:: python
|
|
33
45
|
|
|
@@ -38,15 +50,14 @@ class NodeList(list):
|
|
|
38
50
|
"""
|
|
39
51
|
|
|
40
52
|
def __init__(self):
|
|
53
|
+
"""
|
|
54
|
+
Initialize the NodeList with a built-in default set of Hive node metadata.
|
|
55
|
+
|
|
56
|
+
Creates the list with prepopulated node dictionaries (url, version, type, owner, hive, score)
|
|
57
|
+
and passes them to the parent list constructor. The default entries are Hive-focused
|
|
58
|
+
(appbase and testnet types) and intended as the initial internal node registry.
|
|
59
|
+
"""
|
|
41
60
|
nodes = [
|
|
42
|
-
{
|
|
43
|
-
"url": "https://api.steemit.com",
|
|
44
|
-
"version": "0.20.2",
|
|
45
|
-
"type": "appbase",
|
|
46
|
-
"owner": "steemit",
|
|
47
|
-
"hive": False,
|
|
48
|
-
"score": 50,
|
|
49
|
-
},
|
|
50
61
|
{
|
|
51
62
|
"url": "https://api.hive.blog",
|
|
52
63
|
"version": "1.27.8",
|
|
@@ -177,14 +188,24 @@ class NodeList(list):
|
|
|
177
188
|
super(NodeList, self).__init__(new_nodes)
|
|
178
189
|
|
|
179
190
|
def get_node_answer_time(self, node_list=None, verbose=False):
|
|
180
|
-
"""
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
"""
|
|
192
|
+
Return a list of reachable node endpoints sorted by measured RPC latency.
|
|
193
|
+
|
|
194
|
+
Pings each URL in node_list (or every URL known to this NodeList if node_list is None)
|
|
195
|
+
using node_answer_time and returns a list of dicts sorted by increasing latency.
|
|
196
|
+
Each dict contains:
|
|
197
|
+
- "url": the node endpoint string
|
|
198
|
+
- "delay_ms": measured round-trip delay in milliseconds
|
|
199
|
+
|
|
200
|
+
Parameters:
|
|
201
|
+
node_list (iterable[str] | None): Specific node URLs to test. If None, all URLs
|
|
202
|
+
from this NodeList are tested.
|
|
203
|
+
verbose (bool): If True, logs each node's measured delay.
|
|
204
|
+
|
|
205
|
+
Behavior notes:
|
|
206
|
+
- URLs not present in this NodeList are treated as unreachable and omitted from the result.
|
|
207
|
+
- Nodes that fail measurement are treated as infinite latency and are excluded from the returned list.
|
|
208
|
+
- A KeyboardInterrupt during measurements stops further pinging; the interrupted entry is treated as unreachable.
|
|
188
209
|
"""
|
|
189
210
|
ping_times = []
|
|
190
211
|
if node_list is None:
|
|
@@ -214,27 +235,39 @@ class NodeList(list):
|
|
|
214
235
|
sorted_nodes.append({"url": node_list[i], "delay_ms": ping_times[i] * 1000})
|
|
215
236
|
return sorted_nodes
|
|
216
237
|
|
|
217
|
-
def update_nodes(self, weights=None, blockchain_instance=None
|
|
218
|
-
"""Reads metadata from nectarflower and recalculates the nodes score
|
|
219
|
-
|
|
220
|
-
:param list/dict weight: can be used to weight the different benchmarks
|
|
221
|
-
:type weight: list, dict
|
|
222
|
-
|
|
223
|
-
.. code-block:: python
|
|
224
|
-
|
|
225
|
-
from nectar.nodelist import NodeList
|
|
226
|
-
nl = NodeList()
|
|
227
|
-
weights = [0, 0.1, 0.2, 1]
|
|
228
|
-
nl.update_nodes(weights)
|
|
229
|
-
weights = {'block': 0.1, 'history': 0.1, 'apicall': 1, 'config': 1}
|
|
230
|
-
nl.update_nodes(weights)
|
|
238
|
+
def update_nodes(self, weights=None, blockchain_instance=None):
|
|
231
239
|
"""
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
240
|
+
Update the internal node list and recalculated scores using nectarflower metadata.
|
|
241
|
+
|
|
242
|
+
Fetches the "nectarflower" account's json_metadata (up to 5 attempts) and uses its
|
|
243
|
+
"report", "failing_nodes", and "parameter" sections to recalculate each node's
|
|
244
|
+
score and metadata (version, hive). If metadata cannot be retrieved after
|
|
245
|
+
retries, the method logs a warning and returns without modifying the list.
|
|
246
|
+
|
|
247
|
+
Weights:
|
|
248
|
+
- weights may be None, a list, or a dict.
|
|
249
|
+
- None: benchmarks are weighted uniformly.
|
|
250
|
+
- list: values are assigned in order to discovered benchmark names and normalized by their sum.
|
|
251
|
+
- dict: keys are benchmark names; values are normalized by their sum. Any benchmark not present in the provided dict receives weight 0.
|
|
252
|
+
The code derives benchmark names from metadata.parameters.benchmarks when available,
|
|
253
|
+
otherwise from keys present in report entries (excluding obvious non-benchmark fields).
|
|
254
|
+
|
|
255
|
+
Scoring rules:
|
|
256
|
+
- For each report entry, per-benchmark ranks are converted to scores (0–100),
|
|
257
|
+
multiplied by the benchmark weights, and summed to produce a node score.
|
|
258
|
+
- If a report entry contains a numeric "weighted_score", that value takes precedence.
|
|
259
|
+
- Nodes listed in failing_nodes receive a score of -1.
|
|
260
|
+
- Nodes present in the internal list but missing from the report receive score 0.
|
|
261
|
+
- Nodes present in the report but missing from the internal list are appended to the final list (with fields populated from the report).
|
|
262
|
+
- Nodes listed in failing_nodes but absent elsewhere are appended with score -1.
|
|
263
|
+
|
|
264
|
+
Side effects:
|
|
265
|
+
- Replaces the NodeList contents (in-place) with the newly computed list of nodes.
|
|
266
|
+
- Uses the provided blockchain_instance or a shared blockchain instance to fetch metadata and advance RPC state on transient errors.
|
|
267
|
+
|
|
268
|
+
No return value.
|
|
269
|
+
"""
|
|
270
|
+
bc = blockchain_instance or shared_blockchain_instance()
|
|
238
271
|
|
|
239
272
|
metadata = None
|
|
240
273
|
account = None
|
|
@@ -242,7 +275,7 @@ class NodeList(list):
|
|
|
242
275
|
while metadata is None and cnt < 5:
|
|
243
276
|
cnt += 1
|
|
244
277
|
try:
|
|
245
|
-
account = Account("nectarflower", blockchain_instance=
|
|
278
|
+
account = Account("nectarflower", blockchain_instance=bc)
|
|
246
279
|
# Metadata is stored in the account's json_metadata field (not posting_json_metadata)
|
|
247
280
|
raw_meta = account.get("json_metadata") or ""
|
|
248
281
|
try:
|
|
@@ -251,7 +284,7 @@ class NodeList(list):
|
|
|
251
284
|
metadata = None
|
|
252
285
|
except Exception as e:
|
|
253
286
|
log.warning(f"Error fetching metadata (attempt {cnt}): {str(e)}")
|
|
254
|
-
|
|
287
|
+
bc.rpc.next()
|
|
255
288
|
account = None
|
|
256
289
|
metadata = None
|
|
257
290
|
|
|
@@ -412,7 +445,7 @@ class NodeList(list):
|
|
|
412
445
|
|
|
413
446
|
def get_nodes(
|
|
414
447
|
self,
|
|
415
|
-
hive=
|
|
448
|
+
hive=True,
|
|
416
449
|
exclude_limited=False,
|
|
417
450
|
dev=False,
|
|
418
451
|
testnet=False,
|
|
@@ -423,17 +456,25 @@ class NodeList(list):
|
|
|
423
456
|
normal=True,
|
|
424
457
|
appbase=True,
|
|
425
458
|
):
|
|
426
|
-
"""
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
459
|
+
"""
|
|
460
|
+
Return a list of node URLs filtered and sorted by score (descending).
|
|
461
|
+
|
|
462
|
+
Filters nodes by type (normal, appbase, appbase-dev, testnet, testnet-dev, appbase-limited), by whether they are Hive nodes, by protocol (https/wss), and by working status. Nodes with score < 0 are excluded unless not_working=True. The resulting list is sorted by each node's "score" in descending order.
|
|
463
|
+
|
|
464
|
+
Parameters that add non-obvious behavior:
|
|
465
|
+
hive (bool): If True (default) return only nodes marked as Hive; set to False to include non-Hive entries (note: the bundled node data is Hive-focused).
|
|
466
|
+
exclude_limited (bool): If True, exclude nodes of type "appbase-limited".
|
|
467
|
+
dev (bool): If True, include "appbase-dev" nodes (legacy/dev nodes, historically version 0.19.11).
|
|
468
|
+
testnet (bool): If True, include "testnet" nodes.
|
|
469
|
+
testnetdev (bool): If True, include "testnet-dev" nodes.
|
|
470
|
+
wss (bool): If False, exclude URLs that start with "wss".
|
|
471
|
+
https (bool): If False, exclude URLs that start with "https".
|
|
472
|
+
not_working (bool): If True, include nodes with negative scores (not working).
|
|
473
|
+
normal (bool): Include "normal" nodes when True. (Deprecated)
|
|
474
|
+
appbase (bool): Include "appbase" nodes when True. (Deprecated)
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
list[str]: Filtered node URLs sorted by node["score"] descending.
|
|
437
478
|
"""
|
|
438
479
|
node_list = []
|
|
439
480
|
node_type_list = []
|
|
@@ -451,6 +492,7 @@ class NodeList(list):
|
|
|
451
492
|
node_type_list.append("appbase-limited")
|
|
452
493
|
for node in self:
|
|
453
494
|
if node["type"] in node_type_list and (node["score"] >= 0 or not_working):
|
|
495
|
+
# Hive-only by default; legacy callers can still pass hive=False but list is Hive-only
|
|
454
496
|
if hive != node["hive"]:
|
|
455
497
|
continue
|
|
456
498
|
if not https and node["url"][:5] == "https":
|
|
@@ -464,11 +506,19 @@ class NodeList(list):
|
|
|
464
506
|
]
|
|
465
507
|
|
|
466
508
|
def get_hive_nodes(self, testnet=False, not_working=False, wss=True, https=True):
|
|
467
|
-
"""
|
|
509
|
+
"""
|
|
510
|
+
Return a list of Hive node URLs filtered and ordered by score.
|
|
468
511
|
|
|
469
|
-
|
|
470
|
-
:param bool not_working: When True, all nodes including not working ones will be returned
|
|
512
|
+
Filters internal nodes to Hive-only entries and returns their URLs sorted by score (highest first).
|
|
471
513
|
|
|
514
|
+
Parameters:
|
|
515
|
+
testnet (bool): If True, include only nodes whose type is "testnet". If False, include only non-testnet nodes.
|
|
516
|
+
not_working (bool): If True, include nodes with negative scores (typically non-working). If False, exclude them.
|
|
517
|
+
wss (bool): If True, include nodes with WSS (wss://) URLs; if False, exclude WSS endpoints.
|
|
518
|
+
https (bool): If True, include nodes with HTTPS (https://) URLs; if False, exclude HTTPS endpoints.
|
|
519
|
+
|
|
520
|
+
Returns:
|
|
521
|
+
list[str]: Sorted list of node URLs (strings) matching the filters.
|
|
472
522
|
"""
|
|
473
523
|
node_list = []
|
|
474
524
|
|
|
@@ -490,33 +540,17 @@ class NodeList(list):
|
|
|
490
540
|
node["url"] for node in sorted(node_list, key=lambda self: self["score"], reverse=True)
|
|
491
541
|
]
|
|
492
542
|
|
|
493
|
-
def
|
|
494
|
-
"""Returns steem only nodes as list
|
|
495
|
-
|
|
496
|
-
:param bool testnet: when True, testnet nodes are included
|
|
497
|
-
:param bool not_working: When True, all nodes including not working ones will be returned
|
|
498
|
-
|
|
543
|
+
def get_testnet(self, testnet=True, testnetdev=False):
|
|
499
544
|
"""
|
|
500
|
-
|
|
545
|
+
Return a list of testnet node URLs.
|
|
501
546
|
|
|
502
|
-
|
|
503
|
-
if node["hive"]:
|
|
504
|
-
continue
|
|
505
|
-
if node["score"] < 0 and not not_working:
|
|
506
|
-
continue
|
|
507
|
-
if (testnet and node["type"] == "testnet") or (
|
|
508
|
-
not testnet and node["type"] != "testnet"
|
|
509
|
-
):
|
|
510
|
-
if not https and node["url"][:5] == "https":
|
|
511
|
-
continue
|
|
512
|
-
if not wss and node["url"][:3] == "wss":
|
|
513
|
-
continue
|
|
514
|
-
node_list.append(node)
|
|
547
|
+
Calls get_nodes with normal and appbase disabled to return nodes belonging to the testnet(s).
|
|
515
548
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
549
|
+
Parameters:
|
|
550
|
+
testnet (bool): If True include nodes marked as `testnet`. If False, include non-testnet nodes.
|
|
551
|
+
testnetdev (bool): If True include nodes marked as `testnet-dev` (development testnet).
|
|
519
552
|
|
|
520
|
-
|
|
521
|
-
|
|
553
|
+
Returns:
|
|
554
|
+
list: Sorted list of node URL strings matching the requested testnet filters.
|
|
555
|
+
"""
|
|
522
556
|
return self.get_nodes(normal=False, appbase=False, testnet=testnet, testnetdev=testnetdev)
|
nectar/price.py
CHANGED
|
@@ -4,23 +4,12 @@ from fractions import Fraction
|
|
|
4
4
|
|
|
5
5
|
from nectar.instance import shared_blockchain_instance
|
|
6
6
|
|
|
7
|
-
from .amount import Amount
|
|
7
|
+
from .amount import Amount, check_asset
|
|
8
8
|
from .asset import Asset
|
|
9
9
|
from .exceptions import InvalidAssetException
|
|
10
10
|
from .utils import assets_from_string, formatTimeString
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def check_asset(other, self, stm):
|
|
14
|
-
if isinstance(other, dict) and "asset" in other and isinstance(self, dict) and "asset" in self:
|
|
15
|
-
if not Asset(other["asset"], blockchain_instance=stm) == Asset(
|
|
16
|
-
self["asset"], blockchain_instance=stm
|
|
17
|
-
):
|
|
18
|
-
raise AssertionError()
|
|
19
|
-
else:
|
|
20
|
-
if not other == self:
|
|
21
|
-
raise AssertionError()
|
|
22
|
-
|
|
23
|
-
|
|
24
13
|
class Price(dict):
|
|
25
14
|
"""This class deals with all sorts of prices of any pair of assets to
|
|
26
15
|
simplify dealing with the tuple::
|
|
@@ -37,7 +26,7 @@ class Price(dict):
|
|
|
37
26
|
:param list args: Allows to deal with different representations of a price
|
|
38
27
|
:param Asset base: Base asset
|
|
39
28
|
:param Asset quote: Quote asset
|
|
40
|
-
:param
|
|
29
|
+
:param Hive blockchain_instance: Hive instance
|
|
41
30
|
:returns: All data required to represent a price
|
|
42
31
|
:rtype: dictionary
|
|
43
32
|
|
|
@@ -53,16 +42,16 @@ class Price(dict):
|
|
|
53
42
|
* ``args`` being a list of ``[quote, base]`` both being instances of ``str`` (``amount symbol``)
|
|
54
43
|
* ``base`` and ``quote`` being instances of :class:`nectar.asset.Amount`
|
|
55
44
|
|
|
56
|
-
This allows
|
|
45
|
+
This allows instantiations like:
|
|
57
46
|
|
|
58
|
-
* ``Price("0.315
|
|
59
|
-
* ``Price(0.315, base="
|
|
60
|
-
* ``Price(0.315, base=Asset("
|
|
61
|
-
* ``Price({"base": {"amount": 1, "asset_id": "
|
|
62
|
-
* ``Price(quote="10
|
|
63
|
-
* ``Price("10
|
|
64
|
-
* ``Price(Amount("10
|
|
65
|
-
* ``Price(1.0, "
|
|
47
|
+
* ``Price("0.315 HBD/HIVE")``
|
|
48
|
+
* ``Price(0.315, base="HBD", quote="HIVE")``
|
|
49
|
+
* ``Price(0.315, base=Asset("HBD"), quote=Asset("HIVE"))``
|
|
50
|
+
* ``Price({"base": {"amount": 1, "asset_id": "HBD"}, "quote": {"amount": 10, "asset_id": "HBD"}})``
|
|
51
|
+
* ``Price(quote="10 HIVE", base="1 HBD")``
|
|
52
|
+
* ``Price("10 HIVE", "1 HBD")``
|
|
53
|
+
* ``Price(Amount("10 HIVE"), Amount("1 HBD"))``
|
|
54
|
+
* ``Price(1.0, "HBD/HIVE")``
|
|
66
55
|
|
|
67
56
|
Instances of this class can be used in regular mathematical expressions
|
|
68
57
|
(``+-*/%``) such as:
|
|
@@ -70,12 +59,12 @@ class Price(dict):
|
|
|
70
59
|
.. code-block:: python
|
|
71
60
|
|
|
72
61
|
>>> from nectar.price import Price
|
|
73
|
-
>>> from nectar import
|
|
74
|
-
>>>
|
|
75
|
-
>>> Price("0.3314
|
|
76
|
-
0.662804
|
|
77
|
-
>>> Price(0.3314, "
|
|
78
|
-
0.331402
|
|
62
|
+
>>> from nectar import Hive
|
|
63
|
+
>>> hv = Hive("https://api.hive.blog")
|
|
64
|
+
>>> Price("0.3314 HBD/HIVE", blockchain_instance=hv) * 2
|
|
65
|
+
0.662804 HBD/HIVE
|
|
66
|
+
>>> Price(0.3314, "HBD", "HIVE", blockchain_instance=hv)
|
|
67
|
+
0.331402 HBD/HIVE
|
|
79
68
|
|
|
80
69
|
"""
|
|
81
70
|
|
|
@@ -86,13 +75,38 @@ class Price(dict):
|
|
|
86
75
|
quote=None,
|
|
87
76
|
base_asset=None, # to identify sell/buy
|
|
88
77
|
blockchain_instance=None,
|
|
89
|
-
**kwargs,
|
|
90
78
|
):
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
79
|
+
"""
|
|
80
|
+
Initialize a Price object representing a ratio between a base and quote asset.
|
|
81
|
+
|
|
82
|
+
This constructor accepts multiple input forms and normalizes them into internal
|
|
83
|
+
"base" and "quote" Amount entries. Supported usages:
|
|
84
|
+
- price: str like "X BASE/QUOTE" with no base/quote: parses symbols and creates
|
|
85
|
+
Amounts from the fractional representation of X.
|
|
86
|
+
- price: dict with "base" and "quote": loads Amounts directly (raises AssertionError
|
|
87
|
+
if a top-level "price" key is present).
|
|
88
|
+
- price: numeric (float/int/Decimal) with base and quote provided as Asset or
|
|
89
|
+
symbol strings: converts the numeric value to a Fraction and builds Amounts.
|
|
90
|
+
- price: str representing an Amount and base: when price is a string and base is
|
|
91
|
+
a symbol string, price and base are used to build quote/base Amounts.
|
|
92
|
+
- price and base as Amount instances: accepts Amount objects directly.
|
|
93
|
+
- price is None with base and quote as symbol strings or Amounts: loads assets
|
|
94
|
+
or Amounts respectively.
|
|
95
|
+
|
|
96
|
+
Parameters (not exhaustive):
|
|
97
|
+
- price: numeric, str, dict, or Amount — the price or a representation used to
|
|
98
|
+
derive base/quote Amounts.
|
|
99
|
+
- base: Asset, Amount, or str — identifies the base side (or a symbol string
|
|
100
|
+
used to parse both symbols when combined with a numeric price).
|
|
101
|
+
- quote: Asset, Amount, or str — identifies the quote side.
|
|
102
|
+
- base_asset: optional; used only as an identifier flag for buy/sell contexts.
|
|
103
|
+
- blockchain_instance: blockchain context used to construct Asset/Amount (omitted
|
|
104
|
+
from param listing as a shared service).
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
- AssertionError: if a dict `price` includes a top-level "price" key.
|
|
108
|
+
- ValueError: if the combination of inputs cannot be parsed into base and quote.
|
|
109
|
+
"""
|
|
96
110
|
self.blockchain = blockchain_instance or shared_blockchain_instance()
|
|
97
111
|
if price == "":
|
|
98
112
|
price = None
|
|
@@ -112,7 +126,7 @@ class Price(dict):
|
|
|
112
126
|
elif price is not None and isinstance(price, dict) and "base" in price and "quote" in price:
|
|
113
127
|
if "price" in price:
|
|
114
128
|
raise AssertionError("You cannot provide a 'price' this way")
|
|
115
|
-
# Regular 'price' objects according to
|
|
129
|
+
# Regular 'price' objects according to hive-core
|
|
116
130
|
# base_id = price["base"]["asset_id"]
|
|
117
131
|
# if price["base"]["asset_id"] == base_id:
|
|
118
132
|
self["base"] = Amount(price["base"], blockchain_instance=self.blockchain)
|
|
@@ -201,18 +215,18 @@ class Price(dict):
|
|
|
201
215
|
return self["base"]["symbol"], self["quote"]["symbol"]
|
|
202
216
|
|
|
203
217
|
def as_base(self, base):
|
|
204
|
-
"""
|
|
205
|
-
|
|
206
|
-
.. note:: This makes a copy of the object!
|
|
218
|
+
"""
|
|
219
|
+
Return a copy of this Price expressed with the given asset as the base.
|
|
207
220
|
|
|
208
|
-
|
|
221
|
+
If `base` matches the current base symbol this returns a shallow copy.
|
|
222
|
+
If `base` matches the current quote symbol this returns a copy with base and quote inverted.
|
|
223
|
+
Raises InvalidAssetException if `base` is neither the base nor the quote of this price.
|
|
209
224
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
>>> stm = Steem("https://api.steemit.com")
|
|
213
|
-
>>> Price("0.3314 SBD/STEEM", blockchain_instance=stm).as_base("STEEM")
|
|
214
|
-
3.017483 STEEM/SBD
|
|
225
|
+
Parameters:
|
|
226
|
+
base (str): Asset symbol to use as the base (e.g., "HIVE" or "HBD").
|
|
215
227
|
|
|
228
|
+
Returns:
|
|
229
|
+
Price: A new Price instance whose base asset is `base`.
|
|
216
230
|
"""
|
|
217
231
|
if base == self["base"]["symbol"]:
|
|
218
232
|
return self.copy()
|
|
@@ -222,18 +236,21 @@ class Price(dict):
|
|
|
222
236
|
raise InvalidAssetException
|
|
223
237
|
|
|
224
238
|
def as_quote(self, quote):
|
|
225
|
-
"""
|
|
239
|
+
"""
|
|
240
|
+
Return a Price instance expressed with the given quote asset symbol.
|
|
226
241
|
|
|
227
|
-
|
|
242
|
+
If `quote` matches the current quote symbol, returns a copy of this Price.
|
|
243
|
+
If `quote` matches the current base symbol, returns a copied, inverted Price.
|
|
244
|
+
A new object is always returned (the original is not modified).
|
|
228
245
|
|
|
229
|
-
|
|
246
|
+
Parameters:
|
|
247
|
+
quote (str): Asset symbol to use as the quote (e.g., "HBD" or "HIVE").
|
|
230
248
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
>>> stm = Steem("https://api.steemit.com")
|
|
234
|
-
>>> Price("0.3314 SBD/STEEM", blockchain_instance=stm).as_quote("SBD")
|
|
235
|
-
3.017483 STEEM/SBD
|
|
249
|
+
Returns:
|
|
250
|
+
Price: A Price object with `quote` as the quote asset.
|
|
236
251
|
|
|
252
|
+
Raises:
|
|
253
|
+
InvalidAssetException: If `quote` does not match either the current base or quote symbol.
|
|
237
254
|
"""
|
|
238
255
|
if quote == self["quote"]["symbol"]:
|
|
239
256
|
return self.copy()
|
|
@@ -243,16 +260,18 @@ class Price(dict):
|
|
|
243
260
|
raise InvalidAssetException
|
|
244
261
|
|
|
245
262
|
def invert(self):
|
|
246
|
-
"""
|
|
263
|
+
"""
|
|
264
|
+
Invert the price in place, swapping base and quote assets (e.g., HBD/HIVE -> HIVE/HBD).
|
|
247
265
|
|
|
248
|
-
|
|
266
|
+
Returns:
|
|
267
|
+
self: The same Price instance after inversion.
|
|
249
268
|
|
|
269
|
+
Example:
|
|
250
270
|
>>> from nectar.price import Price
|
|
251
|
-
>>> from nectar import
|
|
252
|
-
>>>
|
|
253
|
-
>>> Price("0.3314
|
|
254
|
-
3.017483
|
|
255
|
-
|
|
271
|
+
>>> from nectar import Hive
|
|
272
|
+
>>> hv = Hive("https://api.hive.blog")
|
|
273
|
+
>>> Price("0.3314 HBD/HIVE", blockchain_instance=hv).invert()
|
|
274
|
+
3.017483 HIVE/HBD
|
|
256
275
|
"""
|
|
257
276
|
tmp = self["quote"]
|
|
258
277
|
self["quote"] = self["base"]
|
|
@@ -451,7 +470,7 @@ class Order(Price):
|
|
|
451
470
|
ratio of base and quote) but instead has those amounts represent the
|
|
452
471
|
amounts of an actual order!
|
|
453
472
|
|
|
454
|
-
:param
|
|
473
|
+
:param Hive blockchain_instance: Hive instance
|
|
455
474
|
|
|
456
475
|
.. note::
|
|
457
476
|
|
|
@@ -504,7 +523,7 @@ class FilledOrder(Price):
|
|
|
504
523
|
ratio of base and quote) but instead has those amounts represent the
|
|
505
524
|
amounts of an actually filled order!
|
|
506
525
|
|
|
507
|
-
:param
|
|
526
|
+
:param Hive blockchain_instance: Hive instance
|
|
508
527
|
|
|
509
528
|
.. note:: Instances of this class come with an additional ``date`` key
|
|
510
529
|
that shows when the order has been filled!
|
nectar/profile.py
CHANGED
|
@@ -39,12 +39,15 @@ class DotDict(dict):
|
|
|
39
39
|
|
|
40
40
|
class Profile(DotDict):
|
|
41
41
|
"""This class is a template to model a user's on-chain
|
|
42
|
-
profile according to
|
|
43
|
-
|
|
44
|
-
* https://github.com/adcpm/steemscript
|
|
42
|
+
profile according to Hive profile metadata conventions.
|
|
45
43
|
"""
|
|
46
44
|
|
|
47
45
|
def __init__(self, *args, **kwargs):
|
|
46
|
+
"""
|
|
47
|
+
Initialize a Profile by delegating to the DotDict initializer.
|
|
48
|
+
|
|
49
|
+
This constructor accepts the same arguments as DotDict (e.g., dot-separated key/value pairs, a dict, or a JSON string) and performs no additional processing.
|
|
50
|
+
"""
|
|
48
51
|
super(Profile, self).__init__(*args, **kwargs)
|
|
49
52
|
|
|
50
53
|
def __str__(self):
|