Skip to content

Commit

Permalink
PyPy support
Browse files Browse the repository at this point in the history
  • Loading branch information
Stranger6667 committed Mar 1, 2021
1 parent 2312ec3 commit a4d7bb1
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 26 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
63 changes: 39 additions & 24 deletions src/hypothesis_jsonschema/_encode.py
Original file line number Diff line number Diff line change
@@ -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:
Expand Down

0 comments on commit a4d7bb1

Please sign in to comment.