or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-json5

A Python implementation of the JSON5 data format.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/json5@0.12.x

To install, run

npx @tessl/cli install tessl/pypi-json5@0.12.0

index.mddocs/

JSON5

A Python implementation of the JSON5 data format. JSON5 extends standard JSON with JavaScript-style features including single and multi-line comments, unquoted object keys for valid ECMAScript identifiers, trailing commas in objects and arrays, single-quoted strings, and multi-line string literals. This library mirrors the standard Python JSON API for ease of use.

Package Information

  • Package Name: json5
  • Language: Python
  • Installation: pip install json5

Core Imports

import json5

All functions are available at the top level:

from json5 import load, loads, dump, dumps, parse, JSON5Encoder, QuoteStyle

Basic Usage

import json5

# Parse JSON5 string
data = json5.loads('''
{
    // JavaScript-style comments
    unquoted: "keys are allowed",
    'single': 'quotes work too',
    "trailing": "commas are ok",
}
''')

# Serialize Python object to JSON5
obj = {"name": "example", "values": [1, 2, 3]}
json5_string = json5.dumps(obj, indent=2, trailing_commas=True)
print(json5_string)
# Output:
# {
#   name: 'example',
#   values: [
#     1,
#     2,
#     3,
#   ],
# }

# Parse from file
with open('config.json5', 'r') as f:
    config = json5.load(f)

# Write to file
with open('output.json5', 'w') as f:
    json5.dump(data, f, indent=2, quote_keys=False)

Capabilities

Parsing Functions

Load and parse JSON5 documents into Python objects, supporting file objects and strings with extensive customization options.

def load(
    fp,
    *,
    encoding=None,
    cls=None,
    object_hook=None,
    parse_float=None,
    parse_int=None,
    parse_constant=None,
    strict=True,
    object_pairs_hook=None,
    allow_duplicate_keys=True,
    consume_trailing=True,
    start=None
):
    """
    Deserialize fp (a .read()-supporting file-like object containing a JSON5 document) to a Python object.

    Parameters:
    - fp: file-like object with .read() method
    - encoding: character encoding (default: UTF-8)
    - cls: ignored (for json compatibility)
    - object_hook: optional function to transform decoded objects
    - parse_float: optional function to parse float values
    - parse_int: optional function to parse integer values  
    - parse_constant: optional function to parse constants (Infinity, NaN)
    - strict: if True, control characters (\\x00-\\x1f) in strings raise ValueError
    - object_pairs_hook: optional function called with ordered list of key-value pairs
    - allow_duplicate_keys: if False, duplicate keys raise ValueError
    - consume_trailing: if True, trailing non-whitespace raises ValueError
    - start: offset position to start parsing from in file

    Returns:
    Parsed Python object

    Raises:
    - ValueError: invalid JSON5 document
    - UnicodeDecodeError: invalid UTF-8 encoding
    """

def loads(
    s,
    *,
    encoding=None,
    cls=None,
    object_hook=None,
    parse_float=None,
    parse_int=None,
    parse_constant=None,
    strict=True,
    object_pairs_hook=None,
    allow_duplicate_keys=True,
    consume_trailing=True,
    start=None
):
    """
    Deserialize s (a string containing a JSON5 document) to a Python object.

    Parameters:
    - s: JSON5 string to parse
    - encoding: character encoding (default: UTF-8)
    - cls: ignored (for json compatibility)
    - object_hook: optional function to transform decoded objects
    - parse_float: optional function to parse float values
    - parse_int: optional function to parse integer values
    - parse_constant: optional function to parse constants (Infinity, NaN)
    - strict: if True, control characters (\\x00-\\x1f) in strings raise ValueError
    - object_pairs_hook: optional function called with ordered list of key-value pairs
    - allow_duplicate_keys: if False, duplicate keys raise ValueError
    - consume_trailing: if True, trailing non-whitespace raises ValueError
    - start: offset position to start parsing from in string

    Returns:
    Parsed Python object

    Raises:
    - ValueError: invalid JSON5 document
    - UnicodeDecodeError: invalid UTF-8 encoding
    """

