[med-svn] [Git][med-team/libsonlib][master] 3 commits: Build against libquicktree-dev

Andreas Tille gitlab at salsa.debian.org
Tue Jun 16 10:43:17 BST 2020



Andreas Tille pushed to branch master at Debian Med / libsonlib


Commits:
afd7c23c by Andreas Tille at 2020-06-16T10:41:48+02:00
Build against libquicktree-dev

- - - - -
d9c8af35 by Andreas Tille at 2020-06-16T11:36:03+02:00
Try really hard to get tests run

- - - - -
e02ce9f8 by Andreas Tille at 2020-06-16T11:43:02+02:00
Build-Depends: tokyocabinet

- - - - -


8 changed files:

- + debian/README.Debian
- + debian/clean
- debian/control
- + debian/patches/2to3.patch
- + debian/patches/fix_test.patch
- debian/patches/series
- debian/patches/use_debian_packaged_quicktree.patch
- debian/rules


Changes:

=====================================
debian/README.Debian
=====================================
@@ -0,0 +1,13 @@
+sonLib for Debian
+=================
+
+SonLib is originally shipped with a code copy of quicktree.  To avoid
+duplicated code the Debian package also builds a static library.  If you
+want to use sonLib in your code you need to add
+
+    CFLAGS += -I/usr/include/quicktree
+    LIBS += -lquicktree
+
+to build successfully.
+
+ -- Andreas Tille <tille at debian.org>  Tue, 16 Jun 2020 08:23:45 +0200


=====================================
debian/clean
=====================================
@@ -0,0 +1 @@
+sonLib_daemonize.py


=====================================
debian/control
=====================================
@@ -5,8 +5,12 @@ Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.
 Uploaders: Andreas Tille <tille at debian.org>
 Build-Depends: debhelper-compat (= 13),
                dh-python,
-               python3-all-dev,
+               python3,
                python3-setuptools,
+               libquicktree-dev,
+               zlib1g-dev,
+               libtokyocabinet-dev,
+               libbz2-dev
 Standards-Version: 4.5.0
 Vcs-Browser: https://salsa.debian.org/med-team/libsonlib
 Vcs-Git: https://salsa.debian.org/med-team/libsonlib.git
@@ -17,7 +21,7 @@ Section: libdevel
 Architecture: any
 Depends: ${shlibs:Depends},
          ${misc:Depends},
-         quicktree
+         libquicktree-dev
 Description: compact C/Python library for sequence analysis in bioinformatics
  SonLib is a small general purpose library for C and Python for sequence
  analysis with focus on bioinformatics.


