[med-svn] [Git][med-team/python-ete3][master] 6 commits: New upstream version 3.1.3+dfsg

Andreas Tille (@tille) gitlab at salsa.debian.org
Wed Nov 15 10:34:04 GMT 2023



Andreas Tille pushed to branch master at Debian Med / python-ete3


Commits:
b99004af by Andreas Tille at 2023-11-15T11:25:03+01:00
New upstream version 3.1.3+dfsg
- - - - -
17ebe75e by Andreas Tille at 2023-11-15T11:25:03+01:00
routine-update: New upstream version

- - - - -
ebc486cc by Andreas Tille at 2023-11-15T11:25:07+01:00
Update upstream source from tag 'upstream/3.1.3+dfsg'

Update to upstream version '3.1.3+dfsg'
with Debian dir 3ff1af71cde14edaf1cd6472390bbca337b700c7
- - - - -
daa807c1 by Andreas Tille at 2023-11-15T11:25:07+01:00
routine-update: Standards-Version: 4.6.2

- - - - -
a678abb2 by Andreas Tille at 2023-11-15T11:25:11+01:00
routine-update: Build-Depends: s/dh-python/dh-sequence-python3/

- - - - -
fe52ec86 by Andreas Tille at 2023-11-15T11:29:03+01:00
routine-update: Ready to upload to unstable

- - - - -


22 changed files:

- PKG-INFO
- VERSION
- debian/changelog
- debian/control
- debian/rules
- ete3.egg-info/PKG-INFO
- ete3.egg-info/entry_points.txt
- ete3/coretype/tree.py
- ete3/evol/evoltree.py
- ete3/evol/model.py
- ete3/evol/parser/codemlparser.py
- ete3/ncbi_taxonomy/ncbiquery.py
- ete3/orthoxml/_orthoxml.py
- ete3/test/test_ncbiquery.py
- ete3/test/test_treeview/barchart_and_piechart_faces.py
- ete3/treeview/faces.py
- ete3/treeview/main.py
- ete3/treeview/qt.py
- ete3/treeview/qt4_face_render.py
- ete3/treeview/qt4_gui.py
- ete3/version.py
- setup.py


Changes:

=====================================
PKG-INFO
=====================================
@@ -1,32 +1,16 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
 Name: ete3
-Version: 3.1.2
+Version: 3.1.3
 Summary: A Python Environment for (phylogenetic) Tree Exploration
 Home-page: http://etetoolkit.org
+Download-URL: http://etetoolkit.org/static/releases/ete3/
 Author: Jaime Huerta-Cepas
 Author-email: jhcepas at gmail.com
 Maintainer: Jaime Huerta-Cepas
 Maintainer-email: huerta at embl.de
 License: GPLv3
-Download-URL: http://etetoolkit.org/static/releases/ete3/
-Description: 
-        The Environment for Tree Exploration (ETE) is a Python programming
-        toolkit that assists in the recontruction, manipulation, analysis and
-        visualization of phylogenetic trees (although clustering trees or any
-        other tree-like data structure are also supported).
-        
-        ETE is currently developed as a tool for researchers working in
-        phylogenetics and genomics. If you use ETE for a published work,
-        please cite:
-        
-        ::
-        
-           Jaime Huerta-Cepas, François Serra and Peer Bork. "ETE 3: Reconstruction,
-           analysis and visualization of phylogenomic data."  Mol Biol Evol (2016) doi:
-           10.1093/molbev/msw046
-        
-        Visit http://etetoolkit.org for more info.
-        
+Project-URL: Documentation, http://etetoolkit.org/docs/latest/tutorial/index.html
+Project-URL: Source, https://github.com/etetoolkit/ete
 Keywords: tree,tree reconstruction,tree visualization,tree comparison,phylogeny,phylogenetics,phylogenomics
 Platform: OS Independent
 Classifier: Development Status :: 6 - Mature
@@ -46,3 +30,22 @@ Classifier: Topic :: Scientific/Engineering :: Visualization
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Requires: six
 Provides: ete3
+License-File: LICENSE
+
+
+The Environment for Tree Exploration (ETE) is a Python programming
+toolkit that assists in the recontruction, manipulation, analysis and
+visualization of phylogenetic trees (although clustering trees or any
+other tree-like data structure are also supported).
+
+ETE is currently developed as a tool for researchers working in
+phylogenetics and genomics. If you use ETE for a published work,
+please cite:
+
+::
+
+   Jaime Huerta-Cepas, François Serra and Peer Bork. "ETE 3: Reconstruction,
+   analysis and visualization of phylogenomic data."  Mol Biol Evol (2016) doi:
+   10.1093/molbev/msw046
+
+Visit http://etetoolkit.org for more info.


=====================================
VERSION
=====================================
@@ -1 +1 @@
-3.1.2
\ No newline at end of file
+3.1.3
\ No newline at end of file


=====================================
debian/changelog
=====================================
@@ -1,3 +1,12 @@
+python-ete3 (3.1.3+dfsg-1) unstable; urgency=medium
+
+  * Team upload.
+  * New upstream version
+  * Standards-Version: 4.6.2 (routine-update)
+  * Build-Depends: s/dh-python/dh-sequence-python3/ (routine-update)
+
+ -- Andreas Tille <tille at debian.org>  Wed, 15 Nov 2023 11:26:38 +0100
+
 python-ete3 (3.1.2+dfsg-3) unstable; urgency=medium
 
   * Team upload.


=====================================
debian/control
=====================================
@@ -6,7 +6,7 @@ Section: python
 Testsuite: autopkgtest-pkg-python
 Priority: optional
 Build-Depends: debhelper-compat (= 13),
-               dh-python,
+               dh-sequence-python3,
                python3-all,
                python3-setuptools,
                python3-numpy,
@@ -17,7 +17,7 @@ Build-Depends: debhelper-compat (= 13),
                python3-six,
                python3-skbio,
                python3-pytest
-Standards-Version: 4.6.0
+Standards-Version: 4.6.2
 Vcs-Browser: https://salsa.debian.org/med-team/python-ete3
 Vcs-Git: https://salsa.debian.org/med-team/python-ete3.git
 Homepage: http://etetoolkit.org


=====================================
debian/rules
=====================================
@@ -6,7 +6,7 @@ export PYBUILD_NAME=ete3
 #export PYBUILD_TEST_ARGS_python3=-k-XTest_ncbiquery
 
 %:
-	dh $@ --with python3 --buildsystem=pybuild
+	dh $@ --buildsystem=pybuild
 override_dh_auto_install:
 	dh_auto_install -O--buildsystem=pybuild
 	rm -r debian/python3-ete3/usr/bin


=====================================
ete3.egg-info/PKG-INFO
=====================================
@@ -1,32 +1,16 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
 Name: ete3
-Version: 3.1.2
+Version: 3.1.3
 Summary: A Python Environment for (phylogenetic) Tree Exploration
 Home-page: http://etetoolkit.org
+Download-URL: http://etetoolkit.org/static/releases/ete3/
 Author: Jaime Huerta-Cepas
 Author-email: jhcepas at gmail.com
 Maintainer: Jaime Huerta-Cepas
 Maintainer-email: huerta at embl.de
 License: GPLv3
-Download-URL: http://etetoolkit.org/static/releases/ete3/
-Description: 
-        The Environment for Tree Exploration (ETE) is a Python programming
-        toolkit that assists in the recontruction, manipulation, analysis and
-        visualization of phylogenetic trees (although clustering trees or any
-        other tree-like data structure are also supported).
-        
-        ETE is currently developed as a tool for researchers working in
-        phylogenetics and genomics. If you use ETE for a published work,
-        please cite:
-        
-        ::
-        
-           Jaime Huerta-Cepas, François Serra and Peer Bork. "ETE 3: Reconstruction,
-           analysis and visualization of phylogenomic data."  Mol Biol Evol (2016) doi:
-           10.1093/molbev/msw046
-        
-        Visit http://etetoolkit.org for more info.
-        
+Project-URL: Documentation, http://etetoolkit.org/docs/latest/tutorial/index.html
+Project-URL: Source, https://github.com/etetoolkit/ete
 Keywords: tree,tree reconstruction,tree visualization,tree comparison,phylogeny,phylogenetics,phylogenomics
 Platform: OS Independent
 Classifier: Development Status :: 6 - Mature
@@ -46,3 +30,22 @@ Classifier: Topic :: Scientific/Engineering :: Visualization
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Requires: six
 Provides: ete3
+License-File: LICENSE
+
+
+The Environment for Tree Exploration (ETE) is a Python programming
+toolkit that assists in the recontruction, manipulation, analysis and
+visualization of phylogenetic trees (although clustering trees or any
+other tree-like data structure are also supported).
+
+ETE is currently developed as a tool for researchers working in
+phylogenetics and genomics. If you use ETE for a published work,
+please cite:
+
+::
+
+   Jaime Huerta-Cepas, François Serra and Peer Bork. "ETE 3: Reconstruction,
+   analysis and visualization of phylogenomic data."  Mol Biol Evol (2016) doi:
+   10.1093/molbev/msw046
+
+Visit http://etetoolkit.org for more info.


