Index: src/sas/sascalc/data_util/calcthread.py
===================================================================
--- src/sas/sascalc/data_util/calcthread.py	(revision a1b8fee73528559155793dd74cda07d0c32e9d72)
+++ src/sas/sascalc/data_util/calcthread.py	(revision 574adc767a9e86744546f8edd6a23dc4f81914ad)
@@ -6,16 +6,19 @@
 from __future__ import print_function
 
-import thread
 import traceback
 import sys
 import logging
+try:
+    import _thread as thread
+except ImportError: # CRUFT: python 2 support
+    import thread
 
 if sys.platform.count("darwin") > 0:
     import time
     stime = time.time()
-    
+
     def clock():
         return time.time() - stime
-    
+
     def sleep(t):
         return time.sleep(t)
@@ -35,5 +38,5 @@
     CalcThread.__init__, passing it the keyword arguments for
     yieldtime, worktime, update and complete.
-    
+
     When defining the compute() method you need to include code which
     allows the GUI to run.  They are as follows: ::
@@ -211,5 +214,5 @@
             self._lock.release()
             self._time_for_update += 1e6  # No more updates
-            
+
             self.updatefn(**kwargs)
             sleep(self.yieldtime)
Index: src/sas/sascalc/data_util/nxsunit.py
===================================================================
--- src/sas/sascalc/data_util/nxsunit.py	(revision 8e9536f96bb3931f62eeba158ab01e1a3a25ded7)
+++ src/sas/sascalc/data_util/nxsunit.py	(revision 574adc767a9e86744546f8edd6a23dc4f81914ad)
@@ -13,5 +13,5 @@
 in the NeXus definition files.
 
-Unlike other units packages, this package does not carry the units along with 
+Unlike other units packages, this package does not carry the units along with
 the value but merely provides a conversion function for transforming values.
 
@@ -68,5 +68,5 @@
     Ack! Allows, e.g., Coulomb and coulomb even though Coulomb is not
     a unit because some NeXus files store it that way!
-    
+
     Returns a dictionary of names and scales.
     """
@@ -78,10 +78,10 @@
                         n=1e-9,p=1e-12,f=1e-15)
     map = {abbr:1}
-    map.update([(P+abbr,scale) for (P,scale) in short_prefix.iteritems()])
+    map.update([(P+abbr,scale) for (P,scale) in short_prefix.items()])
     for name in [unit,unit.capitalize()]:
         map.update({name:1,name+'s':1})
-        map.update([(P+name,scale) for (P,scale) in prefix.iteritems()])
-        map.update([(P+'*'+name,scale) for (P,scale) in prefix.iteritems()])
-        map.update([(P+name+'s',scale) for (P,scale) in prefix.iteritems()])
+        map.update([(P+name,scale) for (P,scale) in prefix.items()])
+        map.update([(P+'*'+name,scale) for (P,scale) in prefix.items()])
+        map.update([(P+name+'s',scale) for (P,scale) in prefix.items()])
     return map
 
@@ -91,6 +91,6 @@
     """
     map = {}
-    map.update([(name,scale) for name,scale in kw.iteritems()])
-    map.update([(name+'s',scale) for name,scale in kw.iteritems()])
+    map.update([(name,scale) for name,scale in kw.items()])
+    map.update([(name+'s',scale) for name,scale in kw.items()])
     return map
 
