diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index b3570636..dd9c6b56 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -27,8 +27,8 @@
- Integration tests now default to `mainnet` (overridable via `--network-id` / `--rpc-url`).
- `build-dev` script builds with `--strip` for smaller artifacts.
- `pyproject.toml`: set `python-source = "python"` and moved the package stub tree under `python/kaspa/` (`kaspa.pyi` → `python/kaspa/__init__.pyi`).
-- `Hash` accepts `str` in addition to `Hash` instances wherever it is used as an argument, and gained `to_hex()` and `__repr__` methods.
-- Added `Balance` `__repr__` method.
+- `Hash` accepts `str` in addition to `Hash` instances wherever it is used as an argument, and gained a `to_hex()` method.
+- Added `__repr__` methods to: `Hash`, `Balance`, `Binary`, `Address`, `NetworkId`, `ScriptPublicKey`, `TransactionOutpoint`, `Transaction`, `TransactionInput`, `TransactionOutput`, `UtxoEntry`, `UtxoEntries` (consensus and generator helper), `UtxoEntryReference`, `ScriptBuilder`, `Wallet`, `Fees`, `PaymentOutput`, `Outputs`, `Generator`, `GeneratorSummary`, `PendingTransaction`, `BalanceStrings`, `UtxoProcessorEvent`, `UtxoProcessor`, `UtxoContext`, `Notification`, `Resolver`, `NotificationEvent`, `RpcClient`, `DerivationPath`, `XPub`, `PublicKey`, `XOnlyPublicKey`, `PublicKeyGenerator`.
- Documentation site reorganization
### Fixed
diff --git a/docs/gen_ref_pages.py b/docs/gen_ref_pages.py
index 0a662c93..a18c89bc 100644
--- a/docs/gen_ref_pages.py
+++ b/docs/gen_ref_pages.py
@@ -159,6 +159,8 @@ def category_to_nav_path(category: str) -> tuple:
module = objects[name].get("module", "kaspa")
with mkdocs_gen_files.open(doc_path, "w") as f:
+ if category == "Exceptions":
+ f.write("---\nsearch:\n boost: 0.3\n---\n\n")
f.write(f'# `{name}` ({type_label})\n\n')
f.write(f"::: {module}.{name}\n")
f.write(" options:\n")
diff --git a/python/kaspa/__init__.pyi b/python/kaspa/__init__.pyi
index abc4076f..730a7f12 100644
--- a/python/kaspa/__init__.pyi
+++ b/python/kaspa/__init__.pyi
@@ -266,6 +266,13 @@ class Address:
Returns:
str: The address as a string
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Address as a repr string.
+ """
@typing.final
class Balance:
@@ -325,6 +332,13 @@ class BalanceStrings:
r"""
Pending balance formatted as a string (if any).
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The BalanceStrings as a repr string.
+ """
@typing.final
class Binary:
@@ -340,7 +354,13 @@ class Binary:
- bytes: Python bytes object.
- list[int]: A list of byte values (0-255).
"""
- ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Binary as a repr string.
+ """
@typing.final
class DerivationPath:
@@ -402,6 +422,13 @@ class DerivationPath:
Returns:
str: The path as a string (e.g., "m/44'/111111'/0'").
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The DerivationPath as a repr string.
+ """
@typing.final
class Fees:
@@ -423,6 +450,13 @@ class Fees:
Returns:
Fees: A new Fees instance.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Fees as a repr string.
+ """
@typing.final
class Generator:
@@ -471,6 +505,13 @@ class Generator:
Returns:
GeneratorSummary: The generation summary with fees and transaction details.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Generator as a repr string.
+ """
def __iter__(self) -> Generator:
r"""
Return self as an iterator.
@@ -560,6 +601,13 @@ class GeneratorSummary:
Returns:
bool: True if both summaries serialize to identical bytes.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The GeneratorSummary as a repr string.
+ """
@typing.final
class Hash:
@@ -870,6 +918,13 @@ class NetworkId:
Returns:
str: The NetworkId as a string
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The NetworkId as a repr string.
+ """
@typing.final
class Notification:
@@ -892,7 +947,13 @@ class Notification:
- SinkBlueScoreChanged: The sink blue score changed.
- VirtualChainChanged: The virtual chain changed.
"""
- ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Notification as a repr string.
+ """
@typing.final
class Outputs:
@@ -907,7 +968,13 @@ class Outputs:
list[PaymentOutput]: A list of PaymentOutput objects.
list[dict]: A list of dicts with `address` and `amount` keys.
"""
- ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Outputs as a repr string.
+ """
@typing.final
class PaymentOutput:
@@ -935,6 +1002,13 @@ class PaymentOutput:
Returns:
bool: True if both outputs have identical address and amount.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The PaymentOutput as a repr string.
+ """
@typing.final
class PendingTransaction:
@@ -1070,6 +1144,13 @@ class PendingTransaction:
Raises:
Exception: If submission fails.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The PendingTransaction as a repr string.
+ """
@typing.final
class PrivateKey:
@@ -1331,6 +1412,13 @@ class PublicKey:
Returns:
str | None: The fingerprint as hex, or None if unavailable.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The PublicKey as a repr string.
+ """
@typing.final
class PublicKeyGenerator:
@@ -1605,6 +1693,13 @@ class PublicKeyGenerator:
Returns:
str: The generator info string.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The PublicKeyGenerator as a repr string.
+ """
@typing.final
class Resolver:
@@ -1661,6 +1756,13 @@ class Resolver:
Raises:
Exception: If no node is available or resolution fails.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Resolver as a repr string.
+ """
@typing.final
class RpcClient:
@@ -1811,6 +1913,13 @@ class RpcClient:
r"""
Remove all registered event listeners.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The RpcClient as a repr string.
+ """
def subscribe_utxos_changed(self, addresses: typing.Sequence[Address]) -> None:
r"""
Subscribe to UTXO changes for specific addresses (async).
@@ -2068,6 +2177,13 @@ class ScriptBuilder:
Returns:
bool: True if both builders have produced identical scripts.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The ScriptBuilder as a repr string.
+ """
@typing.final
class ScriptPublicKey:
@@ -2113,6 +2229,13 @@ class ScriptPublicKey:
Returns:
bytes: The raw script bytes.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The ScriptPublicKey as a repr string.
+ """
@typing.final
class Transaction:
@@ -2311,6 +2434,13 @@ class Transaction:
ValueError: If values are invalid.
"""
def __eq__(self, other: Transaction) -> builtins.bool: ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Transaction as a repr string.
+ """
@typing.final
class TransactionInput:
@@ -2419,6 +2549,13 @@ class TransactionInput:
ValueError: If values are invalid.
"""
def __eq__(self, other: TransactionInput) -> builtins.bool: ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The TransactionInput as a repr string.
+ """
@typing.final
class TransactionOutpoint:
@@ -2490,6 +2627,13 @@ class TransactionOutpoint:
Returns:
bool: True if both outpoints reference the same transaction id and index.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The TransactionOutpoint as a repr string.
+ """
@typing.final
class TransactionOutput:
@@ -2571,6 +2715,13 @@ class TransactionOutput:
Returns:
bool: True if both outputs have identical value and script.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The TransactionOutput as a repr string.
+ """
@typing.final
class UtxoContext:
@@ -2629,6 +2780,13 @@ class UtxoContext:
r"""
Return pending UTXO entries.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoContext as a repr string.
+ """
@typing.final
class UtxoEntries:
@@ -2679,6 +2837,13 @@ class UtxoEntries:
Returns:
bool: True if both collections contain identical entries in the same order.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoEntries as a repr string.
+ """
@typing.final
class UtxoEntries:
@@ -2693,7 +2858,13 @@ class UtxoEntries:
list[UtxoEntryReference]: A list of UtxoEntryReference objects.
list[dict]: A list of dicts with UtxoEntryReference-compatible keys.
"""
- ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoEntries as a repr string.
+ """
@typing.final
class UtxoEntry:
@@ -2772,6 +2943,13 @@ class UtxoEntry:
Returns:
bool: True if both UtxoEntries have identical fields.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoEntry as a repr string.
+ """
@typing.final
class UtxoEntryReference:
@@ -2851,6 +3029,13 @@ class UtxoEntryReference:
KeyError: If required keys are missing.
ValueError: If values are invalid.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoEntryReference as a repr string.
+ """
@typing.final
class UtxoProcessor:
@@ -2945,6 +3130,13 @@ class UtxoProcessor:
Returns:
None
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoProcessor as a repr string.
+ """
@typing.final
class Wallet:
@@ -3059,6 +3251,13 @@ class Wallet:
Exception: If the wRPC client is currently connected. Disconnect
before changing networks.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The Wallet as a repr string.
+ """
def wallet_enumerate(self) -> list[WalletDescriptor]:
r"""
Enumerate all wallet files in the local store.
@@ -3623,6 +3822,13 @@ class XOnlyPublicKey:
Raises:
Exception: If extraction fails.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The XOnlyPublicKey as a repr string.
+ """
@typing.final
class XPrv:
@@ -3849,6 +4055,13 @@ class XPub:
Returns:
PublicKey: The public key.
"""
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The XPub as a repr string.
+ """
@typing.final
class NotificationEvent(enum.Enum):
@@ -3885,6 +4098,14 @@ class NotificationEvent(enum.Enum):
Connect = ...
Disconnect = ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The NotificationEvent as a repr string.
+ """
+
@typing.final
class AccountsDiscoveryKind(enum.Enum):
r"""
@@ -4345,6 +4566,14 @@ class UtxoProcessorEvent(enum.Enum):
Balance = ...
Error = ...
+ def __repr__(self) -> builtins.str:
+ r"""
+ The detailed string representation.
+
+ Returns:
+ str: The UtxoProcessorEvent as a repr string.
+ """
+
def address_from_script_public_key(script_public_key: ScriptPublicKey, network: str | NetworkType) -> Address:
r"""
Extract the address from a script public key.
diff --git a/src/address.rs b/src/address.rs
index d1201738..74a76026 100644
--- a/src/address.rs
+++ b/src/address.rs
@@ -151,6 +151,14 @@ impl PyAddress {
pub fn __str__(&self) -> String {
self.0.address_to_string()
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Address as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!("Address('{}')", self.0.address_to_string())
+ }
}
impl From
for PyAddress {
diff --git a/src/consensus/client/input.rs b/src/consensus/client/input.rs
index 022d6fbf..d41bd6bb 100644
--- a/src/consensus/client/input.rs
+++ b/src/consensus/client/input.rs
@@ -162,6 +162,21 @@ impl PyTransactionInput {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The TransactionInput as a repr string.
+ fn __repr__(&self) -> String {
+ let inner = self.0.inner();
+ format!(
+ "TransactionInput(previous_outpoint=TransactionOutpoint(transaction_id='{}', index={}), sequence={}, sig_op_count={})",
+ inner.previous_outpoint.inner().transaction_id,
+ inner.previous_outpoint.inner().index,
+ inner.sequence,
+ inner.sig_op_count
+ )
+ }
}
impl From for PyTransactionInput {
diff --git a/src/consensus/client/outpoint.rs b/src/consensus/client/outpoint.rs
index 27e7b450..ee7c4dc2 100644
--- a/src/consensus/client/outpoint.rs
+++ b/src/consensus/client/outpoint.rs
@@ -98,6 +98,18 @@ impl PyTransactionOutpoint {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The TransactionOutpoint as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "TransactionOutpoint(transaction_id='{}', index={})",
+ self.0.inner().transaction_id,
+ self.0.inner().index
+ )
+ }
}
impl From for TransactionOutpoint {
diff --git a/src/consensus/client/output.rs b/src/consensus/client/output.rs
index f63784cf..ce7b3cf3 100644
--- a/src/consensus/client/output.rs
+++ b/src/consensus/client/output.rs
@@ -107,6 +107,19 @@ impl PyTransactionOutput {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The TransactionOutput as a repr string.
+ fn __repr__(&self) -> String {
+ let inner = self.0.inner();
+ format!(
+ "TransactionOutput(value={}, script_public_key='{}')",
+ inner.value,
+ inner.script_public_key.script_as_hex()
+ )
+ }
}
impl From for PyTransactionOutput {
diff --git a/src/consensus/client/transaction.rs b/src/consensus/client/transaction.rs
index a1f8e0e5..7de73b77 100644
--- a/src/consensus/client/transaction.rs
+++ b/src/consensus/client/transaction.rs
@@ -326,6 +326,22 @@ impl PyTransaction {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Transaction as a repr string.
+ fn __repr__(&self) -> String {
+ let inner = self.0.inner();
+ format!(
+ "Transaction(id='{}', version={}, inputs={}, outputs={}, lock_time={})",
+ inner.id,
+ inner.version,
+ inner.inputs.len(),
+ inner.outputs.len(),
+ inner.lock_time
+ )
+ }
}
impl From for PyTransaction {
diff --git a/src/consensus/client/utxo.rs b/src/consensus/client/utxo.rs
index 0e7b18bb..e41ea4ea 100644
--- a/src/consensus/client/utxo.rs
+++ b/src/consensus/client/utxo.rs
@@ -106,6 +106,26 @@ impl PyUtxoEntry {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoEntry as a repr string.
+ fn __repr__(&self) -> String {
+ let address = match &self.0.address {
+ Some(addr) => format!("'{}'", addr.address_to_string()),
+ None => "None".to_string(),
+ };
+ format!(
+ "UtxoEntry(address={}, outpoint=TransactionOutpoint(transaction_id='{}', index={}), amount={}, block_daa_score={}, is_coinbase={})",
+ address,
+ self.0.outpoint.inner().transaction_id,
+ self.0.outpoint.inner().index,
+ self.0.amount,
+ self.0.block_daa_score,
+ self.0.is_coinbase
+ )
+ }
}
impl From for UtxoEntry {
@@ -266,6 +286,18 @@ impl PyUtxoEntries {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoEntries as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "UtxoEntries(items={}, amount={})",
+ self.0.len(),
+ self.0.iter().map(|e| e.amount()).sum::()
+ )
+ }
}
/// A reference to a UTXO entry.
@@ -357,6 +389,26 @@ impl PyUtxoEntryReference {
fn from_dict(_cls: &Bound<'_, PyType>, dict: &Bound<'_, PyDict>) -> PyResult {
Self::try_from(dict)
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoEntryReference as a repr string.
+ fn __repr__(&self) -> String {
+ let address = match &self.0.utxo.address {
+ Some(addr) => format!("'{}'", addr.address_to_string()),
+ None => "None".to_string(),
+ };
+ format!(
+ "UtxoEntryReference(address={}, outpoint=TransactionOutpoint(transaction_id='{}', index={}), amount={}, block_daa_score={}, is_coinbase={})",
+ address,
+ self.0.utxo.outpoint.inner().transaction_id,
+ self.0.utxo.outpoint.inner().index,
+ self.0.utxo.amount,
+ self.0.utxo.block_daa_score,
+ self.0.utxo.is_coinbase
+ )
+ }
}
impl From for UtxoEntryReference {
diff --git a/src/consensus/core/network.rs b/src/consensus/core/network.rs
index 2380adfc..fc72d992 100644
--- a/src/consensus/core/network.rs
+++ b/src/consensus/core/network.rs
@@ -184,6 +184,14 @@ impl PyNetworkId {
pub fn __str__(&self) -> String {
self.0.to_string()
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The NetworkId as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!("NetworkId('{}')", self.0)
+ }
}
impl From for NetworkId {
diff --git a/src/consensus/core/script_public_key.rs b/src/consensus/core/script_public_key.rs
index 11c7b9ff..72a00599 100644
--- a/src/consensus/core/script_public_key.rs
+++ b/src/consensus/core/script_public_key.rs
@@ -58,6 +58,18 @@ impl PyScriptPublicKey {
pub fn __bytes__<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
PyBytes::new(py, self.0.script())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The ScriptPublicKey as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!(
+ "ScriptPublicKey(version={}, script='{}')",
+ self.0.version(),
+ self.0.script_as_hex()
+ )
+ }
}
impl From for ScriptPublicKey {
diff --git a/src/crypto/txscript/builder.rs b/src/crypto/txscript/builder.rs
index 7ee85ae1..d4b2a15b 100644
--- a/src/crypto/txscript/builder.rs
+++ b/src/crypto/txscript/builder.rs
@@ -272,6 +272,15 @@ impl PyScriptBuilder {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The ScriptBuilder as a repr string.
+ fn __repr__(&self) -> String {
+ let inner = self.inner();
+ format!("ScriptBuilder(script='{}')", inner.script().to_hex())
+ }
}
// TODO change to PyOpcode struct and handle similar to PyBinary?
diff --git a/src/rpc/notification.rs b/src/rpc/notification.rs
index 17913a95..4172c15d 100644
--- a/src/rpc/notification.rs
+++ b/src/rpc/notification.rs
@@ -1,6 +1,6 @@
use kaspa_rpc_core::api::notifications::Notification;
use pyo3::prelude::*;
-use pyo3_stub_gen::derive::gen_stub_pyclass;
+use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
use serde_pyobject::to_pyobject;
/// RPC notification wrapper for event callbacks.
@@ -24,6 +24,29 @@ use serde_pyobject::to_pyobject;
#[pyclass(name = "Notification")]
pub struct PyNotification(pub Notification);
+#[gen_stub_pymethods]
+#[pymethods]
+impl PyNotification {
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Notification as a repr string.
+ pub fn __repr__(&self) -> String {
+ let variant = match &self.0 {
+ Notification::BlockAdded(_) => "BlockAdded",
+ Notification::FinalityConflict(_) => "FinalityConflict",
+ Notification::FinalityConflictResolved(_) => "FinalityConflictResolved",
+ Notification::NewBlockTemplate(_) => "NewBlockTemplate",
+ Notification::PruningPointUtxoSetOverride(_) => "PruningPointUtxoSetOverride",
+ Notification::UtxosChanged(_) => "UtxosChanged",
+ Notification::VirtualDaaScoreChanged(_) => "VirtualDaaScoreChanged",
+ Notification::SinkBlueScoreChanged(_) => "SinkBlueScoreChanged",
+ Notification::VirtualChainChanged(_) => "VirtualChainChanged",
+ };
+ format!("Notification(type='{}')", variant)
+ }
+}
+
impl PyNotification {
pub fn to_pyobject(&self, py: Python) -> PyResult> {
let bound_obj = match &self.0 {
diff --git a/src/rpc/wrpc/client.rs b/src/rpc/wrpc/client.rs
index b8415336..8e98a9e1 100644
--- a/src/rpc/wrpc/client.rs
+++ b/src/rpc/wrpc/client.rs
@@ -99,6 +99,32 @@ impl<'py> FromPyObject<'_, 'py> for PyNotificationEvent {
}
}
+#[gen_stub_pymethods]
+#[pymethods]
+impl PyNotificationEvent {
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The NotificationEvent as a repr string.
+ pub fn __repr__(&self) -> String {
+ let variant = match self {
+ PyNotificationEvent::All => "All",
+ PyNotificationEvent::BlockAdded => "BlockAdded",
+ PyNotificationEvent::VirtualChainChanged => "VirtualChainChanged",
+ PyNotificationEvent::FinalityConflict => "FinalityConflict",
+ PyNotificationEvent::FinalityConflictResolved => "FinalityConflictResolved",
+ PyNotificationEvent::UtxosChanged => "UtxosChanged",
+ PyNotificationEvent::SinkBlueScoreChanged => "SinkBlueScoreChanged",
+ PyNotificationEvent::VirtualDaaScoreChanged => "VirtualDaaScoreChanged",
+ PyNotificationEvent::PruningPointUtxoSetOverride => "PruningPointUtxoSetOverride",
+ PyNotificationEvent::NewBlockTemplate => "NewBlockTemplate",
+ PyNotificationEvent::Connect => "Connect",
+ PyNotificationEvent::Disconnect => "Disconnect",
+ };
+ format!("NotificationEvent.{}", variant)
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
enum NotificationEvent {
All,
@@ -573,6 +599,22 @@ impl PyRpcClient {
*self.0.callbacks.lock().unwrap() = Default::default();
Ok(())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The RpcClient as a repr string.
+ fn __repr__(&self) -> String {
+ let url = match self.0.client.url() {
+ Some(u) => format!("'{}'", u),
+ None => "None".to_string(),
+ };
+ format!(
+ "RpcClient(url={}, is_connected={})",
+ url,
+ self.0.client.is_connected()
+ )
+ }
}
impl PyRpcClient {
diff --git a/src/rpc/wrpc/resolver.rs b/src/rpc/wrpc/resolver.rs
index 59bdc43e..6192600d 100644
--- a/src/rpc/wrpc/resolver.rs
+++ b/src/rpc/wrpc/resolver.rs
@@ -123,6 +123,15 @@ impl PyResolver {
}
// fn connect() TODO
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Resolver as a repr string.
+ fn __repr__(&self) -> String {
+ let urls = self.0.urls().map(|u| u.len()).unwrap_or(0);
+ format!("Resolver(urls={})", urls)
+ }
}
impl From for Resolver {
diff --git a/src/types.rs b/src/types.rs
index b6051279..777b05dc 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,7 +1,7 @@
use pyo3::exceptions::PyException;
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyList};
-use pyo3_stub_gen::derive::gen_stub_pyclass;
+use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
/// Binary data type for flexible input handling.
///
@@ -19,6 +19,18 @@ pub struct PyBinary {
pub data: Vec,
}
+#[gen_stub_pymethods]
+#[pymethods]
+impl PyBinary {
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Binary as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!("Binary({} bytes)", self.data.len())
+ }
+}
+
impl<'py> FromPyObject<'_, 'py> for PyBinary {
type Error = PyErr;
diff --git a/src/wallet/core/tx/fees.rs b/src/wallet/core/tx/fees.rs
index 3b2da8d6..c708fe78 100644
--- a/src/wallet/core/tx/fees.rs
+++ b/src/wallet/core/tx/fees.rs
@@ -72,6 +72,19 @@ impl PyFees {
pub fn new(amount: u64, source: Option) -> Self {
Self { amount, source }
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Fees as a repr string.
+ pub fn __repr__(&self) -> String {
+ let source = match &self.source {
+ Some(PyFeeSource::SenderPays) => "FeeSource.SenderPays",
+ Some(PyFeeSource::ReceiverPays) => "FeeSource.ReceiverPays",
+ None => "None",
+ };
+ format!("Fees(amount={}, source={})", self.amount, source)
+ }
}
impl<'py> FromPyObject<'_, 'py> for PyFees {
diff --git a/src/wallet/core/tx/generator/generator.rs b/src/wallet/core/tx/generator/generator.rs
index 5b98b387..3b4ba87b 100644
--- a/src/wallet/core/tx/generator/generator.rs
+++ b/src/wallet/core/tx/generator/generator.rs
@@ -30,6 +30,22 @@ pub struct PyUtxoEntries {
pub entries: Vec,
}
+#[gen_stub_pymethods]
+#[pymethods]
+impl PyUtxoEntries {
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoEntries as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "UtxoEntries(items={}, amount={})",
+ self.entries.len(),
+ self.entries.iter().map(|e| e.amount()).sum::()
+ )
+ }
+}
+
impl<'py> FromPyObject<'_, 'py> for PyUtxoEntries {
type Error = PyErr;
@@ -72,6 +88,22 @@ pub struct PyOutputs {
pub outputs: Vec,
}
+#[gen_stub_pymethods]
+#[pymethods]
+impl PyOutputs {
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Outputs as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "Outputs(items={}, amount={})",
+ self.outputs.len(),
+ self.outputs.iter().map(|o| o.amount).sum::()
+ )
+ }
+}
+
impl<'py> FromPyObject<'_, 'py> for PyOutputs {
type Error = PyErr;
@@ -243,6 +275,21 @@ impl PyGenerator {
pub fn summary(&self) -> PyGeneratorSummary {
self.0.summary().into()
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Generator as a repr string.
+ pub fn __repr__(&self) -> String {
+ let summary = self.0.summary();
+ format!(
+ "Generator(network_id='{}', transactions={}, utxos={}, fees={})",
+ summary.network_id(),
+ summary.number_of_generated_transactions(),
+ summary.aggregated_utxos(),
+ summary.aggregate_fees()
+ )
+ }
}
impl PyGenerator {
diff --git a/src/wallet/core/tx/generator/pending.rs b/src/wallet/core/tx/generator/pending.rs
index f2b02034..e2327555 100644
--- a/src/wallet/core/tx/generator/pending.rs
+++ b/src/wallet/core/tx/generator/pending.rs
@@ -243,6 +243,26 @@ impl PendingTransaction {
fn get_transaction(&self) -> PyResult {
Ok(Transaction::from_cctx_transaction(&self.0.transaction(), self.0.utxo_entries()).into())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The PendingTransaction as a repr string.
+ fn __repr__(&self) -> String {
+ let transaction_type = if self.0.is_batch() { "batch" } else { "final" };
+ format!(
+ "PendingTransaction(id='{}', type='{}', payment_amount={}, change_amount={}, fee_amount={}, mass={})",
+ self.0.id(),
+ transaction_type,
+ match self.0.payment_value() {
+ Some(v) => v.to_string(),
+ None => "None".to_string(),
+ },
+ self.0.change_value(),
+ self.0.fees(),
+ self.0.mass()
+ )
+ }
}
impl From for PendingTransaction {
diff --git a/src/wallet/core/tx/generator/summary.rs b/src/wallet/core/tx/generator/summary.rs
index 4bb17ae5..7e7dde97 100644
--- a/src/wallet/core/tx/generator/summary.rs
+++ b/src/wallet/core/tx/generator/summary.rs
@@ -94,6 +94,25 @@ impl PyGeneratorSummary {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The GeneratorSummary as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "GeneratorSummary(network_id='{}', transactions={}, utxos={}, mass={}, fees={}, final_amount={})",
+ self.0.network_id(),
+ self.0.number_of_generated_transactions(),
+ self.0.aggregated_utxos(),
+ self.0.aggregate_mass(),
+ self.0.aggregate_fees(),
+ match self.0.final_transaction_amount() {
+ Some(v) => v.to_string(),
+ None => "None".to_string(),
+ }
+ )
+ }
}
impl From for PyGeneratorSummary {
diff --git a/src/wallet/core/tx/payment.rs b/src/wallet/core/tx/payment.rs
index 9781ed1a..6bdc05f0 100644
--- a/src/wallet/core/tx/payment.rs
+++ b/src/wallet/core/tx/payment.rs
@@ -44,6 +44,18 @@ impl PyPaymentOutput {
_ => false,
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The PaymentOutput as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "PaymentOutput(address='{}', amount={})",
+ self.0.address.address_to_string(),
+ self.0.amount
+ )
+ }
}
impl From for PaymentOutput {
diff --git a/src/wallet/core/utxo/balance.rs b/src/wallet/core/utxo/balance.rs
index f5673d78..8089a3b1 100644
--- a/src/wallet/core/utxo/balance.rs
+++ b/src/wallet/core/utxo/balance.rs
@@ -96,6 +96,21 @@ impl PyBalanceStrings {
pub fn get_pending(&self) -> Option {
self.0.pending.clone()
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The BalanceStrings as a repr string.
+ pub fn __repr__(&self) -> String {
+ let pending = match &self.0.pending {
+ Some(p) => format!("'{}'", p),
+ None => "None".to_string(),
+ };
+ format!(
+ "BalanceStrings(mature='{}', pending={})",
+ self.0.mature, pending
+ )
+ }
}
impl From for PyBalanceStrings {
diff --git a/src/wallet/core/utxo/context.rs b/src/wallet/core/utxo/context.rs
index 48ced415..21c6d016 100644
--- a/src/wallet/core/utxo/context.rs
+++ b/src/wallet/core/utxo/context.rs
@@ -201,6 +201,18 @@ impl PyUtxoContext {
Ok(None)
}
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoContext as a repr string.
+ fn __repr__(&self) -> String {
+ format!(
+ "UtxoContext(id='{}', mature_length={})",
+ self.0.id(),
+ self.0.mature_utxo_size()
+ )
+ }
}
impl From for UtxoContext {
diff --git a/src/wallet/core/utxo/processor.rs b/src/wallet/core/utxo/processor.rs
index cc73fc9a..a271bfa5 100644
--- a/src/wallet/core/utxo/processor.rs
+++ b/src/wallet/core/utxo/processor.rs
@@ -51,6 +51,37 @@ pub enum PyUtxoProcessorEvent {
Error,
}
+#[gen_stub_pymethods]
+#[pymethods]
+impl PyUtxoProcessorEvent {
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoProcessorEvent as a repr string.
+ pub fn __repr__(&self) -> String {
+ let variant = match self {
+ PyUtxoProcessorEvent::All => "All",
+ PyUtxoProcessorEvent::Connect => "Connect",
+ PyUtxoProcessorEvent::Disconnect => "Disconnect",
+ PyUtxoProcessorEvent::UtxoIndexNotEnabled => "UtxoIndexNotEnabled",
+ PyUtxoProcessorEvent::SyncState => "SyncState",
+ PyUtxoProcessorEvent::ServerStatus => "ServerStatus",
+ PyUtxoProcessorEvent::UtxoProcStart => "UtxoProcStart",
+ PyUtxoProcessorEvent::UtxoProcStop => "UtxoProcStop",
+ PyUtxoProcessorEvent::UtxoProcError => "UtxoProcError",
+ PyUtxoProcessorEvent::DaaScoreChange => "DaaScoreChange",
+ PyUtxoProcessorEvent::Pending => "Pending",
+ PyUtxoProcessorEvent::Reorg => "Reorg",
+ PyUtxoProcessorEvent::Stasis => "Stasis",
+ PyUtxoProcessorEvent::Maturity => "Maturity",
+ PyUtxoProcessorEvent::Discovery => "Discovery",
+ PyUtxoProcessorEvent::Balance => "Balance",
+ PyUtxoProcessorEvent::Error => "Error",
+ };
+ format!("UtxoProcessorEvent.{}", variant)
+ }
+}
+
impl<'py> FromPyObject<'_, 'py> for PyUtxoProcessorEvent {
type Error = PyErr;
@@ -481,6 +512,20 @@ impl PyUtxoProcessor {
self.callbacks.lock().unwrap().clear();
Ok(())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The UtxoProcessor as a repr string.
+ fn __repr__(&self) -> String {
+ let network_id = self
+ .processor
+ .network_id()
+ .ok()
+ .map(|n| format!("'{}'", n))
+ .unwrap_or_else(|| "None".to_string());
+ format!("UtxoProcessor(network_id={})", network_id)
+ }
}
fn parse_event_targets(value: Bound<'_, PyAny>) -> PyResult> {
diff --git a/src/wallet/core/wallet.rs b/src/wallet/core/wallet.rs
index 21043e62..20e1e08f 100644
--- a/src/wallet/core/wallet.rs
+++ b/src/wallet/core/wallet.rs
@@ -356,6 +356,25 @@ impl PyWallet {
self.inner.wallet.set_network_id(&(network_id.into()))?;
Ok(())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The Wallet as a repr string.
+ fn __repr__(&self) -> String {
+ let wallet = self.wallet();
+ let network_id = wallet
+ .network_id()
+ .ok()
+ .map(|n| format!("'{}'", n))
+ .unwrap_or_else(|| "None".to_string());
+ format!(
+ "Wallet(network_id={}, is_open={}, is_synced={})",
+ network_id,
+ wallet.is_open(),
+ wallet.is_synced()
+ )
+ }
}
impl PyWallet {
diff --git a/src/wallet/keys/derivation.rs b/src/wallet/keys/derivation.rs
index 00a0a374..b6b71e68 100644
--- a/src/wallet/keys/derivation.rs
+++ b/src/wallet/keys/derivation.rs
@@ -80,6 +80,14 @@ impl PyDerivationPath {
pub fn to_str(&self) -> String {
self.0.to_string()
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The DerivationPath as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!("DerivationPath('{}')", self.0)
+ }
}
impl From for kaspa_bip32::DerivationPath {
diff --git a/src/wallet/keys/pubkeygen.rs b/src/wallet/keys/pubkeygen.rs
index bb4be7e7..a8706444 100644
--- a/src/wallet/keys/pubkeygen.rs
+++ b/src/wallet/keys/pubkeygen.rs
@@ -553,4 +553,15 @@ impl PyPublicKeyGenerator {
pub fn to_string(&self) -> PyResult {
Ok(self.hd_wallet.to_string(None).to_string())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The PublicKeyGenerator as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!(
+ "PublicKeyGenerator('{}')",
+ self.hd_wallet.to_string(None).as_str()
+ )
+ }
}
diff --git a/src/wallet/keys/publickey.rs b/src/wallet/keys/publickey.rs
index ff15f832..9dbb7820 100644
--- a/src/wallet/keys/publickey.rs
+++ b/src/wallet/keys/publickey.rs
@@ -111,6 +111,14 @@ impl PyPublicKey {
// }
self.0.fingerprint().map(|v| String::try_from(v).unwrap())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The PublicKey as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!("PublicKey('{}')", self.to_string_impl())
+ }
}
impl From for PyPublicKey {
@@ -217,6 +225,14 @@ impl PyXOnlyPublicKey {
// .map_err(|err| PyException::new_err(format!("{}", err)))?;
Ok(xonly_public_key.into())
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The XOnlyPublicKey as a repr string.
+ pub fn __repr__(&self) -> String {
+ format!("XOnlyPublicKey('{}')", self.0.inner)
+ }
}
impl From for PyXOnlyPublicKey {
diff --git a/src/wallet/keys/xpub.rs b/src/wallet/keys/xpub.rs
index c9bac7ef..0772a942 100644
--- a/src/wallet/keys/xpub.rs
+++ b/src/wallet/keys/xpub.rs
@@ -159,4 +159,22 @@ impl PyXPub {
pub fn get_chain_code(&self) -> String {
self.0.inner().attrs().chain_code.to_vec().to_hex()
}
+
+ /// The detailed string representation.
+ ///
+ /// Returns:
+ /// str: The XPub as a repr string.
+ pub fn __repr__(&self) -> String {
+ let xpub = self
+ .0
+ .inner()
+ .to_extended_key("kpub".try_into().unwrap())
+ .to_string();
+ format!(
+ "XPub(xpub='{}', depth={}, child_number={})",
+ xpub,
+ self.0.inner().attrs().depth,
+ u32::from(self.0.inner().attrs().child_number)
+ )
+ }
}