Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.

Commit 852d0b3

Browse files
authored
Merge pull request #16 from iotaledger/develop
1.0.0b7
2 parents 2f2fc47 + a952049 commit 852d0b3

24 files changed

+626
-757
lines changed

examples/shell.py

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,25 @@
77

88
from argparse import ArgumentParser
99
from getpass import getpass as secure_input
10-
from sys import argv
10+
from logging import INFO, basicConfig, getLogger
11+
from sys import argv, stderr
1112

12-
from iota import __version__
1313
from six import text_type
1414

1515
# Import all IOTA symbols into module scope, so that it's more
1616
# convenient for the user.
1717
from iota import *
1818

19+
from iota import __version__
20+
from iota.adapter import resolve_adapter
21+
from iota.adapter.wrappers import LogWrapper, RoutingWrapper
22+
1923

20-
def main(uri, testnet):
24+
basicConfig(level=INFO, stream=stderr)
25+
26+
27+
def main(uri, testnet, pow_uri, debug_requests):
28+
# type: (Text, bool, Text, bool) -> None
2129
seed = secure_input(
2230
'Enter seed and press return (typing will not be shown).\n'
2331
'If no seed is specified, a random one will be used instead.\n'
@@ -26,7 +34,17 @@ def main(uri, testnet):
2634
if isinstance(seed, text_type):
2735
seed = seed.encode('ascii')
2836

29-
iota = Iota(uri, seed=seed, testnet=testnet)
37+
# If ``pow_uri`` is specified, route POW requests to a separate node.
38+
adapter_ = create_adapter(uri, debug_requests)
39+
if pow_uri:
40+
pow_adapter = create_adapter(pow_uri, debug_requests)
41+
42+
adapter_ =\
43+
RoutingWrapper(adapter_)\
44+
.add_route('attachToTangle', pow_adapter)\
45+
.add_route('interruptAttachingToTangle', pow_adapter)
46+
47+
iota = Iota(adapter_, seed=seed, testnet=testnet)
3048

3149
_banner = (
3250
'IOTA API client for {uri} ({testnet}) initialized as variable `iota`.\n'
@@ -39,6 +57,26 @@ def main(uri, testnet):
3957
start_shell(iota, _banner)
4058

4159

60+
def create_adapter(uri, debug):
61+
# type: (Text, bool) -> BaseAdapter
62+
"""
63+
Creates an adapter with the specified settings.
64+
65+
:param uri:
66+
Node URI.
67+
68+
:param debug:
69+
Whether to attach a LogWrapper to the adapter.
70+
"""
71+
adapter_ = resolve_adapter(uri)
72+
73+
return (
74+
LogWrapper(adapter_, getLogger(__name__), INFO)
75+
if debug
76+
else adapter_
77+
)
78+
79+
4280
def start_shell(iota, _banner):
4381
"""
4482
Starts the shell with limited scope.
@@ -71,11 +109,27 @@ def start_shell(iota, _banner):
71109
'(defaults to udp://localhost:14265/).',
72110
)
73111

112+
parser.add_argument(
113+
'--pow-uri',
114+
type = text_type,
115+
default = None,
116+
dest = 'pow_uri',
117+
help = 'URI of node to send POW requests to.'
118+
)
119+
74120
parser.add_argument(
75121
'--testnet',
76122
action = 'store_true',
77123
default = False,
78-
help = 'If specified, use testnet settings (e.g., for PoW).',
124+
help = 'If set, use testnet settings (e.g., for PoW).',
125+
)
126+
127+
parser.add_argument(
128+
'--debug',
129+
action = 'store_true',
130+
default = False,
131+
dest = 'debug_requests',
132+
help = 'If set, log HTTP requests to stderr.'
79133
)
80134

81135
main(**vars(parser.parse_args(argv[1:])))

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
name = 'PyOTA',
2929
description = 'IOTA API library for Python',
3030
url = 'https://github.com/iotaledger/iota.lib.py',
31-
version = '1.0.0b6',
31+
version = '1.0.0b7',
3232

3333
packages = find_packages('src'),
3434
include_package_data = True,

src/iota/adapter/wrappers.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44

55
from abc import ABCMeta, abstractmethod as abstract_method
66
from logging import INFO, Logger
7+
from typing import Dict, Text
78

8-
from iota.adapter import AdapterSpec, BaseAdapter, resolve_adapter
99
from six import with_metaclass
1010

11+
from iota.adapter import AdapterSpec, BaseAdapter, resolve_adapter
12+
1113
__all__ = [
1214
'LogWrapper',
15+
'RoutingWrapper',
1316
]
1417

1518

16-
class BaseWrapper(with_metaclass(ABCMeta)):
19+
class BaseWrapper(with_metaclass(ABCMeta, BaseAdapter)):
1720
"""
1821
Base functionality for "adapter wrappers", used to extend the
1922
functionality of IOTA adapters.
@@ -68,3 +71,69 @@ def send_request(self, payload, **kwargs):
6871
))
6972

