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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ repos:

# ruff walks up from each file to find api/ruff.toml automatically
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.13
rev: v0.15.8
hooks:
- id: ruff-check
files: ^api/
Expand Down
5 changes: 3 additions & 2 deletions api/src/damnit_api/graphql/directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
from ..runs.types import Cell, DamnitRun
from ..shared.const import DamnitType

# The summary dtypes worth a second round trip. ARRAY_2D is missing on purpose:
# DamnitRun.get_dtype cannot reach it, so only a preview ever carries one.
HEAVY_DATA = (
DamnitType.IMAGE,
DamnitType.RGBA,
DamnitType.ARRAY,
DamnitType.ARRAY_1D,
)


Expand Down
13 changes: 6 additions & 7 deletions api/src/damnit_api/runs/preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,15 @@ def get_preview_data(proposal, run, variable):

attrs = None
match dtype:
case DamnitType.ARRAY | DamnitType.IMAGE:
case DamnitType.ARRAY_1D | DamnitType.ARRAY_2D:
data = get_array(data)
case DamnitType.RGBA:
case DamnitType.IMAGE:
attrs = {
"shape": list(
data.shape[:2] # FIX: # pyright: ignore[reportAttributeAccessIssue]
)
}
data = get_png(data)
dtype = DamnitType.PNG

return standardize(data, name=variable, dtype=dtype.value, attrs=attrs)

Expand All @@ -81,7 +80,7 @@ def get_array(data):
def get_damnit_type(data, *, type_hint=None): # noqa: C901
match type_hint:
case DataType.Image:
return DamnitType.RGBA
return DamnitType.IMAGE
case DataType.Timestamp:
return DamnitType.TIMESTAMP
case None:
Expand All @@ -94,7 +93,7 @@ def get_damnit_type(data, *, type_hint=None): # noqa: C901
return DamnitType.NUMBER
raise ValueError(NOT_SUPPORTED_MESSAGE)
if data.ndim == 3 and data.shape[-1] in (3, 4):
return DamnitType.RGBA
return DamnitType.IMAGE
case DataType.Dataset | DataType.PlotlyFigure:
raise ValueError(NOT_SUPPORTED_MESSAGE)

Expand All @@ -103,9 +102,9 @@ def get_damnit_type(data, *, type_hint=None): # noqa: C901

match data.ndim:
case 1:
return DamnitType.ARRAY
return DamnitType.ARRAY_1D
case 2:
return DamnitType.IMAGE
return DamnitType.ARRAY_2D
case _:
raise ValueError(NOT_SUPPORTED_MESSAGE)

Expand Down
4 changes: 3 additions & 1 deletion api/src/damnit_api/runs/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ def serialize(value, *, dtype=DamnitType.STRING): # noqa: C901
value = to_complex_string(blob2complex(value))
dtype = DamnitType.STRING

case DamnitType.ARRAY:
case DamnitType.ARRAY_1D:
# The 1-D is what the client receives, not what is stored: a
# trendline summary is a 2xN blob of x and y rows.
if isinstance(value, bytes):
arr = blob2numpy(value)

Expand Down
7 changes: 2 additions & 5 deletions api/src/damnit_api/shared/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ class DamnitType(Enum):
TIMESTAMP = "timestamp"
COMPLEX = "complex"

ARRAY = "array"
ARRAY_1D = "array1d"
ARRAY_2D = "array2d"
IMAGE = "image"
NUMPY = "numpy"
RGBA = "rgba"

PNG = "png"
DATASET = "dataset"
2 changes: 1 addition & 1 deletion api/src/damnit_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
SUMMARY_TYPES = {
"complex": DamnitType.COMPLEX,
"numpy": DamnitType.NUMPY,
"trendline": DamnitType.ARRAY,
"trendline": DamnitType.ARRAY_1D,
}


Expand Down
8 changes: 4 additions & 4 deletions api/tests/graphql/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ def test_serialize_numpy():

def test_serialize_array_unsupported_shape():
blob = to_npy_bytes(np.array([1, 2, 3], dtype=np.float64))
_, dtype = serialize(blob, dtype=DamnitType.ARRAY)
_, dtype = serialize(blob, dtype=DamnitType.ARRAY_1D)
assert dtype == DamnitType.STRING


def test_serialize_array_valid():
def test_serialize_reduces_a_2xn_trendline_to_one_series():
arr = np.array([[1, 2, 3, 4], [10, 20, 30, 40]], dtype=np.float64)
value, dtype = serialize(to_npy_bytes(arr), dtype=DamnitType.ARRAY)
assert dtype == DamnitType.ARRAY
value, dtype = serialize(to_npy_bytes(arr), dtype=DamnitType.ARRAY_1D)
assert dtype == DamnitType.ARRAY_1D
assert isinstance(value, np.ndarray)


