def write(obj, file, encoding=DEFAULT_ENCODING, indent=True): """Write a phyloXML file. :Parameters: obj an instance of `Phyloxml`, `Phylogeny` or `BaseTree.Tree`, or an iterable of either of the latter two. The object will be converted to a Phyloxml object before serialization. file either an open handle or a file name. """ def fix_single(tree): if isinstance(tree, PX.Phylogeny): return tree if isinstance(tree, PX.Clade): return tree.to_phylogeny() if isinstance(tree, PX.BaseTree.Tree): return PX.Phylogeny.from_tree(tree) if isinstance(tree, PX.BaseTree.Clade): return PX.Phylogeny.from_tree(PX.BaseTree.Tree(root=tree)) else: raise ValueError("iterable must contain Tree or Clade types") if isinstance(obj, PX.Phyloxml): pass elif isinstance(obj, (PX.BaseTree.Tree, PX.BaseTree.Clade)): obj = fix_single(obj).to_phyloxml() elif hasattr(obj, '__iter__'): obj = PX.Phyloxml({}, phylogenies=(fix_single(t) for t in obj)) else: raise ValueError("First argument must be a Phyloxml, Phylogeny, " "Tree, or iterable of Trees or Phylogenies.") return Writer(obj).write(file, encoding=encoding, indent=indent)
def read(self): """Parse the phyloXML file and create a single Phyloxml object.""" phyloxml = PX.Phyloxml({_local(key): val for key, val in self.root.items()}) other_depth = 0 for event, elem in self.context: namespace, localtag = _split_namespace(elem.tag) if event == "start": if namespace != NAMESPACES["phy"]: other_depth += 1 continue if localtag == "phylogeny": phylogeny = self._parse_phylogeny(elem) phyloxml.phylogenies.append(phylogeny) if event == "end" and namespace != NAMESPACES["phy"]: # Deal with items not specified by phyloXML other_depth -= 1 if other_depth == 0: # We're directly under the root node -- evaluate otr = self.other(elem, namespace, localtag) phyloxml.other.append(otr) self.root.clear() return phyloxml