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

Commit 9389d17

Browse files
authored
Merge pull request #119 from iotaledger/release/2.0.3
Release/2.0.3
2 parents ac6167d + f4356bc commit 9389d17

25 files changed

+1793
-266
lines changed

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
include docs/conf.py
2+
include docs/make.bat
3+
include docs/Makefile
14
include LICENSE
25
include README.rst
6+
recursive-include docs *.rst
37
recursive-include examples *.py
48
recursive-include test *.py *.csv

README.rst

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@ To install this extension, use the following command::
4545
pip install pyota[ccurl]
4646

4747

48+
.. _readme-installing-from-source:
49+
4850
Installing from Source
4951
======================
5052

51-
1. `Create virtualenv`_ (recommended, but not required).
52-
2. ``git clone https://github.com/iotaledger/iota.lib.py.git``
53-
3. ``pip install -e .``
53+
#. `Create virtualenv`_ (recommended, but not required).
54+
#. ``git clone https://github.com/iotaledger/iota.lib.py.git``
55+
#. ``pip install -e .``
5456

5557
Running Unit Tests
5658
------------------
@@ -66,12 +68,33 @@ PyOTA is also compatible with `tox`_::
6668
=============
6769
Documentation
6870
=============
69-
For the full documentation of this library, please refer to the
70-
`official API`_
71+
PyOTA's documentation is available on `ReadTheDocs`_.
72+
73+
If you are :ref:`installing from source <readme-installing-from-source>`, you
74+
can also build the documentation locally:
75+
76+
#. Install extra dependencies (you only have to do this once)::
77+
78+
pip install '.[docs-builder]'
79+
80+
.. tip::
81+
82+
To install the CCurl extension and the documentation builder tools
83+
together, use the following command::
84+
85+
pip install '.[ccurl,docs-builder]'
86+
87+
#. Switch to the ``docs`` directory::
88+
89+
cd docs
90+
91+
#. Build the documentation::
7192

93+
make html
7294

7395
.. _Create virtualenv: https://realpython.com/blog/python/python-virtual-environments-a-primer/
7496
.. _PyOTA Bug Tracker: https://github.com/iotaledger/iota.lib.py/issues
97+
.. _ReadTheDocs: https://pyota.readthedocs.io/
7598
.. _Slack: https://slack.iota.org/
7699
.. _dedicated forum: https://forum.iota.org/
77100
.. _official API: https://iota.readme.io/

