JXC Python Library¶
Installing¶
The fastest way to start using JXC from Python is with pip. If you're already comfortable installing other Python packages, you can simply run pip install jxc
and you're good to go.
The recommended approach is to set up a virtualenv first, for example:
$ virtualenv venv
$ source venv/bin/activate
(venv) $ pip install jxc
(venv) $ python -c "import jxc; print(jxc.loads('[1, 2, 3]'))"
[1, 2, 3]
Basic Usage¶
The JXC Python library has two APIs - a simple one similar to json.loads
/json.dumps
, and a more complex but more flexible one.
Simple API: Parsing¶
import jxc
print(jxc.loads("[1, 2, true, null, {}, dt'1999-07-18']"))
[1, 2, True, None, {}, datetime.date(1999, 7, 18)]
Simple API: Serializing¶
import jxc, datetime
print(jxc.dumps([1, 2, True, None, {}, datetime.date(1999, 7, 18)]))
[1,2,true,null,{},dt"1999-07-18"]
Handling Annotations¶
Take this data normalization example from the home page. Lets say we wanted to convert any value with a vec3
annotation to a Python tuple containing three floats.
[
vec3{x: 1, y: 2, z: 3}
vec3[-3, -2, -1]
vec3 0.2
vec3 null
]
import jxc
def read_vec3(value):
if isinstance(value, dict) and len(value) == 3:
return (float(value['x']), float(value['y']), float(value['z']))
elif isinstance(value, list) and len(value) == 3:
return tuple(float(v) for v in value)
elif isinstance(value, (int, float)):
return (float(value), float(value), float(value))
elif value is None:
return (0.0, 0.0, 0.0)
else:
raise TypeError(f'Invalid value for vec3: {value!r}')
vecs = jxc.loads("""
[
vec3{ x: 1, y: 2, z: 3 }
vec3[ -3, -2, -1 ]
vec3 0.2
vec3 null
]
""",
annotation_hooks=[('vec3', read_vec3)],
)
assert vecs == [
(1.0, 2.0, 3.0),
(-3.0, -2.0, -1.0),
(0.2, 0.2, 0.2),
(0.0, 0.0, 0.0),
]
Dataclasses and Enums¶
Lets say you want to use more complex objects. You could write your own serializers for types, but if your types are simple, you could just use dataclasses and enums, which are supported out of the box.
To start with, lets define some types we want to use:
from enum import Enum
from dataclasses import dataclass
import jxc
class DataType(Enum):
A = 'A'
B = 'B'
@dataclass
class Data:
val: tuple[float, float]
name: str
ty: DataType
meta: dict[str, str]
Serializing these is trivial:
print(jxc.dumps(
Data(val=(2.5, -5.6), name='abc', ty=DataType.B, meta={ 'key': 'value' }),
indent=4,
encode_dataclass=True,
encode_enum=True))
Output:
Data{
val: [
2.5,
-5.6,
],
name: "abc",
ty: DataType "B",
meta: {
key: "value",
},
}
Parsing these values is also trivial:
print(jxc.loads("""
Data{
name: 'jxc'
ty: DataType 'A'
val: [ -4.1, 9.8 ]
meta: { key.a: 'b', key.b: '_' }
}
""",
decode_dataclass=True,
decode_enum=True))
Output:
Data(val=[-4.1, 9.8], name='jxc', ty=<DataType.A: 'A'>, meta={'key.a': 'b', 'key.b': '_'})