=====================================
ete3.egg-info/entry_points.txt
=====================================
@@ -1,3 +1,2 @@
 [console_scripts]
 ete3 = ete3.tools.ete:main
-


=====================================
ete3/coretype/tree.py
=====================================
@@ -1658,7 +1658,7 @@ class TreeNode(object):
         :param name attr_t2: Compare trees using a custom node
                               attribute as a node name in target tree.
 
-        :param False attr_t2: If True, consider trees as unrooted.
+        :param False unrooted_trees: If True, consider trees as unrooted.
 
         :param False expand_polytomies: If True, all polytomies in the reference
            and target tree will be expanded into all possible binary


=====================================
ete3/evol/evoltree.py
=====================================
@@ -44,12 +44,20 @@ the coretype PhyloNode and add some speciall features to the the node
 instances.
 """
 from __future__ import absolute_import
+from ..tools.utils import which
+from .utils import translate
+from .model import Model, PARAMS, AVAIL
+from ..parser.newick import write_newick
+from .. import PhyloNode, SeqGroup
+from warnings import warn
+import sys
+import os
 from six.moves import map
 
-__author__     = "Francois-Jose Serra"
-__email__      = "francois at barrabin.org"
-__licence__    = "GPLv3"
-__version__    = "0.0"
+__author__ = "Francois-Jose Serra"
+__email__ = "francois at barrabin.org"
+__licence__ = "GPLv3"
+__version__ = "0.0"
 __references__ = '''
 Yang, Z., Nielsen, R., Goldman, N., & Pedersen, A. M. 2000.
     Codon-substitution models for heterogeneous selection pressure at amino acid sites.
@@ -73,18 +81,10 @@ Yang, Z. 2007.
     Retrieved from http://www.ncbi.nlm.nih.gov/pubmed/17483113
 '''
 
-import os
-import sys
-from warnings import warn
 
-from .. import PhyloNode, SeqGroup
-from ..parser.newick import write_newick
-from .model import Model, PARAMS, AVAIL
-from .utils import translate
-from ..tools.utils import which
 try:
     from scipy.stats import chi2
-    chi_high = lambda x, y: 1 - chi2.cdf(x, y)
+    def chi_high(x, y): return 1 - chi2.cdf(x, y)
 except ImportError:
     from .utils import chi_high
 
@@ -97,12 +97,14 @@ else:
 
 __all__ = ["EvolNode", "EvolTree"]
 
+
 def _parse_species(name):
     '''
     just to return specie name from fasta description
     '''
     return name[:3]
 
+
 class EvolNode(PhyloNode):
     """ Re-implementation of the standart TreeNode instance. It adds
     attributes and methods to work with phylogentic trees.
@@ -118,7 +120,7 @@ class EvolNode(PhyloNode):
 
     def __init__(self, newick=None, alignment=None, alg_format="fasta",
                  sp_naming_function=_parse_species, format=0,
-                  binpath='', **kwargs):
+                 binpath='', **kwargs):
         '''
         freebranch: path to find codeml output of freebranch model.
         '''
@@ -167,11 +169,12 @@ class EvolNode(PhyloNode):
         nid = 1
         # check we do not have dupplicated names in tree
         if (len(self)) != len(set(self.get_leaf_names())):
-            duplis = [n for n in self.get_leaf_names() if self.get_leaf_names().count(n)>1]
+            duplis = [n for n in self.get_leaf_names(
+            ) if self.get_leaf_names().count(n) > 1]
             raise Exception('EvolTree require unique names for leaves', duplis)
         # put ids
         for leaf in sorted(self, key=lambda x: x.name):
-            leaf.add_feature ('node_id', nid)
+            leaf.add_feature('node_id', nid)
             nid += 1
         self.add_feature('node_id', nid)
         self._label_internal_nodes([nid])
@@ -187,7 +190,7 @@ class EvolNode(PhyloNode):
             if self.node_id == idname:
                 return self
         except AttributeError:
-            warn('Should be first labelled as paml ' + \
+            warn('Should be first labelled as paml ' +
                  '(automatically done when alignemnt is loaded)')
 
     def _write_algn(self, fullpath):
@@ -196,12 +199,11 @@ class EvolNode(PhyloNode):
         """
         seq_group = SeqGroup()
         for n in self:
-            seq_group.id2seq  [n.node_id] = n.nt_sequence
-            seq_group.id2name [n.node_id] = n.name
-            seq_group.name2id [n.name   ] = n.node_id
+            seq_group.id2seq[n.node_id] = n.nt_sequence
+            seq_group.id2name[n.node_id] = n.name
+            seq_group.name2id[n.name] = n.node_id
         seq_group.write(outfile=fullpath, format='paml')
 
-
     def run_model(self, model_name, ctrl_string='', keep=True, **kwargs):
         '''
         To compute evolutionnary models.     e.g.: b_free_lala.vs.lele, will launch one free branch model, and store
@@ -226,21 +228,22 @@ class EvolNode(PhyloNode):
                               * model-name is compulsory, is the name of the model (see table above for the full list)
                               * the second part is accessory, it is to avoid over-writing models with the same name.
         :argument ctrl_string: list of parameters that can be used as control file.
+        :argument True keep: links the model to the tree (equivalen of running `EVOL_TREE.link_to_evol_model(MODEL_NAME)`)
         :argument kwargs: extra parameters should be one of: %s.
         '''
         from subprocess import Popen, PIPE
         model_obj = Model(model_name, self, **kwargs)
-        fullpath = os.path.join (self.workdir, model_obj.name)
-        os.system("mkdir -p %s" %fullpath)
+        fullpath = os.path.join(self.workdir, model_obj.name)
+        os.system("mkdir -p %s" % fullpath)
         # write tree file
         self._write_algn(fullpath + '/algn')
         if model_obj.properties['exec'] == 'Slr':
-            self.write(outfile=fullpath+'/tree', format = (11))
+            self.write(outfile=fullpath+'/tree', format=(11))
         else:
             self.write(outfile=fullpath+'/tree',
-                       format = (10 if model_obj.properties['allow_mark'] else 9))
+                       format=(10 if model_obj.properties['allow_mark'] else 9))
         # write algn file
-        ## MODEL MODEL MDE
+        # MODEL MODEL MDE
         if ctrl_string == '':
             ctrl_string = model_obj.get_ctrl_string(fullpath+'/tmp.ctl')
         else:
@@ -249,34 +252,31 @@ class EvolNode(PhyloNode):
         os.chdir(fullpath)
         bin_ = os.path.join(self.execpath, model_obj.properties['exec'])
         try:
-            proc = Popen([bin_, 'tmp.ctl'], stdout=PIPE, stdin=PIPE)
+            proc = Popen([bin_, 'tmp.ctl'], stdout=PIPE,
+                         stdin=PIPE, stderr=PIPE)
         except OSError:
             raise Exception(('ERROR: {} not installed, ' +
                              'or wrong path to binary\n').format(bin_))
-        run, err = proc.communicate(b'\n') # send \n via stdin in case codeml/slr asks something (note on py3, stdin needs bytes)
+        # send \n via stdin in case codeml/slr asks something (note on py3, stdin needs bytes)
+        run, err = proc.communicate(b'\n')
         run = run.decode(sys.stdout.encoding)
 
-        if err is not None:
-            warn("ERROR: codeml not found!!!\n" +
-                 "       define your variable EvolTree.execpath")
-            return 1
-        if 'error' in run or 'Error' in run:
-            warn("ERROR: inside codeml!!\n" + run)
-            return 1
         os.chdir(hlddir)
+        if err:
+            warn("ERROR: inside codeml!!\n" + err)
+            return 1
         if keep:
             setattr(model_obj, 'run', run)
-            self.link_to_evol_model(os.path.join(fullpath,'out'), model_obj)
+            self.link_to_evol_model(os.path.join(fullpath, 'out'), model_obj)
     sep = '\n'
     run_model.__doc__ = run_model.__doc__ % \
-                        (sep.join(['          %-8s   %-27s   %-15s  ' % \
-                                      ('%s' % (x), AVAIL[x]['evol'], AVAIL[x]['typ']) for x in sorted (sorted (AVAIL.keys()), key=lambda x: \
-                                              AVAIL[x]['typ'],
-                                              reverse=True)]),
-                         ', '.join(list(PARAMS.keys())))
-
+        (sep.join(['          %-8s   %-27s   %-15s  ' %
+                   ('%s' % (x), AVAIL[x]['evol'], AVAIL[x]['typ']) for x in sorted(sorted(AVAIL.keys()), key=lambda x:
+                                                                                   AVAIL[x]['typ'],
+                                                                                   reverse=True)]),
+         ', '.join(list(PARAMS.keys())))
 
-    #def test_codon_model(self):
+    # def test_codon_model(self):
     #    for c_frq in range(4):
     #        self.run_model('M0.model_test-'+str(c_frq), CodonFreq=c_frq)
     #    if self.get_most_likely('M0.model_test-1', 'M0.model_test-0') > 0.05:
@@ -288,7 +288,7 @@ class EvolNode(PhyloNode):
     #    self.get_most_likely('M0.model_test-3', 'M0.model_test-2')
 
     def link_to_alignment(self, alignment, alg_format="paml",
-                           nucleotides=True, **kwargs):
+                          nucleotides=True, **kwargs):
         '''
         same function as for phyloTree, but translate sequences if nucleotides
         nucleotidic sequence is kept under node.nt_sequence
@@ -332,11 +332,11 @@ class EvolNode(PhyloNode):
                     except AttributeError:
                         warn('model %s not computed' % (hist))
                     if not 'histface' in mdl.properties:
-                        if len(histfaces)>1 and histfaces.index(hist)!=0:
+                        if len(histfaces) > 1 and histfaces.index(hist) != 0:
                             mdl.set_histface(up=False)
                         else:
                             mdl.set_histface()
-                    if mdl.properties ['histface'].up:
+                    if mdl.properties['histface'].up:
                         ts.aligned_header.add_face(
                             mdl.properties['histface'], 1)
                     else:
@@ -346,7 +346,6 @@ class EvolNode(PhyloNode):
         else:
             raise ValueError("Treeview module is disabled")
 
-
     def render(self, file_name, layout=None, w=None, h=None,
                tree_style=None, header=None, histfaces=None):
         '''
@@ -369,11 +368,11 @@ class EvolNode(PhyloNode):
                     except AttributeError:
                         warn('model %s not computed' % (hist))
                     if not 'histface' in mdl.properties:
-                        if len(histfaces)>1 and histfaces.index(hist)!=0:
+                        if len(histfaces) > 1 and histfaces.index(hist) != 0:
                             mdl.set_histface(up=False)
                         else:
                             mdl.set_histface()
-                    if mdl.properties ['histface'].up:
+                    if mdl.properties['histface'].up:
                         ts.aligned_header.add_face(
                             mdl.properties['histface'], 1)
                     else:
@@ -385,7 +384,6 @@ class EvolNode(PhyloNode):
         else:
             raise ValueError("Treeview module is disabled")
 
-
     def mark_tree(self, node_ids, verbose=False, **kargs):
         '''
         function to mark branches on tree in order that paml could interpret it.
@@ -401,11 +399,11 @@ class EvolNode(PhyloNode):
 
         '''
         from re import match
-        node_ids = list(map(int , node_ids))
+        node_ids = list(map(int, node_ids))
         if 'marks' in kargs:
             marks = list(kargs['marks'])
         else:
-            marks = ['#1']*len (node_ids)
+            marks = ['#1']*len(node_ids)
         for node in self.traverse():
             if not hasattr(node, 'node_id'):
                 continue
@@ -415,7 +413,8 @@ class EvolNode(PhyloNode):
                           marks[node_ids.index(node.node_id)]) is None) and verbose:
                     warn('WARNING: marks should be "#" sign directly ' +
                          'followed by integer\n' + self.mark_tree.__doc__)
-                node.add_feature('mark', ' '+marks[node_ids.index(node.node_id)])
+                node.add_feature(
+                    'mark', ' '+marks[node_ids.index(node.node_id)])
             elif not 'mark' in node.features:
                 node.add_feature('mark', '')
 
@@ -430,7 +429,7 @@ class EvolNode(PhyloNode):
         :argument model: either the name of a model, or a Model object (usually empty)
 
         '''
-        if type(model) == str :
+        if isinstance(model, str):
             model = Model(model, self, path)
         else:
             model._load(path)
@@ -443,7 +442,7 @@ class EvolNode(PhyloNode):
         if not os.path.isfile(path):
             warn("ERROR: not a file: " + path)
             return 1
-        if len(self._models) == 1 and model.properties['exec']=='codeml':
+        if len(self._models) == 1 and model.properties['exec'] == 'codeml':
             self.change_dist_to_evol('bL', model, fill=True)
 
     def get_evol_model(self, modelname):
@@ -456,8 +455,7 @@ class EvolNode(PhyloNode):
         try:
             return self._models[modelname]
         except KeyError:
-            warn("Model %s not found." % (modelname))
-
+            Exception("ERROR: Model %s not found." % (modelname))
 
     def write(self, features=None, outfile=None, format=10):
         """
@@ -465,15 +463,15 @@ class EvolNode(PhyloNode):
         TODO: internal writting format need to be something like 0
         """
         from re import sub
-        if int(format)==11:
+        if int(format) == 11:
             nwk = ' %s 1\n' % (len(self))
-            nwk += sub('\[&&NHX:mark=([ #0-9.]*)\]', r'\1', \
-                       write_newick(self, features=['mark'],format=9))
-        elif int(format)==10:
-            nwk = sub('\[&&NHX:mark=([ #0-9.]*)\]', r'\1', \
-                      write_newick(self, features=['mark'],format=9))
+            nwk += sub('\[&&NHX:mark=([ #0-9.]*)\]', r'\1',
+                       write_newick(self, features=['mark'], format=9))
+        elif int(format) == 10:
+            nwk = sub('\[&&NHX:mark=([ #0-9.]*)\]', r'\1',
+                      write_newick(self, features=['mark'], format=9))
         else:
-            nwk = write_newick(self, features=features,format=format)
+            nwk = write_newick(self, features=features, format=format)
         if outfile is not None:
             open(outfile, "w").write(nwk)
             return nwk
@@ -482,7 +480,6 @@ class EvolNode(PhyloNode):
     write.__doc__ += super(PhyloNode, PhyloNode()).write.__doc__.replace(
         'argument format', 'argument 10 format')
 
-
     def get_most_likely(self, altn, null):
         '''
         Returns pvalue of LRT between alternative model and null model.
@@ -530,7 +527,7 @@ class EvolNode(PhyloNode):
             return 1.0
         try:
             if hasattr(altn, 'lnL') and hasattr(null, 'lnL'):
-                if  null.lnL - altn.lnL < 0:
+                if null.lnL - altn.lnL < 0:
                     return chi_high(2 * abs(altn.lnL - null.lnL),
                                     float(altn.np - null.np))
                 else:
@@ -563,7 +560,7 @@ class EvolNode(PhyloNode):
             node.dist = model.branches[node.node_id][evol]
             if fill:
                 for e in ['dN', 'dS', 'w', 'bL']:
-                    node.add_feature(e, model.branches [node.node_id][e])
+                    node.add_feature(e, model.branches[node.node_id][e])
 
 
 # cosmetic alias


=====================================
ete3/evol/model.py
=====================================
@@ -217,8 +217,7 @@ class Model:
         if not 'ylim' in kwargs:
             kwargs['ylim'] = (0, 2)
         if errors:
-            errors = self.sites[val]['se'] if 'se' in self.sites[val]\
-                     else None
+            errors = self.sites[val].get('se', None)
         if TREEVIEW:
             try:
                 hist = SequencePlotFace(self.sites[val]['w'], hlines=hlines,
@@ -336,7 +335,7 @@ class Model:
                                     self.sites[val]['class']):
             if pval < 0.95:
                 categories.append('NS')
-            elif curr_class != self.n_classes[val] and not ps_model:
+            elif curr_class == self.n_classes[val] and not ps_model:
                 if pval < 0.99:
                     categories.append('RX')
                 else:


=====================================
ete3/evol/parser/codemlparser.py
=====================================
@@ -107,16 +107,16 @@ def parse_rst(path):
         sites[typ].setdefault ('aa', []).append (line[1])
         # get site class probability
         probs = []
-        for i in range (k):
+        for i in range(k):
             probs.append (float (line[2+i]))
-            sites [typ].setdefault ('p'+str(i), []).append (float (line[2+i]))
-        sites [typ].setdefault ('pv', []).append (max (probs))
+            sites [typ].setdefault('p' + str(i), []).append(float(line[2+i]))
+        sites [typ].setdefault ('pv', []).append (max(probs))
         # get most likely site class
         classe = int (line [3 + i])
-        sites[typ].setdefault ('class', []).append (classe)
+        sites[typ].setdefault ('class', []).append(classe)
         # if there, get omega and error
         try:
-            sites [typ].setdefault ('w' , []).append (float (line [4 + i]))
+            sites [typ].setdefault('w' , []).append(float (line [4 + i]))
         except IndexError:
             # in this case we are with branch-site A or A1 and we should sum
             # probabilities of categories 2a and 2b
@@ -218,7 +218,7 @@ def parse_paml (pamout, model):
         model._tree._label_as_paml()
     # starts parsing
     for i, line in enumerate (all_lines):
-        if line is '\n':
+        if line == '\n':
             continue
         # codon frequency
         if line.startswith('Codon frequencies under model'):


=====================================
ete3/ncbi_taxonomy/ncbiquery.py
=====================================
@@ -97,7 +97,7 @@ class NCBITaxa(object):
     Provides a local transparent connector to the NCBI taxonomy database.
     """
 
-    def __init__(self, dbfile=None, taxdump_file=None):
+    def __init__(self, dbfile=None, taxdump_file=None, update=True):
 
         if not dbfile:
             self.dbfile = DEFAULT_TAXADB
@@ -107,7 +107,7 @@ class NCBITaxa(object):
         if taxdump_file:
             self.update_taxonomy_database(taxdump_file)
 
-        if dbfile is None and not os.path.exists(self.dbfile):
+        if dbfile != DEFAULT_TAXADB and not os.path.exists(self.dbfile):
             print('NCBI database not present yet (first time used?)', file=sys.stderr)
             self.update_taxonomy_database(taxdump_file)
 
@@ -117,7 +117,7 @@ class NCBITaxa(object):
         self.db = None
         self._connect()
 
-        if not is_taxadb_up_to_date(self.dbfile):
+        if not is_taxadb_up_to_date(self.dbfile) and update:
             print('NCBI database format is outdated. Upgrading', file=sys.stderr)
             self.update_taxonomy_database(taxdump_file)
 
@@ -371,7 +371,7 @@ class NCBITaxa(object):
             elif intermediate_nodes:
                 return list(map(int, [n.name for n in tree.get_descendants()]))
             else:
-                return map(int, [n.name for n in tree])
+                return list(map(int, [n.name for n in tree]))
 
         elif intermediate_nodes:
             return [tid for tid, count in six.iteritems(descendants)]
@@ -410,11 +410,11 @@ class NCBITaxa(object):
             visited = set()
             start = prepostorder.index(root_taxid)
             try:
-            	end = prepostorder.index(root_taxid, start+1)
-            	subtree = prepostorder[start:end+1]
+                end = prepostorder.index(root_taxid, start+1)
+                subtree = prepostorder[start:end+1]
             except ValueError:
                 # If root taxid is not found in postorder, must be a tip node
-            	subtree = [root_taxid]
+                subtree = [root_taxid]
             leaves = set([v for v, count in Counter(subtree).items() if count == 1])
             nodes[root_taxid] = PhyloTree(name=str(root_taxid))
             current_parent = nodes[root_taxid]


=====================================
ete3/orthoxml/_orthoxml.py
=====================================
@@ -447,13 +447,13 @@ class orthoXML(GeneratedsSuper):
     def exportAttributes(self, outfile, level, already_processed, namespace_='ortho:', name_='orthoXML'):
         if self.origin is not None and 'origin' not in already_processed:
             already_processed.append('origin')
-            outfile.write(' origin=%s' % (self.gds_format_string(quote_attrib(self.origin).encode(ExternalEncoding), input_name='origin'), ))
+            outfile.write(' origin=%s' % (self.gds_format_string(quote_attrib(self.origin), input_name='origin'), ))
         if self.version is not None and 'version' not in already_processed:
             already_processed.append('version')
             outfile.write(' version="%s"' % self.gds_format_float(self.version, input_name='version'))
         if self.originVersion is not None and 'originVersion' not in already_processed:
             already_processed.append('originVersion')
-            outfile.write(' originVersion=%s' % (self.gds_format_string(quote_attrib(self.originVersion).encode(ExternalEncoding), input_name='originVersion'), ))
+            outfile.write(' originVersion=%s' % (self.gds_format_string(quote_attrib(self.originVersion), input_name='originVersion'), ))
     def exportChildren(self, outfile, level, namespace_='ortho:', name_='orthoXML', fromsubclass_=False):
         if self.notes:
             self.notes.export(outfile, level, namespace_, name_='notes')
@@ -609,7 +609,7 @@ class species(GeneratedsSuper):
     def exportAttributes(self, outfile, level, already_processed, namespace_='ortho:', name_='species'):
         if self.name is not None and 'name' not in already_processed:
             already_processed.append('name')
-            outfile.write(' name=%s' % (self.gds_format_string(quote_attrib(self.name).encode(ExternalEncoding), input_name='name'), ))
+            outfile.write(' name=%s' % (self.gds_format_string(quote_attrib(self.name), input_name='name'), ))
         if self.NCBITaxId is not None and 'NCBITaxId' not in already_processed:
             already_processed.append('NCBITaxId')
             outfile.write(' NCBITaxId="%s"' % self.gds_format_integer(self.NCBITaxId, input_name='NCBITaxId'))
@@ -740,19 +740,19 @@ class database(GeneratedsSuper):
     def exportAttributes(self, outfile, level, already_processed, namespace_='ortho:', name_='database'):
         if self.transcriptLink is not None and 'transcriptLink' not in already_processed:
             already_processed.append('transcriptLink')
-            outfile.write(' transcriptLink=%s' % (self.gds_format_string(quote_attrib(self.transcriptLink).encode(ExternalEncoding), input_name='transcriptLink'), ))
+            outfile.write(' transcriptLink=%s' % (self.gds_format_string(quote_attrib(self.transcriptLink), input_name='transcriptLink'), ))
         if self.protLink is not None and 'protLink' not in already_processed:
             already_processed.append('protLink')
-            outfile.write(' protLink=%s' % (self.gds_format_string(quote_attrib(self.protLink).encode(ExternalEncoding), input_name='protLink'), ))
+            outfile.write(' protLink=%s' % (self.gds_format_string(quote_attrib(self.protLink), input_name='protLink'), ))
         if self.geneLink is not None and 'geneLink' not in already_processed:
             already_processed.append('geneLink')
-            outfile.write(' geneLink=%s' % (self.gds_format_string(quote_attrib(self.geneLink).encode(ExternalEncoding), input_name='geneLink'), ))
+            outfile.write(' geneLink=%s' % (self.gds_format_string(quote_attrib(self.geneLink), input_name='geneLink'), ))
         if self.name is not None and 'name' not in already_processed:
             already_processed.append('name')
-            outfile.write(' name=%s' % (self.gds_format_string(quote_attrib(self.name).encode(ExternalEncoding), input_name='name'), ))
+            outfile.write(' name=%s' % (self.gds_format_string(quote_attrib(self.name), input_name='name'), ))
         if self.version is not None and 'version' not in already_processed:
             already_processed.append('version')
-            outfile.write(' version=%s' % (self.gds_format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), ))
+            outfile.write(' version=%s' % (self.gds_format_string(quote_attrib(self.version), input_name='version'), ))
     def exportChildren(self, outfile, level, namespace_='ortho:', name_='database', fromsubclass_=False):
         if self.genes:
             self.genes.export(outfile, level, namespace_, name_='genes', )
