Created
January 25, 2025 00:33
-
-
Save twardoch/3b8c846537ec84928317c3eb54c8d531 to your computer and use it in GitHub Desktop.
Quick and dirty JSON parsin with OrJSON, standard JSON and the https://github.com/jsonicjs/jsonic/ JS "relaxed" JSON parser, used via QuickJS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import inspect | |
import uuid | |
from functools import lru_cache | |
from pathlib import Path | |
def get_cache_path(folder_name: str = None) -> Path: | |
def generate_uuid() -> str: | |
"""Generate a UUID based on the file of the caller.""" | |
# Get the stack frame of the caller | |
caller_frame = inspect.stack()[2] | |
caller_file = caller_frame.filename | |
caller_path = Path(caller_file).resolve() | |
return str(uuid.uuid5(uuid.NAMESPACE_URL, str(caller_path))) | |
try: | |
import platformdirs | |
root_cache_dir = platformdirs.user_cache_dir() | |
except ImportError: | |
root_cache_dir = Path.home() / ".cache" | |
if not folder_name: | |
folder_name = generate_uuid() | |
cache_path = Path(root_cache_dir) / folder_name | |
cache_path.mkdir(parents=True, exist_ok=True) | |
return cache_path | |
try: | |
from joblib import Memory | |
JOBLIB_MEMORY = Memory(get_cache_path(), verbose=0) | |
except ImportError: | |
JOBLIB_MEMORY = None | |
@lru_cache(maxsize=None) | |
def ucache(folder_name: str = None): | |
"""A decorator for caching function results.""" | |
if JOBLIB_MEMORY: | |
memory = ( | |
JOBLIB_MEMORY | |
if folder_name is None | |
else Memory(get_cache_path(folder_name), verbose=0) | |
) | |
def decorator(func): | |
return memory.cache(func) | |
else: | |
def decorator(func): | |
return lru_cache(maxsize=None)(func) | |
return decorator |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
try: | |
import orjson as json_impl | |
is_orjson = True | |
import json as json_impl_std | |
from orjson import JSONDecodeError | |
except ImportError: | |
import json as json_impl | |
is_orjson = False | |
from json import JSONDecodeError | |
from microcache import ucache | |
from quickjs import Context | |
def qjs_jsonic_parser(): | |
@ucache() | |
def mjs_jsonic(): | |
import requests | |
mjs = requests.get("https://esm.sh/[email protected]/es2022/jsonic.bundle.mjs").text | |
mjs += "\nglobalThis.Zn = Zn;" | |
return mjs | |
ctx = Context() | |
ctx.module(mjs_jsonic()) | |
return ctx.get("Zn") | |
def get_json_from_any(text: str) -> str: | |
parser = qjs_jsonic_parser() | |
return parser(text).json() | |
def loads(text: str) -> dict: | |
"""Parse JSON string into Python object, handling relaxed JSON syntax. | |
Attempts parsing in this order: | |
1. orjson (if available) | |
2. relaxed JSON via jsonic + orjson/json | |
3. standard json module | |
""" | |
if is_orjson: | |
try: | |
return json_impl.loads(text) | |
except JSONDecodeError: | |
try: | |
cleaned = get_json_from_any(text) | |
return json_impl.loads(cleaned) | |
except json_impl.JSONDecodeError: | |
pass | |
try: | |
return json_impl.loads(text) | |
except JSONDecodeError: | |
raise ValueError("Could not parse JSON with any available method") | |
def dumps(obj: dict) -> str: | |
"""Serialize Python object to JSON string.""" | |
if is_orjson: | |
return json_impl.dumps(obj).decode("utf-8") | |
return json_impl.dumps(obj) | |
if __name__ == "__main__": | |
# Example of parsing standard JSON | |
valid_json = '{"name": John, "age": 30}' | |
parsed = loads(valid_json) | |
print("Parsed standard JSON:", parsed) | |
# Example of parsing relaxed JSON (with comments and trailing commas) | |
relaxed_json = """ | |
{"name": "Jane",//Hello | |
"age": 25,} | |
""" | |
try: | |
parsed = loads(relaxed_json) | |
print("\nParsed relaxed JSON:", parsed) | |
except ValueError as e: | |
print("Error parsing relaxed JSON:", e) | |
# Example of serializing Python dict to JSON | |
python_dict = {"name": "Alice", "scores": [95, 87, 91], "active": True} | |
json_str = dumps(python_dict) | |
print("\nSerialized to JSON:", json_str) | |
print("std", json_impl_std.dumps(python_dict)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment