graphsense-python 2.12.0__tar.gz → 2.13.0__tar.gz

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.
Files changed (195) hide show
  1. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/PKG-INFO +12 -15
  2. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/README.md +11 -14
  3. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/__init__.py +1 -1
  4. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api_client.py +1 -1
  5. graphsense_python-2.13.0/graphsense/cli/gs.py +139 -0
  6. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/main.py +2 -0
  7. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/configuration.py +2 -2
  8. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/client.py +5 -2
  9. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/io.py +31 -40
  10. graphsense_python-2.13.0/graphsense/gs_files/__init__.py +69 -0
  11. graphsense_python-2.13.0/graphsense/gs_files/encoder.py +336 -0
  12. graphsense_python-2.13.0/graphsense/gs_files/parser.py +440 -0
  13. graphsense_python-2.13.0/graphsense/gs_files/summary.py +34 -0
  14. graphsense_python-2.13.0/graphsense/gs_files/writer.py +73 -0
  15. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address.py +3 -1
  16. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense_python.egg-info/PKG-INFO +12 -15
  17. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense_python.egg-info/SOURCES.txt +7 -0
  18. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/pyproject.toml +1 -1
  19. graphsense_python-2.13.0/tests/test_cli_gs.py +80 -0
  20. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_ext_io.py +24 -0
  21. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/__init__.py +0 -0
  22. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/addresses_api.py +0 -0
  23. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/blocks_api.py +0 -0
  24. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/bulk_api.py +0 -0
  25. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/clusters_api.py +0 -0
  26. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/entities_api.py +0 -0
  27. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/general_api.py +0 -0
  28. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/rates_api.py +0 -0
  29. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/tags_api.py +0 -0
  30. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/tokens_api.py +0 -0
  31. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api/txs_api.py +0 -0
  32. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/api_response.py +0 -0
  33. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/__init__.py +0 -0
  34. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/__main__.py +0 -0
  35. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/bulk_cmd.py +0 -0
  36. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/context.py +0 -0
  37. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/convenience.py +0 -0
  38. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/errors.py +0 -0
  39. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/cli/raw.py +0 -0
  40. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/compat.py +0 -0
  41. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/exceptions.py +0 -0
  42. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/__init__.py +0 -0
  43. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/bulk.py +0 -0
  44. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/deprecation.py +0 -0
  45. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/output.py +0 -0
  46. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/ext/selectors.py +0 -0
  47. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/__init__.py +0 -0
  48. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/actor.py +0 -0
  49. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/actor_context.py +0 -0
  50. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/address.py +0 -0
  51. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/address_tag.py +0 -0
  52. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/address_tags.py +0 -0
  53. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/address_tx.py +0 -0
  54. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/address_tx_utxo.py +0 -0
  55. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/address_txs.py +0 -0
  56. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/block.py +0 -0
  57. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/block_at_date.py +0 -0
  58. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/concept.py +0 -0
  59. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/currency_stats.py +0 -0
  60. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/entity.py +0 -0
  61. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/entity_addresses.py +0 -0
  62. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/external_conversion.py +0 -0
  63. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/http_validation_error.py +0 -0
  64. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/label_summary.py +0 -0
  65. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/labeled_item_ref.py +0 -0
  66. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/link.py +0 -0
  67. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/link_utxo.py +0 -0
  68. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/links.py +0 -0
  69. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/links_inner.py +0 -0
  70. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/location_inner.py +0 -0
  71. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/neighbor_address.py +0 -0
  72. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/neighbor_addresses.py +0 -0
  73. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/neighbor_entities.py +0 -0
  74. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/neighbor_entity.py +0 -0
  75. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/rate.py +0 -0
  76. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/rates.py +0 -0
  77. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/related_address.py +0 -0
  78. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/related_addresses.py +0 -0
  79. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result.py +0 -0
  80. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_by_currency.py +0 -0
  81. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_level1.py +0 -0
  82. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_level2.py +0 -0
  83. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_level3.py +0 -0
  84. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_level4.py +0 -0
  85. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_level5.py +0 -0
  86. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/search_result_level6.py +0 -0
  87. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/stats.py +0 -0
  88. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tag.py +0 -0
  89. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tag_cloud_entry.py +0 -0
  90. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tag_summary.py +0 -0
  91. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/taxonomy.py +0 -0
  92. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/token_config.py +0 -0
  93. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/token_configs.py +0 -0
  94. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tx.py +0 -0
  95. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tx_account.py +0 -0
  96. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tx_ref.py +0 -0
  97. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tx_summary.py +0 -0
  98. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tx_utxo.py +0 -0
  99. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/tx_value.py +0 -0
  100. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/user_reported_tag.py +0 -0
  101. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/user_tag_report_response.py +0 -0
  102. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/validation_error.py +0 -0
  103. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/model/values.py +0 -0
  104. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/__init__.py +0 -0
  105. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/actor.py +0 -0
  106. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/actor_context.py +0 -0
  107. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address_output.py +0 -0
  108. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address_tag.py +0 -0
  109. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address_tags.py +0 -0
  110. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address_tx.py +0 -0
  111. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address_tx_utxo.py +0 -0
  112. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/address_txs.py +0 -0
  113. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/block.py +0 -0
  114. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/block_at_date.py +0 -0
  115. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/change_heuristics.py +0 -0
  116. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/cluster.py +0 -0
  117. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/cluster_addresses.py +0 -0
  118. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/coin_join_consensus.py +0 -0
  119. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/coin_join_heuristics.py +0 -0
  120. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/concept.py +0 -0
  121. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/consensus_entry.py +0 -0
  122. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/currency_stats.py +0 -0
  123. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/direct_change_heuristic.py +0 -0
  124. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/entity.py +0 -0
  125. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/entity_addresses.py +0 -0
  126. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/external_conversion.py +0 -0
  127. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/http_validation_error.py +0 -0
  128. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/join_market_heuristic.py +0 -0
  129. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/label_summary.py +0 -0
  130. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/labeled_item_ref.py +0 -0
  131. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/link.py +0 -0
  132. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/link_utxo.py +0 -0
  133. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/links.py +0 -0
  134. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/links_inner.py +0 -0
  135. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/location_inner.py +0 -0
  136. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/multi_input_change_heuristic.py +0 -0
  137. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/neighbor_address.py +0 -0
  138. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/neighbor_addresses.py +0 -0
  139. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/neighbor_cluster.py +0 -0
  140. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/neighbor_clusters.py +0 -0
  141. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/neighbor_entities.py +0 -0
  142. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/neighbor_entity.py +0 -0
  143. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/one_time_change_heuristic.py +0 -0
  144. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/rate.py +0 -0
  145. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/rates.py +0 -0
  146. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/related_address.py +0 -0
  147. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/related_addresses.py +0 -0
  148. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result.py +0 -0
  149. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_by_currency.py +0 -0
  150. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_level1.py +0 -0
  151. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_level2.py +0 -0
  152. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_level3.py +0 -0
  153. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_level4.py +0 -0
  154. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_level5.py +0 -0
  155. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/search_result_level6.py +0 -0
  156. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/stats.py +0 -0
  157. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tag.py +0 -0
  158. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tag_cloud_entry.py +0 -0
  159. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tag_summary.py +0 -0
  160. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/taxonomy.py +0 -0
  161. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/token_config.py +0 -0
  162. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/token_configs.py +0 -0
  163. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tx.py +0 -0
  164. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tx_account.py +0 -0
  165. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tx_ref.py +0 -0
  166. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tx_summary.py +0 -0
  167. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tx_utxo.py +0 -0
  168. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/tx_value.py +0 -0
  169. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/user_reported_tag.py +0 -0
  170. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/user_tag_report_response.py +0 -0
  171. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/utxo_heuristics.py +0 -0
  172. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/validation_error.py +0 -0
  173. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/values.py +0 -0
  174. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/wasabi_heuristic.py +0 -0
  175. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/whirlpool_coin_join_heuristic.py +0 -0
  176. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/models/whirlpool_tx0_heuristic.py +0 -0
  177. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/py.typed +0 -0
  178. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense/rest.py +0 -0
  179. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense_python.egg-info/dependency_links.txt +0 -0
  180. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense_python.egg-info/entry_points.txt +0 -0
  181. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense_python.egg-info/requires.txt +0 -0
  182. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/graphsense_python.egg-info/top_level.txt +0 -0
  183. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/setup.cfg +0 -0
  184. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_cli_bulk.py +0 -0
  185. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_cli_convenience.py +0 -0
  186. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_cli_errors.py +0 -0
  187. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_cli_io_pipes.py +0 -0
  188. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_cli_raw_mirror.py +0 -0
  189. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_cli_tags_and_dates.py +0 -0
  190. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_ext_bulk.py +0 -0
  191. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_ext_client.py +0 -0
  192. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_ext_output.py +0 -0
  193. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_ext_selectors.py +0 -0
  194. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_readme_template.py +0 -0
  195. {graphsense_python-2.12.0 → graphsense_python-2.13.0}/tests/test_regen_survives.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphsense-python