def parse(
    s,
    *,
    encoding=None,
    cls=None,
    object_hook=None,
    parse_float=None,
    parse_int=None,
    parse_constant=None,
    strict=True,
    object_pairs_hook=None,
    allow_duplicate_keys=True,
    consume_trailing=True,
    start=None
):
    """
    Parse s, returning positional information along with a value.

    Useful for parsing multiple values from a single string by repeatedly calling
    with start parameter set to the position returned from previous call.

    Parameters:
    - s: JSON5 string to parse
    - encoding: character encoding (default: UTF-8)
    - cls: ignored (for json compatibility)
    - object_hook: optional function to transform decoded objects
    - parse_float: optional function to parse float values
    - parse_int: optional function to parse integer values
    - parse_constant: optional function to parse constants (Infinity, NaN)
    - strict: if True, control characters (\\x00-\\x1f) in strings raise ValueError
    - object_pairs_hook: optional function called with ordered list of key-value pairs
    - allow_duplicate_keys: if False, duplicate keys raise ValueError
    - consume_trailing: if True, trailing non-whitespace raises ValueError
    - start: offset position to start parsing from in string

    Returns:
    Tuple of (value, error_string, position):
    - value: parsed Python object or None if error
    - error_string: None if successful, error message if failed
    - position: zero-based offset where parsing stopped

    Raises:
    - UnicodeDecodeError: invalid UTF-8 encoding
    """

Usage Examples

import json5

# Basic parsing
data = json5.loads('{"name": "example"}')

# Parse with custom hooks
def custom_object_hook(obj):
    return {k.upper(): v for k, v in obj.items()}

data = json5.loads('{"name": "example"}', object_hook=custom_object_hook)
# Result: {"NAME": "example"}

# Parse multiple values from string
s = '{"a": 1} {"b": 2} {"c": 3}'
values = []
start = 0
while start < len(s):
    value, error, pos = json5.parse(s, start=start, consume_trailing=False)
    if error:
        break
    values.append(value)
    start = pos
    # Skip whitespace
    while start < len(s) and s[start].isspace():
        start += 1

# Reject duplicate keys
try:
    json5.loads('{"key": 1, "key": 2}', allow_duplicate_keys=False)
except ValueError as e:
    print(f"Duplicate key error: {e}")

Serialization Functions

Serialize Python objects to JSON5 format with extensive formatting and style options.

def dump(
    obj,
    fp,
    *,
    skipkeys=False,
    ensure_ascii=True,
    check_circular=True,
    allow_nan=True,
    cls=None,
    indent=None,
    separators=None,
    default=None,
    sort_keys=False,
    quote_keys=False,
    trailing_commas=True,
    allow_duplicate_keys=True,
    quote_style=QuoteStyle.ALWAYS_DOUBLE,
    **kwargs
):
    """
    Serialize obj to a JSON5-formatted stream to fp (a .write()-supporting file-like object).

    Parameters:
    - obj: Python object to serialize
    - fp: file-like object with .write() method
    - skipkeys: if True, skip keys that are not basic types
    - ensure_ascii: if True, escape non-ASCII characters
    - check_circular: if True, check for circular references
    - allow_nan: if True, allow NaN, Infinity, -Infinity
    - cls: custom JSON5Encoder class
    - indent: indentation (int for spaces, str for custom, None for compact)
    - separators: (item_separator, key_separator) tuple
    - default: function to handle non-serializable objects
    - sort_keys: if True, sort object keys
    - quote_keys: if True, always quote object keys
    - trailing_commas: if True, add trailing commas in multiline output
    - allow_duplicate_keys: if True, allow duplicate keys in output
    - quote_style: QuoteStyle enum value controlling string quoting

    Raises:
    - TypeError: non-serializable object
    - ValueError: circular reference or invalid value
    """