Expand Down
2 changes: 1 addition & 1 deletion api/tests/graphql/test_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async def test_lightweight_directive_blanks_heavy_values(
cells = {c["name"]: c["summary"] for c in result.data["runs"][0]["cells"]}
# The heavy value is held back, but its dtype still describes the cell.
assert cells["spectrum"]["value"] is None
assert cells["spectrum"]["dtype"] == "array"
assert cells["spectrum"]["dtype"] == "array1d"
# A scalar is left untouched.
assert cells["n_trains"]["value"] == 3641

Expand Down
6 changes: 2 additions & 4 deletions api/tests/refactor/snapshots/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ enum DamnitType {
boolean
timestamp
complex
array
array1d
array2d
image
numpy
rgba
png
dataset
}

input DatabaseInput {
Expand Down
31 changes: 15 additions & 16 deletions api/tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
@dataclass
class ExtractedData:
value: object
dtype: DamnitType
dtype: DamnitType | None = None
type_hint: DataType | None = None


Expand All @@ -35,17 +35,17 @@ class ExtractedData:
ExtractedData(
value=np.random.randint(0, 256, (2, 3, 4), dtype=np.uint8),
type_hint=DataType.Image,
dtype=DamnitType.RGBA,
dtype=DamnitType.IMAGE,
),
]
ndarrays = [
ExtractedData(
value=np.random.rand(10),
dtype=DamnitType.ARRAY,
dtype=DamnitType.ARRAY_1D,
),
ExtractedData(
value=np.random.rand(4, 3),
dtype=DamnitType.IMAGE,
dtype=DamnitType.ARRAY_2D,
),
]
dataarrays = [
Expand All @@ -66,7 +66,6 @@ class ExtractedData:
coords={"x": np.arange(10)},
),
type_hint=DataType.Dataset,
dtype=DamnitType.DATASET,
),
]

Expand Down Expand Up @@ -170,16 +169,16 @@ def test_to_dataarray_2d_dataarray_with_coords():
@pytest.mark.parametrize("data", scalars + datasets)
def test_to_data_array_unsupported(data):
with pytest.raises(ValueError, match=NOT_SUPPORTED_MESSAGE):
to_dataarray(data)
to_dataarray(data.value)


# -----------------------------------------------------------------------------
# standardize


def test_standardize_dataarray():
name = "some_image"
dtype = DamnitType.IMAGE
name = "some_array"
dtype = DamnitType.ARRAY_2D
data = xr.DataArray(
data=np.random.rand(4, 3),
name=name,
Expand All @@ -206,9 +205,9 @@ def test_standardize_dataarray():
# assert actual == expected


def test_standardize_png():
name = "some_png"
dtype = DamnitType.PNG
def test_standardize_image():
name = "some_image"
dtype = DamnitType.IMAGE
data = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAABQUlEQVR4nAE2Acn+ARvURClMomT2KO" # noqa: E501

assert standardize(data, name=name, dtype=dtype.value) == {
Expand Down Expand Up @@ -239,7 +238,7 @@ def mock_damnit_class(mocker, *, data, type_hint):

def test_get_preview_data_ndarray(mocker):
name = "some_array"
dtype = DamnitType.ARRAY
dtype = DamnitType.ARRAY_1D
data = np.random.rand(4)

mock_damnit_class(mocker, data=data, type_hint=None)
Expand All @@ -257,7 +256,7 @@ def test_get_preview_data_ndarray(mocker):

def test_get_preview_data_dataarray(mocker):
name = "some_array"
dtype = DamnitType.ARRAY
dtype = DamnitType.ARRAY_1D
data = xr.DataArray(
np.random.rand(4),
dims=["trains"],
Expand All @@ -276,9 +275,9 @@ def test_get_preview_data_dataarray(mocker):
assert_coords(actual["coords"], data.coords)


def test_get_preview_data_png(mocker):
name = "some_png"
dtype = DamnitType.PNG # because we convert RGBA array to PNG string
def test_get_preview_data_image(mocker):
name = "some_image"
dtype = DamnitType.IMAGE # a colour array is rendered to a PNG string
data = np.random.randint(0, 256, (2, 3, 4), dtype=np.uint8)

mock_damnit_class(mocker, data=data, type_hint=DataType.Image)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading