diff options
45 files changed, 565 insertions, 54 deletions
| diff --git a/.circleci/config.yml b/.circleci/config.yml index 68d8041a2..bb7a02cd5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -202,14 +202,25 @@ jobs:                    key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}              - run:                    command: | +                      cd python-packages/json_schemas +                      python -m ensurepip +                      python -m pip install .[dev] +                      # HACK! installing the package should do the following +                      # copy for us, but it's not working in CircleCI for some +                      # reason.  Zendesk support ticket raised (#43979) with +                      # CircleCI. +                      mkdir /usr/local/lib/python3.7/site-packages/zero_ex/json_schemas/schemas +                      cp -R src/zero_ex/json_schemas/schemas/* /usr/local/lib/python3.7/site-packages/zero_ex/json_schemas/schemas +            - run: +                  command: |                        cd python-packages/order_utils                        python -m ensurepip -                      python -m pip install -e .[dev] +                      python -m pip install .[dev]              - run:                    command: |                        cd python-packages/sra_client                        python -m ensurepip -                      python -m pip install -e . +                      python -m pip install .[dev]              - save_cache:                    key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}                    paths: @@ -221,6 +232,10 @@ jobs:                        - '.tox'              - run:                    command: | +                      cd python-packages/json_schemas +                      coverage run setup.py test +            - run: +                  command: |                        cd python-packages/order_utils                        coverage run setup.py test              - run: @@ -228,6 +243,10 @@ jobs:                        cd python-packages/sra_client                        coverage run setup.py test              - save_cache: +                  key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }} +                  paths: +                      - ~/repo/python-packages/json_schemas/.coverage +            - save_cache:                    key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}                    paths:                        - ~/repo/python-packages/order_utils/.coverage @@ -249,7 +268,7 @@ jobs:                    command: |                        cd python-packages/order_utils                        python -m ensurepip -                      python -m pip install -e .[dev] +                      python -m pip install .              - save_cache:                    key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}                    paths: @@ -275,9 +294,14 @@ jobs:                    key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}              - run:                    command: | +                      cd python-packages/json_schemas +                      python -m ensurepip +                      python -m pip install .[dev] +            - run: +                  command: |                        cd python-packages/order_utils                        python -m ensurepip -                      python -m pip install -e .[dev] +                      python -m pip install .[dev]              - save_cache:                    key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}                    paths: @@ -285,6 +309,10 @@ jobs:                        - '/usr/local/lib/python3.7/site-packages'              - run:                    command: | +                      cd python-packages/json_schemas +                      python setup.py lint +            - run: +                  command: |                        cd python-packages/order_utils                        python setup.py lint      static-tests: @@ -357,6 +385,9 @@ jobs:                        - coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}              - restore_cache:                    keys: +                      - coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }} +            - restore_cache: +                  keys:                        - coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}              - run: yarn report_coverage  workflows: diff --git a/.prettierignore b/.prettierignore index 7f8662b0a..d0be9ca09 100644 --- a/.prettierignore +++ b/.prettierignore @@ -20,10 +20,13 @@ lib  /packages/contract-artifacts/artifacts  /python-packages/order_utils/src/zero_ex/contract_artifacts/artifacts  /packages/json-schemas/schemas -/python-packages/order_utils/src/zero_ex/json_schemas/schemas +/python-packages/json_schemas/src/zero_ex/json_schemas/schemas  /packages/metacoin/src/contract_wrappers  /packages/metacoin/artifacts  /packages/sra-spec/public/  package.json  scripts/postpublish_utils.js  packages/sol-cov/test/fixtures/artifacts +.pytest_cache +.mypy_cache +.tox @@ -24,10 +24,11 @@ Visit our [developer portal](https://0xproject.com/docs/order-utils) for a compr  ### Python Packages -| Package                                          | Version                                                                                               | Description                                                                                       | -| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| [`0x-order-utils`](/python-packages/order_utils) | [](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders                      | -| [`0x-sra-client`](/python-packages/sra_client)   | [](https://pypi.org/project/0x-sra-client/)   | A Python client for interacting with servers conforming to the Standard Relayer API specification | +| Package                                            | Version                                                                                                 | Description                                                                                       | +| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| [`0x-json-schemas`](/python-packages/json_schemas) | [](https://pypi.org/project/0x-json-schemas/) | 0x-related JSON schemas                                                                           | +| [`0x-order-utils`](/python-packages/order_utils)   | [](https://pypi.org/project/0x-order-utils/)   | A set of utilities for generating, parsing, signing and validating 0x orders                      | +| [`0x-sra-client`](/python-packages/sra_client)     | [](https://pypi.org/project/0x-sra-client/)     | A Python client for interacting with servers conforming to the Standard Relayer API specification |  ### Typescript/Javascript Packages diff --git a/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json b/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json index 174a8fdc3..fad0bd371 100644 --- a/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json +++ b/packages/json-schemas/schemas/asset_pairs_request_opts_schema.json @@ -1,5 +1,5 @@  { -    "id": "/AssetPairsRequestOpts", +    "id": "/AssetPairsRequestOptsSchema",      "type": "object",      "properties": {          "assetDataA": { "$ref": "/hexSchema" }, diff --git a/packages/json-schemas/schemas/call_data_schema.json b/packages/json-schemas/schemas/call_data_schema.json index c5972e8c1..e5e6e3282 100644 --- a/packages/json-schemas/schemas/call_data_schema.json +++ b/packages/json-schemas/schemas/call_data_schema.json @@ -4,13 +4,13 @@          "from": { "$ref": "/addressSchema" },          "to": { "$ref": "/addressSchema" },          "value": { -            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }] +            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]          },          "gas": { -            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }] +            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]          },          "gasPrice": { -            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }] +            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]          },          "data": {              "type": "string", diff --git a/packages/json-schemas/schemas/ec_signature_schema.json b/packages/json-schemas/schemas/ec_signature_schema.json index bc79ca5e9..52ccfe7bb 100644 --- a/packages/json-schemas/schemas/ec_signature_schema.json +++ b/packages/json-schemas/schemas/ec_signature_schema.json @@ -1,5 +1,5 @@  { -    "id": "/ECSignature", +    "id": "/ecSignatureSchema",      "properties": {          "v": {              "type": "number", diff --git a/packages/json-schemas/schemas/js_number.json b/packages/json-schemas/schemas/js_number_schema.json index 6a72d92c0..7df1c4747 100644 --- a/packages/json-schemas/schemas/js_number.json +++ b/packages/json-schemas/schemas/js_number_schema.json @@ -1,5 +1,5 @@  { -    "id": "/jsNumber", +    "id": "/jsNumberSchema",      "type": "number",      "minimum": 0  } diff --git a/packages/json-schemas/schemas/order_config_request_schema.json b/packages/json-schemas/schemas/order_config_request_schema.json index ca9b2e30e..19b043e7f 100644 --- a/packages/json-schemas/schemas/order_config_request_schema.json +++ b/packages/json-schemas/schemas/order_config_request_schema.json @@ -1,5 +1,5 @@  { -    "id": "/OrderConfigRequest", +    "id": "/OrderConfigRequestSchema",      "type": "object",      "properties": {          "makerAddress": { "$ref": "/addressSchema" }, diff --git a/packages/json-schemas/schemas/orderbook_request_schema.json b/packages/json-schemas/schemas/orderbook_request_schema.json index 27848bdcb..5ce6e8ab0 100644 --- a/packages/json-schemas/schemas/orderbook_request_schema.json +++ b/packages/json-schemas/schemas/orderbook_request_schema.json @@ -1,9 +1,9 @@  { -    "id": "/OrderBookRequest", +    "id": "/OrderbookRequestSchema",      "type": "object",      "properties": {          "baseAssetData": { "$ref": "/hexSchema" },          "quoteAssetData": { "$ref": "/hexSchema" }      },      "required": ["baseAssetData", "quoteAssetData"] -}
\ No newline at end of file +} diff --git a/packages/json-schemas/schemas/orders_request_opts_schema.json b/packages/json-schemas/schemas/orders_request_opts_schema.json index 10da51060..4c1b9b4e9 100644 --- a/packages/json-schemas/schemas/orders_request_opts_schema.json +++ b/packages/json-schemas/schemas/orders_request_opts_schema.json @@ -1,5 +1,5 @@  { -    "id": "/OrdersRequestOpts", +    "id": "/OrdersRequestOptsSchema",      "type": "object",      "properties": {          "makerAssetProxyId": { "$ref": "/hexSchema" }, diff --git a/packages/json-schemas/schemas/paged_request_opts_schema.json b/packages/json-schemas/schemas/paged_request_opts_schema.json index 7cfc73947..f143c28b0 100644 --- a/packages/json-schemas/schemas/paged_request_opts_schema.json +++ b/packages/json-schemas/schemas/paged_request_opts_schema.json @@ -1,5 +1,5 @@  { -    "id": "/PagedRequestOpts", +    "id": "/PagedRequestOptsSchema",      "type": "object",      "properties": {          "page": { "type": "number" }, diff --git a/packages/json-schemas/schemas/request_opts_schema.json b/packages/json-schemas/schemas/request_opts_schema.json index b50547d18..2206f5016 100644 --- a/packages/json-schemas/schemas/request_opts_schema.json +++ b/packages/json-schemas/schemas/request_opts_schema.json @@ -1,5 +1,5 @@  { -    "id": "/RequestOpts", +    "id": "/RequestOptsSchema",      "type": "object",      "properties": {          "networkId": { "type": "number" } diff --git a/packages/json-schemas/schemas/tx_data_schema.json b/packages/json-schemas/schemas/tx_data_schema.json index 4643521ce..8c3daba4e 100644 --- a/packages/json-schemas/schemas/tx_data_schema.json +++ b/packages/json-schemas/schemas/tx_data_schema.json @@ -4,13 +4,13 @@          "from": { "$ref": "/addressSchema" },          "to": { "$ref": "/addressSchema" },          "value": { -            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }] +            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]          },          "gas": { -            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }] +            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]          },          "gasPrice": { -            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumber" }] +            "oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]          },          "data": {              "type": "string", diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index 050f4e625..9e8eb6959 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -8,7 +8,7 @@ import * as ecSignatureSchema from '../schemas/ec_signature_schema.json';  import * as eip712TypedDataSchema from '../schemas/eip712_typed_data_schema.json';  import * as hexSchema from '../schemas/hex_schema.json';  import * as indexFilterValuesSchema from '../schemas/index_filter_values_schema.json'; -import * as jsNumber from '../schemas/js_number.json'; +import * as jsNumber from '../schemas/js_number_schema.json';  import * as numberSchema from '../schemas/number_schema.json';  import * as orderCancellationRequestsSchema from '../schemas/order_cancel_schema.json';  import * as orderConfigRequestSchema from '../schemas/order_config_request_schema.json'; diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index ec573290c..7d7ce1d7e 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -42,7 +42,7 @@          "./schemas/relayer_api_orders_schema.json",          "./schemas/signed_orders_schema.json",          "./schemas/token_schema.json", -        "./schemas/js_number.json", +        "./schemas/js_number_schema.json",          "./schemas/zero_ex_transaction_schema.json",          "./schemas/tx_data_schema.json",          "./schemas/index_filter_values_schema.json", diff --git a/python-packages/json_schemas/.discharge.json b/python-packages/json_schemas/.discharge.json new file mode 100644 index 000000000..66d95679f --- /dev/null +++ b/python-packages/json_schemas/.discharge.json @@ -0,0 +1,13 @@ +{ +    "domain": "0x-json-schemas-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/json_schemas/.pylintrc b/python-packages/json_schemas/.pylintrc new file mode 100644 index 000000000..937bc6313 --- /dev/null +++ b/python-packages/json_schemas/.pylintrc @@ -0,0 +1,3 @@ +[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`. diff --git a/python-packages/json_schemas/README.md b/python-packages/json_schemas/README.md new file mode 100644 index 000000000..ef8e888f3 --- /dev/null +++ b/python-packages/json_schemas/README.md @@ -0,0 +1,45 @@ +## 0x-json-schemas + +0x JSON schemas for those developing on top of 0x protocol. + +Read the [documentation](http://0x-json-schemas-py.s3-website-us-east-1.amazonaws.com/) + +## Installing + +```bash +pip install 0x-json-schemas +``` + +## 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/json_schemas/setup.py b/python-packages/json_schemas/setup.py new file mode 100755 index 000000000..7813f101f --- /dev/null +++ b/python-packages/json_schemas/setup.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +"""setuptools module for json_schemas 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 find_packages, 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 src test setup.py".split(), +            # style guide checker (formerly pep8): +            "pycodestyle src test setup.py".split(), +            # docstring style checker: +            "pydocstyle src test setup.py".split(), +            # static type checker: +            "mypy src test setup.py".split(), +            # security issue checker: +            "bandit -r src ./setup.py".split(), +            # general linter: +            "pylint src 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("dist", ignore_errors=True) +        rmtree(".mypy_cache", ignore_errors=True) +        rmtree(".tox", ignore_errors=True) +        rmtree(".pytest_cache", ignore_errors=True) +        rmtree("src/*.egg-info", ignore_errors=True) + + +class TestPublishCommand(distutils.command.build_py.build_py): +    """Custom command to publish to test.pypi.org.""" + +    description = ( +        "Publish dist/* to test.pypi.org. Run sdist & bdist_wheel first." +    ) + +    def run(self): +        """Run twine to upload to test.pypi.org.""" +        subprocess.check_call(  # nosec +            ( +                "twine upload --repository-url https://test.pypi.org/legacy/" +                + " --verbose dist/*" +            ).split() +        ) + + +class PublishCommand(distutils.command.build_py.build_py): +    """Custom command to publish to pypi.org.""" + +    description = "Publish dist/* to pypi.org. Run sdist & bdist_wheel first." + +    def run(self): +        """Run twine to upload to pypi.org.""" +        subprocess.check_call("twine upload dist/*".split())  # nosec + + +class PublishDocsCommand(distutils.command.build_py.build_py): +    """Custom command to publish docs to S3.""" + +    description = ( +        "Publish docs to " +        + "http://0x-json-schemas-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 + + +with open("README.md", "r") as file_handle: +    README_MD = file_handle.read() + + +setup( +    name="0x-json-schemas", +    version="1.0.0", +    description="JSON schemas for 0x applications", +    long_description=README_MD, +    long_description_content_type="text/markdown", +    url=( +        "https://github.com/0xProject/0x-monorepo/tree/development" +        + "/python-packages/json_schemas" +    ), +    author="F. Eugene Aumson", +    author_email="feuGeneA@users.noreply.github.com", +    cmdclass={ +        "clean": CleanCommandExtension, +        "lint": LintCommand, +        "test": TestCommandExtension, +        "test_publish": TestPublishCommand, +        "publish": PublishCommand, +        "publish_docs": PublishDocsCommand, +    }, +    install_requires=["jsonschema", "mypy_extensions", "stringcase"], +    extras_require={ +        "dev": [ +            "bandit", +            "black", +            "coverage", +            "coveralls", +            "mypy", +            "mypy_extensions", +            "pycodestyle", +            "pydocstyle", +            "pylint", +            "pytest", +            "sphinx", +            "tox", +            "twine", +        ] +    }, +    python_requires=">=3.6, <4", +    package_data={"zero_ex.json_schemas": ["py.typed", "schemas/*"]}, +    package_dir={"": "src"}, +    license="Apache 2.0", +    keywords=( +        "ethereum cryptocurrency 0x decentralized blockchain dex exchange" +    ), +    namespace_packages=["zero_ex"], +    packages=find_packages("src"), +    classifiers=[ +        "Development Status :: 2 - Pre-Alpha", +        "Intended Audience :: Developers", +        "Intended Audience :: Financial and Insurance Industry", +        "License :: OSI Approved :: Apache Software License", +        "Natural Language :: English", +        "Operating System :: OS Independent", +        "Programming Language :: Python", +        "Programming Language :: Python :: 3 :: Only", +        "Programming Language :: Python :: 3.6", +        "Programming Language :: Python :: 3.7", +        "Topic :: Internet :: WWW/HTTP", +        "Topic :: Office/Business :: Financial", +        "Topic :: Other/Nonlisted Topic", +        "Topic :: Security :: Cryptography", +        "Topic :: Software Development :: Libraries", +        "Topic :: Utilities", +    ], +    zip_safe=False,  # required per mypy +    command_options={ +        "build_sphinx": { +            "source_dir": ("setup.py", "src"), +            "build_dir": ("setup.py", "build/docs"), +        } +    }, +) diff --git a/python-packages/json_schemas/src/conf.py b/python-packages/json_schemas/src/conf.py new file mode 100644 index 000000000..1ae1493e3 --- /dev/null +++ b/python-packages/json_schemas/src/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-json-schemas" +# pylint: disable=redefined-builtin +copyright = "2018, ZeroEx, Intl." +author = "F. Eugene Aumson" +version = pkg_resources.get_distribution("0x-json-schemas").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 = "json_schemaspydoc" + +# -- Extension configuration: + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {"https://docs.python.org/": None} diff --git a/python-packages/order_utils/stubs/jsonschema/exceptions.pyi b/python-packages/json_schemas/src/doc_static/.gitkeep index e69de29bb..e69de29bb 100644 --- a/python-packages/order_utils/stubs/jsonschema/exceptions.pyi +++ b/python-packages/json_schemas/src/doc_static/.gitkeep diff --git a/python-packages/json_schemas/src/index.rst b/python-packages/json_schemas/src/index.rst new file mode 100644 index 000000000..3de809aa3 --- /dev/null +++ b/python-packages/json_schemas/src/index.rst @@ -0,0 +1,18 @@ +.. source for the sphinx-generated build/docs/web/index.html + +Python zero_ex.json_schemas +=========================== + +.. toctree:: +   :maxdepth: 2 +   :caption: Contents: + +.. automodule:: zero_ex.json_schemas +   :members: + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/python-packages/json_schemas/src/zero_ex/__init__.py b/python-packages/json_schemas/src/zero_ex/__init__.py new file mode 100644 index 000000000..e90d833db --- /dev/null +++ b/python-packages/json_schemas/src/zero_ex/__init__.py @@ -0,0 +1,2 @@ +"""0x Python API.""" +__import__("pkg_resources").declare_namespace(__name__) diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py index a76a2fa3b..10c564b99 100644 --- a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py @@ -6,6 +6,7 @@ from typing import Mapping  from pkg_resources import resource_string  import jsonschema +from stringcase import snakecase  class _LocalRefResolver(jsonschema.RefResolver): @@ -13,20 +14,10 @@ class _LocalRefResolver(jsonschema.RefResolver):      def __init__(self):          """Initialize a new instance.""" -        self.ref_to_file = { -            "/addressSchema": "address_schema.json", -            "/hexSchema": "hex_schema.json", -            "/orderSchema": "order_schema.json", -            "/wholeNumberSchema": "whole_number_schema.json", -            "/ECSignature": "ec_signature_schema.json", -            "/signedOrderSchema": "signed_order_schema.json", -            "/ecSignatureParameterSchema": ( -                "ec_signature_parameter_schema.json" + "" -            ), -        }          jsonschema.RefResolver.__init__(self, "", "") -    def resolve_from_url(self, url: str) -> str: +    @staticmethod +    def resolve_from_url(url: str) -> str:          """Resolve the given URL.          :param url: a string representing the URL of the JSON schema to fetch. @@ -35,15 +26,11 @@ class _LocalRefResolver(jsonschema.RefResolver):                     `url` does not exist.          """          ref = url.replace("file://", "") -        if ref in self.ref_to_file: -            return json.loads( -                resource_string( -                    "zero_ex.json_schemas", f"schemas/{self.ref_to_file[ref]}" -                ) +        return json.loads( +            resource_string( +                "zero_ex.json_schemas", +                f"schemas/{snakecase(ref.lstrip('/'))}.json",              ) -        raise jsonschema.ValidationError( -            f"Unknown ref '{ref}'. " -            + f"Known refs: {list(self.ref_to_file.keys())}."          ) @@ -65,10 +52,32 @@ def assert_valid(data: Mapping, schema_id: str) -> None:      >>> assert_valid(      ...     {'v': 27, 'r': '0x'+'f'*64, 's': '0x'+'f'*64}, -    ...     '/ECSignature', +    ...     '/ecSignatureSchema',      ... )      """      # noqa      _, schema = _LOCAL_RESOLVER.resolve(schema_id)      jsonschema.validate(data, schema, resolver=_LOCAL_RESOLVER) + + +def assert_valid_json(data: str, schema_id: str) -> None: +    """Validate the given `data` against the specified `schema`. + +    :param data: JSON string to be validated. +    :param schema_id: id property of the JSON schema to validate against.  Must +        be one of those listed in `the 0x JSON schema files +        <https://github.com/0xProject/0x-monorepo/tree/development/packages/json-schemas/schemas>`_. + +    Raises an exception if validation fails. + +    >>> assert_valid_json( +    ...     r'''{ +    ...         "v": 27, +    ...         "r": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", +    ...         "s": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" +    ...     }''', +    ...     '/ecSignatureSchema', +    ... ) +    """  # noqa: E501 (line too long) +    assert_valid(json.loads(data), schema_id) diff --git a/python-packages/json_schemas/src/zero_ex/json_schemas/py.typed b/python-packages/json_schemas/src/zero_ex/json_schemas/py.typed new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/py.typed diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/schemas b/python-packages/json_schemas/src/zero_ex/json_schemas/schemas index b8257372c..b8257372c 120000 --- a/python-packages/order_utils/src/zero_ex/json_schemas/schemas +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/schemas diff --git a/python-packages/json_schemas/stubs/distutils/__init__.pyi b/python-packages/json_schemas/stubs/distutils/__init__.pyi new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/python-packages/json_schemas/stubs/distutils/__init__.pyi diff --git a/python-packages/json_schemas/stubs/distutils/command/__init__.pyi b/python-packages/json_schemas/stubs/distutils/command/__init__.pyi new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/python-packages/json_schemas/stubs/distutils/command/__init__.pyi diff --git a/python-packages/json_schemas/stubs/distutils/command/clean.pyi b/python-packages/json_schemas/stubs/distutils/command/clean.pyi new file mode 100644 index 000000000..46a42ddb1 --- /dev/null +++ b/python-packages/json_schemas/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/order_utils/stubs/jsonschema/__init__.pyi b/python-packages/json_schemas/stubs/jsonschema/__init__.pyi index 442e2f65e..442e2f65e 100644 --- a/python-packages/order_utils/stubs/jsonschema/__init__.pyi +++ b/python-packages/json_schemas/stubs/jsonschema/__init__.pyi diff --git a/python-packages/json_schemas/stubs/jsonschema/exceptions.pyi b/python-packages/json_schemas/stubs/jsonschema/exceptions.pyi new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/python-packages/json_schemas/stubs/jsonschema/exceptions.pyi diff --git a/python-packages/json_schemas/stubs/pytest/__init__.pyi b/python-packages/json_schemas/stubs/pytest/__init__.pyi new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/python-packages/json_schemas/stubs/pytest/__init__.pyi diff --git a/python-packages/json_schemas/stubs/pytest/raises.pyi b/python-packages/json_schemas/stubs/pytest/raises.pyi new file mode 100644 index 000000000..2e3b29f3d --- /dev/null +++ b/python-packages/json_schemas/stubs/pytest/raises.pyi @@ -0,0 +1 @@ +def raises(exception: Exception) -> ExceptionInfo: ... diff --git a/python-packages/json_schemas/stubs/setuptools/__init__.pyi b/python-packages/json_schemas/stubs/setuptools/__init__.pyi new file mode 100644 index 000000000..8ea8d32b7 --- /dev/null +++ b/python-packages/json_schemas/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/json_schemas/stubs/setuptools/command/__init__.pyi b/python-packages/json_schemas/stubs/setuptools/command/__init__.pyi new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/python-packages/json_schemas/stubs/setuptools/command/__init__.pyi diff --git a/python-packages/json_schemas/stubs/setuptools/command/test.pyi b/python-packages/json_schemas/stubs/setuptools/command/test.pyi new file mode 100644 index 000000000..c5ec770ad --- /dev/null +++ b/python-packages/json_schemas/stubs/setuptools/command/test.pyi @@ -0,0 +1,3 @@ +from setuptools import Command + +class test(Command): ... diff --git a/python-packages/json_schemas/stubs/stringcase/__init__.pyi b/python-packages/json_schemas/stubs/stringcase/__init__.pyi new file mode 100644 index 000000000..56d784cf5 --- /dev/null +++ b/python-packages/json_schemas/stubs/stringcase/__init__.pyi @@ -0,0 +1,2 @@ +def snakecase(_: str): +    ... diff --git a/python-packages/json_schemas/test/__init__.py b/python-packages/json_schemas/test/__init__.py new file mode 100644 index 000000000..ce724e180 --- /dev/null +++ b/python-packages/json_schemas/test/__init__.py @@ -0,0 +1 @@ +"""Tests of zero_ex.json_schemas.""" diff --git a/python-packages/json_schemas/test/test_doctest.py b/python-packages/json_schemas/test/test_doctest.py new file mode 100644 index 000000000..2aa576422 --- /dev/null +++ b/python-packages/json_schemas/test/test_doctest.py @@ -0,0 +1,25 @@ +"""Exercise doctests for all of our modules.""" + +from doctest import testmod +import pkgutil +import importlib + +import zero_ex.json_schemas + + +def test_all_doctests(): +    """Gather zero_ex.json_schemas.* modules and doctest them.""" +    # json_schemas module +    module = "zero_ex.json_schemas" +    print(module) +    failure_count, _ = testmod(importlib.import_module(module)) +    assert failure_count == 0 + +    # any json_schemas.* sub-modules +    for (_, modname, _) in pkgutil.walk_packages( +        path=zero_ex.json_schemas.__path__, prefix="zero_ex.json_schemas" +    ): +        module = importlib.import_module(modname) +        print(module) +        (failure_count, _) = testmod(module) +        assert failure_count == 0 diff --git a/python-packages/order_utils/test/test_json_schemas.py b/python-packages/json_schemas/test/test_json_schemas.py index 51cecbd4f..d0e9840b3 100644 --- a/python-packages/order_utils/test/test_json_schemas.py +++ b/python-packages/json_schemas/test/test_json_schemas.py @@ -1,10 +1,28 @@  """Tests of zero_ex.json_schemas""" -from zero_ex.order_utils import make_empty_order  from zero_ex.json_schemas import _LOCAL_RESOLVER, assert_valid +NULL_ADDRESS = "0x0000000000000000000000000000000000000000" + +EMPTY_ORDER = { +    "makerAddress": NULL_ADDRESS, +    "takerAddress": NULL_ADDRESS, +    "senderAddress": NULL_ADDRESS, +    "feeRecipientAddress": NULL_ADDRESS, +    "makerAssetData": NULL_ADDRESS, +    "takerAssetData": NULL_ADDRESS, +    "salt": "0", +    "makerFee": "0", +    "takerFee": "0", +    "makerAssetAmount": "0", +    "takerAssetAmount": "0", +    "expirationTimeSeconds": "0", +    "exchangeAddress": NULL_ADDRESS, +} + +  def test_assert_valid_caches_resources():      """Test that the JSON ref resolver in `assert_valid()` caches resources @@ -15,7 +33,7 @@ def test_assert_valid_caches_resources():      """      _LOCAL_RESOLVER._remote_cache.cache_clear()  # pylint: disable=W0212 -    assert_valid(make_empty_order(), "/orderSchema") +    assert_valid(EMPTY_ORDER, "/orderSchema")      cache_info = (          _LOCAL_RESOLVER._remote_cache.cache_info()  # pylint: disable=W0212      ) diff --git a/python-packages/json_schemas/tox.ini b/python-packages/json_schemas/tox.ini new file mode 100644 index 000000000..1d5de646e --- /dev/null +++ b/python-packages/json_schemas/tox.ini @@ -0,0 +1,25 @@ +# tox (https://tox.readthedocs.io/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +envlist = py37 + +[testenv] +commands = +    pip install -e .[dev] +    python setup.py test + +[testenv:run_tests_against_test_deployment] +commands = +    # install dependencies from real PyPI +    pip install jsonschema mypy_extensions pytest +    # install package-under-test from test PyPI +    pip install --index-url https://test.pypi.org/legacy/ 0x-json-schemas +    pytest test + +[testenv:run_tests_against_deployment] +commands = +    pip install 0x-json-schemas +    pytest test diff --git a/python-packages/order_utils/setup.py b/python-packages/order_utils/setup.py index 125de5ff7..fdf8d1e8e 100755 --- a/python-packages/order_utils/setup.py +++ b/python-packages/order_utils/setup.py @@ -171,9 +171,9 @@ setup(          "ganache": GanacheCommand,      },      install_requires=[ +        "0x-json-schemas",          "eth-abi",          "eth_utils", -        "jsonschema",          "mypy_extensions",          "web3",      ], @@ -198,7 +198,6 @@ setup(      package_data={          "zero_ex.order_utils": ["py.typed"],          "zero_ex.contract_artifacts": ["artifacts/*"], -        "zero_ex.json_schemas": ["schemas/*"],      },      package_dir={"": "src"},      license="Apache 2.0", diff --git a/python-packages/order_utils/src/index.rst b/python-packages/order_utils/src/index.rst index 551487ab1..4d27a4b17 100644 --- a/python-packages/order_utils/src/index.rst +++ b/python-packages/order_utils/src/index.rst @@ -22,9 +22,6 @@ See source for class properties.  Sphinx does not easily generate class property  .. autoclass:: zero_ex.order_utils.asset_data_utils.ERC721AssetData -.. automodule:: zero_ex.json_schemas -   :members: -  Indices and tables  ================== diff --git a/python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi b/python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi new file mode 100644 index 000000000..fcecc7434 --- /dev/null +++ b/python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi @@ -0,0 +1,26 @@ +from typing import Dict, Optional, Union + +from web3.utils import datatypes + + +class Web3: +    class HTTPProvider: ... + +    def __init__(self, provider: HTTPProvider) -> None: ... + +    @staticmethod +    def sha3( +        primitive: Optional[Union[bytes, int, None]] = None, +        text: Optional[str] = None, +        hexstr: Optional[str] = None +    ) -> bytes: ... + +    class net: +        version: str +        ... + +    class eth: +        @staticmethod +        def contract(address: str, abi: Dict) -> datatypes.Contract: ... +        ... +    ... diff --git a/python-packages/sra_client/README.md b/python-packages/sra_client/README.md index ab3939b41..279fb41a4 100644 --- a/python-packages/sra_client/README.md +++ b/python-packages/sra_client/README.md @@ -6,6 +6,35 @@ A Python client for interacting with servers conforming to [the Standard Relayer  The [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the 0x.js library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1). +```bash +pip install 0x-json-schemas +``` + +You can easily validate your API's payloads and responses using the [0x-json-schemas](https://github.com/0xProject/0x.js/tree/development/python-packages/json_schemas) package: + +```python +from zero_ex.json_schemas import assert_valid +from zero_ex.order_utils import Order + +order: Order = { +    'makerAddress': "0x0000000000000000000000000000000000000000", +    'takerAddress': "0x0000000000000000000000000000000000000000", +    'feeRecipientAddress': "0x0000000000000000000000000000000000000000", +    'senderAddress': "0x0000000000000000000000000000000000000000", +    'makerAssetAmount': "1000000000000000000", +    'takerAssetAmount': "1000000000000000000", +    'makerFee': "0", +    'takerFee': "0", +    'expirationTimeSeconds': "12345", +    'salt': "12345", +    'makerAssetData': "0x0000000000000000000000000000000000000000", +    'takerAssetData': "0x0000000000000000000000000000000000000000", +    'exchangeAddress': "0x0000000000000000000000000000000000000000", +} + +assert_valid(order, "/orderSchema") +``` +  # Pagination  Requests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example: | 