def dumps(
    obj,
    *,
    skipkeys=False,
    ensure_ascii=True,
    check_circular=True,
    allow_nan=True,
    cls=None,
    indent=None,
    separators=None,
    default=None,
    sort_keys=False,
    quote_keys=False,
    trailing_commas=True,
    allow_duplicate_keys=True,
    quote_style=QuoteStyle.ALWAYS_DOUBLE,
    **kwargs
):
    """
    Serialize obj to a JSON5-formatted string.

    Parameters:
    - obj: Python object to serialize
    - skipkeys: if True, skip keys that are not basic types
    - ensure_ascii: if True, escape non-ASCII characters
    - check_circular: if True, check for circular references
    - allow_nan: if True, allow NaN, Infinity, -Infinity
    - cls: custom JSON5Encoder class
    - indent: indentation (int for spaces, str for custom, None for compact)
    - separators: (item_separator, key_separator) tuple
    - default: function to handle non-serializable objects
    - sort_keys: if True, sort object keys
    - quote_keys: if True, always quote object keys
    - trailing_commas: if True, add trailing commas in multiline output
    - allow_duplicate_keys: if True, allow duplicate keys in output
    - quote_style: QuoteStyle enum value controlling string quoting

    Returns:
    JSON5-formatted string

    Raises:
    - TypeError: non-serializable object
    - ValueError: circular reference or invalid value
    """

Usage Examples

import json5
from json5 import QuoteStyle

# Basic serialization
data = {"name": "example", "values": [1, 2, 3]}
json5_str = json5.dumps(data)

# Pretty-printed with unquoted keys and trailing commas
json5_str = json5.dumps(data, indent=2, quote_keys=False, trailing_commas=True)

# Use single quotes for strings
json5_str = json5.dumps(data, quote_style=QuoteStyle.ALWAYS_SINGLE)

# JSON compatibility mode
json_str = json5.dumps(data, quote_keys=True, trailing_commas=False)

# Custom serialization
def custom_serializer(obj):
    if hasattr(obj, '__dict__'):
        return obj.__dict__
    raise TypeError(f"Object of type {type(obj)} is not JSON5 serializable")

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Alice", 30)
json5_str = json5.dumps(person, default=custom_serializer, indent=2)

Encoder Classes

Customizable JSON5 encoder for advanced serialization control and extensibility.

class JSON5Encoder:
    """
    Customizable JSON5 encoder class.
    """
    
    def __init__(
        self,
        *,
        skipkeys=False,
        ensure_ascii=True,
        check_circular=True,
        allow_nan=True,
        indent=None,
        separators=None,
        default=None,
        sort_keys=False,
        quote_keys=False,
        trailing_commas=True,
        allow_duplicate_keys=True,
        quote_style=QuoteStyle.ALWAYS_DOUBLE,
        **kwargs
    ):
        """
        Initialize JSON5 encoder with formatting options.

        Parameters match those of dumps() function.
        """

    def default(self, obj):
        """
        Override to provide custom serialization for objects that are not
        natively JSON5 serializable.

        Parameters:
        - obj: object to serialize

        Returns:
        JSON5-serializable representation of obj

        Raises:
        - TypeError: if obj cannot be serialized
        """

    def encode(self, obj, seen, level, *, as_key=False):
        """
        Return JSON5-encoded version of obj.

        Parameters:
        - obj: object to encode
        - seen: set of object ids for circular reference detection
        - level: current nesting level
        - as_key: if True, encode as object key

        Returns:
        JSON5-encoded string

        Raises:
        - TypeError: unsupported object type
        - ValueError: circular reference or invalid value
        """

    def is_identifier(self, key):
        """
        Check if key can be used as unquoted object key.

        Parameters:
        - key: string to check

        Returns:
        True if key is valid ECMAScript identifier
        """

    def is_reserved_word(self, key):
        """
        Check if key is ECMAScript reserved word.

        Parameters:
        - key: string to check

        Returns:
        True if key is reserved word
        """