@@ -962,16 +962,16 @@ class gene(GeneratedsSuper):
     def exportAttributes(self, outfile, level, already_processed, namespace_='ortho:', name_='gene'):
         if self.protId is not None and 'protId' not in already_processed:
             already_processed.append('protId')
-            outfile.write(' protId=%s' % (self.gds_format_string(quote_attrib(self.protId).encode(ExternalEncoding), input_name='protId'), ))
+            outfile.write(' protId=%s' % (self.gds_format_string(quote_attrib(self.protId), input_name='protId'), ))
         if self.id is not None and 'id' not in already_processed:
             already_processed.append('id')
             outfile.write(' id="%s"' % self.gds_format_integer(self.id, input_name='id'))
         if self.geneId is not None and 'geneId' not in already_processed:
             already_processed.append('geneId')
-            outfile.write(' geneId=%s' % (self.gds_format_string(quote_attrib(self.geneId).encode(ExternalEncoding), input_name='geneId'), ))
+            outfile.write(' geneId=%s' % (self.gds_format_string(quote_attrib(self.geneId), input_name='geneId'), ))
         if self.transcriptId is not None and 'transcriptId' not in already_processed:
             already_processed.append('transcriptId')
-            outfile.write(' transcriptId=%s' % (self.gds_format_string(quote_attrib(self.transcriptId).encode(ExternalEncoding), input_name='transcriptId'), ))
+            outfile.write(' transcriptId=%s' % (self.gds_format_string(quote_attrib(self.transcriptId), input_name='transcriptId'), ))
     def exportChildren(self, outfile, level, namespace_='ortho:', name_='gene', fromsubclass_=False):
         pass
     def hasContent_(self):
@@ -1277,7 +1277,7 @@ class group(GeneratedsSuper):
     def exportAttributes(self, outfile, level, already_processed, namespace_='ortho:', name_='group'):
         if self.id is not None and 'id' not in already_processed:
             already_processed.append('id')
-            outfile.write(' id=%s' % (self.gds_format_string(quote_attrib(self.id).encode(ExternalEncoding), input_name='id'), ))
+            outfile.write(' id=%s' % (self.gds_format_string(quote_attrib(self.id), input_name='id'), ))
     def exportChildren(self, outfile, level, namespace_='ortho:', name_='group', fromsubclass_=False):
         for score_ in self.score:
             score_.export(outfile, level, namespace_, name_='score')
@@ -1576,7 +1576,7 @@ class scoreDef(GeneratedsSuper):
             outfile.write(' id=%s' % (quote_attrib(self.id), ))
         if self.desc is not None and 'desc' not in already_processed:
             already_processed.append('desc')
-            outfile.write(' desc=%s' % (self.gds_format_string(quote_attrib(self.desc).encode(ExternalEncoding), input_name='desc'), ))
+            outfile.write(' desc=%s' % (self.gds_format_string(quote_attrib(self.desc), input_name='desc'), ))
     def exportChildren(self, outfile, level, namespace_='ortho:', name_='scoreDef', fromsubclass_=False):
         pass
     def hasContent_(self):
@@ -1744,10 +1744,10 @@ class property(GeneratedsSuper):
     def exportAttributes(self, outfile, level, already_processed, namespace_='ortho:', name_='property'):
         if self.name is not None and 'name' not in already_processed:
             already_processed.append('name')
-            outfile.write(' name=%s' % (self.gds_format_string(quote_attrib(self.name).encode(ExternalEncoding), input_name='name'), ))
+            outfile.write(' name=%s' % (self.gds_format_string(quote_attrib(self.name), input_name='name'), ))
         if self.value is not None and 'value' not in already_processed:
             already_processed.append('value')
-            outfile.write(' value=%s' % (self.gds_format_string(quote_attrib(self.value).encode(ExternalEncoding), input_name='value'), ))
+            outfile.write(' value=%s' % (self.gds_format_string(quote_attrib(self.value), input_name='value'), ))
     def exportChildren(self, outfile, level, namespace_='ortho:', name_='property', fromsubclass_=False):
         pass
     def hasContent_(self):


=====================================
ete3/test/test_ncbiquery.py
=====================================
@@ -56,13 +56,13 @@ class Test_ncbiquery(unittest.TestCase):
     self.assertEqual(set(name2id['Bacteria']), set([2]))
 
     out = ncbi.get_descendant_taxa("9605", intermediate_nodes=True)
-    #Out[9]: [9606, 63221, 741158, 2665952, 2665953, 1425170]
+    #Out[9]: [9606, 63221, 741158, 2665952, 2665953, 1425170, 2813598, 2813599]
     # New Taxonomies of Homo in NCBI, {2665952: 'environmental samples', 2665953: 'Homo sapiens environmental sample'}
-    self.assertEqual(set(out), set([9606, 63221, 741158, 2665952, 2665953, 1425170]))
+    self.assertEqual(set(out), set([9606, 63221, 741158, 2665952, 2665953, 1425170, 2813598, 2813599]))
     
     out = ncbi.get_descendant_taxa("9605", intermediate_nodes=False)
     #Out[10]: [63221, 741158, 2665953, 1425170]
-    self.assertEqual(set(out), set([63221, 741158, 2665953, 1425170]))
+    self.assertEqual(set(out), set([63221, 741158, 2665953, 1425170, 2813599]))
     
     out = ncbi.get_descendant_taxa("9596", intermediate_nodes=False, rank_limit="species")
     #Out[11]: [9597, 9598]


=====================================
ete3/test/test_treeview/barchart_and_piechart_faces.py
=====================================
@@ -2,7 +2,7 @@ import sys
 import random
 from ... import Tree, faces, TreeStyle, COLOR_SCHEMES
 
-schema_names = COLOR_SCHEMES.keys()
+schema_names = sorted(COLOR_SCHEMES.keys())
 
 def layout(node):
     if node.is_leaf():


=====================================
ete3/treeview/faces.py
=====================================
@@ -63,9 +63,9 @@ from six.moves import zip
 from .qt import (QGraphicsRectItem, QGraphicsLineItem,
                  QGraphicsPolygonItem, QGraphicsEllipseItem,
                  QPen, QColor, QBrush, QPolygonF, QFont,
-                 QPixmap, QFontMetrics, QPainter,
+                 QPixmap, QFontMetrics, QPainter, QPainterPath,
                  QRadialGradient, QGraphicsSimpleTextItem, QGraphicsTextItem,
-                 QGraphicsItem, Qt,  QPointF, QRect, QRectF, QGraphicsSvgItem)
+                 QGraphicsItem, Qt, QLineF, QPointF, QRect, QRectF, QGraphicsSvgItem)
 
 from .main import add_face_to_node, _Background, _Border, COLOR_SCHEMES
 
@@ -560,19 +560,19 @@ class ProfileFace(Face):
 
         # Draw axis and scale
         p.setPen(QColor("black"))
-        p.drawRect(x2,y,profile_width, profile_height-1)
+        p.drawRect(QRectF(x2,y,profile_width, profile_height-1))
         p.setFont(QFont("Verdana",8))
-        p.drawText(profile_width,y+10,"%0.3f" %self.max_value)
-        p.drawText(profile_width,y+profile_height,"%0.3f" %self.min_value)
+        p.drawText(QPointF(profile_width,y+10), "%0.3f" %self.max_value)
+        p.drawText(QPointF(profile_width,y+profile_height), "%0.3f" %self.min_value)
 
         dashedPen = QPen(QBrush(QColor("#ddd")), 0)
         dashedPen.setStyle(Qt.DashLine)
 
         # Draw hz grid
         p.setPen(dashedPen)
-        p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
-        p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
-        p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
+        p.drawLine(QLineF(x2+1, mean_line_y, profile_width-2, mean_line_y ))
+        p.drawLine(QLineF(x2+1, line2_y, profile_width-2, line2_y ))
+        p.drawLine(QLineF(x2+1, line3_y, profile_width-2, line3_y ))
 
 
         # Draw bars
@@ -603,17 +603,17 @@ class ProfileFace(Face):
 
             # Draw bar border
             p.setPen(QColor("black"))
-            #p.drawRect(x1+2,mean_y1, x_alpha-3, profile_height-mean_y1+1)
+            #p.drawRect(QRectF(x1+2,mean_y1, x_alpha-3, profile_height-mean_y1+1))
             # Fill bar with custom color
-            p.fillRect(x1+3,profile_height-mean_y1, x_alpha-4, mean_y1-1, QBrush(customColor))
+            p.fillRect(QRectF(x1+3,profile_height-mean_y1, x_alpha-4, mean_y1-1), QBrush(customColor))
 
             # Draw error bars
             if dev1 != 0:
                 dev_up_y1   = int((mean1+dev1 - self.min_value) * y_alpha)
                 dev_down_y1 = int((mean1-dev1 - self.min_value) * y_alpha)
-                p.drawLine(x1+x_alpha/2, profile_height-dev_up_y1 ,x1+x_alpha/2, profile_height-dev_down_y1 )
-                p.drawLine(x1-1+x_alpha/2,  profile_height-dev_up_y1, x1+1+x_alpha/2, profile_height-dev_up_y1 )
-                p.drawLine(x1-1+x_alpha/2,  profile_height-dev_down_y1, x1+1+x_alpha/2, profile_height-dev_down_y1 )
+                p.drawLine(QLineF(1+x_alpha/2, profile_height-dev_up_y1 ,x1+x_alpha/2, profile_height-dev_down_y1 ))
+                p.drawLine(QLineF(x1-1+x_alpha/2,  profile_height-dev_up_y1, x1+1+x_alpha/2, profile_height-dev_up_y1 ))
+                p.drawLine(QLineF(x1-1+x_alpha/2,  profile_height-dev_down_y1, x1+1+x_alpha/2, profile_height-dev_down_y1 ))
 
     def draw_centered_bar_profile(self):
         # Calculate vector
@@ -649,20 +649,20 @@ class ProfileFace(Face):
 
         # Draw axis and scale
         p.setPen(QColor("black"))
-        p.drawRect(x2,y,profile_width, profile_height-1)
+        p.drawRect(QRectF(x2,y,profile_width), profile_height-1)
         p.setFont(QFont("Verdana",8))
-        p.drawText(profile_width,y+10,"%0.3f" %self.max_value)
-        p.drawText(profile_width,y+profile_height,"%0.3f" %self.min_value)
-        p.drawText(profile_width,mean_line_y,"%0.3f" %self.center_v)
+        p.drawText(QPointF(profile_width,y+10), "%0.3f" %self.max_value)
+        p.drawText(QPointF(profile_width,y+profile_height), "%0.3f" %self.min_value)
+        p.drawText(QPointF(profile_width,mean_line_y), "%0.3f" %self.center_v)
 
         dashedPen = QPen(QBrush(QColor("#ddd")), 0)
         dashedPen.setStyle(Qt.DashLine)
 
         # Draw hz grid
         p.setPen(dashedPen)
