graphsense-python 2.15.2__py3-none-any.whl → 2.17.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.
- graphsense/__init__.py +7 -1
- graphsense/api/general_api.py +247 -0
- graphsense/api_client.py +1 -1
- graphsense/cli/context.py +9 -4
- graphsense/configuration.py +2 -2
- graphsense/ext/deprecation.py +1 -1
- graphsense/gs_files/__init__.py +15 -0
- graphsense/gs_files/encoder.py +193 -10
- graphsense/gs_files/layout.py +749 -0
- graphsense/models/__init__.py +3 -0
- graphsense/models/address.py +13 -1
- graphsense/models/aggregate_cutoff.py +88 -0
- graphsense/models/capabilities.py +93 -0
- graphsense/models/neighbor_addresses.py +5 -3
- graphsense/models/network_capabilities.py +87 -0
- {graphsense_python-2.15.2.dist-info → graphsense_python-2.17.0.dist-info}/METADATA +9 -5
- {graphsense_python-2.15.2.dist-info → graphsense_python-2.17.0.dist-info}/RECORD +20 -16
- {graphsense_python-2.15.2.dist-info → graphsense_python-2.17.0.dist-info}/WHEEL +0 -0
- {graphsense_python-2.15.2.dist-info → graphsense_python-2.17.0.dist-info}/entry_points.txt +0 -0
- {graphsense_python-2.15.2.dist-info → graphsense_python-2.17.0.dist-info}/top_level.txt +0 -0
graphsense/__init__.py
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
__version__ = "2.
|
|
15
|
+
__version__ = "2.17.0"
|
|
16
16
|
|
|
17
17
|
# Define package exports
|
|
18
18
|
__all__ = [
|
|
@@ -45,8 +45,10 @@ __all__ = [
|
|
|
45
45
|
"AddressTx",
|
|
46
46
|
"AddressTxUtxo",
|
|
47
47
|
"AddressTxs",
|
|
48
|
+
"AggregateCutoff",
|
|
48
49
|
"Block",
|
|
49
50
|
"BlockAtDate",
|
|
51
|
+
"Capabilities",
|
|
50
52
|
"ChangeHeuristics",
|
|
51
53
|
"Cluster",
|
|
52
54
|
"ClusterAddresses",
|
|
@@ -94,6 +96,7 @@ __all__ = [
|
|
|
94
96
|
"NeighborClusters",
|
|
95
97
|
"NeighborEntities",
|
|
96
98
|
"NeighborEntity",
|
|
99
|
+
"NetworkCapabilities",
|
|
97
100
|
"OneTimeChangeHeuristic",
|
|
98
101
|
"PerTxInner",
|
|
99
102
|
"Rate",
|
|
@@ -168,8 +171,10 @@ from graphsense.models.address_tags import AddressTags as AddressTags
|
|
|
168
171
|
from graphsense.models.address_tx import AddressTx as AddressTx
|
|
169
172
|
from graphsense.models.address_tx_utxo import AddressTxUtxo as AddressTxUtxo
|
|
170
173
|
from graphsense.models.address_txs import AddressTxs as AddressTxs
|
|
174
|
+
from graphsense.models.aggregate_cutoff import AggregateCutoff as AggregateCutoff
|
|
171
175
|
from graphsense.models.block import Block as Block
|
|
172
176
|
from graphsense.models.block_at_date import BlockAtDate as BlockAtDate
|
|
177
|
+
from graphsense.models.capabilities import Capabilities as Capabilities
|
|
173
178
|
from graphsense.models.change_heuristics import ChangeHeuristics as ChangeHeuristics
|
|
174
179
|
from graphsense.models.cluster import Cluster as Cluster
|
|
175
180
|
from graphsense.models.cluster_addresses import ClusterAddresses as ClusterAddresses
|
|
@@ -217,6 +222,7 @@ from graphsense.models.neighbor_cluster import NeighborCluster as NeighborCluste
|
|
|
217
222
|
from graphsense.models.neighbor_clusters import NeighborClusters as NeighborClusters
|
|
218
223
|
from graphsense.models.neighbor_entities import NeighborEntities as NeighborEntities
|
|
219
224
|
from graphsense.models.neighbor_entity import NeighborEntity as NeighborEntity
|
|
225
|
+
from graphsense.models.network_capabilities import NetworkCapabilities as NetworkCapabilities
|
|
220
226
|
from graphsense.models.one_time_change_heuristic import OneTimeChangeHeuristic as OneTimeChangeHeuristic
|
|
221
227
|
from graphsense.models.per_tx_inner import PerTxInner as PerTxInner
|
|
222
228
|
from graphsense.models.rate import Rate as Rate
|
graphsense/api/general_api.py
CHANGED
|
@@ -17,6 +17,7 @@ from typing_extensions import Annotated
|
|
|
17
17
|
from pydantic import Field, StrictBool, StrictInt, StrictStr
|
|
18
18
|
from typing import Optional
|
|
19
19
|
from typing_extensions import Annotated
|
|
20
|
+
from graphsense.models.capabilities import Capabilities
|
|
20
21
|
from graphsense.models.search_result import SearchResult
|
|
21
22
|
from graphsense.models.stats import Stats
|
|
22
23
|
|
|
@@ -127,6 +128,252 @@ class GeneralApi:
|
|
|
127
128
|
self.api_client = api_client
|
|
128
129
|
|
|
129
130
|
|
|
131
|
+
@validate_call_compat
|
|
132
|
+
def get_capabilities(
|
|
133
|
+
self,
|
|
134
|
+
_request_timeout: Union[
|
|
135
|
+
None,
|
|
136
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
137
|
+
Tuple[
|
|
138
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
139
|
+
Annotated[StrictFloat, Field(gt=0)]
|
|
140
|
+
]
|
|
141
|
+
] = None,
|
|
142
|
+
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
143
|
+
_content_type: Optional[StrictStr] = None,
|
|
144
|
+
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
145
|
+
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
146
|
+
) -> Capabilities:
|
|
147
|
+
"""Get per-network feature availability
|
|
148
|
+
|
|
149
|
+
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404).
|
|
150
|
+
|
|
151
|
+
:param _request_timeout: timeout setting for this request. If one
|
|
152
|
+
number provided, it will be total request
|
|
153
|
+
timeout. It can also be a pair (tuple) of
|
|
154
|
+
(connection, read) timeouts.
|
|
155
|
+
:type _request_timeout: int, tuple(int, int), optional
|
|
156
|
+
:param _request_auth: set to override the auth_settings for an a single
|
|
157
|
+
request; this effectively ignores the
|
|
158
|
+
authentication in the spec for a single request.
|
|
159
|
+
:type _request_auth: dict, optional
|
|
160
|
+
:param _content_type: force content-type for the request.
|
|
161
|
+
:type _content_type: str, Optional
|
|
162
|
+
:param _headers: set to override the headers for a single
|
|
163
|
+
request; this effectively ignores the headers
|
|
164
|
+
in the spec for a single request.
|
|
165
|
+
:type _headers: dict, optional
|
|
166
|
+
:param _host_index: set to override the host_index for a single
|
|
167
|
+
request; this effectively ignores the host_index
|
|
168
|
+
in the spec for a single request.
|
|
169
|
+
:type _host_index: int, optional
|
|
170
|
+
:return: Returns the result object.
|
|
171
|
+
""" # noqa: E501
|
|
172
|
+
|
|
173
|
+
_param = self._get_capabilities_serialize(
|
|
174
|
+
_request_auth=_request_auth,
|
|
175
|
+
_content_type=_content_type,
|
|
176
|
+
_headers=_headers,
|
|
177
|
+
_host_index=_host_index
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
_response_types_map: Dict[str, Optional[str]] = {
|
|
181
|
+
'200': "Capabilities",
|
|
182
|
+
}
|
|
183
|
+
response_data = self.api_client.call_api(
|
|
184
|
+
*_param,
|
|
185
|
+
_request_timeout=_request_timeout
|
|
186
|
+
)
|
|
187
|
+
response_data.read()
|
|
188
|
+
return self.api_client.response_deserialize(
|
|
189
|
+
response_data=response_data,
|
|
190
|
+
response_types_map=_response_types_map,
|
|
191
|
+
).data
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@validate_call_compat
|
|
195
|
+
def get_capabilities_with_http_info(
|
|
196
|
+
self,
|
|
197
|
+
_request_timeout: Union[
|
|
198
|
+
None,
|
|
199
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
200
|
+
Tuple[
|
|
201
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
202
|
+
Annotated[StrictFloat, Field(gt=0)]
|
|
203
|
+
]
|
|
204
|
+
] = None,
|
|
205
|
+
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
206
|
+
_content_type: Optional[StrictStr] = None,
|
|
207
|
+
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
208
|
+
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
209
|
+
) -> ApiResponse[Capabilities]:
|
|
210
|
+
"""Get per-network feature availability
|
|
211
|
+
|
|
212
|
+
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404).
|
|
213
|
+
|
|
214
|
+
:param _request_timeout: timeout setting for this request. If one
|
|
215
|
+
number provided, it will be total request
|
|
216
|
+
timeout. It can also be a pair (tuple) of
|
|
217
|
+
(connection, read) timeouts.
|
|
218
|
+
:type _request_timeout: int, tuple(int, int), optional
|
|
219
|
+
:param _request_auth: set to override the auth_settings for an a single
|
|
220
|
+
request; this effectively ignores the
|
|
221
|
+
authentication in the spec for a single request.
|
|
222
|
+
:type _request_auth: dict, optional
|
|
223
|
+
:param _content_type: force content-type for the request.
|
|
224
|
+
:type _content_type: str, Optional
|
|
225
|
+
:param _headers: set to override the headers for a single
|
|
226
|
+
request; this effectively ignores the headers
|
|
227
|
+
in the spec for a single request.
|
|
228
|
+
:type _headers: dict, optional
|
|
229
|
+
:param _host_index: set to override the host_index for a single
|
|
230
|
+
request; this effectively ignores the host_index
|
|
231
|
+
in the spec for a single request.
|
|
232
|
+
:type _host_index: int, optional
|
|
233
|
+
:return: Returns the result object.
|
|
234
|
+
""" # noqa: E501
|
|
235
|
+
|
|
236
|
+
_param = self._get_capabilities_serialize(
|
|
237
|
+
_request_auth=_request_auth,
|
|
238
|
+
_content_type=_content_type,
|
|
239
|
+
_headers=_headers,
|
|
240
|
+
_host_index=_host_index
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
_response_types_map: Dict[str, Optional[str]] = {
|
|
244
|
+
'200': "Capabilities",
|
|
245
|
+
}
|
|
246
|
+
response_data = self.api_client.call_api(
|
|
247
|
+
*_param,
|
|
248
|
+
_request_timeout=_request_timeout
|
|
249
|
+
)
|
|
250
|
+
response_data.read()
|
|
251
|
+
return self.api_client.response_deserialize(
|
|
252
|
+
response_data=response_data,
|
|
253
|
+
response_types_map=_response_types_map,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@validate_call_compat
|
|
258
|
+
def get_capabilities_without_preload_content(
|
|
259
|
+
self,
|
|
260
|
+
_request_timeout: Union[
|
|
261
|
+
None,
|
|
262
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
263
|
+
Tuple[
|
|
264
|
+
Annotated[StrictFloat, Field(gt=0)],
|
|
265
|
+
Annotated[StrictFloat, Field(gt=0)]
|
|
266
|
+
]
|
|
267
|
+
] = None,
|
|
268
|
+
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
269
|
+
_content_type: Optional[StrictStr] = None,
|
|
270
|
+
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
271
|
+
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
272
|
+
) -> RESTResponseType:
|
|
273
|
+
"""Get per-network feature availability
|
|
274
|
+
|
|
275
|
+
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404).
|
|
276
|
+
|
|
277
|
+
:param _request_timeout: timeout setting for this request. If one
|
|
278
|
+
number provided, it will be total request
|
|
279
|
+
timeout. It can also be a pair (tuple) of
|
|
280
|
+
(connection, read) timeouts.
|
|
281
|
+
:type _request_timeout: int, tuple(int, int), optional
|
|
282
|
+
:param _request_auth: set to override the auth_settings for an a single
|
|
283
|
+
request; this effectively ignores the
|
|
284
|
+
authentication in the spec for a single request.
|
|
285
|
+
:type _request_auth: dict, optional
|
|
286
|
+
:param _content_type: force content-type for the request.
|
|
287
|
+
:type _content_type: str, Optional
|
|
288
|
+
:param _headers: set to override the headers for a single
|
|
289
|
+
request; this effectively ignores the headers
|
|
290
|
+
in the spec for a single request.
|
|
291
|
+
:type _headers: dict, optional
|
|
292
|
+
:param _host_index: set to override the host_index for a single
|
|
293
|
+
request; this effectively ignores the host_index
|
|
294
|
+
in the spec for a single request.
|
|
295
|
+
:type _host_index: int, optional
|
|
296
|
+
:return: Returns the result object.
|
|
297
|
+
""" # noqa: E501
|
|
298
|
+
|
|
299
|
+
_param = self._get_capabilities_serialize(
|
|
300
|
+
_request_auth=_request_auth,
|
|
301
|
+
_content_type=_content_type,
|
|
302
|
+
_headers=_headers,
|
|
303
|
+
_host_index=_host_index
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
_response_types_map: Dict[str, Optional[str]] = {
|
|
307
|
+
'200': "Capabilities",
|
|
308
|
+
}
|
|
309
|
+
response_data = self.api_client.call_api(
|
|
310
|
+
*_param,
|
|
311
|
+
_request_timeout=_request_timeout
|
|
312
|
+
)
|
|
313
|
+
return response_data.response
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _get_capabilities_serialize(
|
|
317
|
+
self,
|
|
318
|
+
_request_auth,
|
|
319
|
+
_content_type,
|
|
320
|
+
_headers,
|
|
321
|
+
_host_index,
|
|
322
|
+
) -> RequestSerialized:
|
|
323
|
+
|
|
324
|
+
_host = None
|
|
325
|
+
|
|
326
|
+
_collection_formats: Dict[str, str] = {
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
_path_params: Dict[str, str] = {}
|
|
330
|
+
_query_params: List[Tuple[str, str]] = []
|
|
331
|
+
_header_params: Dict[str, Optional[str]] = _headers or {}
|
|
332
|
+
_form_params: List[Tuple[str, str]] = []
|
|
333
|
+
_files: Dict[
|
|
334
|
+
str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]
|
|
335
|
+
] = {}
|
|
336
|
+
_body_params: Optional[bytes] = None
|
|
337
|
+
|
|
338
|
+
# process the path parameters
|
|
339
|
+
# process the query parameters
|
|
340
|
+
# process the header parameters
|
|
341
|
+
# process the form parameters
|
|
342
|
+
# process the body parameter
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
# set the HTTP header `Accept`
|
|
346
|
+
if 'Accept' not in _header_params:
|
|
347
|
+
_header_params['Accept'] = self.api_client.select_header_accept(
|
|
348
|
+
[
|
|
349
|
+
'application/json'
|
|
350
|
+
]
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
# authentication setting
|
|
355
|
+
_auth_settings: List[str] = [
|
|
356
|
+
'api_key'
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
return self.api_client.param_serialize(
|
|
360
|
+
method='GET',
|
|
361
|
+
resource_path='/capabilities',
|
|
362
|
+
path_params=_path_params,
|
|
363
|
+
query_params=_query_params,
|
|
364
|
+
header_params=_header_params,
|
|
365
|
+
body=_body_params,
|
|
366
|
+
post_params=_form_params,
|
|
367
|
+
files=_files,
|
|
368
|
+
auth_settings=_auth_settings,
|
|
369
|
+
collection_formats=_collection_formats,
|
|
370
|
+
_host=_host,
|
|
371
|
+
_request_auth=_request_auth
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
130
377
|
@validate_call_compat
|
|
131
378
|
def get_statistics(
|
|
132
379
|
self,
|
graphsense/api_client.py
CHANGED
|
@@ -95,7 +95,7 @@ class ApiClient:
|
|
|
95
95
|
self.default_headers[header_name] = header_value
|
|
96
96
|
self.cookie = cookie
|
|
97
97
|
# Set default User-Agent.
|
|
98
|
-
self.user_agent = 'graphsense-python/2.
|
|
98
|
+
self.user_agent = 'graphsense-python/2.17.0'
|
|
99
99
|
self.client_side_validation = configuration.client_side_validation
|
|
100
100
|
|
|
101
101
|
def __enter__(self):
|
graphsense/cli/context.py
CHANGED
|
@@ -7,8 +7,6 @@ import sys
|
|
|
7
7
|
from dataclasses import dataclass, field
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
10
|
-
import rich_click as click
|
|
11
|
-
|
|
12
10
|
from graphsense.ext.client import GraphSense
|
|
13
11
|
|
|
14
12
|
|
|
@@ -47,9 +45,16 @@ class CliContext:
|
|
|
47
45
|
"GRAPHSENSE_CLIENT_SHOW_DEPRECATED_ENDPOINTS"
|
|
48
46
|
)
|
|
49
47
|
== "1",
|
|
50
|
-
# Resolve
|
|
48
|
+
# Resolve the current stderr on each write so
|
|
51
49
|
# `CliRunner(mix_stderr=False)` on click 8.1 captures it.
|
|
52
|
-
|
|
50
|
+
# Deliberately not `click.get_text_stream("stderr")`: click
|
|
51
|
+
# 8.5 moved that behind a module-level `__getattr__` that
|
|
52
|
+
# raises a DeprecationWarning (removal in 9.0), and the
|
|
53
|
+
# deprecation hook resolves this stream inside a
|
|
54
|
+
# `try/except Exception`, so under `-W error` the warning
|
|
55
|
+
# became the exception that silently swallowed every
|
|
56
|
+
# deprecation message.
|
|
57
|
+
deprecation_stream=lambda: sys.stderr,
|
|
53
58
|
)
|
|
54
59
|
return self._gs
|
|
55
60
|
|
graphsense/configuration.py
CHANGED
|
@@ -533,8 +533,8 @@ conf = graphsense.Configuration(
|
|
|
533
533
|
return "Python SDK Debug Report:\n"\
|
|
534
534
|
"OS: {env}\n"\
|
|
535
535
|
"Python Version: {pyversion}\n"\
|
|
536
|
-
"Version of the API: 2.
|
|
537
|
-
"SDK Package Version: 2.
|
|
536
|
+
"Version of the API: 2.17.0\n"\
|
|
537
|
+
"SDK Package Version: 2.17.0".\
|
|
538
538
|
format(env=sys.platform, pyversion=sys.version)
|
|
539
539
|
|
|
540
540
|
def get_host_settings(self) -> List[HostSetting]:
|
graphsense/ext/deprecation.py
CHANGED
|
@@ -33,7 +33,7 @@ def install(
|
|
|
33
33
|
* None — write to `sys.stderr` at call time
|
|
34
34
|
* a callable — invoked each write to resolve the current stream (useful
|
|
35
35
|
when a test harness captures stderr with a stream the caller can only
|
|
36
|
-
obtain lazily, e.g.
|
|
36
|
+
obtain lazily, e.g. `lambda: sys.stderr` under click's CliRunner)
|
|
37
37
|
* a file-like object — used directly
|
|
38
38
|
|
|
39
39
|
Safe to call twice on the same client — the second call is a no-op.
|
graphsense/gs_files/__init__.py
CHANGED
|
@@ -14,16 +14,26 @@ Encode:
|
|
|
14
14
|
GsBuilder — high-level fluent API for building graphs
|
|
15
15
|
encode_gs_payload — raw payload list to .gs bytes
|
|
16
16
|
builder_from_spec — build a GsBuilder from a JSON spec dict
|
|
17
|
+
spec_from_pathfinder — decoded pathfinder file back to a spec
|
|
18
|
+
ANNOTATION_PALETTE — the Pathfinder annotation dialog's colors
|
|
19
|
+
|
|
20
|
+
Layout:
|
|
21
|
+
apply_hierarchical_layout — stamp x/y onto a spec (direction-aware
|
|
22
|
+
when txs carry senders / receivers)
|
|
23
|
+
layout_metrics — overlap / crossing / direction numbers
|
|
17
24
|
"""
|
|
18
25
|
|
|
19
26
|
from .encoder import (
|
|
27
|
+
ANNOTATION_PALETTE,
|
|
20
28
|
GsBuilder,
|
|
21
29
|
apply_hierarchical_layout,
|
|
22
30
|
builder_from_spec,
|
|
23
31
|
encode_gs_payload,
|
|
24
32
|
normalize_address_id,
|
|
25
33
|
normalize_tx_id,
|
|
34
|
+
spec_from_pathfinder,
|
|
26
35
|
)
|
|
36
|
+
from .layout import directed_layout, has_flow_info, layout_metrics
|
|
27
37
|
from .parser import (
|
|
28
38
|
Color,
|
|
29
39
|
GraphAddress,
|
|
@@ -46,6 +56,7 @@ from .summary import summarize
|
|
|
46
56
|
from .writer import to_jsonable, write_decoded, write_json
|
|
47
57
|
|
|
48
58
|
__all__ = [
|
|
59
|
+
"ANNOTATION_PALETTE",
|
|
49
60
|
"Color",
|
|
50
61
|
"GraphAddress",
|
|
51
62
|
"GraphCluster",
|
|
@@ -62,11 +73,15 @@ __all__ = [
|
|
|
62
73
|
"builder_from_spec",
|
|
63
74
|
"decode_gs",
|
|
64
75
|
"decode_gs_bytes",
|
|
76
|
+
"directed_layout",
|
|
65
77
|
"encode_gs_payload",
|
|
78
|
+
"has_flow_info",
|
|
79
|
+
"layout_metrics",
|
|
66
80
|
"lzw_pack",
|
|
67
81
|
"lzw_unpack",
|
|
68
82
|
"normalize_address_id",
|
|
69
83
|
"normalize_tx_id",
|
|
84
|
+
"spec_from_pathfinder",
|
|
70
85
|
"structure",
|
|
71
86
|
"summarize",
|
|
72
87
|
"to_jsonable",
|