Usage Examples

import json5
from json5 import JSON5Encoder, QuoteStyle

# Custom encoder for special objects
class CustomEncoder(JSON5Encoder):
    def default(self, obj):
        if isinstance(obj, set):
            return list(obj)
        if hasattr(obj, 'isoformat'):  # datetime objects
            return obj.isoformat()
        return super().default(obj)

# Use custom encoder
from datetime import datetime
data = {
    "timestamp": datetime.now(),
    "tags": {"python", "json5", "serialization"}
}
json5_str = json5.dumps(data, cls=CustomEncoder, indent=2)

# Encoder with custom quote style
encoder = JSON5Encoder(
    quote_style=QuoteStyle.PREFER_SINGLE,
    indent=2,
    trailing_commas=True
)
json5_str = encoder.encode(data, set(), 0, as_key=False)

String Quoting Styles

Control how strings are quoted during JSON5 serialization.

class QuoteStyle(enum.Enum):
    """
    Enum controlling how strings are quoted during encoding.
    """
    
    ALWAYS_DOUBLE = 'always_double'    # Always use double quotes
    ALWAYS_SINGLE = 'always_single'    # Always use single quotes  
    PREFER_DOUBLE = 'prefer_double'    # Prefer double, use single if fewer escapes
    PREFER_SINGLE = 'prefer_single'    # Prefer single, use double if fewer escapes

Usage Examples

import json5
from json5 import QuoteStyle

text = "It's a \"wonderful\" day"

# Different quote styles
double_quoted = json5.dumps(text, quote_style=QuoteStyle.ALWAYS_DOUBLE)
# Result: "\"It's a \\\"wonderful\\\" day\""

single_quoted = json5.dumps(text, quote_style=QuoteStyle.ALWAYS_SINGLE) 
# Result: "'It\\'s a \"wonderful\" day'"

prefer_double = json5.dumps(text, quote_style=QuoteStyle.PREFER_DOUBLE)
# Result: "'It\\'s a \"wonderful\" day'" (fewer escapes with single quotes)

prefer_single = json5.dumps(text, quote_style=QuoteStyle.PREFER_SINGLE)
# Result: "'It\\'s a \"wonderful\" day'" (preferred single quotes)

Version Information

Access package version information for compatibility and debugging.

__version__: str  # Package version string (e.g., "0.12.1")
VERSION: str      # Backward compatibility alias for __version__

Usage Examples

import json5

print(f"Using json5 version: {json5.__version__}")
print(f"Version (legacy): {json5.VERSION}")

# Version checking
from packaging import version
if version.parse(json5.__version__) >= version.parse("0.12.0"):
    print("QuoteStyle enum is available")

JSON5 Features Supported

This implementation supports all JSON5 language features:

  • Comments: Single-line // and multi-line /* */ comments
  • Unquoted Keys: Object keys that are valid ECMAScript identifiers don't need quotes
  • Trailing Commas: Objects and arrays can have trailing commas
  • Single Quotes: Strings can be single-quoted
  • Multi-line Strings: String literals can span multiple lines
  • Additional Number Formats: Hexadecimal numbers (0xFF), positive/negative infinity, NaN
  • Escape Sequences: All JSON escape sequences plus single quote and vertical tab

Error Handling

The library raises standard Python exceptions:

  • ValueError: Invalid JSON5 syntax, duplicate keys (when disabled), circular references
  • TypeError: Non-serializable objects during encoding
  • UnicodeDecodeError: Invalid UTF-8 byte sequences
import json5

# Handle parsing errors
try:
    data = json5.loads('{"invalid": syntax}')
except ValueError as e:
    print(f"Parse error: {e}")

# Handle encoding errors  
try:
    json5.dumps(object())  # object() is not serializable
except TypeError as e:
    print(f"Encoding error: {e}")