7073
return response
74+
75+
76+
class RoutingWrapper(BaseWrapper):
77+
"""
78+
Routes commands to different nodes.
79+
80+
This allows you to, for example, send POW requests to a local node,
81+
while routing all other requests to a remote one.
82+
83+
Example::
84+
85+
# Route POW to localhost, everything else to 12.34.56.78.
86+
iota = Iota(
87+
RoutingWrapper('http://12.34.56.78:14265')
88+
.add_route('attachToTangle', 'http://localhost:14265')
89+
.add_route('interruptAttachingToTangle', 'http://localhost:14265')
90+
),
91+
)
92+
"""
93+
def __init__(self, default_adapter):
94+
# type: (AdapterSpec) -> None
95+
"""
96+
:param default_adapter:
97+
Adapter to use for any routes not listed in ``routes``.
98+
"""
99+
super(RoutingWrapper, self).__init__(default_adapter)
100+
101+
# Try to limit the number of distinct adapter instances we create
102+
# when resolving URIs.
103+
self.adapter_aliases = {} # type: Dict[AdapterSpec, BaseAdapter]
104+
105+
self.routes = {} # type: Dict[Text, BaseAdapter]
106+
107+
def add_route(self, command, adapter):
108+
# type: (Text, AdapterSpec) -> RoutingWrapper
109+
"""
110+
Adds a route to the wrapper.
111+
112+
:param command:
113+
The name of the command to route (e.g., "attachToTangle").
114+
115+
:param adapter:
116+
The adapter object or URI to route requests to.
117+
"""
118+
if not isinstance(adapter, BaseAdapter):
119+
try:
120+
adapter = self.adapter_aliases[adapter]
121+
except KeyError:
122+
self.adapter_aliases[adapter] = adapter = resolve_adapter(adapter)
123+
124+
self.routes[command] = adapter
125+
126+
return self
127+
128+
def get_adapter(self, command):
129+
# type: (Text) -> BaseAdapter
130+
"""
131+
Return the adapter for the specified command.
132+
"""
133+
return self.routes.get(command, self.adapter)
134+
135+
def send_request(self, payload, **kwargs):
136+
# type: (dict, dict) -> dict
137+
command = payload.get('command')
138+
139+
return self.get_adapter(command).send_request(payload, **kwargs)

