From c299c8ec30769702cdff74354e9c84a368f341b0 Mon Sep 17 00:00:00 2001
From: Robert Forkel <xrotwang@googlemail.com>
Date: Tue, 14 Mar 2023 10:00:12 +0100
Subject: [PATCH] support round-tripping Newick data with two comments per node

---
 CHANGELOG.md         |   3 ++
 src/newick.py        |  11 ++--
 tests/test_newick.py | 117 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6e5dcc..98143f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@ The `newick` package adheres to [Semantic Versioning](http://semver.org/spec/v2.
 
 ## [Unreleased]
 
+Support round-tripping Newick with two annotations per node, one before and one after the
+length separator.
+
 
 ## [v1.8.1] - 2023-03-05
 
diff --git a/src/newick.py b/src/newick.py
index fc1f63b..cfe4f1c 100644
--- a/src/newick.py
+++ b/src/newick.py
@@ -203,10 +203,15 @@ class Node(object):
         colon_done = False
         label = self.name or ''
         if self.comments:
-            if self._length and self._colon_before_comment:
-                label += ':'
+            if self._length and len(self.comments) == 2 and not self._colon_before_comment:
+                # We assume that's the variant where one comment comes before and one after the ":".
+                label += '[{}]:[{}]'.format(*self.comments)
                 colon_done = True
-            label += '[{}]'.format('|'.join(self.comments))
+            else:
+                if self._length and self._colon_before_comment:
+                    label += ':'
+                    colon_done = True
+                label += '[{}]'.format('|'.join(self.comments))
         if self._length:
             if not colon_done:
                 label += ':'
diff --git a/tests/test_newick.py b/tests/test_newick.py
index d66a807..52bd63a 100644
--- a/tests/test_newick.py
+++ b/tests/test_newick.py
@@ -561,6 +561,123 @@ def test_with_comments_beast():
     assert tree.newick == nwk
 
 
+def test_roundtrip_two_comments():
+    nwk = "((1[&height=9.687616008832612E-12,height_95%_HPD={0.0,2.9103830456733704E-11}," \
+          "height_median=0.0,height_range={0.0,3.725290298461914E-9},length=107922.03600478375," \
+          "length_95%_HPD={474.13147831140884,255028.5553480226},length_median=16766.239568341443," \
+          "length_range={474.13147831140884,3.1088350108564742E7}]:[&rate=0.10061354528306601]" \
+          "14581.043598225671,(7[&height=9.309604621069004E-12,height_95%_HPD=" \
+          "{0.0,2.9103830456733704E-11},height_median=0.0,height_range={0.0,3.725290298461914E-9}," \
+          "length=65008.773722909886,length_95%_HPD={232.35151363136288,185443.9546690862}," \
+          "length_median=11647.615898062268,length_range={232.35151363136288,1.150899255812396E7}]:" \
+          "[&rate=0.14084529313827582]10185.506184914375,(9[&height=9.127260087722948E-12," \
+          "height_95%_HPD={0.0,2.9103830456733704E-11},height_median=0.0," \
+          "height_range={0.0,3.725290298461914E-9},length=25379.761049583933,length_95%_HPD=" \
+          "{56.592660460186835,58976.07308471651},length_median=3942.1518558536773,length_range=" \
+          "{56.592660460186835,6951356.4983186275}]:[&rate=0.22402647395508335]3942.1518558536773,12" \
+          "[&height=9.127260087722948E-12,height_95%_HPD={0.0,2.9103830456733704E-11},height_median=" \
+          "0.0,height_range={0.0,3.725290298461914E-9},length=25379.761049583933,length_95%_HPD=" \
+          "{56.592660460186835,58976.07308471651},length_median=3942.1518558536773,length_range=" \
+          "{56.592660460186835,6951356.4983186275}]:[&rate=0.22402647395508335]3942.1518558536773)" \
+          "[&height=25379.76104958394,height_95%_HPD={56.59266046018695,58976.07308471651}," \
+          "height_median=3942.1518558536773,height_range={56.59266046018695,6951356.498318631}," \
+          "length=38091.50530423341,length_95%_HPD={46.39747042888712,111881.67133971374}," \
+          "length_median=6404.173915508887,length_range={46.39747042888712,5175584.190381359}," \
+          "posterior=1.0]:[&rate=0.1764340946476647]6243.354329060698)[&height=63964.7133354256," \
+          "height_95%_HPD={232.35151363136288,174173.2306986642},height_median=10185.506184914375," \
+          "height_range={232.35151363136288,1.150899255812396E7},length=35902.53304149997," \
+          "length_95%_HPD={14.560332318756082,95384.63040570999},length_median=4975.027852972411," \
+          "length_range={14.560332318756082,7445332.392798465},posterior=0.8589521397147047]:" \
+          "[&rate=0.07923911606477686]4395.537413311296)[&height=80767.98182026888,height_95%_HPD=" \
+          "{529.6147479238796,233688.59740367957},height_median=14581.043598225671,height_range=" \
+          "{529.6147479238796,1.4524763136448236E7},length=31190.19922532072,length_95%_HPD=" \
+          "{3.6537288492327207,79714.48294750144},length_median=4454.437543634325,length_range=" \
+          "{3.6537288492327207,1.1428212448711276E7},posterior=0.5345953872816958]:[&rate=" \
+          "0.15749022880313052]9820.657628578989,(((2[&height=7.737585890856534E-12,height_95%_HPD=" \
+          "{0.0,2.9103830456733704E-11},height_median=0.0,height_range={0.0,3.725290298461914E-9}," \
+          "length=45609.46047931727,length_95%_HPD={206.83939466644824,123542.2654486959}," \
+          "length_median=8434.012912102502,length_range={206.83939466644824,1.6023311824151885E7}]:" \
+          "[&rate=0.3421656699625563]8434.18109992326,(3[&height=9.379050440351825E-12," \
+          "height_95%_HPD={0.0,2.9103830456733704E-11},height_median=0.0,height_range=" \
+          "{0.0,3.725290298461914E-9},length=29034.80730007669,length_95%_HPD={173.60894978441502," \
+          "80127.43307802954},length_median=5408.332869562197,length_range={173.60894978441502," \
+          "7565197.594627727}]:[&rate=0.40878488857536766]5408.332869562197,(((4[&height=" \
+          "9.533674239636711E-12,height_95%_HPD={0.0,2.9103830456733704E-11},height_median=0.0," \
+          "height_range={0.0,3.725290298461914E-9},length=12414.863740264116,length_95%_HPD=" \
+          "{66.08153995214036,31146.118985240348},length_median=2052.7139045146614,length_range=" \
+          "{66.08153995214036,4162747.7669137157}]:[&rate=0.40878488857536766]2052.713904514665," \
+          "(8[&height=8.76596601525156E-12,height_95%_HPD={0.0,2.9103830456733704E-11},height_median=" \
+          "0.0,height_range={0.0,3.725290298461914E-9},length=7495.104386864869,length_95%_HPD=" \
+          "{33.229724377705,18284.937529115006},length_median=1238.5410223305225,length_range=" \
+          "{33.229724377705,2652538.9755849764}]:[&rate=1.1616489920397255]1238.5410223305262,10" \
+          "[&height=8.76596601525156E-12,height_95%_HPD={0.0,2.9103830456733704E-11},height_median=" \
+          "0.0,height_range={0.0,3.725290298461914E-9},length=7495.104386864869,length_95%_HPD={" \
+          "33.229724377705,18284.937529115006},length_median=1238.5410223305225,length_range={" \
+          "33.229724377705,2652538.9755849764}]:[&rate=0.6807065555747316]1238.5410223305262)[" \
+          "&height=7495.104386864877,height_95%_HPD={33.229724377705,18284.937529115006}," \
+          "height_median=1238.5410223305262,height_range={33.229724377705,2652538.97558498}," \
+          "length=4919.759353399242,length_95%_HPD={11.135741831899963,13615.173191136855}," \
+          "length_median=727.9975598861292,length_range={11.135741831899963,1806011.4114757068}," \
+          "posterior=1.0]:[&rate=0.6807065555747316]814.1728821841389)[&height=12414.863740264125," \
+          "height_95%_HPD={66.08153995214036,31146.118985240348},height_median=2052.713904514665," \
+          "height_range={66.08153995214036,4162747.7669137195},length=4494.749985367252," \
+          "length_95%_HPD={7.997119765025445,13544.827830110327},length_median=743.8499422922905," \
+          "length_range={7.997119765025445,1079092.8689759858},posterior=1.0]:[&rate=1.1616489920397255" \
+          "]556.5552100585955,11[&height=8.828667314765534E-12,height_95%_HPD={" \
+          "0.0,2.9103830456733704E-11},height_median=0.0,height_range={0.0,3.725290298461914E-9}," \
+          "length=14628.206134120901,length_95%_HPD={94.62325431555337,39330.92845327759}," \
+          "length_median=2698.76238812456,length_range={84.29227912953411,3969567.691730257}]:" \
+          "[&rate=1.1616489920397255]2609.2691145732606)[&height=11972.847735373902,height_95%_HPD=" \
+          "{84.29227912953411,37091.0728580773},height_median=2609.2691145732606,height_range=" \
+          "{84.29227912953411,1575701.7833227757},length=2532.3352144701103,length_95%_HPD={" \
+          "0.004421725508564123,7620.200479995983},length_median=483.3085065544801,length_range={" \
+          "0.004421725508564123,488670.1513605751},posterior=0.674310091987735]:[&rate=" \
+          "0.14084529313827582]843.471284182473,13[&height=9.62737001763898E-12,height_95%_HPD={" \
+          "0.0,2.9103830456733704E-11},height_median=0.0,height_range={0.0,3.725290298461914E-9}," \
+          "length=16098.152887077857,length_95%_HPD={101.12152367712349,43253.00278986094}," \
+          "length_median=3021.1956203544178,length_range={87.52788789503245,3969567.691730257}]:" \
+          "[&rate=0.015281431734503132]3452.7403987557336)[&height=18854.825355500612,height_95%_HPD=" \
+          "{117.06952824319609,50863.21772980399},height_median=3452.7403987557336,height_range=" \
+          "{117.06952824319609,5241840.635889705},length=10179.981944576117,length_95%_HPD=" \
+          "{21.621494899670324,27419.87806782825},length_median=1701.737850154088,length_range=" \
+          "{21.621494899670324,2891063.76993455},posterior=1.0]:[&rate=0.22402647395508335]" \
+          "1955.592470806463)[&height=29034.807300076696,height_95%_HPD={173.60894978441502," \
+          "80127.4330780296},height_median=5408.332869562197,height_range={173.60894978441502," \
+          "7565197.594627731},length=16575.3792990243,length_95%_HPD={33.23044488203345,42503.93157259235}," \
+          "length_median=2600.4791495973714,length_range={33.23044488203345,9106986.442180987}," \
+          "posterior=1.0]:[&rate=0.40878488857536766]3025.8482303610635)[&height=45684.27028379785," \
+          "height_95%_HPD={206.83939466644847,123833.12145059655},height_median=8434.18109992326," \
+          "height_range={206.83939466644847,1.6023311824151888E7},length=18834.009102754226," \
+          "length_95%_HPD={12.551497256452194,44713.49388946092},length_median=2723.4761572134503," \
+          "length_range={12.551497256452194,8370840.365275718},posterior=0.9980002666311159]:[" \
+          "&rate=0.1260365850769451]3483.6026288094054,6[&height=8.559841366136245E-12," \
+          "height_95%_HPD={0.0,2.9103830456733704E-11},height_median=0.0,height_range={0.0," \
+          "3.725290298461914E-9},length=64263.38390382354,length_95%_HPD={242.88760407354857," \
+          "168923.3746203835},length_median=11621.922183927634,length_range={242.88760407354857," \
+          "2.4394152189427603E7}]:[&rate=0.15749022880313052]11917.783728732666)[&height=" \
+          "66462.97722328358,height_95%_HPD={242.8876040735488,172328.18950797373},height_median=" \
+          "11917.783728732666,height_range={242.8876040735488,2.4394152189427607E7},length=" \
+          "21074.24071127439,length_95%_HPD={9.33738591016754,65106.83779065257},length_median=" \
+          "3497.449465911657,length_range={9.33738591016754,3253753.156094387},posterior=" \
+          "0.9266764431409146]:[&rate=0.15749022880313052]1863.0826187841885,5[&height=" \
+          "8.909222646386704E-12,height_95%_HPD={0.0,2.9103830456733704E-11},height_median=0.0," \
+          "height_range={0.0,3.725290298461914E-9},length=86228.77947668775,length_95%_HPD={" \
+          "320.8279037754549,250680.98349718086},length_median=16191.236491985874,length_range={" \
+          "320.8279037754549,2.5385363199801262E7}]:[&rate=0.1764340946476647]13780.866347516854)[" \
+          "&height=68851.55714103008,height_95%_HPD={332.8967971018673,208360.19528088247}," \
+          "height_median=13780.866347516854,height_range={332.8967971018673,1.3209839631035523E7}," \
+          "length=36292.10334947041,length_95%_HPD={6.842269636452329,77005.81130131785}," \
+          "length_median=3986.097675025603,length_range={6.842269636452329,7690578.10700983}," \
+          "posterior=0.6665777896280496]:[&rate=0.06963566760197197]10620.834879287806)[&height=" \
+          "138844.64905308632,height_95%_HPD={474.13147831140884,367996.7683084475},height_median=" \
+          "24401.70122680466,height_range={474.13147831140884,3.1088350108564746E7},length=0.0,posterior=1.0]:0.0"
+    tree = loads(nwk)[0]
+    leafs = [n for n in tree.walk() if n.is_leaf]
+    assert len(leafs[0].comments) == 2
+    assert 'rate' in leafs[0].properties
+    assert tree.newick == nwk
+
+
 @pytest.mark.slow
 def test_gtdb_tree(fixture_dir):
     tree = read(fixture_dir / 'ar53_r207.tree')[0]
-- 
GitLab