Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ on:
branches: [ main, master ]

jobs:

pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1

build:

runs-on: ubuntu-latest
Expand Down
22 changes: 22 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-ast
- id: check-case-conflict
- id: check-yaml
args: ["--unsafe"]
- id: check-toml
- id: check-merge-conflict
- id: check-symlinks
- id: debug-statements
- id: detect-private-key
# - id: end-of-file-fixer
# - id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.12.3'
hooks:
- id: ruff
args: ["--fix"]
- id: ruff-format
66 changes: 66 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
extend = "pyproject.toml"

exclude = [
"docs",
".tox",
".eggs",
"build",
"*.ipynb",
"**/tests/**/__init__.py",
]
line-length = 100

target-version = "py312"

[format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true

[lint]
select = [
"F", # Pyflakes (part of default flake8)
"E", # pycodestyle (part of default flake8)
"W", # pycodestyle (part of default flake8)
"D", # docstrings, see also numpydoc pre-commit action
"N", # pep8-naming (naming conventions)
"A", # flake8-builtins (prevent shadowing of builtins)
"ARG", # flake8-unused-arguments (prevent unused arguments)
"B", # flake8-bugbear (miscellaneous best practices to avoid bugs)
"C4", # flake8-comprehensions (best practices for comprehensions)
"I", # isort
"ICN", # flake8-import-conventions (enforce import conventions)
"INP", # flake8-no-pep420 (prevent use of PEP420, i.e. implicit name spaces)
"ISC", # flake8-implicit-str-concat (conventions for concatenating long strings)
"LOG", # flake8-logging
"NPY", # numpy-specific rules
"PGH", # pygrep-hooks (ensure appropriate usage of noqa and type-ignore)
# "PTH", # flake8-use-pathlib (enforce using Pathlib instead of os)
"S", # flake8-bandit (security checks)
"SLF", # flake8-self (prevent using private class members outside class)
"SLOT", # flake8-slots (require __slots__ for immutable classes)
# "T20", # flake8-print (prevent print statements in code)
"TRY", # tryceratops (best practices for try/except blocks)
"UP", # pyupgrade (simplified syntax allowed by newer Python versions)
"YTT", # flake8-2020 (prevent some specific gotchas from sys.version)
"TID252" # Checks for relative imports
]
ignore = ["D100", "D104", "TRY003"]

[lint.per-file-ignores]
"**/tests/test_*.py" = [
"D",
"S",
]

[lint.pydocstyle]
convention = "numpy"

[lint.flake8-annotations]
ignore-fully-untyped = true # Turn off annotation checking for fully untyped code

[lint.flake8-tidy-imports]
ban-relative-imports = "all" # Disallow all relative imports.

[lint.isort]
known-first-party = ["nirc2_reduce"]
13 changes: 5 additions & 8 deletions nirc2_reduce/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@

TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Tuple
from typing import Union

VERSION_TUPLE = Tuple[Union[int, str], ...]
COMMIT_ID = Union[str, None]
VERSION_TUPLE = tuple[int | str, ...]
COMMIT_ID = str | None
else:
VERSION_TUPLE = object
COMMIT_ID = object
Expand All @@ -28,7 +25,7 @@
commit_id: COMMIT_ID
__commit_id__: COMMIT_ID

__version__ = version = '0.1.dev53+g310c26299.d20250816'
__version_tuple__ = version_tuple = (0, 1, 'dev53', 'g310c26299.d20250816')
__version__ = version = "0.1.dev55+g3741c605e.d20250817"
__version_tuple__ = version_tuple = (0, 1, "dev55", "g3741c605e.d20250817")

__commit_id__ = commit_id = 'g310c26299'
__commit_id__ = commit_id = "g3741c605e"
52 changes: 31 additions & 21 deletions nirc2_reduce/flats.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import numpy as np
import matplotlib.pyplot as plt
from astropy.io import fits
from .image import Image
import warnings

import matplotlib.pyplot as plt
import numpy as np

from nirc2_reduce.image import Image


class Flats:
"""
class for dome flats
"""
"""Class for dome flats."""

def __init__(self, fnames_off, fnames_on):
"""
subtract lights off from lights on,
divide by median value to center it around 1

Subtract lights off from lights on.

Divide by median value to center it around 1

Parameters
----------
fnames_off : list, required. fits files for dome flat OFF
fnames_on : list, required. fits files for dome flat ON

Attributes
----------
dummy_fits : Image object used to hijack header info
Expand All @@ -32,16 +33,23 @@ def __init__(self, fnames_off, fnames_on):

off = np.nanmedian(self.frames_off, axis=0)
on = np.nanmedian(self.frames_on, axis=0)
if (np.nanmean(on) - np.nanmean(off))/np.nanmean(on) < 0.01:
warnings.warn(f'brightness difference between domeflaton and domeflatoff is near zero for flat including fname {fnames_on[0]}. setting to off. if this is a thermal filter (lp, ms) then this is probably ok', stacklevel=2)
if (np.nanmean(on) - np.nanmean(off)) / np.nanmean(on) < 0.01:
warnings.warn(
"brightness difference between domeflaton and domeflatoff is near zero "
f"for flat including fname {fnames_on[0]}. setting to off. "
"if this is a thermal filter (lp, ms) then this is probably ok",
stacklevel=2,
)
flat = off
else:
flat = on - off

self.flat = flat / np.nanmedian(flat)

def write(self, outfile):
"""
Write the flat to fits.

Parameters
----------
outfile : str, required. output fits filename
Expand All @@ -53,23 +61,25 @@ def write(self, outfile):
hdulist_out[0].writeto(outfile, overwrite=True)

def plot(self):
"""Make a simple plot of the flat."""
plt.imshow(self.flat, origin="lower")
plt.show()

def make_badpx_map(self, outfile, tol=0.07, blocksize=6):
"""
Find pixels whose values are very far from the average of their neighbors
Bad pixel is defined as
Find pixels whose values are very far from the average of their neighbors.

Bad pixel is defined as
abs(pixel value / median of nearby pixels - 1) > tol

Parameters
----------
outfile : str, required.
outfile : str, required.
fits filename to write to
tol : float, optional. default 0.07
fractional tolerance.
fractional tolerance.
blocksize : int, optional. default 6
number of pixels over which to average
number of pixels over which to average
in each direction
"""
badpx_map = np.ones(self.flat.shape)
Expand All @@ -78,7 +88,7 @@ def make_badpx_map(self, outfile, tol=0.07, blocksize=6):
flatblock = self.flat[i : i + blocksize, j : j + blocksize]
mapblock = badpx_map[i : i + blocksize, j : j + blocksize]
with warnings.catch_warnings():
warnings.filterwarnings('ignore', category=RuntimeWarning)
warnings.filterwarnings("ignore", category=RuntimeWarning)
med = np.median(flatblock)

# if not within tolerance, set to NaN
Expand Down
34 changes: 24 additions & 10 deletions nirc2_reduce/image.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import numpy as np
import warnings

import matplotlib.pyplot as plt
from astropy.io import fits
import warnings


class Image:
"""
Thin wrapper to astropy.io.fits providing convenience functions
and suppression of warnings in fits.open

Thin wrapper to astropy.io.fits.

To do
-----
make agnostic to specific .fits header keywords
Expand All @@ -17,10 +16,12 @@ class Image:

def __init__(self, fname):
"""
Provide convenience function for opening fits files.

Parameters
----------
fname : str, required. input .fits filename

Attributes
----------
hdulist: .fits format hdulist structure
Expand All @@ -31,15 +32,17 @@ def __init__(self, fname):
"""
warnings.filterwarnings(
"ignore",
"The following header keyword is invalid or follows an unrecognized non-standard convention",
"The following header keyword is invalid or follows an unrecognized "
"non-standard convention",
)
warnings.filterwarnings(
"ignore",
"non-ASCII characters are present in the FITS file header and have been replaced",
)
warnings.filterwarnings(
"ignore",
"Header block contains null bytes instead of spaces for padding, and is not FITS-compliant",
"Header block contains null bytes instead of spaces for padding, "
"and is not FITS-compliant",
)
self.hdulist = fits.open(fname, ignore_missing_end=True)
self.header = self.hdulist[0].header
Expand All @@ -51,7 +54,7 @@ def __init__(self, fname):
try:
targ = self.header["OBJECT"]
self.target = targ.split()[0].strip(", \n").capitalize()
except:
except KeyError:
self.target = "Unknown"
try:
fwi = self.header["FWINAME"].strip(", \n")
Expand All @@ -60,14 +63,25 @@ def __init__(self, fname):
self.filt = fwi
elif fwi == "clear" or fwi == "PK50_1.5":
self.filt = fwo
except:
else:
self.filt = "Unknown"
except KeyError:
self.filt = "Unknown"

def plot(self):
"""Make a simple plot of the data."""
plt.imshow(self.data, origin="lower left")
plt.show()

def write(self, fname):
"""
Write the image to fits.

Parameters
----------
fname : str
Filename to write to.
"""
self.hdulist[0].header = self.header
self.hdulist[0].data = self.data
self.hdulist.writeto(fname, overwrite=True)
Loading