@@ -101,6 +101,6 @@
     * WARNING * this will incorrect transform 10^3 to 103.
     """
-    s.update((k.replace('^',''),v) 
-             for k,v in s.items()
+    s.update((k.replace('^',''),v)
+             for k, v in list(s.items())
              if '^' in k)
 
@@ -130,10 +130,10 @@
     temperature.update(_build_metric_units('Celcius', 'C'))
     temperature.update(_build_metric_units('celcius', 'C'))
-    
+
     charge = _build_metric_units('coulomb','C')
     charge.update({'microAmp*hour':0.0036})
 
     sld = { '10^-6 Angstrom^-2': 1e-6, 'Angstrom^-2': 1 }
-    Q = { 'invA': 1, 'invAng': 1, 'invAngstroms': 1, '1/A': 1, 
+    Q = { 'invA': 1, 'invAng': 1, 'invAngstroms': 1, '1/A': 1,
           '10^-3 Angstrom^-1': 1e-3, '1/cm': 1e-8, '1/m': 1e-10,
           'nm^-1': 0.1, '1/nm': 0.1, 'n_m^-1': 0.1 }
@@ -189,5 +189,6 @@
 
 def _check(expect,get):
-    if expect != get: raise ValueError, "Expected %s but got %s"%(expect,get)
+    if expect != get:
+        raise ValueError("Expected %s but got %s"%(expect, get))
      #print expect,"==",get
 
@@ -202,7 +203,10 @@
     _check(123,Converter('a.u.')(123,units='s')) # arbitrary units always returns the same value
     _check(123,Converter('a.u.')(123,units='')) # arbitrary units always returns the same value
-    try: Converter('help')
-    except KeyError: pass
-    else: raise Exception("unknown unit did not raise an error")
+    try:
+        Converter('help')
+    except KeyError:
+        pass
+    else:
+        raise Exception("unknown unit did not raise an error")
 
     # TODO: more tests
Index: src/sas/sascalc/data_util/odict.py
===================================================================
--- src/sas/sascalc/data_util/odict.py	(revision b699768550de9d4b35b087234ec1d2a461922bab)
+++ src/sas/sascalc/data_util/odict.py	(revision 574adc767a9e86744546f8edd6a23dc4f81914ad)
@@ -39,15 +39,15 @@
     """
     A class of dictionary that keeps the insertion order of keys.
-    
+
     All appropriate methods return keys, items, or values in an ordered way.
-    
+
     All normal dictionary methods are available. Update and comparison is
     restricted to other OrderedDict objects.
-    
+
     Various sequence methods are available, including the ability to explicitly
     mutate the key ordering.
-    
+
     __contains__ tests:
-    
+
     >>> d = OrderedDict(((1, 3),))
     >>> 1 in d
@@ -55,7 +55,7 @@
     >>> 4 in d
     0
-    
+
     __getitem__ tests:
-    
+
     >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
     1
@@ -63,14 +63,14 @@
     Traceback (most recent call last):
     KeyError: 4
-    
+
     __len__ tests:
-    
+
     >>> len(OrderedDict())
     0
     >>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
     3
-    
+
     get tests:
-    
+
     >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
     >>> d.get(1)
@@ -82,7 +82,7 @@
     >>> d
     OrderedDict([(1, 3), (3, 2), (2, 1)])
-    
+
     has_key tests:
-    
+
     >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
     >>> d.has_key(1)
@@ -96,9 +96,9 @@
         Create a new ordered dictionary. Cannot init from a normal dict,
         nor from kwargs, since items order is undefined in those cases.
-        
+
         If the ``strict`` keyword argument is ``True`` (``False`` is the
         default) then when doing slice assignment - the ``OrderedDict`` you are
         assigning from *must not* contain any keys in the remaining dict.
-        
+
         >>> OrderedDict()
         OrderedDict([])
@@ -283,5 +283,5 @@
         """
         Used for __repr__ and __str__
-        
+
         >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
         >>> r1
@@ -321,5 +321,5 @@
         >>> d
         OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
-        
+
         >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
         >>> a[3] = 4
@@ -345,10 +345,10 @@
         >>> a
         OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
-        
+
         >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
         >>> d[:1] = 3
         Traceback (most recent call last):
         TypeError: slice assignment requires an OrderedDict
-        
+
         >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
         >>> d[:1] = OrderedDict([(9, 8)])
@@ -444,5 +444,5 @@
         """
         Implemented so that access to ``sequence`` raises a warning.
-        
+
         >>> d = OrderedDict()
         >>> d.sequence
@@ -463,5 +463,5 @@
         """
         To allow deepcopy to work with OrderedDict.
-        
+
         >>> from copy import deepcopy
         >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
@@ -490,7 +490,7 @@
     def items(self):
         """
-        ``items`` returns a list of tuples representing all the 
+        ``items`` returns a list of tuples representing all the
         ``(key, value)`` pairs in the dictionary.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.items()