3
- Version: 2.12.0
3
+ Version: 2.13.0
4
4
  Summary: GraphSense API
5
5
  Author-email: Iknaio Cryptoasset Analytics GmbH <contact@iknaio.com>
6
6
  License-Expression: MIT
@@ -43,22 +43,10 @@ See the [full versioning and deprecation policy](https://github.com/graphsense/g
43
43
  for details.
44
44
 
45
45
 
46
- ## Using the high-level wrapper or CLI
47
-
48
- Two hand-written convenience layers ride on top of the generated client
49
- (both protected from regeneration via `.openapi-generator-ignore`):
50
-
51
- - **Python** — [`README_EXT.md`](README_EXT.md) documents
52
- `graphsense.ext.GraphSense`, a single facade that removes boilerplate and
53
- bundles commonly-paired calls (ships with the base install).
54
- - **Shell** — [`README_CLI.md`](README_CLI.md) documents the `graphsense` CLI
55
- (installed via `uv add 'graphsense-python[cli]'`): pipe-friendly,
56
- JSON/CSV I/O, auto-bulk.
57
-
58
46
  This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
59
47
 
60
- - API version: 2.12.0
61
- - Package version: 2.12.0
48
+ - API version: 2.13.0
49
+ - Package version: 2.13.0
62
50
  - Generator version: 7.19.0
63
51
  - Build package: org.openapitools.codegen.languages.PythonClientCodegen
64
52
  For more information, please visit [https://www.iknaio.com/](https://www.iknaio.com/)
@@ -295,3 +283,12 @@ Authentication schemes defined for the API:
295
283
 
296
284
  contact@iknaio.com
297
285
 
286
+
287
+ ## Using the high-level wrapper or CLI
288
+
289
+ - **Python** — [`README_EXT.md`](README_EXT.md) documents
290
+ `graphsense.ext.GraphSense`, a single facade that removes boilerplate and
291
+ bundles commonly-paired calls (ships with the base install).
292
+ - **Shell** — [`README_CLI.md`](README_CLI.md) documents the `graphsense` CLI
293
+ (installed via `uv add 'graphsense-python[cli]'`): pipe-friendly,
294
+ JSON/CSV I/O, auto-bulk.
@@ -21,22 +21,10 @@ See the [full versioning and deprecation policy](https://github.com/graphsense/g
21
21
  for details.
22
22
 
23
23
 
24
- ## Using the high-level wrapper or CLI
25
-
26
- Two hand-written convenience layers ride on top of the generated client
27
- (both protected from regeneration via `.openapi-generator-ignore`):
28
-
29
- - **Python** — [`README_EXT.md`](README_EXT.md) documents
30
- `graphsense.ext.GraphSense`, a single facade that removes boilerplate and
31
- bundles commonly-paired calls (ships with the base install).
32
- - **Shell** — [`README_CLI.md`](README_CLI.md) documents the `graphsense` CLI
33
- (installed via `uv add 'graphsense-python[cli]'`): pipe-friendly,
34
- JSON/CSV I/O, auto-bulk.
35
-
36
24
  This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
37
25
 
38
- - API version: 2.12.0
39
- - Package version: 2.12.0
26
+ - API version: 2.13.0
27
+ - Package version: 2.13.0
40
28
  - Generator version: 7.19.0
41
29
  - Build package: org.openapitools.codegen.languages.PythonClientCodegen
42
30
  For more information, please visit [https://www.iknaio.com/](https://www.iknaio.com/)
@@ -273,3 +261,12 @@ Authentication schemes defined for the API:
273
261
 
274
262
  contact@iknaio.com
275
263
 
264
+
265
+ ## Using the high-level wrapper or CLI
266
+
267
+ - **Python** — [`README_EXT.md`](README_EXT.md) documents
268
+ `graphsense.ext.GraphSense`, a single facade that removes boilerplate and
269
+ bundles commonly-paired calls (ships with the base install).
270
+ - **Shell** — [`README_CLI.md`](README_CLI.md) documents the `graphsense` CLI
271
+ (installed via `uv add 'graphsense-python[cli]'`): pipe-friendly,
272
+ JSON/CSV I/O, auto-bulk.
@@ -12,7 +12,7 @@
12
12
  """
13
13
 
14
14
 
15
- __version__ = "2.12.0"
15
+ __version__ = "2.13.0"
16
16
 
17
17
  # Define package exports
18
18
  __all__ = [
@@ -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 = 'OpenAPI-Generator/2.12.0/python'
98
+ self.user_agent = 'OpenAPI-Generator/2.13.0/python'
99
99
  self.client_side_validation = configuration.client_side_validation
100
100
 
101
101
  def __enter__(self):
@@ -0,0 +1,139 @@
1
+ """`graphsense gs ...` — read GraphSense `.gs` save files (graph + pathfinder).
2
+
3
+ The extraction commands `txs` and `addresses` emit a uniform
4
+ `[{"network", "id"}, ...]` shape that feeds directly into `lookup-tx`
5
+ and `lookup-address` via the standard
6
+ `--address-jq '[].id' --network-jq '[].network'` selectors.
7
+
8
+ Example:
9
+ graphsense gs txs graph.gs | \\
10
+ graphsense --address-jq '[].id' --network-jq '[].network' \\
11
+ lookup-tx btc
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ import rich_click as click
20
+
21
+ from graphsense.cli.context import CliContext
22
+ from graphsense.ext import output as out_mod
23
+ from graphsense.gs_files import (
24
+ GraphData,
25
+ PathfinderData,
26
+ decode_gs,
27
+ structure,
28
+ summarize,
29
+ to_jsonable,
30
+ )
31
+
32
+ pass_ctx = click.make_pass_decorator(CliContext)
33
+
34
+
35
+ def _write(ctx: CliContext, payload: Any) -> None:
36
+ out_mod.write(
37
+ payload,
38
+ output=ctx.output,
39
+ directory=ctx.directory,
40
+ format=ctx.format,
41
+ color=ctx.color,
42
+ )
43
+
44
+
45
+ def _load(file: Path) -> PathfinderData | GraphData:
46
+ return structure(decode_gs(file))
47
+
48
+
49
+ def _dedupe(records: list[dict[str, Any]]) -> list[dict[str, Any]]:
50
+ """Drop duplicate (network, id) pairs, preserving first-seen order."""
51
+ seen: set[tuple[str, str]] = set()
52
+ out: list[dict[str, Any]] = []
53
+ for r in records:
54
+ key = (str(r["network"]), str(r["id"]))
55
+ if key in seen:
56
+ continue
57
+ seen.add(key)
58
+ out.append(r)
59
+ return out
60
+
61
+
62
+ def _txs(data: PathfinderData | GraphData) -> list[dict[str, Any]]:
63
+ if isinstance(data, PathfinderData):
64
+ return [{"network": t.id.currency, "id": t.id.id} for t in data.txs]
65
+ return []
66
+
67
+
68
+ def _addresses(data: PathfinderData | GraphData) -> list[dict[str, Any]]:
69
+ if isinstance(data, PathfinderData):
70
+ return [{"network": t.id.currency, "id": t.id.id} for t in data.addresses]
71
+ return [{"network": a.currency, "id": a.address} for a in data.addresses]
72
+
73
+
74
+ @click.group(name="gs")
75
+ def gs_group() -> None:
76
+ """Read GraphSense `.gs` save files (Pathfinder + Graph dashboards)."""
77
+
78
+
79
+ @gs_group.command("txs")
80
+ @click.argument("file", type=click.Path(exists=True, dir_okay=False, path_type=Path))
81
+ @click.option(
82
+ "--dedupe/--no-dedupe",
83
+ default=True,
84
+ help="Drop duplicate (network, id) pairs. Default: on.",
85
+ )
86
+ @pass_ctx
87
+ def txs_cmd(ctx: CliContext, file: Path, dedupe: bool) -> None:
88
+ """Emit `{network, id}` records for every transaction in FILE.
89
+
90
+ Only Pathfinder files contain transactions; for Graph files this emits
91
+ an empty list.
92
+ """
93
+ data = _load(file)
94
+ records = _txs(data)
95
+ if dedupe:
96
+ records = _dedupe(records)
97
+ _write(ctx, records)
98
+
99
+
100
+ @gs_group.command("addresses")
101
+ @click.argument("file", type=click.Path(exists=True, dir_okay=False, path_type=Path))
102
+ @click.option(
103
+ "--dedupe/--no-dedupe",
104
+ default=True,
105
+ help="Drop duplicate (network, id) pairs. Default: on.",
106
+ )
107
+ @pass_ctx
108
+ def addresses_cmd(ctx: CliContext, file: Path, dedupe: bool) -> None:
109
+ """Emit `{network, id}` records for every address in FILE."""
110
+ data = _load(file)
111
+ records = _addresses(data)
112
+ if dedupe:
113
+ records = _dedupe(records)
114
+ _write(ctx, records)
115
+
116
+
117
+ @gs_group.command("decode")
118
+ @click.argument("file", type=click.Path(exists=True, dir_okay=False, path_type=Path))
119
+ @click.option(
120
+ "--raw",
121
+ is_flag=True,
122
+ default=False,
123
+ help="Emit the raw decoded JSON instead of the structured view.",
124
+ )
125
+ @pass_ctx
126
+ def decode_cmd(ctx: CliContext, file: Path, raw: bool) -> None:
127
+ """Decode FILE to JSON (structured by default)."""
128
+ if raw:
129
+ _write(ctx, decode_gs(file))
130
+ return
131
+ _write(ctx, to_jsonable(structure(decode_gs(file))))
132
+
133
+
134
+ @gs_group.command("summary")
135
+ @click.argument("file", type=click.Path(exists=True, dir_okay=False, path_type=Path))
136
+ @pass_ctx
137
+ def summary_cmd(ctx: CliContext, file: Path) -> None:
138
+ """Emit a short summary (kind, version, counts) for FILE."""
139
+ _write(ctx, summarize(_load(file)))
@@ -16,6 +16,7 @@ from graphsense.cli.bulk_cmd import bulk_command
16
16
  from graphsense.cli.context import CliContext
17
17
  from graphsense.cli.convenience import register_convenience_commands
18
18
  from graphsense.cli.errors import FriendlyErrorGroup
19
+ from graphsense.cli.gs import gs_group
19
20
  from graphsense.cli.raw import build_raw_group
20
21
  from graphsense.ext.client import API_KEY_ENV_VARS, HOST_ENV_VARS
21
22
 
@@ -206,6 +207,7 @@ def cli(
206
207
  register_convenience_commands(cli)
207
208
  cli.add_command(bulk_command, name="bulk")
208
209
  cli.add_command(build_raw_group(), name="raw")
210
+ cli.add_command(gs_group, name="gs")
209
211
 
210
212
 
211
213
  def main() -> None: # pragma: no cover - trivial
@@ -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.12.0\n"\
537
- "SDK Package Version: 2.12.0".\
536
+ "Version of the API: 2.13.0\n"\
537
+ "SDK Package Version: 2.13.0".\
538
538
  format(env=sys.platform, pyversion=sys.version)
539
539
 
540
540
  def get_host_settings(self) -> List[HostSetting]:
@@ -280,7 +280,10 @@ class GraphSense:
280
280
  cluster_id = getattr(base, "cluster", None)
281
281
  if cluster_id is not None:
282
282
  jobs["cluster"] = pool.submit(
283
- clusters.get_cluster, ccy, int(cluster_id)
283
+ clusters.get_cluster,
284
+ ccy,
285
+ int(cluster_id),
286
+ exclude_best_address_tag=True,
284
287
  )
285
288
  results = {k: f.result() for k, f in jobs.items()}
286
289
 
@@ -302,7 +305,7 @@ class GraphSense:
302
305
  ccy = self._currency(currency)
303
306
  clusters = self.raw.clusters
304
307
  cid = int(cluster_id)
305
- base = clusters.get_cluster(ccy, cid)
308
+ base = clusters.get_cluster(ccy, cid, exclude_best_address_tag=True)
306
309
 
307
310
  jobs: dict[str, Any] = {}
308
311
  with ThreadPoolExecutor(max_workers=self.max_workers) as pool:
@@ -131,27 +131,32 @@ def _extract_from_csv(
131
131
  rows = list(reader)
132
132
  if not rows:
133
133
  return []
134
- header, body = rows[0], rows[1:]
135
- has_header = _looks_like_header(header)
136
- if has_header:
137
- if col is None:
138
- if len(header) != 1:
134
+ header = rows[0]
135
+
136
+ # Named --col: row 1 is the header, look the name up directly. This
137
+ # avoids relying on `_looks_like_header` heuristics for the path that
138
+ # users hit most often.
139
+ if col is not None:
140
+ try:
141
+ idx = int(col)
142
+ except ValueError:
143
+ try:
144
+ idx = header.index(col)
145
+ except ValueError as exc:
139
146
  raise ValueError(
140
- "CSV has multiple columns; specify --col <name_or_index>"
141
- )
142
- idx = 0
143
- else:
144
- idx = _resolve_col_index(col, header)
145
- return [_cell(row, idx) for row in body if _row_keep(row, idx, skip_empty)]
146
- # No header: treat all rows as data
147
- all_rows = [header] + body
148
- if col is None:
149
- if len(header) != 1:
150
- raise ValueError("CSV has multiple columns; specify --col <index>")
151
- idx = 0
152
- else:
153
- idx = _resolve_col_index(col, None)
154
- return [_cell(row, idx) for row in all_rows if _row_keep(row, idx, skip_empty)]
147
+ f"column {col!r} not found in header {header!r}"
148
+ ) from exc
149
+ return [_cell(r, idx) for r in rows[1:] if _row_keep(r, idx, skip_empty)]
150
+
151
+ data_rows = rows[1:] if _looks_like_header(header) else rows
152
+ return [_cell(r, idx) for r in data_rows if _row_keep(r, idx, skip_empty)]
153
+
154
+ # No --col: only single-column input is unambiguous.
155
+ has_header = _looks_like_header(header)
156
+ if len(header) != 1:
157
+ raise ValueError("CSV has multiple columns; specify --col <name_or_index>")
158
+ data_rows = rows[1:] if has_header else rows
159
+ return [_cell(r, 0) for r in data_rows if _row_keep(r, 0, skip_empty)]
155
160
 
156
161
 
157
162
  def _cell(row: list[str], idx: int) -> str:
@@ -164,35 +169,21 @@ def _row_keep(row: list[str], idx: int, skip_empty: bool) -> bool:
164
169
  return True
165
170
 
166
171
 
167
- def _resolve_col_index(col: str, header: Optional[list[str]]) -> int:
168
- try:
169
- return int(col)
170
- except ValueError:
171
- pass
172
- if header is None:
173
- raise ValueError(f"column name {col!r} given but CSV has no header")
174
- try:
175
- return header.index(col)
176
- except ValueError as exc:
177
- raise ValueError(f"column {col!r} not found in header {header!r}") from exc
178
-
179
-
180
172
  def _looks_like_header(row: list[str]) -> bool:
181
173
  """Treat the first row as a header unless every cell looks like an id."""
182
174
  if not row:
183
175
  return False
184
- # If any cell contains characters that are common in plain-text headers
185
- # but unusual in blockchain ids, treat it as a header. Simple heuristic:
186
- # header cells tend to be short and contain only letters/_.
187
176
  for cell in row:
188
177
  c = cell.strip()
189
178
  if not c:
190
179
  return False
191
- if not c.replace("_", "").isalnum():
180
+ # Header cells: letters + underscores only, capped length. Digits
181
+ # disqualify (would suggest an id like `1A1z…`, `0xabc…`, or a
182
+ # numeric cluster id).
183
+ stripped = c.replace("_", "")
184
+ if not stripped.isalpha() or len(c) > 32:
192
185
  return False
193
- # As a pragmatic default: if each cell is purely alphabetic and <= 20
194
- # chars, call it a header. Otherwise treat it as data.
195
- return all(c.strip().isalpha() and len(c.strip()) <= 20 for c in row)
186
+ return True
196
187
 
197
188
 
198
189
  def _extract_from_lines(text: str, *, skip_empty: bool = True) -> list[str]:
@@ -0,0 +1,69 @@
1
+ # AUTO-GENERATED — DO NOT EDIT.
2
+ # Synced from src/graphsenselib/convert/gs_files/__init__.py via
3
+ # clients/python/scripts/sync_gs_files.py. Edit the source and re-run
4
+ # `make -C clients/python sync-gs-files`.
5
+ """Encode and decode GraphSense `.gs` save files.
6
+
7
+ Decode:
8
+ decode_gs_bytes / decode_gs — bytes/path to raw JSON
9
+ structure — raw JSON to typed dataclasses
10
+ summarize — typed dataclasses to short summary dict
11
+ to_jsonable / write_json — JSON serialization helpers
12
+
13
+ Encode:
14
+ GsBuilder — high-level fluent API for building graphs
15
+ encode_gs_payload — raw payload list to .gs bytes
16
+ builder_from_spec — build a GsBuilder from a JSON spec dict
17
+ """
18
+
19
+ from .encoder import (
20
+ GsBuilder,
21
+ builder_from_spec,
22
+ encode_gs_payload,
23
+ )
24
+ from .parser import (
25
+ Color,
26
+ GraphAddress,
27
+ GraphData,
28
+ GraphEntity,
29
+ Highlight,
30
+ PathfinderAggEdge,
31
+ PathfinderAnnotation,
32
+ PathfinderData,
33
+ PathfinderId,
34
+ PathfinderThing,
35
+ UserTag,
36
+ decode_gs,
37
+ decode_gs_bytes,
38
+ lzw_pack,
39
+ lzw_unpack,
40
+ structure,
41
+ )
42
+ from .summary import summarize
43
+ from .writer import to_jsonable, write_decoded, write_json
44
+
45
+ __all__ = [
46
+ "Color",
47
+ "GraphAddress",
48
+ "GraphData",
49
+ "GraphEntity",
50
+ "GsBuilder",
51
+ "Highlight",
52
+ "PathfinderAggEdge",
53
+ "PathfinderAnnotation",
54
+ "PathfinderData",
55
+ "PathfinderId",
56
+ "PathfinderThing",
57
+ "UserTag",
58
+ "builder_from_spec",
59
+ "decode_gs",
60
+ "decode_gs_bytes",
61
+ "encode_gs_payload",
62
+ "lzw_pack",
63
+ "lzw_unpack",
64
+ "structure",
65
+ "summarize",
66
+ "to_jsonable",
67
+ "write_decoded",
68
+ "write_json",
69
+ ]