From 542591743fe3229ad857d8a073aa5a37473bdb85 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Tue, 15 Oct 2024 12:38:59 -0400 Subject: [PATCH] Add column property accessors for selectors and descriptors (#7752) ### What - Resolves: https://github.com/rerun-io/rerun/issues/7747 ### Checklist * [x] I have read and agree to [Contributor Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and the [Code of Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md) * [x] I've included a screenshot or gif (if applicable) * [x] I have tested the web demo (if applicable): * Using examples from latest `main` build: [rerun.io/viewer](https://rerun.io/viewer/pr/7752?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [rerun.io/viewer](https://rerun.io/viewer/pr/7752?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG * [x] If applicable, add a new check to the [release checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)! * [x] If have noted any breaking changes to the log API in `CHANGELOG.md` and the migration guide - [PR Build Summary](https://build.rerun.io/pr/7752) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) To run all checks from `main`, comment on the PR with `@rerun-bot full-check`. --- rerun_py/rerun_bindings/rerun_bindings.pyi | 50 ++++++++++++++++++++++ rerun_py/src/dataframe.rs | 30 +++++++++++++ rerun_py/tests/unit/test_dataframe.py | 17 ++++++++ scripts/ci/python_check_signatures.py | 5 +++ 4 files changed, 102 insertions(+) diff --git a/rerun_py/rerun_bindings/rerun_bindings.pyi b/rerun_py/rerun_bindings/rerun_bindings.pyi index 0dc62e0fc11f..0a607b29463c 100644 --- a/rerun_py/rerun_bindings/rerun_bindings.pyi +++ b/rerun_py/rerun_bindings/rerun_bindings.pyi @@ -8,18 +8,68 @@ from .types import AnyColumn, ComponentLike, IndexValuesLike, ViewContentsLike class IndexColumnDescriptor: """A column containing the index values for when the component data was updated.""" + def name(self) -> str: + """ + The name of the index. + + This property is read-only. + """ + ... + class IndexColumnSelector: """A selector for an index column.""" def __init__(self, index: str): ... + def name(self) -> str: + """ + The name of the index. + + This property is read-only. + """ + ... class ComponentColumnDescriptor: """A column containing the component data.""" + @property + def entity_path(self) -> str: + """ + The entity path. + + This property is read-only. + """ + ... + + @property + def component_name(self) -> str: + """ + The component name. + + This property is read-only. + """ + ... + class ComponentColumnSelector: """A selector for a component column.""" def __init__(self, entity_path: str, component: ComponentLike): ... + @property + def entity_path(self) -> str: + """ + The entity path. + + This property is read-only. + """ + ... + + @property + def component_name(self) -> str: + """ + The component name. + + This property is read-only. + """ + ... class Schema: """The schema representing all columns in a [`Recording`][].""" diff --git a/rerun_py/src/dataframe.rs b/rerun_py/src/dataframe.rs index efb818100a45..444a01cc79c4 100644 --- a/rerun_py/src/dataframe.rs +++ b/rerun_py/src/dataframe.rs @@ -52,6 +52,11 @@ impl PyIndexColumnDescriptor { fn __repr__(&self) -> String { format!("Index(timeline:{})", self.0.timeline.name()) } + + #[getter] + fn name(&self) -> &str { + self.0.timeline.name() + } } impl From for PyIndexColumnDescriptor { @@ -78,6 +83,11 @@ impl PyIndexColumnSelector { fn __repr__(&self) -> String { format!("Index(timeline:{})", self.0.timeline) } + + #[getter] + fn name(&self) -> &str { + &self.0.timeline + } } /// Python binding for [`ComponentColumnDescriptor`] @@ -105,6 +115,16 @@ impl PyComponentColumnDescriptor { fn __eq__(&self, other: &Self) -> bool { self.0 == other.0 } + + #[getter] + fn entity_path(&self) -> String { + self.0.entity_path.to_string() + } + + #[getter] + fn component_name(&self) -> &str { + &self.0.component_name + } } impl From for ComponentColumnDescriptor { @@ -135,6 +155,16 @@ impl PyComponentColumnSelector { self.0.entity_path, self.0.component_name ) } + + #[getter] + fn entity_path(&self) -> String { + self.0.entity_path.to_string() + } + + #[getter] + fn component_name(&self) -> &str { + &self.0.component_name + } } /// Python binding for [`AnyColumn`] type-alias. diff --git a/rerun_py/tests/unit/test_dataframe.py b/rerun_py/tests/unit/test_dataframe.py index 072542d239c9..0f09cdc029d4 100644 --- a/rerun_py/tests/unit/test_dataframe.py +++ b/rerun_py/tests/unit/test_dataframe.py @@ -95,6 +95,23 @@ def test_recording_info(self) -> None: assert self.recording.application_id() == APP_ID assert self.recording.recording_id() == str(RECORDING_ID) + def test_schema(self) -> None: + schema = self.recording.schema() + + assert len(schema.index_columns()) == 3 + # Points3DIndicator, Position3D, Color + assert len(schema.component_columns()) == 3 + + assert schema.index_columns()[0].name == "log_tick" + assert schema.index_columns()[1].name == "log_time" + assert schema.index_columns()[2].name == "my_index" + assert schema.component_columns()[0].entity_path == "/points" + assert schema.component_columns()[0].component_name == "rerun.components.Color" + assert schema.component_columns()[1].entity_path == "/points" + assert schema.component_columns()[1].component_name == "rerun.components.Points3DIndicator" + assert schema.component_columns()[2].entity_path == "/points" + assert schema.component_columns()[2].component_name == "rerun.components.Position3D" + def test_full_view(self) -> None: view = self.recording.view(index="my_index", contents="points") diff --git a/scripts/ci/python_check_signatures.py b/scripts/ci/python_check_signatures.py index 41f303c39e77..4257173f39d3 100644 --- a/scripts/ci/python_check_signatures.py +++ b/scripts/ci/python_check_signatures.py @@ -112,6 +112,11 @@ def load_runtime_signatures(module_name: str) -> TotalSignature: class_def[method_name] = inspect.signature(method_obj) except Exception: pass + # Get property getters + for method_name, method_obj in inspect.getmembers( + obj, lambda o: o.__class__.__name__ == "getset_descriptor" + ): + class_def[method_name] = Signature(parameters=[Parameter("self", Parameter.POSITIONAL_ONLY)]) signatures[name] = class_def return signatures