2012-02-06 19 views
7

El título es bastante autoexplicativo.¿Cómo puedo agregar una tupla de python a un archivo YAML usando pyYAML?

Cuando guardo una tupla en un archivo YAML, me sale algo que se parece a esto:

ambient: !!python/tuple [0.3, 0.3 ,0.3] 

Cuando intento cargar con yaml.safe_load (FILE_OBJECT), Me aparece un error que dice :

yaml.constructor.ConstructorError: could not determine a constructor for the tag 'tag:yaml.org,2002:python/tuple' 

¿Qué hay que hacer?

Respuesta

9

En pyyaml, SafeLoader no incluye un cargador para los tipos nativos de python, solo los tipos definidos en la especificación yaml. Puede ver los tipos para SafeLoader y Loader aquí en el ejemplo de interacción a continuación.

se puede definir una nueva clase Loader que se suma en la tupla Python, pero no otros tipos, por lo que aún debe ser bastante segura:

import yaml 

class PrettySafeLoader(yaml.SafeLoader): 
    def construct_python_tuple(self, node): 
     return tuple(self.construct_sequence(node)) 

PrettySafeLoader.add_constructor(
    u'tag:yaml.org,2002:python/tuple', 
    PrettySafeLoader.construct_python_tuple) 

doc = yaml.dump(tuple("foo bar baaz".split())) 
print repr(doc) 
thing = yaml.load(doc, Loader=PrettySafeLoader) 
print thing 

lo que resulta en:

'!!python/tuple [foo, bar, baaz]\n' 
('foo', 'bar', 'baaz') 

continuación, se muestran para los constructores asociados con las clases SafeLoader y Loader.

>>> yaml.SafeLoader.yaml_constructors 
{None: <unbound method SafeConstructor.construct_undefined>, 
u'tag:yaml.org,2002:binary': <unbound method SafeConstructor.construct_yaml_binary>, 
u'tag:yaml.org,2002:bool': <unbound method SafeConstructor.construct_yaml_bool>, 
u'tag:yaml.org,2002:float': <unbound method SafeConstructor.construct_yaml_float>, 
u'tag:yaml.org,2002:int': <unbound method SafeConstructor.construct_yaml_int>, 
u'tag:yaml.org,2002:map': <unbound method SafeConstructor.construct_yaml_map>, 
u'tag:yaml.org,2002:null': <unbound method SafeConstructor.construct_yaml_null>, 
u'tag:yaml.org,2002:omap': <unbound method SafeConstructor.construct_yaml_omap>, 
u'tag:yaml.org,2002:pairs': <unbound method SafeConstructor.construct_yaml_pairs>, 
u'tag:yaml.org,2002:seq': <unbound method SafeConstructor.construct_yaml_seq>, 
u'tag:yaml.org,2002:set': <unbound method SafeConstructor.construct_yaml_set>, 
u'tag:yaml.org,2002:str': <unbound method SafeConstructor.construct_yaml_str>, 
u'tag:yaml.org,2002:timestamp': <unbound method SafeConstructor.construct_yaml_timestamp>} 

>>> yaml.Loader.yaml_constructors 
{None: <unbound method SafeConstructor.construct_undefined>, 
u'tag:yaml.org,2002:binary': <unbound method SafeConstructor.construct_yaml_binary>, 
u'tag:yaml.org,2002:bool': <unbound method SafeConstructor.construct_yaml_bool>, 
u'tag:yaml.org,2002:float': <unbound method SafeConstructor.construct_yaml_float>, 
u'tag:yaml.org,2002:int': <unbound method SafeConstructor.construct_yaml_int>, 
u'tag:yaml.org,2002:map': <unbound method SafeConstructor.construct_yaml_map>, 
u'tag:yaml.org,2002:null': <unbound method SafeConstructor.construct_yaml_null>, 
u'tag:yaml.org,2002:omap': <unbound method SafeConstructor.construct_yaml_omap>, 
u'tag:yaml.org,2002:pairs': <unbound method SafeConstructor.construct_yaml_pairs>, 
u'tag:yaml.org,2002:python/bool': <unbound method Constructor.construct_yaml_bool>, 
u'tag:yaml.org,2002:python/complex': <unbound method Constructor.construct_python_complex>, 
u'tag:yaml.org,2002:python/dict': <unbound method Constructor.construct_yaml_map>, 
u'tag:yaml.org,2002:python/float': <unbound method Constructor.construct_yaml_float>, 
u'tag:yaml.org,2002:python/int': <unbound method Constructor.construct_yaml_int>, 
u'tag:yaml.org,2002:python/list': <unbound method Constructor.construct_yaml_seq>, 
u'tag:yaml.org,2002:python/long': <unbound method Constructor.construct_python_long>, 
u'tag:yaml.org,2002:python/none': <unbound method Constructor.construct_yaml_null>, 
u'tag:yaml.org,2002:python/str': <unbound method Constructor.construct_python_str>, 
u'tag:yaml.org,2002:python/tuple': <unbound method Constructor.construct_python_tuple>, 
u'tag:yaml.org,2002:python/unicode': <unbound method Constructor.construct_python_unicode>, 
u'tag:yaml.org,2002:seq': <unbound method SafeConstructor.construct_yaml_seq>, 
u'tag:yaml.org,2002:set': <unbound method SafeConstructor.construct_yaml_set>, 
u'tag:yaml.org,2002:str': <unbound method SafeConstructor.construct_yaml_str>, 
u'tag:yaml.org,2002:timestamp': <unbound method SafeConstructor.construct_yaml_timestamp>} 
+0

Eso tiene perfecto sentido. ¡Muchas gracias! – blz

0

Al menos según the PyYAML documentation:

La función limita yaml.safe_load Esta capacidad de objetos de Python simples, como enteros o listas.

La lista, as you can see in the source, es algo más extensa pero no incluye tag:yaml.org,2002:python/tuple.

Parece que si está generando un tipo !!python/tuple en su archivo YAML, está usando dump() en comparación con safe_dump(). Si ese es el caso, probablemente debería cambiar a usar load() en lugar de safe_load(), ya que no se garantiza que los archivos creados por dump() puedan cargarse por safe_load(). (Ver el description of safe_dump()).

+1

añadí la palabra faltante * * No, pero no estoy seguro de si en realidad no quiere formularlo al revés ... –

+0

@NiklasB .: Gracias. – ig0774

+0

¿Bajo qué condiciones una persona razonable consideraría peligroso el uso de yaml.loader (en lugar de safe_loader)? Estoy escribiendo un juego que carga activos definidos en un archivo YAML. Una descarga maliciosa podría supuestamente sobrescribir mis archivos YAML, lo que hace que mi carga de juego sea un código peligroso, pero parece ser un problema para el usuario final. No hay mucho que pueda hacer ... ¿verdad? – blz

Cuestiones relacionadas