-
-
Notifications
You must be signed in to change notification settings - Fork 76
add_inputs
, add_outputs
& apply
method to facilitate method chaining
#124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
|
||
from copy import deepcopy | ||
from dataclasses import dataclass, field, fields | ||
from typing import Dict, List, Optional, Set, Tuple, Union | ||
from typing import Dict, List, Optional, Set, Tuple, Union, Callable | ||
|
||
from pycardano.address import Address, AddressType | ||
from pycardano.backend.base import ChainContext | ||
|
@@ -143,16 +143,36 @@ class TransactionBuilder: | |
|
||
_should_estimate_execution_units: bool = field(init=False, default=None) | ||
|
||
def add_input(self, utxo: UTxO) -> TransactionBuilder: | ||
"""Add a specific UTxO to transaction's inputs. | ||
def apply(self, callback: Callable[[], None]) -> TransactionBuilder: | ||
"""Apply the provided callback function to the transaction. | ||
|
||
Args: | ||
utxo (UTxO): UTxO to be added. | ||
callback (Callable[[], None]): A callback function. The callback | ||
should not return a value, as nothing will be done with it. | ||
|
||
Returns: | ||
TransactionBuilder: Current transaction builder. | ||
""" | ||
self.inputs.append(utxo) | ||
if callable(callback): | ||
callback() | ||
else: | ||
raise ValueError("Not a callable.") | ||
return self | ||
|
||
def add_input(self, utxo: Union[UTxO, List[UTxO]]) -> TransactionBuilder: | ||
"""Add a specific UTxO or a list of UTxOs to the transaction's inputs. | ||
|
||
Args: | ||
utxo (Union[UTxO, List[UTxO]]): UTxO or list of UTxOs to be added to the transaction. | ||
|
||
Returns: | ||
TransactionBuilder: Current transaction builder. | ||
""" | ||
if isinstance(utxo, list): | ||
for o in utxo: | ||
self.inputs.append(o) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. . If
Cons:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am fine with either way, will let you decide :D For union type, we will probably still need to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't mind haha - maybe do an emoji poll on Discord to see what most people would prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we need to support Python3.7 and up, we should stick to Mypy is set to target Python3.7 for type static analysis as well. |
||
else: | ||
self.inputs.append(utxo) | ||
return self | ||
|
||
def _consolidate_redeemer(self, redeemer): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A simpler approach is make the type of this callable to take the builder as the input, like this:
Doing so, we don't need to create a lambda function in caller's code:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Only drawback is that you're now required to have a builder parameter in the callback every time. And when the callback is going to take more arguments than just the builder, you'll end up using a lambda again.
Now the lambda will need to take a builder arg too, like the following:
apply(lambda builder: add_utxos_with_ten_ada(builder, arg1, arg2)
As opposed to:
apply(lambda: add_utxos_with_ten_ada(builder1, arg1, arg2)
I think the number of times you'll have to apply additional params is a handful of cases though, so in that case it's easier with your suggestion because it avoids the lambda altogether. On the other hand lambdas can be a bit confusing and having to provide no input is also convenient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This problem could be solved by using
(*args, **kwargs)
like this:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought of this as well and tried it, but the problem is that it gives a type error.
We need to add
*args
and**kwargs
to the type signature ofcallback
. I tried looking up if there's a canonical way of doing this, but there doesn't seem to be until 3.10. AssumingAny
type does work:def apply(self, callback: Callable[[TransactionBuilder, Any, Any], None], *args, **kwargs) -> TransactionBuilder:
Not the prettiest solution😄
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, that gives a type error again when you remove the optional args from
add_utxos_with_ten_ada
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only solution to make it type correct so far seems to be
callback: Callable[..., None]
.https://stackoverflow.com/a/68472403/12541069
However, this also means TransactionBuilder is an optional arg, which it shouldn't be. Therefore I propose for now to just restrict it to TransactionBuilder as only arg, and allow no other added optional arguments in the callback:
So basically your first suggestion I think is best. A user can still add parameters if they really need to. They'll have to add a lambda in that case. But in most cases it'll just be the direct callback function without a lambda.
apply(lambda builder: add_utxos_with_ten_ada(builder, arg1, arg2)
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for experimenting these options. I don't think it is worth enforcing strict typing in this use case, because
apply
is supposed to be very generic, and we are kind of creating a problem for ourselves here. I prefer usingcallback(self, *args, **kwargs)
and put a@typing.no_type_check
decorator forapply
to bypass mypy type checking. This will make everything concise again.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, makes sense. Avoids use of lambdas altogether