-        p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
-        p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
-        p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
+        p.drawLine(QLineF(x2+1, mean_line_y, profile_width-2, mean_line_y ))
+        p.drawLine(QLineF(x2+1, line2_y, profile_width-2, line2_y ))
+        p.drawLine(QLineF(x2+1, line3_y, profile_width-2, line3_y ))
 
 
         # Draw bars
@@ -704,24 +704,24 @@ class ProfileFace(Face):
             #p.drawRect(x1+2,mean_y1, x_alpha-3, profile_height-mean_y1+1)
             # Fill bar with custom color
             if mean1<self.center_v:
-                p.fillRect(x1+3, mean_line_y, x_alpha-4, mean_y1, QBrush(customColor))
+                p.fillRect(QRectF(x1+3, mean_line_y, x_alpha-4, mean_y1), QBrush(customColor))
             else:
-                p.fillRect(x1+3, mean_line_y-mean_y1, x_alpha-4, mean_y1+1, QBrush(customColor))
+                p.fillRect(QRectF(x1+3, mean_line_y-mean_y1, x_alpha-4, mean_y1+1), QBrush(customColor))
 
             # Draw error bars
             if dev1 != 0:
                 if mean1<self.center_v:
                     dev_up_y1   = int((mean1+dev1 - self.center_v) * y_alpha_down)
                     dev_down_y1 = int((mean1-dev1 - self.center_v) * y_alpha_down)
-                    p.drawLine(x1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+x_alpha/2, mean_line_y+dev_down_y1 )
-                    p.drawLine(x1-1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+1+x_alpha/2, mean_line_y+dev_up_y1 )
-                    p.drawLine(x1-1+x_alpha/2, mean_line_y+dev_down_y1 ,x1+1+x_alpha/2, mean_line_y+dev_down_y1 )
+                    p.drawLine(QLineF(x1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+x_alpha/2, mean_line_y+dev_down_y1 ))
+                    p.drawLine(QLineF(x1-1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+1+x_alpha/2, mean_line_y+dev_up_y1 ))
+                    p.drawLine(QLineF(x1-1+x_alpha/2, mean_line_y+dev_down_y1 ,x1+1+x_alpha/2, mean_line_y+dev_down_y1 ))
                 else:
                     dev_up_y1   = int((mean1+dev1 - self.center_v) * y_alpha_up)
                     dev_down_y1 = int((mean1-dev1 - self.center_v) * y_alpha_up)
-                    p.drawLine(x1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+x_alpha/2, mean_line_y-dev_down_y1 )
-                    p.drawLine(x1-1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+1+x_alpha/2, mean_line_y-dev_up_y1 )
-                    p.drawLine(x1-1+x_alpha/2, mean_line_y-dev_down_y1 ,x1+1+x_alpha/2, mean_line_y-dev_down_y1 )
+                    p.drawLine(QLineF(x1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+x_alpha/2, mean_line_y-dev_down_y1 ))
+                    p.drawLine(QLineF(x1-1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+1+x_alpha/2, mean_line_y-dev_up_y1 ))
+                    p.drawLine(QLineF(x1-1+x_alpha/2, mean_line_y-dev_down_y1 ,x1+1+x_alpha/2, mean_line_y-dev_down_y1 ))
 
     def draw_line_profile(self):
         # Calculate vector
@@ -754,20 +754,20 @@ class ProfileFace(Face):
 
         # Draw axis and scale
         p.setPen(QColor("black"))
-        p.drawRect(x2,y,profile_width, profile_height-1)
+        p.drawRect(QRectF(x2,y,profile_width, profile_height-1))
         p.setFont(QFont("Verdana",8))
-        p.drawText(profile_width,y+10,"%0.3f" %self.max_value)
-        p.drawText(profile_width,y+profile_height,"%0.3f" %self.min_value)
-        p.drawText(profile_width,mean_line_y+5,"%0.3f" %self.center_v)
+        p.drawText(QPointF(profile_width,y+10), "%0.3f" %self.max_value)
+        p.drawText(QPointF(profile_width,y+profile_height), "%0.3f" %self.min_value)
+        p.drawText(QPointF(profile_width,mean_line_y+5), "%0.3f" %self.center_v)
 
         dashedPen = QPen(QBrush(QColor("#ddd")), 0)
         dashedPen.setStyle(Qt.DashLine)
 
         # Draw hz grid
         p.setPen(dashedPen)
-        p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
-        p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
-        p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
+        p.drawLine(QLineF(x2+1, mean_line_y, profile_width-2, mean_line_y ))
+        p.drawLine(QLineF(x2+1, line2_y, profile_width-2, line2_y ))
+        p.drawLine(QLineF(x2+1, line3_y, profile_width-2, line3_y ))
 
         # Draw lines
         for pos in range(0,vlength-1):
@@ -782,7 +782,7 @@ class ProfileFace(Face):
             # Draw vt grid
             if x2 < profile_width:
                 p.setPen(dashedPen)
-                p.drawLine(x2, y+1, x2, profile_height-2)
+                p.drawLine(QLineF(x2, y+1, x2, profile_height-2))
 
             # If nan values, continue
             if not isfinite(mean1) or not isfinite(mean2):
@@ -799,11 +799,11 @@ class ProfileFace(Face):
                 dev_y2   = (dev2 - self.min_value) * y_alpha
                 # Draw red deviation lines
                 p.setPen(QColor("red"))
-                p.drawLine(x1, profile_height-dev_y1, x2, profile_height-dev_y2)
-                p.drawLine(x1, profile_height+dev_y1, x2, profile_height+dev_y2)
+                p.drawLine(QLineF(x1, profile_height-dev_y1, x2, profile_height-dev_y2))
+                p.drawLine(QLineF(x1, profile_height+dev_y1, x2, profile_height+dev_y2))
             # Draw blue mean line
             p.setPen(QColor("blue"))
-            p.drawLine(x1, profile_height-mean_y1, x2, profile_height-mean_y2)
+            p.drawLine(QLineF(x1, profile_height-mean_y1, x2, profile_height-mean_y2))
 
 
     def draw_heatmap_profile(self):
@@ -857,11 +857,11 @@ class ProfileFace(Face):
                     customColor = colors[100]
 
                 # Fill bar with custom color
-                p.fillRect(x1, y, x_alpha, y_step, QBrush(customColor))
+                p.fillRect(QRectF(x1, y, x_alpha, y_step), QBrush(customColor))
             y+= y_step
             x2 = 0
         p.end()
-        
+
     def fit_to_scale(self,v):
         if v<self.min_value:
             return float(self.min_value)
@@ -944,8 +944,8 @@ class OLD_SequenceFace(Face):
                 letter_pen = QPen(QColor(self.aafg.get(letter,"black" )))
 
             p.setPen(letter_pen)
-            p.fillRect(x,0,width, height,letter_brush)
-            p.drawText(x, y, letter)
+            p.fillRect(QRectF(x,0,width, height,letter_brush))
+            p.drawText(QPointF(x, y), letter)
             x += float(width)/len(self.seq)
         p.end()
 
@@ -1225,7 +1225,7 @@ class _PieChartItem(QGraphicsRectItem):
             col = self.colors[i]
             painter.setBrush(QBrush(QColor(col)))
             angle_span = (p/100.) * a
-            painter.drawPie(self.rect(), angle_start, angle_span )
+            painter.drawPie(self.rect(), int(angle_start), int(angle_span) )
             angle_start += angle_span
 
 
@@ -1478,26 +1478,26 @@ class _BarChartItem(QGraphicsRectItem):
 
         if self.draw_border:
             p.setPen(QColor("black"))
-            p.drawRect(x, y + 1, plot_width, plot_height)
+            p.drawRect(QRectF(x, y + 1, plot_width, plot_height))
 
         if self.draw_scale:
             p.setFont(QFont("Verdana", self.scale_fsize))
             font_height = QFontMetrics(p.font()).height()
             max_string = "% 7.2f" %max_value
             min_string = "% 7.2f" %min_value
-            p.drawText(plot_width + margin, font_height-2, max_string)
-            p.drawText(plot_width + margin, plot_height - 2, min_string)
-            p.drawLine(plot_width + margin - 1, 1, plot_width + margin - 1, plot_height+1)
-            p.drawLine(plot_width + margin - 1, 1, plot_width + margin + 2, 1)
-            p.drawLine(plot_width + margin - 1, plot_height+1, plot_width + margin + 2, plot_height+1)
+            p.drawText(QPointF(plot_width + margin, font_height-2), max_string)
+            p.drawText(QPointF(plot_width + margin, plot_height - 2), min_string)
+            p.drawLine(QLineF(plot_width + margin - 1, 1, plot_width + margin - 1, plot_height+1))
+            p.drawLine(QLineF(plot_width + margin - 1, 1, plot_width + margin + 2, 1))
+            p.drawLine(QLineF(plot_width + margin - 1, plot_height+1, plot_width + margin + 2, plot_height+1))
 
         if self.draw_grid:
             dashedPen = QPen(QBrush(QColor("#ddd")), 0)
             dashedPen.setStyle(Qt.DashLine)
             p.setPen(dashedPen)
