From a4d7bb16ac7ba7ea1772dc563556d662713429eb Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Mon, 1 Mar 2021 13:04:35 +0100 Subject: [PATCH 1/4] PyPy support --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 2 + src/hypothesis_jsonschema/_encode.py | 63 +++++++++++++++++----------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 945d235..c2e9752 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,12 +26,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.6, 3.7, 3.8, 3.9, "pypy-3.6", "pypy-3.7"] fail-fast: false steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ea271e..55ac5ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +- PyPy support (#77) + #### 0.19.0 - 2021-01-06 - Generate empty lists when `maxItems > 0` but no elements are allowed (#75) - Correct handling of regex patterns which are invalid in Python (#75) diff --git a/src/hypothesis_jsonschema/_encode.py b/src/hypothesis_jsonschema/_encode.py index b0c8dbc..8f1a423 100644 --- a/src/hypothesis_jsonschema/_encode.py +++ b/src/hypothesis_jsonschema/_encode.py @@ -1,38 +1,53 @@ """Canonical encoding for the JSONSchema semantics, where 1 == 1.0.""" import json import math -from json.encoder import _make_iterencode, encode_basestring_ascii # type: ignore +import platform from typing import Any, Dict, Tuple, Union # Mypy does not (yet!) support recursive type definitions. # (and writing a few steps by hand is a DoS attack on the AST walker in Pytest) +PYTHON_IMPLEMENTATION = platform.python_implementation() JSONType = Union[None, bool, float, str, list, Dict[str, Any]] +if PYTHON_IMPLEMENTATION != "PyPy": + from json.encoder import _make_iterencode, encode_basestring_ascii # type: ignore +else: + _make_iterencode = None + encode_basestring_ascii = None + + +def _floatstr(o: float) -> str: + # This is the bit we're overriding - integer-valued floats are + # encoded as integers, to support JSONschemas's uniqueness. + assert math.isfinite(o) + if o == int(o): + return repr(int(o)) + return repr(o) + class CanonicalisingJsonEncoder(json.JSONEncoder): - def iterencode(self, o: Any, _one_shot: bool = False) -> Any: - """Replace a stdlib method, so we encode integer-valued floats as ints.""" - - def floatstr(o: float) -> str: - # This is the bit we're overriding - integer-valued floats are - # encoded as integers, to support JSONschemas's uniqueness. - assert math.isfinite(o) - if o == int(o): - return repr(int(o)) - return repr(o) - - return _make_iterencode( - {}, - self.default, - encode_basestring_ascii, - self.indent, - floatstr, - self.key_separator, - self.item_separator, - self.sort_keys, - self.skipkeys, - _one_shot, - )(o, 0) + + if PYTHON_IMPLEMENTATION == "PyPy": + + def _JSONEncoder__floatstr(self, o: float) -> str: # noqa: N802 + return _floatstr(o) + + else: + + def iterencode(self, o: Any, _one_shot: bool = False) -> Any: + """Replace a stdlib method, so we encode integer-valued floats as ints.""" + return _make_iterencode( + {}, + self.default, + encode_basestring_ascii, + self.indent, + _floatstr, + self.key_separator, + self.item_separator, + self.sort_keys, + self.skipkeys, + _one_shot, + )(o, 0) def encode_canonical_json(value: JSONType) -> str: From 9bce86aea5f9c3d8676d378bf731b0921173ec5d Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Fri, 5 Mar 2021 17:22:18 +0100 Subject: [PATCH 2/4] Disable coverage on PyPy --- .github/workflows/ci.yml | 3 ++- src/hypothesis_jsonschema/_encode.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2e9752..78d6dcf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,8 @@ jobs: - name: Install dependencies run: python -m pip install --upgrade pip setuptools tox - name: Run tests - run: python -m tox --recreate -e test + # Disable coverage on PyPy + run: python -m tox --recreate -e test $(${{ startsWith(matrix.python-version, 'pypy') }} && echo '-- -n auto --no-cov') release: runs-on: ubuntu-latest diff --git a/src/hypothesis_jsonschema/_encode.py b/src/hypothesis_jsonschema/_encode.py index 8f1a423..74df1a0 100644 --- a/src/hypothesis_jsonschema/_encode.py +++ b/src/hypothesis_jsonschema/_encode.py @@ -11,7 +11,7 @@ if PYTHON_IMPLEMENTATION != "PyPy": from json.encoder import _make_iterencode, encode_basestring_ascii # type: ignore -else: +else: # pragma: no cover _make_iterencode = None encode_basestring_ascii = None @@ -27,7 +27,7 @@ def _floatstr(o: float) -> str: class CanonicalisingJsonEncoder(json.JSONEncoder): - if PYTHON_IMPLEMENTATION == "PyPy": + if PYTHON_IMPLEMENTATION == "PyPy": # pragma: no cover def _JSONEncoder__floatstr(self, o: float) -> str: # noqa: N802 return _floatstr(o) From 258a7d2b0d274227774db508c4121d2c0b738801 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Sat, 20 Mar 2021 19:43:21 +0100 Subject: [PATCH 3/4] Add explicit test case for merging `items` schemas --- tests/test_canonicalise.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_canonicalise.py b/tests/test_canonicalise.py index fd5f4ff..a4c8d43 100644 --- a/tests/test_canonicalise.py +++ b/tests/test_canonicalise.py @@ -451,6 +451,16 @@ def test_canonicalises_to_expected(schema, expected): "additionalItems": FALSEY, }, ), + ( + [ + {"items": [{}, {"type": "string"}], "additionalItems": False}, + {"items": {"type": "string"}}, + ], + { + "items": [{"type": "string"}, {"type": "string"}], + "additionalItems": FALSEY, + }, + ), ] + [ ([{lo: 0, hi: 9}, {lo: 1, hi: 10}], {lo: 1, hi: 9}) From 264ee19e3ef9add91016b60dc53164b956f6d3fb Mon Sep 17 00:00:00 2001 From: Zac-HD Date: Tue, 23 Mar 2021 12:09:13 +1100 Subject: [PATCH 4/4] Skip JSCS test --- tests/test_from_schema.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_from_schema.py b/tests/test_from_schema.py index b17d60f..ae41470 100644 --- a/tests/test_from_schema.py +++ b/tests/test_from_schema.py @@ -131,6 +131,7 @@ def test_invalid_regex_emit_warning(schema): "draft4/oneOf with missing optional property", "draft7/oneOf with missing optional property", # Sometimes unsatisfiable. TODO: improve canonicalisation to remove filters + "JSCS configuration file", # https://github.com/Zac-HD/hypothesis-jsonschema/pull/78#issuecomment-803519293 "Drone CI configuration file", "PHP Composer configuration file", "Pyrseas database schema versioning for Postgres databases, v0.8",