Coverage for python / lsst / images / fields / _concrete.py: 41%

29 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-05-15 01:54 -0700

1# This file is part of lsst-images. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12from __future__ import annotations 

13 

14__all__ = ( 

15 "Field", 

16 "FieldSerializationModel", 

17 "field_from_legacy", 

18 "field_from_legacy_background", 

19) 

20 

21from typing import TYPE_CHECKING, Annotated, Any 

22 

23import astropy.units 

24import pydantic 

25 

26from ._chebyshev import ChebyshevField, ChebyshevFieldSerializationModel 

27from ._product import ProductField, ProductFieldSerializationModel 

28from ._spline import SplineField, SplineFieldSerializationModel 

29from ._sum import SumField, SumFieldSerializationModel 

30 

31if TYPE_CHECKING: 

32 try: 

33 from lsst.afw.math import BackgroundList as LegacyBackgroundList 

34 from lsst.afw.math import BackgroundMI as LegacyBackground 

35 from lsst.afw.math import BoundedField as LegacyBoundedField 

36 except ImportError: 

37 type LegacyBoundedField = Any # type: ignore[no-redef] 

38 type LegacyBackground = Any # type: ignore[no-redef] 

39 type LegacyBackgroundList = Any # type: ignore[no-redef] 

40 

41 

42# Since Sphinx can't handle doc links to type aliases, whenever we annotate 

43# a type as `Field`, we override the docs to say `BaseField`, since 

44# `BaseField` is a base class that serves as a much more useful doc link, and 

45# because the hierarchy is closed they're equivalent. But we have to use 

46# `Field` in the type annotations because there's no way to declare to MyPy 

47# et all that the hierarchy is closed. 

48 

49type Field = ChebyshevField | ProductField | SplineField | SumField 

50type FieldSerializationModel = Annotated[ 

51 ChebyshevFieldSerializationModel 

52 | ProductFieldSerializationModel 

53 | SplineFieldSerializationModel 

54 | SumFieldSerializationModel, 

55 pydantic.Field(discriminator="field_type"), 

56] 

57 

58 

59ProductFieldSerializationModel.model_rebuild() 

60SumFieldSerializationModel.model_rebuild() 

61 

62 

63def field_from_legacy( 

64 legacy_bounded_field: LegacyBoundedField, unit: astropy.units.UnitBase | None = None 

65) -> Field: 

66 """Convert a legacy `lsst.afw.math.BoundedField` subclass to a `BaseField` 

67 object. 

68 """ 

69 from lsst.afw.math import ChebyshevBoundedField, ProductBoundedField 

70 

71 match legacy_bounded_field: 

72 case ChebyshevBoundedField(): 

73 return ChebyshevField.from_legacy(legacy_bounded_field, unit=unit) 

74 case ProductBoundedField(): 

75 return ProductField.from_legacy(legacy_bounded_field, unit=unit) 

76 case _: 

77 raise NotImplementedError( 

78 f"Conversion from {type(legacy_bounded_field).__name__} is not supported." 

79 ) 

80 

81 

82def field_from_legacy_background( 

83 legacy_background: LegacyBackground | LegacyBackgroundList, unit: astropy.units.UnitBase | None = None 

84) -> Field: 

85 """Convert a legacy `lsst.afw.math.Background` or 

86 `lsst.afw.math.BackgroundList` instance to a `BaseField` object. 

87 """ 

88 from lsst.afw.math import ApproximateControl, BackgroundList 

89 

90 if isinstance(legacy_background, BackgroundList): 

91 return SumField.from_legacy_background(legacy_background) 

92 

93 approx_control = legacy_background.getBackgroundControl().getApproximateControl() 

94 if approx_control.getStyle() == ApproximateControl.UNKNOWN: 

95 return SplineField.from_legacy_background(legacy_background, unit=unit) 

96 else: 

97 return ChebyshevField.from_legacy_background(legacy_background, unit=unit)