docs/adapters.rst

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
Adapters and Wrappers
2+
=====================
3+
4+
The ``Iota`` class defines the API methods that are available for
5+
interacting with the node, but it delegates the actual interaction to
6+
another set of classes: Adapters and Wrappers.
7+
8+
AdapterSpec
9+
-----------
10+
11+
In a few places in the PyOTA codebase, you may see references to a
12+
meta-type called ``AdapterSpec``.
13+
14+
``AdapterSpec`` is a placeholder that means "URI or adapter instance".
15+
16+
For example, the first argument of ``Iota.__init__`` is an
17+
``AdapterSpec``. This means that you can initialize an ``Iota`` object
18+
using either a node URI, or an adapter instance:
19+
20+
- Node URI: ``Iota('http://localhost:14265')``
21+
- Adapter instance: ``Iota(HttpAdapter('http://localhost:14265'))``
22+
23+
Adapters
24+
--------
25+
26+
Adapters are responsible for sending requests to the node and returning
27+
the response.
28+
29+
PyOTA ships with a few adapters:
30+
31+
HttpAdapter
32+
~~~~~~~~~~~
33+
34+
.. code:: python
35+
36+
from iota import Iota
37+
from iota.adapter import HttpAdapter
38+
39+
# Use HTTP:
40+
api = Iota('http://localhost:14265')
41+
api = Iota(HttpAdapter('http://localhost:14265'))
42+
43+
# Use HTTPS:
44+
api = Iota('https://service.iotasupport.com:14265')
45+
api = Iota(HttpAdapter('https://service.iotasupport.com:14265'))
46+
47+
``HttpAdapter`` uses the HTTP protocol to send requests to the node.
48+
49+
To configure an ``Iota`` instance to use ``HttpAdapter``, specify an
50+
``http://`` or ``https://`` URI, or provide an ``HttpAdapter`` instance.
51+
52+
The ``HttpAdapter`` raises a ``BadApiResponse`` exception if the server
53+
sends back an error response (due to invalid request parameters, for
54+
example).
55+
56+
Debugging HTTP Requests
57+
^^^^^^^^^^^^^^^^^^^^^^^
58+
59+
.. code:: python
60+
61+
from logging import getLogger
62+
63+
from iota import Iota
64+
65+
api = Iota('http://localhost:14265')
66+
api.adapter.set_logger(getLogger(__name__))
67+
68+
To see all HTTP requests and responses as they happen, attach a
69+
``logging.Logger`` instance to the adapter via its ``set_logger``
70+
method.
71+
72+
Any time the ``HttpAdapter`` sends a request or receives a response, it
73+
will first generate a log message. Note: if the response is an error
74+
response (e.g., due to invalid request parameters), the ``HttpAdapter``
75+
will log the request before raising ``BadApiResponse``.
76+
77+
.. note::
78+
79+
``HttpAdapter`` generates log messages with ``DEBUG`` level, so make sure that your logger's ``level`` attribute is set low enough that it doesn't filter these messages!
80+
81+
SandboxAdapter
82+
~~~~~~~~~~~~~~
83+
84+
.. code:: python
85+
86+
from iota import Iota
87+
from iota.adapter.sandbox import SandboxAdapter
88+
89+
api =\
90+
Iota(
91+
SandboxAdapter(
92+
uri = 'https://sandbox.iotatoken.com/api/v1/',
93+
auth_token = 'demo7982-be4a-4afa-830e-7859929d892c',
94+
),
95+
)
96+
97+
The ``SandboxAdapter`` is a specialized ``HttpAdapter`` that sends
98+
authenticated requests to sandbox nodes.
99+
100+
.. note::
101+
102+
See `Sandbox <https://dev.iota.org/sandbox/>`_ Documentation for more information about sandbox nodes.
103+
104+
Sandbox nodes process certain commands asynchronously. When
105+
``SandboxAdapter`` determines that a request is processed
106+
asynchronously, it will block, then poll the node periodically until it
107+
receives a response.
108+
109+
The result is that ``SandboxAdapter`` abstracts away the sandbox node's
110+
asynchronous functionality so that your API client behaves exactly the
111+
same as if it were connecting to a non-sandbox node.
112+
113+
To create a ``SandboxAdapter``, you must provide the URI of the sandbox
114+
node and the auth token that you received from the node maintainer. Note
115+
that ``SandboxAdapter`` only works with ``http://`` and ``https://``
116+
URIs.
117+
118+
You may also specify the polling interval (defaults to 15 seconds) and
119+
the number of polls before giving up on an asynchronous job (defaults to
120+
8 times).
121+
122+
.. note::
123+
124+
For parity with the other adapters, ``SandboxAdapter`` blocks until it receives a response from the node.
125+
126+
If you do not want ``SandboxAdapter`` to block the main thread, it is recommended that you execute it in a separate thread or process.
127+
128+
129+
MockAdapter
130+
~~~~~~~~~~~
131+
132+
.. code:: python
133+
134+
from iota import Iota
135+
from iota.adapter import MockAdapter
136+
137+
# Inject a mock adapter.
138+
api = Iota('mock://')
139+
api = Iota(MockAdapter())
140+
141+
# Seed responses from the node.
142+
api.adapter.seed_response('getNodeInfo', {'message': 'Hello, world!'})
143+
api.adapter.seed_response('getNodeInfo', {'message': 'Hello, IOTA!'})
144+
145+
# Invoke API commands, using the adapter.
146+
print(api.get_node_info()) # {'message': 'Hello, world!'}
147+
print(api.get_node_info()) # {'message': 'Hello, IOTA!'}
148+
print(api.get_node_info()) # raises BadApiResponse exception
149+
150+
``MockAdapter`` is used to simulate the behavior of an adapter without
151+
actually sending any requests to the node.
152+
153+
This is particularly useful in unit and functional tests where you want
154+
to verify that your code works correctly in specific scenarios, without
155+
having to engineer your own subtangle.
156+
157+
To configure an ``Iota`` instance to use ``MockAdapter``, specify
158+
``mock://`` as the node URI, or provide a ``MockAdapter`` instance.
159+
160+
To use ``MockAdapter``, you must first seed the responses that you want
161+
it to return by calling its ``seed_response`` method.
162+
163+
``seed_response`` takes two parameters:
164+
165+
- ``command: Text``: The name of the command. Note that this is the
166+
camelCase version of the command name (e.g., ``getNodeInfo``, not
167+
``get_node_info``).
168+
- ``response: dict``: The response that the adapter will return.
169+
170+
You can seed multiple responses for the same command; the
171+
``MockAdapter`` maintains a queue for each command internally, and it
172+
will pop a response off of the corresponding queue each time it
173+
processes a request.
174+
175+
Note that you have to call ``seed_response`` once for each request you
176+
expect it to process. If ``MockAdapter`` does not have a seeded response
177+
for a particular command, it will raise a ``BadApiResponse`` exception
178+
(simulates a 404 response).
179+
180+
Wrappers
181+
--------
182+
183+
Wrappers act like decorators for adapters; they are used to enhance or
184+
otherwise modify the behavior of adapters.
185+
186+
RoutingWrapper
187+
~~~~~~~~~~~~~~
188+
189+
.. code:: python
190+
191+
from iota import Iota
192+
from iota.adapter.wrappers import RoutingWrapper
193+
194+
api =\
195+
Iota(
196+
# Send PoW requests to local node.
197+
# All other requests go to light wallet node.
198+
RoutingWrapper('https://service.iotasupport.com:14265')
199+
.add_route('attachToTangle', 'http://localhost:14265')
200+
.add_route('interruptAttachingToTangle', 'http://localhost:14265')
201+
)
202+
203+
``RoutingWrapper`` allows you to route API requests to different nodes
204+
depending on the command name.
205+
206+
For example, you could use this wrapper to direct all PoW requests to a
207+
local node, while sending the other requests to a light wallet node.
208+
209+
``RoutingWrapper`` must be initialized with a default URI/adapter. This
210+
is the adapter that will be used for any command that doesn't have a
211+
route associated with it.
212+
213+
Once you've initialized the ``RoutingWrapper``, invoke its ``add_route``
214+
method to specify a different adapter to use for a particular command.
215+
216+
``add_route`` requires two arguments:
217+
218+
- ``command: Text``: The name of the command. Note that this is the
219+
camelCase version of the command name (e.g., ``getNodeInfo``, not
220+
``get_node_info``).
221+
- ``adapter: AdapterSpec``: The adapter or URI to send this request to.

0 commit comments

Comments
 (0)