Skip to content

encoding parameter to json.loads has been deprecated and removed in Python 3.9 #150

Closed

Description

@tirkarthi

encoding parameter has been deprecated and removed in Python 3.9. geojson.loads internally uses json.loads. This will cause test failure.

feature = geojson.loads(json, object_hook=factory, encoding="utf-8")

Ref : python/cpython#18075

Sample fa

pytest -v tests/test_features.py
=============================== test session starts ===============================
platform linux -- Python 3.10.0a0, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 -- /root/pydev-venv/bin/python
cachedir: .pytest_cache
rootdir: /root/checked_repos/geojson
collected 4 items                                                                 

tests/test_features.py::FeaturesTest::test_feature_class FAILED             [ 25%]
tests/test_features.py::FeaturesTest::test_geo_interface PASSED             [ 50%]
tests/test_features.py::FeaturesTest::test_protocol PASSED                  [ 75%]
tests/test_features.py::FeaturesTest::test_unicode_properties PASSED        [100%]

==================================== FAILURES =====================================
_________________________ FeaturesTest.test_feature_class _________________________

self = <tests.test_features.FeaturesTest testMethod=test_feature_class>

    def test_feature_class(self):
        """
        Test the Feature class
        """
    
        from geojson.examples import SimpleWebFeature
        feature = SimpleWebFeature(
            id='1',
            geometry={'type': 'Point', 'coordinates': [53.0, -4.0]},
            title='Feature 1', summary='The first feature',
            link='http://example.org/features/1'
        )
    
        # It satisfies the feature protocol
        self.assertEqual(feature.id, '1')
        self.assertEqual(feature.properties['title'], 'Feature 1')
        self.assertEqual(feature.properties['summary'], 'The first feature')
        self.assertEqual(feature.properties['link'],
                         'http://example.org/features/1')
        self.assertEqual(geojson.dumps(feature.geometry, sort_keys=True),
                         '{"coordinates": [53.0, -4.0], "type": "Point"}')
    
        # Encoding
        json = ('{"geometry": {"coordinates": [53.0, -4.0],'
                ' "type": "Point"},'
                ' "id": "1",'
                ' "properties":'
                ' {"link": "http://example.org/features/1",'
                ' "summary": "The first feature",'
                ' "title": "Feature 1"},'
                ' "type": "Feature"}')
        self.assertEqual(geojson.dumps(feature, sort_keys=True), json)
    
        # Decoding
        factory = geojson.examples.create_simple_web_feature
        json = ('{"geometry": {"type": "Point",'
                ' "coordinates": [53.0, -4.0]},'
                ' "id": "1",'
                ' "properties": {"summary": "The first feature",'
                ' "link": "http://example.org/features/1",'
                ' "title": "Feature 1"}}')
>       feature = geojson.loads(json, object_hook=factory, encoding="utf-8")

tests/test_features.py:85: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
geojson/codec.py:51: in loads
    return json.loads(s,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

s = '{"geometry": {"type": "Point", "coordinates": [53.0, -4.0]}, "id": "1", "properties": {"summary": "The first feature", "link": "http://example.org/features/1", "title": "Feature 1"}}'
cls = <class 'json.decoder.JSONDecoder'>
object_hook = <function create_simple_web_feature at 0x7f711ac7dd30>
parse_float = None, parse_int = None
parse_constant = <function _enforce_strict_numbers at 0x7f711acff1f0>
object_pairs_hook = None
kw = {'encoding': 'utf-8', 'object_hook': <function create_simple_web_feature at 0x7f711ac7dd30>, 'parse_constant': <function _enforce_strict_numbers at 0x7f711acff1f0>}

    def loads(s, *, cls=None, object_hook=None, parse_float=None,
            parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
        """Deserialize ``s`` (a ``str``, ``bytes`` or ``bytearray`` instance
        containing a JSON document) to a Python object.
    
        ``object_hook`` is an optional function that will be called with the
        result of any object literal decode (a ``dict``). The return value of
        ``object_hook`` will be used instead of the ``dict``. This feature
        can be used to implement custom decoders (e.g. JSON-RPC class hinting).
    
        ``object_pairs_hook`` is an optional function that will be called with the
        result of any object literal decoded with an ordered list of pairs.  The
        return value of ``object_pairs_hook`` will be used instead of the ``dict``.
        This feature can be used to implement custom decoders.  If ``object_hook``
        is also defined, the ``object_pairs_hook`` takes priority.
    
        ``parse_float``, if specified, will be called with the string
        of every JSON float to be decoded. By default this is equivalent to
        float(num_str). This can be used to use another datatype or parser
        for JSON floats (e.g. decimal.Decimal).
    
        ``parse_int``, if specified, will be called with the string
        of every JSON int to be decoded. By default this is equivalent to
        int(num_str). This can be used to use another datatype or parser
        for JSON integers (e.g. float).
    
        ``parse_constant``, if specified, will be called with one of the
        following strings: -Infinity, Infinity, NaN.
        This can be used to raise an exception if invalid JSON numbers
        are encountered.
    
        To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
        kwarg; otherwise ``JSONDecoder`` is used.
        """
        if isinstance(s, str):
            if s.startswith('\ufeff'):
                raise JSONDecodeError("Unexpected UTF-8 BOM (decode using utf-8-sig)",
                                      s, 0)
        else:
            if not isinstance(s, (bytes, bytearray)):
                raise TypeError(f'the JSON object must be str, bytes or bytearray, '
                                f'not {s.__class__.__name__}')
            s = s.decode(detect_encoding(s), 'surrogatepass')
    
        if (cls is None and object_hook is None and
                parse_int is None and parse_float is None and
                parse_constant is None and object_pairs_hook is None and not kw):
            return _default_decoder.decode(s)
        if cls is None:
            cls = JSONDecoder
        if object_hook is not None:
            kw['object_hook'] = object_hook
        if object_pairs_hook is not None:
            kw['object_pairs_hook'] = object_pairs_hook
        if parse_float is not None:
            kw['parse_float'] = parse_float
        if parse_int is not None:
            kw['parse_int'] = parse_int
        if parse_constant is not None:
            kw['parse_constant'] = parse_constant
>       return cls(**kw).decode(s)
E       TypeError: JSONDecoder.__init__() got an unexpected keyword argument 'encoding'

/root/cpython/Lib/json/__init__.py:359: TypeError
============================= short test summary info =============================
FAILED tests/test_features.py::FeaturesTest::test_feature_class - TypeError: JSO...
=========================== 1 failed, 3 passed in 0.09s ===========================

Activity

  1. rayrrr commented on Aug 8, 2020

    @rayrrr
    Member

    @tirkarthi thank you for submitting this issue and PR. I think it should be fine but I am going to take a bit of time this weekend to consider "Chesterton's Fence" and make sure removing the utf-8 encoding thing is all good and then will merge or circle back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions