Skip to content

Commit

Permalink
Merge 1dc2c13 into 0463d46
Browse files Browse the repository at this point in the history
  • Loading branch information
cdeil committed Oct 21, 2019
2 parents 0463d46 + 1dc2c13 commit e264961
Show file tree
Hide file tree
Showing 58 changed files with 129 additions and 306 deletions.
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ matrix:

# Try older numpy versions
- env: PYTHON_VERSION=3.6
NUMPY_VERSION=1.11
- env: PYTHON_VERSION=3.5
NUMPY_VERSION=1.10
ASTROPY_VERSION=3.0
NUMPY_VERSION=1.16

# Do a PEP8 test with pycodestyle
- env: MAIN_CMD='pycodestyle regions --count' SETUP_CMD=''
Expand Down
9 changes: 4 additions & 5 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ Installation

The regions package requires the following packages:

* Python 2.7 or 3.4 and above
* `Numpy <http://www.numpy.org>`_ 1.9 or later
* `Astropy <http://www.astropy.org>`__ 1.3 or later
* `six <http://pypi.python.org/pypi/six/>`__
* Python 3.6 or later
* `Numpy <http://www.numpy.org>`_ 1.16 or later
* `Astropy <http://www.astropy.org>`__ 2.0 or later

In addition, the following packages are needed for optional functionality:

* `Matplotlib <https://matplotlib.org>`__ 1.5 or later
* `Matplotlib <https://matplotlib.org>`__ 2.0 or later

Stable version
==============
Expand Down
4 changes: 0 additions & 4 deletions regions/_geometry/circular_overlap.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
The functions defined here allow one to determine the exact area of
overlap of a rectangle and a circle (written by Thomas Robitaille).
"""

from __future__ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
cimport numpy as np

Expand Down
7 changes: 0 additions & 7 deletions regions/_geometry/core.pyx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# cython: language_level=3
"""The functions here are the core geometry functions."""

from __future__ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
cimport numpy as np


__all__ = ['elliptical_overlap_grid']


cdef extern from "math.h":

double asin(double x)
Expand Down
4 changes: 0 additions & 4 deletions regions/_geometry/elliptical_overlap.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ The approach is to divide the rectangle into two triangles, and
reproject these so that the ellipse is a unit circle, then compute the
intersection of a triangle with a unit circle.
"""

from __future__ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
cimport numpy as np

Expand Down
3 changes: 0 additions & 3 deletions regions/_geometry/polygonal_overlap.pyx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# cython: language_level=3
from __future__ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
cimport numpy as np

Expand Down
3 changes: 0 additions & 3 deletions regions/_geometry/rectangular_overlap.pyx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# cython: language_level=3
from __future__ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
cimport numpy as np

Expand Down
2 changes: 0 additions & 2 deletions regions/_geometry/tests/test_circular_overlap_grid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import itertools

from numpy.testing import assert_allclose
Expand Down
2 changes: 0 additions & 2 deletions regions/_geometry/tests/test_elliptical_overlap_grid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import itertools

from numpy.testing import assert_allclose
Expand Down
2 changes: 0 additions & 2 deletions regions/_geometry/tests/test_rectangular_overlap_grid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import itertools

from numpy.testing import assert_allclose
Expand Down
5 changes: 2 additions & 3 deletions regions/_utils/examples.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
from astropy.utils import lazyproperty
from astropy.io import fits
Expand Down Expand Up @@ -61,10 +60,10 @@ def make_example_dataset(data='simulated', config=None):
elif data == 'fermi':
return ExampleDatasetFermi(config=config)
else:
raise ValueError('Invalid selection data: {}'.format(data))
raise ValueError(f'Invalid selection data: {data}')


class ExampleDataset(object):
class ExampleDataset:
"""Base class for example dataset.
"""