@@ -505,5 +505,5 @@
         """
         Return a list of keys in the ``OrderedDict``.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.keys()
@@ -515,8 +515,8 @@
         """
         Return a list of all the values in the OrderedDict.
-        
+
         Optionally you can pass in a list of values, which will replace the
         current list. The value list must be the same len as the OrderedDict.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.values()
@@ -596,5 +596,5 @@
         """
         No dict.pop in Python 2.2, gotta reimplement it
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.pop(3)
@@ -612,5 +612,5 @@
         """
         if len(args) > 1:
-            raise TypeError, ('pop expected at most 2 arguments, got %s' %
+            raise TypeError('pop expected at most 2 arguments, got %s' %
                 (len(args) + 1))
         if key in self:
@@ -628,5 +628,5 @@
         Delete and return an item specified by index, not a random one as in
         dict. The index is -1 by default (the last item).
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.popitem()
@@ -674,5 +674,5 @@
         """
         Update from another OrderedDict or sequence of (key, value) pairs
-        
+
         >>> d = OrderedDict(((1, 0), (0, 1)))
         >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
@@ -706,9 +706,9 @@
         """
         Rename the key for a given value, without modifying sequence order.
-        
+
         For the case where new_key already exists this raise an exception,
         since if new_key exists, it is ambiguous as to what happens to the
         associated values, and the position of new_key in the sequence.
-        
+
         >>> od = OrderedDict()
         >>> od['a'] = 1
@@ -732,5 +732,5 @@
             raise ValueError("New key already exists: %r" % new_key)
         # rename sequence entry
-        value = self[old_key] 
+        value = self[old_key]
         old_idx = self._sequence.index(old_key)
         self._sequence[old_idx] = new_key
@@ -742,8 +742,8 @@
         """
         This method allows you to set the items in the dict.
-        
+
         It takes a list of tuples - of the same sort returned by the ``items``
         method.
-        
+
         >>> d = OrderedDict()
         >>> d.setitems(((3, 1), (2, 3), (1, 2)))
@@ -760,8 +760,8 @@
         replace the current set. This must contain the same set of keys, but
         need not be in the same order.
-        
+
         If you pass in new keys that don't match, a ``KeyError`` will be
         raised.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.keys()
@@ -791,7 +791,7 @@
         You can pass in a list of values, which will replace the
         current list. The value list must be the same len as the OrderedDict.
-        
+
         (Or a ``ValueError`` is raised.)
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.setvalues((1, 2, 3))
@@ -813,5 +813,5 @@
         """
         Return the position of the specified key in the OrderedDict.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.index(3)
@@ -826,8 +826,8 @@
         """
         Takes ``index``, ``key``, and ``value`` as arguments.
-        
+
         Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
         the OrderedDict.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.insert(0, 4, 0)
@@ -850,5 +850,5 @@
         """
         Reverse the order of the OrderedDict.
-        
+
         >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
         >>> d.reverse()
@@ -861,8 +861,8 @@
         """
         Sort the key order in the OrderedDict.
-        
+
         This method takes the same arguments as the ``list.sort`` method on
         your version of Python.
-        
+
         >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
         >>> d.sort()
@@ -876,5 +876,5 @@
     """
     Custom object for accessing the keys of an OrderedDict.
-    
+
     Can be called like the normal ``OrderedDict.keys`` method, but also
     supports indexing and sequence methods.
@@ -897,5 +897,5 @@
         You cannot assign to keys, but you can do slice assignment to re-order
         them.
-        
+
         You can only do slice assignment if the new set of keys is a reordering
         of the original set.
@@ -967,5 +967,5 @@
     """
     Custom object for accessing the items of an OrderedDict.
-    
+
     Can be called like the normal ``OrderedDict.items`` method, but also
     supports indexing and sequence methods.
@@ -1077,5 +1077,5 @@
     """
     Custom object for accessing the values of an OrderedDict.
-    
+
     Can be called like the normal ``OrderedDict.values`` method, but also
     supports indexing and sequence methods.
@@ -1099,5 +1099,5 @@
         """
         Set the value at position i to value.
-        
+
         You can only do slice assignment to values if you supply a sequence of
         equal length to the slice you are replacing.
@@ -1168,10 +1168,10 @@
     Experimental version of OrderedDict that has a custom object for ``keys``,
     ``values``, and ``items``.
-    
+
     These are callable sequence objects that work as methods, or can be
     manipulated directly as sequences.
-    
+
     Test for ``keys``, ``items`` and ``values``.
-    
+
     >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
     >>> d
@@ -1293,5 +1293,5 @@
     >>> d
     SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
-    
+
     >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
     >>> d
Index: src/sas/sascalc/data_util/uncertainty.py
===================================================================
--- src/sas/sascalc/data_util/uncertainty.py	(revision 9a5097cd1c76689d1f997b85ba43d12a95d8f243)
+++ src/sas/sascalc/data_util/uncertainty.py	(revision 574adc767a9e86744546f8edd6a23dc4f81914ad)
@@ -2,10 +2,10 @@
 Uncertainty propagation class for arithmetic, log and exp.
 
-Based on scalars or numpy vectors, this class allows you to store and 
+Based on scalars or numpy vectors, this class allows you to store and
 manipulate values+uncertainties, with propagation of gaussian error for
 addition, subtraction, multiplication, division, power, exp and log.
 
 Storage properties are determined by the numbers used to set the value
-and uncertainty.  Be sure to use floating point uncertainty vectors 
+and uncertainty.  Be sure to use floating point uncertainty vectors
 for inplace operations since numpy does not do automatic type conversion.
 Normal operations can use mixed integer and floating point.  In place
@@ -18,6 +18,7 @@
 
 import numpy as np
-import err1d
-from formatnum import format_uncertainty
+
+from .import err1d
+from .formatnum import format_uncertainty
 
 __all__ = ['Uncertainty']
@@ -28,5 +29,5 @@
     # Make standard deviation available
     def _getdx(self): return np.sqrt(self.variance)
-    def _setdx(self,dx): 
+    def _setdx(self,dx):
         # Direct operation
         #    variance = dx**2
@@ -38,10 +39,10 @@
     # Constructor
     def __init__(self, x, variance=None):
-        self.x, self.variance = x, variance    
- 
+        self.x, self.variance = x, variance
+
     # Numpy array slicing operations
-    def __len__(self): 
+    def __len__(self):
         return len(self.x)
-    def __getitem__(self,key): 
+    def __getitem__(self,key):
         return Uncertainty(self.x[key],self.variance[key])
     def __setitem__(self,key,value):
@@ -137,5 +138,5 @@
     def __idiv__(self, other): return self.__itruediv__(other)
 
-        
+
     # Unary ops
     def __neg__(self):
@@ -151,5 +152,5 @@
             return format_uncertainty(self.x,np.sqrt(self.variance))
         else:
-            return [format_uncertainty(v,dv) 
+            return [format_uncertainty(v,dv)
                     for v,dv in zip(self.x,np.sqrt(self.variance))]
     def __repr__(self):
@@ -219,5 +220,5 @@
     z = a/4
     assert z.x == 5./4 and z.variance == 3./4**2
-    
+
     # Reverse scalar operations
     z = 4+a
@@ -229,5 +230,5 @@
     z = 4/a
     assert z.x == 4./5 and abs(z.variance - 3./5**4 * 4**2) < 1e-15
-    
+
     # Power operations
     z = a**2
@@ -250,5 +251,5 @@
     assert z.x == 5./4 and abs(z.variance - (3./5**2 + 2./4**2)*(5./4)**2) < 1e-15
 
-    # ===== Inplace operations =====    
+    # ===== Inplace operations =====
     # Scalar operations
     y = a+0; y += 4
@@ -308,5 +309,5 @@
     assert (z.x == 5./4).all()
     assert (abs(z.variance - (3./5**2 + 2./4**2)*(5./4)**2) < 1e-15).all()
-    
+
     # printing; note that sqrt(3) ~ 1.7
     assert str(Uncertainty(5,3)) == "5.0(17)"
