Skip to content

Implementation of the standard json module with support for Python < 2.3

License

Notifications You must be signed in to change notification settings

LukeSavefrogs/python21-json

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

python2-json

Basic implementation of a JSON parser written in pure Python and created as a drop-in replacement (well, almost) for the json module in environments using very old Python versions (2.2 and lower).

Provides loads, dumps and their counterparts load and dump.

Please note that speed is clearly not the focus here...

Features

  • Same function names and signature: loads, dumps, load, dump;

  • Handles all base JSON types:

    • Arrays: []
    • Objects: {}
    • Strings: ""
    • Numbers: integers (3), floating point (3.14), exponential (3.14e10)
    • Boolean: true and false
    • Null: null
  • Handles nested data structures, such as:

     { "key": "value", "nested": [{"name": "first", "elems": [1, true, null]}] }

    If passed through the loads(...) method will return:

     {'key': 'value', 'nested': [{'name': 'first', 'elems': [1, True, None]}]}

Known limitations & gotchas

Gotchas 👀

  • Infinity and NaN currently do not follow strictly the json module rules (still no allow_nan parameter).
  • If using this module on Python 2.3 and lower you MUST pass truthy_value and falsy_value;

Known bugs 🐛

These are some known bugs that will be fixed in the next releases:

  • Does not convert unicode strings to the respective character and viceversa (e.g. \u1eb7 is not converted to ).

     >>> json.loads('"\\u1eb7 \\u00a3"')
     - ORIGINAL: 'ặ £'
     - THIS    : '\\u1eb7 \\u00a3'
    
     >>> json.dumps('ặ £')
     - ORIGINAL: '"\\u1eb7 \\u00a3"'
     - THIS    : '"ặ £"'
    
  • Has some problems with backslashes (e.g. \n is not converted to \\n).

     >>> json.loads(r'"\" \\ \/ \b \f \n \r \t"')
     - ORIGINAL: '" \\ / \x08 \x0c \n \r \t'
     - THIS    : '" \\ / \x08 \x0c \n \r \t'
    
     >>> json.dumps('" \\ / \x08 \x0c \n \r \t')
     - ORIGINAL: '"\\" \\\\ / \\b \\f \\n \\r \\t"'
     - THIS    : '"\\" \\\\ / \x08 \x0c \n \r \t"'
    

Resources

Valid alternatives

These are some valid alternatives if this is not what you're looking for (as it probably is and should be), ordered by minimum supported version.

Library Description Built-in Supported Python versions
simplejson/python2.2 Branch of the simplejson library that mantains backwards compatibility with Python 2.2. Makes use of generator functions that were introduced in Python 2.2 (via PEP 255). No Python >= 2.2
demjson Feature rich module that uses only built-in methods and allows to encode, decode and syntax-checking JSON data. No Python >= 2.4
simplejson Externally maintained development version of the built-in json library included with Python. No Python >= 2.5
json Built-in library included with Python. Yes Python >= 2.6
orjson Fast JSON library written in Rust that serializes various data structures, such as dataclass, datetime/date/time and numpy.ndarray instances. No CPython >= 3.7
ujson Ultra fast JSON encoder and decoder written in pure C. No Python >= 3.7
python-rapidjson Python 3 wrapper around RapidJSON, an extremely fast C++ JSON parser and serialization library No Python >= 3.x
(unknown minor)

Development

  1. Clone the repository
  2. Install with poetry install --with dev

Tests

Tests ensure that changes to the codebase do not break existing features and that anything works as expected.

To launch the tests run the following command:

poetry run poe test

Please make sure to...

  • ... keep existing tests up-to-date with the latest changes;
  • ... write relative tests when adding new features.

Tests code style

When writing tests please keep the in mind that:

  • test files MUST be written for unittest;
  • test cases names MUST be a descriptive name written in PascalCase and end with TestCase (e.g. class MyTestCase(unittest.TestCase):);
  • test names MUST be a descriptive name written in snake_case (all lowercase, with words separated with an underscore) and start with test_ (e.g. def test_feature(self):);
  • MAY use the setUp() and teardown() methods to define instructions that will be executed before and after each test method;
  • each test MUST contain at least one self.assert* method call (we don't want empty no-op tests);

The following is an example of agood test from the official Python documentation:

import unittest

class WidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        self.widget.dispose()

    def test_default_widget_size(self):
        self.assertEqual(
			self.widget.size(),
			(50,50),
            'incorrect default size'
		)

    def test_widget_resize(self):
        self.widget.resize(100,150)
        self.assertEqual(
			self.widget.size(),
			(100,150),
            'wrong size after resize'
		)