Expand Down
1 change: 0 additions & 1 deletion regions/_utils/tests/test_examples.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
from numpy.testing import assert_allclose
from ..examples import make_example_dataset
Expand Down
10 changes: 4 additions & 6 deletions regions/_utils/wcs_helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# (taken from photutils: should probably migrate into astropy.wcs)
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
from astropy import units as u
from astropy.coordinates import UnitSphericalRepresentation
Expand Down Expand Up @@ -77,10 +76,9 @@ def assert_angle_or_pixel(name, q):
if q.unit.physical_type == 'angle' or q.unit is u.pixel:
pass
else:
raise ValueError("{0} should have angular or pixel "
"units".format(name))
raise ValueError(f"{name} should have angular or pixel units")
else:
raise TypeError("{0} should be a Quantity instance".format(name))
raise TypeError(f"{name} should be a Quantity instance")


def assert_angle(name, q):
Expand All @@ -91,6 +89,6 @@ def assert_angle(name, q):
if q.unit.physical_type == 'angle':
pass
else:
raise ValueError("{0} should have angular units".format(name))
raise ValueError(f"{name} should have angular units")
else:
raise TypeError("{0} should be a Quantity instance".format(name))
raise TypeError(f"{name} should be a Quantity instance")
31 changes: 11 additions & 20 deletions regions/core/attributes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst

import abc
import six
import weakref

from astropy.coordinates import SkyCoord
from astropy.units import Quantity
Expand All @@ -21,8 +19,7 @@
"""


@six.add_metaclass(abc.ABCMeta)
class RegionAttr(object):
class RegionAttr(abc.ABC):
"""Descriptor base class"""
def __init__(self, name):
self.name = name
Expand Down Expand Up @@ -52,8 +49,7 @@ class ScalarPix(RegionAttr):

def _validate(self, value):
if not (isinstance(value, PixCoord) and value.isscalar):
raise ValueError('The {} must be a 0D PixCoord object'
.format(self.name))
raise ValueError(f'The {self.name} must be a 0D PixCoord object')


class OneDPix(RegionAttr):
Expand All @@ -65,8 +61,7 @@ class OneDPix(RegionAttr):
def _validate(self, value):
if not (isinstance(value, PixCoord) and not value.isscalar
and value.x.ndim == 1):
raise ValueError('The {} must be a 1D PixCoord object'
.format(self.name))
raise ValueError(f'The {self.name} must be a 1D PixCoord object')


class ScalarLength(RegionAttr):
Expand All @@ -78,7 +73,7 @@ class ScalarLength(RegionAttr):
def _validate(self, value):
if not np.isscalar(value):
raise ValueError(
'The {} must be a scalar numpy/python number'.format(self.name))
f'The {self.name} must be a scalar numpy/python number')


class ScalarSky(RegionAttr):
Expand Down Expand Up @@ -113,8 +108,7 @@ class QuantityLength(RegionAttr):

def _validate(self, value):
if not (isinstance(value, Quantity) and value.isscalar):
raise ValueError('The {} must be a scalar astropy Quantity object'
.format(self.name))
raise ValueError(f'The {self.name} must be a scalar astropy Quantity object')


class CompoundRegionPix(RegionAttr):
Expand All @@ -125,8 +119,7 @@ class CompoundRegionPix(RegionAttr):

def _validate(self, value):
if not isinstance(value, PixelRegion):
raise ValueError('The {} must be a PixelRegion object'
.format(self.name))
raise ValueError(f'The {self.name} must be a PixelRegion object')


class CompoundRegionSky(RegionAttr):
Expand All @@ -137,16 +130,14 @@ class CompoundRegionSky(RegionAttr):

def _validate(self, value):
if not isinstance(value, SkyRegion):
raise ValueError('The {} must be a SkyRegion object'
.format(self.name))
raise ValueError(f'The {self.name} must be a SkyRegion object')


@six.add_metaclass(abc.ABCMeta)
class Meta(dict):

def __init__(self, seq=None, **kwargs):

super(Meta, self).__init__()
super().__init__()

if seq:
if isinstance(seq, dict):
Expand All @@ -163,14 +154,14 @@ def __init__(self, seq=None, **kwargs):
def __setitem__(self, key, value):
key = self.key_mapping.get(key, key)
if key in self.valid_keys:
super(Meta, self).__setitem__(key, value)
super().__setitem__(key, value)
else:
raise KeyError(
"{} is not a valid key for this class.".format(key))
f"{key} is not a valid key for this class.")

def __getitem__(self, item):
item = self.key_mapping.get(item, item)
return super(Meta, self).__getitem__(item)
return super().__getitem__(item)


class RegionMeta(Meta):
Expand Down
5 changes: 1 addition & 4 deletions regions/core/bounding_box.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import (absolute_import, division, print_function,
unicode_literals)

import numpy as np
from astropy.io.fits.util import _is_int


__all__ = ['BoundingBox']


class BoundingBox(object):
class BoundingBox:
"""
A rectangular bounding box in integer (not float) pixel indices.
Expand Down
2 changes: 0 additions & 2 deletions regions/core/compound.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import absolute_import, division, print_function, unicode_literals

