New demos for Python packages (#1734)
End-to-end demos of constructing and signing an order and submitting it to a Relayer. Docs are generated from the code, and include usage examples that are verified through automated testing.
This commit is contained in:
committed by
F. Eugene Aumson
parent
28c4ca73ab
commit
3099ba71eb
4
python-packages/sra_client/.pylintrc
Normal file
4
python-packages/sra_client/.pylintrc
Normal file
@@ -0,0 +1,4 @@
|
||||
[MESSAGES CONTROL]
|
||||
disable=C0330,line-too-long,fixme,too-few-public-methods,too-many-ancestors
|
||||
# C0330 is "bad hanging indent". we use indents per `black`.
|
||||
|
@@ -1,11 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1553491629,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix regex validation on numeric values"
|
||||
"note": "Fix regex validation on numeric values",
|
||||
"pr": 1731
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1553491629
|
||||
},
|
||||
{
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added new devdependencies, and linting commands to `setup.py`. Added sphinx docs to demonstrate how to use sra_client.",
|
||||
"pr": 1734
|
||||
}
|
||||
],
|
||||
"timestamp": 1553183790
|
||||
}
|
||||
]
|
||||
|
55
python-packages/sra_client/conf.py
Normal file
55
python-packages/sra_client/conf.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Configuration file for the Sphinx documentation builder."""
|
||||
|
||||
# Reference: http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
from typing import List
|
||||
import pkg_resources
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
# because these variables are not named in upper case, as globals should be.
|
||||
|
||||
project = "0x-sra-client"
|
||||
# pylint: disable=redefined-builtin
|
||||
copyright = "2018, ZeroEx, Intl."
|
||||
author = "F. Eugene Aumson"
|
||||
version = pkg_resources.get_distribution("0x-sra-client").version
|
||||
release = "" # The full version, including alpha/beta/rc tags
|
||||
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.doctest",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.coverage",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx_autodoc_typehints",
|
||||
]
|
||||
|
||||
templates_path = ["doc_templates"]
|
||||
|
||||
source_suffix = ".rst"
|
||||
# eg: source_suffix = [".rst", ".md"]
|
||||
|
||||
master_doc = "index" # The master toctree document.
|
||||
|
||||
language = None
|
||||
|
||||
exclude_patterns: List[str] = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
html_theme = "alabaster"
|
||||
|
||||
html_static_path = ["doc_static"]
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = "sraclientpydoc"
|
||||
|
||||
# -- Extension configuration:
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {"https://docs.python.org/": None}
|
0
python-packages/sra_client/doc_static/.gitkeep
Normal file
0
python-packages/sra_client/doc_static/.gitkeep
Normal file
0
python-packages/sra_client/doc_template/.gitkeep
Normal file
0
python-packages/sra_client/doc_template/.gitkeep
Normal file
25
python-packages/sra_client/index.rst
Normal file
25
python-packages/sra_client/index.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
.. source for the sphinx-generated build/docs/web/index.html
|
||||
|
||||
Python zero_ex.sra_client.api_client
|
||||
====================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
.. automodule:: sra_client
|
||||
|
||||
----
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
.. automodule:: sra_client.api.default_api
|
||||
:members:
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
@@ -1,14 +1,16 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
"""setuptools module for sra_client package."""
|
||||
|
||||
import subprocess
|
||||
import subprocess # nosec
|
||||
import distutils.command.build_py
|
||||
|
||||
from setuptools import setup, find_packages # noqa: H301
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
NAME = "0x-sra-client"
|
||||
VERSION = "1.0.0"
|
||||
VERSION = "1.0.1"
|
||||
# To install the library, run the following
|
||||
#
|
||||
# python setup.py install
|
||||
@@ -21,6 +23,17 @@ with open("README.md", "r") as file_handle:
|
||||
|
||||
REQUIRES = ["urllib3 >= 1.15", "six >= 1.10", "certifi", "python-dateutil"]
|
||||
|
||||
|
||||
class TestCommandExtension(TestCommand):
|
||||
"""Run pytest tests."""
|
||||
|
||||
def run_tests(self):
|
||||
"""Invoke pytest."""
|
||||
import pytest
|
||||
|
||||
exit(pytest.main(["--doctest-modules"]))
|
||||
|
||||
|
||||
class TestPublishCommand(distutils.command.build_py.build_py):
|
||||
"""Custom command to publish to test.pypi.org."""
|
||||
|
||||
@@ -38,6 +51,59 @@ class TestPublishCommand(distutils.command.build_py.build_py):
|
||||
)
|
||||
|
||||
|
||||
class GanacheCommand(distutils.command.build_py.build_py):
|
||||
"""Custom command to publish to pypi.org."""
|
||||
|
||||
description = "Run ganache daemon to support tests."
|
||||
|
||||
def run(self):
|
||||
"""Run ganache."""
|
||||
cmd_line = (
|
||||
"docker run -d -p 8545:8545 0xorg/ganache-cli:2.2.2"
|
||||
).split()
|
||||
subprocess.call(cmd_line) # nosec
|
||||
|
||||
|
||||
class LaunchKitCommand(distutils.command.build_py.build_py):
|
||||
"""Custom command to boot up a local 0x-launch-kit in docker."""
|
||||
|
||||
description = "Run launch-kit daemon to support sra_client demos."
|
||||
|
||||
def run(self):
|
||||
"""Run 0x-launch-kit."""
|
||||
cmd_line = ("docker run -d -p 3000:3000 0xorg/launch-kit-ci").split()
|
||||
subprocess.call(cmd_line) # nosec
|
||||
|
||||
|
||||
class LintCommand(distutils.command.build_py.build_py):
|
||||
"""Custom setuptools command class for running linters."""
|
||||
|
||||
description = "Run linters"
|
||||
|
||||
def run(self):
|
||||
"""Run linter shell commands."""
|
||||
lint_commands = [
|
||||
# formatter:
|
||||
"black --line-length 79 --check --diff test sra_client/__init__.py setup.py".split(), # noqa: E501 (line too long)
|
||||
# style guide checker (formerly pep8):
|
||||
"pycodestyle test sra_client/__init__.py setup.py".split(),
|
||||
# docstring style checker:
|
||||
"pydocstyle src test sra_client/__init__.py setup.py".split(),
|
||||
# static type checker:
|
||||
"bandit -r test sra_client/__init__.py setup.py".split(),
|
||||
# general linter:
|
||||
"pylint test sra_client/__init__.py setup.py".split(),
|
||||
# pylint takes relatively long to run, so it runs last, to enable
|
||||
# fast failures.
|
||||
]
|
||||
|
||||
for lint_command in lint_commands:
|
||||
print(
|
||||
"Running lint command `", " ".join(lint_command).strip(), "`"
|
||||
)
|
||||
subprocess.check_call(lint_command) # nosec
|
||||
|
||||
|
||||
class PublishCommand(distutils.command.build_py.build_py):
|
||||
"""Custom command to publish to pypi.org."""
|
||||
|
||||
@@ -48,13 +114,17 @@ class PublishCommand(distutils.command.build_py.build_py):
|
||||
subprocess.check_call("twine upload dist/*".split()) # nosec
|
||||
|
||||
|
||||
class LintCommand(distutils.command.build_py.build_py):
|
||||
"""No-op lint command to support top-level lint script."""
|
||||
class PublishDocsCommand(distutils.command.build_py.build_py):
|
||||
"""Custom command to publish docs to S3."""
|
||||
|
||||
description = "No-op"
|
||||
description = (
|
||||
"Publish docs to "
|
||||
+ "http://0x-sra-demos-py.s3-website-us-east-1.amazonaws.com/"
|
||||
)
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
"""Run npm package `discharge` to build & upload docs."""
|
||||
subprocess.check_call("discharge deploy".split()) # nosec
|
||||
|
||||
|
||||
setup(
|
||||
@@ -72,6 +142,33 @@ setup(
|
||||
cmdclass={
|
||||
"test_publish": TestPublishCommand,
|
||||
"publish": PublishCommand,
|
||||
"launch_kit": LaunchKitCommand,
|
||||
"lint": LintCommand,
|
||||
"publish_docs": PublishDocsCommand,
|
||||
"test": TestCommandExtension,
|
||||
"ganache": GanacheCommand,
|
||||
},
|
||||
extras_require={
|
||||
"dev": [
|
||||
"0x-contract-addresses",
|
||||
"0x-order-utils",
|
||||
"0x-web3",
|
||||
"bandit",
|
||||
"black",
|
||||
"coverage",
|
||||
"coveralls",
|
||||
"pycodestyle",
|
||||
"pydocstyle",
|
||||
"pylint",
|
||||
"pytest",
|
||||
"sphinx",
|
||||
"sphinx-autodoc-typehints",
|
||||
]
|
||||
},
|
||||
command_options={
|
||||
"build_sphinx": {
|
||||
"source_dir": ("setup.py", "."),
|
||||
"build_dir": ("setup.py", "build/docs"),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@@ -2,6 +2,167 @@
|
||||
|
||||
# flake8: noqa
|
||||
|
||||
"""Python api client to interact with SRA compatible 0x relayers.
|
||||
|
||||
0x Protocol is an open standard. Many relayers opt-in to implementing a set of
|
||||
`standard relayer API endpoints <http://sra-spec.s3-website-us-east-1.amazonaws.com/>`_
|
||||
to make it easier for anyone to source liquidity that conforms to the 0x order format.
|
||||
Here, we will show you how you can use our `sra_client
|
||||
<https://github.com/0xProject/0x-monorepo/tree/development/python-packages/sra_client#0x-sra-client>`_
|
||||
module to interact with 0x relayers that implements the Standard Relayer API.
|
||||
|
||||
Setup
|
||||
=====
|
||||
Install the sra-client package with pip:
|
||||
|
||||
`pip install 0x-sra-client`:code:
|
||||
|
||||
To interact with a 0x Relayer, you need the HTTP endpoint of the Relayer you'd like to
|
||||
connect to (i.e. https://api.radarrelay.com/0x/v2).
|
||||
|
||||
For local testing one can use the `0x-launch-kit
|
||||
<https://github.com/0xProject/0x-launch-kit#table-of-contents/>`_
|
||||
to host orders locally. For convenience, a docker container is provided
|
||||
for just this purpose. To start it:
|
||||
|
||||
`docker run -d -p 3000:3000 0xorg/launch-kit-ci`:code:
|
||||
|
||||
and then connect to the http server running at http://localhost:3000.
|
||||
|
||||
----
|
||||
|
||||
Configure and create an API client instance
|
||||
--------------------------------------------
|
||||
|
||||
>>> from sra_client import ApiClient, Configuration
|
||||
>>> from sra_client.api import DefaultApi
|
||||
>>> config = Configuration()
|
||||
>>> config.host = "http://localhost:3000"
|
||||
>>> relayer_api = DefaultApi(ApiClient(config))
|
||||
|
||||
Post Order
|
||||
-----------
|
||||
Post an order to an SRA-compliant Relayer.
|
||||
|
||||
>>> from web3 import HTTPProvider, Web3
|
||||
>>> from zero_ex.contract_addresses import (
|
||||
... NETWORK_TO_ADDRESSES, NetworkId)
|
||||
>>> from zero_ex.order_utils import (
|
||||
... asset_data_utils,
|
||||
... generate_order_hash_hex,
|
||||
... jsdict_order_to_struct,
|
||||
... sign_hash)
|
||||
>>> provider = HTTPProvider("http://localhost:8545")
|
||||
>>> maker_address = "0x5409ed021d9299bf6814279a6a1411a7e866a631"
|
||||
>>> exchange_address = NETWORK_TO_ADDRESSES[NetworkId.KOVAN].exchange
|
||||
>>> weth_address = NETWORK_TO_ADDRESSES[NetworkId.KOVAN].ether_token
|
||||
>>> zrx_address = NETWORK_TO_ADDRESSES[NetworkId.KOVAN].zrx_token
|
||||
>>> weth_asset_data = asset_data_utils.encode_erc20_asset_data(weth_address)
|
||||
>>> zrx_asset_data = asset_data_utils.encode_erc20_asset_data(zrx_address)
|
||||
>>> example_order = {
|
||||
... "makerAddress": maker_address,
|
||||
... "takerAddress": "0x0000000000000000000000000000000000000000",
|
||||
... "senderAddress": "0x0000000000000000000000000000000000000000",
|
||||
... "exchangeAddress": exchange_address,
|
||||
... "feeRecipientAddress":
|
||||
... "0x0000000000000000000000000000000000000000",
|
||||
... "makerAssetData": weth_asset_data,
|
||||
... "takerAssetData": zrx_asset_data,
|
||||
... "salt": "2362734632784682376287462",
|
||||
... "makerFee": "0",
|
||||
... "takerFee": "0",
|
||||
... "makerAssetAmount": "1000000000000000000",
|
||||
... "takerAssetAmount": "500000000000000000000",
|
||||
... "expirationTimeSeconds": "999999999999999999999"}
|
||||
>>> order_hash = generate_order_hash_hex(
|
||||
... jsdict_order_to_struct(example_order), exchange_address)
|
||||
>>> example_order["signature"] = sign_hash(
|
||||
... provider, Web3.toChecksumAddress(maker_address), order_hash)
|
||||
>>> relayer_api.post_order_with_http_info(
|
||||
... network_id=42, signed_order_schema=example_order)[1]
|
||||
200
|
||||
|
||||
Get Orders
|
||||
-----------
|
||||
Get orders from an SRA-compliant Relayer.
|
||||
|
||||
>>> relayer_api.get_orders()
|
||||
{'records': [{'meta_data': {},
|
||||
'order': {'exchange_address': '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
|
||||
'expiration_time_seconds': '1000000000000000000000',
|
||||
'fee_recipient_address': '0x0000000000000000000000000000000000000000',
|
||||
'maker_address': '0x5409ed021d9299bf6814279a6a1411a7e866a631',
|
||||
'maker_asset_amount': '1000000000000000000',
|
||||
'maker_asset_data': '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
|
||||
'maker_fee': '0',
|
||||
'salt': '2362734632784682376287462',
|
||||
'sender_address': '0x0000000000000000000000000000000000000000',
|
||||
'taker_address': '0x0000000000000000000000000000000000000000',
|
||||
'taker_asset_amount': '500000000000000000000',
|
||||
'taker_asset_data': '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
|
||||
'taker_fee': '0'}}]}
|
||||
|
||||
Get Order
|
||||
---------
|
||||
Get an order by hash from an SRA-compliant Relayer.
|
||||
|
||||
>>> relayer_api.get_order(order_hash) # doctest: +SKIP
|
||||
{'meta_data': {},
|
||||
'order': {'exchange_address': '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
|
||||
'expiration_time_seconds': '1000000000000000000000',
|
||||
'fee_recipient_address': '0x0000000000000000000000000000000000000000',
|
||||
'maker_address': '0x5409ed021d9299bf6814279a6a1411a7e866a631',
|
||||
'maker_asset_amount': '1000000000000000000',
|
||||
'maker_asset_data': '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
|
||||
'maker_fee': '0',
|
||||
'salt': '2362734632784682376287462',
|
||||
'sender_address': '0x0000000000000000000000000000000000000000',
|
||||
'taker_address': '0x0000000000000000000000000000000000000000',
|
||||
'taker_asset_amount': '500000000000000000000',
|
||||
'taker_asset_data': '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
|
||||
'taker_fee': '0'}},
|
||||
|
||||
Get Asset Pair
|
||||
---------------
|
||||
Get available asset pairs from an SRA-compliant Relayer.
|
||||
|
||||
>>> relayer_api.get_asset_pairs()
|
||||
{'records': [{'assetDataA': {'assetData': '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
|
||||
'maxAmount': '115792089237316195423570985008687907853269984665640564039457584007913129639936',
|
||||
'minAmount': '0',
|
||||
'precision': 18},
|
||||
'assetDataB': {'assetData': '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
|
||||
'maxAmount': '115792089237316195423570985008687907853269984665640564039457584007913129639936',
|
||||
'minAmount': '0',
|
||||
'precision': 18}}]}
|
||||
|
||||
Get Orderbook
|
||||
-------------
|
||||
Get the orderbook for the WETH/ZRX asset pair from an SRA-compliant Relayer.
|
||||
|
||||
>>> relayer_api.get_orderbook(
|
||||
... base_asset_data=weth_asset_data,
|
||||
... quote_asset_data=zrx_asset_data)
|
||||
{'asks': {'records': [{'meta_data': {},
|
||||
'order': {'exchange_address': '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
|
||||
'expiration_time_seconds': '1000000000000000000000',
|
||||
'fee_recipient_address': '0x0000000000000000000000000000000000000000',
|
||||
'maker_address': '0x5409ed021d9299bf6814279a6a1411a7e866a631',
|
||||
'maker_asset_amount': '1000000000000000000',
|
||||
'maker_asset_data': '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
|
||||
'maker_fee': '0',
|
||||
'salt': '2362734632784682376287462',
|
||||
'sender_address': '0x0000000000000000000000000000000000000000',
|
||||
'taker_address': '0x0000000000000000000000000000000000000000',
|
||||
'taker_asset_amount': '500000000000000000000',
|
||||
'taker_asset_data': '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
|
||||
'taker_fee': '0'}}]},
|
||||
'bids': {'records': []}}
|
||||
""" # noqa: E501 (line too long)
|
||||
|
||||
# NOTE: Bug in get_order method.
|
||||
# Sra_client not deserialzing order from server properly, need fix!
|
||||
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
@@ -28,7 +189,7 @@ from sra_client.models.relayer_api_asset_data_trade_info_schema import (
|
||||
from sra_client.models.relayer_api_error_response_schema import (
|
||||
RelayerApiErrorResponseSchema,
|
||||
)
|
||||
from sra_client.models.relayer_api_error_response_schema_validation_errors import (
|
||||
from sra_client.models.relayer_api_error_response_schema_validation_errors import ( # noqa: E501 (line too long)
|
||||
RelayerApiErrorResponseSchemaValidationErrors,
|
||||
)
|
||||
from sra_client.models.relayer_api_fee_recipients_response_schema import (
|
||||
@@ -44,7 +205,7 @@ from sra_client.models.relayer_api_order_schema import RelayerApiOrderSchema
|
||||
from sra_client.models.relayer_api_orderbook_response_schema import (
|
||||
RelayerApiOrderbookResponseSchema,
|
||||
)
|
||||
from sra_client.models.relayer_api_orders_channel_subscribe_payload_schema import (
|
||||
from sra_client.models.relayer_api_orders_channel_subscribe_payload_schema import ( # noqa: E501 (line too long)
|
||||
RelayerApiOrdersChannelSubscribePayloadSchema,
|
||||
)
|
||||
from sra_client.models.relayer_api_orders_channel_subscribe_schema import (
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -207,8 +207,7 @@ class ApiClient(object):
|
||||
|
||||
If obj is None, return None.
|
||||
If obj is str, int, long, float, bool, return directly.
|
||||
If obj is datetime.datetime, datetime.date
|
||||
convert to string in iso8601 format.
|
||||
If obj is datetime.datetime, datetime.date convert to string in iso8601 format.
|
||||
If obj is list, sanitize each element in the list.
|
||||
If obj is dict, return the dict.
|
||||
If obj is OpenAPI model, return the properties dict.
|
||||
|
@@ -0,0 +1 @@
|
||||
"""Test for sra_client."""
|
||||
|
@@ -1,3 +1,4 @@
|
||||
"""Test the default api client"""
|
||||
# coding: utf-8
|
||||
|
||||
|
||||
@@ -5,30 +6,92 @@ from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import sra_client
|
||||
from sra_client.api.default_api import DefaultApi # noqa: E501
|
||||
from sra_client.models.relayer_api_asset_data_pairs_response_schema import (
|
||||
RelayerApiAssetDataPairsResponseSchema
|
||||
)
|
||||
from sra_client.rest import ApiException
|
||||
from sra_client import ApiClient, Configuration
|
||||
from sra_client.api import DefaultApi
|
||||
|
||||
|
||||
class TestDefaultApi(unittest.TestCase):
|
||||
"""DefaultApi unit test stubs"""
|
||||
|
||||
def setUp(self):
|
||||
self.api = sra_client.api.default_api.DefaultApi() # noqa: E501
|
||||
config = Configuration()
|
||||
config.host = "http://localhost:3000"
|
||||
self.api = DefaultApi(ApiClient(config))
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
# pylint: disable=too-many-locals
|
||||
def test_get_asset_pairs(self):
|
||||
"""Test case for get_asset_pairs
|
||||
|
||||
"""
|
||||
expected = RelayerApiAssetDataPairsResponseSchema([])
|
||||
expected = {
|
||||
"records": [
|
||||
{
|
||||
"assetDataA": {
|
||||
"assetData": "0xf47261b0000000000000000000000000"
|
||||
"d0a1e359811322d97991e03f863a0c30c2cf029c",
|
||||
"maxAmount": "115792089237316195423570985008687907853"
|
||||
"269984665640564039457584007913129639936",
|
||||
"minAmount": "0",
|
||||
"precision": 18,
|
||||
},
|
||||
"assetDataB": {
|
||||
"assetData": "0xf47261b0000000000000000000000000"
|
||||
"2002d3812f58e35f0ea1ffbf80a75a38c32175fa",
|
||||
"maxAmount": "115792089237316195423570985008687907853"
|
||||
"269984665640564039457584007913129639936",
|
||||
"minAmount": "0",
|
||||
"precision": 18,
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
actual = self.api.get_asset_pairs()
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
acutal_asset_data_a = actual.records[0]["assetDataA"]["assetData"]
|
||||
expected_asset_data_a = expected["records"][0]["assetDataA"][
|
||||
"assetData"
|
||||
]
|
||||
self.assertEqual(acutal_asset_data_a, expected_asset_data_a)
|
||||
acutal_max_amount_a = actual.records[0]["assetDataA"]["maxAmount"]
|
||||
expected_max_amount_a = expected["records"][0]["assetDataA"][
|
||||
"maxAmount"
|
||||
]
|
||||
self.assertEqual(acutal_max_amount_a, expected_max_amount_a)
|
||||
acutal_min_amount_a = actual.records[0]["assetDataA"]["minAmount"]
|
||||
expected_min_amount_a = expected["records"][0]["assetDataA"][
|
||||
"minAmount"
|
||||
]
|
||||
self.assertEqual(acutal_min_amount_a, expected_min_amount_a)
|
||||
acutal_precision_a = actual.records[0]["assetDataA"]["precision"]
|
||||
expected_precision_a = expected["records"][0]["assetDataA"][
|
||||
"precision"
|
||||
]
|
||||
self.assertEqual(acutal_precision_a, expected_precision_a)
|
||||
|
||||
acutal_asset_data_b = actual.records[0]["assetDataB"]["assetData"]
|
||||
expected_asset_data_b = expected["records"][0]["assetDataB"][
|
||||
"assetData"
|
||||
]
|
||||
self.assertEqual(acutal_asset_data_b, expected_asset_data_b)
|
||||
acutal_max_amount_b = actual.records[0]["assetDataB"]["maxAmount"]
|
||||
expected_max_amount_b = expected["records"][0]["assetDataB"][
|
||||
"maxAmount"
|
||||
]
|
||||
self.assertEqual(acutal_max_amount_b, expected_max_amount_b)
|
||||
acutal_min_amount_b = actual.records[0]["assetDataB"]["minAmount"]
|
||||
expected_min_amount_b = expected["records"][0]["assetDataB"][
|
||||
"minAmount"
|
||||
]
|
||||
self.assertEqual(acutal_min_amount_b, expected_min_amount_b)
|
||||
acutal_precision_b = actual.records[0]["assetDataB"]["precision"]
|
||||
expected_precision_b = expected["records"][0]["assetDataB"][
|
||||
"precision"
|
||||
]
|
||||
self.assertEqual(acutal_precision_b, expected_precision_b)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Reference in New Issue
Block a user