Je rencontre des problèmes avec les classes de sérialisation YAML qui ont des références de type en tant que membres. J'utilise le chargeur sécurisé de ruamel.yaml.YAML - Attributs de sérialisation qui sont des types
J'ai exécuté tout ce qui suit à partir d'une invite REPL (pour obtenir plusieurs erreurs).
Initialisation:
import sys
from ruamel.yaml import YAML, yaml_object
Y = YAML(typ="safe",pure=True)
# ==============
@yaml_object(Y)
class A(object):
"""Object I want to serialize"""
yaml_tag = "!Aclass"
def __init__(self, type):
self.type = type
def f(self):
return self.type()
pass
class T1(object):
"""This will be referenced."""
pass
@yaml_object(Y)
class T2(object):
"""Another referenced object"""
pass
class T3(object):
"""Yet another try"""
pass
Y.register_class(T3.__class__)
code
qui provoque un échec:
Y.dump(A(T1), sys.stdout)
Y.dump(A(T2), sys.stdout)
Y.dump(A(T3), sys.stdout)
Y.dump(A(int), sys.stdout)
Ce sorties (seulement dernières lignes de retraçage):
ruamel.yaml.representer.RepresenterError: cannot represent an object: <attribute '__dict__' of 'T1' objects>
ruamel.yaml.representer.RepresenterError: cannot represent an object: <attribute '__dict__' of 'T2' objects>
ruamel.yaml.representer.RepresenterError: cannot represent an object: <attribute '__dict__' of 'T3' objects>
ruamel.yaml.representer.RepresenterError: cannot represent an object: <slot wrapper '__abs__' of 'int' objects>
Toute solution qui me permet de (en toute sécurité) sauvegarder uniquement le type (j'ai besoin de générer des objets du type ET vérifier si un objet entrant est d'un certain type) serait apprécié. Une fonction ou une classe qui génère mon type requis aurait le même problème de ne pas être sérialisable non plus.
P.S. J'ai aussi peut-être trouvé un bogue, où l'analyseur aura, pour une raison quelconque, un comportement différent selon que le même argument efficace a été (tenté) d'être sérialisé.
Y.dump(A(str), sys.stdout)
Y.dump(A(str), sys.stdout)
Y.dump(A(str), sys.stdout)
Y.dump(A(str), sys.stdout)
Sorties:
>>> Y.dump(A(str), sys.stdout)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\main.py", line 352, in dump
return self.dump_all([data], stream, _kw, transform=transform)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\main.py", line 383, in dump_all
self.representer.represent(data)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 73, in represent
node = self.represent_data(data)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 101, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\main.py", line 552, in t_y
tag, data, cls, flow_style=representer.default_flow_style)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 371, in represent_yaml_object
return self.represent_mapping(tag, state, flow_style=flow_style)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 206, in represent_mapping
node_value = self.represent_data(item_value)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 101, in represent_data
node = self.yaml_representers[data_types[0]](self, data)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\main.py", line 492, in t_y
tag, data, cls, flow_style=representer.default_flow_style)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 371, in represent_yaml_object
return self.represent_mapping(tag, state, flow_style=flow_style)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 206, in represent_mapping
node_value = self.represent_data(item_value)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 111, in represent_data
node = self.yaml_representers[None](self, data)
File "C:\Program Files\Anaconda3\lib\site-packages\ruamel\yaml\representer.py", line 375, in represent_undefined
raise RepresenterError("cannot represent an object: %s" % data)
ruamel.yaml.representer.RepresenterError: cannot represent an object: <slot wrapper '__add__' of 'str' objects>
>>> Y.dump(A(str), sys.stdout)
!Aclass
type: !type {}
>>> Y.dump(A(str), sys.stdout)
Traceback (most recent call last):
# same traceback here
ruamel.yaml.representer.RepresenterError: cannot represent an object: <slot wrapper '__add__' of 'str' objects>
>>> Y.dump(A(str), sys.stdout)
!Aclass
type: !type {}
>>>
Très bien, cela semble fonctionner, si je veux garder, par exemple, T2 dans mon. Cependant, puisque je construis des objets de la classe donnée, et que Y ne peut pas dire (du moins pas à partir de votre implémentation A) s'il est sûr de charger l'objet, je peux charger un type malveillant dans mon code. Dans ce cas, T1 était "chargé" même si la classe n'était pas enregistrée. Une solution possible serait de vérifier dans A.from_yaml() si la classe trouvée a été enregistrée par Y (c'est-à-dire dans constructor.yaml_constructors?), Je suppose. En ce qui concerne la deuxième partie, cela a du sens. –
Vous avez raison à propos de la sécurité, j'ai réfléchi à cela en travaillant sur la réponse, mais j'ai oublié de l'inclure. Je voudrais mettre tous les types pertinents dans un module (ou plusieurs modules dans un sous-répertoire) et les importer à partir de là. Ensuite, vous pouvez vérifier la chaîne dans 'node.value' dans' A' 'from_yaml()'. Vous pouvez également créer votre propre @ @ yaml_type qui définit un attribut (unique) sur lequel vous testez (au moment du vidage et/ou du chargement). Il n'est pas nécessaire de réutiliser l'enregistrement des objets par ruamel.yaml (ce qui est essentiellement autre chose). – Anthon
J'ai fait une petite maquette dans ma réponse, n'hésitez pas à la modifier (ou votre propre réponse) pour la mettre en sécurité. EDIT: J'ai manqué ton commentaire en postant, pas très sûr de ce que tu veux dire par là? Voulez-vous dire utiliser un décorateur @yaml_type pour définir un attribut caché dans un objet? Qu'est-ce qui empêche quelqu'un de faire la même chose à sa propre classe et d'imiter le nôtre? –