diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 4d4b5ef..a636f5e 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -22,11 +22,6 @@ jobs: strategy: matrix: include: - - name: Code style checks - os: ubuntu-latest - python: 3.x - toxenv: codestyle - - name: Python 3.10 with minimal dependencies os: ubuntu-latest python: '3.10' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..319bd61 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +ci: + autofix_prs: false + autoupdate_schedule: 'monthly' + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + args: ["--enforce-all", "--maxkb=300"] + exclude: "^(\ + cextern/wcslib/C/flexed/.*|\ + CHANGES.rst|\ + )$" + # Prevent giant files from being committed. + - id: check-case-conflict + # Check for files with names that would conflict on a case-insensitive + # filesystem like MacOS HFS+ or Windows FAT. + - id: check-json + # Attempts to load all json files to verify syntax. + - id: check-merge-conflict + # Check for files that contain merge conflict strings. + - id: check-symlinks + # Checks for symlinks which do not point to anything. + - id: check-toml + # Attempts to load all TOML files to verify syntax. + - id: check-xml + # Attempts to load all xml files to verify syntax. + - id: check-yaml + # Attempts to load all yaml files to verify syntax. + exclude: ".*(.github.*)$" + - id: detect-private-key + # Checks for the existence of private keys. + - id: end-of-file-fixer + # Makes sure files end in a newline and only a newline. + exclude: ".*(data.*|extern.*|licenses.*|_static.*|_parsetab.py)$" + # - id: fix-encoding-pragma # covered by pyupgrade + - id: trailing-whitespace + # Trims trailing whitespace. + exclude_types: [python] # Covered by Ruff W291. + exclude: ".*(data.*|extern.*|licenses.*|_static.*)$" + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-directive-colons + # Detect mistake of rst directive not ending with double colon. + - id: rst-inline-touching-normal + # Detect mistake of inline code touching normal text in rst. + - id: text-unicode-replacement-char + # Forbid files which have a UTF-8 Unicode replacement character. + + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + args: ["--write-changes"] + additional_dependencies: + - tomli + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.6 + hooks: + - id: ruff + args: ["--fix", "--show-fixes"] + - id: ruff-format diff --git a/astropy_healpix/__init__.py b/astropy_healpix/__init__.py index f6dd708..0023891 100644 --- a/astropy_healpix/__init__.py +++ b/astropy_healpix/__init__.py @@ -7,7 +7,7 @@ # Packages may add whatever they like to this file, but # should keep this content at the top. # ---------------------------------------------------------------------------- -from ._astropy_init import * # noqa +from ._astropy_init import * # noqa # ---------------------------------------------------------------------------- from .high_level import * # noqa diff --git a/astropy_healpix/_astropy_init.py b/astropy_healpix/_astropy_init.py index bd45324..fa5b5c7 100644 --- a/astropy_healpix/_astropy_init.py +++ b/astropy_healpix/_astropy_init.py @@ -1,13 +1,14 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst import os -__all__ = ['__version__', 'test'] +__all__ = ["__version__", "test"] try: from .version import version as __version__ except ImportError: - __version__ = '' + __version__ = "" # Create the test function for self test from astropy.tests.runner import TestRunner + test = TestRunner.make_test_runner_in(os.path.dirname(__file__)) diff --git a/astropy_healpix/bench.py b/astropy_healpix/bench.py index 7036cb1..1170460 100644 --- a/astropy_healpix/bench.py +++ b/astropy_healpix/bench.py @@ -32,7 +32,7 @@ # Copied from https://github.com/kwgoodman/bottleneck/blob/master/bottleneck/benchmark/autotimeit.py -def autotimeit(stmt, setup='pass', repeat=3, mintime=0.2): +def autotimeit(stmt, setup="pass", repeat=3, mintime=0.2): timer = timeit.Timer(stmt, setup) number, time1 = autoscaler(timer, mintime) time2 = timer.repeat(repeat=repeat - 1, number=number) @@ -47,89 +47,105 @@ def autoscaler(timer, mintime): if time > mintime: return number, time number *= 10 - raise RuntimeError('function is too fast to test') + raise RuntimeError("function is too fast to test") def get_import(package, function): - if package == 'astropy_healpix': - return f'from astropy_healpix.healpy import {function}' + if package == "astropy_healpix": + return f"from astropy_healpix.healpy import {function}" else: - return f'from healpy import {function}' + return f"from healpy import {function}" def bench_pix2ang(size=None, nside=None, nest=None, package=None, fast=False): - setup = '\n'.join([ - get_import(package, 'pix2ang'), - 'import numpy as np', - f'nside={nside}', - f'ipix=(np.random.random({size}) * 12 * nside ** 2).astype(np.int64)', - f'nest={nest}']) - - stmt = 'pix2ang(nside, ipix, nest)' + setup = "\n".join( + [ + get_import(package, "pix2ang"), + "import numpy as np", + f"nside={nside}", + f"ipix=(np.random.random({size}) * 12 * nside ** 2).astype(np.int64)", + f"nest={nest}", + ] + ) + + stmt = "pix2ang(nside, ipix, nest)" return autotimeit(stmt=stmt, setup=setup, repeat=1, mintime=0 if fast else 0.1) def bench_ang2pix(size=None, nside=None, nest=None, package=None, fast=False): - setup = '\n'.join([ - get_import(package, 'ang2pix'), - 'import numpy as np', - f'nside={nside}', - f'lon=360 * np.random.random({size})', - f'lat=180 * np.random.random({size}) - 90', - f'nest={nest}']) - - stmt = 'ang2pix(nside, lon, lat, nest, lonlat=True)' + setup = "\n".join( + [ + get_import(package, "ang2pix"), + "import numpy as np", + f"nside={nside}", + f"lon=360 * np.random.random({size})", + f"lat=180 * np.random.random({size}) - 90", + f"nest={nest}", + ] + ) + + stmt = "ang2pix(nside, lon, lat, nest, lonlat=True)" return autotimeit(stmt=stmt, setup=setup, repeat=1, mintime=0 if fast else 0.1) def bench_nest2ring(size=None, nside=None, package=None, fast=False): - setup = '\n'.join([ - get_import(package, 'nest2ring'), - 'import numpy as np', - f'nside={nside}', - f'ipix=(np.random.random({size}) * 12 * nside ** 2).astype(np.int64)']) + setup = "\n".join( + [ + get_import(package, "nest2ring"), + "import numpy as np", + f"nside={nside}", + f"ipix=(np.random.random({size}) * 12 * nside ** 2).astype(np.int64)", + ] + ) - stmt = 'nest2ring(nside, ipix)' + stmt = "nest2ring(nside, ipix)" return autotimeit(stmt=stmt, setup=setup, repeat=1, mintime=0 if fast else 0.1) def bench_ring2nest(size=None, nside=None, package=None, fast=False): - setup = '\n'.join([ - get_import(package, 'ring2nest'), - 'import numpy as np', - f'nside={nside}', - f'ipix=(np.random.random({size}) * 12 * nside ** 2).astype(np.int64)']) + setup = "\n".join( + [ + get_import(package, "ring2nest"), + "import numpy as np", + f"nside={nside}", + f"ipix=(np.random.random({size}) * 12 * nside ** 2).astype(np.int64)", + ] + ) - stmt = 'ring2nest(nside, ipix)' + stmt = "ring2nest(nside, ipix)" return autotimeit(stmt=stmt, setup=setup, repeat=1, mintime=0 if fast else 0.1) -def bench_get_interp_weights(size=None, nside=None, nest=None, package=None, fast=False): - setup = '\n'.join([ - get_import(package, 'get_interp_weights'), - 'import numpy as np', - f'nside={nside}', - f'lon=360 * np.random.random({size})', - f'lat=180 * np.random.random({size}) - 90', - f'nest={nest}']) +def bench_get_interp_weights( + size=None, nside=None, nest=None, package=None, fast=False +): + setup = "\n".join( + [ + get_import(package, "get_interp_weights"), + "import numpy as np", + f"nside={nside}", + f"lon=360 * np.random.random({size})", + f"lat=180 * np.random.random({size}) - 90", + f"nest={nest}", + ] + ) - stmt = 'get_interp_weights(nside, lon, lat, nest=nest, lonlat=True)' + stmt = "get_interp_weights(nside, lon, lat, nest=nest, lonlat=True)" return autotimeit(stmt=stmt, setup=setup, repeat=1, mintime=0 if fast else 0.1) def run_single(name, benchmark, fast=False, **kwargs): - - time_self = benchmark(package='astropy_healpix', fast=fast, **kwargs) + time_self = benchmark(package="astropy_healpix", fast=fast, **kwargs) results_single = dict(function=name, time_self=time_self, **kwargs) if HEALPY_INSTALLED: - time_healpy = bench_ang2pix(package='healpy', fast=fast, **kwargs) - results_single['time_healpy'] = time_healpy + time_healpy = bench_ang2pix(package="healpy", fast=fast, **kwargs) + results_single["time_healpy"] = time_healpy return results_single @@ -146,31 +162,60 @@ def bench_run(fast=False): for nest in [True, False]: for size in SIZES: for nside in [1, 128]: - results.append(run_single('pix2ang', bench_pix2ang, fast=fast, - size=size, nside=nside, nest=nest)) + results.append( + run_single( + "pix2ang", + bench_pix2ang, + fast=fast, + size=size, + nside=nside, + nest=nest, + ) + ) for nest in [True, False]: for size in SIZES: for nside in [1, 128]: - results.append(run_single('ang2pix', bench_ang2pix, fast=fast, - size=size, nside=nside, nest=nest)) + results.append( + run_single( + "ang2pix", + bench_ang2pix, + fast=fast, + size=size, + nside=nside, + nest=nest, + ) + ) for size in SIZES: for nside in [1, 128]: - results.append(run_single('nest2ring', bench_nest2ring, fast=fast, - size=size, nside=nside)) + results.append( + run_single( + "nest2ring", bench_nest2ring, fast=fast, size=size, nside=nside + ) + ) for size in SIZES: for nside in [1, 128]: - results.append(run_single('ring2nest', bench_ring2nest, fast=fast, - size=size, nside=nside)) + results.append( + run_single( + "ring2nest", bench_ring2nest, fast=fast, size=size, nside=nside + ) + ) for nest in [True, False]: for size in SIZES: for nside in [1, 128]: - results.append(run_single('get_interp_weights', bench_get_interp_weights, - fast=fast, size=size, - nside=nside, nest=nest)) + results.append( + run_single( + "get_interp_weights", + bench_get_interp_weights, + fast=fast, + size=size, + nside=nside, + nest=nest, + ) + ) return results @@ -178,28 +223,38 @@ def bench_run(fast=False): def bench_report(results): """Print a report for given benchmark results to the console.""" - table = Table(names=['function', 'nest', 'nside', 'size', - 'time_healpy', 'time_self', 'ratio'], - dtype=['S20', bool, int, int, float, float, float], masked=True) + table = Table( + names=[ + "function", + "nest", + "nside", + "size", + "time_healpy", + "time_self", + "ratio", + ], + dtype=["S20", bool, int, int, float, float, float], + masked=True, + ) for row in results: table.add_row(row) - table['time_self'].format = '10.7f' + table["time_self"].format = "10.7f" if HEALPY_INSTALLED: - table['ratio'] = table['time_self'] / table['time_healpy'] - table['time_healpy'].format = '10.7f' - table['ratio'].format = '7.2f' + table["ratio"] = table["time_self"] / table["time_healpy"] + table["time_healpy"].format = "10.7f" + table["ratio"].format = "7.2f" table.pprint(max_lines=-1) def main(fast=False): """Run all benchmarks and print report to the console.""" - print('Running benchmarks...\n') + print("Running benchmarks...\n") results = bench_run(fast=fast) bench_report(results) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/astropy_healpix/conftest.py b/astropy_healpix/conftest.py index fa4d640..5439c62 100644 --- a/astropy_healpix/conftest.py +++ b/astropy_healpix/conftest.py @@ -13,6 +13,7 @@ try: from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS + ASTROPY_HEADER = True except ImportError: ASTROPY_HEADER = False @@ -27,24 +28,24 @@ def pytest_configure(config): """ if ASTROPY_HEADER: - config.option.astropy_header = True # Customize the following lines to add/remove entries from the list of # packages for which version numbers are displayed when running the tests. - PYTEST_HEADER_MODULES.pop('h5py', None) - PYTEST_HEADER_MODULES.pop('Pandas', None) - PYTEST_HEADER_MODULES['Astropy'] = 'astropy' - PYTEST_HEADER_MODULES['healpy'] = 'healpy' + PYTEST_HEADER_MODULES.pop("h5py", None) + PYTEST_HEADER_MODULES.pop("Pandas", None) + PYTEST_HEADER_MODULES["Astropy"] = "astropy" + PYTEST_HEADER_MODULES["healpy"] = "healpy" from . import __version__ + packagename = os.path.basename(os.path.dirname(__file__)) TESTED_VERSIONS[packagename] = __version__ # Set the Numpy print style to a fixed version to make doctest outputs # reproducible. try: - np.set_printoptions(legacy='1.13') + np.set_printoptions(legacy="1.13") except TypeError: # On older versions of Numpy, the unrecognized 'legacy' option will # raise a TypeError. diff --git a/astropy_healpix/core.py b/astropy_healpix/core.py index cf0c39b..389793c 100644 --- a/astropy_healpix/core.py +++ b/astropy_healpix/core.py @@ -9,23 +9,23 @@ from . import _core __all__ = [ - 'nside_to_pixel_area', - 'nside_to_pixel_resolution', - 'pixel_resolution_to_nside', - 'nside_to_npix', - 'npix_to_nside', - 'level_to_nside', - 'nside_to_level', - 'level_ipix_to_uniq', - 'uniq_to_level_ipix', - 'lonlat_to_healpix', - 'healpix_to_lonlat', - 'xyz_to_healpix', - 'healpix_to_xyz', - 'bilinear_interpolation_weights', - 'interpolate_bilinear_lonlat', - 'boundaries_lonlat', - 'neighbours', + "nside_to_pixel_area", + "nside_to_pixel_resolution", + "pixel_resolution_to_nside", + "nside_to_npix", + "npix_to_nside", + "level_to_nside", + "nside_to_level", + "level_ipix_to_uniq", + "uniq_to_level_ipix", + "lonlat_to_healpix", + "healpix_to_lonlat", + "xyz_to_healpix", + "healpix_to_xyz", + "bilinear_interpolation_weights", + "interpolate_bilinear_lonlat", + "boundaries_lonlat", + "neighbours", ] _NUMPY_COPY_IF_NEEDED = False if np.__version__.startswith("1.") else None @@ -35,10 +35,10 @@ def _validate_order(order): # We also support upper-case, to support directly the values # ORDERING = {'RING', 'NESTED'} in FITS headers # This is currently undocumented in the docstrings. - if order == 'nested' or order == 'NESTED': - return 'nested' - elif order == 'ring' or order == 'RING': - return 'ring' + if order == "nested" or order == "NESTED": + return "nested" + elif order == "ring" or order == "RING": + return "ring" else: raise ValueError("order must be 'nested' or 'ring'") @@ -46,23 +46,23 @@ def _validate_order(order): def _validate_offset(label, offset): offset = np.asarray(offset) if np.any((offset < 0) | (offset > 1)): - raise ValueError(f'd{label} must be in the range [0:1]') + raise ValueError(f"d{label} must be in the range [0:1]") def _validate_level(level): if np.any(level < 0): - raise ValueError('level must be positive') + raise ValueError("level must be positive") def _validate_nside(nside): log_2_nside = np.round(np.log2(nside)) - if not np.all(2 ** log_2_nside == nside): - raise ValueError('nside must be a power of two') + if not np.all(2**log_2_nside == nside): + raise ValueError("nside must be a power of two") def _validate_npix(level, ipix): - if not np.all(ipix < (3 << 2*(level + 1))): - raise ValueError('ipix for a specific level must be inferior to npix') + if not np.all(ipix < (3 << 2 * (level + 1))): + raise ValueError("ipix for a specific level must be inferior to npix") def level_to_nside(level): @@ -84,7 +84,7 @@ def level_to_nside(level): level = np.asarray(level, dtype=np.int64) _validate_level(level) - return 2 ** level + return 2**level def nside_to_level(nside): @@ -132,11 +132,11 @@ def uniq_to_level_ipix(uniq): """ uniq = np.asarray(uniq, dtype=np.int64) - level = (np.log2(uniq//4)) // 2 + level = (np.log2(uniq // 4)) // 2 level = level.astype(np.int64) _validate_level(level) - ipix = uniq - (1 << 2*(level + 1)) + ipix = uniq - (1 << 2 * (level + 1)) _validate_npix(level, ipix) return level, ipix @@ -166,7 +166,7 @@ def level_ipix_to_uniq(level, ipix): _validate_level(level) _validate_npix(level, ipix) - return ipix + (1 << 2*(level + 1)) + return ipix + (1 << 2 * (level + 1)) def nside_to_pixel_area(nside): @@ -215,7 +215,7 @@ def nside_to_pixel_resolution(nside): return (nside_to_pixel_area(nside) ** 0.5).to(u.arcmin) -def pixel_resolution_to_nside(resolution, round='nearest'): +def pixel_resolution_to_nside(resolution, round="nearest"): """Find closest HEALPix nside for a given angular resolution. This function is the inverse of `nside_to_pixel_resolution`, @@ -260,14 +260,14 @@ def pixel_resolution_to_nside(resolution, round='nearest'): # round the level and then go back to nside level = np.log2(nside) - if round == 'up': + if round == "up": level = np.ceil(level) - elif round == 'nearest': + elif round == "nearest": level = np.round(level) - elif round == 'down': + elif round == "down": level = np.floor(level) else: - raise ValueError(f'Invalid value for round: {round!r}') + raise ValueError(f"Invalid value for round: {round!r}") # For very low requested resolution (i.e. large angle values), we # return ``level=0``, i.e. ``nside=1``, i.e. the lowest resolution @@ -293,7 +293,7 @@ def nside_to_npix(nside): """ nside = np.asanyarray(nside, dtype=np.int64) _validate_nside(nside) - return 12 * nside ** 2 + return 12 * nside**2 def npix_to_nside(npix): @@ -315,16 +315,16 @@ def npix_to_nside(npix): npix = np.asanyarray(npix, dtype=np.int64) if not np.all(npix % 12 == 0): - raise ValueError('Number of pixels must be divisible by 12') + raise ValueError("Number of pixels must be divisible by 12") square_root = np.sqrt(npix / 12) - if not np.all(square_root ** 2 == npix / 12): - raise ValueError('Number of pixels is not of the form 12 * nside ** 2') + if not np.all(square_root**2 == npix / 12): + raise ValueError("Number of pixels is not of the form 12 * nside ** 2") return np.round(square_root).astype(int) -def healpix_to_lonlat(healpix_index, nside, dx=None, dy=None, order='ring'): +def healpix_to_lonlat(healpix_index, nside, dx=None, dy=None, order="ring"): """ Convert HEALPix indices (optionally with offsets) to longitudes/latitudes. @@ -353,7 +353,7 @@ def healpix_to_lonlat(healpix_index, nside, dx=None, dy=None, order='ring'): _validate_nside(nside) - if _validate_order(order) == 'ring': + if _validate_order(order) == "ring": func = _core.healpix_ring_to_lonlat else: # _validate_order(order) == 'nested' func = _core.healpix_nested_to_lonlat @@ -361,11 +361,11 @@ def healpix_to_lonlat(healpix_index, nside, dx=None, dy=None, order='ring'): if dx is None: dx = 0.5 else: - _validate_offset('x', dx) + _validate_offset("x", dx) if dy is None: dy = 0.5 else: - _validate_offset('y', dy) + _validate_offset("y", dy) nside = np.asarray(nside, dtype=np.intc) @@ -377,7 +377,7 @@ def healpix_to_lonlat(healpix_index, nside, dx=None, dy=None, order='ring'): return lon, lat -def lonlat_to_healpix(lon, lat, nside, return_offsets=False, order='ring'): +def lonlat_to_healpix(lon, lat, nside, return_offsets=False, order="ring"): """ Convert longitudes/latitudes to HEALPix indices @@ -404,7 +404,7 @@ def lonlat_to_healpix(lon, lat, nside, return_offsets=False, order='ring'): center of the HEALPix pixels """ - if _validate_order(order) == 'ring': + if _validate_order(order) == "ring": func = _core.lonlat_to_healpix_ring else: # _validate_order(order) == 'nested' func = _core.lonlat_to_healpix_nested @@ -422,7 +422,7 @@ def lonlat_to_healpix(lon, lat, nside, return_offsets=False, order='ring'): return healpix_index -def healpix_to_xyz(healpix_index, nside, dx=None, dy=None, order='ring'): +def healpix_to_xyz(healpix_index, nside, dx=None, dy=None, order="ring"): """ Convert HEALPix indices (optionally with offsets) to Cartesian coordinates. @@ -449,7 +449,7 @@ def healpix_to_xyz(healpix_index, nside, dx=None, dy=None, order='ring'): _validate_nside(nside) - if _validate_order(order) == 'ring': + if _validate_order(order) == "ring": func = _core.healpix_ring_to_xyz else: # _validate_order(order) == 'nested' func = _core.healpix_nested_to_xyz @@ -457,18 +457,18 @@ def healpix_to_xyz(healpix_index, nside, dx=None, dy=None, order='ring'): if dx is None: dx = 0.5 else: - _validate_offset('x', dx) + _validate_offset("x", dx) if dy is None: dy = 0.5 else: - _validate_offset('y', dy) + _validate_offset("y", dy) nside = np.asarray(nside, dtype=np.intc) return func(healpix_index, nside, dx, dy) -def xyz_to_healpix(x, y, z, nside, return_offsets=False, order='ring'): +def xyz_to_healpix(x, y, z, nside, return_offsets=False, order="ring"): """ Convert longitudes/latitudes to HEALPix indices @@ -494,7 +494,7 @@ def xyz_to_healpix(x, y, z, nside, return_offsets=False, order='ring'): center of the HEALPix pixels """ - if _validate_order(order) == 'ring': + if _validate_order(order) == "ring": func = _core.xyz_to_healpix_ring else: # _validate_order(order) == 'nested' func = _core.xyz_to_healpix_nested @@ -553,7 +553,7 @@ def ring_to_nested(ring_index, nside): return _core.ring_to_nested(ring_index, nside) -def bilinear_interpolation_weights(lon, lat, nside, order='ring'): +def bilinear_interpolation_weights(lon, lat, nside, order="ring"): """ Get the four neighbours for each (lon, lat) position and the weight associated with each one for bilinear interpolation. @@ -589,13 +589,13 @@ def bilinear_interpolation_weights(lon, lat, nside, order='ring'): indices = np.stack(result[:4]) weights = np.stack(result[4:]) - if _validate_order(order) == 'nested': + if _validate_order(order) == "nested": indices = ring_to_nested(indices, nside) return indices, weights -def interpolate_bilinear_lonlat(lon, lat, values, order='ring'): +def interpolate_bilinear_lonlat(lon, lat, values, order="ring"): """ Interpolate values at specific longitudes/latitudes using bilinear interpolation @@ -627,7 +627,7 @@ def interpolate_bilinear_lonlat(lon, lat, values, order='ring'): return result.sum(axis=0) -def neighbours(healpix_index, nside, order='ring'): +def neighbours(healpix_index, nside, order="ring"): """ Find all the HEALPix pixels that are the neighbours of a HEALPix pixel @@ -660,7 +660,7 @@ def neighbours(healpix_index, nside, order='ring'): nside = np.asarray(nside, dtype=np.intc) - if _validate_order(order) == 'ring': + if _validate_order(order) == "ring": func = _core.neighbours_ring else: # _validate_order(order) == 'nested' func = _core.neighbours_nested @@ -668,7 +668,7 @@ def neighbours(healpix_index, nside, order='ring'): return np.stack(func(healpix_index, nside)) -def healpix_cone_search(lon, lat, radius, nside, order='ring'): +def healpix_cone_search(lon, lat, radius, nside, order="ring"): """ Find all the HEALPix pixels within a given radius of a longitude/latitude. @@ -704,7 +704,7 @@ def healpix_cone_search(lon, lat, radius, nside, order='ring'): return _core.healpix_cone_search(lon, lat, radius, nside, order) -def boundaries_lonlat(healpix_index, step, nside, order='ring'): +def boundaries_lonlat(healpix_index, step, nside, order="ring"): """ Return the longitude and latitude of the edges of HEALPix pixels @@ -735,18 +735,20 @@ def boundaries_lonlat(healpix_index, step, nside, order='ring'): step = int(step) if step < 1: - raise ValueError('step must be at least 1') + raise ValueError("step must be at least 1") # PERF: this could be optimized by writing a Cython routine to do this to # avoid allocating temporary arrays - frac = np.linspace(0., 1., step + 1)[:-1] + frac = np.linspace(0.0, 1.0, step + 1)[:-1] dx = np.hstack([1 - frac, np.repeat(0, step), frac, np.repeat(1, step)]) dy = np.hstack([np.repeat(1, step), 1 - frac, np.repeat(0, step), frac]) healpix_index, dx, dy = np.broadcast_arrays(healpix_index.reshape(-1, 1), dx, dy) - lon, lat = healpix_to_lonlat(healpix_index.ravel(), nside, dx.ravel(), dy.ravel(), order=order) + lon, lat = healpix_to_lonlat( + healpix_index.ravel(), nside, dx.ravel(), dy.ravel(), order=order + ) lon = lon.reshape(-1, 4 * step) lat = lat.reshape(-1, 4 * step) diff --git a/astropy_healpix/healpy.py b/astropy_healpix/healpy.py index 4af20ae..5066133 100644 --- a/astropy_healpix/healpy.py +++ b/astropy_healpix/healpy.py @@ -5,34 +5,50 @@ import numpy as np from astropy import units as u -from astropy.coordinates.representation import CartesianRepresentation, UnitSphericalRepresentation - -from .core import (nside_to_pixel_resolution, nside_to_pixel_area, - nside_to_npix, npix_to_nside, nested_to_ring, ring_to_nested, - level_to_nside, lonlat_to_healpix, healpix_to_lonlat, - xyz_to_healpix, healpix_to_xyz, - boundaries_lonlat, bilinear_interpolation_weights, - interpolate_bilinear_lonlat, _NUMPY_COPY_IF_NEEDED) +from astropy.coordinates.representation import ( + CartesianRepresentation, + UnitSphericalRepresentation, +) + +from .core import ( + nside_to_pixel_resolution, + nside_to_pixel_area, + nside_to_npix, + npix_to_nside, + nested_to_ring, + ring_to_nested, + level_to_nside, + lonlat_to_healpix, + healpix_to_lonlat, + xyz_to_healpix, + healpix_to_xyz, + boundaries_lonlat, + bilinear_interpolation_weights, + interpolate_bilinear_lonlat, + _NUMPY_COPY_IF_NEEDED, +) RAD2DEG = 180 / np.pi PI_2 = np.pi / 2 -__all__ = ['nside2resol', - 'nside2pixarea', - 'nside2npix', - 'npix2nside', - 'pix2ang', - 'ang2pix', - 'pix2vec', - 'vec2pix', - 'order2nside', - 'nest2ring', - 'ring2nest', - 'boundaries', - 'vec2ang', - 'ang2vec', - 'get_interp_weights', - 'get_interp_val'] +__all__ = [ + "nside2resol", + "nside2pixarea", + "nside2npix", + "npix2nside", + "pix2ang", + "ang2pix", + "pix2vec", + "vec2pix", + "order2nside", + "nest2ring", + "ring2nest", + "boundaries", + "vec2ang", + "ang2vec", + "get_interp_weights", + "get_interp_val", +] def _lonlat_to_healpy(lon, lat, lonlat=False): @@ -61,7 +77,8 @@ def _healpy_to_lonlat(theta, phi, lonlat=False): lat = PI_2 - np.asarray(theta) lon = np.asarray(phi) return u.Quantity(lon, u.rad, copy=_NUMPY_COPY_IF_NEEDED), u.Quantity( - lat, u.rad, copy=_NUMPY_COPY_IF_NEEDED) + lat, u.rad, copy=_NUMPY_COPY_IF_NEEDED + ) def nside2resol(nside, arcmin=False): @@ -77,7 +94,7 @@ def nside2pixarea(nside, degrees=False): """Drop-in replacement for healpy `~healpy.pixelfunc.nside2pixarea`.""" area = nside_to_pixel_area(nside) if degrees: - return area.to(u.deg ** 2).value + return area.to(u.deg**2).value else: return area.to(u.sr).value @@ -99,24 +116,24 @@ def order2nside(order): def pix2ang(nside, ipix, nest=False, lonlat=False): """Drop-in replacement for healpy `~healpy.pixelfunc.pix2ang`.""" - lon, lat = healpix_to_lonlat(ipix, nside, order='nested' if nest else 'ring') + lon, lat = healpix_to_lonlat(ipix, nside, order="nested" if nest else "ring") return _lonlat_to_healpy(lon, lat, lonlat=lonlat) def ang2pix(nside, theta, phi, nest=False, lonlat=False): """Drop-in replacement for healpy `~healpy.pixelfunc.ang2pix`.""" lon, lat = _healpy_to_lonlat(theta, phi, lonlat=lonlat) - return lonlat_to_healpix(lon, lat, nside, order='nested' if nest else 'ring') + return lonlat_to_healpix(lon, lat, nside, order="nested" if nest else "ring") def pix2vec(nside, ipix, nest=False): """Drop-in replacement for healpy `~healpy.pixelfunc.pix2vec`.""" - return healpix_to_xyz(ipix, nside, order='nested' if nest else 'ring') + return healpix_to_xyz(ipix, nside, order="nested" if nest else "ring") def vec2pix(nside, x, y, z, nest=False): """Drop-in replacement for healpy `~healpy.pixelfunc.vec2pix`.""" - return xyz_to_healpix(x, y, z, nside, order='nested' if nest else 'ring') + return xyz_to_healpix(x, y, z, nside, order="nested" if nest else "ring") def nest2ring(nside, ipix): @@ -137,7 +154,7 @@ def boundaries(nside, pix, step=1, nest=False): if pix.ndim > 1: # For consistency with healpy we only support scalars or 1D arrays raise ValueError("Array has to be one dimensional") - lon, lat = boundaries_lonlat(pix, step, nside, order='nested' if nest else 'ring') + lon, lat = boundaries_lonlat(pix, step, nside, order="nested" if nest else "ring") rep_sph = UnitSphericalRepresentation(lon, lat) rep_car = rep_sph.to_cartesian().xyz.value.swapaxes(0, 1) if rep_car.shape[0] == 1: @@ -173,7 +190,9 @@ def get_interp_weights(nside, theta, phi=None, nest=False, lonlat=False): theta, phi = pix2ang(nside, ipix=theta, nest=nest) lon, lat = _healpy_to_lonlat(theta, phi, lonlat=lonlat) - return bilinear_interpolation_weights(lon, lat, nside, order='nested' if nest else 'ring') + return bilinear_interpolation_weights( + lon, lat, nside, order="nested" if nest else "ring" + ) def get_interp_val(m, theta, phi, nest=False, lonlat=False): @@ -181,4 +200,4 @@ def get_interp_val(m, theta, phi, nest=False, lonlat=False): Drop-in replacement for healpy `~healpy.pixelfunc.get_interp_val`. """ lon, lat = _healpy_to_lonlat(theta, phi, lonlat=lonlat) - return interpolate_bilinear_lonlat(lon, lat, m, order='nested' if nest else 'ring') + return interpolate_bilinear_lonlat(lon, lat, m, order="nested" if nest else "ring") diff --git a/astropy_healpix/high_level.py b/astropy_healpix/high_level.py index 3bbd434..8534f3e 100644 --- a/astropy_healpix/high_level.py +++ b/astropy_healpix/high_level.py @@ -2,27 +2,43 @@ import inspect import os -from astropy.coordinates import (BaseCoordinateFrame, frame_transform_graph, - SkyCoord, UnitSphericalRepresentation) - -from .core import (nside_to_pixel_area, nside_to_pixel_resolution, - nside_to_level, nside_to_npix, npix_to_nside, - healpix_to_lonlat, lonlat_to_healpix, - healpix_to_xyz, xyz_to_healpix, - bilinear_interpolation_weights, interpolate_bilinear_lonlat, - ring_to_nested, nested_to_ring, healpix_cone_search, - boundaries_lonlat, neighbours, _validate_order, - _NUMPY_COPY_IF_NEEDED) +from astropy.coordinates import ( + BaseCoordinateFrame, + frame_transform_graph, + SkyCoord, + UnitSphericalRepresentation, +) + +from .core import ( + nside_to_pixel_area, + nside_to_pixel_resolution, + nside_to_level, + nside_to_npix, + npix_to_nside, + healpix_to_lonlat, + lonlat_to_healpix, + healpix_to_xyz, + xyz_to_healpix, + bilinear_interpolation_weights, + interpolate_bilinear_lonlat, + ring_to_nested, + nested_to_ring, + healpix_cone_search, + boundaries_lonlat, + neighbours, + _validate_order, + _NUMPY_COPY_IF_NEEDED, +) from .utils import parse_input_healpix_data -__all__ = ['HEALPix'] +__all__ = ["HEALPix"] NO_FRAME_MESSAGE = """ No frame was specified when initializing HEALPix, so SkyCoord objects cannot be returned. Either specify a frame when initializing HEALPix or use the {0} method. -""".replace(os.linesep, ' ').strip() +""".replace(os.linesep, " ").strip() class NoFrameError(Exception): @@ -46,18 +62,22 @@ def _get_frame(frame): frame_cls = frame_transform_graph.lookup_name(frame) if frame_cls is None: frame_names = frame_transform_graph.get_names() - raise ValueError('Coordinate frame name "{}" is not a known ' - 'coordinate frame ({})' - .format(frame, sorted(frame_names))) + raise ValueError( + 'Coordinate frame name "{}" is not a known ' + "coordinate frame ({})".format(frame, sorted(frame_names)) + ) return frame_cls() elif inspect.isclass(frame) and issubclass(frame, BaseCoordinateFrame): return frame() else: - raise ValueError("Coordinate frame must be a frame name, frame " - "instance, frame class, or None, not a '{}'" - .format(frame.__class__.__name__)) + raise ValueError( + "Coordinate frame must be a frame name, frame " + "instance, frame class, or None, not a '{}'".format( + frame.__class__.__name__ + ) + ) class HEALPix: @@ -72,7 +92,7 @@ class HEALPix: Order of HEALPix pixels. Input string can be lower or upper case. frame : str or :class:`~astropy.coordinates.BaseCoordinateFrame`, optional The celestial coordinate frame of the pixellization. This can be - ommitted, in which case the pixellization will not be attached to any + omitted, in which case the pixellization will not be attached to any particular celestial frame, and the methods ending in _skycoord will not work (but the _lonlat methods will still work and continue to return generic longitudes/latitudes). The frame may be passed as a @@ -85,9 +105,9 @@ class HEALPix: If 'order' is not one of the allowed options. """ - def __init__(self, nside=None, order='ring', frame=None): + def __init__(self, nside=None, order="ring", frame=None): if nside is None: - raise ValueError('nside has not been set') + raise ValueError("nside has not been set") self.nside = nside self.order = _validate_order(order) self.frame = _get_frame(frame) @@ -121,9 +141,10 @@ def from_header(cls, input_data, field=0, hdu_in=None, nested=None): A HEALPix pixellization corresponding to the input data. """ array_in, frame, nested = parse_input_healpix_data( - input_data, field=field, hdu_in=hdu_in, nested=nested) + input_data, field=field, hdu_in=hdu_in, nested=nested + ) nside = npix_to_nside(len(array_in)) - order = 'nested' if nested else 'ring' + order = "nested" if nested else "ring" return cls(nside=nside, order=order, frame=frame) @property @@ -174,7 +195,9 @@ def healpix_to_lonlat(self, healpix_index, dx=None, dy=None): lat : :class:`~astropy.coordinates.Latitude` The latitude values """ - return healpix_to_lonlat(healpix_index, self.nside, dx=dx, dy=dy, order=self.order) + return healpix_to_lonlat( + healpix_index, self.nside, dx=dx, dy=dy, order=self.order + ) def lonlat_to_healpix(self, lon, lat, return_offsets=False): """ @@ -199,8 +222,9 @@ def lonlat_to_healpix(self, lon, lat, return_offsets=False): is the center of the HEALPix pixels). This is returned if ``return_offsets`` is `True`. """ - return lonlat_to_healpix(lon, lat, self.nside, - return_offsets=return_offsets, order=self.order) + return lonlat_to_healpix( + lon, lat, self.nside, return_offsets=return_offsets, order=self.order + ) def healpix_to_xyz(self, healpix_index, dx=None, dy=None): """ @@ -252,8 +276,9 @@ def xyz_to_healpix(self, x, y, z, return_offsets=False): is the center of the HEALPix pixels). This is returned if ``return_offsets`` is `True`. """ - return xyz_to_healpix(x, y, z, self.nside, - return_offsets=return_offsets, order=self.order) + return xyz_to_healpix( + x, y, z, self.nside, return_offsets=return_offsets, order=self.order + ) def nested_to_ring(self, nested_index): """ @@ -331,8 +356,11 @@ def interpolate_bilinear_lonlat(self, lon, lat, values): 1-D array of interpolated values """ if len(values) != self.npix: - raise ValueError('values must be an array of length {} (got {})' - .format(self.npix, len(values))) + raise ValueError( + "values must be an array of length {} (got {})".format( + self.npix, len(values) + ) + ) return interpolate_bilinear_lonlat(lon, lat, values, order=self.order) def cone_search_lonlat(self, lon, lat, radius): @@ -357,8 +385,9 @@ def cone_search_lonlat(self, lon, lat, radius): 1-D array with all the matching HEALPix pixel indices. """ if not lon.isscalar or not lat.isscalar or not radius.isscalar: - raise ValueError('The longitude, latitude and radius must be ' - 'scalar Quantity objects') + raise ValueError( + "The longitude, latitude and radius must be " "scalar Quantity objects" + ) return healpix_cone_search(lon, lat, radius, self.nside, order=self.order) def boundaries_lonlat(self, healpix_index, step): @@ -436,7 +465,9 @@ def healpix_to_skycoord(self, healpix_index, dx=None, dy=None): if self.frame is None: raise NoFrameError("healpix_to_skycoord") lon, lat = self.healpix_to_lonlat(healpix_index, dx=dx, dy=dy) - representation = UnitSphericalRepresentation(lon, lat, copy=_NUMPY_COPY_IF_NEEDED) + representation = UnitSphericalRepresentation( + lon, lat, copy=_NUMPY_COPY_IF_NEEDED + ) return SkyCoord(self.frame.realize_frame(representation)) def skycoord_to_healpix(self, skycoord, return_offsets=False): @@ -562,5 +593,7 @@ def boundaries_skycoord(self, healpix_index, step): if self.frame is None: raise NoFrameError("boundaries_skycoord") lon, lat = self.boundaries_lonlat(healpix_index, step) - representation = UnitSphericalRepresentation(lon, lat, copy=_NUMPY_COPY_IF_NEEDED) + representation = UnitSphericalRepresentation( + lon, lat, copy=_NUMPY_COPY_IF_NEEDED + ) return SkyCoord(self.frame.realize_frame(representation)) diff --git a/astropy_healpix/setup_package.py b/astropy_healpix/setup_package.py index a9de775..5a9a597 100644 --- a/astropy_healpix/setup_package.py +++ b/astropy_healpix/setup_package.py @@ -6,18 +6,19 @@ HEALPIX_ROOT = os.path.relpath(os.path.dirname(__file__)) -C_FILES = ['bl.c', - 'healpix-utils.c', - 'healpix.c', - 'mathutil.c', - 'permutedsort.c', - 'qsort_reentrant.c', - 'starutil.c'] +C_FILES = [ + "bl.c", + "healpix-utils.c", + "healpix.c", + "mathutil.c", + "permutedsort.c", + "qsort_reentrant.c", + "starutil.c", +] -C_DIR = os.path.join('cextern', 'astrometry.net') -C_DIRS = [np.get_include(), C_DIR, HEALPIX_ROOT, - os.path.join('cextern', 'numpy')] +C_DIR = os.path.join("cextern", "astrometry.net") +C_DIRS = [np.get_include(), C_DIR, HEALPIX_ROOT, os.path.join("cextern", "numpy")] def get_extensions(): @@ -26,8 +27,8 @@ def get_extensions(): libraries = [] sources = [os.path.join(C_DIR, filename) for filename in C_FILES] - sources.append(os.path.join(HEALPIX_ROOT, 'interpolation.c')) - sources.append(os.path.join(HEALPIX_ROOT, '_core.c')) + sources.append(os.path.join(HEALPIX_ROOT, "interpolation.c")) + sources.append(os.path.join(HEALPIX_ROOT, "_core.c")) extension = Extension( name="astropy_healpix._core", @@ -35,10 +36,13 @@ def get_extensions(): include_dirs=C_DIRS, libraries=libraries, language="c", - extra_compile_args=['-O2'], + extra_compile_args=["-O2"], py_limited_api=True, - define_macros=[('Py_LIMITED_API', 0x030A0000), - ('NPY_TARGET_VERSION', 'NPY_1_19_API_VERSION'), - ('NPY_NO_DEPRECATED_API', 'NPY_1_19_API_VERSION')]) + define_macros=[ + ("Py_LIMITED_API", 0x030A0000), + ("NPY_TARGET_VERSION", "NPY_1_19_API_VERSION"), + ("NPY_NO_DEPRECATED_API", "NPY_1_19_API_VERSION"), + ], + ) return [extension] diff --git a/astropy_healpix/tests/test_core.py b/astropy_healpix/tests/test_core.py index 64916f6..74e7ea3 100644 --- a/astropy_healpix/tests/test_core.py +++ b/astropy_healpix/tests/test_core.py @@ -9,43 +9,53 @@ from astropy import units as u from astropy.coordinates import Longitude, Latitude -from ..core import (nside_to_pixel_area, nside_to_pixel_resolution, pixel_resolution_to_nside, - nside_to_npix, npix_to_nside, healpix_to_lonlat, - lonlat_to_healpix, interpolate_bilinear_lonlat, - neighbours, healpix_cone_search, boundaries_lonlat, - level_to_nside, nside_to_level, - nested_to_ring, ring_to_nested, - level_ipix_to_uniq, uniq_to_level_ipix, - bilinear_interpolation_weights) +from ..core import ( + nside_to_pixel_area, + nside_to_pixel_resolution, + pixel_resolution_to_nside, + nside_to_npix, + npix_to_nside, + healpix_to_lonlat, + lonlat_to_healpix, + interpolate_bilinear_lonlat, + neighbours, + healpix_cone_search, + boundaries_lonlat, + level_to_nside, + nside_to_level, + nested_to_ring, + ring_to_nested, + level_ipix_to_uniq, + uniq_to_level_ipix, + bilinear_interpolation_weights, +) def test_level_to_nside(): - assert level_to_nside(5) == 2 ** 5 + assert level_to_nside(5) == 2**5 with pytest.raises(ValueError) as exc: level_to_nside(-1) - assert exc.value.args[0] == 'level must be positive' + assert exc.value.args[0] == "level must be positive" def test_nside_to_level(): assert nside_to_level(1024) == 10 with pytest.raises(ValueError) as exc: nside_to_level(511) - assert exc.value.args[0] == 'nside must be a power of two' + assert exc.value.args[0] == "nside must be a power of two" def test_level_ipix_to_uniq(): - assert 11 + 4*4**0 == level_ipix_to_uniq(0, 11) - assert 62540 + 4*4**15 == level_ipix_to_uniq(15, 62540) + assert 11 + 4 * 4**0 == level_ipix_to_uniq(0, 11) + assert 62540 + 4 * 4**15 == level_ipix_to_uniq(15, 62540) with pytest.raises(ValueError) as exc: level_ipix_to_uniq(1, 49) - assert exc.value.args[0] == 'ipix for a specific level must be inferior to npix' + assert exc.value.args[0] == "ipix for a specific level must be inferior to npix" -@pytest.mark.parametrize("level", [ - 0, 5, 10, 15, 20, 22, 25, 26, 27, 28, 29 -]) +@pytest.mark.parametrize("level", [0, 5, 10, 15, 20, 22, 25, 26, 27, 28, 29]) def test_uniq_to_level_ipix(level): - npix = 3 << 2*(level + 1) + npix = 3 << 2 * (level + 1) # Take 10 pixel indices between 0 and npix - 1 size = 10 @@ -69,23 +79,22 @@ def test_nside_to_pixel_resolution(): def test_pixel_resolution_to_nside(): - # Check the different rounding options - nside = pixel_resolution_to_nside(13 * u.arcmin, round='nearest') + nside = pixel_resolution_to_nside(13 * u.arcmin, round="nearest") assert nside == 256 - nside = pixel_resolution_to_nside(13 * u.arcmin, round='up') + nside = pixel_resolution_to_nside(13 * u.arcmin, round="up") assert nside == 512 - nside = pixel_resolution_to_nside(13 * u.arcmin, round='down') + nside = pixel_resolution_to_nside(13 * u.arcmin, round="down") assert nside == 256 # Check that it works with arrays - nside = pixel_resolution_to_nside([1e3, 10, 1e-3] * u.deg, round='nearest') + nside = pixel_resolution_to_nside([1e3, 10, 1e-3] * u.deg, round="nearest") assert_equal(nside, [1, 8, 65536]) with pytest.raises(ValueError) as exc: - pixel_resolution_to_nside(13 * u.arcmin, round='peaches') + pixel_resolution_to_nside(13 * u.arcmin, round="peaches") assert exc.value.args[0] == "Invalid value for round: 'peaches'" with pytest.raises(AttributeError) as exc: @@ -102,7 +111,7 @@ def test_nside_to_npix(): with pytest.raises(ValueError) as exc: nside_to_npix(15) - assert exc.value.args[0] == 'nside must be a power of two' + assert exc.value.args[0] == "nside must be a power of two" def test_npix_to_nside(): @@ -114,11 +123,11 @@ def test_npix_to_nside(): with pytest.raises(ValueError) as exc: npix_to_nside(7) - assert exc.value.args[0] == 'Number of pixels must be divisible by 12' + assert exc.value.args[0] == "Number of pixels must be divisible by 12" with pytest.raises(ValueError) as exc: npix_to_nside(12 * 8 * 9) - assert exc.value.args[0] == 'Number of pixels is not of the form 12 * nside ** 2' + assert exc.value.args[0] == "Number of pixels is not of the form 12 * nside ** 2" # For the following tests, the numerical accuracy of this function is already @@ -126,7 +135,7 @@ def test_npix_to_nside(): # the Python functions. -@pytest.mark.parametrize('order', ['nested', 'ring']) +@pytest.mark.parametrize("order", ["nested", "ring"]) def test_healpix_to_lonlat(order): lon, lat = healpix_to_lonlat([1, 2, 3], 4, order=order) @@ -137,9 +146,9 @@ def test_healpix_to_lonlat(order): assert_equal(index, [1, 2, 3]) - lon, lat = healpix_to_lonlat([1, 2, 3], 4, - dx=[0.1, 0.2, 0.3], - dy=[0.5, 0.4, 0.7], order=order) + lon, lat = healpix_to_lonlat( + [1, 2, 3], 4, dx=[0.1, 0.2, 0.3], dy=[0.5, 0.4, 0.7], order=order + ) assert isinstance(lon, Longitude) assert isinstance(lat, Latitude) @@ -155,27 +164,27 @@ def test_healpix_to_lonlat_invalid(): dx = [0.1, 0.4, 0.9] dy = [0.4, 0.3, 0.2] - with pytest.warns(RuntimeWarning, match='invalid value'): + with pytest.warns(RuntimeWarning, match="invalid value"): lon, lat = healpix_to_lonlat([-1, 2, 3], 4) - with pytest.warns(RuntimeWarning, match='invalid value'): + with pytest.warns(RuntimeWarning, match="invalid value"): lon, lat = healpix_to_lonlat([192, 2, 3], 4) with pytest.raises(ValueError) as exc: lon, lat = healpix_to_lonlat([1, 2, 3], 5) - assert exc.value.args[0] == 'nside must be a power of two' + assert exc.value.args[0] == "nside must be a power of two" with pytest.raises(ValueError) as exc: - lon, lat = healpix_to_lonlat([1, 2, 3], 4, order='banana') + lon, lat = healpix_to_lonlat([1, 2, 3], 4, order="banana") assert exc.value.args[0] == "order must be 'nested' or 'ring'" with pytest.raises(ValueError) as exc: lon, lat = healpix_to_lonlat([1, 2, 3], 4, dx=[-0.1, 0.4, 0.5], dy=dy) - assert exc.value.args[0] == 'dx must be in the range [0:1]' + assert exc.value.args[0] == "dx must be in the range [0:1]" with pytest.raises(ValueError) as exc: lon, lat = healpix_to_lonlat([1, 2, 3], 4, dx=dx, dy=[-0.1, 0.4, 0.5]) - assert exc.value.args[0] == 'dy must be in the range [0:1]' + assert exc.value.args[0] == "dy must be in the range [0:1]" def test_healpix_to_lonlat_shape(): @@ -197,7 +206,9 @@ def test_lonlat_to_healpix_shape(): healpix_index = lonlat_to_healpix(lon, lat, 8) assert healpix_index.shape == (2, 4) - healpix_index, dx, dy = lonlat_to_healpix(2 * u.deg, 3 * u.deg, 8, return_offsets=True) + healpix_index, dx, dy = lonlat_to_healpix( + 2 * u.deg, 3 * u.deg, 8, return_offsets=True + ) assert np.can_cast(healpix_index, np.int64) assert isinstance(dx, float) assert isinstance(dy, float) @@ -211,12 +222,11 @@ def test_lonlat_to_healpix_shape(): def test_lonlat_to_healpix_invalid(): """Check that if we pass NaN values for example, the index is set to -1""" - ipix = lonlat_to_healpix(np.nan * u.deg, np.nan * u.deg, - nside=1, order='nested') + ipix = lonlat_to_healpix(np.nan * u.deg, np.nan * u.deg, nside=1, order="nested") assert ipix == -1 -@pytest.mark.parametrize('function', [nested_to_ring, ring_to_nested]) +@pytest.mark.parametrize("function", [nested_to_ring, ring_to_nested]) def test_nested_ring_shape(function): index = function(1, 8) assert np.can_cast(index, np.int64) @@ -225,12 +235,12 @@ def test_nested_ring_shape(function): assert index.shape == (2, 3) -@pytest.mark.parametrize('order', ['nested', 'ring']) +@pytest.mark.parametrize("order", ["nested", "ring"]) def test_bilinear_interpolation_weights(order): - - indices, weights = bilinear_interpolation_weights(100 * u.deg, 10 * u.deg, - nside=4, order=order) - if order == 'nested': + indices, weights = bilinear_interpolation_weights( + 100 * u.deg, 10 * u.deg, nside=4, order=order + ) + if order == "nested": indices = nested_to_ring(indices, nside=4) assert_equal(indices, [76, 77, 60, 59]) assert_allclose(weights, [0.532723, 0.426179, 0.038815, 0.002283], atol=1e-6) @@ -239,31 +249,31 @@ def test_bilinear_interpolation_weights(order): def test_bilinear_interpolation_weights_invalid(): with pytest.raises(ValueError) as exc: bilinear_interpolation_weights(1 * u.deg, 2 * u.deg, nside=5) - assert exc.value.args[0] == 'nside must be a power of two' + assert exc.value.args[0] == "nside must be a power of two" with pytest.raises(ValueError) as exc: - bilinear_interpolation_weights(3 * u.deg, 4 * u.deg, - nside=4, order='banana') + bilinear_interpolation_weights(3 * u.deg, 4 * u.deg, nside=4, order="banana") assert exc.value.args[0] == "order must be 'nested' or 'ring'" def test_bilinear_interpolation_weights_shape(): - indices, weights = bilinear_interpolation_weights(3 * u.deg, 4 * u.deg, nside=8) assert indices.shape == (4,) assert weights.shape == (4,) - indices, weights = bilinear_interpolation_weights([[1, 2, 3], [2, 3, 4]] * u.deg, - [[1, 2, 3], [2, 3, 4]] * u.deg, nside=8) + indices, weights = bilinear_interpolation_weights( + [[1, 2, 3], [2, 3, 4]] * u.deg, [[1, 2, 3], [2, 3, 4]] * u.deg, nside=8 + ) assert indices.shape == (4, 2, 3) assert weights.shape == (4, 2, 3) -@pytest.mark.parametrize('order', ['nested', 'ring']) +@pytest.mark.parametrize("order", ["nested", "ring"]) def test_interpolate_bilinear_lonlat(order): values = np.ones(192) * 3 - result = interpolate_bilinear_lonlat([1, 3, 4] * u.deg, [3, 2, 6] * u.deg, - values, order=order) + result = interpolate_bilinear_lonlat( + [1, 3, 4] * u.deg, [3, 2, 6] * u.deg, values, order=order + ) assert_allclose(result, [3, 3, 3]) @@ -271,31 +281,32 @@ def test_interpolate_bilinear_invalid(): values = np.ones(133) with pytest.raises(ValueError) as exc: interpolate_bilinear_lonlat([1, 3, 4] * u.deg, [3, 2, 6] * u.deg, values) - assert exc.value.args[0] == 'Number of pixels must be divisible by 12' + assert exc.value.args[0] == "Number of pixels must be divisible by 12" values = np.ones(192) with pytest.raises(ValueError) as exc: - interpolate_bilinear_lonlat([1, 3, 4] * u.deg, [3, 2, 6] * u.deg, - values, order='banana') + interpolate_bilinear_lonlat( + [1, 3, 4] * u.deg, [3, 2, 6] * u.deg, values, order="banana" + ) assert exc.value.args[0] == "order must be 'nested' or 'ring'" - result = interpolate_bilinear_lonlat([0, np.nan] * u.deg, - [0, np.nan] * u.deg, values, - order='nested') + result = interpolate_bilinear_lonlat( + [0, np.nan] * u.deg, [0, np.nan] * u.deg, values, order="nested" + ) assert result.shape == (2,) assert result[0] == 1 assert np.isnan(result[1]) def test_interpolate_bilinear_lonlat_shape(): - values = np.ones(192) * 3 result = interpolate_bilinear_lonlat(3 * u.deg, 4 * u.deg, values) assert isinstance(result, float) - result = interpolate_bilinear_lonlat([[1, 2, 3], [2, 3, 4]] * u.deg, - [[1, 2, 3], [2, 3, 4]] * u.deg, values) + result = interpolate_bilinear_lonlat( + [[1, 2, 3], [2, 3, 4]] * u.deg, [[1, 2, 3], [2, 3, 4]] * u.deg, values + ) assert result.shape == (2, 3) values = np.ones((192, 50)) * 3 @@ -307,46 +318,49 @@ def test_interpolate_bilinear_lonlat_shape(): assert result.shape == (3, 6, 5, 50) -@pytest.mark.parametrize('order', ['nested', 'ring']) +@pytest.mark.parametrize("order", ["nested", "ring"]) def test_neighbours(order): neigh = neighbours([1, 2, 3], 4, order=order) - if order == 'nested': - expected = [[0, 71, 2], - [2, 77, 8], - [3, 8, 9], - [6, 9, 12], - [4, 3, 6], - [94, 1, 4], - [91, 0, 1], - [90, 69, 0]] + if order == "nested": + expected = [ + [0, 71, 2], + [2, 77, 8], + [3, 8, 9], + [6, 9, 12], + [4, 3, 6], + [94, 1, 4], + [91, 0, 1], + [90, 69, 0], + ] else: - - expected = [[6, 8, 10], - [5, 7, 9], - [0, 1, 2], - [3, 0, 1], - [2, 3, 0], - [8, 10, 4], - [7, 9, 11], - [16, 19, 22]] + expected = [ + [6, 8, 10], + [5, 7, 9], + [0, 1, 2], + [3, 0, 1], + [2, 3, 0], + [8, 10, 4], + [7, 9, 11], + [16, 19, 22], + ] assert_equal(neigh, expected) def test_neighbours_invalid(): - with pytest.warns(RuntimeWarning, match='invalid value'): + with pytest.warns(RuntimeWarning, match="invalid value"): neighbours([-1, 2, 3], 4) - with pytest.warns(RuntimeWarning, match='invalid value'): + with pytest.warns(RuntimeWarning, match="invalid value"): neighbours([192, 2, 3], 4) with pytest.raises(ValueError) as exc: neighbours([1, 2, 3], 5) - assert exc.value.args[0] == 'nside must be a power of two' + assert exc.value.args[0] == "nside must be a power of two" with pytest.raises(ValueError) as exc: - neighbours([1, 2, 3], 4, order='banana') + neighbours([1, 2, 3], 4, order="banana") assert exc.value.args[0] == "order must be 'nested' or 'ring'" @@ -355,15 +369,16 @@ def test_neighbours_shape(): assert neigh.shape == (8, 2, 3) -@pytest.mark.parametrize('order', ['nested', 'ring']) +@pytest.mark.parametrize("order", ["nested", "ring"]) def test_healpix_cone_search(order): - indices = healpix_cone_search(10 * u.deg, 20 * u.deg, 1 * u.deg, - nside=256, order=order) + indices = healpix_cone_search( + 10 * u.deg, 20 * u.deg, 1 * u.deg, nside=256, order=order + ) assert len(indices) == 80 -@pytest.mark.parametrize(('step', 'order'), product([1, 4, 10], ['nested', 'ring'])) +@pytest.mark.parametrize(("step", "order"), product([1, 4, 10], ["nested", "ring"])) def test_boundaries_lonlat(step, order): lon, lat = boundaries_lonlat([10, 20, 30], step, 256, order=order) assert lon.shape == (3, 4 * step) diff --git a/astropy_healpix/tests/test_healpy.py b/astropy_healpix/tests/test_healpy.py index 0e3b7a4..fd751a9 100644 --- a/astropy_healpix/tests/test_healpy.py +++ b/astropy_healpix/tests/test_healpy.py @@ -17,40 +17,40 @@ # NOTE: If healpy is installed, we use it in these tests, but healpy is not a # formal dependency of astropy-healpix. -hp = pytest.importorskip('healpy') +hp = pytest.importorskip("healpy") -NSIDE_VALUES = [2 ** n for n in range(1, 6)] +NSIDE_VALUES = [2**n for n in range(1, 6)] -@pytest.mark.parametrize(('nside', 'degrees'), product(NSIDE_VALUES, (False, True))) +@pytest.mark.parametrize(("nside", "degrees"), product(NSIDE_VALUES, (False, True))) def test_nside2pixarea(nside, degrees): actual = hp_compat.nside2pixarea(nside=nside, degrees=degrees) expected = hp.nside2pixarea(nside=nside, degrees=degrees) assert_allclose(actual, expected) -@pytest.mark.parametrize(('nside', 'arcmin'), product(NSIDE_VALUES, (False, True))) +@pytest.mark.parametrize(("nside", "arcmin"), product(NSIDE_VALUES, (False, True))) def test_nside2resol(nside, arcmin): actual = hp_compat.nside2resol(nside=nside, arcmin=arcmin) expected = hp.nside2resol(nside=nside, arcmin=arcmin) assert_allclose(actual, expected) -@pytest.mark.parametrize('nside', NSIDE_VALUES) +@pytest.mark.parametrize("nside", NSIDE_VALUES) def test_nside2npix(nside): actual = hp_compat.nside2npix(nside) expected = hp.nside2npix(nside) assert_equal(actual, expected) -@pytest.mark.parametrize('level', [0, 3, 7]) +@pytest.mark.parametrize("level", [0, 3, 7]) def test_order2nside(level): actual = hp_compat.order2nside(level) expected = hp.order2nside(level) assert_equal(actual, expected) -@pytest.mark.parametrize('npix', [12 * 2 ** (2 * n) for n in range(1, 6)]) +@pytest.mark.parametrize("npix", [12 * 2 ** (2 * n) for n in range(1, 6)]) def test_npix2nside(npix): actual = hp_compat.npix2nside(npix) expected = hp.npix2nside(npix) @@ -60,28 +60,35 @@ def test_npix2nside(npix): # For the test below, we exclude latitudes that fall exactly on the pole or # the equator since points that fall at exact boundaries are ambiguous. -@given(nside_pow=integers(0, 29), nest=booleans(), lonlat=booleans(), - lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( - lambda lon: abs(lon) > 1e-10), - lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( - lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-10)) + +@given( + nside_pow=integers(0, 29), + nest=booleans(), + lonlat=booleans(), + lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( + lambda lon: abs(lon) > 1e-10 + ), + lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( + lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-10 + ), +) @settings(max_examples=2000, derandomize=True, deadline=None) def test_ang2pix(nside_pow, lon, lat, nest, lonlat): - nside = 2 ** nside_pow + nside = 2**nside_pow if lonlat: theta, phi = lon, lat else: - theta, phi = np.pi / 2. - np.radians(lat), np.radians(lon) + theta, phi = np.pi / 2.0 - np.radians(lat), np.radians(lon) ipix1 = hp_compat.ang2pix(nside, theta, phi, nest=nest, lonlat=lonlat) ipix2 = hp.ang2pix(nside, theta, phi, nest=nest, lonlat=lonlat) assert ipix1 == ipix2 def test_ang2pix_shape(): - ipix = hp_compat.ang2pix(8, 1., 2.) + ipix = hp_compat.ang2pix(8, 1.0, 2.0) assert np.can_cast(ipix, np.int64) - ipix = hp_compat.ang2pix(8, [[1., 2.], [3., 4.]], [[1., 2.], [3., 4.]]) + ipix = hp_compat.ang2pix(8, [[1.0, 2.0], [3.0, 4.0]], [[1.0, 2.0], [3.0, 4.0]]) assert ipix.shape == (2, 2) @@ -95,14 +102,18 @@ def test_pix2ang_shape(): assert lat.shape == (2, 3) -@given(nside_pow=integers(0, 29), nest=booleans(), lonlat=booleans(), - frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1)) +@given( + nside_pow=integers(0, 29), + nest=booleans(), + lonlat=booleans(), + frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1), +) @settings(max_examples=2000, derandomize=True, deadline=None) @example(nside_pow=29, frac=0.1666666694606345, nest=False, lonlat=False) -@example(nside_pow=27, frac=2./3., nest=True, lonlat=False) +@example(nside_pow=27, frac=2.0 / 3.0, nest=True, lonlat=False) def test_pix2ang(nside_pow, frac, nest, lonlat): - nside = 2 ** nside_pow - ipix = int(frac * 12 * nside ** 2) + nside = 2**nside_pow + ipix = int(frac * 12 * nside**2) theta1, phi1 = hp_compat.pix2ang(nside, ipix, nest=nest, lonlat=lonlat) theta2, phi2 = hp.pix2ang(nside, ipix, nest=nest, lonlat=lonlat) if lonlat: @@ -118,7 +129,7 @@ def test_pix2ang(nside_pow, frac, nest, lonlat): def not_on_boundaries(args): """Skip vectors that are on the boundary of a pixel where ipix is ambiguous.""" nside_pow, nest, x, y, z = args - nside = 2 ** nside_pow + nside = 2**nside_pow _, dx, dy = xyz_to_healpix( x, y, z, nside, return_offsets=True, order="nested" if nest else "ring" ) @@ -127,38 +138,53 @@ def not_on_boundaries(args): @given( args=tuples( - integers(0, 29), booleans(), - floats(-1, 1, allow_nan=False, allow_infinity=False).filter(lambda x: abs(x) > 1e-10), - floats(-1, 1, allow_nan=False, allow_infinity=False).filter(lambda y: abs(y) > 1e-10), - floats(-1, 1, allow_nan=False, allow_infinity=False).filter(lambda z: abs(z) > 1e-10) + integers(0, 29), + booleans(), + floats(-1, 1, allow_nan=False, allow_infinity=False).filter( + lambda x: abs(x) > 1e-10 + ), + floats(-1, 1, allow_nan=False, allow_infinity=False).filter( + lambda y: abs(y) > 1e-10 + ), + floats(-1, 1, allow_nan=False, allow_infinity=False).filter( + lambda z: abs(z) > 1e-10 + ), ).filter(not_on_boundaries) ) @settings(max_examples=2000, derandomize=True, deadline=None) def test_vec2pix(args): nside_pow, nest, x, y, z = args - nside = 2 ** nside_pow + nside = 2**nside_pow ipix1 = hp_compat.vec2pix(nside, x, y, z, nest=nest) ipix2 = hp.vec2pix(nside, x, y, z, nest=nest) assert ipix1 == ipix2 -@given(nside_pow=integers(0, 29), nest=booleans(), - frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1)) +@given( + nside_pow=integers(0, 29), + nest=booleans(), + frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1), +) @settings(max_examples=2000, derandomize=True, deadline=None) @example(nside_pow=29, frac=0.1666666694606345, nest=False) def test_pix2vec(nside_pow, frac, nest): - nside = 2 ** nside_pow - ipix = int(frac * 12 * nside ** 2) + nside = 2**nside_pow + ipix = int(frac * 12 * nside**2) xyz1 = hp_compat.pix2vec(nside, ipix, nest=nest) xyz2 = hp.pix2vec(nside, ipix, nest=nest) assert_allclose(xyz1, xyz2, atol=1e-8) def test_vec2pix_shape(): - ipix = hp_compat.vec2pix(8, 1., 2., 3.) + ipix = hp_compat.vec2pix(8, 1.0, 2.0, 3.0) assert np.can_cast(ipix, np.int64) - ipix = hp_compat.vec2pix(8, [[1., 2.], [3., 4.]], [[5., 6.], [7., 8.]], [[9., 10.], [11., 12.]]) + ipix = hp_compat.vec2pix( + 8, + [[1.0, 2.0], [3.0, 4.0]], + [[5.0, 6.0], [7.0, 8.0]], + [[9.0, 10.0], [11.0, 12.0]], + ) assert ipix.shape == (2, 2) @@ -174,35 +200,43 @@ def test_pix2vec_shape(): assert z.shape == (2, 3) -@given(nside_pow=integers(0, 29), - frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1)) +@given( + nside_pow=integers(0, 29), + frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1), +) @settings(max_examples=2000, derandomize=True, deadline=None) def test_nest2ring(nside_pow, frac): - nside = 2 ** nside_pow - nest = int(frac * 12 * nside ** 2) + nside = 2**nside_pow + nest = int(frac * 12 * nside**2) ring1 = hp_compat.nest2ring(nside, nest) ring2 = hp.nest2ring(nside, nest) assert ring1 == ring2 -@given(nside_pow=integers(0, 29), - frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1)) +@given( + nside_pow=integers(0, 29), + frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1), +) @settings(max_examples=2000, derandomize=True, deadline=None) @example(nside_pow=29, frac=0.16666666697710755) def test_ring2nest(nside_pow, frac): - nside = 2 ** nside_pow - ring = int(frac * 12 * nside ** 2) + nside = 2**nside_pow + ring = int(frac * 12 * nside**2) nest1 = hp_compat.ring2nest(nside, ring) nest2 = hp.ring2nest(nside, ring) assert nest1 == nest2 -@given(nside_pow=integers(0, 29), step=integers(1, 10), nest=booleans(), - frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1)) +@given( + nside_pow=integers(0, 29), + step=integers(1, 10), + nest=booleans(), + frac=floats(0, 1, allow_nan=False, allow_infinity=False).filter(lambda x: x < 1), +) @settings(max_examples=500, derandomize=True, deadline=None) def test_boundaries(nside_pow, frac, step, nest): - nside = 2 ** nside_pow - pix = int(frac * 12 * nside ** 2) + nside = 2**nside_pow + pix = int(frac * 12 * nside**2) b1 = hp_compat.boundaries(nside, pix, step=step, nest=nest) b2 = hp.boundaries(nside, pix, step=step, nest=nest) assert_allclose(b1, b2, atol=1e-8) @@ -224,8 +258,11 @@ def not_at_origin(vec): return np.linalg.norm(vec) > 0 -@given(vectors=arrays(float, (3,), elements=floats(-1, 1)).filter(not_at_origin), - lonlat=booleans(), ndim=integers(0, 4)) +@given( + vectors=arrays(float, (3,), elements=floats(-1, 1)).filter(not_at_origin), + lonlat=booleans(), + ndim=integers(0, 4), +) @settings(max_examples=500, derandomize=True, deadline=None) def test_vec2ang(vectors, lonlat, ndim): vectors = np.broadcast_to(vectors, (2,) * ndim + (3,)) @@ -240,17 +277,21 @@ def test_vec2ang(vectors, lonlat, ndim): assert_allclose(sep, 0, atol=1e-8) -@given(lonlat=booleans(), - lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( - lambda lon: abs(lon) > 1e-10), - lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( - lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-10)) +@given( + lonlat=booleans(), + lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( + lambda lon: abs(lon) > 1e-10 + ), + lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( + lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-10 + ), +) @settings(max_examples=2000, derandomize=True, deadline=None) def test_ang2vec(lon, lat, lonlat): if lonlat: theta, phi = lon, lat else: - theta, phi = np.pi / 2. - np.radians(lat), np.radians(lon) + theta, phi = np.pi / 2.0 - np.radians(lat), np.radians(lon) xyz1 = hp_compat.ang2vec(theta, phi, lonlat=lonlat) xyz2 = hp.ang2vec(theta, phi, lonlat=lonlat) assert_allclose(xyz1, xyz2, atol=1e-10) @@ -261,33 +302,99 @@ def test_ang2vec(lon, lat, lonlat): # nest=False, lonlat=False) # -@given(nside_pow=integers(0, 28), nest=booleans(), lonlat=booleans(), - lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( - lambda lon: abs(lon) > 1e-5), - lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( - lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-5)) + +@given( + nside_pow=integers(0, 28), + nest=booleans(), + lonlat=booleans(), + lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( + lambda lon: abs(lon) > 1e-5 + ), + lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( + lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-5 + ), +) @settings(max_examples=500, derandomize=True, deadline=None) -@example(nside_pow=27, lon=1.0000000028043134e-05, lat=-41.81031451395941, nest=False, lonlat=False) -@example(nside_pow=6, lon=1.6345238095238293, lat=69.42254649458224, nest=False, lonlat=False) -@example(nside_pow=15, lon=1.0000000028043134e-05, lat=1.000000000805912e-05, - nest=False, lonlat=False) -@example(nside_pow=0, lon=315.0000117809725, lat=1.000000000805912e-05, nest=False, lonlat=False) -@example(nside_pow=0, lon=1.0000000028043134e-05, lat=-41.81031489577861, nest=False, lonlat=False) -@example(nside_pow=0, lon=35.559942143736414, lat=-41.8103252622604, nest=False, lonlat=False) -@example(nside_pow=28, lon=359.9999922886491, lat=-41.81031470486902, nest=False, lonlat=False) -@example(nside_pow=0, lon=1.0000000028043134e-05, lat=-41.81031489577861, nest=False, lonlat=False) -@example(nside_pow=27, lon=1.0000000028043134e-05, lat=-41.81031451395941, nest=False, lonlat=False) -@example(nside_pow=26, lon=359.9999986588955, lat=41.81031489577861, nest=False, lonlat=False) -@example(nside_pow=27, lon=359.999997317791, lat=-41.81031451395943, nest=False, lonlat=False) -@example(nside_pow=27, lon=1.0000000028043134e-05, lat=89.80224636153702, nest=False, lonlat=False) +@example( + nside_pow=27, + lon=1.0000000028043134e-05, + lat=-41.81031451395941, + nest=False, + lonlat=False, +) +@example( + nside_pow=6, lon=1.6345238095238293, lat=69.42254649458224, nest=False, lonlat=False +) +@example( + nside_pow=15, + lon=1.0000000028043134e-05, + lat=1.000000000805912e-05, + nest=False, + lonlat=False, +) +@example( + nside_pow=0, + lon=315.0000117809725, + lat=1.000000000805912e-05, + nest=False, + lonlat=False, +) +@example( + nside_pow=0, + lon=1.0000000028043134e-05, + lat=-41.81031489577861, + nest=False, + lonlat=False, +) +@example( + nside_pow=0, lon=35.559942143736414, lat=-41.8103252622604, nest=False, lonlat=False +) +@example( + nside_pow=28, + lon=359.9999922886491, + lat=-41.81031470486902, + nest=False, + lonlat=False, +) +@example( + nside_pow=0, + lon=1.0000000028043134e-05, + lat=-41.81031489577861, + nest=False, + lonlat=False, +) +@example( + nside_pow=27, + lon=1.0000000028043134e-05, + lat=-41.81031451395941, + nest=False, + lonlat=False, +) +@example( + nside_pow=26, lon=359.9999986588955, lat=41.81031489577861, nest=False, lonlat=False +) +@example( + nside_pow=27, lon=359.999997317791, lat=-41.81031451395943, nest=False, lonlat=False +) +@example( + nside_pow=27, + lon=1.0000000028043134e-05, + lat=89.80224636153702, + nest=False, + lonlat=False, +) def test_interp_weights(nside_pow, lon, lat, nest, lonlat): - nside = 2 ** nside_pow + nside = 2**nside_pow if lonlat: theta, phi = lon, lat else: - theta, phi = np.pi / 2. - np.radians(lat), np.radians(lon) - indices1, weights1 = hp_compat.get_interp_weights(nside, theta, phi, nest=nest, lonlat=lonlat) - indices2, weights2 = hp.get_interp_weights(nside, theta, phi, nest=nest, lonlat=lonlat) + theta, phi = np.pi / 2.0 - np.radians(lat), np.radians(lon) + indices1, weights1 = hp_compat.get_interp_weights( + nside, theta, phi, nest=nest, lonlat=lonlat + ) + indices2, weights2 = hp.get_interp_weights( + nside, theta, phi, nest=nest, lonlat=lonlat + ) # Ignore neighbours with weights < 1e-6 - we have to exclude these otherwise # in some corner cases there will be different low-probability neighbours. @@ -307,22 +414,28 @@ def test_interp_weights(nside_pow, lon, lat, nest, lonlat): # Make an array that can be useful up to the highest nside tested below NSIDE_POW_MAX = 8 -VALUES = np.random.random(12 * NSIDE_POW_MAX ** 2) +VALUES = np.random.random(12 * NSIDE_POW_MAX**2) -@given(nside_pow=integers(0, NSIDE_POW_MAX), nest=booleans(), lonlat=booleans(), - lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( - lambda lon: abs(lon) > 1e-5), - lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( - lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-5)) +@given( + nside_pow=integers(0, NSIDE_POW_MAX), + nest=booleans(), + lonlat=booleans(), + lon=floats(0, 360, allow_nan=False, allow_infinity=False).filter( + lambda lon: abs(lon) > 1e-5 + ), + lat=floats(-90, 90, allow_nan=False, allow_infinity=False).filter( + lambda lat: abs(lat) < 89.99 and abs(lat) > 1e-5 + ), +) @settings(max_examples=500, derandomize=True, deadline=None) def test_interp_val(nside_pow, lon, lat, nest, lonlat): - nside = 2 ** nside_pow + nside = 2**nside_pow if lonlat: theta, phi = lon, lat else: - theta, phi = np.pi / 2. - np.radians(lat), np.radians(lon) - m = VALUES[:12 * nside ** 2] + theta, phi = np.pi / 2.0 - np.radians(lat), np.radians(lon) + m = VALUES[: 12 * nside**2] value1 = hp_compat.get_interp_val(m, theta, phi, nest=nest, lonlat=lonlat) value2 = hp.get_interp_val(m, theta, phi, nest=nest, lonlat=lonlat) - assert_allclose(value1, value2, rtol=0.1, atol=1.e-10) + assert_allclose(value1, value2, rtol=0.1, atol=1.0e-10) diff --git a/astropy_healpix/tests/test_high_level.py b/astropy_healpix/tests/test_high_level.py index b822d53..5ab8a7f 100644 --- a/astropy_healpix/tests/test_high_level.py +++ b/astropy_healpix/tests/test_high_level.py @@ -10,9 +10,8 @@ class TestHEALPix: - def setup_class(self): - self.pix = HEALPix(nside=256, order='nested') + self.pix = HEALPix(nside=256, order="nested") def test_pixel_area(self): pixel_area = self.pix.pixel_area @@ -28,7 +27,7 @@ def test_level(self): assert self.pix.level == 8 def test_npix(self): - assert self.pix.npix == 12 * 256 ** 2 + assert self.pix.npix == 12 * 256**2 # For the following tests, the numerical accuracy of this function is # already tested in test_cython_api.py, so we focus here on functionality @@ -44,9 +43,9 @@ def test_healpix_to_lonlat(self): assert_equal(index, [1, 2, 3]) - lon, lat = self.pix.healpix_to_lonlat([1, 2, 3], - dx=[0.1, 0.2, 0.3], - dy=[0.5, 0.4, 0.7]) + lon, lat = self.pix.healpix_to_lonlat( + [1, 2, 3], dx=[0.1, 0.2, 0.3], dy=[0.5, 0.4, 0.7] + ) assert isinstance(lon, Longitude) assert isinstance(lat, Latitude) @@ -68,9 +67,9 @@ def test_healpix_to_xyz(self): assert_equal(index, [1, 2, 3]) - x, y, z = self.pix.healpix_to_xyz([1, 2, 3], - dx=[0.1, 0.2, 0.3], - dy=[0.5, 0.4, 0.7]) + x, y, z = self.pix.healpix_to_xyz( + [1, 2, 3], dx=[0.1, 0.2, 0.3], dy=[0.5, 0.4, 0.7] + ) assert isinstance(x, np.ndarray) assert isinstance(y, np.ndarray) @@ -89,23 +88,26 @@ def test_nested_to_ring(self): assert_equal(nested_index_1, nested_index_2) def test_bilinear_interpolation_weights(self): - indices, weights = self.pix.bilinear_interpolation_weights([1, 3, 4] * u.deg, - [3, 2, 6] * u.deg) + indices, weights = self.pix.bilinear_interpolation_weights( + [1, 3, 4] * u.deg, [3, 2, 6] * u.deg + ) assert indices.shape == (4, 3) assert weights.shape == (4, 3) def test_interpolate_bilinear_lonlat(self): - values = np.ones(12 * 256 ** 2) * 3 - result = self.pix.interpolate_bilinear_lonlat([1, 3, 4] * u.deg, - [3, 2, 6] * u.deg, values) + values = np.ones(12 * 256**2) * 3 + result = self.pix.interpolate_bilinear_lonlat( + [1, 3, 4] * u.deg, [3, 2, 6] * u.deg, values + ) assert_allclose(result, [3, 3, 3]) def test_interpolate_bilinear_lonlat_invalid(self): values = np.ones(222) * 3 with pytest.raises(ValueError) as exc: - self.pix.interpolate_bilinear_lonlat([1, 3, 4] * u.deg, - [3, 2, 6] * u.deg, values) - assert exc.value.args[0] == 'values must be an array of length 786432 (got 222)' + self.pix.interpolate_bilinear_lonlat( + [1, 3, 4] * u.deg, [3, 2, 6] * u.deg, values + ) + assert exc.value.args[0] == "values must be an array of length 786432 (got 222)" def test_cone_search_lonlat(self): lon, lat = 1 * u.deg, 4 * u.deg @@ -116,8 +118,9 @@ def test_cone_search_lonlat_invalid(self): lon, lat = [1, 2] * u.deg, [3, 4] * u.deg with pytest.raises(ValueError) as exc: self.pix.cone_search_lonlat(lon, lat, 1 * u.deg) - assert exc.value.args[0] == ('The longitude, latitude and radius must ' - 'be scalar Quantity objects') + assert exc.value.args[0] == ( + "The longitude, latitude and radius must " "be scalar Quantity objects" + ) def test_boundaries_lonlat(self): lon, lat = self.pix.boundaries_lonlat([10, 20, 30], 4) @@ -130,9 +133,8 @@ def test_neighbours(self): class TestCelestialHEALPix: - def setup_class(self): - self.pix = HEALPix(nside=256, order='nested', frame=Galactic()) + self.pix = HEALPix(nside=256, order="nested", frame=Galactic()) def test_healpix_from_header(self): """Test instantiation from a FITS header. @@ -146,8 +148,8 @@ def test_healpix_from_header(self): """ pix = HEALPix.from_header( - (np.empty(self.pix.npix), 'G'), - nested=self.pix.order == 'nested') + (np.empty(self.pix.npix), "G"), nested=self.pix.order == "nested" + ) assert pix.nside == self.pix.nside assert type(pix.frame) == type(self.pix.frame) # noqa @@ -161,22 +163,22 @@ def test_healpix_to_skycoord(self): # Make sure that the skycoord_to_healpix method converts coordinates # to the frame of the HEALPix - coord = coord.transform_to('fk5') + coord = coord.transform_to("fk5") index = self.pix.skycoord_to_healpix(coord) assert_equal(index, [1, 2, 3]) - coord = self.pix.healpix_to_skycoord([1, 2, 3], - dx=[0.1, 0.2, 0.3], - dy=[0.5, 0.4, 0.7]) + coord = self.pix.healpix_to_skycoord( + [1, 2, 3], dx=[0.1, 0.2, 0.3], dy=[0.5, 0.4, 0.7] + ) assert isinstance(coord, SkyCoord) assert isinstance(coord.frame, Galactic) # Make sure that the skycoord_to_healpix method converts coordinates # to the frame of the HEALPix - coord = coord.transform_to('fk5') + coord = coord.transform_to("fk5") index, dx, dy = self.pix.skycoord_to_healpix(coord, return_offsets=True) @@ -185,15 +187,15 @@ def test_healpix_to_skycoord(self): assert_allclose(dy, [0.5, 0.4, 0.7]) def test_interpolate_bilinear_skycoord(self): - values = np.ones(12 * 256 ** 2) * 3 - coord = SkyCoord([1, 2, 3] * u.deg, [4, 3, 1] * u.deg, frame='fk4') + values = np.ones(12 * 256**2) * 3 + coord = SkyCoord([1, 2, 3] * u.deg, [4, 3, 1] * u.deg, frame="fk4") result = self.pix.interpolate_bilinear_skycoord(coord, values) assert_allclose(result, [3, 3, 3]) # Make sure that coordinate system is correctly taken into account - values = np.arange(12 * 256 ** 2) * 3 - coord = SkyCoord([1, 2, 3] * u.deg, [4, 3, 1] * u.deg, frame='fk4') + values = np.arange(12 * 256**2) * 3 + coord = SkyCoord([1, 2, 3] * u.deg, [4, 3, 1] * u.deg, frame="fk4") result1 = self.pix.interpolate_bilinear_skycoord(coord, values) result2 = self.pix.interpolate_bilinear_skycoord(coord.icrs, values) @@ -201,7 +203,7 @@ def test_interpolate_bilinear_skycoord(self): assert_allclose(result1, result2) def test_cone_search_skycoord(self): - coord = SkyCoord(1 * u.deg, 4 * u.deg, frame='galactic') + coord = SkyCoord(1 * u.deg, 4 * u.deg, frame="galactic") result1 = self.pix.cone_search_skycoord(coord, 1 * u.deg) assert len(result1) == 77 result2 = self.pix.cone_search_skycoord(coord.icrs, 1 * u.deg) @@ -213,22 +215,20 @@ def test_boundaries_skycoord(self): class TestCelestialHEALPixFrameAsClass(TestCelestialHEALPix): - def setup_class(self): - self.pix = HEALPix(nside=256, order='nested', frame=Galactic) + self.pix = HEALPix(nside=256, order="nested", frame=Galactic) class TestCelestialHEALPixFrameAsString(TestCelestialHEALPix): - def setup_class(self): - self.pix = HEALPix(nside=256, order='nested', frame='galactic') + self.pix = HEALPix(nside=256, order="nested", frame="galactic") def test_invalid_frame_name(): with pytest.raises(ValueError, match='Coordinate frame name "foobar"'): - HEALPix(nside=256, frame='foobar') + HEALPix(nside=256, frame="foobar") def test_invalid_frame_type(): - with pytest.raises(ValueError, match='Coordinate frame must be a'): - HEALPix(nside=256, frame=('obviously', 'not', 'a', 'frame')) + with pytest.raises(ValueError, match="Coordinate frame must be a"): + HEALPix(nside=256, frame=("obviously", "not", "a", "frame")) diff --git a/astropy_healpix/tests/test_utils.py b/astropy_healpix/tests/test_utils.py index 0209dad..3186e98 100644 --- a/astropy_healpix/tests/test_utils.py +++ b/astropy_healpix/tests/test_utils.py @@ -8,40 +8,38 @@ def test_parse_coord_system(): - frame = parse_coord_system(Galactic()) assert isinstance(frame, Galactic) - frame = parse_coord_system('fk5') + frame = parse_coord_system("fk5") assert isinstance(frame, FK5) with pytest.raises(ValueError) as exc: - frame = parse_coord_system('e') + frame = parse_coord_system("e") assert exc.value.args[0] == "Ecliptic coordinate frame not yet supported" - frame = parse_coord_system('g') + frame = parse_coord_system("g") assert isinstance(frame, Galactic) with pytest.raises(ValueError) as exc: - frame = parse_coord_system('spam') + frame = parse_coord_system("spam") assert exc.value.args[0] == "Could not determine frame for system=spam" def test_parse_input_healpix_data(tmpdir): - data = np.arange(3072) - col = fits.Column(array=data, name='flux', format="E") + col = fits.Column(array=data, name="flux", format="E") hdu = fits.BinTableHDU.from_columns([col]) - hdu.header['NSIDE'] = 512 - hdu.header['COORDSYS'] = "G" + hdu.header["NSIDE"] = 512 + hdu.header["COORDSYS"] = "G" # As HDU array, coordinate_system, nested = parse_input_healpix_data(hdu) np.testing.assert_allclose(array, data) # As filename - filename = tmpdir.join('test.fits').strpath + filename = tmpdir.join("test.fits").strpath hdu.writeto(filename) array, coordinate_system, nested = parse_input_healpix_data(filename) np.testing.assert_allclose(array, data) @@ -53,5 +51,6 @@ def test_parse_input_healpix_data(tmpdir): # Invalid with pytest.raises(TypeError) as exc: parse_input_healpix_data(data) - assert exc.value.args[0] == ("input_data should either be an HDU object or " - "a tuple of (array, frame)") + assert exc.value.args[0] == ( + "input_data should either be an HDU object or " "a tuple of (array, frame)" + ) diff --git a/astropy_healpix/utils.py b/astropy_healpix/utils.py index 92ad4ff..b56434a 100644 --- a/astropy_healpix/utils.py +++ b/astropy_healpix/utils.py @@ -2,12 +2,14 @@ from astropy.io import fits from astropy.io.fits import TableHDU, BinTableHDU -from astropy.coordinates import BaseCoordinateFrame, frame_transform_graph, Galactic, ICRS +from astropy.coordinates import ( + BaseCoordinateFrame, + frame_transform_graph, + Galactic, + ICRS, +) -FRAMES = { - 'g': Galactic(), - 'c': ICRS() -} +FRAMES = {"g": Galactic(), "c": ICRS()} def parse_coord_system(system): @@ -15,7 +17,7 @@ def parse_coord_system(system): return system elif isinstance(system, str): system = system.lower() - if system == 'e': + if system == "e": raise ValueError("Ecliptic coordinate frame not yet supported") elif system in FRAMES: return FRAMES[system] @@ -35,10 +37,10 @@ def parse_input_healpix_data(input_data, field=0, hdu_in=None, nested=None): if isinstance(input_data, (TableHDU, BinTableHDU)): data = input_data.data header = input_data.header - coordinate_system_in = parse_coord_system(header['COORDSYS']) + coordinate_system_in = parse_coord_system(header["COORDSYS"]) array_in = data[data.columns[field].name].ravel() - if 'ORDERING' in header: - nested = header['ORDERING'].lower() == 'nested' + if "ORDERING" in header: + nested = header["ORDERING"].lower() == "nested" elif isinstance(input_data, str): hdu = fits.open(input_data)[hdu_in or 1] return parse_input_healpix_data(hdu, field=field) @@ -46,6 +48,8 @@ def parse_input_healpix_data(input_data, field=0, hdu_in=None, nested=None): array_in = input_data[0] coordinate_system_in = parse_coord_system(input_data[1]) else: - raise TypeError("input_data should either be an HDU object or a tuple of (array, frame)") + raise TypeError( + "input_data should either be an HDU object or a tuple of (array, frame)" + ) return array_in, coordinate_system_in, nested diff --git a/cextern/README.md b/cextern/README.md index efce305..b90eaee 100644 --- a/cextern/README.md +++ b/cextern/README.md @@ -6,7 +6,7 @@ See http://astropy-healpix.readthedocs.io/en/latest/about.html This README gives some technical details on the C code here. - The main file is `healpix.h` and `healpix.c`, start reading there first. -- For the Python `astropy-healpix` packge, the C code is built via `setup.py` +- For the Python `astropy-healpix` package, the C code is built via `setup.py` - However, to help work on the C code and test it directly, a `Makefile` is included here. - For testing, a copy of `CuTest.h` and `CuTest.c` from here is bundled: diff --git a/docs/_templates/autosummary/base.rst b/docs/_templates/autosummary/base.rst index 9cabaf5..1621719 100644 --- a/docs/_templates/autosummary/base.rst +++ b/docs/_templates/autosummary/base.rst @@ -1,2 +1,2 @@ {% extends "autosummary_core/base.rst" %} -{# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #} \ No newline at end of file +{# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #} diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst index 6b214a5..0fa59f2 100644 --- a/docs/_templates/autosummary/class.rst +++ b/docs/_templates/autosummary/class.rst @@ -1,2 +1,2 @@ {% extends "autosummary_core/class.rst" %} -{# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #} \ No newline at end of file +{# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #} diff --git a/docs/_templates/autosummary/module.rst b/docs/_templates/autosummary/module.rst index f38315b..230cd6e 100644 --- a/docs/_templates/autosummary/module.rst +++ b/docs/_templates/autosummary/module.rst @@ -1,2 +1,2 @@ {% extends "autosummary_core/module.rst" %} -{# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #} \ No newline at end of file +{# The template this is inherited from is in astropy/sphinx/ext/templates/autosummary_core. If you want to modify this template, it is strongly recommended that you still inherit from the astropy template. #} diff --git a/docs/cone_search.rst b/docs/cone_search.rst index a63d9c6..4ddd6f3 100644 --- a/docs/cone_search.rst +++ b/docs/cone_search.rst @@ -1,5 +1,5 @@ -Seaching for pixels around a position (cone search) -=================================================== +Searching for pixels around a position (cone search) +==================================================== A common operation when using HEALPix maps is to try and find all pixels that lie within a certain radius of a given longitude/latitude. One way to @@ -20,7 +20,7 @@ longitude/latitude:: 140 142 130 131 1239 1244 1238 1241 1243 1265 1267 1276 1273 1277 168 169 163 166 164] -Likewise, if a celestial frame was specified using the ``frame`` keyword arguent +Likewise, if a celestial frame was specified using the ``frame`` keyword argument to :class:`~astropy_healpix.HEALPix`, you can use the :meth:`~astropy_healpix.HEALPix.cone_search_skycoord` method to query around specific celestial coordinates:: diff --git a/docs/conf.py b/docs/conf.py index 94f122a..09cf0fa 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,23 +33,26 @@ try: from sphinx_astropy.conf.v1 import * # noqa except ImportError: - print('ERROR: the documentation requires the sphinx-astropy package to be installed') + print( + "ERROR: the documentation requires the sphinx-astropy package to be installed" + ) sys.exit(1) # Get configuration information from setup.cfg from configparser import ConfigParser + conf = ConfigParser() -conf.read([os.path.join(os.path.dirname(__file__), '..', 'setup.cfg')]) -setup_cfg = dict(conf.items('metadata')) +conf.read([os.path.join(os.path.dirname(__file__), "..", "setup.cfg")]) +setup_cfg = dict(conf.items("metadata")) # -- General configuration ---------------------------------------------------- # By default, highlight as Python 3. -highlight_language = 'python3' +highlight_language = "python3" # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.2' +# needs_sphinx = '1.2' # To perform a Sphinx version check that needs to be more specific than # major.minor, call `check_sphinx_version("X.Y.Z")` here. @@ -57,7 +60,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns.append('_templates') +exclude_patterns.append("_templates") # This is added to the end of RST files - a good place to put substitutions to # be used globally. @@ -67,20 +70,19 @@ # -- Project information ------------------------------------------------------ # This does not *have* to match the package name, but typically does -project = setup_cfg['name'] -author = setup_cfg['author'] -copyright = '{0}, {1}'.format( - datetime.datetime.now().year, setup_cfg['author']) +project = setup_cfg["name"] +author = setup_cfg["author"] +copyright = "{0}, {1}".format(datetime.datetime.now().year, setup_cfg["author"]) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -import_module(setup_cfg['name']) -package = sys.modules[setup_cfg['name']] +import_module(setup_cfg["name"]) +package = sys.modules[setup_cfg["name"]] # The short X.Y version. -version = package.__version__.split('-', 1)[0] +version = package.__version__.split("-", 1)[0] # The full version, including alpha/beta/rc tags. release = package.__version__ @@ -97,43 +99,43 @@ # Add any paths that contain custom themes here, relative to this directory. # To use a different custom theme, add the directory containing the theme. -#html_theme_path = [] +# html_theme_path = [] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. To override the custom theme, set this to the # name of a builtin theme or the name of a custom theme in html_theme_path. -#html_theme = None +# html_theme = None html_theme_options = { - 'logotext1': 'astropy', # white, semi-bold - 'logotext2': '-healpix', # orange, light - 'logotext3': ':docs' # white, light - } + "logotext1": "astropy", # white, semi-bold + "logotext2": "-healpix", # orange, light + "logotext3": ":docs", # white, light +} # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = '' +# html_logo = '' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = '' +# html_favicon = '' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '' +# html_last_updated_fmt = '' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = '{0} v{1}'.format(project, release) +html_title = "{0} v{1}".format(project, release) # Output file base name for HTML help builder. -htmlhelp_basename = project + 'doc' +htmlhelp_basename = project + "doc" # Prefixes that are ignored for sorting the Python module index modindex_common_prefix = ["astropy_healpix."] @@ -143,38 +145,37 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [('index', project + '.tex', project + u' Documentation', - author, 'manual')] +latex_documents = [ + ("index", project + ".tex", project + " Documentation", author, "manual") +] # -- Options for manual page output ------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [('index', project.lower(), project + u' Documentation', - [author], 1)] +man_pages = [("index", project.lower(), project + " Documentation", [author], 1)] # -- Options for the edit_on_github extension --------------------------------- -if setup_cfg.get('edit_on_github').lower() == 'true': - - extensions += ['sphinx_astropy.ext.edit_on_github'] +if setup_cfg.get("edit_on_github").lower() == "true": + extensions += ["sphinx_astropy.ext.edit_on_github"] - edit_on_github_project = setup_cfg['github_project'] + edit_on_github_project = setup_cfg["github_project"] edit_on_github_branch = "main" edit_on_github_source_root = "" edit_on_github_doc_root = "docs" # -- Resolving issue number to links in changelog ----------------------------- -github_issues_url = 'https://github.com/{0}/issues/'.format(setup_cfg['github_project']) +github_issues_url = "https://github.com/{0}/issues/".format(setup_cfg["github_project"]) # -- Options for linkcheck output ------------------------------------------- linkcheck_retry = 5 linkcheck_ignore = [ - r'https://github\.com/astropy/astropy/(?:issues|pull)/\d+', + r"https://github\.com/astropy/astropy/(?:issues|pull)/\d+", ] linkcheck_timeout = 180 linkcheck_anchors = False diff --git a/docs/interpolation.rst b/docs/interpolation.rst index 373b33c..f352eca 100644 --- a/docs/interpolation.rst +++ b/docs/interpolation.rst @@ -28,7 +28,7 @@ longitude/latitude on the sphere, there are two main options: interpolation. This is trickier to do by hand, and we therefore provide the methods :meth:`~astropy_healpix.HEALPix.interpolate_bilinear_lonlat` and :meth:`~astropy_healpix.HEALPix.interpolate_bilinear_skycoord` methods to - faciliate this. If you are not already familiar with how to access HEALPix + facilitate this. If you are not already familiar with how to access HEALPix data from FITS files, we have provided a `Full example`_ in the following section. diff --git a/environment-dev.yml b/environment-dev.yml index a101e5b..c2f2f8f 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -23,7 +23,6 @@ dependencies: - pytest - sphinx - pylint - - flake8 - hypothesis - pip: - sphinx-rtd-theme==0.3 diff --git a/pyproject.toml b/pyproject.toml index 8f4cd77..1105332 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,3 +12,14 @@ skip = "*-musllinux_* pp*" [tool.cibuildwheel.macos] archs = ["x86_64", "universal2"] + +[tool.ruff] +exclude = [ + "cextern", + "docs/conf.py", +] + +[tool.codespell] +skip = """ +cextern/* +""" diff --git a/setup.py b/setup.py index 709ef1d..5486812 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ http://docs.astropy.org/en/latest/development/testguide.html#running-tests """ -if 'test' in sys.argv: +if "test" in sys.argv: print(TEST_HELP) sys.exit(1) @@ -61,7 +61,7 @@ http://docs.astropy.org/en/latest/install.html#builddocs """ -if 'build_docs' in sys.argv or 'build_sphinx' in sys.argv: +if "build_docs" in sys.argv or "build_sphinx" in sys.argv: print(DOCS_HELP) sys.exit(1) @@ -76,6 +76,10 @@ version = '{version}' """.lstrip() -setup(use_scm_version={'write_to': os.path.join('astropy_healpix', 'version.py'), - 'write_to_template': VERSION_TEMPLATE}, - ext_modules=get_extensions()) +setup( + use_scm_version={ + "write_to": os.path.join("astropy_healpix", "version.py"), + "write_to_template": VERSION_TEMPLATE, + }, + ext_modules=get_extensions(), +) diff --git a/tox.ini b/tox.ini index 035b7aa..ffe087c 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,6 @@ envlist = py{310,311,312,313}-test{,-alldeps,-devdeps,-predeps}{,-cov} build_docs linkcheck - codestyle requires = setuptools >= 30.3.0 pip >= 19.3.1 @@ -88,10 +87,3 @@ extras = docs commands = pip freeze sphinx-build -W -b linkcheck . _build/html - -[testenv:codestyle] -skip_install = true -changedir = . -description = check code style, e.g. with flake8 -deps = flake8 -commands = flake8 astropy_healpix --count --max-line-length=100