Skip to content

Python 3.11 issues #42

@ancieg

Description

@ancieg

Description

The packages doesn't pass its tests.

Steps to Reproduce

  1. $ git clone https://github.com/domdfcoding/singledispatch-json && cd singledispatch-json
  2. python3 -m venv .venv && source .venv/bin/activate
  3. pip install -r requirements.txt -r tests/requirements.txt
  4. pip install .
  5. pytest -vra

Actual result:

Expected result:

Reproduces how often:

==================================================================== FAILURES =====================================================================
_________________________________________________________________ test_protocols __________________________________________________________________

    def test_protocols() -> None:

    	class Integer:

    		def __int__(self) -> int:
    			return 42

    	class Float:

    		def __float__(self) -> float:
    			return 42.0

    	class Bytes:

    		def __bytes__(self) -> bytes:
    			return b"42"

    	with pytest.raises(TypeError, match="Object of type '?Integer'? is not JSON serializable"):
    		sdjson.dumps(Integer())

    	with pytest.raises(TypeError, match="Object of type '?Float'? is not JSON serializable"):
    		sdjson.dumps(Float())

    	with pytest.raises(TypeError, match="Object of type '?Bytes'? is not JSON serializable"):
    		sdjson.dumps(Bytes())

    	@sdjson.encoders.register(SupportsInt)
    	def supports_int_encoder(obj):
    		return int(obj)

    	@sdjson.encoders.register(SupportsFloat)
    	def supports_float_encoder(obj):
    		return float(obj)

    	@sdjson.encoders.register(SupportsBytes)
    	def supports_bytes_encoder(obj):
    		return bytes(obj)

    	assert sdjson.dumps(Integer()) == "42"
    	assert sdjson.dumps(Float()) == "42.0"

    	# To prove the protocols don't take precedence
    	assert sdjson.dumps(123) == "123"

    	with pytest.raises(TypeError, match="Object of type '?bytes'? is not JSON serializable"):
>   		sdjson.dumps(Bytes())

tests/test_protocols.py:100:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
sdjson/__init__.py:326: in dumps
    return _default_encoder.encode(obj)
sdjson/__init__.py:385: in encode
    return super().encode(o)
/usr/lib64/python3.11/json/encoder.py:200: in encode
    chunks = self.iterencode(o, _one_shot=True)
sdjson/__init__.py:394: in iterencode
    return super().iterencode(o, _one_shot)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <sdjson._CustomEncoder object at 0x7fc4922fef90>, o = <tests.test_protocols.test_protocols.<locals>.Bytes object at 0x7fc492b637d0>
_one_shot = True

    def iterencode(self, o, _one_shot=False):
        """Encode the given object and yield each string
        representation as available.

        For example::

            for chunk in JSONEncoder().iterencode(bigobject):
                mysocket.write(chunk)

        """
        if self.check_circular:
            markers = {}
        else:
            markers = None
        if self.ensure_ascii:
            _encoder = encode_basestring_ascii
        else:
            _encoder = encode_basestring

        def floatstr(o, allow_nan=self.allow_nan,
                _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
            # Check for specials.  Note that this type of test is processor
            # and/or platform-specific, so do tests which don't depend on the
            # internals.

            if o != o:
                text = 'NaN'
            elif o == _inf:
                text = 'Infinity'
            elif o == _neginf:
                text = '-Infinity'
            else:
                return _repr(o)

            if not allow_nan:
                raise ValueError(
                    "Out of range float values are not JSON compliant: " +
                    repr(o))

            return text


        if (_one_shot and c_make_encoder is not None
                and self.indent is None):
            _iterencode = c_make_encoder(
                markers, self.default, _encoder, self.indent,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, self.allow_nan)
        else:
            _iterencode = _make_iterencode(
                markers, self.default, _encoder, self.indent, floatstr,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, _one_shot)
>       return _iterencode(o, 0)
E       ValueError: Circular reference detected

/usr/lib64/python3.11/json/encoder.py:258: ValueError
_________________________________________________________________ test_unregister _________________________________________________________________

    def test_unregister() -> None:
    	# Create and register a custom encoder for Decimal that turns it into a string
    	@sdjson.encoders.register(Decimal)
    	def encode_str(obj):
    		return str(obj)

    	# Test that we get the expected output from the first encoder
    	assert sdjson.dumps(Decimal(1)) == '"1"'

    	# Unregister that encoder
    	sdjson.unregister_encoder(Decimal)

    	# We should now get an error
>   	with pytest.raises(TypeError, match="Object of type [']*Decimal[']* is not JSON serializable") as e:
E    Failed: DID NOT RAISE <class 'TypeError'>

tests/test_unregister.py:24: Failed
________________________________________________________________ test_bytes_encode ________________________________________________________________

    def test_bytes_encode() -> None:
    	with pytest.raises(TypeError):
>   		sdjson.dumps(b"hi")

tests/stdlib_tests/test_unicode.py:66:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
sdjson/__init__.py:326: in dumps
    return _default_encoder.encode(obj)
sdjson/__init__.py:385: in encode
    return super().encode(o)
/usr/lib64/python3.11/json/encoder.py:200: in encode
    chunks = self.iterencode(o, _one_shot=True)
sdjson/__init__.py:394: in iterencode
    return super().iterencode(o, _one_shot)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <sdjson._CustomEncoder object at 0x7fc4922fef90>, o = b'hi', _one_shot = True

    def iterencode(self, o, _one_shot=False):
        """Encode the given object and yield each string
        representation as available.

        For example::

            for chunk in JSONEncoder().iterencode(bigobject):
                mysocket.write(chunk)

        """
        if self.check_circular:
            markers = {}
        else:
            markers = None
        if self.ensure_ascii:
            _encoder = encode_basestring_ascii
        else:
            _encoder = encode_basestring

        def floatstr(o, allow_nan=self.allow_nan,
                _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
            # Check for specials.  Note that this type of test is processor
            # and/or platform-specific, so do tests which don't depend on the
            # internals.

            if o != o:
                text = 'NaN'
            elif o == _inf:
                text = 'Infinity'
            elif o == _neginf:
                text = '-Infinity'
            else:
                return _repr(o)

            if not allow_nan:
                raise ValueError(
                    "Out of range float values are not JSON compliant: " +
                    repr(o))

            return text


        if (_one_shot and c_make_encoder is not None
                and self.indent is None):
            _iterencode = c_make_encoder(
                markers, self.default, _encoder, self.indent,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, self.allow_nan)
        else:
            _iterencode = _make_iterencode(
                markers, self.default, _encoder, self.indent, floatstr,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, _one_shot)
>       return _iterencode(o, 0)
E       ValueError: Circular reference detected

/usr/lib64/python3.11/json/encoder.py:258: ValueError
============================================================== slowest 25 durations ===============================================================
0.10s call     tests/stdlib_tests/test_unicode.py::test_unicode_decode
0.09s call     tests/stdlib_tests/test_recursion.py::test_highly_nested_objects_encoding

(23 durations < 0.005s hidden.  Use -vv to show these durations.)

Version

  • Operating System: ALT Starterkit 10 (Hypericum) (updated to Sisyphus branch).
  • Python: 3.11.4
  • sdjson: v0.4.0

Installation source

$ git clone https://github.com/domdfcoding/singledispatch-json

Other Additional Information:

The error doesn't occur for Python 3.10.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingstale

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions