format_utils#

Shared format structure (NEXUS, PHYLIP, DOT). Class-specific (de)serialization lives in core/*/io.

Nexus#

Shared NEXUS format structure.

Provides parse_nexus (labels + all blocks), write helpers (header, TAXA block, block). Class-specific parsing of block content stays in core/distance/io, core/sequence/io, core/split/io.

phylozoo.utils.io.format_utils.nexus.nexus_header() str[source]#

Return the NEXUS file header (#NEXUS and blank line).

Returns:

The NEXUS file header.

Return type:

str

phylozoo.utils.io.format_utils.nexus.parse_nexus(nexus_string: str) tuple[list[str], dict[str, str]][source]#

Parse a NEXUS string into labels (from TAXA block) and data blocks.

Parameters:

nexus_string (str) – Full NEXUS file content.

Returns:

(labels, blocks). labels from TAXA block; blocks maps canonical block name (DISTANCES, CHARACTERS, SPLITS) to full block content (including trailing “;”).

Return type:

tuple[list[str], dict[str, str]]

Raises:

PhyloZooParseError – If no TAXA block with TAXLABELS is found.

Notes

A file may contain multiple data blocks (e.g. DISTANCES and SPLITS). Callers use only the block they need (e.g. DistanceMatrix uses “DISTANCES”).

phylozoo.utils.io.format_utils.nexus.write_block(block_name: str, body: str) str[source]#

Build a NEXUS data block (BEGIN name; body END;).

Parameters:
  • block_name (str) – Block name (e.g. DISTANCES, CHARACTERS, SPLITS).

  • body (str) – Block body (commands and MATRIX etc.); need not include trailing “;”.

Returns:

Full block including BEGIN/END.

Return type:

str

phylozoo.utils.io.format_utils.nexus.write_taxa_block(labels: list[str]) str[source]#

Build the TAXA block string (BEGIN TAXA; DIMENSIONS ntax=N; TAXLABELS … ; END;).

Parameters:

labels (list[str]) – Taxon labels.

Returns:

Full TAXA block including BEGIN/END.

Return type:

str

Phylip#

Shared PHYLIP matrix format structure.

Generic layout: first line = n, then n lines of (label, rest). Class-specific parsing (e.g. float matrix, symmetry) stays in core/distance/io.

phylozoo.utils.io.format_utils.phylip.parse_phylip_matrix(phylip_string: str) tuple[int, list[tuple[str, str]]][source]#

Parse PHYLIP matrix layout into n and rows (label, rest of line).

Parameters:

phylip_string (str) – Full PHYLIP file content.

Returns:

(n, rows). n = number of taxa; rows = list of (label, rest) per line. Label is first 10 chars or until whitespace; rest is the remainder.

Return type:

tuple[int, list[tuple[str, str]]]

Raises:

PhyloZooParseError – If string is empty or first line is not an integer.

phylozoo.utils.io.format_utils.phylip.write_phylip_matrix(n: int, rows: list[tuple[str, str]]) str[source]#

Build PHYLIP matrix string (first line n, then n lines of label + rest).

Parameters:
  • n (int) – Number of taxa.

  • rows (list[tuple[str, str]]) – Each element is (label, rest) for one row. Label is padded to 10 chars.

Returns:

Full PHYLIP matrix content (no trailing newline required by callers).

Return type:

str

Dot#

Shared DOT-format scaffolding for the graph primitives.

Three closely related serialisations are built on the same DOT syntax and share the helpers below (mirroring how nexus and phylip are shared between classes):

  • dot for DirectedMultiGraph — a standard Graphviz digraph with -> edges;

  • dot for MixedMultiGraph — a standard Graphviz digraph whose undirected edges carry dir=none (Graphviz’s own marker for an edge drawn without arrowheads), so the file is valid DOT and opens in any Graphviz tool;

  • phylozoo-dot for MixedMultiGraph — the legacy PhyloZoo dialect using a graph block with both -> (directed) and -- (undirected) edges.

Parallel (multi-)edges are encoded with an explicit key=<int> attribute.

parse_dot_document() parses all three: it accepts either header, treats an edge as undirected when it is written with -- or carries dir=none, and returns the structural dir/key markers consumed (not as leftover attributes). The class-specific readers in core/primitives/*/io.py then build the appropriate graph from its output.

phylozoo.utils.io.format_utils.dot.convert_node_id(node_str: str) Any[source]#

Coerce a node-id string to int, then float, else keep it a string.

phylozoo.utils.io.format_utils.dot.dot_edge_line(u: Any, v: Any, attrs: dict[str, Any], *, arrow: str = '->', indent: str = '    ') str[source]#

Render one u <arrow> v [attrs]; edge declaration (arrow is -> or --).

phylozoo.utils.io.format_utils.dot.dot_node_line(node: Any, attrs: dict[str, Any], *, indent: str = '    ') str[source]#

Render one node [attrs]; declaration (bare node; if no attributes).

phylozoo.utils.io.format_utils.dot.escape_dot_string(s: str) str[source]#

Escape a string for DOT, quoting it when it contains special characters.

phylozoo.utils.io.format_utils.dot.format_dot_attributes(attrs: dict[str, Any]) str[source]#

Format an attribute mapping as [key1=value1, key2=value2] ("" if empty).

phylozoo.utils.io.format_utils.dot.parse_dot_attributes(attrs_str: str) dict[str, Any][source]#

Parse a DOT attribute string like key1=value1, key2=value2 into a dict.

Values are coerced to bool/int/float where possible, except a label, which is always kept as a string — a label is a display string, and coercing e.g. label=1 to an int would leave nodes with non-string labels that downstream label validation rejects.

phylozoo.utils.io.format_utils.dot.parse_dot_document(dot_string: str) tuple[dict[str, Any], dict[Any, dict[str, Any]], list[tuple[Any, Any, int | None, dict[str, Any], bool]]][source]#

Parse a DOT / phylozoo-dot document into its components.

Parameters:

dot_string (str) – A graph or digraph document.

Returns:

  • graph_attrs (dict) – Graph-level attributes.

  • nodes_data (dict) – Maps each declared node id to its attribute dict.

  • edges_data (list) – One (u, v, key, attrs, directed) tuple per edge. directed is False when the edge used -- or carried dir=none; the dir and key markers are consumed and never appear in attrs.

Raises:

PhyloZooParseError – If no graph declaration is found or the braces are unbalanced.