X-Git-Url: https://git.yukkurigames.com/?p=python-bulletml.git;a=blobdiff_plain;f=bulletml%2Fparser.py;h=10b789ae83a801bc0dc538afc183f8194240f00c;hp=a89d1c5b8ce207c7f8a5a37db780f0d38ba43d7f;hb=70d25195d561d8b5d3126c6bbac0ecad2a502f06;hpb=4f0e7df685d8d25cd0f1bbce7d6330f87c8cf178 diff --git a/bulletml/parser.py b/bulletml/parser.py index a89d1c5..10b789a 100644 --- a/bulletml/parser.py +++ b/bulletml/parser.py @@ -24,6 +24,7 @@ except ImportError: from bulletml.errors import Error from bulletml.expr import NumberDef, INumberDef + __all_ = ["ParseError", "BulletML"] class ParseError(Error): @@ -49,15 +50,6 @@ class ParamList(object): return cls([NumberDef(subelem.text) for subelem in element if realtag(subelem) == "param"]) - def __getstate__(self): - if self.params: - return dict(params=[param.expr for param in self.params]) - else: - return {} - - def __setstate__(self, state): - self.__init__(NumberDef(param) for param in state.get("params", [])) - def __call__(self, params, rank): return [param(params, rank) for param in self.params] @@ -321,7 +313,7 @@ class Accel(object): return state def __setstate__(self, state): - self.__init__(INumberDef(state["term"]), state.get("horizontal"), + self.__init__(INumberDef(state["frames"]), state.get("horizontal"), state.get("vertical")) @classmethod @@ -419,13 +411,13 @@ class BulletRef(object): def __getstate__(self): state = dict(bullet=self.bullet) if self.params.params: - state["params"] = self.params.__getstate__() + state["params"] = [param.expr for param in self.params.params] return state def __setstate__(self, state): bullet = state["bullet"] params = [NumberDef(param) for param in state.get("params", [])] - self.__init__(bullet, params) + self.__init__(bullet, ParamList(params)) @classmethod def FromElement(cls, doc, element): @@ -460,7 +452,7 @@ class ActionDef(object): return dict(actions=self.actions) def __setstate__(self, state): - self.__init__(state) + self.__init__(state["actions"]) @classmethod def FromElement(cls, doc, element): @@ -494,13 +486,13 @@ class ActionRef(object): def __getstate__(self): state = dict(action=self.action) if self.params.params: - state["params"] = self.params.__getstate__() + state["params"] = [param.expr for param in self.params.params] return state def __setstate__(self, state): action = state["action"] params = [NumberDef(param) for param in state.get("params", [])] - self.__init__(action, params) + self.__init__(action, ParamList(params)) @classmethod def FromElement(cls, doc, element): @@ -584,6 +576,9 @@ class FireDef(object): state["offset"] = self.offset return state + def __setstate__(self, state): + self.__init__(**state) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -633,13 +628,13 @@ class FireRef(object): def __getstate__(self): state = dict(fire=self.fire) if self.params.params: - state["params"] = self.params.__getstate__() + state["params"] = [param.expr for param in self.params.params] return state def __setstate__(self, state): fire = state["fire"] params = [NumberDef(param) for param in state.get("params", [])] - self.__init__(fire, params) + self.__init__(fire, ParamList(params)) @classmethod def FromElement(cls, doc, element): @@ -684,11 +679,11 @@ class BulletML(object): return dict(type=self.type, actions=self.actions) def __setstate__(self, state): - self.__init__(state["type"], state.get("actions")) + self.__init__(state["type"], actions=state.get("actions")) @classmethod - def FromDocument(cls, source): - """Return a BulletML instance based on a string or file-like.""" + def FromXML(cls, source): + """Return a BulletML instance based on XML.""" if not hasattr(source, 'read'): source = StringIO(source) @@ -726,6 +721,39 @@ class BulletML(object): return self + @classmethod + def FromYAML(cls, source): + """Create a BulletML instance based on YAML.""" + + # Late import to avoid a circular dependency. + try: + import bulletml.bulletyaml + import yaml + except ImportError: + raise ParseError("PyYAML is not available") + else: + try: + return yaml.load(source) + except Exception, exc: + raise ParseError(str(exc)) + + @classmethod + def FromDocument(cls, source): + """Create a BulletML instance based on a seekable file or string. + + This attempts to autodetect if the stream is XML or YAML. + """ + if not hasattr(source, 'read'): + source = StringIO(source) + start = source.read(1) + source.seek(0) + if start == "<": + return cls.FromXML(source) + elif start == "!": + return cls.FromYAML(source) + else: + raise ParseError("unknown initial character %r" % start) + @property def top(self): """Get a list of all top-level actions."""