Skip to content

Commit

Permalink
Add utils for supporting rerun panel plugin (#4876)
Browse files Browse the repository at this point in the history
* add dynamic embedded document field type for rrd files

* add schema utils to work with embedded doc type fields

* add versioned renderer with url+metadata support

* remove explicit version
  • Loading branch information
sashankaryal authored Oct 4, 2024
1 parent 69a89e8 commit 97ccc02
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 8 deletions.
3 changes: 2 additions & 1 deletion app/packages/state/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
RecordSource,
Store,
} from "relay-runtime";
import { State } from "./recoil";
import { ModalSample, State } from "./recoil";

export const deferrer =
(initialized: MutableRefObject<boolean>) =>
Expand Down Expand Up @@ -105,6 +105,7 @@ export const getStandardizedUrls = (
urls:
| readonly { readonly field: string; readonly url: string }[]
| { [field: string]: string }
| ModalSample["urls"]
) => {
if (!Array.isArray(urls)) {
return urls;
Expand Down
79 changes: 72 additions & 7 deletions app/packages/utilities/src/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const SCHEMA: schema.Schema = {
"fiftyone.core.odm.embedded_document.DynamicEmbeddedDocument",
ftype: "fiftyone.core.fields.EmbeddedDocumentField",
info: {},
name: "top",
name: "embedded",
path: "embedded",
subfield: null,
fields: {
Expand All @@ -30,7 +30,7 @@ const SCHEMA: schema.Schema = {
ftype: "fiftyone.core.fields.EmbeddedDocumentField",
info: {},
name: "field",
path: "field",
path: "embedded.field",
subfield: null,
},
},
Expand All @@ -42,7 +42,7 @@ const SCHEMA: schema.Schema = {
"fiftyone.core.odm.embedded_document.DynamicEmbeddedDocument",
ftype: "fiftyone.core.fields.EmbeddedDocumentField",
info: {},
name: "top",
name: "embeddedWithDbFields",
path: "embeddedWithDbFields",
subfield: null,
fields: {
Expand All @@ -54,15 +54,15 @@ const SCHEMA: schema.Schema = {
ftype: "fiftyone.core.fields.EmbeddedDocumentField",
info: {},
name: "sample_id",
path: "sample_id",
path: "embeddedWithDbFields.sample_id",
subfield: null,
},
},
},
};

describe("schema", () => {
describe("getCls ", () => {
describe("getCls", () => {
it("should get top level cls", () => {
expect(schema.getCls("top", SCHEMA)).toBe("TopLabel");
});
Expand All @@ -79,7 +79,7 @@ describe("schema", () => {
});
});

describe("getFieldInfo ", () => {
describe("getFieldInfo", () => {
it("should get top level field info", () => {
expect(schema.getFieldInfo("top", SCHEMA)).toEqual({
...SCHEMA.top,
Expand All @@ -89,7 +89,7 @@ describe("schema", () => {

it("should get embedded field info", () => {
expect(schema.getFieldInfo("embedded.field", SCHEMA)).toEqual({
...SCHEMA.embedded.fields.field,
...SCHEMA.embedded.fields!.field,
pathWithDbField: "",
});
});
Expand All @@ -109,4 +109,69 @@ describe("schema", () => {
expect(field?.pathWithDbField).toBe("embeddedWithDbFields._sample_id");
});
});

describe("getFieldsWithEmbeddedDocType", () => {
it("should get all fields with embeddedDocType at top level", () => {
expect(
schema.getFieldsWithEmbeddedDocType(
SCHEMA,
"fiftyone.core.labels.TopLabel"
)
).toEqual([SCHEMA.top]);
});

it("should get all fields with embeddedDocType in nested fields", () => {
expect(
schema.getFieldsWithEmbeddedDocType(
SCHEMA,
"fiftyone.core.labels.EmbeddedLabel"
)
).toEqual([
SCHEMA.embedded.fields!.field,
SCHEMA.embeddedWithDbFields.fields!.sample_id,
]);
});

it("should return empty array if embeddedDocType does not exist", () => {
expect(
schema.getFieldsWithEmbeddedDocType(SCHEMA, "nonexistentDocType")
).toEqual([]);
});

it("should return empty array for empty schema", () => {
expect(schema.getFieldsWithEmbeddedDocType({}, "anyDocType")).toEqual([]);
});
});

describe("doesSchemaContainEmbeddedDocType", () => {
it("should return true if embeddedDocType exists at top level", () => {
expect(
schema.doesSchemaContainEmbeddedDocType(
SCHEMA,
"fiftyone.core.labels.TopLabel"
)
).toBe(true);
});

it("should return true if embeddedDocType exists in nested fields", () => {
expect(
schema.doesSchemaContainEmbeddedDocType(
SCHEMA,
"fiftyone.core.labels.EmbeddedLabel"
)
).toBe(true);
});

it("should return false if embeddedDocType does not exist", () => {
expect(
schema.doesSchemaContainEmbeddedDocType(SCHEMA, "nonexistentDocType")
).toBe(false);
});

it("should return false for empty schema", () => {
expect(schema.doesSchemaContainEmbeddedDocType({}, "anyDocType")).toBe(
false
);
});
});
});
40 changes: 40 additions & 0 deletions app/packages/utilities/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,43 @@ export function getCls(fieldPath: string, schema: Schema): string | undefined {

return field.embeddedDocType.split(".").slice(-1)[0];
}

export function getFieldsWithEmbeddedDocType(
schema: Schema,
embeddedDocType: string
): Field[] {
const result: Field[] = [];

function recurse(schema: Schema) {
for (const field of Object.values(schema ?? {})) {
if (field.embeddedDocType === embeddedDocType) {
result.push(field);
}
if (field.fields) {
recurse(field.fields);
}
}
}

recurse(schema);
return result;
}

export function doesSchemaContainEmbeddedDocType(
schema: Schema,
embeddedDocType: string
): boolean {
function recurse(schema: Schema): boolean {
return Object.values(schema ?? {}).some((field) => {
if (field.embeddedDocType === embeddedDocType) {
return true;
}
if (field.fields) {
return recurse(field.fields);
}
return false;
});
}

return recurse(schema);
}
2 changes: 2 additions & 0 deletions fiftyone/server/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import fiftyone.core.labels as fol
from fiftyone.core.collections import SampleCollection
from fiftyone.utils.utils3d import OrthographicProjectionMetadata
from fiftyone.utils.rerun import RrdFile

import fiftyone.core.media as fom

Expand All @@ -33,6 +34,7 @@
fol.Heatmap: "map_path",
fol.Segmentation: "mask_path",
OrthographicProjectionMetadata: "filepath",
RrdFile: "filepath",
}
_FFPROBE_BINARY_PATH = shutil.which("ffprobe")

Expand Down
25 changes: 25 additions & 0 deletions fiftyone/utils/rerun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Utilities for working with `Rerun <https://rerun.io/>`_.
| Copyright 2017-2024, Voxel51, Inc.
| `voxel51.com <https://voxel51.com/>`_
|
"""

import fiftyone.core.fields as fof
import fiftyone.core.labels as fol
from fiftyone.core.odm import DynamicEmbeddedDocument


class RrdFile(DynamicEmbeddedDocument, fol._HasMedia):
"""Class for storing a rerun data (rrd) file and its associated metadata.
Args:
filepath (None): the path to the rrd file
version (None): the version of the rrd file
"""

_MEDIA_FIELD = "filepath"

filepath = fof.StringField()
version = fof.StringField()

0 comments on commit 97ccc02

Please sign in to comment.