orjson est une bibliothèque JSON rapide et correcte pour Python. Elle est considérée comme la bibliothèque Python la plus rapide pour JSON et est plus correcte que la bibliothèque json standard ou d'autres bibliothèques tierces. Il sérialise les instances dataclass, datetime, numpy et UUID de manière native.
orjson.dumps() est environ 10 fois plus rapide que json
, sérialise les types et sous-types courants, possède un paramètre default
permettant à l'appelant de spécifier comment sérialiser les types arbitraires et dispose d'un certain nombre d'indicateurs contrôlant la sortie.
orjson.loads() est environ 2 fois plus rapide que json
et est strictement conforme à UTF-8 et RFC 8259 ("Le format d'échange de données JavaScript Object Notation (JSON)").
La lecture et l'écriture dans des fichiers, des fichiers JSON délimités par des lignes, etc. ne sont pas fournies par la bibliothèque.
orjson prend en charge CPython 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 et 3.14.
Il distribue les roues amd64/x86_64, i686/x86, aarch64/armv8, arm7, POWER/ppc64le et s390x pour Linux, les roues amd64 et aarch64 pour macOS et les roues amd64 et i686/x86 pour Windows.
orjson ne prend pas en charge et ne prendra pas en charge PyPy, les versions Python intégrées pour Android/iOS ou les sous-interprètes PEP 554.
Les versions suivent le versionnement sémantique et la sérialisation d'un nouveau type d'objet sans indicateur d'adhésion est considérée comme une modification radicale.
orjson est sous licence Apache 2.0 et MIT. Le référentiel et le suivi des problèmes sont github.com/ijl/orjson, et les correctifs peuvent y être soumis. Il existe un CHANGELOG disponible dans le référentiel.
Pour installer une roue depuis PyPI, installez le package orjson
.
Au format requirements.in
ou requirements.txt
, spécifiez :
orjson >= 3.10,<4
Au format pyproject.toml
, précisez :
orjson = " ^3.10 "
Pour construire une roue, voir emballage.
Voici un exemple de sérialisation, avec des options spécifiées, et de désérialisation :
> >> import orjson , datetime , numpy
> >> data = {
"type" : "job" ,
"created_at" : datetime . datetime ( 1970 , 1 , 1 ),
"status" : "?" ,
"payload" : numpy . array ([[ 1 , 2 ], [ 3 , 4 ]]),
}
> >> orjson . dumps ( data , option = orjson . OPT_NAIVE_UTC | orjson . OPT_SERIALIZE_NUMPY )
b'{"type":"job","created_at":"1970-01-01T00:00:00+00:00","status":" xf0 x9f x86 x97 ","payload":[[1,2],[3,4]]}'
> >> orjson . loads ( _ )
{ 'type' : 'job' , 'created_at' : '1970-01-01T00:00:00+00:00' , 'status' : '?' , 'payload' : [[ 1 , 2 ], [ 3 , 4 ]]}
orjson version 3 sérialise plus de types que la version 2. Les sous-classes de str
, int
, dict
et list
sont désormais sérialisées. C'est plus rapide et plus similaire à la bibliothèque standard. Il peut être désactivé avec orjson.OPT_PASSTHROUGH_SUBCLASS
. Les instances dataclasses.dataclass
sont désormais sérialisées par défaut et ne peuvent pas être personnalisées dans une fonction default
à moins que option=orjson.OPT_PASSTHROUGH_DATACLASS
ne soit spécifié. Les instances uuid.UUID
sont sérialisées par défaut. Pour tout type désormais sérialisé, les implémentations dans une fonction default
et les options les activant peuvent être supprimées mais ce n'est pas obligatoire. Il n'y a eu aucun changement dans la désérialisation.
Pour migrer depuis la bibliothèque standard, la plus grande différence est que orjson.dumps
renvoie bytes
et json.dumps
renvoie un str
.
Les utilisateurs avec des objets dict
utilisant des clés non str
doivent spécifier option=orjson.OPT_NON_STR_KEYS
.
sort_keys
est remplacé par option=orjson.OPT_SORT_KEYS
.
indent
est remplacé par option=orjson.OPT_INDENT_2
et les autres niveaux d'indentation ne sont pas pris en charge.
ensure_ascii
n'est probablement pas pertinent aujourd'hui et les caractères UTF-8 ne peuvent pas être échappés en ASCII.
def dumps (
__obj : Any ,
default : Optional [ Callable [[ Any ], Any ]] = ...,
option : Optional [ int ] = ...,
) -> bytes : ...
dumps()
sérialise les objets Python en JSON.
Il sérialise nativement str
, dict
, list
, tuple
, int
, float
, bool
, None
, dataclasses.dataclass
, typing.TypedDict
, datetime.datetime
, datetime.date
, datetime.time
, uuid.UUID
, numpy.ndarray
et orjson.Fragment
les instances. Il prend en charge les types arbitraires par default
. Il sérialise les sous-classes de str
, int
, dict
, list
, dataclasses.dataclass
et enum.Enum
. Il ne sérialise pas les sous-classes de tuple
pour éviter de sérialiser les objets namedtuple
sous forme de tableaux. Pour éviter de sérialiser les sous-classes, spécifiez l'option orjson.OPT_PASSTHROUGH_SUBCLASS
.
La sortie est un objet bytes
contenant UTF-8.
Le verrouillage global de l'interprète (GIL) est maintenu pendant toute la durée de l'appel.
Il déclenche JSONEncodeError
sur un type non pris en charge. Ce message d'exception décrit l'objet non valide avec le message d'erreur Type is not JSON serializable: ...
. Pour résoudre ce problème, spécifiez default.
Il déclenche JSONEncodeError
sur une str
contenant du UTF-8 non valide.
Il lève JSONEncodeError
sur un entier qui dépasse 64 bits par défaut ou, avec OPT_STRICT_INTEGER
, 53 bits.
Il déclenche JSONEncodeError
si un dict
a une clé d'un type autre que str
, sauf si OPT_NON_STR_KEYS
est spécifié.
Il déclenche JSONEncodeError
si la sortie par default
revient à la gestion par default
de plus de 254 niveaux de profondeur.
Il déclenche JSONEncodeError
sur les références circulaires.
Il génère JSONEncodeError
si un tzinfo
sur un objet datetime n'est pas pris en charge.
JSONEncodeError
est une sous-classe de TypeError
. Ceci est pour la compatibilité avec la bibliothèque standard.
Si l'échec a été provoqué par une exception par default
, JSONEncodeError
enchaîne l'exception d'origine sous la forme __cause__
.
Pour sérialiser une sous-classe ou des types arbitraires, spécifiez default
comme appelable qui renvoie un type pris en charge. default
peut être une instance de fonction, lambda ou de classe appelable. Pour spécifier qu'un type n'a pas été géré par default
, déclenchez une exception telle que TypeError
.
> >> import orjson , decimal
> >>
def default ( obj ):
if isinstance ( obj , decimal . Decimal ):
return str ( obj )
raise TypeError
> >> orjson . dumps ( decimal . Decimal ( "0.0842389659712649442845" ))
JSONEncodeError : Type is not JSON serializable : decimal . Decimal
> >> orjson . dumps ( decimal . Decimal ( "0.0842389659712649442845" ), default = default )
b'"0.0842389659712649442845"'
> >> orjson . dumps ({ 1 , 2 }, default = default )
orjson . JSONEncodeError : Type is not JSON serializable : set
L'appelable default
peut renvoyer un objet qui doit lui-même être géré par default
jusqu'à 254 fois avant qu'une exception ne soit levée.
Il est important que default
déclenche une exception si un type ne peut pas être géré. Sinon, Python renvoie implicitement None
, qui apparaît à l'appelant comme une valeur légitime et est sérialisée :
> >> import orjson , json
> >>
def default ( obj ):
if isinstance ( obj , decimal . Decimal ):
return str ( obj )
> >> orjson . dumps ({ "set" :{ 1 , 2 }}, default = default )
b'{"set":null}'
> >> json . dumps ({ "set" :{ 1 , 2 }}, default = default )
'{"set":null}'
Pour modifier la façon dont les données sont sérialisées, spécifiez option
. Chaque option
est une constante entière dans orjson
. Pour spécifier plusieurs options, masquez-les ensemble, par exemple option=orjson.OPT_STRICT_INTEGER | orjson.OPT_NAIVE_UTC
.
Ajoutez n
à la sortie. Il s'agit d'une commodité et d'une optimisation pour le modèle de dumps(...) + "n"
. Les objets bytes
sont immuables et ce modèle copie le contenu original.
> >> import orjson
> >> orjson . dumps ([])
b"[]"
> >> orjson . dumps ([], option = orjson . OPT_APPEND_NEWLINE )
b"[] n "
Sortie joliment imprimée avec un retrait de deux espaces. Cela équivaut à indent=2
dans la bibliothèque standard. L'impression jolie est plus lente et le résultat est plus grand. orjson est la bibliothèque comparée la plus rapide en matière d'impression jolie et présente beaucoup moins de ralentissement pour l'impression jolie que la bibliothèque standard. Cette option est compatible avec toutes les autres options.
> >> import orjson
> >> orjson . dumps ({ "a" : "b" , "c" : { "d" : True }, "e" : [ 1 , 2 ]})
b'{"a":"b","c":{"d":true},"e":[1,2]}'
> >> orjson . dumps (
{ "a" : "b" , "c" : { "d" : True }, "e" : [ 1 , 2 ]},
option = orjson . OPT_INDENT_2
)
b'{ n "a": "b", n "c": { n "d": true n }, n "e": [ n 1, n 2 n ] n }'
S'ils sont affichés, l'indentation et les sauts de ligne apparaissent comme ceci :
{
"a" : " b " ,
"c" : {
"d" : true
},
"e" : [
1 ,
2
]
}
Cela mesure la sérialisation du luminaire github.json comme étant compact (52 Ko) ou joli (64 Ko) :
Bibliothèque | compact (ms) | jolie (mme) | contre orjson |
---|---|---|---|
orjson | 0,01 | 0,02 | 1 |
json | 0,13 | 0,54 | 34 |
Cela mesure la sérialisation du luminaire citm_catalog.json, plutôt dans le pire des cas en raison de la quantité d'imbrication et de nouvelles lignes, aussi compact (489 Ko) ou joli (1,1 Mo) :
Bibliothèque | compact (ms) | jolie (mme) | contre orjson |
---|---|---|---|
orjson | 0,25 | 0,45 | 1 |
json | 3.01 | 24h42 | 54,4 |
Ceci peut être reproduit à l'aide du script pyindent
.
Sérialisez les objets datetime.datetime
sans tzinfo
au format UTC. Cela n'a aucun effet sur les objets datetime.datetime
pour lesquels tzinfo
est défini.
> >> import orjson , datetime
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 ),
)
b'"1970-01-01T00:00:00"'
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 ),
option = orjson . OPT_NAIVE_UTC ,
)
b'"1970-01-01T00:00:00+00:00"'
Sérialisez les clés dict
d'un type autre que str
. Cela permet aux clés dict
d'être l'une des suivantes str
, int
, float
, bool
, None
, datetime.datetime
, datetime.date
, datetime.time
, enum.Enum
et uuid.UUID
. À titre de comparaison, la bibliothèque standard sérialise str
, int
, float
, bool
ou None
par défaut. orjson est considéré comme étant plus rapide à sérialiser les clés non str
que les autres bibliothèques. Cette option est plus lente pour les clés str
que la valeur par défaut.
> >> import orjson , datetime , uuid
> >> orjson . dumps (
{ uuid . UUID ( "7202d115-7ff3-4c81-a7c1-2a1f067b1ece" ): [ 1 , 2 , 3 ]},
option = orjson . OPT_NON_STR_KEYS ,
)
b'{"7202d115-7ff3-4c81-a7c1-2a1f067b1ece":[1,2,3]}'
> >> orjson . dumps (
{ datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 ): [ 1 , 2 , 3 ]},
option = orjson . OPT_NON_STR_KEYS | orjson . OPT_NAIVE_UTC ,
)
b'{"1970-01-01T00:00:00+00:00":[1,2,3]}'
Ces types sont généralement sérialisés comme ils le seraient en tant que valeurs, par exemple, datetime.datetime
est toujours une chaîne RFC 3339 et respecte les options qui l'affectent. L'exception est que la sérialisation int
ne respecte pas OPT_STRICT_INTEGER
.
Cette option présente le risque de créer des clés en double. En effet, les objets non str
peuvent être sérialisés avec la même str
qu'une clé existante, par exemple {"1": true, 1: false}
. La dernière clé à insérer dans le dict
sera sérialisée en dernier et un désérialiseur JSON prendra probablement la dernière occurrence d'une clé (dans ce qui précède, false
). La première valeur sera perdue.
Cette option est compatible avec orjson.OPT_SORT_KEYS
. Si le tri est utilisé, notez que le tri est instable et sera imprévisible pour les clés en double.
> >> import orjson , datetime
> >> orjson . dumps (
{ "other" : 1 , datetime . date ( 1970 , 1 , 5 ): 2 , datetime . date ( 1970 , 1 , 3 ): 3 },
option = orjson . OPT_NON_STR_KEYS | orjson . OPT_SORT_KEYS
)
b'{"1970-01-03":3,"1970-01-05":2,"other":1}'
Cela mesure la sérialisation de 589 Ko de JSON comprenant une list
de 100 dict
dans laquelle chaque dict
a à la fois 365 clés int
triées de manière aléatoire représentant les horodatages d'époque ainsi qu'une clé str
et la valeur de chaque clé est un seul entier. Dans "str key", les clés ont été converties en str
avant la sérialisation, et orjson spécifie toujours option=orjson.OPT_NON_STR_KEYS
(ce qui est toujours un peu plus lent).
Bibliothèque | touches str (ms) | clés int (ms) | clés int triées (ms) |
---|---|---|---|
orjson | 0,5 | 0,93 | 2.08 |
json | 2,72 | 3,59 |
json est vide car il déclenche TypeError
lors de la tentative de tri avant de convertir toutes les clés en str
. Ceci peut être reproduit à l'aide du script pynonstr
.
Ne sérialisez pas le champ microsecond
sur les instances datetime.datetime
et datetime.time
.
> >> import orjson , datetime
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , 1 ),
)
b'"1970-01-01T00:00:00.000001"'
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , 1 ),
option = orjson . OPT_OMIT_MICROSECONDS ,
)
b'"1970-01-01T00:00:00"'
Passthrough des instances dataclasses.dataclass
vers default
. Cela permet de personnaliser leur sortie mais est beaucoup plus lent.
> >> import orjson , dataclasses
> >>
@ dataclasses . dataclass
class User :
id : str
name : str
password : str
def default ( obj ):
if isinstance ( obj , User ):
return { "id" : obj . id , "name" : obj . name }
raise TypeError
> >> orjson . dumps ( User ( "3b1" , "asd" , "zxc" ))
b'{"id":"3b1","name":"asd","password":"zxc"}'
> >> orjson . dumps ( User ( "3b1" , "asd" , "zxc" ), option = orjson . OPT_PASSTHROUGH_DATACLASS )
TypeError : Type is not JSON serializable : User
> >> orjson . dumps (
User ( "3b1" , "asd" , "zxc" ),
option = orjson . OPT_PASSTHROUGH_DATACLASS ,
default = default ,
)
b'{"id":"3b1","name":"asd"}'
Passthrough des instances datetime.datetime
, datetime.date
et datetime.time
par default
. Cela permet de sérialiser les dates et heures dans un format personnalisé, par exemple des dates HTTP :
> >> import orjson , datetime
> >>
def default ( obj ):
if isinstance ( obj , datetime . datetime ):
return obj . strftime ( "%a, %d %b %Y %H:%M:%S GMT" )
raise TypeError
> >> orjson . dumps ({ "created_at" : datetime . datetime ( 1970 , 1 , 1 )})
b'{"created_at":"1970-01-01T00:00:00"}'
> >> orjson . dumps ({ "created_at" : datetime . datetime ( 1970 , 1 , 1 )}, option = orjson . OPT_PASSTHROUGH_DATETIME )
TypeError : Type is not JSON serializable : datetime . datetime
> >> orjson . dumps (
{ "created_at" : datetime . datetime ( 1970 , 1 , 1 )},
option = orjson . OPT_PASSTHROUGH_DATETIME ,
default = default ,
)
b'{"created_at":"Thu, 01 Jan 1970 00:00:00 GMT"}'
Cela n'affecte pas les dates et heures dans les clés dict
si vous utilisez OPT_NON_STR_KEYS.
Passthrough des sous-classes des types intégrés par default
.
> >> import orjson
> >>
class Secret ( str ):
pass
def default ( obj ):
if isinstance ( obj , Secret ):
return "******"
raise TypeError
> >> orjson . dumps ( Secret ( "zxc" ))
b'"zxc"'
> >> orjson . dumps ( Secret ( "zxc" ), option = orjson . OPT_PASSTHROUGH_SUBCLASS )
TypeError : Type is not JSON serializable : Secret
> >> orjson . dumps ( Secret ( "zxc" ), option = orjson . OPT_PASSTHROUGH_SUBCLASS , default = default )
b'"******"'
Cela n'affecte pas la sérialisation des sous-classes en tant que clés dict
si vous utilisez OPT_NON_STR_KEYS.
Ceci est obsolète et n’a aucun effet dans la version 3. Dans la version 2, cela était nécessaire pour sérialiser les instances dataclasses.dataclass
. Pour en savoir plus, consultez dataclass.
Sérialisez les instances numpy.ndarray
. Pour en savoir plus, consultez numpy.
Ceci est obsolète et n'a aucun effet dans la version 3. Dans la version 2, cela était nécessaire pour sérialiser les instances uuid.UUID
. Pour en savoir plus, consultez UUID.
Sérialisez les clés dict
dans l’ordre trié. La valeur par défaut est de sérialiser dans un ordre non spécifié. Ceci équivaut à sort_keys=True
dans la bibliothèque standard.
Cela peut être utilisé pour garantir que l'ordre est déterministe pour le hachage ou les tests. Cela entraîne une perte de performances substantielle et n'est pas recommandé en général.
> >> import orjson
> >> orjson . dumps ({ "b" : 1 , "c" : 2 , "a" : 3 })
b'{"b":1,"c":2,"a":3}'
> >> orjson . dumps ({ "b" : 1 , "c" : 2 , "a" : 3 }, option = orjson . OPT_SORT_KEYS )
b'{"a":3,"b":1,"c":2}'
Cela mesure la sérialisation du luminaire twitter.json non trié et trié :
Bibliothèque | non trié (ms) | trié (ms) | contre orjson |
---|---|---|---|
orjson | 0,11 | 0,3 | 1 |
json | 1,36 | 1,93 | 6.4 |
Le benchmark peut être reproduit à l'aide du script pysort
.
Le tri n'est pas compatible avec le classement/les paramètres régionaux :
> >> import orjson
> >> orjson . dumps ({ "a" : 1 , "ä" : 2 , "A" : 3 }, option = orjson . OPT_SORT_KEYS )
b'{"A":3,"a":1," xc3 xa4 ":2}'
C'est le même comportement de tri que la bibliothèque standard.
dataclass
est également sérialisé sous forme de cartes mais cela n'a aucun effet sur elles.
Appliquez une limite de 53 bits aux nombres entiers. La limite est par ailleurs de 64 bits, identique à celle de la bibliothèque standard Python. Pour en savoir plus, voir int.
Sérialisez un fuseau horaire UTC sur les instances datetime.datetime
en tant que Z
au lieu de +00:00
.
> >> import orjson , datetime , zoneinfo
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , tzinfo = zoneinfo . ZoneInfo ( "UTC" )),
)
b'"1970-01-01T00:00:00+00:00"'
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , tzinfo = zoneinfo . ZoneInfo ( "UTC" )),
option = orjson . OPT_UTC_Z
)
b'"1970-01-01T00:00:00Z"'
orjson.Fragment
inclut du JSON déjà sérialisé dans un document. Il s'agit d'un moyen efficace d'inclure des blobs JSON à partir d'un cache, d'un champ JSONB ou d'un objet sérialisé séparément sans d'abord désérialiser en objets Python via loads()
.
> >> import orjson
> >> orjson . dumps ({ "key" : "zxc" , "data" : orjson . Fragment ( b'{"a": "b", "c": 1}' )})
b'{"key":"zxc","data":{"a": "b", "c": 1}}'
Il n'effectue aucun reformatage : orjson.OPT_INDENT_2
n'affectera pas un blob compact et un blob JSON joliment imprimé ne sera pas réécrit en tant que compact.
L'entrée doit être bytes
ou str
et donnée comme argument de position.
Cela déclenche orjson.JSONEncodeError
si une str
est donnée et que l'entrée n'est pas UTF-8 valide. Sinon, aucune validation n’est effectuée et il est possible d’écrire du JSON invalide. Cela n'échappe pas aux caractères. L'implémentation est testée pour ne pas planter en cas de chaînes non valides ou de JSON non valide.
def loads ( __obj : Union [ bytes , bytearray , memoryview , str ]) -> Any : ...
loads()
désérialise JSON en objets Python. Il se désérialise en objets dict
, list
, int
, float
, str
, bool
et None
.
Les entrées bytes
, bytearray
, memoryview
et str
sont acceptées. Si l'entrée existe en tant qu'objet memoryview
, bytearray
ou bytes
, il est recommandé de les transmettre directement plutôt que de créer un objet str
inutile. Autrement dit, orjson.loads(b"{}")
au lieu de orjson.loads(b"{}".decode("utf-8"))
. Cela entraîne une utilisation moindre de la mémoire et une latence plus faible.
L’entrée doit être UTF-8 valide.
orjson maintient un cache de clés de carte pendant toute la durée du processus. Cela entraîne une réduction nette de l'utilisation de la mémoire en évitant les chaînes en double. Les clés doivent faire au plus 64 octets pour être mises en cache et 2 048 entrées sont stockées.
Le verrouillage global de l'interprète (GIL) est maintenu pendant toute la durée de l'appel.
Il génère JSONDecodeError
si un type non valide ou un JSON non valide lui sont attribués. Cela inclut si l'entrée contient NaN
, Infinity
ou -Infinity
, ce que la bibliothèque standard autorise, mais n'est pas un JSON valide.
Il déclenche JSONDecodeError
si une combinaison de tableau ou d'objet récure jusqu'à 1024 niveaux de profondeur.
JSONDecodeError
est une sous-classe de json.JSONDecodeError
et ValueError
. Ceci est pour la compatibilité avec la bibliothèque standard.
orjson sérialise les instances de dataclasses.dataclass
de manière native. Il sérialise les instances 40 à 50 fois plus rapidement que les autres bibliothèques et évite un ralentissement important observé dans d'autres bibliothèques par rapport à la sérialisation dict
.
Il est pris en charge pour transmettre toutes les variantes de classes de données, y compris les classes de données utilisant __slots__
, les classes de données gelées, celles avec des attributs facultatifs ou par défaut et les sous-classes. Il y a un avantage en termes de performances à ne pas utiliser __slots__
.
Bibliothèque | dict (ms) | classe de données (ms) | contre orjson |
---|---|---|---|
orjson | 0,43 | 0,95 | 1 |
json | 5,81 | 38.32 | 40 |
Cela mesure la sérialisation de 555 Ko de JSON, orjson de manière native et d'autres bibliothèques en utilisant default
pour sérialiser la sortie de dataclasses.asdict()
. Cela peut être reproduit à l'aide du script pydataclass
.
Les classes de données sont sérialisées sous forme de cartes, avec chaque attribut sérialisé et dans l'ordre indiqué lors de la définition de la classe :
> >> import dataclasses , orjson , typing
@ dataclasses . dataclass
class Member :
id : int
active : bool = dataclasses . field ( default = False )
@ dataclasses . dataclass
class Object :
id : int
name : str
members : typing . List [ Member ]
> >> orjson . dumps ( Object ( 1 , "a" , [ Member ( 1 , True ), Member ( 2 )]))
b'{"id":1,"name":"a","members":[{"id":1,"active":true},{"id":2,"active":false}]}'
orjson sérialise les objets datetime.datetime
au format RFC 3339, par exemple "1970-01-01T00:00:00+00:00". Il s'agit d'un sous-ensemble de la norme ISO 8601 et est compatible avec isoformat()
dans la bibliothèque standard.
> >> import orjson , datetime , zoneinfo
> >> orjson . dumps (
datetime . datetime ( 2018 , 12 , 1 , 2 , 3 , 4 , 9 , tzinfo = zoneinfo . ZoneInfo ( "Australia/Adelaide" ))
)
b'"2018-12-01T02:03:04.000009+10:30"'
> >> orjson . dumps (
datetime . datetime ( 2100 , 9 , 1 , 21 , 55 , 2 ). replace ( tzinfo = zoneinfo . ZoneInfo ( "UTC" ))
)
b'"2100-09-01T21:55:02+00:00"'
> >> orjson . dumps (
datetime . datetime ( 2100 , 9 , 1 , 21 , 55 , 2 )
)
b'"2100-09-01T21:55:02"'
datetime.datetime
prend en charge les instances avec un tzinfo
qui est None
, datetime.timezone.utc
, une instance de fuseau horaire du module python3.9+ zoneinfo
ou une instance de fuseau horaire des bibliothèques tierces pendulum
, pytz
ou dateutil
/ arrow
.
Il est plus rapide d’utiliser zoneinfo.ZoneInfo
de la bibliothèque standard pour les fuseaux horaires.
Les objets datetime.time
ne doivent pas avoir de tzinfo
.
> >> import orjson , datetime
> >> orjson . dumps ( datetime . time ( 12 , 0 , 15 , 290 ))
b'"12:00:15.000290"'
Les objets datetime.date
seront toujours sérialisés.
> >> import orjson , datetime
> >> orjson . dumps ( datetime . date ( 1900 , 1 , 2 ))
b'"1900-01-02"'
Les erreurs avec tzinfo
entraînent l'apparition de JSONEncodeError
.
Pour désactiver la sérialisation des objets datetime
, spécifiez l'option orjson.OPT_PASSTHROUGH_DATETIME
.
Pour utiliser le suffixe "Z" au lieu de "+00:00" pour indiquer l'heure UTC ("Zulu"), utilisez l'option orjson.OPT_UTC_Z
.
Pour supposer que les dates et heures sans fuseau horaire sont UTC, utilisez l'option orjson.OPT_NAIVE_UTC
.
orjson sérialise les énumérations de manière native. Les options s'appliquent à leurs valeurs.
> >> import enum , datetime , orjson
> >>
class DatetimeEnum ( enum . Enum ):
EPOCH = datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 )
> >> orjson . dumps ( DatetimeEnum . EPOCH )
b'"1970-01-01T00:00:00"'
> >> orjson . dumps ( DatetimeEnum . EPOCH , option = orjson . OPT_NAIVE_UTC )
b'"1970-01-01T00:00:00+00:00"'
Les énumérations avec des membres qui ne sont pas des types pris en charge peuvent être sérialisées en utilisant default
:
> >> import enum , orjson
> >>
class Custom :
def __init__ ( self , val ):
self . val = val
def default ( obj ):
if isinstance ( obj , Custom ):
return obj . val
raise TypeError
class CustomEnum ( enum . Enum ):
ONE = Custom ( 1 )
> >> orjson . dumps ( CustomEnum . ONE , default = default )
b'1'
orjson sérialise et désérialise les flotteurs double précision sans perte de précision et avec un arrondi cohérent.
orjson.dumps()
sérialise Nan, Infinity et -Infinity, qui ne sont pas conformes à JSON, comme null
:
> >> import orjson , json
> >> orjson . dumps ([ float ( "NaN" ), float ( "Infinity" ), float ( "-Infinity" )])
b'[null,null,null]'
> >> json . dumps ([ float ( "NaN" ), float ( "Infinity" ), float ( "-Infinity" )])
'[NaN, Infinity, -Infinity]'
orjson sérialise et désérialise les entiers 64 bits par défaut. La plage prise en charge va du minimum d'un entier signé de 64 bits (-9223372036854775807) au maximum d'un entier non signé de 64 bits (18446744073709551615). Ceci est largement compatible, mais il existe des implémentations qui ne prennent en charge que 53 bits pour les entiers, par exemple les navigateurs Web. Pour ces implémentations, dumps()
peut être configuré pour déclencher une JSONEncodeError
sur les valeurs dépassant la plage de 53 bits.
> >> import orjson
> >> orjson . dumps ( 9007199254740992 )
b'9007199254740992'
> >> orjson . dumps ( 9007199254740992 , option = orjson . OPT_STRICT_INTEGER )
JSONEncodeError : Integer exceeds 53 - bit range
>> > orjson . dumps ( - 9007199254740992 , option = orjson . OPT_STRICT_INTEGER )
JSONEncodeError : Integer exceeds 53 - bit range
orjson sérialise nativement numpy.ndarray
et numpy.float64
, numpy.float32
, numpy.float16
( numpy.half
), numpy.int64
, numpy.int32
, numpy.int16
, numpy.int8
, numpy.uint64
, numpy.uint32
, numpy.uint16
, numpy.uint8
, instances numpy.uintp
, numpy.intp
, numpy.datetime64
et numpy.bool
.
orjson est compatible avec numpy v1 et v2.
orjson est plus rapide que toutes les bibliothèques comparées pour sérialiser les instances numpy. La sérialisation des données numpy nécessite de spécifier option=orjson.OPT_SERIALIZE_NUMPY
.
> >> import orjson , numpy
> >> orjson . dumps (
numpy . array ([[ 1 , 2 , 3 ], [ 4 , 5 , 6 ]]),
option = orjson . OPT_SERIALIZE_NUMPY ,
)
b'[[1,2,3],[4,5,6]]'
Le tableau doit être un tableau C contigu ( C_CONTIGUOUS
) et l'un des types de données pris en charge.
Notez une différence entre la sérialisation numpy.float32
à l'aide de ndarray.tolist()
ou orjson.dumps(..., option=orjson.OPT_SERIALIZE_NUMPY)
: tolist()
se convertit en double
avant la sérialisation et pas le chemin natif d'orjson. Cela peut entraîner des arrondis différents.
Les instances numpy.datetime64
sont sérialisées sous forme de chaînes RFC 3339 et les options datetime les affectent.
> >> import orjson , numpy
> >> orjson . dumps (
numpy . datetime64 ( "2021-01-01T00:00:00.172" ),
option = orjson . OPT_SERIALIZE_NUMPY ,
)
b'"2021-01-01T00:00:00.172000"'
> >> orjson . dumps (
numpy . datetime64 ( "2021-01-01T00:00:00.172" ),
option = (
orjson . OPT_SERIALIZE_NUMPY |
orjson . OPT_NAIVE_UTC |
orjson . OPT_OMIT_MICROSECONDS
),
)
b'"2021-01-01T00:00:00+00:00"'
Si un tableau n'est pas un tableau C contigu, contient un type de données non pris en charge ou contient un numpy.datetime64
utilisant une représentation non prise en charge (par exemple, des picosecondes), orjson passe à default
. Par default
, obj.tolist()
peut être spécifié.
Si un tableau n'est pas dans le format endian natif, par exemple un tableau de valeurs big-endian sur un système small-endian, orjson.JSONEncodeError
est déclenché.
Si un tableau est mal formé, orjson.JSONEncodeError
est déclenché.
Cela mesure la sérialisation de 92 Mo de JSON à partir d'un numpy.ndarray
avec des dimensions de (50000, 100)
et des valeurs numpy.float64
:
Bibliothèque | Latence (ms) | Différent RSS (Mio) | contre orjson |
---|---|---|---|
orjson | 105 | 105 | 1 |
json | 1 481 | 295 | 14.2 |
Cela mesure la sérialisation de 100 Mo de JSON à partir d'un numpy.ndarray
avec des dimensions de (100000, 100)
et des valeurs numpy.int32
:
Bibliothèque | Latence (ms) | Différent RSS (Mio) | contre orjson |
---|---|---|---|
orjson | 68 | 119 | 1 |
json | 684 | 501 | 10.1 |
Cela mesure la sérialisation de 105 Mo de JSON à partir d'un numpy.ndarray
avec des dimensions de (100000, 200)
et des valeurs numpy.bool
:
Bibliothèque | Latence (ms) | Différent RSS (Mio) | contre orjson |
---|---|---|---|
orjson | 50 | 125 | 1 |
json | 573 | 398 | 11.5 |
Dans ces tests, orjson sérialise nativement et json
sérialise ndarray.tolist()
via default
. La colonne RSS mesure l'utilisation maximale de la mémoire pendant la sérialisation. Ceci peut être reproduit à l'aide du script pynumpy
.
orjson n'a pas de dépendance d'installation ou de compilation sur numpy. L'implémentation est indépendante, lisant numpy.ndarray
en utilisant PyArrayInterface
.
orjson est strict quant à la conformité UTF-8. Ceci est plus strict que le module json de la bibliothèque standard, qui sérialisera et désérialisera les substituts UTF-16, par exemple "ud800", qui ne sont pas valides en UTF-8.
Si orjson.dumps()
reçoit une str
qui ne contient pas d'UTF-8 valide, orjson.JSONEncodeError
est déclenché. Si loads()
reçoit un UTF-8 non valide, orjson.JSONDecodeError
est déclenché.
> >> import orjson , json
> >> orjson . dumps ( ' ud800 ' )
JSONEncodeError : str is not valid UTF - 8 : surrogates not allowed
>> > json . dumps ( ' ud800 ' )
'" \ ud800"'
> >> orjson . loads ( '" \ ud800"' )
JSONDecodeError : unexpected end of hex escape at line 1 column 8 : line 1 column 1 ( char 0 )
> >> json . loads ( '" \ ud800"' )
' ud800 '
Pour faire de votre mieux pour désérialiser les mauvaises entrées, décodez d'abord bytes
en utilisant l'argument replace
ou lossy
pour errors
:
> >> import orjson
> >> orjson . loads ( b'" xed xa0 x80 "' )
JSONDecodeError : str is not valid UTF - 8 : surrogates not allowed
>> > orjson . loads ( b'" xed xa0 x80 "' . decode ( "utf-8" , "replace" ))
'���'
orjson sérialise les instances uuid.UUID
au format RFC 4122, par exemple "f81d4fae-7dec-11d0-a765-00a0c91e6bf6".
> >> import orjson , uuid
> >> orjson . dumps ( uuid . uuid5 ( uuid . NAMESPACE_DNS , "python.org" ))
b'"886313e1-3b8a-5372-9b90-0c9aee199e5d"'
La bibliothèque propose des tests complets. Il existe des tests sur les appareils dans les référentiels JSONTestSuite et nativejson-benchmark. Il est testé pour ne pas s'écraser contre la Big List of Naughty Strings. Il est testé pour ne pas perdre de mémoire. Il est testé pour ne pas planter et ne pas accepter l'UTF-8 invalide. Il existe des tests d'intégration exerçant l'utilisation de la bibliothèque dans les serveurs Web (gunicorn utilisant des travailleurs multiprocessus/forked) et en mode multithread. Il utilise également certains tests de la bibliothèque ultrajson.
orjson est la plus correcte des bibliothèques comparées. Ce graphique montre comment chaque bibliothèque gère un total de 342 appareils JSON issus des tests JSONTestSuite et nativejson-benchmark :
Bibliothèque | Documents JSON invalides non rejetés | Documents JSON valides non désérialisés |
---|---|---|
orjson | 0 | 0 |
json | 17 | 0 |
Cela montre que toutes les bibliothèques désérialisent le JSON valide, mais que seul orjson rejette correctement les appareils JSON non valides donnés. Les erreurs sont en grande partie dues à l’acceptation de chaînes et de nombres non valides.
Le graphique ci-dessus peut être reproduit à l'aide du script pycorrectness
.
Les performances de sérialisation et de désérialisation d'orjson sont systématiquement meilleures que json
de la bibliothèque standard. Les graphiques ci-dessous illustrent quelques documents couramment utilisés.
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 0,1 | 8453 | 1 |
json | 1.3 | 765 | 11.1 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 0,5 | 1889 | 1 |
json | 2.2 | 453 | 4.2 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 0,01 | 103693 | 1 |
json | 0,13 | 7648 | 13.6 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 0,04 | 23264 | 1 |
json | 0,1 | 10430 | 2.2 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 0,3 | 3975 | 1 |
json | 3 | 338 | 11.8 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 1.3 | 781 | 1 |
json | 4 | 250 | 3.1 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 2.5 | 399 | 1 |
json | 29,8 | 33 | 11.9 |
Bibliothèque | Latence médiane (millisecondes) | Opérations par seconde | Relatif (latence) |
---|---|---|---|
orjson | 3 | 333 | 1 |
json | 18 | 55 | 6 |
Ce qui précède a été mesuré à l'aide de Python 3.11.10 dans un conteneur Fedora 42 sur une machine x86-64-v4 à l'aide de l' orjson-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
sur PyPI. Les résultats de latence peuvent être reproduits à l'aide du script pybench
.
pip
doit probablement être mis à niveau vers la version 20.3 ou ultérieure pour prendre en charge les derniers formats de roue manylinux_x_y ou universal2.
Cela se produit lorsqu'il n'y a pas de roues binaires (comme manylinux) pour votre plateforme sur PyPI. Vous pouvez installer Rust via rustup
ou un gestionnaire de paquets, puis il sera compilé.
Non. Cela nécessite un schéma spécifiant quels types sont attendus et comment gérer les erreurs, etc. Ce problème est résolu par les bibliothèques de validation de données d'un niveau supérieur.
str
? Le nombre bytes
est le type correct pour un blob sérialisé.
Non, orjsonl peut être approprié.
Non, il prend en charge la RFC 8259.
Pour empaqueter orjson, il faut au moins Rust 1.72 et l'outil de construction maturin. La commande de build recommandée est :
maturin build --release --strip
Il bénéficie également d'un environnement de construction C pour compiler un backend de désérialisation plus rapide. Voir les versions manylinux_2_28
de ce projet pour un exemple utilisant clang et LTO.
Les propres tests CI du projet contre nightly-2024-11-22
et stable 1.72. Il est prudent d’épingler la version nocturne car cette chaîne peut introduire des modifications importantes. L'utilisation nocturne présente un avantage significatif en termes de performances.
orjson est testé pour amd64, aarch64 et i686 sous Linux et est compilé de manière croisée pour arm7, ppc64le et s390x. Il est testé pour aarch64 ou amd64 sur macOS et est compilé de manière croisée pour l'autre, selon la version. Pour Windows, il est testé sur amd64 et i686.
Il n'y a aucune dépendance d'exécution autre que la libc.
La distribution source sur PyPI contient la source de toutes les dépendances et peut être construite sans accès au réseau. Le fichier peut être téléchargé depuis https://files.pythonhosted.org/packages/source/o/orjson/orjson-${version}.tar.gz
.
Les tests d'orjson sont inclus dans la distribution source sur PyPI. Les exigences pour exécuter les tests sont spécifiées dans test/requirements.txt
. Les tests doivent être exécutés dans le cadre de la construction. Il peut être exécuté avec pytest -q test
.
orjson a été écrit par ijl