From b6c8126589a94c2986c591ad7741cd3787a96e58 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Wed, 12 Dec 2018 17:47:25 -0800 Subject: Move zero_ex.json_schemas to its own package --- .circleci/config.yml | 25 +++ .prettierignore | 2 +- README.md | 9 +- python-packages/json_schemas/.discharge.json | 13 ++ python-packages/json_schemas/.pylintrc | 3 + python-packages/json_schemas/README.md | 45 +++++ python-packages/json_schemas/setup.py | 191 +++++++++++++++++++++ python-packages/json_schemas/src/conf.py | 54 ++++++ .../json_schemas/src/doc_static/.gitkeep | 0 python-packages/json_schemas/src/index.rst | 18 ++ .../json_schemas/src/zero_ex/__init__.py | 2 + .../src/zero_ex/json_schemas/__init__.py | 74 ++++++++ .../json_schemas/src/zero_ex/json_schemas/py.typed | 0 .../json_schemas/src/zero_ex/json_schemas/schemas | 1 + .../json_schemas/stubs/distutils/__init__.pyi | 0 .../stubs/distutils/command/__init__.pyi | 0 .../json_schemas/stubs/distutils/command/clean.pyi | 7 + .../json_schemas/stubs/jsonschema/__init__.pyi | 11 ++ .../json_schemas/stubs/jsonschema/exceptions.pyi | 0 .../json_schemas/stubs/pytest/__init__.pyi | 0 .../json_schemas/stubs/pytest/raises.pyi | 1 + .../json_schemas/stubs/setuptools/__init__.pyi | 8 + .../stubs/setuptools/command/__init__.pyi | 0 .../json_schemas/stubs/setuptools/command/test.pyi | 3 + python-packages/json_schemas/test/__init__.py | 1 + python-packages/json_schemas/test/test_doctest.py | 25 +++ .../json_schemas/test/test_json_schemas.py | 41 +++++ python-packages/json_schemas/tox.ini | 25 +++ python-packages/order_utils/setup.py | 3 +- python-packages/order_utils/src/index.rst | 3 - .../src/zero_ex/json_schemas/__init__.py | 74 -------- .../order_utils/src/zero_ex/json_schemas/schemas | 1 - .../order_utils/stubs/jsonschema/__init__.pyi | 11 -- .../order_utils/stubs/jsonschema/exceptions.pyi | 0 .../order_utils/stubs/web3/__init___BASE_31011.pyi | 26 +++ .../order_utils/test/test_json_schemas.py | 23 --- 36 files changed, 581 insertions(+), 119 deletions(-) create mode 100644 python-packages/json_schemas/.discharge.json create mode 100644 python-packages/json_schemas/.pylintrc create mode 100644 python-packages/json_schemas/README.md create mode 100755 python-packages/json_schemas/setup.py create mode 100644 python-packages/json_schemas/src/conf.py create mode 100644 python-packages/json_schemas/src/doc_static/.gitkeep create mode 100644 python-packages/json_schemas/src/index.rst create mode 100644 python-packages/json_schemas/src/zero_ex/__init__.py create mode 100644 python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py create mode 100644 python-packages/json_schemas/src/zero_ex/json_schemas/py.typed create mode 120000 python-packages/json_schemas/src/zero_ex/json_schemas/schemas create mode 100644 python-packages/json_schemas/stubs/distutils/__init__.pyi create mode 100644 python-packages/json_schemas/stubs/distutils/command/__init__.pyi create mode 100644 python-packages/json_schemas/stubs/distutils/command/clean.pyi create mode 100644 python-packages/json_schemas/stubs/jsonschema/__init__.pyi create mode 100644 python-packages/json_schemas/stubs/jsonschema/exceptions.pyi create mode 100644 python-packages/json_schemas/stubs/pytest/__init__.pyi create mode 100644 python-packages/json_schemas/stubs/pytest/raises.pyi create mode 100644 python-packages/json_schemas/stubs/setuptools/__init__.pyi create mode 100644 python-packages/json_schemas/stubs/setuptools/command/__init__.pyi create mode 100644 python-packages/json_schemas/stubs/setuptools/command/test.pyi create mode 100644 python-packages/json_schemas/test/__init__.py create mode 100644 python-packages/json_schemas/test/test_doctest.py create mode 100644 python-packages/json_schemas/test/test_json_schemas.py create mode 100644 python-packages/json_schemas/tox.ini delete mode 100644 python-packages/order_utils/src/zero_ex/json_schemas/__init__.py delete mode 120000 python-packages/order_utils/src/zero_ex/json_schemas/schemas delete mode 100644 python-packages/order_utils/stubs/jsonschema/__init__.pyi delete mode 100644 python-packages/order_utils/stubs/jsonschema/exceptions.pyi create mode 100644 python-packages/order_utils/stubs/web3/__init___BASE_31011.pyi delete mode 100644 python-packages/order_utils/test/test_json_schemas.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 68d8041a2..d9debc408 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -200,6 +200,11 @@ jobs: - run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages - restore_cache: key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} + - run: + command: | + cd python-packages/json_schemas + python -m ensurepip + python -m pip install . - run: command: | cd python-packages/order_utils @@ -219,6 +224,10 @@ jobs: - '.mypy_cache' - '.pytest_cache' - '.tox' + - run: + command: | + cd python-packages/json_schemas + coverage run setup.py test - run: command: | cd python-packages/order_utils @@ -227,6 +236,10 @@ jobs: command: | 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: @@ -273,6 +286,11 @@ jobs: - run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages - restore_cache: key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} + - run: + command: | + cd python-packages/json_schemas + python -m ensurepip + python -m pip install . - run: command: | cd python-packages/order_utils @@ -283,6 +301,10 @@ jobs: paths: - '/usr/local/bin' - '/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 @@ -355,6 +377,9 @@ jobs: - restore_cache: keys: - 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 }} diff --git a/.prettierignore b/.prettierignore index 7f8662b0a..c2ebff4a0 100644 --- a/.prettierignore +++ b/.prettierignore @@ -20,7 +20,7 @@ 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/ diff --git a/README.md b/README.md index fd96c2b86..25cdf3fb9 100644 --- a/README.md +++ b/README.md @@ -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) | [![PyPI](https://img.shields.io/pypi/v/0x-order-utils.svg)](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) | [![PyPI](https://img.shields.io/pypi/v/0x-sra-client.svg)](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) | [![PyPI](https://img.shields.io/pypi/v/0x-json-schemas.svg)](https://pypi.org/project/0x-json-schemas/) | 0x-related JSON schemas | +| [`0x-order-utils`](/python-packages/order_utils) | [![PyPI](https://img.shields.io/pypi/v/0x-order-utils.svg)](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) | [![PyPI](https://img.shields.io/pypi/v/0x-sra-client.svg)](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/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..f8c3cf14b --- /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"], + 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..caed8a4b0 --- /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 = "order_utilspydoc" + +# -- Extension configuration: + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {"https://docs.python.org/": None} diff --git a/python-packages/json_schemas/src/doc_static/.gitkeep b/python-packages/json_schemas/src/doc_static/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/python-packages/json_schemas/src/index.rst b/python-packages/json_schemas/src/index.rst new file mode 100644 index 000000000..3bdb73463 --- /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.order_utils +========================== + +.. 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/json_schemas/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py new file mode 100644 index 000000000..a76a2fa3b --- /dev/null +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py @@ -0,0 +1,74 @@ +"""JSON schemas and associated utilities.""" + +from os import path +import json +from typing import Mapping + +from pkg_resources import resource_string +import jsonschema + + +class _LocalRefResolver(jsonschema.RefResolver): + """Resolve package-local JSON schema id's.""" + + 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: + """Resolve the given URL. + + :param url: a string representing the URL of the JSON schema to fetch. + :returns: a string representing the deserialized JSON schema + :raises jsonschema.ValidationError: when the resource associated with + `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]}" + ) + ) + raise jsonschema.ValidationError( + f"Unknown ref '{ref}'. " + + f"Known refs: {list(self.ref_to_file.keys())}." + ) + + +# Instantiate the `_LocalRefResolver()` only once so that `assert_valid()` can +# perform multiple schema validations without reading from disk the schema +# every time. +_LOCAL_RESOLVER = _LocalRefResolver() + + +def assert_valid(data: Mapping, schema_id: str) -> None: + """Validate the given `data` against the specified `schema`. + + :param data: Python dictionary to be validated as a JSON object. + :param schema_id: id property of the JSON schema to validate against. Must + be one of those listed in `the 0x JSON schema files + `_. + + Raises an exception if validation fails. + + >>> assert_valid( + ... {'v': 27, 'r': '0x'+'f'*64, 's': '0x'+'f'*64}, + ... '/ECSignature', + ... ) + """ + # noqa + + _, schema = _LOCAL_RESOLVER.resolve(schema_id) + jsonschema.validate(data, schema, resolver=_LOCAL_RESOLVER) 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 diff --git a/python-packages/json_schemas/src/zero_ex/json_schemas/schemas b/python-packages/json_schemas/src/zero_ex/json_schemas/schemas new file mode 120000 index 000000000..b8257372c --- /dev/null +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/schemas @@ -0,0 +1 @@ +../../../../../packages/json-schemas/schemas/ \ No newline at end of file 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 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 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/json_schemas/stubs/jsonschema/__init__.pyi b/python-packages/json_schemas/stubs/jsonschema/__init__.pyi new file mode 100644 index 000000000..442e2f65e --- /dev/null +++ b/python-packages/json_schemas/stubs/jsonschema/__init__.pyi @@ -0,0 +1,11 @@ +from typing import Any, Dict, Tuple + + +class RefResolver: + def resolve(self, url: str) -> Tuple[str, Dict]: + ... + + +class ValidationError(Exception): pass + +def validate(instance: Any, schema: Dict, cls=None, *args, **kwargs) -> None: pass 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 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 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 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/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/json_schemas/test/test_json_schemas.py b/python-packages/json_schemas/test/test_json_schemas.py new file mode 100644 index 000000000..d0e9840b3 --- /dev/null +++ b/python-packages/json_schemas/test/test_json_schemas.py @@ -0,0 +1,41 @@ +"""Tests of zero_ex.json_schemas""" + + +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 + + In order to test the cache we much access the private class of + `json_schemas` and reset the LRU cache on `_LocalRefResolver`. + For this to happen, we need to disable errror `W0212` + on _LOCAL_RESOLVER + """ + _LOCAL_RESOLVER._remote_cache.cache_clear() # pylint: disable=W0212 + + assert_valid(EMPTY_ORDER, "/orderSchema") + cache_info = ( + _LOCAL_RESOLVER._remote_cache.cache_info() # pylint: disable=W0212 + ) + assert cache_info.currsize == 4 + assert cache_info.hits == 10 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/src/zero_ex/json_schemas/__init__.py b/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py deleted file mode 100644 index a76a2fa3b..000000000 --- a/python-packages/order_utils/src/zero_ex/json_schemas/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -"""JSON schemas and associated utilities.""" - -from os import path -import json -from typing import Mapping - -from pkg_resources import resource_string -import jsonschema - - -class _LocalRefResolver(jsonschema.RefResolver): - """Resolve package-local JSON schema id's.""" - - 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: - """Resolve the given URL. - - :param url: a string representing the URL of the JSON schema to fetch. - :returns: a string representing the deserialized JSON schema - :raises jsonschema.ValidationError: when the resource associated with - `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]}" - ) - ) - raise jsonschema.ValidationError( - f"Unknown ref '{ref}'. " - + f"Known refs: {list(self.ref_to_file.keys())}." - ) - - -# Instantiate the `_LocalRefResolver()` only once so that `assert_valid()` can -# perform multiple schema validations without reading from disk the schema -# every time. -_LOCAL_RESOLVER = _LocalRefResolver() - - -def assert_valid(data: Mapping, schema_id: str) -> None: - """Validate the given `data` against the specified `schema`. - - :param data: Python dictionary to be validated as a JSON object. - :param schema_id: id property of the JSON schema to validate against. Must - be one of those listed in `the 0x JSON schema files - `_. - - Raises an exception if validation fails. - - >>> assert_valid( - ... {'v': 27, 'r': '0x'+'f'*64, 's': '0x'+'f'*64}, - ... '/ECSignature', - ... ) - """ - # noqa - - _, schema = _LOCAL_RESOLVER.resolve(schema_id) - jsonschema.validate(data, schema, resolver=_LOCAL_RESOLVER) diff --git a/python-packages/order_utils/src/zero_ex/json_schemas/schemas b/python-packages/order_utils/src/zero_ex/json_schemas/schemas deleted file mode 120000 index b8257372c..000000000 --- a/python-packages/order_utils/src/zero_ex/json_schemas/schemas +++ /dev/null @@ -1 +0,0 @@ -../../../../../packages/json-schemas/schemas/ \ No newline at end of file diff --git a/python-packages/order_utils/stubs/jsonschema/__init__.pyi b/python-packages/order_utils/stubs/jsonschema/__init__.pyi deleted file mode 100644 index 442e2f65e..000000000 --- a/python-packages/order_utils/stubs/jsonschema/__init__.pyi +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Any, Dict, Tuple - - -class RefResolver: - def resolve(self, url: str) -> Tuple[str, Dict]: - ... - - -class ValidationError(Exception): pass - -def validate(instance: Any, schema: Dict, cls=None, *args, **kwargs) -> None: pass diff --git a/python-packages/order_utils/stubs/jsonschema/exceptions.pyi b/python-packages/order_utils/stubs/jsonschema/exceptions.pyi deleted file mode 100644 index e69de29bb..000000000 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/order_utils/test/test_json_schemas.py b/python-packages/order_utils/test/test_json_schemas.py deleted file mode 100644 index 51cecbd4f..000000000 --- a/python-packages/order_utils/test/test_json_schemas.py +++ /dev/null @@ -1,23 +0,0 @@ -"""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 - - -def test_assert_valid_caches_resources(): - """Test that the JSON ref resolver in `assert_valid()` caches resources - - In order to test the cache we much access the private class of - `json_schemas` and reset the LRU cache on `_LocalRefResolver`. - For this to happen, we need to disable errror `W0212` - on _LOCAL_RESOLVER - """ - _LOCAL_RESOLVER._remote_cache.cache_clear() # pylint: disable=W0212 - - assert_valid(make_empty_order(), "/orderSchema") - cache_info = ( - _LOCAL_RESOLVER._remote_cache.cache_info() # pylint: disable=W0212 - ) - assert cache_info.currsize == 4 - assert cache_info.hits == 10 -- cgit v1.2.3 From 087469f1f303285c3c234b367f60dbe8a0e9258a Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Thu, 13 Dec 2018 11:31:07 -0800 Subject: Support ALL the schemas --- python-packages/json_schemas/setup.py | 2 +- .../src/zero_ex/json_schemas/__init__.py | 39 +++++++++++----------- .../json_schemas/stubs/stringcase/__init__.pyi | 2 ++ 3 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 python-packages/json_schemas/stubs/stringcase/__init__.pyi diff --git a/python-packages/json_schemas/setup.py b/python-packages/json_schemas/setup.py index f8c3cf14b..7813f101f 100755 --- a/python-packages/json_schemas/setup.py +++ b/python-packages/json_schemas/setup.py @@ -136,7 +136,7 @@ setup( "publish": PublishCommand, "publish_docs": PublishDocsCommand, }, - install_requires=["jsonschema", "mypy_extensions"], + install_requires=["jsonschema", "mypy_extensions", "stringcase"], extras_require={ "dev": [ "bandit", diff --git a/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py index a76a2fa3b..f609ea103 100644 --- a/python-packages/json_schemas/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,19 +14,23 @@ 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, "", "") + @staticmethod + def _ref_to_file(ref: str) -> str: + """Translate a JSON schema ref to its corresponding file name. + + >>> _LocalRefResolver._ref_to_file("/addressSchema") + 'address_schema.json' + """ + _ref = ref.lstrip("/") + + # handle weird special cases + _ref = _ref.replace("ECSignature", "EcSignature") + _ref = _ref.replace("Schema", "") + + return f"{snakecase(_ref)}_schema.json" + def resolve_from_url(self, url: str) -> str: """Resolve the given URL. @@ -35,15 +40,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/{_LocalRefResolver._ref_to_file(ref)}", ) - raise jsonschema.ValidationError( - f"Unknown ref '{ref}'. " - + f"Known refs: {list(self.ref_to_file.keys())}." ) 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): + ... -- cgit v1.2.3 From d92e143a7ebbe65d1800e4e8e7f6a56663add62a Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Thu, 13 Dec 2018 12:13:31 -0800 Subject: Stop installing packages as editable --- .circleci/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d9debc408..343199f67 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -204,17 +204,17 @@ jobs: command: | cd python-packages/json_schemas python -m ensurepip - python -m pip install . + 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] - 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: @@ -262,7 +262,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: @@ -290,12 +290,12 @@ jobs: command: | cd python-packages/json_schemas python -m ensurepip - python -m pip install . + 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: -- cgit v1.2.3 From 210840444d0eea3284bf973d13f1ad4b3b1db8fb Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 14 Dec 2018 12:19:46 -0800 Subject: HACK: cp files because CircleCI isn't --- .circleci/config.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 343199f67..7ee4921da 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -205,6 +205,11 @@ jobs: 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. Support ticket raised (#43979). + 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 -- cgit v1.2.3 From 57ac2f28a43067e51f1db1736b48893189ce9dd0 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 14 Dec 2018 16:08:57 -0800 Subject: Add example usage to sra_client README --- python-packages/sra_client/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) 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: -- cgit v1.2.3 From 6639201fdbfe28f9d49e19f29b5606ba9cebdd85 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 14 Dec 2018 16:11:00 -0800 Subject: Tweak special case: only strip Schema as suffix --- python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py index f609ea103..1752c5761 100644 --- a/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py @@ -27,7 +27,9 @@ class _LocalRefResolver(jsonschema.RefResolver): # handle weird special cases _ref = _ref.replace("ECSignature", "EcSignature") - _ref = _ref.replace("Schema", "") + if _ref.endswith("Schema"): + # strip off the Schema suffix + _ref = _ref[:-6] return f"{snakecase(_ref)}_schema.json" -- cgit v1.2.3 From c6815bddac755537950a924ed2763b3811748aa0 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 14 Dec 2018 16:22:58 -0800 Subject: Correct doc titles --- python-packages/json_schemas/src/conf.py | 2 +- python-packages/json_schemas/src/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python-packages/json_schemas/src/conf.py b/python-packages/json_schemas/src/conf.py index caed8a4b0..1ae1493e3 100644 --- a/python-packages/json_schemas/src/conf.py +++ b/python-packages/json_schemas/src/conf.py @@ -46,7 +46,7 @@ html_static_path = ["doc_static"] # so a file named "default.css" will overwrite the builtin "default.css". # Output file base name for HTML help builder. -htmlhelp_basename = "order_utilspydoc" +htmlhelp_basename = "json_schemaspydoc" # -- Extension configuration: diff --git a/python-packages/json_schemas/src/index.rst b/python-packages/json_schemas/src/index.rst index 3bdb73463..3de809aa3 100644 --- a/python-packages/json_schemas/src/index.rst +++ b/python-packages/json_schemas/src/index.rst @@ -1,7 +1,7 @@ .. source for the sphinx-generated build/docs/web/index.html -Python zero_ex.order_utils -========================== +Python zero_ex.json_schemas +=========================== .. toctree:: :maxdepth: 2 -- cgit v1.2.3 From 7e12ae1bfce33dcd6812c10a0d03ff16bd4f3884 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Thu, 20 Dec 2018 17:34:14 -0500 Subject: Clarify what kind of support ticket was raised. --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7ee4921da..bb7a02cd5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -207,7 +207,8 @@ jobs: 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. Support ticket raised (#43979). + # 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: -- cgit v1.2.3 From a3eab71908cd2e188438b4d411b7c426c874f0b2 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 28 Dec 2018 15:08:15 -0500 Subject: Correct inconsistencies in JSON schema names In both ref ID's and file names. --- .prettierignore | 3 +++ .../schemas/asset_pairs_request_opts_schema.json | 2 +- .../json-schemas/schemas/call_data_schema.json | 6 +++--- .../json-schemas/schemas/ec_signature_schema.json | 2 +- packages/json-schemas/schemas/js_number.json | 5 ----- .../json-schemas/schemas/js_number_schema.json | 5 +++++ .../schemas/order_config_request_schema.json | 2 +- .../schemas/orderbook_request_schema.json | 4 ++-- .../schemas/orders_request_opts_schema.json | 2 +- .../schemas/paged_request_opts_schema.json | 2 +- .../json-schemas/schemas/request_opts_schema.json | 2 +- packages/json-schemas/schemas/tx_data_schema.json | 6 +++--- packages/json-schemas/src/schemas.ts | 2 +- packages/json-schemas/tsconfig.json | 2 +- .../src/zero_ex/json_schemas/__init__.py | 22 +++------------------- 15 files changed, 27 insertions(+), 40 deletions(-) delete mode 100644 packages/json-schemas/schemas/js_number.json create mode 100644 packages/json-schemas/schemas/js_number_schema.json diff --git a/.prettierignore b/.prettierignore index c2ebff4a0..d0be9ca09 100644 --- a/.prettierignore +++ b/.prettierignore @@ -27,3 +27,6 @@ lib package.json scripts/postpublish_utils.js packages/sol-cov/test/fixtures/artifacts +.pytest_cache +.mypy_cache +.tox 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.json deleted file mode 100644 index 6a72d92c0..000000000 --- a/packages/json-schemas/schemas/js_number.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "/jsNumber", - "type": "number", - "minimum": 0 -} diff --git a/packages/json-schemas/schemas/js_number_schema.json b/packages/json-schemas/schemas/js_number_schema.json new file mode 100644 index 000000000..7df1c4747 --- /dev/null +++ b/packages/json-schemas/schemas/js_number_schema.json @@ -0,0 +1,5 @@ +{ + "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 21a6f424c..44673383d 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 a79d54385..11e68b6fb 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -40,7 +40,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/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py index 1752c5761..792e6041f 100644 --- a/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py @@ -17,23 +17,7 @@ class _LocalRefResolver(jsonschema.RefResolver): jsonschema.RefResolver.__init__(self, "", "") @staticmethod - def _ref_to_file(ref: str) -> str: - """Translate a JSON schema ref to its corresponding file name. - - >>> _LocalRefResolver._ref_to_file("/addressSchema") - 'address_schema.json' - """ - _ref = ref.lstrip("/") - - # handle weird special cases - _ref = _ref.replace("ECSignature", "EcSignature") - if _ref.endswith("Schema"): - # strip off the Schema suffix - _ref = _ref[:-6] - - return f"{snakecase(_ref)}_schema.json" - - def resolve_from_url(self, url: str) -> str: + def resolve_from_url(url: str) -> str: """Resolve the given URL. :param url: a string representing the URL of the JSON schema to fetch. @@ -45,7 +29,7 @@ class _LocalRefResolver(jsonschema.RefResolver): return json.loads( resource_string( "zero_ex.json_schemas", - f"schemas/{_LocalRefResolver._ref_to_file(ref)}", + f"schemas/{snakecase(ref.lstrip('/'))}.json", ) ) @@ -68,7 +52,7 @@ def assert_valid(data: Mapping, schema_id: str) -> None: >>> assert_valid( ... {'v': 27, 'r': '0x'+'f'*64, 's': '0x'+'f'*64}, - ... '/ECSignature', + ... '/ecSignatureSchema', ... ) """ # noqa -- cgit v1.2.3 From e62e61bf7145c0a8011e098aa22168416d01a781 Mon Sep 17 00:00:00 2001 From: "F. Eugene Aumson" Date: Fri, 28 Dec 2018 15:28:30 -0500 Subject: Add entry point for validation of JSON strings --- .../src/zero_ex/json_schemas/__init__.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py index 792e6041f..10c564b99 100644 --- a/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py +++ b/python-packages/json_schemas/src/zero_ex/json_schemas/__init__.py @@ -59,3 +59,25 @@ def assert_valid(data: Mapping, schema_id: str) -> None: _, 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 + `_. + + 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) -- cgit v1.2.3