aboutsummaryrefslogtreecommitdiffstats
path: root/python-packages/contract_demo
diff options
context:
space:
mode:
Diffstat (limited to 'python-packages/contract_demo')
-rw-r--r--python-packages/contract_demo/.discharge.json13
-rw-r--r--python-packages/contract_demo/README.md39
-rwxr-xr-xpython-packages/contract_demo/setup.py146
-rw-r--r--python-packages/contract_demo/stubs/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/command/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/command/clean.pyi7
-rw-r--r--python-packages/contract_demo/stubs/distutils/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/distutils/command/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/distutils/command/clean.pyi7
-rw-r--r--python-packages/contract_demo/stubs/eth_utils/__init__.pyi4
-rw-r--r--python-packages/contract_demo/stubs/pytest/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/setuptools/__init__.pyi8
-rw-r--r--python-packages/contract_demo/stubs/setuptools/command/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/setuptools/command/test.pyi3
-rw-r--r--python-packages/contract_demo/stubs/web3/__init__.pyi2
-rw-r--r--python-packages/contract_demo/stubs/web3/utils/__init__.pyi0
-rw-r--r--python-packages/contract_demo/stubs/web3/utils/datatypes.pyi3
-rw-r--r--python-packages/contract_demo/test/__init__.py1
-rw-r--r--python-packages/contract_demo/test/conf.py54
-rw-r--r--python-packages/contract_demo/test/doc_static/.gitkeep0
-rw-r--r--python-packages/contract_demo/test/index.rst18
-rw-r--r--python-packages/contract_demo/test/test_exchange.py65
22 files changed, 370 insertions, 0 deletions
diff --git a/python-packages/contract_demo/.discharge.json b/python-packages/contract_demo/.discharge.json
new file mode 100644
index 000000000..9d811ae3e
--- /dev/null
+++ b/python-packages/contract_demo/.discharge.json
@@ -0,0 +1,13 @@
+{
+ "domain": "0x-contract-demo-py",
+ "build_command": "python setup.py build_sphinx",
+ "upload_directory": "build/docs/html",
+ "index_key": "index.html",
+ "error_key": "index.html",
+ "trailing_slashes": true,
+ "cache": 3600,
+ "aws_profile": "default",
+ "aws_region": "us-east-1",
+ "cdn": false,
+ "dns_configured": true
+}
diff --git a/python-packages/contract_demo/README.md b/python-packages/contract_demo/README.md
new file mode 100644
index 000000000..3a0f964e3
--- /dev/null
+++ b/python-packages/contract_demo/README.md
@@ -0,0 +1,39 @@
+## 0x-contract-demo
+
+A demonstration of calling 0x smart contracts from Python.
+
+Read the [documentation](http://0x-contract-demo-py.s3-website-us-east-1.amazonaws.com/)
+
+## Contributing
+
+We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
+
+Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
+
+### Install Code and Dependencies
+
+Ensure that you have installed Python >=3.6 and Docker. Then:
+
+```bash
+pip install -e .[dev]
+```
+
+### Test
+
+Tests depend on a running ganache instance with the 0x contracts deployed in it. For convenience, a docker container is provided that has ganache-cli and a snapshot containing the necessary contracts. A shortcut is provided to run that docker container: `./setup.py ganache`. With that running, the tests can be run with `./setup.py test`.
+
+### Clean
+
+`./setup.py clean --all`
+
+### Lint
+
+`./setup.py lint`
+
+### Build Documentation
+
+`./setup.py build_sphinx`
+
+### More
+
+See `./setup.py --help-commands` for more info.
diff --git a/python-packages/contract_demo/setup.py b/python-packages/contract_demo/setup.py
new file mode 100755
index 000000000..a7afbd30c
--- /dev/null
+++ b/python-packages/contract_demo/setup.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+
+"""setuptools module for 0x-contract-demo package."""
+
+import distutils.command.build_py
+from distutils.command.clean import clean
+import subprocess # nosec
+from shutil import rmtree
+from os import environ, path
+from sys import argv
+
+from setuptools import setup
+from setuptools.command.test import test as TestCommand
+
+
+class TestCommandExtension(TestCommand):
+ """Run pytest tests."""
+
+ def run_tests(self):
+ """Invoke pytest."""
+ import pytest
+
+ exit(pytest.main())
+
+
+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 setup.py".split(),
+ # style guide checker (formerly pep8):
+ "pycodestyle test setup.py".split(),
+ # docstring style checker:
+ "pydocstyle test setup.py".split(),
+ # static type checker:
+ "mypy test setup.py".split(),
+ # security issue checker:
+ "bandit -r ./setup.py".split(),
+ # general linter:
+ "pylint test setup.py".split(),
+ # pylint takes relatively long to run, so it runs last, to enable
+ # fast failures.
+ ]
+
+ # tell mypy where to find interface stubs for 3rd party libs
+ environ["MYPYPATH"] = path.join(
+ path.dirname(path.realpath(argv[0])), "stubs"
+ )
+
+ for lint_command in lint_commands:
+ print(
+ "Running lint command `", " ".join(lint_command).strip(), "`"
+ )
+ subprocess.check_call(lint_command) # nosec
+
+
+class CleanCommandExtension(clean):
+ """Custom command to do custom cleanup."""
+
+ def run(self):
+ """Run the regular clean, followed by our custom commands."""
+ super().run()
+ rmtree(".mypy_cache", ignore_errors=True)
+ rmtree(".tox", ignore_errors=True)
+ rmtree(".pytest_cache", ignore_errors=True)
+
+
+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 PublishDocsCommand(distutils.command.build_py.build_py):
+ """Custom command to publish docs to S3."""
+
+ description = (
+ "Publish docs to "
+ + "http://0x-contract-addresses-py.s3-website-us-east-1.amazonaws.com/"
+ )
+
+ def run(self):
+ """Run npm package `discharge` to build & upload docs."""
+ subprocess.check_call("discharge deploy".split()) # nosec
+
+
+setup(
+ name="0x-contract-demo",
+ version="1.0.0",
+ description="Demonstration of calling 0x contracts",
+ url=(
+ "https://github.com/0xProject/0x-monorepo/tree/development"
+ + "/python-packages/contract_demo"
+ ),
+ author="F. Eugene Aumson",
+ author_email="feuGeneA@users.noreply.github.com",
+ cmdclass={
+ "clean": CleanCommandExtension,
+ "lint": LintCommand,
+ "test": TestCommandExtension,
+ "ganache": GanacheCommand,
+ "publish_docs": PublishDocsCommand,
+ },
+ install_requires=[
+ "0x-contract-addresses",
+ "0x-contract-artifacts",
+ "0x-order-utils",
+ "0x-web3", # TEMPORARY! pending resolution of our web3.py PR#1147
+ "mypy_extensions",
+ ],
+ extras_require={
+ "dev": [
+ "bandit",
+ "black",
+ "coverage",
+ "coveralls",
+ "mypy",
+ "mypy_extensions",
+ "pycodestyle",
+ "pydocstyle",
+ "pylint",
+ "pytest",
+ "sphinx",
+ "tox",
+ ]
+ },
+ python_requires=">=3.6, <4",
+ license="Apache 2.0",
+ zip_safe=False, # required per mypy
+ command_options={
+ "build_sphinx": {
+ "source_dir": ("setup.py", "test"),
+ "build_dir": ("setup.py", "build/docs"),
+ }
+ },
+)
diff --git a/python-packages/contract_demo/stubs/__init__.pyi b/python-packages/contract_demo/stubs/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/command/__init__.pyi b/python-packages/contract_demo/stubs/command/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/command/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/command/clean.pyi b/python-packages/contract_demo/stubs/command/clean.pyi
new file mode 100644
index 000000000..46a42ddb1
--- /dev/null
+++ b/python-packages/contract_demo/stubs/command/clean.pyi
@@ -0,0 +1,7 @@
+from distutils.core import Command
+
+class clean(Command):
+ def initialize_options(self: clean) -> None: ...
+ def finalize_options(self: clean) -> None: ...
+ def run(self: clean) -> None: ...
+ ...
diff --git a/python-packages/contract_demo/stubs/distutils/__init__.pyi b/python-packages/contract_demo/stubs/distutils/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/distutils/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/distutils/command/__init__.pyi b/python-packages/contract_demo/stubs/distutils/command/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/distutils/command/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/distutils/command/clean.pyi b/python-packages/contract_demo/stubs/distutils/command/clean.pyi
new file mode 100644
index 000000000..46a42ddb1
--- /dev/null
+++ b/python-packages/contract_demo/stubs/distutils/command/clean.pyi
@@ -0,0 +1,7 @@
+from distutils.core import Command
+
+class clean(Command):
+ def initialize_options(self: clean) -> None: ...
+ def finalize_options(self: clean) -> None: ...
+ def run(self: clean) -> None: ...
+ ...
diff --git a/python-packages/contract_demo/stubs/eth_utils/__init__.pyi b/python-packages/contract_demo/stubs/eth_utils/__init__.pyi
new file mode 100644
index 000000000..4a83338ca
--- /dev/null
+++ b/python-packages/contract_demo/stubs/eth_utils/__init__.pyi
@@ -0,0 +1,4 @@
+from typing import Union
+
+def to_checksum_address(value: Union[str, bytes]) -> str:
+ ...
diff --git a/python-packages/contract_demo/stubs/pytest/__init__.pyi b/python-packages/contract_demo/stubs/pytest/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/pytest/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/setuptools/__init__.pyi b/python-packages/contract_demo/stubs/setuptools/__init__.pyi
new file mode 100644
index 000000000..8ea8d32b7
--- /dev/null
+++ b/python-packages/contract_demo/stubs/setuptools/__init__.pyi
@@ -0,0 +1,8 @@
+from distutils.dist import Distribution
+from typing import Any, List
+
+def setup(**attrs: Any) -> Distribution: ...
+
+class Command: ...
+
+def find_packages(where: str) -> List[str]: ...
diff --git a/python-packages/contract_demo/stubs/setuptools/command/__init__.pyi b/python-packages/contract_demo/stubs/setuptools/command/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/setuptools/command/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/setuptools/command/test.pyi b/python-packages/contract_demo/stubs/setuptools/command/test.pyi
new file mode 100644
index 000000000..c5ec770ad
--- /dev/null
+++ b/python-packages/contract_demo/stubs/setuptools/command/test.pyi
@@ -0,0 +1,3 @@
+from setuptools import Command
+
+class test(Command): ...
diff --git a/python-packages/contract_demo/stubs/web3/__init__.pyi b/python-packages/contract_demo/stubs/web3/__init__.pyi
new file mode 100644
index 000000000..21482d598
--- /dev/null
+++ b/python-packages/contract_demo/stubs/web3/__init__.pyi
@@ -0,0 +1,2 @@
+class Web3:
+ ...
diff --git a/python-packages/contract_demo/stubs/web3/utils/__init__.pyi b/python-packages/contract_demo/stubs/web3/utils/__init__.pyi
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/stubs/web3/utils/__init__.pyi
diff --git a/python-packages/contract_demo/stubs/web3/utils/datatypes.pyi b/python-packages/contract_demo/stubs/web3/utils/datatypes.pyi
new file mode 100644
index 000000000..70baff372
--- /dev/null
+++ b/python-packages/contract_demo/stubs/web3/utils/datatypes.pyi
@@ -0,0 +1,3 @@
+class Contract:
+ def call(self): ...
+ ...
diff --git a/python-packages/contract_demo/test/__init__.py b/python-packages/contract_demo/test/__init__.py
new file mode 100644
index 000000000..600f143bf
--- /dev/null
+++ b/python-packages/contract_demo/test/__init__.py
@@ -0,0 +1 @@
+"""Demonstrations of calling 0x smart contracts."""
diff --git a/python-packages/contract_demo/test/conf.py b/python-packages/contract_demo/test/conf.py
new file mode 100644
index 000000000..45ed4b2a5
--- /dev/null
+++ b/python-packages/contract_demo/test/conf.py
@@ -0,0 +1,54 @@
+"""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-contract-demo"
+# pylint: disable=redefined-builtin
+copyright = "2018, ZeroEx, Intl."
+author = "F. Eugene Aumson"
+version = pkg_resources.get_distribution("0x-contract-demo").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",
+]
+
+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 = "contract_demopydoc"
+
+# -- Extension configuration:
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {"https://docs.python.org/": None}
diff --git a/python-packages/contract_demo/test/doc_static/.gitkeep b/python-packages/contract_demo/test/doc_static/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/python-packages/contract_demo/test/doc_static/.gitkeep
diff --git a/python-packages/contract_demo/test/index.rst b/python-packages/contract_demo/test/index.rst
new file mode 100644
index 000000000..c546eccfa
--- /dev/null
+++ b/python-packages/contract_demo/test/index.rst
@@ -0,0 +1,18 @@
+.. source for the sphinx-generated build/docs/web/index.html
+
+Python demo of 0x Smart Contracts
+=================================
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+.. automodule:: test.test_exchange
+ :members:
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/python-packages/contract_demo/test/test_exchange.py b/python-packages/contract_demo/test/test_exchange.py
new file mode 100644
index 000000000..07492a403
--- /dev/null
+++ b/python-packages/contract_demo/test/test_exchange.py
@@ -0,0 +1,65 @@
+"""Test calling methods on the Exchange contract."""
+
+from eth_utils import to_checksum_address
+from web3 import Web3
+from web3.utils import datatypes
+
+from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
+import zero_ex.contract_artifacts
+from zero_ex.json_schemas import assert_valid
+from zero_ex.order_utils import (
+ Order,
+ OrderInfo,
+ order_to_jsdict,
+ generate_order_hash_hex,
+)
+
+
+def test_get_order_info():
+ """Demonstrate Exchange.getOrderInfo()."""
+ order: Order = {
+ "makerAddress": "0x0000000000000000000000000000000000000000",
+ "takerAddress": "0x0000000000000000000000000000000000000000",
+ "feeRecipientAddress": "0x0000000000000000000000000000000000000000",
+ "senderAddress": "0x0000000000000000000000000000000000000000",
+ "makerAssetAmount": 1000000000000000000,
+ "takerAssetAmount": 1000000000000000000,
+ "makerFee": 0,
+ "takerFee": 0,
+ "expirationTimeSeconds": 12345,
+ "salt": 12345,
+ "makerAssetData": (b"\x00") * 20,
+ "takerAssetData": (b"\x00") * 20,
+ }
+
+ web3_instance = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))
+
+ # false positive from pylint: disable=no-member
+ contract_address = NETWORK_TO_ADDRESSES[
+ NetworkId(int(web3_instance.net.version))
+ ].exchange
+
+ assert_valid(
+ order_to_jsdict(order, exchange_address=contract_address),
+ "/orderSchema",
+ )
+
+ # false positive from pylint: disable=no-member
+ exchange: datatypes.Contract = web3_instance.eth.contract(
+ address=to_checksum_address(contract_address),
+ abi=zero_ex.contract_artifacts.abi_by_name("Exchange"),
+ )
+
+ order_info = OrderInfo(*exchange.call().getOrderInfo(order))
+
+ assert isinstance(order_info.order_status, int)
+ assert order_info.order_status == 4
+
+ assert isinstance(order_info.order_hash, bytes)
+ assert order_info.order_hash.hex() == generate_order_hash_hex(
+ order,
+ exchange_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange,
+ )
+
+ assert isinstance(order_info.order_taker_asset_filled_amount, int)
+ assert order_info.order_taker_asset_filled_amount == 0