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.langasek@ubuntu.com>
Last-Modified: 2019-08-15
Bug-Debian: https://bugs.debian.org/934845

--- a/setup.py
+++ b/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'
 """
--- a/poretools/__init__.py
+++ b/poretools/__init__.py
@@ -1,5 +1,4 @@
 import os
 import sys
-import scripts
-from Fast5File import *
-from version import __version__
+from . import scripts
+from .version import __version__
--- a/poretools/Fast5File.py
+++ b/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")
--- a/poretools/formats.py
+++ b/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
 
 
--- a/poretools/times.py
+++ b/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,8 +29,8 @@
 				read_length = 0
 
 			lt = localtime(start_time)
-			print "\t".join([fast5.get_channel_number(),
-				fast5.filename, 
+			print("\t".join([str(fast5.get_channel_number()),
+				str(fast5.filename),
 				str(read_length),
 				str(fast5.get_exp_start_time()),
 				str(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()
--- a/poretools/events.py
+++ b/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()
 
--- a/poretools/qualdist.py
+++ b/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)]))
--- a/poretools/metadata.py
+++ b/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()
--- a/poretools/fastq.py
+++ b/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()
 
--- a/poretools/occupancy.py
+++ b/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':
--- a/poretools/index.py
+++ b/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()
--- a/poretools/readstats.py
+++ b/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()
--- a/poretools/winner.py
+++ b/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)
 
--- a/poretools/stats.py
+++ b/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")
--- a/poretools/nucdist.py
+++ b/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)]))
--- a/poretools/tabular.py
+++ b/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()
--- a/poretools/fasta.py
+++ b/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()
 
--- a/poretools/statistics.py
+++ b/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
--- a/poretools/poretools_main.py
+++ b/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
 
--- a/poretools/combine.py
+++ b/poretools/combine.py
@@ -1,6 +1,6 @@
 import tarfile
 import sys
-import Fast5File
+from . import Fast5File
 
 #logging
 import logging
--- a/poretools/hist.py
+++ b/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')
--- a/poretools/organise.py
+++ b/poretools/organise.py
@@ -1,4 +1,4 @@
-import Fast5File
+from . import Fast5File
 import sys
 import os
 from os import makedirs
--- a/poretools/qual_v_pos.py
+++ b/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
--- a/poretools/squiggle.py
+++ b/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:
--- a/poretools/yield_plot.py
+++ b/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:
