Package: poretools
Version: 0.6.0+dfsg-3
Severity: normal
Tags: patch
User: ubuntu-de...@lists.ubuntu.com
Usertags: origin-ubuntu eoan ubuntu-patch

Hi Afif,

As you may know, we are in the process of deprecating python2 in Debian for
the next release.  In Ubuntu, I've identified that it may be useful to
accelerate this deprecation for pandas and its reverse-dependencies, because
the pandas tests appear to have bit-rotted for python2 on one architecture,
and it would be better to remove the python2 bits rather than invest in
fixing them.

poretools is a package that depends on python-pandas, so I've looked at
porting the code to python3.  With 2to3 this has been reasonably
straightforward; and although there are no tests in the package, there are
various imports that happen as part of the package build and the python
usage here seems reasonably straightforward, so I'm fairly confident that
this port will work.

I've therefore uploaded this change to Ubuntu.  Please consider applying
these changes in Debian as well and forwarding them upstream.

Thanks,
-- 
Steve Langasek                   Give me a lever long enough and a Free OS
Debian Developer                   to set it on, and I can move the world.
Ubuntu Developer                                   https://www.debian.org/
slanga...@ubuntu.com                                     vor...@debian.org
diff -Nru poretools-0.6.0+dfsg/debian/control 
poretools-0.6.0+dfsg/debian/control
--- poretools-0.6.0+dfsg/debian/control 2018-07-19 00:48:29.000000000 -0700
+++ poretools-0.6.0+dfsg/debian/control 2019-08-15 09:24:04.000000000 -0700
@@ -5,12 +5,12 @@
 Priority: optional
 Build-Depends: debhelper (>= 11~),
                dh-python,
-               python-all,
-               python-setuptools,
-               python-h5py (>= 2.2),
-               python-matplotlib,
-               python-seaborn,
-               python-pandas
+               python3-all,
+               python3-setuptools,
+               python3-h5py (>= 2.2),
+               python3-matplotlib,
+               python3-seaborn,
+               python3-pandas
 Standards-Version: 4.1.5
 Vcs-Browser: https://salsa.debian.org/med-team/poretools
 Vcs-Git: https://salsa.debian.org/med-team/poretools.git
@@ -19,8 +19,8 @@
 Package: poretools
 Architecture: all
 Depends: ${misc:Depends},
-         ${python:Depends},
-         python-pkg-resources
+         ${python3:Depends},
+         python3-pkg-resources
 Description: toolkit for nanopore nucleotide sequencing data
  poretools is a flexible toolkit for exploring datasets generated by nanopore
  sequencing devices from MinION for the purposes of quality control and