-            p.drawLine(x+1, mean_line_y, plot_width - 2, mean_line_y)
-            p.drawLine(x+1, line2_y, plot_width - 2, line2_y )
-            p.drawLine(x+1, line3_y, plot_width - 2, line3_y )
+            p.drawLineQLineF((x+1, mean_line_y, plot_width - 2, mean_line_y))
+            p.drawLine(QLineF(x+1, line2_y, plot_width - 2, line2_y ))
+            p.drawLine(QLineF(x+1, line3_y, plot_width - 2, line3_y ))
 
         # Draw bars
         p.setFont(QFont("Verdana", self.label_fsize))
@@ -1515,8 +1515,8 @@ class _BarChartItem(QGraphicsRectItem):
                 p.save()
                 p.translate(x1, plot_height+2)
                 p.rotate(90)
-                p.drawText(0, -x_alpha, label_height, x_alpha, Qt.AlignVCenter, str(self.labels[pos]))
-                #p.drawRect(0, -x_alpha, label_height, x_alpha)
+                p.drawText(QRectF(0, -x_alpha, label_height, x_alpha), Qt.AlignVCenter, str(self.labels[pos]))
+                #p.drawRect(QRectF(0, -x_alpha, label_height, x_alpha))
                 p.restore()
 
             # If nan value, skip
@@ -1530,16 +1530,16 @@ class _BarChartItem(QGraphicsRectItem):
             p.setPen(QColor("black"))
 
             # Fill bar with custom color
-            p.fillRect(x1, height - mean_y1, x_alpha, mean_y1, QBrush(color))
+            p.fillRect(QRectF(x1, height - mean_y1, x_alpha, mean_y1), QBrush(color))
 
             # Draw error bars
             if std != 0:
                 dev_up_y1   = int((val + std - min_value) * y_alpha)
                 dev_down_y1 = int((val - std - min_value) * y_alpha)
                 center_x = x1 + (x_alpha / 2)
-                p.drawLine(center_x, plot_height - dev_up_y1, center_x, plot_height - dev_down_y1)
-                p.drawLine(center_x + 1, plot_height - dev_up_y1, center_x -1, plot_height - dev_up_y1)
-                p.drawLine(center_x + 1, plot_height - dev_down_y1, center_x -1, plot_height - dev_down_y1)
+                p.drawLine(QLineF(center_x, plot_height - dev_up_y1, center_x, plot_height - dev_down_y1))
+                p.drawLine(QLineF(center_x + 1, plot_height - dev_up_y1, center_x -1, plot_height - dev_up_y1))
+                p.drawLine(QLineF(center_x + 1, plot_height - dev_down_y1, center_x -1, plot_height - dev_down_y1))
 
 
 
@@ -1617,20 +1617,20 @@ class SequenceItem(QGraphicsRectItem):
                 if self.draw_text and self.poswidth >= 8:
                     br = QBrush(QColor(self.bg.get(letter, "white")))
                     p.setPen(blackPen)
-                    p.fillRect(x, 0, self.poswidth, self.posheight, br)
+                    p.fillRect(QRectF(x, 0, self.poswidth, self.posheight), br)
                     qfont.setPixelSize(min(self.posheight, self.poswidth))
                     p.setFont(qfont)
                     p.setBrush(QBrush(QColor("black")))
