diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..4ca1bec --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: © 2024 the i3astropy contributors +# +# SPDX-License-Identifier: BSD-2-Clause + +version: 2 +updates: + - package-ecosystem: pip + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: + - "*" + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e9df6c2..bd4a846 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,49 +6,53 @@ name: Tests on: push: branches: - - main + - main pull_request: + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: Tests: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11', '3.12'] + python-version: ["3.9", "3.10", "3.11", "3.12"] os: [ubuntu-22.04] include: - - python-version: 3.12 - os: macos-12 + - python-version: 3.12 + os: macos-12 steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: pip - cache-dependency-path: pyproject.toml - - name: Install i3astropy - run: python3 -m pip install .[test] - - name: Run Unit Tests - run: pytest - - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v3 - with: - fail_ci_if_error: false - verbose: true + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: pyproject.toml + - name: Install i3astropy + run: python3 -m pip install .[test] + - name: Run Unit Tests + run: pytest + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v3 + with: + fail_ci_if_error: false + verbose: true Docs: runs-on: ubuntu-22.04 strategy: fail-fast: false steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: pip - cache-dependency-path: pyproject.toml - - name: Install i3astropy - run: python3 -m pip install .[docs] - - name: Build Docs - run: mkdocs build + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml + - name: Install i3astropy + run: python3 -m pip install .[docs] + - name: Build Docs + run: mkdocs build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 10c07f8..e18cbf7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,67 +6,77 @@ ci: autoupdate_commit_msg: autoupdate pre-commit hooks autoupdate_schedule: quarterly repos: -- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks - rev: v2.12.0 - hooks: - - id: pretty-format-toml - args: [--autofix] - - id: pretty-format-yaml - args: [--autofix] -- repo: https://github.com/fsfe/reuse-tool - rev: v2.1.0 - hooks: - - id: reuse -- repo: https://github.com/psf/black - rev: 23.12.1 - hooks: - - id: black -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.9 - hooks: - - id: ruff - args: [--fix] -- repo: https://github.com/pycqa/pylint - rev: v3.0.3 - hooks: - - id: pylint -- repo: https://github.com/codespell-project/codespell - rev: v2.2.6 - hooks: - - id: codespell - args: [-L, livetime] -- repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.10.0 - hooks: - - id: python-check-blanket-noqa - - id: python-no-log-warn - - id: python-no-eval - - id: python-use-type-annotations -- repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.4 - hooks: - - id: forbid-crlf - - id: forbid-tabs -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: check-added-large-files - - id: check-ast - - id: check-builtin-literals - - id: check-case-conflict - - id: check-docstring-first - - id: check-executables-have-shebangs - - id: check-merge-conflict - - id: check-shebang-scripts-are-executable - - id: check-toml - - id: check-vcs-permalinks - - id: check-yaml - - id: debug-statements - - id: detect-private-key - - id: end-of-file-fixer - - id: fix-byte-order-marker - - id: mixed-line-ending - - id: name-tests-test - args: [--pytest-test-first] - - id: trailing-whitespace - exclude: \.svg$ + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + files: \.ya?ml$ + - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks + rev: v2.12.0 + hooks: + - id: pretty-format-toml + args: [--autofix] + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.1 + hooks: + - id: reuse + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + additional_dependencies: [numpy] + files: src/i3astropy + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.14 + hooks: + - id: ruff + args: [--fix, --show-fixes] + - id: ruff-format + - repo: https://github.com/pycqa/pylint + rev: v3.0.3 + hooks: + - id: pylint + - repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + args: [-L, livetime] + - repo: https://github.com/adamchainz/blacken-docs + rev: "1.16.0" + hooks: + - id: blacken-docs + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: python-check-blanket-noqa + - id: python-no-log-warn + - id: python-no-eval + - id: python-use-type-annotations + - repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.4 + hooks: + - id: forbid-crlf + - id: forbid-tabs + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-added-large-files + - id: check-ast + - id: check-builtin-literals + - id: check-case-conflict + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-toml + - id: check-vcs-permalinks + - id: check-yaml + - id: debug-statements + - id: detect-private-key + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending + - id: name-tests-test + args: [--pytest-test-first] + - id: trailing-whitespace + exclude: \.svg$ diff --git a/README.md b/README.md index bc51d4b..025a742 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ so that you can test changes without reinstalling the module: This example takes an event which occurred at DAQ time (2021, 155525688461058500) and was reconstructed in the direction of zenith = 0.73884 rad, azimuth = 2.7348 rad and converts it to RA and Dec. In addition, get the Sun position in IceCube coordinates at the same time. -```python +```pycon >>> from astropy.coordinates import ICRS, get_sun >>> from astropy.time import Time diff --git a/examples/compare_ps_sample.py b/examples/compare_ps_sample.py index 048f650..a539408 100755 --- a/examples/compare_ps_sample.py +++ b/examples/compare_ps_sample.py @@ -17,9 +17,10 @@ from astropy import units as u from astropy.coordinates import ICRS from astropy.time import Time -from i3astropy import I3Dir from numpy import allclose +from i3astropy import I3Dir + # need file from /data/ana/analyses/ps_tracks/version-004-p00/IC86_2019_exp.npy f = np.load("IC86_2019_exp.npy") N = 10000 diff --git a/examples/plot_analemma.py b/examples/plot_analemma.py index 4c03e09..49d1c3d 100755 --- a/examples/plot_analemma.py +++ b/examples/plot_analemma.py @@ -16,9 +16,10 @@ from astropy.coordinates import get_sun from astropy.time import Time from astropy.units import day -from i3astropy import I3Dir from matplotlib import ticker +from i3astropy import I3Dir + LEFT_MARGIN, RIGHT_MARGIN = 0.08, 0.02 ANALAMA_WIDTH = 0.2 TOP_MARGIN, BOTTOM_MARGIN = 0.01, 0.08 diff --git a/examples/plot_moon.py b/examples/plot_moon.py index 4fd6d54..38c6d73 100755 --- a/examples/plot_moon.py +++ b/examples/plot_moon.py @@ -18,10 +18,11 @@ from astropy.coordinates import get_moon from astropy.time import Time from astropy.units import day -from i3astropy import I3Dir from matplotlib.dates import DateFormatter, YearLocator from matplotlib.ticker import FormatStrFormatter +from i3astropy import I3Dir + warnings.simplefilter("ignore") t0 = Time("2020-01-02 00:00") diff --git a/examples/plot_sun_azimuth.py b/examples/plot_sun_azimuth.py index 2a7d19d..8e20acd 100755 --- a/examples/plot_sun_azimuth.py +++ b/examples/plot_sun_azimuth.py @@ -18,9 +18,10 @@ from astropy.coordinates import ICRS, get_sun from astropy.time import Time from astropy.units import day, deg -from i3astropy import I3Dir from matplotlib import patches, ticker +from i3astropy import I3Dir + # pylint: disable=R0913 def draw_circ(axis, radius, cent_x, cent_y, angle_, theta2_, color_="black"): diff --git a/pyproject.toml b/pyproject.toml index 8c7e300..8a553c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,16 @@ line_length = 108 multi_line_output = 3 use_parentheses = true +[tool.mypy] +allow_subclassing_any = true +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] +exclude = 'docs|examples|tests' +files = 'src/i3astropy' +ignore_missing_imports = true +plugins = "numpy.typing.mypy_plugin" +strict = true +warn_unreachable = true + [tool.pylint.format] max-line-length = "108" @@ -59,26 +69,38 @@ max-line-length = "108" disable = ["W0201", "R0903", "E0401", "C0411"] [tool.pytest.ini_options] -addopts = "--cov=i3astropy --doctest-glob='README.md'" +addopts = ["--cov=i3astropy", "--doctest-glob=README.md", "-ra", "--strict-config", "--strict-markers"] +filterwarnings = ["error"] +log_cli_level = "INFO" +minversion = 7 testpaths = ["tests", "README.md"] +xfail_strict = true [tool.ruff] +line-length = 108 +show-fixes = true +src = ['src'] +target-version = "py39" + +[tool.ruff.lint] fixable = ["I"] ignore = [ - "ANN", # flake8-annotations + "ANN401", # any-type "INP001", # flake8-no-pep420 "S101", # assert-used "D213", # multi-line-summary-second-line incompatible with multi-line-summary-first-line "D203", # one-blank-line-before-class" incompatible with no-blank-line-before-class "RUF012" # mutable-class-default ] -line-length = 108 select = ["ALL"] -target-version = "py39" -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "examples/*" = [ + "ANN", # flake8-annotations "PLR", # max-statements "ARG", # flake8-unused-arguments "T201" # flake8-print ] +"tests/*" = [ + "ANN" # flake8-annotations +] diff --git a/src/i3astropy/__init__.py b/src/i3astropy/__init__.py index 073c00a..268533b 100644 --- a/src/i3astropy/__init__.py +++ b/src/i3astropy/__init__.py @@ -7,6 +7,8 @@ __all__ = ["I3Time", "I3Dir", "I3DirToAltAz", "AltAzToI3Dir", "i3location"] __version__ = "0.1" +from typing import Any + import erfa import numpy as np from astropy.coordinates import AltAz, EarthLocation @@ -17,6 +19,7 @@ from astropy.time import TimeFormat from astropy.time.core import ScaleValueError from astropy.units import deg, m +from numpy.typing import NDArray # This is the nominal location of the center of the IceCube detector i3location = EarthLocation(lat=-89.9944 * deg, lon=-62.6081 * deg, height=883.9 * m) @@ -41,14 +44,14 @@ class I3Time(TimeFormat): _DAQ_TICKS_IN_DAY = int(864e12) _default_precision = 9 - def set_jds(self, val1, val2): + def set_jds(self: "I3Time", val1: NDArray[np.float64], val2: NDArray[np.float64]) -> None: """Set the internal jd1 and jd2 values from the input year and DAQ time. Year is in val1 and daq time is in val2. The input values are expected to conform to this format, as validated by self._check_val_type(val1, val2) during __init__. """ - self._scale = self._check_scale(self._scale) # Validate scale. + self._scale: str = self._check_scale(self._scale) # Validate scale. if self._scale != "utc": msg = f"Got scale '{self._scale}', The only allowed scale for I3Time is 'utc'" raise ScaleValueError(msg) @@ -66,7 +69,7 @@ def set_jds(self, val1, val2): self.jd1, self.jd2 = erfa.taiutc(tai1 + days, tai2 + remainder / self._DAQ_TICKS_IN_DAY) @property - def value(self): + def value(self: "I3Time") -> NDArray[np.float64]: """Return year and daq time from internal jd1, jd2.""" assert self.scale == "utc" # create empty output array with correct type @@ -106,7 +109,7 @@ class I3Dir(BaseCoordinateFrame): obstime = TimeAttribute(default=None) location = i3location - def __init__(self, *args, **kwargs) -> None: + def __init__(self: "I3Dir", *args: Any, **kwargs: Any) -> None: """Initialize I3Dir.""" if "zen" in kwargs and "az" in kwargs and "r" not in kwargs: kwargs["r"] = 1 @@ -119,11 +122,11 @@ class I3DirToAltAz(CoordinateTransform): For local directions. """ - def __init__(self) -> None: + def __init__(self: "I3DirToAltAz") -> None: """Initialize I3DirToAltAz.""" super().__init__(I3Dir, AltAz) - def __call__(self, i3dir, *args, **kwargs): # noqa: ARG002 + def __call__(self: "I3DirToAltAz", i3dir: I3Dir, *args: Any, **kwargs: Any) -> AltAz: # noqa: ARG002 """Call I3DirToAltAz.""" alt = 90 * deg - i3dir.zen azi = 90 * deg - i3dir.az - i3location.lon @@ -133,11 +136,11 @@ def __call__(self, i3dir, *args, **kwargs): # noqa: ARG002 class AltAzToI3Dir(CoordinateTransform): """Convert from local astronomy coordinates to IceCube coordinates.""" - def __init__(self) -> None: + def __init__(self: "AltAzToI3Dir") -> None: """Initialize AltAzToI3Dir.""" super().__init__(AltAz, I3Dir) - def __call__(self, altaz, *args, **kwargs): # noqa: ARG002 + def __call__(self: "AltAzToI3Dir", altaz: AltAz, *args: Any, **kwargs: Any) -> I3Dir: # noqa: ARG002 """Call AltAzToI3Dir.""" zen = 90 * deg - altaz.alt azi = 90 * deg - altaz.az - i3location.lon diff --git a/tests/test_coord.py b/tests/test_coord.py index 381a350..b017b5e 100755 --- a/tests/test_coord.py +++ b/tests/test_coord.py @@ -7,6 +7,7 @@ """Test Coordinate transforms in i3astropy.""" import contextlib +import sys import numpy as np import pytest @@ -14,9 +15,10 @@ from astropy.coordinates import ICRS, Angle, SkyCoord, get_moon, get_sun from astropy.time import Time from astropy.units import day, deg, hour -from i3astropy import I3Dir from numpy.testing import assert_allclose +from i3astropy import I3Dir + with contextlib.suppress(ImportError): from icecube import astro @@ -206,4 +208,4 @@ def test_icetray(): if __name__ == "__main__": - pytest.main(["-v", __file__]) + pytest.main(["-v", __file__, *sys.argv]) diff --git a/tests/test_time.py b/tests/test_time.py index f6ab669..9990442 100755 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -7,8 +7,8 @@ """Tests related to I3Time in i3astropy.""" import contextlib +import sys -import i3astropy # noqa: F401 pylint: disable=W0611 import numpy as np import pytest from astropy import units as u @@ -16,6 +16,8 @@ from astropy.time.core import ScaleValueError from numpy.testing import assert_allclose, assert_equal +import i3astropy # noqa: F401 pylint: disable=W0611 + with contextlib.suppress(ImportError): from icecube.dataclasses import I3Time # pylint: disable=E0611 @@ -114,4 +116,4 @@ def test_icetray(subtests): if __name__ == "__main__": - pytest.main(["-v", __file__]) + pytest.main(["-v", __file__, *sys.argv])