Skip to content

Commit

Permalink
v1.6.4
Browse files Browse the repository at this point in the history
version 1.6.4
  • Loading branch information
thusser authored Nov 13, 2023
2 parents 74fd14e + 22400b7 commit 166b061
Show file tree
Hide file tree
Showing 21 changed files with 982 additions and 332 deletions.
650 changes: 366 additions & 284 deletions poetry.lock

Large diffs are not rendered by default.

30 changes: 12 additions & 18 deletions pyobs/images/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,8 @@ def from_file(cls, filename: str) -> Image:
New image.
"""

# open file
data = fits.open(filename, memmap=False, lazy_load_hdus=False)

# load image
image = cls._from_hdu_list(data)

# close file
data.close()
return image
with fits.open(filename, memmap=False, lazy_load_hdus=False) as data:
return cls._from_hdu_list(data)

@classmethod
def from_ccddata(cls, data: CCDData) -> Image:
Expand All @@ -113,7 +106,7 @@ def from_ccddata(cls, data: CCDData) -> Image:
image = Image(
data=data.data.astype(np.float32),
header=data.header,
mask=None if data.mask is None else data.mask,
mask=data.mask,
uncertainty=None if data.uncertainty is None else data.uncertainty.array.astype(np.float32),
)
return image
Expand All @@ -135,10 +128,8 @@ def _from_hdu_list(cls, data: fits.HDUList) -> "Image":
# find HDU with image data
for hdu in data:
if (
isinstance(hdu, fits.PrimaryHDU)
and hdu.header["NAXIS"] > 0
or isinstance(hdu, fits.ImageHDU)
and hdu.name == "SCI"
isinstance(hdu, fits.PrimaryHDU) and hdu.header["NAXIS"] > 0
or isinstance(hdu, fits.ImageHDU) and hdu.name == "SCI"
or isinstance(hdu, fits.CompImageHDU)
):
# found image HDU
Expand Down Expand Up @@ -173,7 +164,10 @@ def _from_hdu_list(cls, data: fits.HDUList) -> "Image":
@property
def unit(self) -> str:
"""Returns units of pixels in image."""
return str(self.header["BUNIT"]).lower() if "BUNIT" in self.header else "adu"
if "BUNIT" in self.header:
return str(self.header["BUNIT"]).lower()
else:
return "adu"

def __deepcopy__(self) -> Image:
"""Returns a shallow copy of this image."""
Expand All @@ -191,7 +185,7 @@ def copy(self) -> Image:
meta=self.meta,
)

def __truediv__(self, other: "Image") -> "Image":
def __truediv__(self, other: Image) -> Image:
"""Divides this image by other."""
img = self.copy()
if img.data is None or other.data is None:
Expand Down Expand Up @@ -251,8 +245,8 @@ def write_catalog(self, f: Any, *args: Any, **kwargs: Any) -> None:
if self.catalog is None:
return

# create HDU and write it
table_to_hdu(self.catalog).writeto(f, *args, **kwargs)
hdu = table_to_hdu(self.catalog)
hdu.writeto(f, *args, **kwargs)

def to_ccddata(self) -> CCDData:
"""Convert Image to CCDData"""
Expand Down
1 change: 1 addition & 0 deletions pyobs/images/meta/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .radecoffsets import RaDecOffsets
from .skyoffsets import SkyOffsets
from .onskydistance import OnSkyDistance
from .exptime import ExpTime
2 changes: 1 addition & 1 deletion pyobs/images/processors/astrometry/_dotnet_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def _handle_request_error(self):
error_msg = self._generate_request_error_msg()
raise exc.ImageError(error_msg)

def _is_request_successful(self):
def _is_request_successful(self) -> bool:
return self._status_code != 200 or "error" in self._response_data

async def send(self, url: str, timeout: int):
Expand Down
27 changes: 12 additions & 15 deletions pyobs/images/processors/astrometry/_dotnet_request_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, Any
from typing import Optional

import pandas as pd
from astropy.io.fits import Header
Expand All @@ -14,17 +14,8 @@ def __init__(self, source_count: int, radius: float):
self._radius = radius

self._request_data = {}
self._catalog: pd.DataFrame = None
self._header: Header = None

def add_catalog_from_image(self, image: Image):
if image.catalog is None:
raise exc.ImageError("No catalog found in image.")

self._catalog = image.catalog[["x", "y", "flux", "peak"]].to_pandas()

def add_header_from_image(self, image: Image):
self._header = image.header
self._catalog = pd.DataFrame()
self._header: Optional[Header] = None

def _filter_catalog(self):
self._catalog = self._catalog.dropna(how="any")
Expand Down Expand Up @@ -57,13 +48,19 @@ def _build_request_data(self):
"flux": self._catalog["flux"].tolist(),
}

def __call__(self) -> _DotNetRequest:
def __call__(self, image: Image) -> _DotNetRequest:
# set catalog and header
if image.catalog is None:
raise exc.ImageError("No catalog found in image.")
self._catalog = image.catalog[["x", "y", "flux", "peak"]].to_pandas()
self._header = image.header

# select stars
self._filter_catalog()
self._validate_catalog()
self._select_brightest_stars()

# validate header and build request
self._validate_header()

self._build_request_data()

return _DotNetRequest(self._request_data)
5 changes: 2 additions & 3 deletions pyobs/images/processors/astrometry/dotnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ def __init__(
self._request_builder = _DotNetRequestBuilder(source_count, radius)

async def _process(self, image: Image) -> Image:
self._request_builder.add_catalog_from_image(image)
self._request_builder.add_header_from_image(image)
request = self._request_builder()
# build the request
request = self._request_builder(image)

logger = _RequestLogger(log, image, request.request_data)
logger.log_request_data()
Expand Down
2 changes: 2 additions & 0 deletions pyobs/utils/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ def handle_exception(exception: PyObsError) -> PyObsError:

# filter triggered handlers by those that actually handle the exception
handlers = list(filter(lambda h: isinstance(exception, h.exc_type), triggered_handlers))
if hasattr(exception, "exception"):
handlers += list(filter(lambda h: isinstance(exception.exception, h.exc_type), triggered_handlers))

# check all handlers
for h in handlers:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "pyobs-core"
packages = [{ include = "pyobs" }]
version = "1.6.3"
version = "1.6.4"
description = "robotic telescope software"
authors = ["Tim-Oliver Husser <[email protected]>"]
license = "MIT"
Expand Down
Empty file added tests/images/__init__.py
Empty file.
Empty file added tests/images/meta/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions tests/images/meta/test_altazoffsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pyobs.images.meta import AltAzOffsets


def test_alt_az_offsets():
dalt = 1.0
daz = 2.0

meta = AltAzOffsets(dalt, daz)

assert meta.dalt == dalt
assert meta.daz == daz
8 changes: 8 additions & 0 deletions tests/images/meta/test_exptime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from pyobs.images.meta import ExpTime


def test_exp_time():
exp_time = 1.0
meta = ExpTime(exp_time)

assert meta.exptime == exp_time
10 changes: 10 additions & 0 deletions tests/images/meta/test_onskydistance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from astropy.coordinates import Angle
from pyobs.images.meta import OnSkyDistance


def test_onskydistance():
distance = Angle(1.0, unit="deg")
meta = OnSkyDistance(distance)

assert meta.distance.unit == distance.unit
assert meta.distance.value == distance.value
11 changes: 11 additions & 0 deletions tests/images/meta/test_pixeloffsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pyobs.images.meta import PixelOffsets


def test_pixeloffsets():
dx = 1.0
dy = 2.0

meta = PixelOffsets(dx, dy)

assert meta.dx == dx
assert meta.dy == dy
12 changes: 12 additions & 0 deletions tests/images/meta/test_radecoffsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pyobs.images.meta import RaDecOffsets


def test_radecoffsets():
dra = 1.0
ddec = 2.0

meta = RaDecOffsets(dra, ddec)

assert meta.dra == dra
assert meta.ddec == ddec

86 changes: 86 additions & 0 deletions tests/images/meta/test_skyoffsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import astropy

from pyobs.images.meta import SkyOffsets
from astropy.coordinates import SkyCoord, BaseCoordinateFrame


def test_init():
coord0 = SkyCoord(ra=0.0, dec=0.0, unit="deg")
coord1 = SkyCoord(ra=1.0, dec=1.0, unit="deg")

meta = SkyOffsets(coord0, coord1)

assert meta.coord0.ra.deg == coord0.ra.deg
assert meta.coord0.dec.deg == coord0.dec.deg

assert meta.coord1.ra.deg == coord1.ra.deg
assert meta.coord1.dec.deg == coord1.dec.deg


def test_to_frame_non_value():
coord0 = SkyCoord(ra=0.0, dec=0.0, unit="deg")
coord1 = SkyCoord(ra=1.0, dec=1.0, unit="deg")

meta = SkyOffsets(coord0, coord1)

framed_coord0, framed_coord1 = meta._to_frame()

assert framed_coord0.ra.deg == coord0.ra.deg
assert framed_coord0.dec.deg == coord0.dec.deg

assert framed_coord1.ra.deg == coord1.ra.deg
assert framed_coord1.dec.deg == coord1.dec.deg


def test_to_frame_w_value(mocker):
"""
Tests that SkyCoord.transform_to is correctly used
"""
frame = BaseCoordinateFrame()

coord0 = SkyCoord(ra=0.0, dec=0.0, unit="deg")
coord1 = SkyCoord(ra=1.0, dec=1.0, unit="deg")
meta = SkyOffsets(coord0, coord1)

mocker.patch("astropy.coordinates.SkyCoord.transform_to", return_value=0)

x, y = meta._to_frame(frame)

astropy.coordinates.SkyCoord.transform_to.assert_called_with(frame)

assert x == 0
assert y == 0


def test_separation(mocker):
"""
Tests that _to_frame and separation is correctly used
"""
coord0 = SkyCoord(ra=0.0, dec=0.0, unit="deg")
coord1 = SkyCoord(ra=1.0, dec=1.0, unit="deg")
meta = SkyOffsets(coord0, coord1)

mocker.patch.object(meta, "_to_frame", return_value=(coord0, coord1))
mocker.patch("astropy.coordinates.SkyCoord.separation", return_value=0)

assert meta.separation() == 0

meta._to_frame.assert_called_once_with(None)
astropy.coordinates.SkyCoord.separation.assert_called_once_with(coord1)


def test_spherical_offsets(mocker):
"""
Tests that _to_frame and spherical_offsets_to is correctly used
"""
coord0 = SkyCoord(ra=0.0, dec=0.0, unit="deg")
coord1 = SkyCoord(ra=1.0, dec=1.0, unit="deg")
meta = SkyOffsets(coord0, coord1)

mocker.patch.object(meta, "_to_frame", return_value=(coord0, coord1))
mocker.patch("astropy.coordinates.SkyCoord.spherical_offsets_to", return_value=(0, 1))

assert meta.spherical_offsets() == (0, 1)

meta._to_frame.assert_called_once_with(None)
astropy.coordinates.SkyCoord.spherical_offsets_to.assert_called_once_with(coord1.frame)
Loading

0 comments on commit 166b061

Please sign in to comment.