-                    p.drawText(x, 0, self.poswidth, self.posheight,
+                    p.drawText(QRectF(x, 0, self.poswidth, self.posheight),
                                Qt.AlignCenter |  Qt.AlignVCenter,
                                letter)
                 elif letter == "-" or letter == ".":
                     p.setPen(blackPen)
-                    p.drawLine(x, self.posheight/2, x+self.poswidth, self.posheight/2)
+                    p.drawLine(QLineF(x, self.posheight/2, x+self.poswidth, self.posheight/2))
 
                 else:
                     br = QBrush(QColor(self.bg.get(letter, "white")))
-                    p.fillRect(x, 0, max(1, self.poswidth), self.posheight, br)
+                    p.fillRect(QRectF(x, 0, max(1, self.poswidth), self.posheight), br)
                     #p.setPen(QPen(QColor(self.bg.get(letter, "black"))))
                     #p.drawLine(x, 0, x, self.posheight)
                 current_pixel = int(x)
@@ -2420,3 +2420,68 @@ class DiamondFace(StaticItemFace, Face):
     def _height(self):
         return self.height
 
+
+class ArrowFace(Face):
+
+    """
+
+    Creates a color-stripped arrow representation for synteny visualization
+
+    :param width: width of the arrow (min of 10)
+    :param height: height of arrow (min of 10)
+    :param strand: defines gene orientation. "-" entails left-oriented arrows
+                   while "+" strand right-oriented arrows.
+    :param colors: array containing values to color stripes
+
+    """
+
+    def __init__(self, width, height, strand, colors):
+        Face.__init__(self)
+        self.width = width
+        self.height = height
+        self.strand = strand
+        self.colors = colors
+
+    def _width(self):
+        return self.width
+
+    def _height(self):
+        return self.height
+
+    def update_items(self):
+        return
+
+    def update_pixmap(self):
+        # Create pixmap
+        self.pixmap = QPixmap(self.width, self.height)
+        self.pixmap.fill(QColor("white"))
+        p = QPainter(self.pixmap)
+
+        # Create pen
+        solidPen = QPen(QBrush(QColor("black")), 0)
+        solidPen.setStyle(Qt.SolidLine)
+        p.setPen(solidPen)
+
+        # Define bands width and arrow height taking padding into account
+        rect_w = (self.width - 10) / len(self.colors)
+        rect_h = self.height - 10
+
+        # Draw each of the color bands and the arrow pointer depending on the
+        # strand (+,right/-,left)
+        for i, color in enumerate(self.colors):
+            if self.strand == "+":
+                p.fillRect(3 + i*rect_w, 5, math.ceil(rect_w), rect_h, QColor(color))
+                if i == (len(self.colors) - 1):
+                    path = QPainterPath()
+                    path.moveTo(3+(i+1)*rect_w, 5)
+                    path.lineTo(7+(i+1)*rect_w, 5+rect_h / 2)
+                    path.lineTo(3+(i+1)*rect_w, 5+rect_h)
+                    p.fillPath(path, QColor(color))
+            elif self.strand == "-":
+                p.fillRect(7 + i*rect_w, 5, math.ceil(rect_w), rect_h, QColor(color))
+                if i == 0:
+                    path = QPainterPath()
+                    path.moveTo(7, 5)
+                    path.lineTo(3, 5+rect_h / 2)
+                    path.lineTo(7, 5+rect_h)
+                    p.fillPath(path, QColor(color))


=====================================
ete3/treeview/main.py
=====================================
@@ -407,7 +407,7 @@ class TreeStyle(object):
 
         for ly in layout:
             # Validates layout function
-            if (type(ly) == types.FunctionType or type(ly) == types.MethodType or ly is None):
+            if callable(ly) is True or ly is None:
                 self._layout_handler.append(ly)
             else:
                 from . import layouts
@@ -682,7 +682,7 @@ def save(scene, imgName, w=None, h=None, dpi=90,\
     if ext == "SVG":
         svg = QSvgGenerator()
         targetRect = QRectF(0, 0, w, h)
-        svg.setSize(QSize(w, h))
+        svg.setSize(QSize(int(w), int(h)))
         svg.setViewBox(targetRect)
         svg.setTitle("Generated with ETE http://etetoolkit.org")
         svg.setDescription("Generated with ETE http://etetoolkit.org")
@@ -703,7 +703,9 @@ def save(scene, imgName, w=None, h=None, dpi=90,\
             compatible_code = str(ba)
             print('from memory')
         else:
-            compatible_code = open(imgName).read()
+            with open(imgName) as f:
+                compatible_code = f.read()
+            
         # Fix a very annoying problem with Radial gradients in
         # inkscape and browsers...
         compatible_code = compatible_code.replace("xml:id=", "id=")
@@ -718,8 +720,8 @@ def save(scene, imgName, w=None, h=None, dpi=90,\
         elif imgName == '%%return':
             return x_scale, y_scale, compatible_code
         else:
-            open(imgName, "w").write(compatible_code)
-
+            with open(imgName, "w") as f:
+                f.write(compatible_code)
 
     elif ext == "PDF" or ext == "PS":
         if ext == "PS":
@@ -749,10 +751,10 @@ def save(scene, imgName, w=None, h=None, dpi=90,\
         scene.render(pp, targetRect, scene.sceneRect(), ratio_mode)
     else:
         targetRect = QRectF(0, 0, w, h)
-        ii= QImage(w, h, QImage.Format_ARGB32)
+        ii= QImage(int(w), int(h), QImage.Format_ARGB32)
         ii.fill(QColor(Qt.white).rgb())
-        ii.setDotsPerMeterX(dpi / 0.0254) # Convert inches to meters
-        ii.setDotsPerMeterY(dpi / 0.0254)
+        ii.setDotsPerMeterX(int(dpi / 0.0254)) # Convert inches to meters
+        ii.setDotsPerMeterY(int(dpi / 0.0254))
         pp = QPainter(ii)
         pp.setRenderHint(QPainter.Antialiasing)
         pp.setRenderHint(QPainter.TextAntialiasing)


=====================================
ete3/treeview/qt.py
=====================================
@@ -1,6 +1,6 @@
 try:
     from PyQt4 import QtGui, QtCore
-    from PyQt4.QtCore import (Qt, QPointF, QRect, QRectF, QBuffer, QByteArray,
+    from PyQt4.QtCore import (Qt, QPointF, QRect, QLineF, QRectF, QBuffer, QByteArray,
                               QThread, QIODevice, QMetaObject, QModelIndex, QObject, QRegExp, QSize,
                               QSizeF,QVariant )
     from PyQt4.QtGui import (QAction, QApplication, QBrush, QCheckBox, QColor,
@@ -25,7 +25,13 @@ try:
 
 except ImportError:
     from PyQt5 import QtGui, QtCore
-    from PyQt5.QtCore import (Qt, QPointF, QRect, QRectF, QBuffer, QByteArray,
+
+    # Fixes incompatibilities due to new overflow checking when converting integers introduced in qt 5.12
+    # https://www.riverbankcomputing.com/static/Docs/PyQt5/incompatibilities.html#pyqt-v5-12
+    import sip
+    sip.enableoverflowchecking(False)
+
+    from PyQt5.QtCore import (Qt, QPointF, QLineF, QRect, QRectF, QBuffer, QByteArray,
                               QThread, QIODevice, QMetaObject, QModelIndex, QObject, QRegExp, QSize,
                               QSizeF,  QVariant) #QString
     from PyQt5.QtSvg import QGraphicsSvgItem, QSvgGenerator


=====================================
ete3/treeview/qt4_face_render.py
=====================================
@@ -248,7 +248,7 @@ class _FaceGroupItem(QGraphicsRectItem): # I was about to name this FaceBookItem
                     elif f.vt_align == 1:
                         # Vertically centered
                         y_offset = (max_h - h) / 2
-                    elif f.hz_align == 2:
+                    elif f.vt_align == 2:
                         # Vertically at bottom
                         y_offset = (max_h - h)
 


=====================================
ete3/treeview/qt4_gui.py
=====================================
@@ -72,17 +72,12 @@ class _SelectorItem(QGraphicsRectItem):
     def paint(self, p, option, widget):
         p.setPen(self.Color)
         p.setBrush(QBrush(Qt.NoBrush))
-        p.drawRect(self.rect().x(),self.rect().y(),self.rect().width(),self.rect().height())
+        p.drawRect(QRectF(self.rect().x(),self.rect().y(),self.rect().width(),self.rect().height()))
         return
         # Draw info text
         font = QFont("Arial",13)
         text = "%d selected."  % len(self.get_selected_nodes())
         textR = QFontMetrics(font).boundingRect(text)
-        if  self.rect().width() > textR.width() and \
-                self.rect().height() > textR.height()/2 and 0: # OJO !!!!
-            p.setPen(QPen(self.Color))
-            p.setFont(QFont("Arial",13))
-            p.drawText(self.rect().bottomLeft().x(),self.rect().bottomLeft().y(),text)
 
     def get_selected_nodes(self):
         selPath = QPainterPath()
@@ -169,7 +164,7 @@ class _GUI(QMainWindow):
         # Shows the whole tree by default
         #self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
         splitter.setCollapsible(1, True)
-        splitter.setSizes([self.scene.sceneRect().width(), 10])
+        splitter.setSizes([int(self.scene.sceneRect().width()), 10])
 
         self.view.fitInView(0, 0, self.scene.sceneRect().width(), 200, Qt.KeepAspectRatio)
 


=====================================
ete3/version.py
=====================================
@@ -1,2 +1,2 @@
 #autogenerated during release process. Do not modify
-__version__='3.1.2'
+__version__='3.1.3'


=====================================
setup.py
=====================================
@@ -18,42 +18,12 @@ except ImportError:
     from urllib.request import urlopen
     from urllib.error import HTTPError
 
-HERE = os.path.abspath(os.path.split(os.path.realpath(__file__))[0])
-
-if "--donottrackinstall" in sys.argv:
-    TRACKINSTALL = None
-    sys.argv.remove("--donottrackinstall")
-else:
-    # Avoids importing self module
-    orig_path = list(sys.path)
-    _wd = os.getcwd()
-    try:
-        sys.path.remove(_wd)
-    except ValueError:
-        pass
-    try:
-        sys.path.remove("")
-    except ValueError:
-        pass
-
-    # Is this and upgrade or a new install?
-    try:
-        import ete3
-    except ImportError:
-        TRACKINSTALL = "ete-new-installation"
-    else:
-        TRACKINSTALL = "ete-upgrade"
-
-    sys.path = orig_path
-
-
 try:
     from setuptools import setup, find_packages
 except ImportError:
     ez_setup.use_setuptools()
     from setuptools import setup, find_packages
 
-
 PYTHON_DEPENDENCIES = [
     ["numpy", "Numpy is required for the ArrayTable and ClusterTree classes.", 0],
     ["PyQt", "PyQt4/5 is required for tree visualization and image rendering.", 0],
@@ -78,40 +48,14 @@ CLASSIFIERS= [
     "Topic :: Software Development :: Libraries :: Python Modules",
     ]
 
-def can_import(mname):
-    'Test if a module can be imported '
-    if mname == "PyQt":
-        try:
-            __import__("PyQt4.QtCore")
-            __import__("PyQt4.QtGui")
-        except ImportError:
-            try:
-                __import__("PyQt5.QtCore")
-                __import__("PyQt5.QtGui")
-            except ImportError:
-                return False
-            else:
-                return True
-        else:
-            return True
-    else:
-        try:
-            __import__(mname)
-        except ImportError:
-            return False
-        else:
-            return True
+
+HERE = os.path.abspath(os.path.split(os.path.realpath(__file__))[0])
 
 try:
     ETE_VERSION = open(os.path.join(HERE, "VERSION")).readline().strip()
 except IOError:
     ETE_VERSION = 'unknown'
 
-print("\nInstalling ETE (%s) \n" %ETE_VERSION)
-print()
-
-
-    
 MOD_NAME = "ete3"
 
 LONG_DESCRIPTION="""
@@ -133,8 +77,8 @@ please cite:
 Visit http://etetoolkit.org for more info.
 """
 
-try:
-    _s = setup(
+
+_s = setup(
         include_package_data = True,
 
         name = MOD_NAME,
@@ -167,31 +111,10 @@ try:
         provides = [MOD_NAME],
         keywords = "tree, tree reconstruction, tree visualization, tree comparison, phylogeny, phylogenetics, phylogenomics",
         url = "http://etetoolkit.org",
+        project_urls = {
+            "Documentation": "http://etetoolkit.org/docs/latest/tutorial/index.html",
+            "Source": "https://github.com/etetoolkit/ete",
+        },
         download_url = "http://etetoolkit.org/static/releases/ete3/",
 
-    )
-
-except:
-    print("\033[91m - Errors found! - \033[0m")
-    raise
-
-else:
-
-    print("\033[92m - Done! - \033[0m")
-    missing = False
-    for mname, msg, ex in PYTHON_DEPENDENCIES:
-        if not can_import(mname):
-            print(" Warning:\033[93m Optional library [%s] could not be found \033[0m" %mname)
-            print("  ",msg)
-            missing=True
-
-    notwanted = set(["-h", "--help", "-n", "--dry-run"])
-    seen = set(_s.script_args)
-    wanted = set(["install", "bdist", "bdist_egg"])
-    if TRACKINSTALL is not None and (wanted & seen) and not (notwanted & seen):
-        try:
-            welcome = quote("New alien in earth! (%s %s)" %(TRACKINSTALL, time.ctime()))
-            urlopen("http://etetoolkit.org/static/et_phone_home.php?ID=%s&VERSION=%s&MSG=%s"
-                            %(TRACKINSTALL, ETE_VERSION, welcome))
-        except Exception:
-            pass
+)



View it on GitLab: https://salsa.debian.org/med-team/python-ete3/-/compare/1ccb7a3fe282c6a5b8d538cc54d8cd6d9f574929...fe52ec8644b7dec36539cf763370fea3f9be8ed3

-- 
View it on GitLab: https://salsa.debian.org/med-team/python-ete3/-/compare/1ccb7a3fe282c6a5b8d538cc54d8cd6d9f574929...fe52ec8644b7dec36539cf763370fea3f9be8ed3
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20231115/7951962d/attachment-0001.htm>


More information about the debian-med-commit mailing list