From 360af2f75cc41a9f0782cfdba3991b463a7c330a Mon Sep 17 00:00:00 2001 From: Marshall Perrin Date: Wed, 15 Aug 2018 21:28:56 -0400 Subject: [PATCH] Remove more Python 2-isms; part of #262 --- poppy/dms.py | 3 +- poppy/fresnel.py | 1 - poppy/fwcentroid.py | 2 - poppy/instrument.py | 8 +- poppy/matrixDFT.py | 2 - poppy/misc.py | 1 - poppy/optics.py | 1 - poppy/physical_wavefront.py | 1 - poppy/poppy_core.py | 15 ++- poppy/special_prop.py | 1 - poppy/utils.py | 23 ++--- poppy/vendor/__init__.py | 0 poppy/vendor/lru_cache.py | 198 ------------------------------------ poppy/wfe.py | 2 - poppy/zernike.py | 20 +--- 15 files changed, 24 insertions(+), 254 deletions(-) delete mode 100644 poppy/vendor/__init__.py delete mode 100644 poppy/vendor/lru_cache.py diff --git a/poppy/dms.py b/poppy/dms.py index 9d4c2d9f..71d86e18 100644 --- a/poppy/dms.py +++ b/poppy/dms.py @@ -3,7 +3,6 @@ import numpy as np import matplotlib.pyplot as plt -import six import scipy.ndimage.interpolation import scipy.signal import astropy.io.fits as fits @@ -87,7 +86,7 @@ def __init__(self, dm_shape=(10, 10), actuator_spacing=None, if self.include_actuator_print_through: self._load_actuator_surface_file(actuator_print_through_file) - if isinstance(influence_func, six.string_types): + if isinstance(influence_func, str): self.influence_type = "from file" self._load_influence_fn(filename=influence_func) elif isinstance(influence_func, fits.HDUList): diff --git a/poppy/fresnel.py b/poppy/fresnel.py index 1a778185..ea817a32 100644 --- a/poppy/fresnel.py +++ b/poppy/fresnel.py @@ -1,4 +1,3 @@ -from __future__ import division import numpy as np import matplotlib.pyplot as plt import astropy.units as u diff --git a/poppy/fwcentroid.py b/poppy/fwcentroid.py index 9126ecb2..89ac4cca 100644 --- a/poppy/fwcentroid.py +++ b/poppy/fwcentroid.py @@ -22,8 +22,6 @@ M. Perrin, 2011-02-17, based on IDL code by Jeff Valenti et al. """ -from __future__ import (absolute_import, division, print_function, unicode_literals) - import numpy as np diff --git a/poppy/instrument.py b/poppy/instrument.py index c3d18b1b..33c0001a 100644 --- a/poppy/instrument.py +++ b/poppy/instrument.py @@ -1,4 +1,3 @@ -from __future__ import (absolute_import, division, print_function, unicode_literals) import getpass import os import platform @@ -10,7 +9,6 @@ import numpy as np import scipy.interpolate import scipy.ndimage -import six import warnings try: @@ -428,7 +426,7 @@ def _get_fits_header(self, result, options): __version__ = '' # --- update FITS header, display, and output. - if isinstance(self.pupil, six.string_types): + if isinstance(self.pupil, str): pupilstr = os.path.basename(self.pupil) elif isinstance(self.pupil, fits.HDUList): pupilstr = 'pupil from supplied FITS HDUList object' @@ -438,7 +436,7 @@ def _get_fits_header(self, result, options): if self.pupilopd is None: opdstring = "NONE - perfect telescope! " - elif isinstance(self.pupilopd, six.string_types): + elif isinstance(self.pupilopd, str): opdstring = os.path.basename(self.pupilopd) elif isinstance(self.pupilopd, fits.HDUList): opdstring = 'OPD from supplied FITS HDUlist object' @@ -559,7 +557,7 @@ def _get_optical_system(self, fft_oversample=2, detector_oversample=None, fov_ar full_opd_path = self.pupilopd if os.path.exists(self.pupilopd) else os.path.join(self._datapath, "OPD", self.pupilopd) elif hasattr(self.pupilopd, '__getitem__') and isinstance(self.pupilopd[0], - six.string_types): # tuple with filename and slice + str): # tuple with filename and slice full_opd_path = ( self.pupilopd[0] if os.path.exists(self.pupilopd[0]) else os.path.join(self._datapath, "OPD", self.pupilopd[0]), diff --git a/poppy/matrixDFT.py b/poppy/matrixDFT.py index 69c63313..bb8ef9dd 100644 --- a/poppy/matrixDFT.py +++ b/poppy/matrixDFT.py @@ -40,8 +40,6 @@ PEP8 formatting pass (except variable names)-- J. Long """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) __all__ = ['MatrixFourierTransform'] diff --git a/poppy/misc.py b/poppy/misc.py index cc4f79aa..ae7d1e5f 100644 --- a/poppy/misc.py +++ b/poppy/misc.py @@ -3,7 +3,6 @@ # Airy functions for comparison's sake # ############################################################################ -from __future__ import (absolute_import, division, print_function, unicode_literals) import numpy as np import scipy diff --git a/poppy/optics.py b/poppy/optics.py index 9fd7af0e..655f19ce 100644 --- a/poppy/optics.py +++ b/poppy/optics.py @@ -1,4 +1,3 @@ -from __future__ import (absolute_import, division, print_function, unicode_literals) import numpy as np import scipy.special import scipy.ndimage.interpolation diff --git a/poppy/physical_wavefront.py b/poppy/physical_wavefront.py index 92f21a45..363592d9 100644 --- a/poppy/physical_wavefront.py +++ b/poppy/physical_wavefront.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division import numpy as np import scipy.constants as const import astropy.units as u diff --git a/poppy/poppy_core.py b/poppy/poppy_core.py index 87ed5569..fa114a33 100644 --- a/poppy/poppy_core.py +++ b/poppy/poppy_core.py @@ -1,4 +1,3 @@ -from __future__ import (absolute_import, division, print_function, unicode_literals) import multiprocessing import copy import time @@ -6,8 +5,6 @@ import warnings import textwrap -import six - import numpy as np import matplotlib.pyplot as plt import scipy.ndimage.interpolation @@ -1144,7 +1141,7 @@ def add_pupil(self, optic=None, function=None, index=None, **kwargs): # OpticalElement object provided. # We can use it directly, but make sure the plane type is set. optic.planetype = PlaneType.pupil - elif isinstance(optic, six.string_types): + elif isinstance(optic, str): # convenience code to instantiate objects from a string name. raise NotImplementedError('Setting optics based on strings is now deprecated.') elif optic is None and len(kwargs) > 0: # create image from files specified in kwargs @@ -1204,7 +1201,7 @@ def add_image(self, optic=None, function=None, index=None, **kwargs): """ - if isinstance(optic, six.string_types): + if isinstance(optic, str): function = optic optic = None @@ -2286,7 +2283,7 @@ def __init__(self, name="unnamed optic", transmission=None, opd=None, opdunits=N else: # load transmission file. if transmission is not None: - if isinstance(transmission, six.string_types): + if isinstance(transmission, str): self.amplitude_file = transmission self.amplitude, self.amplitude_header = fits.getdata(self.amplitude_file, header=True) self.amplitude = self.amplitude.astype('=f8') # ensure native byte order, see #213 @@ -2331,7 +2328,7 @@ def __init__(self, name="unnamed optic", transmission=None, opd=None, opdunits=N if self.name == 'unnamed optic': self.name = 'OPD from supplied fits.HDUList object' _log.info(self.name + ": Loaded OPD from supplied fits.HDUList object") - elif isinstance(opd, six.string_types): + elif isinstance(opd, str): # load from regular FITS filename self.opd_file = opd self.opd, self.opd_header = fits.getdata(self.opd_file, header=True) @@ -2339,7 +2336,7 @@ def __init__(self, name="unnamed optic", transmission=None, opd=None, opdunits=N if self.name == 'unnamed optic': self.name = 'OPD from ' + self.opd_file _log.info(self.name + ": Loaded OPD from " + self.opd_file) - elif len(opd) == 2 and isinstance(opd[0], six.string_types): + elif len(opd) == 2 and isinstance(opd[0], str): # if OPD is specified as a 2-element iterable, treat the first element as the filename # and 2nd as the slice of a cube. self.opd_file = opd[0] @@ -2490,7 +2487,7 @@ def _find_pixelscale_in_headers(keywords, headers): ('PIXELSCL', 'PUPLSCAL',), (self.amplitude_header, self.opd_header) ) - elif isinstance(pixelscale, six.string_types): + elif isinstance(pixelscale, str): # If provided as a keyword string, check for it using the same helper function _log.debug(" Getting pixel scale from FITS keyword:" + pixelscale) _, self.pixelscale = _find_pixelscale_in_headers( diff --git a/poppy/special_prop.py b/poppy/special_prop.py index b548ab3d..50106632 100644 --- a/poppy/special_prop.py +++ b/poppy/special_prop.py @@ -1,7 +1,6 @@ # Specialized optical system propagators # In particular for efficient modeling of astronomical coronagraphs -from __future__ import (absolute_import, division, print_function, unicode_literals) import numpy as np import time import logging diff --git a/poppy/utils.py b/poppy/utils.py index 54a2da99..69e87937 100644 --- a/poppy/utils.py +++ b/poppy/utils.py @@ -4,8 +4,6 @@ # These provide various utilities to measure the PSF's properties in certain ways, display it on screen etc. # -from __future__ import (absolute_import, division, print_function, unicode_literals) - import json import logging import os.path @@ -16,7 +14,6 @@ import numpy as np import scipy.interpolate import scipy.ndimage -import six import warnings from astropy import config @@ -148,7 +145,7 @@ def display_psf(HDUlist_or_filename, ext=0, vmin=1e-7, vmax=1e-1, meaning it is taken from matplotlib's `image.interpolation` rcParam. """ - if isinstance(HDUlist_or_filename, six.string_types): + if isinstance(HDUlist_or_filename, str): hdulist = fits.open(HDUlist_or_filename) elif isinstance(HDUlist_or_filename, fits.HDUList): hdulist = HDUlist_or_filename @@ -180,7 +177,7 @@ def display_psf(HDUlist_or_filename, ext=0, vmin=1e-7, vmax=1e-1, norm = matplotlib.colors.LogNorm(vmin=vmin, vmax=vmax) psf_array_shape = hdulist[ext].data.shape - if isinstance(pixelscale, six.string_types): + if isinstance(pixelscale, str): pixelscale = hdulist[ext].header[pixelscale] halffov_x = pixelscale * psf_array_shape[1] / 2.0 halffov_y = pixelscale * psf_array_shape[0] / 2.0 @@ -316,13 +313,13 @@ def display_psf_difference(hdulist_or_filename1=None, HDUlist_or_filename2=None, the difference image. Mutually exclusive to `normalize`. (Default: False) """ - if isinstance(hdulist_or_filename1, six.string_types): + if isinstance(hdulist_or_filename1, str): hdulist1 = fits.open(hdulist_or_filename1) elif isinstance(hdulist_or_filename1, fits.HDUList): hdulist1 = hdulist_or_filename1 else: raise ValueError("input must be a filename or HDUlist") - if isinstance(HDUlist_or_filename2, six.string_types): + if isinstance(HDUlist_or_filename2, str): hdulist2 = fits.open(HDUlist_or_filename2) elif isinstance(HDUlist_or_filename2, fits.HDUList): hdulist2 = HDUlist_or_filename2 @@ -416,7 +413,7 @@ def display_ee(HDUlist_or_filename=None, ext=0, overplot=False, ax=None, mark_le Default is True """ - if isinstance(HDUlist_or_filename, six.string_types): + if isinstance(HDUlist_or_filename, str): hdu_list = fits.open(HDUlist_or_filename) elif isinstance(HDUlist_or_filename, fits.HDUList): hdu_list = HDUlist_or_filename @@ -459,7 +456,7 @@ def display_profiles(HDUlist_or_filename=None, ext=0, overplot=False, title=None Title for plot """ - if isinstance(HDUlist_or_filename, six.string_types): + if isinstance(HDUlist_or_filename, str): hdu_list = fits.open(HDUlist_or_filename, ext=ext) elif isinstance(HDUlist_or_filename, fits.HDUList): hdu_list = HDUlist_or_filename @@ -540,7 +537,7 @@ def radial_profile(hdulist_or_filename=None, ext=0, ee=False, center=None, stdde so you should use (radius+binsize/2) for the radius of the EE curve if you want to be as precise as possible. """ - if isinstance(hdulist_or_filename, six.string_types): + if isinstance(hdulist_or_filename, str): hdu_list = fits.open(hdulist_or_filename) elif isinstance(hdulist_or_filename, fits.HDUList): hdu_list = hdulist_or_filename @@ -791,7 +788,7 @@ def measure_fwhm(HDUlist_or_filename, ext=0, center=None, plot=False, threshold= """ from astropy.modeling import models, fitting - if isinstance(HDUlist_or_filename, six.string_types): + if isinstance(HDUlist_or_filename, str): HDUlist = fits.open(HDUlist_or_filename) elif isinstance(HDUlist_or_filename, fits.HDUList): HDUlist = HDUlist_or_filename @@ -928,7 +925,7 @@ def measure_sharpness(HDUlist_or_filename=None, ext=0): Same as above """ - if isinstance(HDUlist_or_filename, six.string_types): + if isinstance(HDUlist_or_filename, str): HDUlist = fits.open(HDUlist_or_filename) elif isinstance(HDUlist_or_filename, fits.HDUList): HDUlist = HDUlist_or_filename @@ -981,7 +978,7 @@ def measure_centroid(HDUlist_or_filename=None, ext=0, slice=0, boxsize=20, verbo """ from .fwcentroid import fwcentroid - if isinstance(HDUlist_or_filename, six.string_types): + if isinstance(HDUlist_or_filename, str): HDUlist = fits.open(HDUlist_or_filename) elif isinstance(HDUlist_or_filename, fits.HDUList): HDUlist = HDUlist_or_filename diff --git a/poppy/vendor/__init__.py b/poppy/vendor/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/poppy/vendor/lru_cache.py b/poppy/vendor/lru_cache.py deleted file mode 100644 index 53d6c58c..00000000 --- a/poppy/vendor/lru_cache.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -Py2.6+ and Py3.0+ backport of Python 3.3's LRU Cache (Python recipe) -Full featured backport from Python 3.3. It passes the 3.3 test suite. - -Full-featured O(1) LRU cache backported from Python3.3. The full Py3.3 API is supported (thread -safety, maxsize, keyword args, type checking, __wrapped__, and cache_info). Includes Py3.3 -optimizations for better memory utilization, fewer dependencies, and fewer dict lookups. - -http://code.activestate.com/recipes/578078-py26-and-py30-backport-of-python-33s-lru-cache/ -Created by Raymond Hettinger on Sat, 17 Mar 2012 - -The MIT License (MIT) - -Copyright (c) 2012 Raymond Hettinger - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -""" - -from collections import namedtuple -from functools import update_wrapper -from threading import RLock - -_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"]) - -class _HashedSeq(list): - __slots__ = 'hashvalue' - - def __init__(self, tup, hash=hash): - self[:] = tup - self.hashvalue = hash(tup) - - def __hash__(self): - return self.hashvalue - -def _make_key(args, kwds, typed, - kwd_mark = (object(),), - fasttypes = {int, str, frozenset, type(None)}, - sorted=sorted, tuple=tuple, type=type, len=len): - 'Make a cache key from optionally typed positional and keyword arguments' - key = args - if kwds: - sorted_items = sorted(kwds.items()) - key += kwd_mark - for item in sorted_items: - key += item - if typed: - key += tuple(type(v) for v in args) - if kwds: - key += tuple(type(v) for k, v in sorted_items) - elif len(key) == 1 and type(key[0]) in fasttypes: - return key[0] - return _HashedSeq(key) - -def lru_cache(maxsize=100, typed=False): - """Least-recently-used cache decorator. - - If *maxsize* is set to None, the LRU features are disabled and the cache - can grow without bound. - - If *typed* is True, arguments of different types will be cached separately. - For example, f(3.0) and f(3) will be treated as distinct calls with - distinct results. - - Arguments to the cached function must be hashable. - - View the cache statistics named tuple (hits, misses, maxsize, currsize) with - f.cache_info(). Clear the cache and statistics with f.cache_clear(). - Access the underlying function with f.__wrapped__. - - See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used - - """ - - # Users should only access the lru_cache through its public API: - # cache_info, cache_clear, and f.__wrapped__ - # The internals of the lru_cache are encapsulated for thread safety and - # to allow the implementation to change (including a possible C version). - - def decorating_function(user_function): - - cache = dict() - stats = [0, 0] # make statistics updateable non-locally - HITS, MISSES = 0, 1 # names for the stats fields - make_key = _make_key - cache_get = cache.get # bound method to lookup key or return None - _len = len # localize the global len() function - lock = RLock() # because linkedlist updates aren't threadsafe - root = [] # root of the circular doubly linked list - root[:] = [root, root, None, None] # initialize by pointing to self - nonlocal_root = [root] # make updateable non-locally - PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields - - if maxsize == 0: - - def wrapper(*args, **kwds): - # no caching, just do a statistics update after a successful call - result = user_function(*args, **kwds) - stats[MISSES] += 1 - return result - - elif maxsize is None: - - def wrapper(*args, **kwds): - # simple caching without ordering or size limit - key = make_key(args, kwds, typed) - result = cache_get(key, root) # root used here as a unique not-found sentinel - if result is not root: - stats[HITS] += 1 - return result - result = user_function(*args, **kwds) - cache[key] = result - stats[MISSES] += 1 - return result - - else: - - def wrapper(*args, **kwds): - # size limited caching that tracks accesses by recency - key = make_key(args, kwds, typed) if kwds or typed else args - with lock: - link = cache_get(key) - if link is not None: - # record recent use of the key by moving it to the front of the list - root, = nonlocal_root - link_prev, link_next, key, result = link - link_prev[NEXT] = link_next - link_next[PREV] = link_prev - last = root[PREV] - last[NEXT] = root[PREV] = link - link[PREV] = last - link[NEXT] = root - stats[HITS] += 1 - return result - result = user_function(*args, **kwds) - with lock: - root, = nonlocal_root - if key in cache: - # getting here means that this same key was added to the - # cache while the lock was released. since the link - # update is already done, we need only return the - # computed result and update the count of misses. - pass - elif _len(cache) >= maxsize: - # use the old root to store the new key and result - oldroot = root - oldroot[KEY] = key - oldroot[RESULT] = result - # empty the oldest link and make it the new root - root = nonlocal_root[0] = oldroot[NEXT] - oldkey = root[KEY] - oldvalue = root[RESULT] - root[KEY] = root[RESULT] = None - # now update the cache dictionary for the new links - del cache[oldkey] - cache[key] = oldroot - else: - # put result in a new link at the front of the list - last = root[PREV] - link = [last, root, key, result] - last[NEXT] = root[PREV] = cache[key] = link - stats[MISSES] += 1 - return result - - def cache_info(): - """Report cache statistics""" - with lock: - return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache)) - - def cache_clear(): - """Clear the cache and cache statistics""" - with lock: - cache.clear() - root = nonlocal_root[0] - root[:] = [root, root, None, None] - stats[:] = [0, 0] - - wrapper.__wrapped__ = user_function - wrapper.cache_info = cache_info - wrapper.cache_clear = cache_clear - return update_wrapper(wrapper, user_function) - - return decorating_function diff --git a/poppy/wfe.py b/poppy/wfe.py index 17d30765..4eefb783 100644 --- a/poppy/wfe.py +++ b/poppy/wfe.py @@ -11,8 +11,6 @@ """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) import collections from functools import wraps import numpy as np diff --git a/poppy/zernike.py b/poppy/zernike.py index a82e8890..0698333b 100644 --- a/poppy/zernike.py +++ b/poppy/zernike.py @@ -1,5 +1,3 @@ -from __future__ import division - """ Zernike & Related Polynomials @@ -22,7 +20,6 @@ Mahajan and Dai, 2006. Optics Letters Vol 31, 16, p 2462: """ -import six import inspect from math import factorial import numpy as np @@ -34,10 +31,7 @@ from poppy.poppy_core import Wavefront -if sys.version_info > (3, 2): - from functools import lru_cache -else: - from poppy.vendor.lru_cache import lru_cache +from functools import lru_cache __all__ = [ 'R', 'cached_zernike1', 'hex_aperture', 'hexike_basis', 'noll_indices', @@ -1065,9 +1059,7 @@ def opd_expand_nonorthonormal(opd, aperture=None, nterms=15, basis=zernike_basis # If so, append that into the function's kwargs. This check is needed to # handle e.g. both the zernike_basis function (which doesn't accept aperture) # and hexike_basis or arbitrary_basis (which do). - # How to do this check is annoyingly version-dependent. - if ((six.PY2 and 'aperture' in inspect.getargspec(basis).args) or - (six.PY3 and 'aperture' in inspect.signature(basis).parameters)): + if 'aperture' in inspect.signature(basis).parameters: kwargs['aperture'] = aperture basis_set = basis( @@ -1129,9 +1121,7 @@ def opd_from_zernikes(coeffs, basis=zernike_basis_faster, aperture=None, outside # If so, append that into the function's kwargs. This check is needed to # handle e.g. both the zernike_basis function (which doesn't accept aperture) # and hexike_basis or arbitrary_basis (which do). - # How to do this check is annoyingly version-dependent. - if ((six.PY2 and 'aperture' in inspect.getargspec(basis).args) or - (six.PY3 and 'aperture' in inspect.signature(basis).parameters)): + if 'aperture' in inspect.signature(basis).parameters: kwargs['aperture'] = aperture basis_set = basis( @@ -1225,9 +1215,7 @@ def opd_expand_segments(opd, aperture=None, nterms=15, basis=None, # If so, append that into the function's kwargs. This check is needed to # handle e.g. both the zernike_basis function (which doesn't accept aperture) # and hexike_basis or arbitrary_basis (which do). - # How to do this check is annoyingly version-dependent. - if ((six.PY2 and 'aperture' in inspect.getargspec(basis).args) or - (six.PY3 and 'aperture' in inspect.signature(basis).parameters)): + if 'aperture' in inspect.signature(basis).parameters: kwargs['aperture'] = aperture basis_set = basis(