import operator as op

import numpy as np
Expand Down
57 changes: 9 additions & 48 deletions regions/core/core.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import abc
import six
import copy
import operator
import inspect
Expand All @@ -28,44 +25,8 @@
VALID_MASK_MODES = {'center', 'exact', 'subpixels'}


class MetaRegion(abc.ABCMeta):
"""
This is a sub metaclass of `abc.ABCMeta` that makes methods of a class
automatically have their docstrings filled in from the methods they override
in the base class.
If the class uses multiple inheritance, the docstring will be
chosen from the first class in the bases list, in the same way as
methods are normally resolved in Python. If this results in
selecting the wrong docstring, the docstring will need to be
explicitly included on the method.
"""

def __init__(cls, name, bases, dct):
def is_public_member(key):
return (
(key.startswith('__') and key.endswith('__')
and len(key) > 4) or
not key.startswith('_'))

for key, val in six.iteritems(dct):
if (inspect.isfunction(val) and is_public_member(key)
and val.__doc__ is None):
for base in cls.__mro__[1:]:
super_method = getattr(base, key, None)
if super_method is not None:
val.__doc__ = super_method.__doc__
break

super(MetaRegion, cls).__init__(name, bases, dct)


@six.add_metaclass(MetaRegion)
class Region(object):
"""
Base class for all regions.
"""
class Region(abc.ABC):
"""Base class for all regions."""

def copy(self, **changes):
"""Make an independent (deep) copy."""
Expand All @@ -81,19 +42,19 @@ def __repr__(self):
params = []
if self._params is not None:
for key in self._params:
params.append('{0}={1}'.format(key.replace("_", " "),
params.append('{}={}'.format(key.replace("_", " "),
getattr(self, key)))
params = ', '.join(params)

return '<{0}({1})>'.format(self.__class__.__name__, params)
return f'<{self.__class__.__name__}({params})>'

def __str__(self):
cls_info = [('Region', self.__class__.__name__)]
if self._params is not None:
params_value = [(x.replace("_", " "), getattr(self, x))
for x in self._params]
cls_info += params_value
fmt = ['{0}: {1}'.format(key, val) for key, val in cls_info]
fmt = [f'{key}: {val}' for key, val in cls_info]

return '\n'.join(fmt)

Expand Down Expand Up @@ -172,7 +133,7 @@ def contains(self, pixcoord):

def __contains__(self, coord):
if not coord.isscalar:
raise ValueError('coord must be scalar. coord={}'.format(coord))
raise ValueError(f'coord must be scalar. coord={coord}')
return self.contains(coord)

@abc.abstractmethod
Expand Down Expand Up @@ -234,11 +195,11 @@ def to_mask(self, mode='center', subpixels=5):
@staticmethod
def _validate_mode(mode, subpixels):
if mode not in VALID_MASK_MODES:
raise ValueError("Invalid mask mode: {0} (should be one "
"of {1})".format(mode, '/'.join(VALID_MASK_MODES)))
raise ValueError("Invalid mask mode: {} (should be one "
"of {})".format(mode, '/'.join(VALID_MASK_MODES)))
if mode == 'subpixels':
if not isinstance(subpixels, int) or subpixels <= 0:
raise ValueError("Invalid subpixels value: {0} (should be"
raise ValueError("Invalid subpixels value: {} (should be"
" a strictly positive integer)".format(subpixels))

@abc.abstractmethod
Expand Down

0 comments on commit e264961

Please sign in to comment.