CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-json5

A Python implementation of the JSON5 data format.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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}")
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/json5@0.12.x
Publish Source
CLI
Badge
tessl/pypi-json5 badge