hive-nectar 0.2.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.
- hive_nectar-0.2.9.dist-info/METADATA +194 -0
- hive_nectar-0.2.9.dist-info/RECORD +87 -0
- hive_nectar-0.2.9.dist-info/WHEEL +4 -0
- hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
- hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +37 -0
- nectar/account.py +5076 -0
- nectar/amount.py +553 -0
- nectar/asciichart.py +303 -0
- nectar/asset.py +122 -0
- nectar/block.py +574 -0
- nectar/blockchain.py +1242 -0
- nectar/blockchaininstance.py +2590 -0
- nectar/blockchainobject.py +263 -0
- nectar/cli.py +5937 -0
- nectar/comment.py +1552 -0
- nectar/community.py +854 -0
- nectar/constants.py +95 -0
- nectar/discussions.py +1437 -0
- nectar/exceptions.py +152 -0
- nectar/haf.py +381 -0
- nectar/hive.py +630 -0
- nectar/imageuploader.py +114 -0
- nectar/instance.py +113 -0
- nectar/market.py +876 -0
- nectar/memo.py +542 -0
- nectar/message.py +379 -0
- nectar/nodelist.py +309 -0
- nectar/price.py +603 -0
- nectar/profile.py +74 -0
- nectar/py.typed +0 -0
- nectar/rc.py +333 -0
- nectar/snapshot.py +1024 -0
- nectar/storage.py +62 -0
- nectar/transactionbuilder.py +659 -0
- nectar/utils.py +630 -0
- nectar/version.py +3 -0
- nectar/vote.py +722 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +728 -0
- nectarapi/__init__.py +12 -0
- nectarapi/exceptions.py +126 -0
- nectarapi/graphenerpc.py +596 -0
- nectarapi/node.py +194 -0
- nectarapi/noderpc.py +79 -0
- nectarapi/openapi.py +107 -0
- nectarapi/py.typed +0 -0
- nectarapi/rpcutils.py +98 -0
- nectarapi/version.py +3 -0
- nectarbase/__init__.py +15 -0
- nectarbase/ledgertransactions.py +106 -0
- nectarbase/memo.py +242 -0
- nectarbase/objects.py +521 -0
- nectarbase/objecttypes.py +21 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1357 -0
- nectarbase/py.typed +0 -0
- nectarbase/signedtransactions.py +89 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +3 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +1121 -0
- nectargraphenebase/aes.py +49 -0
- nectargraphenebase/base58.py +197 -0
- nectargraphenebase/bip32.py +575 -0
- nectargraphenebase/bip38.py +110 -0
- nectargraphenebase/chains.py +15 -0
- nectargraphenebase/dictionary.py +2 -0
- nectargraphenebase/ecdsasig.py +309 -0
- nectargraphenebase/objects.py +130 -0
- nectargraphenebase/objecttypes.py +8 -0
- nectargraphenebase/operationids.py +5 -0
- nectargraphenebase/operations.py +25 -0
- nectargraphenebase/prefix.py +13 -0
- nectargraphenebase/py.typed +0 -0
- nectargraphenebase/signedtransactions.py +221 -0
- nectargraphenebase/types.py +557 -0
- nectargraphenebase/unsignedtransactions.py +288 -0
- nectargraphenebase/version.py +3 -0
- nectarstorage/__init__.py +57 -0
- nectarstorage/base.py +317 -0
- nectarstorage/exceptions.py +15 -0
- nectarstorage/interfaces.py +244 -0
- nectarstorage/masterpassword.py +237 -0
- nectarstorage/py.typed +0 -0
- nectarstorage/ram.py +27 -0
- nectarstorage/sqlite.py +343 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import threading
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from typing import Any, Dict, Optional, Union, cast
|
|
5
|
+
|
|
6
|
+
from nectar.instance import shared_blockchain_instance
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ObjectCache(dict):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
initial_data: Optional[Dict[Any, Any]] = None,
|
|
13
|
+
default_expiration: int = 10,
|
|
14
|
+
auto_clean: bool = True,
|
|
15
|
+
) -> None:
|
|
16
|
+
super().__init__(initial_data or {})
|
|
17
|
+
self.set_expiration(default_expiration)
|
|
18
|
+
self.auto_clean = auto_clean
|
|
19
|
+
self.lock = threading.RLock()
|
|
20
|
+
|
|
21
|
+
def __setitem__(self, key: Any, value: Any) -> None:
|
|
22
|
+
data = {
|
|
23
|
+
"expires": datetime.now(timezone.utc) + timedelta(seconds=self.default_expiration),
|
|
24
|
+
"data": value,
|
|
25
|
+
}
|
|
26
|
+
with self.lock:
|
|
27
|
+
if key in self:
|
|
28
|
+
del self[key]
|
|
29
|
+
dict.__setitem__(self, key, data)
|
|
30
|
+
if self.auto_clean:
|
|
31
|
+
self.clear_expired_items()
|
|
32
|
+
|
|
33
|
+
def __getitem__(self, key: Any) -> Any:
|
|
34
|
+
with self.lock:
|
|
35
|
+
if key in self:
|
|
36
|
+
value = dict.__getitem__(self, key)
|
|
37
|
+
if value is not None:
|
|
38
|
+
return value["data"]
|
|
39
|
+
|
|
40
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
|
41
|
+
with self.lock:
|
|
42
|
+
if key in self:
|
|
43
|
+
if self[key] is not None:
|
|
44
|
+
return self[key]
|
|
45
|
+
else:
|
|
46
|
+
return default
|
|
47
|
+
else:
|
|
48
|
+
return default
|
|
49
|
+
|
|
50
|
+
def clear_expired_items(self) -> None:
|
|
51
|
+
with self.lock:
|
|
52
|
+
del_list = []
|
|
53
|
+
utc_now = datetime.now(timezone.utc)
|
|
54
|
+
for key in self:
|
|
55
|
+
value = dict.__getitem__(self, key)
|
|
56
|
+
if value is None:
|
|
57
|
+
del_list.append(key)
|
|
58
|
+
continue
|
|
59
|
+
if utc_now >= value["expires"]:
|
|
60
|
+
del_list.append(key)
|
|
61
|
+
for key in del_list:
|
|
62
|
+
del self[key]
|
|
63
|
+
|
|
64
|
+
def __contains__(self, key: Any) -> bool:
|
|
65
|
+
with self.lock:
|
|
66
|
+
if dict.__contains__(self, key):
|
|
67
|
+
value = dict.__getitem__(self, key)
|
|
68
|
+
if value is None:
|
|
69
|
+
return False
|
|
70
|
+
if datetime.now(timezone.utc) < value["expires"]:
|
|
71
|
+
return True
|
|
72
|
+
else:
|
|
73
|
+
value["data"] = None
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
def __str__(self) -> str:
|
|
77
|
+
if self.auto_clean:
|
|
78
|
+
self.clear_expired_items()
|
|
79
|
+
n = 0
|
|
80
|
+
with self.lock:
|
|
81
|
+
n = len(list(self.keys()))
|
|
82
|
+
return f"ObjectCache(n={n}, default_expiration={self.default_expiration})"
|
|
83
|
+
|
|
84
|
+
def set_expiration(self, expiration: int) -> None:
|
|
85
|
+
"""Set new default expiration time in seconds (default: 10s)"""
|
|
86
|
+
self.default_expiration = expiration
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class BlockchainObject(dict):
|
|
90
|
+
space_id = 1
|
|
91
|
+
type_id = None
|
|
92
|
+
type_ids = []
|
|
93
|
+
|
|
94
|
+
_cache = ObjectCache()
|
|
95
|
+
|
|
96
|
+
def __init__(
|
|
97
|
+
self,
|
|
98
|
+
data: Union[Dict[str, Any], int, str, Any],
|
|
99
|
+
klass: Optional[type] = None,
|
|
100
|
+
space_id: int = 1,
|
|
101
|
+
object_id: Optional[Any] = None,
|
|
102
|
+
lazy: bool = False,
|
|
103
|
+
use_cache: bool = True,
|
|
104
|
+
id_item: Optional[str] = None,
|
|
105
|
+
blockchain_instance: Optional[Any] = None,
|
|
106
|
+
*args,
|
|
107
|
+
**kwargs,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Initialize a BlockchainObject, setting its identifier and optionally loading or caching its data.
|
|
111
|
+
|
|
112
|
+
This constructor accepts a variety of `data` forms:
|
|
113
|
+
- dict or instance of `klass`: uses the mapping directly as the object's data.
|
|
114
|
+
- int: treated as a block number (identifier) and stored under `id_item`.
|
|
115
|
+
- str: treated as an object identifier string and stored under `id_item`.
|
|
116
|
+
- other scalar identifiers: validated with test_valid_objectid and may trigger a lookup.
|
|
117
|
+
|
|
118
|
+
Behavioral notes:
|
|
119
|
+
- If `lazy` is False the constructor may call refresh() to populate the object from the blockchain.
|
|
120
|
+
- If `use_cache` is True and not lazy, the object will be stored in the class-level cache and marked as cached.
|
|
121
|
+
- Raises ValueError if `data` is a list, set, or tuple (these collection types are not supported).
|
|
122
|
+
|
|
123
|
+
Parameters:
|
|
124
|
+
data: dict, instance, int, str, or identifier
|
|
125
|
+
The source for the object's data or its identifier.
|
|
126
|
+
klass (optional): type
|
|
127
|
+
If provided and `data` is an instance of this type, the instance's mapping is used directly.
|
|
128
|
+
space_id (int, optional):
|
|
129
|
+
Numeric namespace for the object type (defaults to 1).
|
|
130
|
+
object_id (optional):
|
|
131
|
+
Explicit object id value — kept for callers that supply it but not otherwise interpreted by the constructor.
|
|
132
|
+
lazy (bool, optional):
|
|
133
|
+
If True, defer loading object contents (do not call refresh()).
|
|
134
|
+
use_cache (bool, optional):
|
|
135
|
+
If True and not lazy, store the constructed object in the class cache.
|
|
136
|
+
id_item (str, optional):
|
|
137
|
+
Key name used to read/write the object's identifier in the underlying mapping (defaults to "id").
|
|
138
|
+
|
|
139
|
+
Raises:
|
|
140
|
+
ValueError: if `data` is a list, set, or tuple.
|
|
141
|
+
"""
|
|
142
|
+
self.blockchain = blockchain_instance or shared_blockchain_instance()
|
|
143
|
+
self.cached = False
|
|
144
|
+
self.identifier = None
|
|
145
|
+
|
|
146
|
+
# We don't read lists, sets, or tuples
|
|
147
|
+
if isinstance(data, (list, set, tuple)):
|
|
148
|
+
raise ValueError("Cannot interpret lists! Please load elements individually!")
|
|
149
|
+
|
|
150
|
+
if id_item and isinstance(id_item, str):
|
|
151
|
+
self.id_item = id_item
|
|
152
|
+
else:
|
|
153
|
+
self.id_item = "id"
|
|
154
|
+
if klass and isinstance(data, klass) and hasattr(data, "get"):
|
|
155
|
+
mapping_data = cast(Dict[str, Any], data)
|
|
156
|
+
self.identifier = mapping_data.get(self.id_item)
|
|
157
|
+
super().__init__(mapping_data)
|
|
158
|
+
elif isinstance(data, dict):
|
|
159
|
+
mapping_data = cast(Dict[str, Any], data)
|
|
160
|
+
self.identifier = mapping_data.get(self.id_item)
|
|
161
|
+
super().__init__(mapping_data)
|
|
162
|
+
elif isinstance(data, int):
|
|
163
|
+
# This is only for block number basically
|
|
164
|
+
self.identifier = data
|
|
165
|
+
if not lazy and not self.cached:
|
|
166
|
+
self.refresh()
|
|
167
|
+
# make sure to store the blocknumber for caching
|
|
168
|
+
self[self.id_item] = data
|
|
169
|
+
# Set identifier again as it is overwritten in super() in refresh()
|
|
170
|
+
self.identifier = data
|
|
171
|
+
elif isinstance(data, str):
|
|
172
|
+
self.identifier = data
|
|
173
|
+
if not lazy and not self.cached:
|
|
174
|
+
self.refresh()
|
|
175
|
+
self[self.id_item] = str(data)
|
|
176
|
+
self.identifier = data
|
|
177
|
+
else:
|
|
178
|
+
self.identifier = data
|
|
179
|
+
if self.test_valid_objectid(self.identifier):
|
|
180
|
+
# Here we assume we deal with an id
|
|
181
|
+
self.testid(self.identifier)
|
|
182
|
+
if self.iscached(data):
|
|
183
|
+
super().__init__(self.getcache(data))
|
|
184
|
+
elif not lazy and not self.cached:
|
|
185
|
+
self.refresh()
|
|
186
|
+
|
|
187
|
+
if use_cache and not lazy:
|
|
188
|
+
self.cache()
|
|
189
|
+
self.cached = True
|
|
190
|
+
|
|
191
|
+
def refresh(self) -> None:
|
|
192
|
+
"""Refresh the object's data from the API.
|
|
193
|
+
|
|
194
|
+
This method should be overridden by subclasses to implement
|
|
195
|
+
specific refresh logic. The base implementation does nothing.
|
|
196
|
+
"""
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def clear_cache() -> None:
|
|
201
|
+
BlockchainObject._cache = ObjectCache()
|
|
202
|
+
|
|
203
|
+
def test_valid_objectid(self, i: Any) -> bool:
|
|
204
|
+
if isinstance(i, str):
|
|
205
|
+
return True
|
|
206
|
+
elif isinstance(i, int):
|
|
207
|
+
return True
|
|
208
|
+
else:
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
def testid(self, id: Any) -> None:
|
|
212
|
+
if not self.type_id:
|
|
213
|
+
return
|
|
214
|
+
|
|
215
|
+
if not self.type_ids:
|
|
216
|
+
self.type_ids = [self.type_id]
|
|
217
|
+
|
|
218
|
+
def cache(self) -> None:
|
|
219
|
+
# store in cache
|
|
220
|
+
if dict.__contains__(self, self.id_item):
|
|
221
|
+
BlockchainObject._cache[self.get(self.id_item)] = self
|
|
222
|
+
|
|
223
|
+
def clear_cache_from_expired_items(self) -> None:
|
|
224
|
+
BlockchainObject._cache.clear_expired_items()
|
|
225
|
+
|
|
226
|
+
def set_cache_expiration(self, expiration: int) -> None:
|
|
227
|
+
BlockchainObject._cache.default_expiration = expiration
|
|
228
|
+
|
|
229
|
+
def set_cache_auto_clean(self, auto_clean: bool) -> None:
|
|
230
|
+
BlockchainObject._cache.auto_clean = auto_clean
|
|
231
|
+
|
|
232
|
+
def get_cache_expiration(self) -> int:
|
|
233
|
+
return BlockchainObject._cache.default_expiration
|
|
234
|
+
|
|
235
|
+
def get_cache_auto_clean(self) -> bool:
|
|
236
|
+
return BlockchainObject._cache.auto_clean
|
|
237
|
+
|
|
238
|
+
def iscached(self, id: Any) -> bool:
|
|
239
|
+
return id in BlockchainObject._cache
|
|
240
|
+
|
|
241
|
+
def getcache(self, id: Any) -> Any:
|
|
242
|
+
return BlockchainObject._cache.get(id, None)
|
|
243
|
+
|
|
244
|
+
def __getitem__(self, key: Any) -> Any:
|
|
245
|
+
if not self.cached:
|
|
246
|
+
self.refresh()
|
|
247
|
+
return super().__getitem__(key)
|
|
248
|
+
|
|
249
|
+
def items(self):
|
|
250
|
+
if not self.cached:
|
|
251
|
+
self.refresh()
|
|
252
|
+
return super().items()
|
|
253
|
+
|
|
254
|
+
def __contains__(self, key: Any) -> bool:
|
|
255
|
+
if not self.cached:
|
|
256
|
+
self.refresh()
|
|
257
|
+
return super().__contains__(key)
|
|
258
|
+
|
|
259
|
+
def __repr__(self) -> str:
|
|
260
|
+
return "<{} {}>".format(self.__class__.__name__, str(self.identifier))
|
|
261
|
+
|
|
262
|
+
def json(self) -> Dict[str, Any]:
|
|
263
|
+
return json.loads(str(json.dumps(self)))
|