=====================================
debian/patches/2to3.patch
=====================================
@@ -0,0 +1,848 @@
+--- a/C/Makefile
++++ b/C/Makefile
+@@ -65,4 +65,4 @@ ${libPath}/sonLib.a : ${libSources} ${cp
+ 	mv sonLib.a ${libPath}/
+ 
+ test:
+-	python allTests.py --testLength=SHORT --logLevel CRITICAL
++	python3 allTests.py --testLength=SHORT --logLevel CRITICAL
+--- a/Makefile
++++ b/Makefile
+@@ -21,7 +21,7 @@ externalToolsP.clean :
+ 	cd externalTools && make clean
+ 
+ test : all
+-	PYTHONPATH=.. PATH=../../bin:$$PATH python allTests.py --testLength=SHORT --logLevel=CRITICAL
++	PYTHONPATH=.. PATH=../../bin:$$PATH python3 allTests.py --testLength=SHORT --logLevel=CRITICAL
+ 
+ ${binPath}/sonLib_daemonize.py : sonLib_daemonize.py
+ 	cp sonLib_daemonize.py ${binPath}/sonLib_daemonize.py
+--- a/setup.py
++++ b/setup.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ from setuptools import setup, find_packages
+ #import subprocess
+--- a/src/sonLib/__init__.py
++++ b/src/sonLib/__init__.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+--- a/src/sonLib/bioio.py
++++ b/src/sonLib/bioio.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+@@ -421,14 +421,14 @@ def nameValue(name, value, valueType=str
+ def getRandomAlphaNumericString(length=10):
+     """Returns a random alpha numeric string of the given length.
+     """
+-    return "".join([ random.choice('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') for i in xrange(0, length) ])
++    return "".join([ random.choice('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') for i in range(0, length) ])
+ 
+ def makeSubDir(dirName):
+     """Makes a given subdirectory if it doesn't already exist, making sure it us public.
+     """
+     if not os.path.exists(dirName):
+         os.mkdir(dirName)
+-        os.chmod(dirName, 0777)
++        os.chmod(dirName, 0o777)
+     return dirName
+ 
+ def getTempFile(suffix="", rootDir=None):
+@@ -441,7 +441,7 @@ def getTempFile(suffix="", rootDir=None)
+     else:
+         tmpFile = os.path.join(rootDir, "tmp_" + getRandomAlphaNumericString() + suffix)
+         open(tmpFile, 'w').close()
+-        os.chmod(tmpFile, 0777) #Ensure everyone has access to the file.
++        os.chmod(tmpFile, 0o777) #Ensure everyone has access to the file.
+         return tmpFile
+ 
+ def getTempDirectory(rootDir=None):
+@@ -468,7 +468,7 @@ def getTempDirectory(rootDir=None):
+                 break
+                 
+         os.mkdir(tmpDir)
+-        os.chmod(tmpDir, 0777) #Ensure everyone has access to the file.
++        os.chmod(tmpDir, 0o777) #Ensure everyone has access to the file.
+         return tmpDir
+ 
+ class TempFileTree:
+@@ -744,7 +744,7 @@ def fastaWrite(fileHandleOrFile, name, s
+     fileHandle = _getFileHandle(fileHandleOrFile, mode)
+     valid_chars = {x for x in string.ascii_letters + "-"}
+     try:
+-        assert any([isinstance(seq, unicode), isinstance(seq, str)])
++        assert any([isinstance(seq, str), isinstance(seq, str)])
+     except AssertionError:
+         raise RuntimeError("Sequence is not unicode or string")
+     try:
+@@ -754,7 +754,7 @@ def fastaWrite(fileHandleOrFile, name, s
+         raise RuntimeError("Invalid FASTA character(s) see in fasta sequence: {}".format(bad_chars))
+     fileHandle.write(">%s\n" % name)
+     chunkSize = 100
+-    for i in xrange(0, len(seq), chunkSize):
++    for i in range(0, len(seq), chunkSize):
+         fileHandle.write("%s\n" % seq[i:i+chunkSize])
+     if isinstance(fileHandleOrFile, "".__class__):
+         fileHandle.close()
+@@ -849,23 +849,23 @@ def fastaAlignmentRead(fasta, mapFn=(lam
+     else:
+         l = l[:]
+     seqNo = len(l)
+-    for i in xrange(0, seqNo):
++    for i in range(0, seqNo):
+         j = open(fasta, 'r')
+         j.seek(l[i])
+         l[i] = j
+-    column = [sys.maxint]*seqNo
++    column = [sys.maxsize]*seqNo
+     if seqNo != 0:
+         while True:
+-            for j in xrange(0, seqNo):
++            for j in range(0, seqNo):
+                 i = l[j].read(1)
+                 while i == '\n':
+                     i = l[j].read(1)
+                 column[j] = i
+             if column[0] == '>' or column[0] == '':
+-                for j in xrange(1, seqNo):
++                for j in range(1, seqNo):
+                     assert column[j] == '>' or column[j] == ''
+                 break
+-            for j in xrange(1, seqNo):
++            for j in range(1, seqNo):
+                  assert column[j] != '>' and column[j] != ''
+                  column[j] = mapFn(column[j])
+             yield column[:]
+@@ -878,8 +878,8 @@ def fastaAlignmentWrite(columnAlignment,
+     Writes out column alignment to given file multi-fasta format
+     """
+     fastaFile = open(fastaFile, 'w')
+-    columnAlignment = [ i for i in columnAlignment if filter(i) ]
+-    for seq in xrange(0, seqNo):
++    columnAlignment = [ i for i in columnAlignment if list(filter(i)) ]
++    for seq in range(0, seqNo):
+         fastaFile.write(">%s\n" % names[seq])
+         for column in columnAlignment:
+             fastaFile.write(column[seq])
+@@ -890,10 +890,10 @@ def getRandomSequence(length=500):
+     """Generates a random name and sequence.
+     """
+     fastaHeader = ""
+-    for i in xrange(int(random.random()*100)):
++    for i in range(int(random.random()*100)):
+         fastaHeader = fastaHeader + random.choice([ 'A', 'C', '0', '9', ' ', '\t' ])
+     return (fastaHeader, \
+-            "".join([ random.choice([ 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'N' ]) for i in xrange((int)(random.random() * length))]))
++            "".join([ random.choice([ 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'A', 'C', 'T', 'G', 'N' ]) for i in range((int)(random.random() * length))]))
+ 
+ def _expLength(i=0, prob=0.95):
+     if random.random() >= prob:
+@@ -932,7 +932,7 @@ def reverseComplementChar(x):
+                         _reverseComplementDict else x
+ 
+ def reverseComplement(seq):
+-    return "".join(map(lambda x : reverseComplementChar(x), seq[::-1]))
++    return "".join([reverseComplementChar(x) for x in seq[::-1]])
+ 
+ #########################################################
+ #########################################################
+@@ -1044,9 +1044,9 @@ def pWMRead(fileHandle, alphabetSize=4):
+     for line in lines[1:]:
+         l2 = [ float(i) for i in line.split() ]
+         assert len(l) == len(l2)
+-        for i in xrange(0, len(l)):
++        for i in range(0, len(l)):
+             l[i].append(l2[i])
+-    for i in xrange(0, len(l)):
++    for i in range(0, len(l)):
+         j = sum(l[i]) + 0.0
+         l[i] = [ k/j for k in l[i] ]
+     return l
+@@ -1054,8 +1054,8 @@ def pWMRead(fileHandle, alphabetSize=4):
+ def pWMWrite(fileHandle, pWM, alphabetSize=4):
+     """Writes file in standard PWM format, is reverse of pWMParser
+     """
+-    for i in xrange(0, alphabetSize):
+-        fileHandle.write("%s\n" % ' '.join([ str(pWM[j][i]) for j in xrange(0, len(pWM)) ]))
++    for i in range(0, alphabetSize):
++        fileHandle.write("%s\n" % ' '.join([ str(pWM[j][i]) for j in range(0, len(pWM)) ]))
+ 
+ #########################################################
+ #########################################################
+@@ -1230,8 +1230,8 @@ def cigarWrite(fileHandle, pairwiseAlign
+ 
+ def _getRandomSegment():
+     contig = random.choice([ "one", "two", "three", "four" ])
+-    start = random.choice(xrange(0, 10000))
+-    end = start + random.choice(xrange(0, 1000))
++    start = random.choice(range(0, 10000))
++    end = start + random.choice(range(0, 1000))
+     strand = random.choice([ True, False ])
+     if not strand:
+         start, end = end, start
+@@ -1245,7 +1245,7 @@ def getRandomOperationList(xLength, yLen
+         if operationMaxLength == 1:
+             length = 1
+         else:
+-            length = random.choice(xrange(1, operationMaxLength))
++            length = random.choice(range(1, operationMaxLength))
+         if opType != PairwiseAlignment.PAIRWISE_INDEL_Y and xLength - length < 0:
+             continue
+         if opType != PairwiseAlignment.PAIRWISE_INDEL_X and yLength - length < 0:
+@@ -1263,7 +1263,7 @@ def getRandomPairwiseAlignment():
+     """
+     i, j, k, l = _getRandomSegment()
+     m, n, o, p = _getRandomSegment()
+-    score = random.choice(xrange(-1000, 1000))
++    score = random.choice(range(-1000, 1000))
+     return PairwiseAlignment(i, j, k, l, m, n, o, p, score, getRandomOperationList(abs(k - j), abs(o - n)))
+ 
+ #########################################################
+--- a/src/sonLib/misc.py
++++ b/src/sonLib/misc.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+--- a/src/sonLib/nxnewick.py
++++ b/src/sonLib/nxnewick.py
+@@ -1,9 +1,8 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Glenn Hickey
+ #
+ #Released under the MIT license, see LICENSE.txt
+-#!/usr/bin/env python
+ 
+ """read and write newick trees to and from networkx graphs (as wrapped by nxtree). 
+ """
+@@ -14,7 +13,7 @@ import math
+ import random
+ from string import whitespace as ws
+ from sonLib.misc import close
+-import bioio
++from . import bioio
+ import networkx as NX
+ from optparse import OptionParser
+ from sonLib.nxtree import NXTree
+@@ -187,15 +186,15 @@ def main():
+     parser.parseFile(args[0])
+     NX.drawing.nx_agraph.write_dot(parser.nxTree.nxDg, args[1])
+     parser.writeFile(args[2])
+-    print "PRE"
++    print("PRE")
+     for i in parser.nxTree.preOrderTraversal():
+-        print ("%d %s" % (i, parser.nxTree.getName(i)))
+-    print "POST"
++        print(("%d %s" % (i, parser.nxTree.getName(i))))
++    print("POST")
+     for i in parser.nxTree.postOrderTraversal():
+-        print ("%d %s" % (i, parser.nxTree.getName(i)))
+-    print "BFS"
++        print(("%d %s" % (i, parser.nxTree.getName(i))))
++    print("BFS")
+     for i in parser.nxTree.breadthFirstTraversal():
+-        print ("%d %s" % (i, parser.nxTree.getName(i)))
++        print(("%d %s" % (i, parser.nxTree.getName(i))))
+     return 0
+ 
+ if __name__ == '__main__':    
+--- a/src/sonLib/nxtree.py
++++ b/src/sonLib/nxtree.py
+@@ -1,9 +1,8 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Glenn Hickey
+ #
+ #Released under the MIT license, see LICENSE.txt
+-#!/usr/bin/env python
+ 
+ """A more general (ie arbitrary degree) tree to replace the BinaryTree
+ in sonLib.tree.py.  Implemented as a lightweight wrapper over a 
+--- a/src/sonLib/test/allTests.py
++++ b/src/sonLib/test/allTests.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+--- a/src/sonLib/test/bioioTest.py
++++ b/src/sonLib/test/bioioTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+@@ -61,12 +61,12 @@ class TestCase(unittest.TestCase):
+     #########################################################
+     
+     def testTempFileTree(self):
+-        for test in xrange(100): #self.testNo):
+-            levels = random.choice(xrange(1, 4))
+-            fileNo = random.choice(xrange(1, 6))
++        for test in range(100): #self.testNo):
++            levels = random.choice(range(1, 4))
++            fileNo = random.choice(range(1, 6))
+             maxTempFiles = int(math.pow(fileNo, levels))
+             
+-            print "Got %s levels, %s fileNo and %s maxTempFiles" % (levels, fileNo, maxTempFiles)
++            print("Got %s levels, %s fileNo and %s maxTempFiles" % (levels, fileNo, maxTempFiles))
+             
+             tempFileTreeRootDir = os.path.join(self.tempDir, getRandomAlphaNumericString())
+             tempFileTree = TempFileTree(tempFileTreeRootDir, fileNo, levels)
+@@ -74,7 +74,7 @@ class TestCase(unittest.TestCase):
+             tempFiles = []
+             tempDirs = []
+             #Check we can mac number of temp files.
+-            for i in xrange(maxTempFiles):
++            for i in range(maxTempFiles):
+                 if random.random() > 0.5:
+                     tempFile = tempFileTree.getTempFile()
+                     assert os.path.isfile(tempFile)
+@@ -132,9 +132,9 @@ class TestCase(unittest.TestCase):
+     def testFastaReadWrite(self):
+         tempFile = getTempFile()
+         self.tempFiles.append(tempFile)
+-        for test in xrange(0, self.testNo):
+-            fastaNumber = random.choice(xrange(10))
+-            l = [ getRandomSequence() for i in xrange(fastaNumber) ]
++        for test in range(0, self.testNo):
++            fastaNumber = random.choice(range(10))
++            l = [ getRandomSequence() for i in range(fastaNumber) ]
+             fileHandle = open(tempFile, 'w')
+             for name, seq in l:
+                 fastaWrite(fileHandle, name, seq)
+@@ -150,9 +150,9 @@ class TestCase(unittest.TestCase):
+     def testFastqReadWrite(self):
+         tempFile = getTempFile()
+         self.tempFiles.append(tempFile)
+-        for test in xrange(0, self.testNo):
+-            fastaNumber = random.choice(xrange(10))
+-            fastqs = [ (name, seq, [ random.randint(33, 126) for i in range(len(seq)) ]) for name, seq in [ getRandomSequence() for i in xrange(fastaNumber) ]]
++        for test in range(0, self.testNo):
++            fastaNumber = random.choice(range(10))
++            fastqs = [ (name, seq, [ random.randint(33, 126) for i in range(len(seq)) ]) for name, seq in [ getRandomSequence() for i in range(fastaNumber) ]]
+             fH = open(tempFile, 'w')
+             for name, seq, quals in fastqs:
+                 fastqWrite(fH, name, seq, quals)
+@@ -170,9 +170,9 @@ class TestCase(unittest.TestCase):
+         self.tempFiles.append(tempFile)
+         tempFile2 = getTempFile()
+         self.tempFiles.append(tempFile2)
+-        for test in xrange(0, self.testNo):
+-            fastaNumber = random.choice(xrange(10))
+-            l = [ getRandomSequence() for i in xrange(fastaNumber) ]
++        for test in range(0, self.testNo):
++            fastaNumber = random.choice(range(10))
++            l = [ getRandomSequence() for i in range(fastaNumber) ]
+             fileHandle = open(tempFile, 'w')
+             for name, seq in l:
+                 fastaWrite(fileHandle, name, seq)
+@@ -180,7 +180,7 @@ class TestCase(unittest.TestCase):
+             
+             command = "sonLib_fastaCTest %s %s" % (tempFile, tempFile2)
+             
+-            print command
++            print(command)
+             
+             system(command)
+             
+@@ -205,12 +205,12 @@ class TestCase(unittest.TestCase):
+             d = '((human,baboon),chimp);'
+             e = newickTreeParser(d)
+             f = printBinaryTree(e, False)
+-            print d, f
++            print(d, f)
+             assert d == f
+     
+     def testNewickTreeParser_UnaryNodes(self):
+         #tests with unary nodes 
+-        for test in xrange(0, self.testNo):
++        for test in range(0, self.testNo):
+             tree = getRandomTreeString()
+             logger.debug("tree to try\t", tree)
+             tree2 = newickTreeParser(tree, reportUnaryNodes=True)
+@@ -229,7 +229,7 @@ class TestCase(unittest.TestCase):
+     def testPWMParser(self):
+         tempFile = getTempFile()
+         self.tempFiles.append(tempFile)
+-        for test in xrange(0, self.testNo):
++        for test in range(0, self.testNo):
+             pWM = getRandomPWM()
+             
+             fileHandle = open(tempFile, 'w')
+@@ -240,7 +240,7 @@ class TestCase(unittest.TestCase):
+             pWM2 = pWMRead(fileHandle)
+             fileHandle.close()
+             
+-            for i in xrange(0, len(pWM)):  
++            for i in range(0, len(pWM)):  
+                 pWM[i] == pWM2[i]
+     
+     #########################################################
+@@ -254,9 +254,9 @@ class TestCase(unittest.TestCase):
+     def testCigarReadWrite(self):
+         tempFile = getTempFile()
+         self.tempFiles.append(tempFile)
+-        for test in xrange(0, self.testNo):
+-            cigarNumber = random.choice(xrange(10))
+-            l = [ getRandomPairwiseAlignment() for i in xrange(cigarNumber) ]
++        for test in range(0, self.testNo):
++            cigarNumber = random.choice(range(10))
++            l = [ getRandomPairwiseAlignment() for i in range(cigarNumber) ]
+             fileHandle = open(tempFile, 'w')
+             for cigar in l:
+                 cigarWrite(fileHandle, cigar)
+@@ -292,10 +292,10 @@ def getRandomPWM(length=-1):
+     if length == -1:
+         length = 1 + int(random.random()*10)
+     def fn():
+-        l = [ random.random()*100 for i in xrange(0, 4) ]
++        l = [ random.random()*100 for i in range(0, 4) ]
+         i = sum(l)
+         return [ j/i for j in l ]
+-    return [ fn() for i in xrange(0, length) ]
++    return [ fn() for i in range(0, length) ]
+         
+ if __name__ == '__main__':
+     unittest.main()
+--- a/src/sonLib/test/cigarsTest.py
++++ b/src/sonLib/test/cigarsTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+@@ -36,9 +36,9 @@ class TestCase(unittest.TestCase):
+         """
+         tempFile = getTempFile()
+         self.tempFiles.append(tempFile)
+-        for test in xrange(0, self.testNo):
+-            pairwiseAlignmentNumber = random.choice(xrange(10))
+-            l = [ getRandomPairwiseAlignment() for i in xrange(pairwiseAlignmentNumber) ]
++        for test in range(0, self.testNo):
++            pairwiseAlignmentNumber = random.choice(range(10))
++            l = [ getRandomPairwiseAlignment() for i in range(pairwiseAlignmentNumber) ]
+             fileHandle = open(tempFile, 'w')
+             
+             keepProbs = random.random() > 0.5
+--- a/src/sonLib/test/kvdbTest.py
++++ b/src/sonLib/test/kvdbTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+--- a/src/sonLib/test/nxnewickTest.py
++++ b/src/sonLib/test/nxnewickTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 011 by Glenn Hickey
+ #
+--- a/src/sonLib/test/nxtreeTest.py
++++ b/src/sonLib/test/nxtreeTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 011 by Glenn Hickey
+ #
+--- a/src/sonLib/test/sonLib_daemonize.py
++++ b/src/sonLib/test/sonLib_daemonize.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ # Glenn Hickey 2011
+ #
+@@ -66,7 +66,7 @@ else:
+    
+ if __name__ == '__main__':
+     if len(sys.argv) != 2:
+-        raise Exception, "%s: Wrong number of arguments" % sys.argv[0]
++        raise Exception("%s: Wrong number of arguments" % sys.argv[0])
+     
+     pid = os.fork()
+     if pid > 0:
+--- a/src/sonLib/test/treeTest.py
++++ b/src/sonLib/test/treeTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+@@ -29,29 +29,29 @@ class TestCase(unittest.TestCase):
+         unittest.TestCase.tearDown(self)
+         
+     def testRemodelTreeRemovingRoot(self):
+-        for test in xrange(0, self.testNo):
++        for test in range(0, self.testNo):
+             binaryTree = getRandomTree()
+             binaryTree_depthFirstNumbers(binaryTree) 
+             node = getRandomLeafNode(binaryTree)
+             remodTree = remodelTreeRemovingRoot(binaryTree, node.traversalID.mid)
+-            print "test", test, printBinaryTree(binaryTree, True), printBinaryTree(node, True), printBinaryTree(remodTree, True)
++            print("test", test, printBinaryTree(binaryTree, True), printBinaryTree(node, True), printBinaryTree(remodTree, True))
+             binaryTree_depthFirstNumbers(remodTree)
+             distances = mapTraversalIDsBetweenTrees(binaryTree, remodTree)
+             d = getDistancesBetweenLeaves(binaryTree)
+             d2 = getDistancesBetweenLeaves(remodTree)
+-            print d
+-            print d2
++            print(d)
++            print(d2)
+             for key in d2:
+                 assert close(d2[key], d[key], 0.0001)
+                 
+     def testMoveRoot(self):
+-        for test in xrange(0, self.testNo):
++        for test in range(0, self.testNo):
+             binaryTree = getRandomTree()
+             binaryTree_depthFirstNumbers(binaryTree)
+             node = getRandomNode(binaryTree)
+-            print "before", printBinaryTree(binaryTree, True), printBinaryTree(node, True)
++            print("before", printBinaryTree(binaryTree, True), printBinaryTree(node, True))
+             remodTree = moveRoot(binaryTree, node.traversalID.mid)
+-            print "test", test, printBinaryTree(binaryTree, True), printBinaryTree(node, True), printBinaryTree(remodTree, True)
++            print("test", test, printBinaryTree(binaryTree, True), printBinaryTree(node, True), printBinaryTree(remodTree, True))
+             binaryTree_depthFirstNumbers(remodTree)
+             #distances = mapTraversalIDsBetweenTrees(binaryTree, remodTree)
+             #d = getDistancesBetweenLeaves(binaryTree)
+@@ -62,7 +62,7 @@ class TestCase(unittest.TestCase):
+             #    assert close(d2[key], d[key], 0.0001)
+     
+     def testCalculateDupsAndLossesByReconcilingTrees(self):
+-        for test in xrange(0, self.testNo):
++        for test in range(0, self.testNo):
+             speciesTree = getRandomTree()
+             binaryTree_depthFirstNumbers(speciesTree)
+             geneTree = getRandomTree()
+@@ -102,13 +102,13 @@ class TestCase(unittest.TestCase):
+         geneStrings = [ geneString1, geneString2, geneString3, geneString4, \
+                         geneString5, geneString6, geneString7, geneString8,
+                         geneString9, geneString10, geneString11 ]
+-        print ""
++        print("")
+         for geneString, dupCount, lossCount in geneStrings:
+             geneTree = newickTreeParser(geneString)
+             binaryTree_depthFirstNumbers(geneTree)
+-            print printBinaryTree(geneTree, True), printBinaryTree(speciesTree, True)
++            print(printBinaryTree(geneTree, True), printBinaryTree(speciesTree, True))
+             dupCount2, lossCount2 = calculateDupsAndLossesByReconcilingTrees(speciesTree, geneTree, processID=lambda x : x)
+-            print geneString, "dups", dupCount, dupCount2, "losses", lossCount, lossCount2
++            print(geneString, "dups", dupCount, dupCount2, "losses", lossCount, lossCount2)
+             assert dupCount == dupCount2
+             assert lossCount == lossCount2
+             
+@@ -144,11 +144,11 @@ class TestCase(unittest.TestCase):
+             rootedGeneTree = newickTreeParser(geneString)
+             binaryTree_depthFirstNumbers(geneTree)
+             rootedGeneTree2, dupCount, lossCount = calculateProbableRootOfGeneTree(speciesTree, geneTree)
+-            print "rootedGeneTree", rootedGeneString, dupCount, lossCount, printBinaryTree(rootedGeneTree2, False)
++            print("rootedGeneTree", rootedGeneString, dupCount, lossCount, printBinaryTree(rootedGeneTree2, False))
+             #assert printBinaryTree(rootedGeneTree, False) == printBinaryTree(rootedGeneTree2, False)
+     
+     def testCalculateProbableRootOfGeneTree(self):
+-        for test in xrange(0, self.testNo):
++        for test in range(0, self.testNo):
+             speciesTree = getRandomTree()
+             binaryTree_depthFirstNumbers(speciesTree)
+             geneTree = getRandomTree()
+--- a/src/sonLib/test/unitTest.py
++++ b/src/sonLib/test/unitTest.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+--- a/src/sonLib/tree.py
++++ b/src/sonLib/tree.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python
++#!/usr/bin/env python3
+ 
+ #Copyright (C) 2006-2012 by Benedict Paten (benedictpaten at gmail.com)
+ #
+@@ -69,7 +69,7 @@ def binaryTree_depthFirstNumbers(binaryT
+         return mid+1, leafNo+1
+     traverse(binaryTree)
+     if labelTree:
+-        for binaryTree in traversalIDs.keys():
++        for binaryTree in list(traversalIDs.keys()):
+             binaryTree.traversalID = traversalIDs[binaryTree]
+     return traversalIDs
+ 
+@@ -164,18 +164,18 @@ def transformByDistance(wV, subModel, al
+     transform wV by given substitution matrix
+     """
+     nc = [0.0]*alphabetSize
+-    for i in xrange(0, alphabetSize):
++    for i in range(0, alphabetSize):
+         j = wV[i]
+         k = subModel[i]
+-        for l in xrange(0, alphabetSize):
++        for l in range(0, alphabetSize):
+             nc[l] += j * k[l]
+     return nc
+ 
+ def multiplyWV(wVX, wVY, alphabetSize=4):
+-    return [ wVX[i] * wVY[i] for i in xrange(0, alphabetSize) ]
++    return [ wVX[i] * wVY[i] for i in range(0, alphabetSize) ]
+ 
+ def sumWV(wVX, wVY, alphabetSize=4):
+-    return [ wVX[i] + wVY[i] for i in xrange(0, alphabetSize) ]
++    return [ wVX[i] + wVY[i] for i in range(0, alphabetSize) ]
+     
+ def normaliseWV(wV, normFac=1.0):
+     """
+@@ -187,7 +187,7 @@ def normaliseWV(wV, normFac=1.0):
+ def sumWVA(wVA, alphabetSize=4):
+     totals = [0.0]*alphabetSize
+     for wV in wVA:
+-        for i in xrange(0, alphabetSize):
++        for i in range(0, alphabetSize):
+             totals[i] += wV[i]
+     return totals
+ 
+@@ -222,7 +222,7 @@ def felsensteins(binaryTree, subMatrices
+ def calculateCharacterFrequencies(seq, map, alphabetSize):
+     counts = [0.0]*alphabetSize
+     for i in seq:
+-        counts[map(i)] += 1
++        counts[list(map(i))] += 1
+     return counts
+     
+ #########################################################
+@@ -261,9 +261,9 @@ def calculateDNADistanceMatrix(seqNo, fa
+     transversions = [0.1]*seqNo*seqNo
+     counts = [1.0]*seqNo*seqNo
+     for column in fastaIter:
+-        for i in xrange(0, seqNo):
++        for i in range(0, seqNo):
+             if column[i] in [ 'A', 'C', 'T', 'G' ]:
+-                for j in xrange(i+1, seqNo):
++                for j in range(i+1, seqNo):
+                     if column[j] in [ 'A', 'C', 'T', 'G' ]:
+                         counts[i*seqNo + j] += 1
+                         if column[i] != column[j]:
+@@ -277,9 +277,9 @@ def calculateDNADistanceMatrix(seqNo, fa
+                                     transversions[i*seqNo + j] += 1
+                                 else:
+                                     transitions[i*seqNo + j] += 1
+-    distanceMatrix = [ [None]*seqNo for i in xrange(0, seqNo) ]
+-    for i in xrange(0, seqNo*seqNo):
+-        for j in xrange(i+1, seqNo):
++    distanceMatrix = [ [None]*seqNo for i in range(0, seqNo) ]
++    for i in range(0, seqNo*seqNo):
++        for j in range(i+1, seqNo):
+             k = i * seqNo + j
+             distanceMatrix[i][j] = -0.75*math.log(1 - (4/3)*((transitions[k]+transversions[k])/counts[k])) #jukes cantor correction
+             distanceMatrix[j][i] = distanceMatrix[i][j]
+@@ -288,10 +288,10 @@ def calculateDNADistanceMatrix(seqNo, fa
+     return distanceMatrix
+ 
+ def makeDistancePairs(distanceMatrix, iDs, seqNo):
+-    binaryTrees = [ BinaryTree(0.0, False, None, None, iDs[i]) for i in xrange(0, seqNo) ]
++    binaryTrees = [ BinaryTree(0.0, False, None, None, iDs[i]) for i in range(0, seqNo) ]
+     distancePairs = []
+-    for i in xrange(0, seqNo):
+-        for j in xrange(i+1, seqNo): 
++    for i in range(0, seqNo):
++        for j in range(i+1, seqNo): 
+             distancePairs.append(DistancePair(distanceMatrix[i][j], binaryTrees[i], 1, binaryTrees[j], 1))
+             distancePairs.append(DistancePair(distanceMatrix[i][j], binaryTrees[j], 1, binaryTrees[i], 1))
+     return distancePairs
+@@ -327,10 +327,10 @@ def upgmaI(distancePairs, leafNo):
+             holder1[i.leaf2] = i
+         if i.leaf1 == distancePair.leaf2 and i.leaf2 != distancePair.leaf1:
+             holder2[i.leaf2] = i
+-    assert len(holder1.keys()) == leafNo-2
+-    assert len(holder2.keys()) == leafNo-2
++    assert len(list(holder1.keys())) == leafNo-2
++    assert len(list(holder2.keys())) == leafNo-2
+     assert set(holder1.keys()) == set(holder2.keys())
+-    for i in holder1.keys():
++    for i in list(holder1.keys()):
+         j = holder1[i]
+         k = holder2[i]
+         newDistance = (j.distance*j.leafNo1 + k.distance*k.leafNo1)/(j.leafNo1 + k.leafNo1)
+@@ -346,7 +346,7 @@ def nj(distanceMatrix, iDs, leafNo):
+ 
+ def getMinPair(distancePairs, rValues, leafNo):
+     j = None
+-    k = sys.maxint
++    k = sys.maxsize
+     for i in distancePairs:
+         adjustD = i.distance - (rValues[i.leaf1] + rValues[i.leaf2])/(leafNo-2)
+         #print "the adjusted value ", adjustD, i.distance, rValues[i.leaf1]/(leafNo-2), rValues[i.leaf2]/(leafNo-2)
+@@ -359,11 +359,11 @@ def getMinPair(distancePairs, rValues, l
+ def calculateRValues(distancePairs, leafNo):
+     j = {}
+     for i in distancePairs:
+-        if j.has_key(i.leaf1):
++        if i.leaf1 in j:
+             j[i.leaf1] += i.distance
+         else:
+             j[i.leaf1] = i.distance
+-    assert len(j.keys()) == leafNo
++    assert len(list(j.keys())) == leafNo
+     return j
+ 
+ def njI(distancePairs, leafNo):
+@@ -391,10 +391,10 @@ def njI(distancePairs, leafNo):
+             holder1[i.leaf2] = i
+         if i.leaf1 == distancePair.leaf2 and i.leaf2 != distancePair.leaf1:
+             holder2[i.leaf2] = i
+-    assert len(holder1.keys()) == leafNo-2
+-    assert len(holder2.keys()) == leafNo-2
++    assert len(list(holder1.keys())) == leafNo-2
++    assert len(list(holder2.keys())) == leafNo-2
+     assert set(holder1.keys()) == set(holder2.keys())
+-    for i in holder1.keys():
++    for i in list(holder1.keys()):
+         j = holder1[i]
+         k = holder2[i]
+         assert j.leaf2 == k.leaf2
+@@ -416,13 +416,13 @@ def njI(distancePairs, leafNo):
+ 
+ def checkMatrix(m, fV, AS=4, reversible=True):
+     #print m
+-    for i in xrange(0, AS):
++    for i in range(0, AS):
+         j = sum(m[i])
+         #print "AAAAA", j
+         assert j <= 1.0001
+         assert j >= 0.9999
+         if reversible:
+-            for k in xrange(0, AS):
++            for k in range(0, AS):
+                 #print "comp2", (fV[i] * m[i][k]), (fV[k] * m[k][i] )
+                 assert close(fV[i] * m[i][k], fV[k] * m[k][i], 0.00001)
+     
+@@ -436,9 +436,9 @@ def checkMatrix(m, fV, AS=4, reversible=
+     assert close(i, j, 0.00001)
+     
+ def reverseSubMatrix(m, AS=4):
+-    k = [ [None]*AS for i in xrange(0, AS) ]
+-    for i in xrange(0, AS):
+-        for j in xrange(0, AS):
++    k = [ [None]*AS for i in range(0, AS) ]
++    for i in range(0, AS):
++        for j in range(0, AS):
+             k[j][i] = m[i][j]
+     return k
+     
+@@ -476,7 +476,7 @@ def subMatrix_TamuraNei(d, fA, fC, fG, f
+     AS = 4
+     freq = ( fA, fC, fG, fT )
+     alpha = ( alphaPur, alphaPyr, alphaPur, alphaPyr )
+-    matrix = [ [ 0.0 ]*AS for i in xrange(0, AS) ]
++    matrix = [ [ 0.0 ]*AS for i in range(0, AS) ]
+     #see page 203 of Felsenstein's Inferring Phylogenies for explanation of calculations
+     def watKro(j, k):
+         if (j % 2) == (k % 2):
+@@ -486,10 +486,10 @@ def subMatrix_TamuraNei(d, fA, fC, fG, f
+         if i == j:
+             return 1.0
+         return 0.0
+-    for i in xrange(0, AS): #long winded, totally unoptimised method for calculating matrix
+-        for j in xrange(0, AS):
++    for i in range(0, AS): #long winded, totally unoptimised method for calculating matrix
++        for j in range(0, AS):
+             l = 0.0
+-            for k in xrange(0, AS):
++            for k in range(0, AS):
+                 l += watKro(j, k) * freq[k]
+             matrix[i][j] =\
+             math.exp(-(alpha[i] + beta) * d) * kroenickerDelta(i, j) + \
+@@ -516,9 +516,9 @@ def subMatrix_HKY(d, fA, fC, fG, fT, tra
+ def subMatrix_HalpernBruno(d, freqColumn, subMatrix, AS=4):
+     #return subMatrix_HKY(d, freqColumn[0], freqColumn[1], freqColumn[2], freqColumn[3], 2.0)
+     #return subMatrix
+-    matrix = [ [ 0.0 ]*AS for i in xrange(0, AS) ]
+-    for i in xrange(0, AS):
+-        for j in xrange(0, AS):
++    matrix = [ [ 0.0 ]*AS for i in range(0, AS) ]
++    for i in range(0, AS):
++        for j in range(0, AS):
+             a = freqColumn[i] * subMatrix[i][j]
+             b = freqColumn[j] * subMatrix[j][i]
+             if not close(a, b, 0.0001):
+@@ -580,8 +580,8 @@ def mapTraversalIDsBetweenTrees(oldTree,
+             internalMap[(fn(oldTree), fn(oldTree.left))] = fn(oldTree.right)
+             internalMap[(fn(oldTree.left), fn(oldTree))] = fn(oldTree.right)
+     fn3(oldTree)
+-    print leafMap
+-    print internalMap
++    print(leafMap)
++    print(internalMap)
+     def fn4(newTree):
+         if newTree.internal:
+             fn4(newTree.left)
+@@ -596,7 +596,7 @@ def remodelTreeRemovingRoot(root, node):
+     """
+     Node is mid order number
+     """
+-    import bioio
++    from . import bioio
+     assert root.traversalID.mid != node
+     hash = {}
+     def fn(bT):
+@@ -632,7 +632,7 @@ def moveRoot(root, branch):
+     """
+     Removes the old root and places the new root at the mid point along the given branch
+     """
+-    import bioio
++    from . import bioio
+     if root.traversalID.mid == branch:
+         return bioio.newickTreeParser(bioio.printBinaryTree(root, True))
+     def fn2(tree, seq):
+@@ -703,7 +703,7 @@ def calculateDupsAndLossesByReconcilingT
+             if nodes.issubset(a[speciesTree.right.traversalID.mid]):
+                 return fn2(nodes, speciesTree.right)
+         return speciesTree.traversalID.mid
+-    for iD in b.keys():
++    for iD in list(b.keys()):
+         nodes = b[iD]
+         b[iD] = fn2(nodes, speciesTree)
+     dups = []
+@@ -725,7 +725,7 @@ def calculateDupsAndLossesByReconcilingT
+                 nodes.append((node, losses+1))
+         return nodes
+     for node, losses in fn4(speciesTree):
+-        lossMap[(sys.maxint, node)] = losses+1
++        lossMap[(sys.maxsize, node)] = losses+1
+     losses = [0]
+     def fn5(geneTree, ancestor):
+         if geneTree.internal:
+@@ -745,7 +745,7 @@ def calculateDupsAndLossesByReconcilingT
+         if speciesTree.internal:
+             fn6(speciesTree.left, speciesTree.traversalID.mid, node)
+             fn6(speciesTree.right, speciesTree.traversalID.mid, node)
+-    ancestor = fn6(speciesTree, sys.maxint, b[geneTree.traversalID.mid])
++    ancestor = fn6(speciesTree, sys.maxsize, b[geneTree.traversalID.mid])
+     assert ancestorHolder[0] is not None
+     fn5(geneTree, ancestorHolder[0])
+     return len(dups), losses[0]


=====================================
debian/patches/fix_test.patch
=====================================
@@ -0,0 +1,19 @@
+--- a/C/Makefile
++++ b/C/Makefile
+@@ -65,4 +65,4 @@ ${libPath}/sonLib.a : ${libSources} ${cp
+ 	mv sonLib.a ${libPath}/
+ 
+ test:
+-	python3 allTests.py --testLength=SHORT --logLevel CRITICAL
++	PYTHONPATH=../src/sonLib python3 allTests.py --testLength=SHORT --logLevel CRITICAL
+--- a/Makefile
++++ b/Makefile
+@@ -21,7 +21,7 @@ externalToolsP.clean :
+ 	cd externalTools && make clean
+ 
+ test : all
+-	PYTHONPATH=.. PATH=../../bin:$$PATH python3 allTests.py --testLength=SHORT --logLevel=CRITICAL
++	PYTHONPATH=$(CURDIR)/src:$(CURDIR)/src/sonLib PATH=$(CURDIR)/bin:$$PATH python3 src/sonLib/test/allTests.py --testLength=SHORT --logLevel=CRITICAL
+ 
+ ${binPath}/sonLib_daemonize.py : sonLib_daemonize.py
+ 	cp sonLib_daemonize.py ${binPath}/sonLib_daemonize.py


=====================================
debian/patches/series
=====================================
@@ -1 +1,3 @@
 use_debian_packaged_quicktree.patch
+2to3.patch
+fix_test.patch


=====================================
debian/patches/use_debian_packaged_quicktree.patch
=====================================
@@ -1,3 +1,8 @@
+Author: Andreas Tille <tille at debian.org>
+Last-Update: Tue, 16 Jun 2020 08:23:45 +0200
+Description: To avoid a code copy of quicktree here inside the quicktree
+ package a static lib is built and used to link here
+
 --- a/externalTools/Makefile
 +++ b/externalTools/Makefile
 @@ -1,20 +1,14 @@
@@ -24,3 +29,37 @@
 -
 -quicktreeM.clean :
 -	cd quicktree_1.1 && make clean
+--- a/C/Makefile
++++ b/C/Makefile
+@@ -7,12 +7,11 @@ cppSources = impl/*.cpp
+ libHeaders = $(wildcard inc/*.h)
+ libInternalHeaders = impl/*.h
+ libTests = tests/sonLib*.c tests/st*
+-quickTreeObjects = ../externalTools/quicktree_1.1/obj/buildtree.o ../externalTools/quicktree_1.1/obj/cluster.o ../externalTools/quicktree_1.1/obj/distancemat.o ../externalTools/quicktree_1.1/obj/options.o ../externalTools/quicktree_1.1/obj/sequence.o ../externalTools/quicktree_1.1/obj/tree.o ../externalTools/quicktree_1.1/obj/util.o
+ quickTreeLibPath = ../externalTools/quicktree_1.1/include/
+ 
+ testProgs = ${binPath}/sonLibTests ${binPath}/sonLib_kvDatabaseTest ${binPath}/sonLib_cigarTest ${binPath}/sonLib_fastaCTest ${binPath}/sonLib_dynamicConnectivity_performance
+ 
+-cflags += ${tokyoCabinetIncl} ${kyotoTycoonIncl} ${tokyoTyrantIncl} ${mysqlIncl} ${pgsqlIncl} -I${quickTreeLibPath}
++cflags += ${tokyoCabinetIncl} ${kyotoTycoonIncl} ${tokyoTyrantIncl} ${mysqlIncl} ${pgsqlIncl} -I/usr/include/quicktree
+ cppflags += ${kyotoTycoonIncl}
+ 
+ all : ${libPath}/sonLib.a ${testProgs}
+@@ -22,7 +21,7 @@ clean :
+ 
+ ${binPath}/sonLibTests : ${libTests} ${libInternalHeaders} ${libPath}/sonLib.a ${libPath}/cuTest.a tests/allTests.c
+ 	@mkdir -p $(dir $@)
+-	${cxx} ${cflags} -I inc -I ${libPath} -o $@.tmp tests/allTests.c ${libTests} ${libPath}/sonLib.a ${libPath}/cuTest.a ${dblibs} ${mysqlLibs} -lm -lstdc++ -lpthread
++	${cxx} ${cflags} -I inc -I ${libPath} -o $@.tmp tests/allTests.c ${libTests} ${libPath}/sonLib.a ${libPath}/cuTest.a ${dblibs} ${mysqlLibs} -lm -lstdc++ -lpthread -lquicktree
+ 	mv $@.tmp $@
+ 
+ ${binPath}/sonLib_kvDatabaseTest : ${libTests} ${libInternalHeaders} ${libPath}/sonLib.a ${libPath}/cuTest.a tests/kvDatabaseTest.c tests/kvDatabaseTestCommon.c
+@@ -60,7 +59,7 @@ ${libPath}/sonLib.a : ${libSources} ${cp
+ 	@mkdir -p $(dir $@)
+ 	${cxx} ${cflags} -I inc -I ${libPath}/  -c ${libSources}
+ 	${cpp} ${cppflags} -I inc -I ${libPath}/ -c ${cppSources}
+-	ar rc sonLib.a *.o ${quickTreeObjects}
++	ar rc sonLib.a *.o
+ 	ranlib sonLib.a 
+ 	rm *.o
+ 	mv sonLib.a ${libPath}/


=====================================
debian/rules
=====================================
@@ -20,6 +20,12 @@ include /usr/share/dpkg/default.mk
 %:
 	dh $@
 
+override_dh_auto_build:
+	# Somehow Makefile does not deal with this ...
+	mkdir -p bin
+	cp -a src/sonLib/test/sonLib_daemonize.py .
+	dh_auto_build
+
 ### When overriding auto_test make sure DEB_BUILD_OPTIONS will be respected
 #override_dh_auto_test:
 #ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))



View it on GitLab: https://salsa.debian.org/med-team/libsonlib/-/compare/2fdf58ac24255692fccd10b4df734b2ee6304528...e02ce9f8e568331b7320aaad5855e7fa59c8b051

-- 
View it on GitLab: https://salsa.debian.org/med-team/libsonlib/-/compare/2fdf58ac24255692fccd10b4df734b2ee6304528...e02ce9f8e568331b7320aaad5855e7fa59c8b051
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/20200616/6c11c40e/attachment-0001.html>


More information about the debian-med-commit mailing list