diff -Nru poretools-0.6.0+dfsg/debian/patches/python3.patch 
poretools-0.6.0+dfsg/debian/patches/python3.patch
--- poretools-0.6.0+dfsg/debian/patches/python3.patch   1969-12-31 
16:00:00.000000000 -0800
+++ poretools-0.6.0+dfsg/debian/patches/python3.patch   2019-08-15 
09:24:04.000000000 -0700
@@ -0,0 +1,934 @@
+Description: port to python3
+ Python2 is obsolete.  Port this code to python3.
+ Changes consist of 2to3 output, plus fixes for tab vs. space issues, and
+ a fix to argparse handling when we're called with no arguments.
+Author: Steve Langasek <steve.langa...@ubuntu.com>
+Last-Modified: 2019-08-15
+
+Index: poretools-0.6.0+dfsg/setup.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/setup.py
++++ poretools-0.6.0+dfsg/setup.py
+@@ -3,7 +3,7 @@
+ 
+ version_py = os.path.join(os.path.dirname(__file__), 'poretools', 
'version.py')
+ version = 
open(version_py).read().strip().split('=')[-1].replace('"','').strip()
+-print version
++print(version)
+ long_description = """
+ ``poretools`` is a toolset for working with nanopore sequencing data'
+ """
+Index: poretools-0.6.0+dfsg/poretools/__init__.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/__init__.py
++++ poretools-0.6.0+dfsg/poretools/__init__.py
+@@ -1,5 +1,5 @@
+ import os
+ import sys
+-import scripts
+-from Fast5File import *
+-from version import __version__
++from . import scripts
++from .Fast5File import *
++from .version import __version__
+Index: poretools-0.6.0+dfsg/poretools/Fast5File.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/Fast5File.py
++++ poretools-0.6.0+dfsg/poretools/Fast5File.py
+@@ -11,8 +11,8 @@
+ 
+ 
+ # poretools imports
+-import formats
+-from Event import Event
++from . import formats
++from .Event import Event
+ 
+ fastq_paths = {
+   'closed' : {},
+@@ -63,7 +63,7 @@
+     def __iter__(self):
+         return self
+ 
+-    def next(self):
++    def __next__(self):
+         if len(self.files) > 0:
+             return self.files.pop(0)
+         else:
+@@ -93,9 +93,9 @@
+       def __iter__(self):
+               return self
+ 
+-      def next(self):
++      def __next__(self):
+               try:
+-                      return Fast5File(self.files.next(), self.group)
++                      return Fast5File(next(self.files), self.group)
+               except Exception as e:
+                       # cleanup our mess
+                       if self.set_type == FAST5SET_TARBALL:
+@@ -156,9 +156,9 @@
+       def __iter__(self):
+               return self
+ 
+-      def next(self):
++      def __next__(self):
+               while True:
+-                      tarinfo = self._tarfile.next()
++                      tarinfo = next(self._tarfile)
+                       if tarinfo is None:
+                               raise StopIteration
+                       elif self._fast5_filename_filter(tarinfo.name):
+@@ -211,7 +211,7 @@
+               try:
+                       self.hdf5file = h5py.File(self.filename, 'r')
+                       return True
+-              except Exception, e:
++              except Exception as e:
+                       logger.warning("Cannot open file: %s. Perhaps it is 
corrupt? Moving on.\n" % self.filename)
+                       return False
+ 
+@@ -327,7 +327,7 @@
+                         self._extract_fastas_from_fast5()
+                         self.have_fastas = True
+ 
+-              return self.fastas
++                return self.fastas
+ 
+       def get_fastq(self):
+               """
+@@ -465,7 +465,7 @@
+     https://github.com/arq5x/poretools/issues"""; % (self.filename, reason)
+               sys.exit(msg)
+ 
+-        def find_read_number_block_fixed_raw(self):
++      def find_read_number_block_fixed_raw(self):
+               """
+               New-style FAST5/HDF5 structure:
+               There is a fixed 'Raw/Reads' node with only one 'read_NNN' item
+@@ -477,7 +477,7 @@
+               if raw_reads is None:
+                       return None
+ 
+-              reads = raw_reads.keys()
++              reads = list(raw_reads.keys())
+               if len(reads)==0:
+                       self.hdf_internal_error("Raw/Reads group does not 
contain any items")
+               if len(reads)>1:
+@@ -489,7 +489,7 @@
+                       self.hdf_internal_error("Failed to get HDF5 item '%s'"% 
(path))
+               return node
+ 
+-        def find_read_number_block(self):
++      def find_read_number_block(self):
+               """Returns the node of the 'Read_NNN' information, or None if 
not
+               found"""
+               node = self.find_read_number_block_link()
+@@ -652,31 +652,31 @@
+                       self._get_metadata()
+                       self.have_metadata = True
+ 
+-        def get_host_name(self):
+-                """
+-                Return the MinKNOW host computer name.
+-                """
+-                if self.have_metadata is False:
+-                        self._get_metadata()
+-                        self.have_metadata = True
+-
+-                try:
+-                        return self.keyinfo['tracking_id'].attrs['hostname']
+-                except:
+-                        return None
+-
+-                if self.have_metadata is False:
+-                        self._get_metadata()
+-                        self.have_metadata = True
++      def get_host_name(self):
++              """
++              Return the MinKNOW host computer name.
++              """
++              if self.have_metadata is False:
++                      self._get_metadata()
++                      self.have_metadata = True
++
++              try:
++                      return self.keyinfo['tracking_id'].attrs['hostname']
++              except:
++                      return None
++
++              if self.have_metadata is False:
++                      self._get_metadata()
++                      self.have_metadata = True
+ 
+       def get_device_id(self):
+               """
+               Return the flowcell's device id.
+               """
+ 
+-                if self.have_metadata is False:
+-                        self._get_metadata()
+-                        self.have_metadata = True
++              if self.have_metadata is False:
++                      self._get_metadata()
++                      self.have_metadata = True
+ 
+               try:
+                       return self.keyinfo['tracking_id'].attrs['device_id']
+@@ -688,13 +688,13 @@
+               Return the user supplied sample name
+               """
+ 
+-                if self.have_metadata is False:
+-                        self._get_metadata()
+-                        self.have_metadata = True
++              if self.have_metadata is False:
++                      self._get_metadata()
++                      self.have_metadata = True
+ 
+               try:
+                       return 
self.keyinfo['context_tags'].attrs['user_filename_input']
+-              except Exception, e:
++              except Exception as e:
+                       return None
+ 
+ 
+@@ -705,7 +705,7 @@
+               try:
+                       table = 
self.hdf5file[fastq_paths[self.version]['template'] % self.group]
+                       return len(table['Events'][()])
+-              except Exception, e:
++              except Exception as e:
+                       return 0
+ 
+       def get_complement_events_count(self):
+@@ -715,7 +715,7 @@
+               try:
+                       table = 
self.hdf5file[fastq_paths[self.version]['complement'] % self.group]
+                       return len(table['Events'][()])
+-              except Exception, e:
++              except Exception as e:
+                       return 0
+ 
+       def is_high_quality(self):
+@@ -746,7 +746,7 @@
+                                       return 'template'
+                               else:
+                                       return 'complement'
+-              except Exception, e:
++              except Exception as e:
+                       return None
+ 
+       ####################################################################
+@@ -757,26 +757,26 @@
+               """
+               Return the sequence in the FAST5 file in FASTQ format
+               """
+-              for id, h5path in fastq_paths[self.version].iteritems(): 
++              for id, h5path in fastq_paths[self.version].items(): 
+                       try:
+                               table = self.hdf5file[h5path % self.group]
+                               fq = formats.Fastq(table['Fastq'][()])
+                               fq.name += " " + self.filename
+                               self.fastqs[id] = fq
+-                      except Exception, e:
++                      except Exception as e:
+                               pass
+ 
+       def _extract_fastas_from_fast5(self):
+               """
+               Return the sequence in the FAST5 file in FASTA format
+               """
+-              for id, h5path in fastq_paths[self.version].iteritems(): 
++              for id, h5path in fastq_paths[self.version].items(): 
+                       try:
+                               table = self.hdf5file[h5path % self.group]
+                               fa = formats.Fasta(table['Fastq'][()])
+                               fa.name += " " + self.filename
+                               self.fastas[id] = fa
+-                      except Exception, e:
++                      except Exception as e:
+                               pass
+ 
+       def _extract_template_events(self):
+@@ -786,7 +786,7 @@
+               try:
+                       table = 
self.hdf5file[fastq_paths[self.version]['template'] % self.group]
+                       self.template_events = [Event(x) for x in 
table['Events'][()]]
+-              except Exception, e:
++              except Exception as e:
+                       self.template_events = []
+ 
+       def _extract_complement_events(self):
+@@ -796,7 +796,7 @@
+               try:
+                       table = 
self.hdf5file[fastq_paths[self.version]['complement'] % self.group]
+                       self.complement_events = [Event(x) for x in 
table['Events'][()]]
+-              except Exception, e:
++              except Exception as e:
+                       self.complement_events = []
+ 
+       def _extract_pre_basecalled_events(self):
+@@ -815,9 +815,9 @@
+       def _get_metadata(self):
+               try:
+                       self.keyinfo = self.hdf5file['/UniqueGlobalKey']
+-              except Exception, e:
++              except Exception as e:
+                       try:
+                               self.keyinfo = self.hdf5file['/Key']
+-                      except Exception, e:
++                      except Exception as e:
+                               self.keyinfo = None
+                               logger.warning("Cannot find keyinfo. 
Exiting.\n")
+Index: poretools-0.6.0+dfsg/poretools/formats.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/formats.py
++++ poretools-0.6.0+dfsg/poretools/formats.py
+@@ -19,7 +19,7 @@
+                               phred = ord(score) - 33
+                               error_count += 10.0 ** (-phred / 10.0)
+                       return error_count / len(self.qual)
+-              except Exception, e:
++              except Exception as e:
+                       return 0.0
+ 
+ 
+Index: poretools-0.6.0+dfsg/poretools/times.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/times.py
++++ poretools-0.6.0+dfsg/poretools/times.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ from time import strftime, localtime
+ import sys
+ 
+@@ -7,10 +7,10 @@
+ logger = logging.getLogger('poretools')
+ 
+ def run(parser, args):
+-      print '\t'.join(['channel', 'filename', 'read_length', 
++      print('\t'.join(['channel', 'filename', 'read_length', 
+               'exp_starttime', 'unix_timestamp', 'duration', 
+               'unix_timestamp_end', 'iso_timestamp', 'day', 
+-              'hour', 'minute'])
++              'hour', 'minute']))
+       
+       for fast5 in Fast5File.Fast5FileSet(args.files):
+               if fast5.is_open:
+@@ -29,7 +29,7 @@
+                               read_length = 0
+ 
+                       lt = localtime(start_time)
+-                      print "\t".join([fast5.get_channel_number(),
++                      print("\t".join([fast5.get_channel_number(),
+                               fast5.filename, 
+                               str(read_length),
+                               str(fast5.get_exp_start_time()),
+@@ -39,5 +39,5 @@
+                               strftime('%Y-%m-%dT%H:%M:%S%z', lt),
+                               strftime('%d', lt),
+                               strftime('%H', lt),
+-                              strftime('%M', lt)])
++                              strftime('%M', lt)]))
+                       fast5.close()
+Index: poretools-0.6.0+dfsg/poretools/events.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/events.py
++++ poretools-0.6.0+dfsg/poretools/events.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ 
+ def run(parser, args):
+ 
+@@ -7,18 +7,18 @@
+                       'length', 'model_state', 'model_level', 'move', \
+                       'p_model_state', 'mp_model_state', 'p_mp_model_state', \
+                       'p_A', 'p_C', 'p_G', 'p_T', 'raw_index']
+-      print "\t".join(keys)
++      print("\t".join(keys))
+ 
+       if args.pre_basecalled:
+               for fast5 in Fast5File.Fast5FileSet(args.files):
+                       for event in fast5.get_pre_basecalled_events(): 
+-                              print '\t'.join([fast5.filename, 
'pre_basecalled', str(event)])
++                              print('\t'.join([fast5.filename, 
'pre_basecalled', str(event)]))
+       else:
+               for fast5 in Fast5File.Fast5FileSet(args.files):
+                       for event in fast5.get_template_events():
+-                              print '\t'.join([fast5.filename, 'template', 
str(event)]) 
++                              print('\t'.join([fast5.filename, 'template', 
str(event)])) 
+                       for event in fast5.get_complement_events():
+-                              print '\t'.join([fast5.filename, 'complement', 
str(event)]) 
++                              print('\t'.join([fast5.filename, 'complement', 
str(event)])) 
+ 
+               fast5.close()
+ 
+Index: poretools-0.6.0+dfsg/poretools/qualdist.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/qualdist.py
++++ poretools-0.6.0+dfsg/poretools/qualdist.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ from collections import Counter
+ 
+ def run(parser, args):
+@@ -15,5 +15,5 @@
+               fast5.close()
+ 
+       for q in qual_count:
+-              print '\t'.join(str(s) for s in [chr(q+33), q, qual_count[q], 
+-                      total_nucs, float(qual_count[q]) / float(total_nucs)])
+\ No newline at end of file
++              print ('\t'.join(str(s) for s in [chr(q+33), q, qual_count[q], 
++                      total_nucs, float(qual_count[q]) / float(total_nucs)]))
+Index: poretools-0.6.0+dfsg/poretools/metadata.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/metadata.py
++++ poretools-0.6.0+dfsg/poretools/metadata.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ 
+ def run(parser, args):
+ 
+@@ -6,17 +6,17 @@
+               for i, fast5 in enumerate(Fast5File.Fast5FileSet(args.files)):
+                       for metadata_dict in fast5.read_metadata:
+                               if i == 0:
+-                                      header = metadata_dict.keys()
+-                                      print "\t".join(["filename"] + header)
+-                              print "\t".join([fast5.filename] + [str( 
metadata_dict[k] ) for k in header])
++                                      header = list(metadata_dict.keys())
++                                      print("\t".join(["filename"] + header))
++                              print("\t".join([fast5.filename] + [str( 
metadata_dict[k] ) for k in header]))
+       else:
+-              print "asic_id\tasic_temp\theatsink_temp"
++              print("asic_id\tasic_temp\theatsink_temp")
+               for fast5 in Fast5File.Fast5FileSet(args.files):
+ 
+                       asic_temp  = fast5.get_asic_temp()
+                       asic_id = fast5.get_asic_id()
+                       heatsink_temp = fast5.get_heatsink_temp()
+ 
+-                      print "%s\t%s\t%s" % (asic_id, asic_temp, heatsink_temp)
++                      print("%s\t%s\t%s" % (asic_id, asic_temp, 
heatsink_temp))
+ 
+                       fast5.close()
+Index: poretools-0.6.0+dfsg/poretools/fastq.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/fastq.py
++++ poretools-0.6.0+dfsg/poretools/fastq.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ import sys
+ 
+ def run(parser, args):
+@@ -42,7 +42,7 @@
+                       args.max_length > 0):                   
+                               continue
+ 
+-                      print fa
++                      print(fa)
+ 
+               fast5.close()
+ 
+Index: poretools-0.6.0+dfsg/poretools/occupancy.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/occupancy.py
++++ poretools-0.6.0+dfsg/poretools/occupancy.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ from collections import Counter
+ import sys
+ import pandas as pd
+@@ -35,8 +35,8 @@
+             pore_values.append(0)
+ 
+     # make a data frame of the lists
+-    d = {'rownum': range(1,17)*32,
+-        'colnum': sorted(range(1,33)*16),
++    d = {'rownum': list(range(1,17))*32,
++        'colnum': sorted(list(range(1,33))*16),
+         'tot_reads': pore_values,
+         'labels': flowcell_layout}
+     df = pd.DataFrame(d)
+@@ -55,7 +55,7 @@
+     tot_reads_per_pore = Counter()
+     tot_bp_per_pore = Counter()
+ 
+-    print "\t".join(['channel_number', 'start_time', 'duration'])
++    print("\t".join(['channel_number', 'start_time', 'duration']))
+     for fast5 in Fast5File.Fast5FileSet(args.files):
+         if fast5.is_open:
+             fq = fast5.get_fastq()
+@@ -70,10 +70,10 @@
+             tot_reads_per_pore[int(pore_id)] += 1
+             tot_bp_per_pore[int(pore_id)] += len(fq.seq)
+ 
+-            print "\t".join([
++            print("\t".join([
+                 str(pore_id),
+                 str(start_time),
+-                str(fast5.get_duration())])
++                str(fast5.get_duration())]))
+             fast5.close()
+ 
+     if args.plot_type == 'read_count':
+Index: poretools-0.6.0+dfsg/poretools/index.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/index.py
++++ poretools-0.6.0+dfsg/poretools/index.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ import datetime
+ 
+ ############
+@@ -17,7 +17,7 @@
+ 
+ def run(parser, args):
+ 
+-      print 
"source_filename\ttemplate_fwd_length\tcomplement_rev_length\t2d_length\tasic_id\tasic_temp\theatsink_temp\tchannel\texp_start_time\texp_start_time_string_date\texp_start_time_string_time\tstart_time\tstart_time_string_date\tstart_time_string_time\tduration\tfast5_version"
++      
print("source_filename\ttemplate_fwd_length\tcomplement_rev_length\t2d_length\tasic_id\tasic_temp\theatsink_temp\tchannel\texp_start_time\texp_start_time_string_date\texp_start_time_string_time\tstart_time\tstart_time_string_date\tstart_time_string_time\tduration\tfast5_version")
+ 
+       for fast5 in Fast5File.Fast5FileSet(args.files):
+               
+@@ -56,11 +56,11 @@
+                       length_complement = len(fastq_reads[1].seq)
+                       length_2d = len(fastq_reads[2].seq)
+ 
+-              print "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s" 
% (
++              print("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s" 
% (
+                       fast5.filename,
+                       length_template,
+                       length_complement,
+                       length_2d,              
+-                      asic_id, asic_temp, 
heatsink_temp,channel_number,exp_start_time,exp_start_time_string,start_time,start_time_string,duration,fast5_version)
++                      asic_id, asic_temp, 
heatsink_temp,channel_number,exp_start_time,exp_start_time_string,start_time,start_time_string,duration,fast5_version))
+ 
+               fast5.close()
+Index: poretools-0.6.0+dfsg/poretools/readstats.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/readstats.py
++++ poretools-0.6.0+dfsg/poretools/readstats.py
+@@ -1,8 +1,8 @@
+-import Fast5File
++from . import Fast5File
+ 
+ def run(parser, args):
+ 
+-      print 
"start_time\tchannel_number\tread_number\ttemplate_events\tcomplement_events"
++      
print("start_time\tchannel_number\tread_number\ttemplate_events\tcomplement_events")
+ 
+       for fast5 in Fast5File.Fast5FileSet(args.files):
+ 
+@@ -22,6 +22,6 @@
+               else:
+                       complement_len = 0
+ 
+-              print "%s\t%s\t%s\t%s\t%s" % (start_time, channel_number, 
read_number, template_len, complement_len)
++              print("%s\t%s\t%s\t%s\t%s" % (start_time, channel_number, 
read_number, template_len, complement_len))
+ 
+               fast5.close()
+Index: poretools-0.6.0+dfsg/poretools/winner.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/winner.py
++++ poretools-0.6.0+dfsg/poretools/winner.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ import sys
+ 
+ #logging
+@@ -21,5 +21,5 @@
+               fast5.close()
+ 
+       logger.info("Wow, it's a whopper: your longest read is %d bases." % 
(longest_size,))
+-      print longest_read
++      print(longest_read)
+ 
+Index: poretools-0.6.0+dfsg/poretools/stats.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/stats.py
++++ poretools-0.6.0+dfsg/poretools/stats.py
+@@ -1,5 +1,5 @@
+-import statistics as stat
+-import Fast5File
++from . import statistics as stat
++from . import Fast5File
+ import logging
+ from collections import defaultdict
+ logger = logging.getLogger('poretools')
+@@ -14,7 +14,7 @@
+                       fas = fast5.get_fastas_dict()
+                       if len(fas) > 0:
+                               basecalled_files += 1
+-                      for category, fa in fas.iteritems():
++                      for category, fa in fas.items():
+                               if fa is not None:
+                                       stats[category].append(len(fa.seq))
+                                       if category == 'twodirections':
+@@ -23,22 +23,22 @@
+ 
+                       fast5.close()
+ 
+-              print "files\ttotal reads\t%d" % (files)
+-              print "files\ttotal base-called reads\t%d" % (basecalled_files)
++              print("files\ttotal reads\t%d" % (files))
++              print("files\ttotal base-called reads\t%d" % (basecalled_files))
+               for category in sorted(stats.keys()):
+                       sizes = stats[category]
+ 
+                       if len(sizes) > 0:
+-                              print "%s\ttotal reads\t%d" % (category, 
len(sizes))
+-                              print "%s\ttotal base pairs\t%d" % (category, 
sum(sizes))
+-                              print "%s\tmean\t%.2f" % (category, 
stat.mean(sizes))
+-                              print "%s\tmedian\t%d" % (category, 
stat.median(sizes))
+-                              print "%s\tmin\t%d" % (category, min(sizes))
+-                              print "%s\tmax\t%d" % (category, max(sizes))
++                              print("%s\ttotal reads\t%d" % (category, 
len(sizes)))
++                              print("%s\ttotal base pairs\t%d" % (category, 
sum(sizes)))
++                              print("%s\tmean\t%.2f" % (category, 
stat.mean(sizes)))
++                              print("%s\tmedian\t%d" % (category, 
stat.median(sizes)))
++                              print("%s\tmin\t%d" % (category, min(sizes)))
++                              print("%s\tmax\t%d" % (category, max(sizes)))
+                               nxvalues = stat.NX(sizes, [25,50,75])
+-                              print "%s\tN25\t%d" % (category, nxvalues[25])
+-                              print "%s\tN50\t%d" % (category, nxvalues[50])
+-                              print "%s\tN75\t%d" % (category, nxvalues[75])
++                              print("%s\tN25\t%d" % (category, nxvalues[25]))
++                              print("%s\tN50\t%d" % (category, nxvalues[50]))
++                              print("%s\tN75\t%d" % (category, nxvalues[75]))
+                       else:
+                               logger.warning("No valid sequences observed.\n")
+       else:
+@@ -49,15 +49,15 @@
+                       fast5.close()
+ 
+               if len(sizes) > 0:
+-                      print "total reads\t%d" % (len(sizes))
+-                      print "total base pairs\t%d" % (sum(sizes))
+-                      print "mean\t%.2f" % (stat.mean(sizes))
+-                      print "median\t%d" % (stat.median(sizes))
+-                      print "min\t%d" % (min(sizes))
+-                      print "max\t%d" % (max(sizes))
+-                        nxvalues = stat.NX(sizes, [25,50,75])
+-                        print "N25\t%d" % (nxvalues[25])
+-                        print "N50\t%d" % (nxvalues[50])
+-                        print "N75\t%d" % (nxvalues[75])
++                      print("total reads\t%d" % (len(sizes)))
++                      print("total base pairs\t%d" % (sum(sizes)))
++                      print("mean\t%.2f" % (stat.mean(sizes)))
++                      print("median\t%d" % (stat.median(sizes)))
++                      print("min\t%d" % (min(sizes)))
++                      print("max\t%d" % (max(sizes)))
++                      nxvalues = stat.NX(sizes, [25,50,75])
++                      print("N25\t%d" % (nxvalues[25]))
++                      print("N50\t%d" % (nxvalues[50]))
++                      print("N75\t%d" % (nxvalues[75]))
+               else:
+                       logger.warning("No valid sequences observed.\n")
+Index: poretools-0.6.0+dfsg/poretools/nucdist.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/nucdist.py
++++ poretools-0.6.0+dfsg/poretools/nucdist.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ from collections import Counter
+ 
+ def run(parser, args):
+@@ -15,5 +15,5 @@
+               fast5.close()
+ 
+       for n in nuc_count:
+-              print '\t'.join(str(s) for s in [n, nuc_count[n], 
+-                      total_nucs, float(nuc_count[n]) / float(total_nucs)])
+\ No newline at end of file
++              print ('\t'.join(str(s) for s in [n, nuc_count[n], 
++                      total_nucs, float(nuc_count[n]) / float(total_nucs)]))
+Index: poretools-0.6.0+dfsg/poretools/tabular.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/tabular.py
++++ poretools-0.6.0+dfsg/poretools/tabular.py
+@@ -1,8 +1,8 @@
+-import Fast5File
++from . import Fast5File
+ 
+ def run(parser, args):
+       
+-      print '\t'.join(['length', 'name', 'sequence', 'quals'])
++      print('\t'.join(['length', 'name', 'sequence', 'quals']))
+       
+       for fast5 in Fast5File.Fast5FileSet(args.files):
+               fqs = fast5.get_fastqs(args.type)
+@@ -10,5 +10,5 @@
+                       if fq is None:
+                               fast5.close()
+                               continue
+-                      print '\t'.join([str(len(fq.seq)), fq.name, fq.seq, 
fq.qual])
+-              fast5.close()
+\ No newline at end of file
++                      print ('\t'.join([str(len(fq.seq)), fq.name, fq.seq, 
fq.qual]))
++              fast5.close()
+Index: poretools-0.6.0+dfsg/poretools/fasta.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/fasta.py
++++ poretools-0.6.0+dfsg/poretools/fasta.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ import sys
+ 
+ def run(parser, args):
+@@ -42,7 +42,7 @@
+                       args.max_length > 0):                   
+                               continue                        
+ 
+-                      print fa
++                      print(fa)
+ 
+               fast5.close()
+ 
+Index: poretools-0.6.0+dfsg/poretools/statistics.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/statistics.py
++++ poretools-0.6.0+dfsg/poretools/statistics.py
+@@ -27,25 +27,25 @@
+               return None
+ 
+ def NX(l, x=[25,50,75]):
+-        """
+-        Returns NX for all x for a list of numbers l.
+-        Default: N25, N50, N75
+-        Assumes all values in list x are between 0 and 100.
+-        Interpretation: When NX = NX_value, X% of data (in bp) is contained 
in reads at least NX_value bp long.
+-        """
++      """
++      Returns NX for all x for a list of numbers l.
++      Default: N25, N50, N75
++      Assumes all values in list x are between 0 and 100.
++      Interpretation: When NX = NX_value, X% of data (in bp) is contained in 
reads at least NX_value bp long.
++      """
+       if isinstance(l, list) and isinstance(x, list):
+               l = sorted(l)
+               x = sorted(x)
+               total = sum(l)
+-                nxsum = 0
+-                nxvalues = {e:0 for e in x}
++              nxsum = 0
++              nxvalues = {e:0 for e in x}
+               for e in x:
+-                        xpct = total*e/100.0
+-                        while nxsum < xpct and l:
+-                                nxsum += l[-1]
+-                                lastsize = l.pop()
+-                        nxvalues[e] = lastsize
+-                return nxvalues
++                      xpct = total*e/100.0
++                      while nxsum < xpct and l:
++                              nxsum += l[-1]
++                              lastsize = l.pop()
++                      nxvalues[e] = lastsize
++              return nxvalues
+ 
+       else:
+               return None
+Index: poretools-0.6.0+dfsg/poretools/poretools_main.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/poretools_main.py
++++ poretools-0.6.0+dfsg/poretools/poretools_main.py
+@@ -13,43 +13,43 @@
+ 
+ def run_subtool(parser, args):
+     if args.command == 'combine':
+-        import combine as submodule
++        from . import combine as submodule
+     elif args.command == 'events':
+-        import events as submodule
++        from . import events as submodule
+     elif args.command == 'fasta':
+-        import fasta as submodule
++        from . import fasta as submodule
+     elif args.command == 'fastq':
+-        import fastq as submodule
++        from . import fastq as submodule
+     elif args.command == 'hist':
+-        import hist as submodule
++        from . import hist as submodule
+     elif args.command == 'metadata':
+-        import metadata as submodule
++        from . import metadata as submodule
+     elif args.command == 'nucdist':
+-        import nucdist as submodule
++        from . import nucdist as submodule
+     elif args.command == 'occupancy':
+-        import occupancy as submodule
++        from . import occupancy as submodule
+     elif args.command == 'qualdist':
+-        import qualdist as submodule
++        from . import qualdist as submodule
+     elif args.command == 'qualpos':
+-        import qual_v_pos as submodule
++        from . import qual_v_pos as submodule
+     elif args.command == 'readstats':
+-        import readstats as submodule
++        from . import readstats as submodule
+     elif args.command == 'stats':
+-        import stats as submodule
++        from . import stats as submodule
+     elif args.command == 'tabular':
+-        import tabular as submodule
++        from . import tabular as submodule
+     elif args.command == 'times':
+-        import times as submodule
++        from . import times as submodule
+     elif args.command == 'squiggle':
+-        import squiggle as submodule
++        from . import squiggle as submodule
+     elif args.command == 'winner':
+-        import winner as submodule
++        from . import winner as submodule
+     elif args.command == 'yield_plot':
+-        import yield_plot as submodule
++        from . import yield_plot as submodule
+     elif args.command == 'index':
+-        import index as submodule
++        from . import index as submodule
+     elif args.command == 'organise':
+-        import organise as submodule
++        from . import organise as submodule
+ 
+     # run the chosen submodule.
+     submodule.run(parser, args)
+@@ -57,7 +57,7 @@
+ class ArgumentParserWithDefaults(argparse.ArgumentParser):
+     def __init__(self, *args, **kwargs):
+         super(ArgumentParserWithDefaults, self).__init__(*args, **kwargs)
+-      self.add_argument("-q", "--quiet", help="Do not output warnings to 
stderr",
++        self.add_argument("-q", "--quiet", help="Do not output warnings to 
stderr",
+                         action="store_true",
+                         dest="quiet")
+ 
+@@ -526,12 +526,16 @@
+     #######################################################
+     args = parser.parse_args()
+ 
++    if not args.command:
++        parser.print_help()
++        sys.exit(0)
++
+     if args.quiet:
+         logger.setLevel(logging.ERROR)
+ 
+     try:
+       args.func(parser, args)
+-    except IOError, e:
++    except IOError as e:
+          if e.errno != 32:  # ignore SIGPIPE
+              raise
+ 
+Index: poretools-0.6.0+dfsg/poretools/combine.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/combine.py
++++ poretools-0.6.0+dfsg/poretools/combine.py
+@@ -1,6 +1,6 @@
+ import tarfile
+ import sys
+-import Fast5File
++from . import Fast5File
+ 
+ #logging
+ import logging
+Index: poretools-0.6.0+dfsg/poretools/hist.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/hist.py
++++ poretools-0.6.0+dfsg/poretools/hist.py
+@@ -6,7 +6,7 @@
+ from matplotlib import pyplot as plt
+ 
+ import seaborn as sns
+-import Fast5File
++from . import Fast5File
+ 
+ import logging
+ logger = logging.getLogger('poretools')
+Index: poretools-0.6.0+dfsg/poretools/organise.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/organise.py
++++ poretools-0.6.0+dfsg/poretools/organise.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ import sys
+ import os
+ from os import makedirs
+Index: poretools-0.6.0+dfsg/poretools/qual_v_pos.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/qual_v_pos.py
++++ poretools-0.6.0+dfsg/poretools/qual_v_pos.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ from collections import defaultdict
+ import pandas
+ import matplotlib.pyplot as plt
+Index: poretools-0.6.0+dfsg/poretools/squiggle.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/squiggle.py
++++ poretools-0.6.0+dfsg/poretools/squiggle.py
+@@ -10,7 +10,7 @@
+ import logging
+ logger = logging.getLogger('poretools')
+ 
+-import Fast5File
++from . import Fast5File
+ 
+ def plot_squiggle(args, filename, start_times, mean_signals):
+     """
+@@ -70,7 +70,7 @@
+ 
+     fast5_set = Fast5File.Fast5FileSet(args.files)
+ 
+-    first_fast5 = fast5_set.next()
++    first_fast5 = next(fast5_set)
+     for fast5 in fast5_set:
+         # only create a squiggle plot for multiple reads if saving to file.
+         if args.saveas is None:
+Index: poretools-0.6.0+dfsg/poretools/yield_plot.py
+===================================================================
+--- poretools-0.6.0+dfsg.orig/poretools/yield_plot.py
++++ poretools-0.6.0+dfsg/poretools/yield_plot.py
+@@ -1,4 +1,4 @@
+-import Fast5File
++from . import Fast5File
+ import matplotlib
+ #matplotlib.use('Agg') # Must be called before any other matplotlib calls
+ from matplotlib import pyplot as plt
+@@ -25,16 +25,16 @@
+         # compute the cumulative based on reads or total base pairs
+         if args.plot_type == 'reads':
+                 y_label = "Total reads"
+-                cumulative = np.cumsum(range(len(start_times)))
++                cumulative = np.cumsum(list(range(len(start_times))))
+         elif args.plot_type == 'basepairs':
+                 y_label = "Total base pairs"
+                 cumulative = np.cumsum(read_lengths)
+ 
+         step = args.skip
+         # make a data frame of the lists
+-        d = {'start': [start_times[n] for n in xrange(0, len(start_times), 
step)],
+-             'lengths': [read_lengths[n] for n in xrange(0, 
len(read_lengths), step)],
+-             'cumul': [cumulative[n] for n in xrange(0, len(cumulative), 
step)]}
++        d = {'start': [start_times[n] for n in range(0, len(start_times), 
step)],
++             'lengths': [read_lengths[n] for n in range(0, len(read_lengths), 
step)],
++             'cumul': [cumulative[n] for n in range(0, len(cumulative), 
step)]}
+         df = pd.DataFrame(d)
+ 
+         if args.savedf:
diff -Nru poretools-0.6.0+dfsg/debian/patches/series 
poretools-0.6.0+dfsg/debian/patches/series
--- poretools-0.6.0+dfsg/debian/patches/series  1969-12-31 16:00:00.000000000 
-0800
+++ poretools-0.6.0+dfsg/debian/patches/series  2019-08-15 09:24:04.000000000 
-0700
@@ -0,0 +1 @@
+python3.patch
diff -Nru poretools-0.6.0+dfsg/debian/rules poretools-0.6.0+dfsg/debian/rules
--- poretools-0.6.0+dfsg/debian/rules   2018-07-19 00:48:29.000000000 -0700
+++ poretools-0.6.0+dfsg/debian/rules   2019-08-15 09:24:04.000000000 -0700
@@ -6,4 +6,4 @@
 export PYBUILD_DESTDIR=debian/poretools
 
 %:
-       dh $@ --with python2 --buildsystem=pybuild
+       dh $@ --with python3 --buildsystem=pybuild

Reply via email to