src/iota/api.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ def attach_to_tangle(
112112
min_weight_magnitude = self.default_min_weight_magnitude
113113

114114
return self.attachToTangle(
115-
trunk_transaction = trunk_transaction,
116-
branch_transaction = branch_transaction,
117-
min_weight_magnitude = min_weight_magnitude,
118-
trytes = trytes,
115+
trunkTransaction = trunk_transaction,
116+
branchTransaction = branch_transaction,
117+
minWeightMagnitude = min_weight_magnitude,
118+
trytes = trytes,
119119
)
120120

121121
def broadcast_transactions(self, trytes):
@@ -524,10 +524,10 @@ def get_transfers(self, start=0, stop=None, inclusion_states=False):
524524
- https://github.com/iotaledger/wiki/blob/master/api-proposal.md#gettransfers
525525
"""
526526
return self.getTransfers(
527-
seed = self.seed,
528-
start = start,
529-
stop = stop,
530-
inclusion_states = inclusion_states,
527+
seed = self.seed,
528+
start = start,
529+
stop = stop,
530+
inclusionStates = inclusion_states,
531531
)
532532

533533
def prepare_transfer(self, transfers, inputs=None, change_address=None):
@@ -567,10 +567,10 @@ def prepare_transfer(self, transfers, inputs=None, change_address=None):
567567
- https://github.com/iotaledger/wiki/blob/master/api-proposal.md#preparetransfers
568568
"""
569569
return self.prepareTransfer(
570-
seed = self.seed,
571-
transfers = transfers,
572-
inputs = inputs,
573-
change_address = change_address,
570+
seed = self.seed,
571+
transfers = transfers,
572+
inputs = inputs,
573+
changeAddress = change_address,
574574
)
575575

576576
def replay_bundle(
@@ -607,9 +607,9 @@ def replay_bundle(
607607
min_weight_magnitude = self.default_min_weight_magnitude
608608

609609
return self.replayBundle(
610-
transaction = transaction,
611-
depth = depth,
612-
min_weight_magnitude = min_weight_magnitude,
610+
transaction = transaction,
611+
depth = depth,
612+
minWeightMagnitude = min_weight_magnitude,
613613
)
614614

615615
def send_transfer(
@@ -659,12 +659,12 @@ def send_transfer(
659659
min_weight_magnitude = self.default_min_weight_magnitude
660660

661661
return self.sendTransfer(
662-
seed = self.seed,
663-
depth = depth,
664-
transfers = transfers,
665-
inputs = inputs,
666-
change_address = change_address,
667-
min_weight_magnitude = min_weight_magnitude,
662+
seed = self.seed,
663+
depth = depth,
664+
transfers = transfers,
665+
inputs = inputs,
666+
changeAddress = change_address,
667+
minWeightMagnitude = min_weight_magnitude,
668668
)
669669

670670
def send_trytes(self, trytes, depth, min_weight_magnitude=18):
@@ -690,7 +690,7 @@ def send_trytes(self, trytes, depth, min_weight_magnitude=18):
690690
- https://github.com/iotaledger/wiki/blob/master/api-proposal.md#sendtrytes
691691
"""
692692
return self.sendTrytes(
693-
trytes = trytes,
694-
depth = depth,
695-
min_weight_magnitude = min_weight_magnitude,
693+
trytes = trytes,
694+
depth = depth,
695+
minWeightMagnitude = min_weight_magnitude,
696696
)

src/iota/commands/core/attach_to_tangle.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ def get_response_filter(self):
3030
class AttachToTangleRequestFilter(RequestFilter):
3131
def __init__(self):
3232
super(AttachToTangleRequestFilter, self).__init__({
33-
'branch_transaction': f.Required | Trytes(result_type=TransactionHash),
34-
'trunk_transaction': f.Required | Trytes(result_type=TransactionHash),
33+
'branchTransaction': f.Required | Trytes(result_type=TransactionHash),
34+
'trunkTransaction': f.Required | Trytes(result_type=TransactionHash),
3535

3636
'trytes':
3737
f.Required
@@ -40,12 +40,16 @@ def __init__(self):
4040

4141
# Loosely-validated; testnet nodes require a different value than
4242
# mainnet.
43-
'min_weight_magnitude': f.Required| f.Type(int) | f.Min(1),
43+
'minWeightMagnitude': f.Required| f.Type(int) | f.Min(1),
4444
})
4545

4646

4747
class AttachToTangleResponseFilter(ResponseFilter):
4848
def __init__(self):
4949
super(AttachToTangleResponseFilter, self).__init__({
50-
'trytes': f.FilterRepeater(f.ByteString(encoding='ascii') | Trytes),
50+
'trytes':
51+
f.FilterRepeater(
52+
f.ByteString(encoding='ascii')
53+
| Trytes(result_type=TransactionTrytes)
54+
),
5155
})

src/iota/commands/core/broadcast_transactions.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
unicode_literals
44

55
import filters as f
6+
67
from iota import TransactionTrytes
7-
from iota.commands import FilterCommand, RequestFilter, ResponseFilter
8+
from iota.commands import FilterCommand, RequestFilter
89
from iota.filters import Trytes
910

1011
__all__ = [
@@ -24,7 +25,7 @@ def get_request_filter(self):
2425
return BroadcastTransactionsRequestFilter()
2526

2627
def get_response_filter(self):
27-
return BroadcastTransactionsResponseFilter()
28+
pass
2829

2930

3031
class BroadcastTransactionsRequestFilter(RequestFilter):
@@ -35,10 +36,3 @@ def __init__(self):
3536
| f.Array
3637
| f.FilterRepeater(f.Required | Trytes(result_type=TransactionTrytes)),
3738
})
38-
39-
40-
class BroadcastTransactionsResponseFilter(ResponseFilter):
41-
def __init__(self):
42-
super(BroadcastTransactionsResponseFilter, self).__init__({
43-
'trytes': f.FilterRepeater(f.ByteString(encoding='ascii') | Trytes),
44-
})

src/iota/commands/extended/broadcast_and_store.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,7 @@ def get_response_filter(self):
2828

2929
def _execute(self, request):
3030
BroadcastTransactionsCommand(self.adapter)(**request)
31-
return StoreTransactionsCommand(self.adapter)(**request)
31+
StoreTransactionsCommand(self.adapter)(**request)
32+
return {
33+
'trytes': request['trytes'],
34+
}

src/iota/commands/extended/get_transfers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def get_response_filter(self):
3737

3838
def _execute(self, request):
3939
stop = request['stop'] # type: Optional[int]
40-
inclusion_states = request['inclusion_states'] # type: bool
40+
inclusion_states = request['inclusionStates'] # type: bool
4141
seed = request['seed'] # type: Seed
4242
start = request['start'] # type: int
4343

@@ -165,12 +165,12 @@ def __init__(self):
165165
'stop': f.Type(int) | f.Min(0),
166166
'start': f.Type(int) | f.Min(0) | f.Optional(0),
167167

168-
'inclusion_states': f.Type(bool) | f.Optional(False),
168+
'inclusionStates': f.Type(bool) | f.Optional(False),
169169
},
170170

171171
allow_missing_keys = {
172172
'stop',
173-
'inclusion_states',
173+
'inclusionStates',
174174
'start',
175175
},
176176
)

0 commit comments

Comments
 (0)