Ich habe Probleme YAML-Serialisierung Klassen, die Typ Referenzen als Mitglieder haben. Ich benutze den Safe Loader von ramel.yaml.YAML - Serialisierung Attribute, die Typen sind
Ich führte alle folgenden von einer REPL-Eingabeaufforderung (um mehrere Fehler zu erhalten).
Initialisierung:
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, der einen Fehler verursacht:
Y.dump(A(T1), sys.stdout)
Y.dump(A(T2), sys.stdout)
Y.dump(A(T3), sys.stdout)
Y.dump(A(int), sys.stdout)
Diese Ausgänge (nur die letzte Zeile von Tracebacks):
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>
Jede Lösung, die mich lässt (sicher) einmalig den Typ speichern (ich muss Objekte vom Typ generieren und prüfen, ob ein ankommendes Objekt ist von einem bestimmten Typ) würde geschätzt werden. Eine Funktion oder Klasse, die meinen erforderlichen Typ generiert, hätte das gleiche Problem, dass sie auch nicht serialisierbar sind.
P.S. Ich habe möglicherweise auch einen Fehler gefunden, bei dem der Parser aus irgendeinem Grund ein unterschiedliches Verhalten hat, abhängig davon, ob das gleiche effektive Argument versucht wurde, serialisiert zu werden.
Y.dump(A(str), sys.stdout)
Y.dump(A(str), sys.stdout)
Y.dump(A(str), sys.stdout)
Y.dump(A(str), sys.stdout)
Ausgänge:
>>> 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 {}
>>>
In Ordnung, das scheint gut zu funktionieren, wenn ich z.B. T2 in meinem. Da ich jedoch Objekte der angegebenen Klasse konstruiere und Y nicht sagen kann (zumindest nicht von Ihrer A-Implementierung), ob das Objekt sicher geladen werden kann, lade ich möglicherweise einen bösartigen Typ in meinen Code ein. In diesem Fall wurde T1 "geladen", obwohl die Klasse nicht registriert war. Eine mögliche Lösung wäre das Einchecken von A.from_yaml(), ob die gefundene Klasse von Y registriert wurde (d. H. Ist es in constructor.yaml_constructors?), Denke ich. Bezüglich des zweiten Teils macht das Sinn. –
Sie haben Recht mit der Sicherheit, ich habe darüber nachgedacht, während ich an der Antwort gearbeitet habe, habe aber vergessen, das mit aufzunehmen. Ich würde alle relevanten Typen in ein Modul (oder mehrere Module in einem Unterverzeichnis) einfügen und sie von dort importieren. Dann können Sie den String im 'node.value' in' A''s 'from_yaml()' überprüfen. Sie können auch einen eigenen '@ yaml_type' erstellen, der ein (eindeutiges) Attribut festlegt, auf dem Sie testen (zum Zeitpunkt des Ladens und/oder Ladens). Es besteht keine Notwendigkeit, die Registrierung von ramel.yaml für Objekte zu speichern (was im Wesentlichen etwas anderes ist). – Anthon
Ich habe ein kleines Mock-Up in meiner Antwort gemacht, ich kann es gerne ändern (oder deine eigene Antwort), um es sicher zu machen. EDIT: Ich verpasste Ihren Kommentar beim Posten, nicht ganz sicher, was Sie damit meinen? Meinst du einen @yaml_type Dekorator verwenden, um ein verstecktes Attribut in einem Objekt zu setzen? Was hindert jemanden daran, das gleiche für seine Klasse zu tun und uns zu verkörpern? –