From e75c28176a86769ebe12d1b01d640ad13d2c19c5 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Thu, 28 Sep 2023 19:12:00 +0200 Subject: [PATCH 01/27] New decorator: 'catch_and_log_exceptions' and refactor strict_mode checking --- rerun_py/rerun_sdk/rerun/__init__.py | 39 +------ rerun_py/rerun_sdk/rerun/error_utils.py | 103 ++++++++++++++++-- .../rerun/log_deprecated/log_decorator.py | 5 +- 3 files changed, 100 insertions(+), 47 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/__init__.py b/rerun_py/rerun_sdk/rerun/__init__.py index f1cbcc695d09..34162f40864c 100644 --- a/rerun_py/rerun_sdk/rerun/__init__.py +++ b/rerun_py/rerun_sdk/rerun/__init__.py @@ -142,6 +142,7 @@ ) from .components import MediaType from .datatypes import Quaternion, RotationAxisAngle, Scale3D, TranslationAndMat3x3, TranslationRotationScale3D +from .error_utils import set_strict_mode from .log_deprecated.annotation import AnnotationInfo, ClassDescription, log_annotation_context from .log_deprecated.arrow import log_arrow from .log_deprecated.bounding_box import log_obb, log_obbs @@ -195,7 +196,6 @@ "unregister_shutdown", "cleanup_if_forked_child", "shutdown_at_exit", - "strict_mode", "set_strict_mode", "start_web_viewer_server", ] @@ -220,11 +220,6 @@ def _init_recording_stream() -> None: _init_recording_stream() -# If `True`, we raise exceptions on use error (wrong parameter types, etc.). -# If `False` we catch all errors and log a warning instead. -_strict_mode = False - - def init( application_id: str, *, @@ -294,8 +289,7 @@ def init( random.seed(0) np.random.seed(0) - global _strict_mode - _strict_mode = strict + set_strict_mode(strict) # Always check whether we are a forked child when calling init. This should have happened # via `_register_on_fork` but it's worth being conservative. @@ -502,35 +496,6 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: # --- -def strict_mode() -> bool: - """ - Strict mode enabled. - - In strict mode, incorrect use of the Rerun API (wrong parameter types etc.) - will result in exception being raised. - When strict mode is on, such problems are instead logged as warnings. - - The default is OFF. - """ - - return _strict_mode - - -def set_strict_mode(mode: bool) -> None: - """ - Turn strict mode on/off. - - In strict mode, incorrect use of the Rerun API (wrong parameter types etc.) - will result in exception being raised. - When strict mode is off, such problems are instead logged as warnings. - - The default is OFF. - """ - global _strict_mode - - _strict_mode = mode - - def start_web_viewer_server(port: int = 0) -> None: """ Start an HTTP server that hosts the rerun web viewer. diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index d350f498accc..28c8d3130b8b 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -1,15 +1,65 @@ from __future__ import annotations +import functools import inspect -import logging +import threading +import warnings +from typing import Any, Callable, TypeVar, cast -import rerun -from rerun.recording_stream import RecordingStream +from .recording_stream import RecordingStream __all__ = [ "_send_warning", ] +_TFunc = TypeVar("_TFunc", bound=Callable[..., Any]) + +# If `True`, we raise exceptions on use error (wrong parameter types, etc.). +# If `False` we catch all errors and log a warning instead. +_strict_mode = False + +_rerun_exception_ctx = threading.local() +_rerun_exception_ctx.strict_mode = None +_rerun_exception_ctx.depth = 0 + + +def check_strict_mode() -> bool: + """ + Strict mode enabled. + + In strict mode, incorrect use of the Rerun API (wrong parameter types etc.) + will result in exception being raised. + When strict mode is on, such problems are instead logged as warnings. + + The default is OFF. + """ + # If strict was set explicitly, we are in struct mode + if _rerun_exception_ctx.strict_mode is not None: + return _rerun_exception_ctx.strict_mode # type: ignore[no-any-return] + else: + return _strict_mode + + +def set_strict_mode(mode: bool) -> None: + """ + Turn strict mode on/off. + + In strict mode, incorrect use of the Rerun API (wrong parameter types etc.) + will result in exception being raised. + When strict mode is off, such problems are instead logged as warnings. + + The default is OFF. + """ + global _strict_mode + + _strict_mode = mode + + +class RerunWarning(Warning): + """A custom warning class that we use to identify warnings that are emitted by the Rerun SDK itself.""" + + pass + def _build_warning_context_string(skip_first: int) -> str: """Builds a string describing the user context of a warning.""" @@ -32,11 +82,48 @@ def _send_warning( from rerun._log import log from rerun.archetypes import TextLog - if rerun.strict_mode(): + if check_strict_mode(): raise TypeError(message) - context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 2) - warning = f"{message}\n{context_descriptor}" + context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 1) + + # TODO(jleibs): Context/stack should be its component. + log("rerun", TextLog(body=f"{message}\n{context_descriptor}", level="WARN"), recording=recording) + warnings.warn(message, category=RerunWarning, stacklevel=depth_to_user_code + 1) + + +def catch_and_log_exceptions(func: _TFunc) -> _TFunc: + """ + A decorator we add to any function we want to catch exceptions if we're not in strict mode. + + This function checks for a strict kwarg and uses it to override the global strict mode + if provided. Additionally it tracks the depth of the call stack to the user code -- the + highest point in the stack where the user called a decorated function. + + This is important in order not to crash the users application + just because they misused the Rerun API (or because we have a bug!). + """ + + @functools.wraps(func) + def wrapper(*args: Any, **kwargs: Any) -> Any: + try: + original_strict = _rerun_exception_ctx.strict_mode + _rerun_exception_ctx.depth += 2 + if "strict" in kwargs: + _rerun_exception_ctx.strict_mode = kwargs["strict"] + + if check_strict_mode(): + # Pass on any exceptions to the caller + return func(*args, **kwargs) + else: + try: + return func(*args, **kwargs) + except Exception as e: + warning = f"{type(e).__name__}: {e}" + + _send_warning(warning, depth_to_user_code=_rerun_exception_ctx.depth) + finally: + _rerun_exception_ctx.strict_mode = original_strict + _rerun_exception_ctx.depth -= 2 - log("rerun", TextLog(warning, level="WARN"), recording=recording) - logging.warning(warning) + return cast(_TFunc, wrapper) diff --git a/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py b/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py index 14f0c83132f8..de0dc79f9813 100644 --- a/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py +++ b/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py @@ -5,12 +5,13 @@ import warnings from typing import Any, Callable, TypeVar, cast -import rerun from rerun import bindings from rerun._log import log from rerun.archetypes import TextLog from rerun.recording_stream import RecordingStream +from ..error_utils import check_strict_mode + _TFunc = TypeVar("_TFunc", bound=Callable[..., Any]) @@ -44,7 +45,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: ) return - if rerun.strict_mode(): + if check_strict_mode(): # Pass on any exceptions to the caller return func(*args, **kwargs) else: From c844cba9be8dc0af3eabcb694314567ba68b1f93 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Thu, 28 Sep 2023 19:12:23 +0200 Subject: [PATCH 02/27] Test the new decorator --- crates/re_sdk/src/log_sink.rs | 6 ++++ rerun_py/rerun_sdk/rerun/recording.py | 8 ++++++ rerun_py/src/python_bridge.rs | 16 ++++++++++- rerun_py/tests/unit/test_exceptions.py | 40 ++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 rerun_py/tests/unit/test_exceptions.py diff --git a/crates/re_sdk/src/log_sink.rs b/crates/re_sdk/src/log_sink.rs index e7314af4a82c..e6985ce65816 100644 --- a/crates/re_sdk/src/log_sink.rs +++ b/crates/re_sdk/src/log_sink.rs @@ -147,6 +147,12 @@ impl MemorySinkStorage { self.msgs.read() } + /// How many messages are currently written to this memory sink + #[inline] + pub fn num_msgs(&self) -> usize { + self.read().len() + } + /// Consumes and returns the inner array of [`LogMsg`]. /// /// This automatically takes care of flushing the underlying [`crate::RecordingStream`]. diff --git a/rerun_py/rerun_sdk/rerun/recording.py b/rerun_py/rerun_sdk/rerun/recording.py index acfa19addad6..a974e3962000 100644 --- a/rerun_py/rerun_sdk/rerun/recording.py +++ b/rerun_py/rerun_sdk/rerun/recording.py @@ -26,6 +26,14 @@ def reset_blueprint(self, *, add_to_app_default_blueprint: bool = False) -> None """Reset the blueprint in the MemoryRecording.""" self.storage.reset_blueprint(add_to_app_default_blueprint) + def num_msgs(self) -> int: + """ + The number of pending messages in the MemoryRecording. + + Note: counting the messages will flush the batcher in order to get a deterministic count. + """ + return self.storage.num_msgs() + def as_html( self, *, diff --git a/rerun_py/src/python_bridge.rs b/rerun_py/src/python_bridge.rs index a49a28be03b2..5b6d29882baa 100644 --- a/rerun_py/src/python_bridge.rs +++ b/rerun_py/src/python_bridge.rs @@ -531,7 +531,9 @@ struct PyMemorySinkStorage { #[pymethods] impl PyMemorySinkStorage { - /// This will do a blocking flush before returning! + /// Concatenate the contents of the [`MemorySinkStorage`] as byes. + /// + /// Note: This will do a blocking flush before returning! fn concat_as_bytes<'p>( &self, concat: Option<&PyMemorySinkStorage>, @@ -552,6 +554,18 @@ impl PyMemorySinkStorage { .map(|bytes| PyBytes::new(py, bytes.as_slice())) .map_err(|err| PyRuntimeError::new_err(err.to_string())) } + + /// Count the number of pending messages in the [`MemorySinkStorage`]. + /// + /// This will do a blocking flush before returning! + fn num_msgs(&self, py: Python<'_>) -> usize { + // Release the GIL in case any flushing behavior needs to cleanup a python object. + py.allow_threads(|| { + self.rec.flush_blocking(); + }); + + self.inner.num_msgs() + } } #[cfg(feature = "web_viewer")] diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py new file mode 100644 index 000000000000..5f1eb78d3e9b --- /dev/null +++ b/rerun_py/tests/unit/test_exceptions.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +import inspect + +import pytest +import rerun as rr +from rerun.error_utils import RerunWarning, catch_and_log_exceptions + + +@catch_and_log_exceptions +def outer() -> None: + inner(3) + + +@catch_and_log_exceptions +def inner(count: int) -> None: + if count < 0: + raise ValueError("count must be positive") + inner(count - 1) + + +def get_line_number() -> int: + frame = inspect.currentframe().f_back # type: ignore[union-attr] + return frame.f_lineno # type: ignore[union-attr] + + +def test_enable_strict_mode() -> None: + rr.init("test_enable_strict_mode", spawn=False) + mem = rr.memory_recording() + with pytest.warns(RerunWarning) as record: + starting_msgs = mem.num_msgs() + outer() + assert record[0].lineno == get_line_number() - 1 + assert record[0].filename == __file__ + assert "count must be positive" in str(record[0].message) + assert mem.num_msgs() == starting_msgs + 1 + + rr.set_strict_mode(True) + with pytest.raises(ValueError): + outer() From 508e41ae9fe6dd37ff8f840e2727b0e352af8b3a Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Thu, 28 Sep 2023 22:13:09 +0200 Subject: [PATCH 03/27] Convert to a hybrid context-object + decorator --- rerun_py/rerun_sdk/rerun/error_utils.py | 76 ++++++++++++++++++------- rerun_py/rerun_sdk/rerun/recording.py | 2 +- rerun_py/tests/unit/test_exceptions.py | 55 ++++++++++++++++-- 3 files changed, 106 insertions(+), 27 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index 28c8d3130b8b..29acf530830d 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -4,6 +4,7 @@ import inspect import threading import warnings +from types import TracebackType from typing import Any, Callable, TypeVar, cast from .recording_stream import RecordingStream @@ -92,11 +93,11 @@ def _send_warning( warnings.warn(message, category=RerunWarning, stacklevel=depth_to_user_code + 1) -def catch_and_log_exceptions(func: _TFunc) -> _TFunc: +class catch_and_log_exceptions: """ A decorator we add to any function we want to catch exceptions if we're not in strict mode. - This function checks for a strict kwarg and uses it to override the global strict mode + This decorator checks for a strict kwarg and uses it to override the global strict mode if provided. Additionally it tracks the depth of the call stack to the user code -- the highest point in the stack where the user called a decorated function. @@ -104,26 +105,57 @@ def catch_and_log_exceptions(func: _TFunc) -> _TFunc: just because they misused the Rerun API (or because we have a bug!). """ - @functools.wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> Any: + def __init__(self, bare_context: bool = True) -> None: + self.bare_context = bare_context + + def __enter__(self) -> catch_and_log_exceptions: + # Track the original strict_mode setting in case it's being + # overridden locally in this stack + self.original_strict = _rerun_exception_ctx.strict_mode + self.added_depth = 0 + + # Functions add a depth of 2 + # Bare context helpers don't add a depth + if not self.bare_context: + self.added_depth = 2 + _rerun_exception_ctx.depth += self.added_depth + + return self + + @classmethod + def __call__(cls, func: _TFunc) -> _TFunc: + @functools.wraps(func) + def wrapper(*args: Any, **kwargs: Any) -> Any: + with cls(bare_context=False): + if "strict" in kwargs: + _rerun_exception_ctx.strict_mode = kwargs["strict"] + + func(*args, **kwargs) + + return cast(_TFunc, wrapper) + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: try: - original_strict = _rerun_exception_ctx.strict_mode - _rerun_exception_ctx.depth += 2 - if "strict" in kwargs: - _rerun_exception_ctx.strict_mode = kwargs["strict"] - - if check_strict_mode(): - # Pass on any exceptions to the caller - return func(*args, **kwargs) + if exc_type is not None and not check_strict_mode(): + warning = f"{exc_type.__name__}: {exc_val}" + + # If the raise comes directly from a bare context, we need + # to add 1 extra layer of depth. + if self.bare_context: + extra_depth = 2 + else: + extra_depth = 1 + _send_warning(warning, depth_to_user_code=_rerun_exception_ctx.depth + extra_depth) + return True else: - try: - return func(*args, **kwargs) - except Exception as e: - warning = f"{type(e).__name__}: {e}" - - _send_warning(warning, depth_to_user_code=_rerun_exception_ctx.depth) + return False finally: - _rerun_exception_ctx.strict_mode = original_strict - _rerun_exception_ctx.depth -= 2 - - return cast(_TFunc, wrapper) + # Return the local context to the prior value + _rerun_exception_ctx.strict_mode = self.original_strict + _rerun_exception_ctx.depth -= self.added_depth + return False diff --git a/rerun_py/rerun_sdk/rerun/recording.py b/rerun_py/rerun_sdk/rerun/recording.py index a974e3962000..9c1efd8d97d1 100644 --- a/rerun_py/rerun_sdk/rerun/recording.py +++ b/rerun_py/rerun_sdk/rerun/recording.py @@ -32,7 +32,7 @@ def num_msgs(self) -> int: Note: counting the messages will flush the batcher in order to get a deterministic count. """ - return self.storage.num_msgs() + return self.storage.num_msgs() # type: ignore[no-any-return] def as_html( self, diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py index 5f1eb78d3e9b..1751cbd21eda 100644 --- a/rerun_py/tests/unit/test_exceptions.py +++ b/rerun_py/tests/unit/test_exceptions.py @@ -7,25 +7,35 @@ from rerun.error_utils import RerunWarning, catch_and_log_exceptions -@catch_and_log_exceptions -def outer() -> None: +@catch_and_log_exceptions() +def outer(strict: bool | None = None) -> None: + """Calls an inner decorated function.""" inner(3) -@catch_and_log_exceptions +@catch_and_log_exceptions() def inner(count: int) -> None: + """Calls itself recursively but ultimately raises an error.""" if count < 0: raise ValueError("count must be positive") inner(count - 1) +@catch_and_log_exceptions() +def uses_context(strict: bool | None = None) -> None: + with catch_and_log_exceptions(): + raise ValueError + + def get_line_number() -> int: + """Helper to get a line-number. Make sure our warnings point to the right place.""" frame = inspect.currentframe().f_back # type: ignore[union-attr] return frame.f_lineno # type: ignore[union-attr] -def test_enable_strict_mode() -> None: +def test_stack_tracking() -> None: rr.init("test_enable_strict_mode", spawn=False) + mem = rr.memory_recording() with pytest.warns(RerunWarning) as record: starting_msgs = mem.num_msgs() @@ -35,6 +45,43 @@ def test_enable_strict_mode() -> None: assert "count must be positive" in str(record[0].message) assert mem.num_msgs() == starting_msgs + 1 + mem = rr.memory_recording() + with pytest.warns(RerunWarning) as record: + starting_msgs = mem.num_msgs() + uses_context() + assert record[0].lineno == get_line_number() - 1 + assert record[0].filename == __file__ + assert mem.num_msgs() == starting_msgs + 1 + + mem = rr.memory_recording() + with pytest.warns(RerunWarning) as record: + starting_msgs = mem.num_msgs() + with catch_and_log_exceptions(): + inner(count=2) + assert record[0].lineno == get_line_number() - 1 + assert record[0].filename == __file__ + assert "count must be positive" in str(record[0].message) + assert mem.num_msgs() == starting_msgs + 1 + + mem = rr.memory_recording() + with pytest.warns(RerunWarning) as record: + starting_msgs = mem.num_msgs() + with catch_and_log_exceptions(): + raise ValueError + assert record[0].lineno == get_line_number() - 2 + assert record[0].filename == __file__ + assert mem.num_msgs() == starting_msgs + 1 + + +def test_strict_mode() -> None: + # We can disable strict on just this function + with pytest.raises(ValueError): + outer(strict=True) + + with pytest.raises(ValueError): + uses_context(strict=True) + + # We can disable strict mode globally rr.set_strict_mode(True) with pytest.raises(ValueError): outer() From 621963648bdb1f9510afa9428bf2213f8dcfa35a Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Thu, 28 Sep 2023 22:14:08 +0200 Subject: [PATCH 04/27] Decorate the new log function --- rerun_py/rerun_sdk/rerun/_log.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/_log.py b/rerun_py/rerun_sdk/rerun/_log.py index 22fed55ae672..4522b892ad82 100644 --- a/rerun_py/rerun_sdk/rerun/_log.py +++ b/rerun_py/rerun_sdk/rerun/_log.py @@ -9,7 +9,7 @@ from . import components as cmp from ._baseclasses import AsComponents, ComponentBatchLike -from .error_utils import _send_warning +from .error_utils import _send_warning, catch_and_log_exceptions from .recording_stream import RecordingStream __all__ = ["log", "IndicatorComponentBatch", "AsComponents"] @@ -102,6 +102,7 @@ def _splat() -> cmp.InstanceKeyBatch: return pa.array([_MAX_U64], type=cmp.InstanceKeyType().storage_type) # type: ignore[no-any-return] +@catch_and_log_exceptions() def log( entity_path: str, entity: AsComponents | Iterable[ComponentBatchLike], @@ -109,6 +110,7 @@ def log( ext: dict[str, Any] | None = None, timeless: bool = False, recording: RecordingStream | None = None, + strict: bool | None = None, ) -> None: """ Log an entity. @@ -127,7 +129,10 @@ def log( Specifies the [`rerun.RecordingStream`][] to use. If left unspecified, defaults to the current active data recording, if there is one. See also: [`rerun.init`][], [`rerun.set_global_data_recording`][]. - + strict: + If True, raise exceptions on non-loggable data. + If False, warn on non-loggable data. + if None, use the global default from `rerun.strict_mode()` """ # TODO(jleibs): Profile is_instance with runtime_checkable vs has_attr # Note from: https://docs.python.org/3/library/typing.html#typing.runtime_checkable @@ -156,6 +161,7 @@ def log( ) +@catch_and_log_exceptions() def log_components( entity_path: str, components: Iterable[ComponentBatchLike], @@ -164,6 +170,7 @@ def log_components( ext: dict[str, Any] | None = None, timeless: bool = False, recording: RecordingStream | None = None, + strict: bool | None = None, ) -> None: """ Log an entity from a collection of `ComponentBatchLike` objects. @@ -190,7 +197,10 @@ def log_components( Specifies the [`rerun.RecordingStream`][] to use. If left unspecified, defaults to the current active data recording, if there is one. See also: [`rerun.init`][], [`rerun.set_global_data_recording`][]. - + strict: + If True, raise exceptions on non-loggable data. + If False, warn on non-loggable data. + if None, use the global default from `rerun.strict_mode()` """ instanced: dict[str, pa.Array] = {} splats: dict[str, pa.Array] = {} From 2c022e7cb9bd117c85c9bc76c782169500d592d0 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Thu, 28 Sep 2023 22:46:11 +0200 Subject: [PATCH 05/27] Clean up tests --- rerun_py/rerun_sdk/rerun/error_utils.py | 2 +- rerun_py/tests/unit/test_exceptions.py | 75 ++++++++++++++++--------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index 29acf530830d..ce9b117fc68b 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -130,7 +130,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if "strict" in kwargs: _rerun_exception_ctx.strict_mode = kwargs["strict"] - func(*args, **kwargs) + return func(*args, **kwargs) return cast(_TFunc, wrapper) diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py index 1751cbd21eda..44de0799770b 100644 --- a/rerun_py/tests/unit/test_exceptions.py +++ b/rerun_py/tests/unit/test_exceptions.py @@ -1,6 +1,8 @@ from __future__ import annotations import inspect +import os +from typing import Any import pytest import rerun as rr @@ -8,23 +10,33 @@ @catch_and_log_exceptions() -def outer(strict: bool | None = None) -> None: +def outer(strict: bool | None = None) -> int: """Calls an inner decorated function.""" inner(3) + return 42 + + +@catch_and_log_exceptions() +def two_calls(strict: bool | None = None) -> None: + """Calls an inner decorated function twice.""" + inner(3) + inner(3) + @catch_and_log_exceptions() def inner(count: int) -> None: """Calls itself recursively but ultimately raises an error.""" if count < 0: - raise ValueError("count must be positive") + raise ValueError("some value error") inner(count - 1) @catch_and_log_exceptions() def uses_context(strict: bool | None = None) -> None: + """Uses a context manager instead of a function.""" with catch_and_log_exceptions(): - raise ValueError + raise ValueError("some value error") def get_line_number() -> int: @@ -33,44 +45,55 @@ def get_line_number() -> int: return frame.f_lineno # type: ignore[union-attr] +def expected_warnings(warnings: Any, mem: Any, starting_msgs: int, count: int, expected_line: int) -> None: + for w in warnings: + assert w.lineno == expected_line + assert w.filename == __file__ + assert "some value error" in str(w.message) + + def test_stack_tracking() -> None: + # Force flushing so we can count the messages + os.environ["RERUN_FLUSH_NUM_ROWS"] = "0" rr.init("test_enable_strict_mode", spawn=False) mem = rr.memory_recording() - with pytest.warns(RerunWarning) as record: + with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() - outer() - assert record[0].lineno == get_line_number() - 1 - assert record[0].filename == __file__ - assert "count must be positive" in str(record[0].message) - assert mem.num_msgs() == starting_msgs + 1 - mem = rr.memory_recording() - with pytest.warns(RerunWarning) as record: + assert outer() == 42 + + expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 2) + + with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() + + two_calls() + + expected_warnings(warnings, mem, starting_msgs, 2, get_line_number() - 2) + + with pytest.warns(RerunWarning) as warnings: + starting_msgs = mem.num_msgs() + uses_context() - assert record[0].lineno == get_line_number() - 1 - assert record[0].filename == __file__ - assert mem.num_msgs() == starting_msgs + 1 - mem = rr.memory_recording() - with pytest.warns(RerunWarning) as record: + expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 2) + + with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() + with catch_and_log_exceptions(): inner(count=2) - assert record[0].lineno == get_line_number() - 1 - assert record[0].filename == __file__ - assert "count must be positive" in str(record[0].message) - assert mem.num_msgs() == starting_msgs + 1 - mem = rr.memory_recording() - with pytest.warns(RerunWarning) as record: + expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 2) + + with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() + with catch_and_log_exceptions(): - raise ValueError - assert record[0].lineno == get_line_number() - 2 - assert record[0].filename == __file__ - assert mem.num_msgs() == starting_msgs + 1 + raise ValueError("some value error") + + expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) def test_strict_mode() -> None: From 683d713ad53b04b516aec9843e98294228ea0c4a Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 00:20:00 +0200 Subject: [PATCH 06/27] Actually do the right thing to track user depth --- rerun_py/rerun_sdk/rerun/error_utils.py | 73 +++++++++++++------------ rerun_py/tests/unit/test_exceptions.py | 27 +++++++-- 2 files changed, 60 insertions(+), 40 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index ce9b117fc68b..cc43f4f2c90c 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -20,8 +20,6 @@ _strict_mode = False _rerun_exception_ctx = threading.local() -_rerun_exception_ctx.strict_mode = None -_rerun_exception_ctx.depth = 0 def check_strict_mode() -> bool: @@ -35,7 +33,7 @@ def check_strict_mode() -> bool: The default is OFF. """ # If strict was set explicitly, we are in struct mode - if _rerun_exception_ctx.strict_mode is not None: + if getattr(_rerun_exception_ctx, "strict_mode", None) is not None: return _rerun_exception_ctx.strict_mode # type: ignore[no-any-return] else: return _strict_mode @@ -88,48 +86,49 @@ def _send_warning( context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 1) - # TODO(jleibs): Context/stack should be its component. + # TODO(jleibs): Context/stack should be its own component. log("rerun", TextLog(body=f"{message}\n{context_descriptor}", level="WARN"), recording=recording) warnings.warn(message, category=RerunWarning, stacklevel=depth_to_user_code + 1) class catch_and_log_exceptions: """ - A decorator we add to any function we want to catch exceptions if we're not in strict mode. + A hybrid decorator / context-manager. - This decorator checks for a strict kwarg and uses it to override the global strict mode - if provided. Additionally it tracks the depth of the call stack to the user code -- the - highest point in the stack where the user called a decorated function. + We can add this to any function or scope where we want to catch and log + exceptions. - This is important in order not to crash the users application - just because they misused the Rerun API (or because we have a bug!). + Warnings are attached to a thread-local context, and are sent out when + we leave the outer-most context object. This gives us a warning that + points to the user call-site rather than somewhere buried in Rerun code. + + For functions, this decorator checks for a strict kwarg and uses it to + override the global strict mode if provided. """ - def __init__(self, bare_context: bool = True) -> None: - self.bare_context = bare_context + def __init__(self, context: str = "", depth_to_user_code: int = 0) -> None: + self.depth_to_user_code = depth_to_user_code + self.context = context def __enter__(self) -> catch_and_log_exceptions: # Track the original strict_mode setting in case it's being # overridden locally in this stack - self.original_strict = _rerun_exception_ctx.strict_mode - self.added_depth = 0 - - # Functions add a depth of 2 - # Bare context helpers don't add a depth - if not self.bare_context: - self.added_depth = 2 - _rerun_exception_ctx.depth += self.added_depth + self.original_strict = getattr(_rerun_exception_ctx, "strict_mode", None) + if getattr(_rerun_exception_ctx, "depth", None) is None: + _rerun_exception_ctx.depth = 1 + else: + _rerun_exception_ctx.depth += 1 return self - @classmethod - def __call__(cls, func: _TFunc) -> _TFunc: + def __call__(self, func: _TFunc) -> _TFunc: + self.depth_to_user_code += 1 + @functools.wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: - with cls(bare_context=False): + with self: if "strict" in kwargs: _rerun_exception_ctx.strict_mode = kwargs["strict"] - return func(*args, **kwargs) return cast(_TFunc, wrapper) @@ -142,20 +141,24 @@ def __exit__( ) -> bool: try: if exc_type is not None and not check_strict_mode(): - warning = f"{exc_type.__name__}: {exc_val}" - - # If the raise comes directly from a bare context, we need - # to add 1 extra layer of depth. - if self.bare_context: - extra_depth = 2 - else: - extra_depth = 1 - _send_warning(warning, depth_to_user_code=_rerun_exception_ctx.depth + extra_depth) + if getattr(_rerun_exception_ctx, "pending_warnings", None) is None: + _rerun_exception_ctx.pending_warnings = [] + _rerun_exception_ctx.pending_warnings.append(f"{self.context or exc_type.__name__}: {exc_val}") return True else: return False finally: + if getattr(_rerun_exception_ctx, "depth", None) is not None: + _rerun_exception_ctx.depth -= 1 + if _rerun_exception_ctx.depth == 0: + pending_warnings = getattr(_rerun_exception_ctx, "pending_warnings", []) + _rerun_exception_ctx.pending_warnings = [] + _rerun_exception_ctx.depth = None + + for warning in pending_warnings: + _send_warning(warning, depth_to_user_code=self.depth_to_user_code + 2) + + # If we're back to the top of the stack, send out the pending warnings + # Return the local context to the prior value _rerun_exception_ctx.strict_mode = self.original_strict - _rerun_exception_ctx.depth -= self.added_depth - return False diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py index 44de0799770b..7c3995168bc6 100644 --- a/rerun_py/tests/unit/test_exceptions.py +++ b/rerun_py/tests/unit/test_exceptions.py @@ -24,7 +24,7 @@ def two_calls(strict: bool | None = None) -> None: inner(3) -@catch_and_log_exceptions() +@catch_and_log_exceptions(context="function context") def inner(count: int) -> None: """Calls itself recursively but ultimately raises an error.""" if count < 0: @@ -35,7 +35,7 @@ def inner(count: int) -> None: @catch_and_log_exceptions() def uses_context(strict: bool | None = None) -> None: """Uses a context manager instead of a function.""" - with catch_and_log_exceptions(): + with catch_and_log_exceptions("inner context"): raise ValueError("some value error") @@ -64,6 +64,7 @@ def test_stack_tracking() -> None: assert outer() == 42 expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 2) + assert "function context" in str(warnings[0].message) with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() @@ -83,17 +84,19 @@ def test_stack_tracking() -> None: starting_msgs = mem.num_msgs() with catch_and_log_exceptions(): - inner(count=2) + uses_context() - expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 2) + expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) + assert "inner context" in str(warnings[0].message) with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() - with catch_and_log_exceptions(): + with catch_and_log_exceptions("some context"): raise ValueError("some value error") expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) + assert "some context" in str(warnings[0].message) def test_strict_mode() -> None: @@ -108,3 +111,17 @@ def test_strict_mode() -> None: rr.set_strict_mode(True) with pytest.raises(ValueError): outer() + # Clear the global strict mode again + rr.set_strict_mode(False) + + +def test_bad_components() -> None: + with pytest.warns(RerunWarning) as warnings: + points = rr.Points3D(positions=[1, 2, 3], colors="RED") + assert len(warnings) == 1 + assert len(points.positions) == 1 + assert len(points.colors) == 0 + + rr.set_strict_mode(True) + with pytest.raises(ValueError): + points = rr.Points3D(positions=[1, 2, 3], colors="RED") From ae31d46760a33418bd910bfceabc871936d98b26 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 01:07:46 +0200 Subject: [PATCH 07/27] Better context handling and avoid recursion issues --- rerun_py/rerun_sdk/rerun/error_utils.py | 31 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index cc43f4f2c90c..d1bc4d28271d 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -84,12 +84,23 @@ def _send_warning( if check_strict_mode(): raise TypeError(message) - context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 1) - - # TODO(jleibs): Context/stack should be its own component. - log("rerun", TextLog(body=f"{message}\n{context_descriptor}", level="WARN"), recording=recording) + # Send the warning to the user first warnings.warn(message, category=RerunWarning, stacklevel=depth_to_user_code + 1) + # Logging the warning to Rerun is a complex operation could produce another warning. Avoid recursion. + if not getattr(_rerun_exception_ctx, "sending_warning", False): + _rerun_exception_ctx.sending_warning = True + + # TODO(jleibs): Context/stack should be its own component. + context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 1) + + log("rerun", TextLog(body=f"{message}\n{context_descriptor}", level="WARN"), recording=recording) + _rerun_exception_ctx.sending_warning = False + else: + warnings.warn( + "Encountered Error while sending warning", category=RerunWarning, stacklevel=depth_to_user_code + 1 + ) + class catch_and_log_exceptions: """ @@ -106,7 +117,7 @@ class catch_and_log_exceptions: override the global strict mode if provided. """ - def __init__(self, context: str = "", depth_to_user_code: int = 0) -> None: + def __init__(self, context: str | None = None, depth_to_user_code: int = 0) -> None: self.depth_to_user_code = depth_to_user_code self.context = context @@ -124,6 +135,9 @@ def __enter__(self) -> catch_and_log_exceptions: def __call__(self, func: _TFunc) -> _TFunc: self.depth_to_user_code += 1 + if self.context is None: + self.context = func.__qualname__ + @functools.wraps(func) def wrapper(*args: Any, **kwargs: Any) -> Any: with self: @@ -143,7 +157,12 @@ def __exit__( if exc_type is not None and not check_strict_mode(): if getattr(_rerun_exception_ctx, "pending_warnings", None) is None: _rerun_exception_ctx.pending_warnings = [] - _rerun_exception_ctx.pending_warnings.append(f"{self.context or exc_type.__name__}: {exc_val}") + + context = f"{self.context}: " if self.context is not None else "" + + warning_message = f"{context}{exc_type.__name__}({exc_val})" + + _rerun_exception_ctx.pending_warnings.append(warning_message) return True else: return False From f7ec126d4a35b1e4b6ab7e751e43018671a2f820 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 01:08:26 +0200 Subject: [PATCH 08/27] Handle errors when producing any kind of Batch --- rerun_py/rerun_sdk/rerun/_baseclasses.py | 32 +++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/_baseclasses.py b/rerun_py/rerun_sdk/rerun/_baseclasses.py index 7d691246578a..fca0bd7187ab 100644 --- a/rerun_py/rerun_sdk/rerun/_baseclasses.py +++ b/rerun_py/rerun_sdk/rerun/_baseclasses.py @@ -5,6 +5,8 @@ import pyarrow as pa from attrs import define, fields +from .error_utils import catch_and_log_exceptions + T = TypeVar("T") @@ -150,6 +152,7 @@ class BaseBatch(Generic[T]): _ARROW_TYPE: BaseExtensionType = None # type: ignore[assignment] """The pyarrow type of this batch.""" + @catch_and_log_exceptions() def __init__(self, data: T | None) -> None: """ Primary method for creating Arrow arrays for required components. @@ -172,22 +175,21 @@ def __init__(self, data: T | None) -> None: ------- The Arrow array encapsulating the data. """ - - # If data is already an arrow array, use it - if isinstance(data, pa.Array): - if data.type == self._ARROW_TYPE: - self.pa_array = data - return - elif data.type == self._ARROW_TYPE.storage_type: - self.pa_array = self._ARROW_TYPE.wrap_array(data) + if data is not None: + with catch_and_log_exceptions(self.__class__.__name__): + # If data is already an arrow array, use it + if isinstance(data, pa.Array) and data.type == self._ARROW_TYPE: + self.pa_array = data + elif isinstance(data, pa.Array) and data.type == self._ARROW_TYPE.storage_type: + self.pa_array = self._ARROW_TYPE.wrap_array(data) + else: + self.pa_array = self._ARROW_TYPE.wrap_array( + self._native_to_pa_array(data, self._ARROW_TYPE.storage_type) + ) return - if data is None: - pa_array = _empty_pa_array(self._ARROW_TYPE.storage_type) - else: - pa_array = self._native_to_pa_array(data, self._ARROW_TYPE.storage_type) - - self.pa_array = self._ARROW_TYPE.wrap_array(pa_array) + # If we didn't return above, default to the empty array + self.pa_array = _empty_pa_array(self._ARROW_TYPE) @classmethod def _optional(cls, data: T | None) -> BaseBatch[T] | None: @@ -272,7 +274,7 @@ def component_name(self) -> str: def _empty_pa_array(type: pa.DataType) -> pa.Array: if isinstance(type, pa.ExtensionType): - return _empty_pa_array(type.storage_type) + return type.wrap_array(_empty_pa_array(type.storage_type)) # Creation of empty arrays of dense unions aren't implemented in pyarrow yet. if isinstance(type, pa.UnionType): From d8dd544b305510fbd6f3623988c446264d547d1e Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 01:26:34 +0200 Subject: [PATCH 09/27] All archetype constructors will catch errors if not strict --- crates/re_types_builder/src/codegen/python.rs | 10 +++++++++- .../rerun_sdk/rerun/archetypes/annotation_context.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/asset3d.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/depth_image.py | 2 ++ .../rerun_sdk/rerun/archetypes/disconnected_space.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/image.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/points2d.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/points3d.py | 2 ++ .../rerun_sdk/rerun/archetypes/segmentation_image.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/text_document.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/text_log.py | 2 ++ .../rerun_sdk/rerun/archetypes/time_series_scalar.py | 2 ++ rerun_py/rerun_sdk/rerun/archetypes/transform3d.py | 2 ++ .../rerun_sdk/rerun/archetypes/view_coordinates.py | 2 ++ rerun_py/tests/test_types/archetypes/affix_fuzzer1.py | 2 ++ rerun_py/tests/test_types/archetypes/affix_fuzzer2.py | 2 ++ rerun_py/tests/test_types/archetypes/affix_fuzzer3.py | 2 ++ rerun_py/tests/test_types/archetypes/affix_fuzzer4.py | 2 ++ 21 files changed, 49 insertions(+), 1 deletion(-) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index 84fc1f0f47bd..cd5bda581925 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -323,6 +323,7 @@ impl PythonCodeGenerator { import numpy.typing as npt import pyarrow as pa import uuid + from ..error_utils import catch_and_log_exceptions from {rerun_path}_baseclasses import ( Archetype, @@ -1656,8 +1657,15 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects format!("self.__attrs_init__({})", attribute_init.join(", ")) }; + // Make sure Archetypes catch and log exceptions as a fallback + let decorator = if obj.kind == ObjectKind::Archetype { + "@catch_and_log_exceptions()\n" + } else { + "" + }; + format!( - "{head}\n{}", + "{decorator}{head}\n{}", indent::indent_all_by( 4, format!("{doc_block}\n\n{custom_init_hint}\n{forwarding_call}"), diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index 71fc6a6529f4..c9407e05d4bc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -11,6 +11,7 @@ from .. import components from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["AnnotationContext"] @@ -124,6 +125,7 @@ class AnnotationContext(Archetype): """ + @catch_and_log_exceptions() def __init__(self: Any, context: components.AnnotationContextLike): """Create a new instance of the AnnotationContext archetype.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index cdb76cb4ef2c..cb5290f18425 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions from .asset3d_ext import Asset3DExt __all__ = ["Asset3D"] @@ -73,6 +74,7 @@ class Asset3D(Asset3DExt, Archetype): ``` """ + @catch_and_log_exceptions() def __init__( self: Any, blob: components.BlobLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 6d5b16845f65..763a6f05fa52 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions from .bar_chart_ext import BarChartExt __all__ = ["BarChart"] @@ -34,6 +35,7 @@ class BarChart(BarChartExt, Archetype): ``` """ + @catch_and_log_exceptions() def __init__(self: Any, values: datatypes.TensorDataLike): """ Create a new instance of the BarChart archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 59c7a4751f06..161db42b1808 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions from .depth_image_ext import DepthImageExt __all__ = ["DepthImage"] @@ -87,6 +88,7 @@ class DepthImage(DepthImageExt, Archetype): """ + @catch_and_log_exceptions() def __init__( self: Any, data: datatypes.TensorDataLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index 581fee317e85..f40a9aaab81a 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -11,6 +11,7 @@ from .. import components from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["DisconnectedSpace"] @@ -42,6 +43,7 @@ class DisconnectedSpace(Archetype): ``` """ + @catch_and_log_exceptions() def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): """Create a new instance of the DisconnectedSpace archetype.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index 4712fde46810..904c3a761a9f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions from .image_ext import ImageExt __all__ = ["Image"] @@ -54,6 +55,7 @@ class Image(ImageExt, Archetype): """ + @catch_and_log_exceptions() def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: components.DrawOrderLike | None = None): """ Create a new instance of the Image archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index e8ffd80d4e7b..df62b11395e0 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["LineStrips2D"] @@ -95,6 +96,7 @@ class LineStrips2D(Archetype): """ + @catch_and_log_exceptions() def __init__( self: Any, strips: components.LineStrip2DArrayLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index cb963d15a517..8341f42e8db6 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["LineStrips3D"] @@ -121,6 +122,7 @@ class LineStrips3D(Archetype): """ + @catch_and_log_exceptions() def __init__( self: Any, strips: components.LineStrip3DArrayLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index b07582c04db3..1d1b87f1e318 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["Points2D"] @@ -65,6 +66,7 @@ class Points2D(Archetype): """ + @catch_and_log_exceptions() def __init__( self: Any, positions: datatypes.Vec2DArrayLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 324e0f1337b0..2e3a88b30793 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["Points3D"] @@ -59,6 +60,7 @@ class Points3D(Archetype): """ + @catch_and_log_exceptions() def __init__( self: Any, positions: datatypes.Vec3DArrayLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index cde92b6c29c6..c9e5b2acf717 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions from .segmentation_image_ext import SegmentationImageExt __all__ = ["SegmentationImage"] @@ -55,6 +56,7 @@ class SegmentationImage(SegmentationImageExt, Archetype): """ + @catch_and_log_exceptions() def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: components.DrawOrderLike | None = None): """ Create a new instance of the SegmentationImage archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index eba8e0f2d706..e22d3b06be9b 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["TextDocument"] @@ -19,6 +20,7 @@ class TextDocument(Archetype): """A text element intended to be displayed in its own text-box.""" + @catch_and_log_exceptions() def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8Like | None = None): """ Create a new instance of the TextDocument archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index 1cd20f74aa8a..f4158f670dbe 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["TextLog"] @@ -19,6 +20,7 @@ class TextLog(Archetype): """A log entry in a text log, comprised of a text body and its log level.""" + @catch_and_log_exceptions() def __init__( self: Any, text: datatypes.Utf8Like, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index bd8b9423ae7d..042ee4b11f26 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["TimeSeriesScalar"] @@ -60,6 +61,7 @@ class TimeSeriesScalar(Archetype): ``` """ + @catch_and_log_exceptions() def __init__( self: Any, scalar: components.ScalarLike, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index 6a57d6b17935..c007f3092de4 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -11,6 +11,7 @@ from .. import components, datatypes from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions __all__ = ["Transform3D"] @@ -53,6 +54,7 @@ class Transform3D(Archetype): """ + @catch_and_log_exceptions() def __init__(self: Any, transform: datatypes.Transform3DLike): """ Create a new instance of the Transform3D archetype. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index f0add00961cf..d4d8bc727334 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -11,6 +11,7 @@ from .. import components from .._baseclasses import Archetype +from ..error_utils import catch_and_log_exceptions from .view_coordinates_ext import ViewCoordinatesExt __all__ = ["ViewCoordinates"] @@ -47,6 +48,7 @@ class ViewCoordinates(ViewCoordinatesExt, Archetype): ``` """ + @catch_and_log_exceptions() def __init__(self: Any, xyz: components.ViewCoordinatesLike): """Create a new instance of the ViewCoordinates archetype.""" diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index f9c81b436ad0..a604cc22f213 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -11,12 +11,14 @@ from rerun._baseclasses import Archetype from .. import components, datatypes +from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer1"] @define(str=False, repr=False, init=False) class AffixFuzzer1(Archetype): + @catch_and_log_exceptions() def __init__( self: Any, fuzz1001: datatypes.AffixFuzzer1Like, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 5ade70ad6ff7..97fc373892dc 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -11,12 +11,14 @@ from rerun._baseclasses import Archetype from .. import components, datatypes +from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer2"] @define(str=False, repr=False, init=False) class AffixFuzzer2(Archetype): + @catch_and_log_exceptions() def __init__( self: Any, fuzz1101: datatypes.AffixFuzzer1ArrayLike, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index b3170480b7c2..c2d8841858f7 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -11,12 +11,14 @@ from rerun._baseclasses import Archetype from .. import components, datatypes +from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer3"] @define(str=False, repr=False, init=False) class AffixFuzzer3(Archetype): + @catch_and_log_exceptions() def __init__( self: Any, *, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index 7006598163a0..a6d36a8c7580 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -11,12 +11,14 @@ from rerun._baseclasses import Archetype from .. import components, datatypes +from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer4"] @define(str=False, repr=False, init=False) class AffixFuzzer4(Archetype): + @catch_and_log_exceptions() def __init__( self: Any, *, From dec1fe56bf25d68859ec4eb64bafad2526eccce2 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 04:32:04 +0200 Subject: [PATCH 10/27] Don't decorate __init__ functions --- crates/re_types_builder/src/codegen/python.rs | 18 ++-- rerun_py/rerun_sdk/rerun/_baseclasses.py | 13 ++- rerun_py/rerun_sdk/rerun/_log.py | 5 + .../rerun/archetypes/annotation_context.py | 8 +- .../rerun_sdk/rerun/archetypes/arrows3d.py | 2 +- .../rerun_sdk/rerun/archetypes/asset3d.py | 8 +- .../rerun_sdk/rerun/archetypes/bar_chart.py | 6 +- .../rerun_sdk/rerun/archetypes/boxes2d.py | 2 +- .../rerun_sdk/rerun/archetypes/boxes3d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/clear.py | 2 +- .../rerun_sdk/rerun/archetypes/depth_image.py | 6 +- .../rerun/archetypes/disconnected_space.py | 8 +- rerun_py/rerun_sdk/rerun/archetypes/image.py | 6 +- .../rerun/archetypes/line_strips2d.py | 24 ++--- .../rerun/archetypes/line_strips3d.py | 17 +++- rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py | 2 +- .../rerun_sdk/rerun/archetypes/pinhole.py | 2 +- .../rerun_sdk/rerun/archetypes/points2d.py | 26 ++--- .../rerun_sdk/rerun/archetypes/points3d.py | 24 ++--- .../rerun/archetypes/segmentation_image.py | 6 +- rerun_py/rerun_sdk/rerun/archetypes/tensor.py | 2 +- .../rerun/archetypes/text_document.py | 8 +- .../rerun_sdk/rerun/archetypes/text_log.py | 8 +- .../rerun/archetypes/time_series_scalar.py | 8 +- .../rerun_sdk/rerun/archetypes/transform3d.py | 8 +- .../rerun/archetypes/view_coordinates.py | 8 +- rerun_py/rerun_sdk/rerun/error_utils.py | 8 +- .../test_types/archetypes/affix_fuzzer1.py | 94 ++++++++++--------- .../test_types/archetypes/affix_fuzzer2.py | 82 ++++++++-------- .../test_types/archetypes/affix_fuzzer3.py | 46 ++++----- .../test_types/archetypes/affix_fuzzer4.py | 46 ++++----- rerun_py/tests/unit/test_exceptions.py | 2 +- 32 files changed, 289 insertions(+), 218 deletions(-) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index cd5bda581925..2688bc8bd842 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -323,8 +323,8 @@ impl PythonCodeGenerator { import numpy.typing as npt import pyarrow as pa import uuid - from ..error_utils import catch_and_log_exceptions + from {rerun_path}error_utils import catch_and_log_exceptions from {rerun_path}_baseclasses import ( Archetype, BaseExtensionType, @@ -548,7 +548,7 @@ fn code_for_struct( if field.is_nullable { format!("converter={typ_unwrapped}Batch._optional, # type: ignore[misc]\n") } else { - format!("converter={typ_unwrapped}Batch, # type: ignore[misc]\n") + format!("converter={typ_unwrapped}Batch._required, # type: ignore[misc]\n") } } else if !default_converter.is_empty() { code.push_text(&converter_function, 1, 0); @@ -1658,14 +1658,20 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects }; // Make sure Archetypes catch and log exceptions as a fallback - let decorator = if obj.kind == ObjectKind::Archetype { - "@catch_and_log_exceptions()\n" + let forwarding_call = if obj.kind == ObjectKind::Archetype { + [ + format!("with catch_and_log_exceptions(\"{}\"):", obj.name), + indent::indent_all_by(4, forwarding_call), + indent::indent_all_by(4, "return"), + "self.__attrs_init__()".to_owned(), + ] + .join("\n") } else { - "" + forwarding_call }; format!( - "{decorator}{head}\n{}", + "{head}\n{}", indent::indent_all_by( 4, format!("{doc_block}\n\n{custom_init_hint}\n{forwarding_call}"), diff --git a/rerun_py/rerun_sdk/rerun/_baseclasses.py b/rerun_py/rerun_sdk/rerun/_baseclasses.py index fca0bd7187ab..aeb3e40e8e25 100644 --- a/rerun_py/rerun_sdk/rerun/_baseclasses.py +++ b/rerun_py/rerun_sdk/rerun/_baseclasses.py @@ -152,10 +152,9 @@ class BaseBatch(Generic[T]): _ARROW_TYPE: BaseExtensionType = None # type: ignore[assignment] """The pyarrow type of this batch.""" - @catch_and_log_exceptions() def __init__(self, data: T | None) -> None: """ - Primary method for creating Arrow arrays for required components. + Construct a new batch. This method must flexibly accept native data (which comply with type `T`). Subclasses must provide a type parameter specifying the type of the native data (this is automatically handled by the code generator). @@ -191,6 +190,15 @@ def __init__(self, data: T | None) -> None: # If we didn't return above, default to the empty array self.pa_array = _empty_pa_array(self._ARROW_TYPE) + @classmethod + def _required(cls, data: T | None) -> BaseBatch[T]: + """ + Primary method for creating Arrow arrays for optional components. + + Just calls through to __init__, but with clearer type annotations. + """ + return cls(data) + @classmethod def _optional(cls, data: T | None) -> BaseBatch[T] | None: """ @@ -272,6 +280,7 @@ def component_name(self) -> str: return self._ARROW_TYPE._TYPE_NAME # type: ignore[attr-defined, no-any-return] +@catch_and_log_exceptions(context="creating empty array") def _empty_pa_array(type: pa.DataType) -> pa.Array: if isinstance(type, pa.ExtensionType): return type.wrap_array(_empty_pa_array(type.storage_type)) diff --git a/rerun_py/rerun_sdk/rerun/_log.py b/rerun_py/rerun_sdk/rerun/_log.py index 4522b892ad82..d7aa6f9b608c 100644 --- a/rerun_py/rerun_sdk/rerun/_log.py +++ b/rerun_py/rerun_sdk/rerun/_log.py @@ -214,6 +214,11 @@ def log_components( num_instances = max(len(arr) for arr in arrow_arrays) for name, array in zip(names, arrow_arrays): + # Array could be None if there was an error producing the empty array + # Nothing we can do at this point other than ignore it. Some form of error + # should have been logged. + if array is None: + pass # Strip off the ExtensionArray if it's present. We will always log via component_name. # TODO(jleibs): Maybe warn if there is a name mismatch here. if isinstance(array, pa.ExtensionArray): diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index c9407e05d4bc..a73110752ab6 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -125,16 +125,18 @@ class AnnotationContext(Archetype): """ - @catch_and_log_exceptions() def __init__(self: Any, context: components.AnnotationContextLike): """Create a new instance of the AnnotationContext archetype.""" # You can define your own __init__ function as a member of AnnotationContextExt in annotation_context_ext.py - self.__attrs_init__(context=context) + with catch_and_log_exceptions("AnnotationContext"): + self.__attrs_init__(context=context) + return + self.__attrs_init__() context: components.AnnotationContextBatch = field( metadata={"component": "required"}, - converter=components.AnnotationContextBatch, # type: ignore[misc] + converter=components.AnnotationContextBatch._required, # type: ignore[misc] ) __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ diff --git a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py index b422336a8cbf..c023bc852b2f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py @@ -50,7 +50,7 @@ class Arrows3D(Arrows3DExt, Archetype): vectors: components.Vector3DBatch = field( metadata={"component": "required"}, - converter=components.Vector3DBatch, # type: ignore[misc] + converter=components.Vector3DBatch._required, # type: ignore[misc] ) """ All the vectors for each arrow in the batch. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index cb5290f18425..94971c2726c9 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -74,7 +74,6 @@ class Asset3D(Asset3DExt, Archetype): ``` """ - @catch_and_log_exceptions() def __init__( self: Any, blob: components.BlobLike, @@ -105,11 +104,14 @@ def __init__( """ # You can define your own __init__ function as a member of Asset3DExt in asset3d_ext.py - self.__attrs_init__(blob=blob, media_type=media_type, transform=transform) + with catch_and_log_exceptions("Asset3D"): + self.__attrs_init__(blob=blob, media_type=media_type, transform=transform) + return + self.__attrs_init__() blob: components.BlobBatch = field( metadata={"component": "required"}, - converter=components.BlobBatch, # type: ignore[misc] + converter=components.BlobBatch._required, # type: ignore[misc] ) """ The asset's bytes. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 763a6f05fa52..902022351bff 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -35,7 +35,6 @@ class BarChart(BarChartExt, Archetype): ``` """ - @catch_and_log_exceptions() def __init__(self: Any, values: datatypes.TensorDataLike): """ Create a new instance of the BarChart archetype. @@ -47,7 +46,10 @@ def __init__(self: Any, values: datatypes.TensorDataLike): """ # You can define your own __init__ function as a member of BarChartExt in bar_chart_ext.py - self.__attrs_init__(values=values) + with catch_and_log_exceptions("BarChart"): + self.__attrs_init__(values=values) + return + self.__attrs_init__() values: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py index 830fcb475160..4eccb863b6df 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py @@ -38,7 +38,7 @@ class Boxes2D(Boxes2DExt, Archetype): half_sizes: components.HalfSizes2DBatch = field( metadata={"component": "required"}, - converter=components.HalfSizes2DBatch, # type: ignore[misc] + converter=components.HalfSizes2DBatch._required, # type: ignore[misc] ) """ All half-extents that make up the batch of boxes. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py index cdfeed1b06ad..e6cc40d811bf 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py @@ -73,7 +73,7 @@ class Boxes3D(Boxes3DExt, Archetype): half_sizes: components.HalfSizes3DBatch = field( metadata={"component": "required"}, - converter=components.HalfSizes3DBatch, # type: ignore[misc] + converter=components.HalfSizes3DBatch._required, # type: ignore[misc] ) """ All half-extents that make up the batch of boxes. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/clear.py b/rerun_py/rerun_sdk/rerun/archetypes/clear.py index c103bc9a0119..4a8b79fd28fc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/clear.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/clear.py @@ -65,7 +65,7 @@ class Clear(ClearExt, Archetype): recursive: components.ClearIsRecursiveBatch = field( metadata={"component": "required"}, - converter=components.ClearIsRecursiveBatch, # type: ignore[misc] + converter=components.ClearIsRecursiveBatch._required, # type: ignore[misc] ) __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 161db42b1808..29788b7b77cf 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -88,7 +88,6 @@ class DepthImage(DepthImageExt, Archetype): """ - @catch_and_log_exceptions() def __init__( self: Any, data: datatypes.TensorDataLike, @@ -114,7 +113,10 @@ def __init__( """ # You can define your own __init__ function as a member of DepthImageExt in depth_image_ext.py - self.__attrs_init__(data=data, meter=meter, draw_order=draw_order) + with catch_and_log_exceptions("DepthImage"): + self.__attrs_init__(data=data, meter=meter, draw_order=draw_order) + return + self.__attrs_init__() data: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index f40a9aaab81a..3c683d81166a 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -43,16 +43,18 @@ class DisconnectedSpace(Archetype): ``` """ - @catch_and_log_exceptions() def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): """Create a new instance of the DisconnectedSpace archetype.""" # You can define your own __init__ function as a member of DisconnectedSpaceExt in disconnected_space_ext.py - self.__attrs_init__(disconnected_space=disconnected_space) + with catch_and_log_exceptions("DisconnectedSpace"): + self.__attrs_init__(disconnected_space=disconnected_space) + return + self.__attrs_init__() disconnected_space: components.DisconnectedSpaceBatch = field( metadata={"component": "required"}, - converter=components.DisconnectedSpaceBatch, # type: ignore[misc] + converter=components.DisconnectedSpaceBatch._required, # type: ignore[misc] ) __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index 904c3a761a9f..89fdebce9671 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -55,7 +55,6 @@ class Image(ImageExt, Archetype): """ - @catch_and_log_exceptions() def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: components.DrawOrderLike | None = None): """ Create a new instance of the Image archetype. @@ -70,7 +69,10 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component """ # You can define your own __init__ function as a member of ImageExt in image_ext.py - self.__attrs_init__(data=data, draw_order=draw_order) + with catch_and_log_exceptions("Image"): + self.__attrs_init__(data=data, draw_order=draw_order) + return + self.__attrs_init__() data: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index df62b11395e0..8bcc0445a27f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -96,7 +96,6 @@ class LineStrips2D(Archetype): """ - @catch_and_log_exceptions() def __init__( self: Any, strips: components.LineStrip2DArrayLike, @@ -133,19 +132,22 @@ def __init__( """ # You can define your own __init__ function as a member of LineStrips2DExt in line_strips2d_ext.py - self.__attrs_init__( - strips=strips, - radii=radii, - colors=colors, - labels=labels, - draw_order=draw_order, - class_ids=class_ids, - instance_keys=instance_keys, - ) + with catch_and_log_exceptions("LineStrips2D"): + self.__attrs_init__( + strips=strips, + radii=radii, + colors=colors, + labels=labels, + draw_order=draw_order, + class_ids=class_ids, + instance_keys=instance_keys, + ) + return + self.__attrs_init__() strips: components.LineStrip2DBatch = field( metadata={"component": "required"}, - converter=components.LineStrip2DBatch, # type: ignore[misc] + converter=components.LineStrip2DBatch._required, # type: ignore[misc] ) """ All the actual 2D line strips that make up the batch. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index 8341f42e8db6..2a6e33f5560d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -122,7 +122,6 @@ class LineStrips3D(Archetype): """ - @catch_and_log_exceptions() def __init__( self: Any, strips: components.LineStrip3DArrayLike, @@ -155,13 +154,21 @@ def __init__( """ # You can define your own __init__ function as a member of LineStrips3DExt in line_strips3d_ext.py - self.__attrs_init__( - strips=strips, radii=radii, colors=colors, labels=labels, class_ids=class_ids, instance_keys=instance_keys - ) + with catch_and_log_exceptions("LineStrips3D"): + self.__attrs_init__( + strips=strips, + radii=radii, + colors=colors, + labels=labels, + class_ids=class_ids, + instance_keys=instance_keys, + ) + return + self.__attrs_init__() strips: components.LineStrip3DBatch = field( metadata={"component": "required"}, - converter=components.LineStrip3DBatch, # type: ignore[misc] + converter=components.LineStrip3DBatch._required, # type: ignore[misc] ) """ All the actual 3D line strips that make up the batch. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py index 816d5e8e69b6..e49008bf3178 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py @@ -73,7 +73,7 @@ class Mesh3D(Mesh3DExt, Archetype): vertex_positions: components.Position3DBatch = field( metadata={"component": "required"}, - converter=components.Position3DBatch, # type: ignore[misc] + converter=components.Position3DBatch._required, # type: ignore[misc] ) """ The positions of each vertex. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py index fb315aa8dd67..1700e727a9bc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py @@ -45,7 +45,7 @@ class Pinhole(PinholeExt, Archetype): image_from_camera: components.PinholeProjectionBatch = field( metadata={"component": "required"}, - converter=components.PinholeProjectionBatch, # type: ignore[misc] + converter=components.PinholeProjectionBatch._required, # type: ignore[misc] ) """ Camera projection, from image coordinates to view coordinates. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index 1d1b87f1e318..5e37201ed15d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -66,7 +66,6 @@ class Points2D(Archetype): """ - @catch_and_log_exceptions() def __init__( self: Any, positions: datatypes.Vec2DArrayLike, @@ -116,20 +115,23 @@ def __init__( """ # You can define your own __init__ function as a member of Points2DExt in points2d_ext.py - self.__attrs_init__( - positions=positions, - radii=radii, - colors=colors, - labels=labels, - draw_order=draw_order, - class_ids=class_ids, - keypoint_ids=keypoint_ids, - instance_keys=instance_keys, - ) + with catch_and_log_exceptions("Points2D"): + self.__attrs_init__( + positions=positions, + radii=radii, + colors=colors, + labels=labels, + draw_order=draw_order, + class_ids=class_ids, + keypoint_ids=keypoint_ids, + instance_keys=instance_keys, + ) + return + self.__attrs_init__() positions: components.Position2DBatch = field( metadata={"component": "required"}, - converter=components.Position2DBatch, # type: ignore[misc] + converter=components.Position2DBatch._required, # type: ignore[misc] ) """ All the 2D positions at which the point cloud shows points. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 2e3a88b30793..24f1702b0544 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -60,7 +60,6 @@ class Points3D(Archetype): """ - @catch_and_log_exceptions() def __init__( self: Any, positions: datatypes.Vec3DArrayLike, @@ -106,19 +105,22 @@ def __init__( """ # You can define your own __init__ function as a member of Points3DExt in points3d_ext.py - self.__attrs_init__( - positions=positions, - radii=radii, - colors=colors, - labels=labels, - class_ids=class_ids, - keypoint_ids=keypoint_ids, - instance_keys=instance_keys, - ) + with catch_and_log_exceptions("Points3D"): + self.__attrs_init__( + positions=positions, + radii=radii, + colors=colors, + labels=labels, + class_ids=class_ids, + keypoint_ids=keypoint_ids, + instance_keys=instance_keys, + ) + return + self.__attrs_init__() positions: components.Position3DBatch = field( metadata={"component": "required"}, - converter=components.Position3DBatch, # type: ignore[misc] + converter=components.Position3DBatch._required, # type: ignore[misc] ) """ All the 3D positions at which the point cloud shows points. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index c9e5b2acf717..f89f64dff407 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -56,7 +56,6 @@ class SegmentationImage(SegmentationImageExt, Archetype): """ - @catch_and_log_exceptions() def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: components.DrawOrderLike | None = None): """ Create a new instance of the SegmentationImage archetype. @@ -71,7 +70,10 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component """ # You can define your own __init__ function as a member of SegmentationImageExt in segmentation_image_ext.py - self.__attrs_init__(data=data, draw_order=draw_order) + with catch_and_log_exceptions("SegmentationImage"): + self.__attrs_init__(data=data, draw_order=draw_order) + return + self.__attrs_init__() data: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/tensor.py b/rerun_py/rerun_sdk/rerun/archetypes/tensor.py index 9783a1cba823..214fa46abd8f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/tensor.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/tensor.py @@ -72,7 +72,7 @@ class Tensor(TensorExt, Archetype): data: components.TensorDataBatch = field( metadata={"component": "required"}, - converter=components.TensorDataBatch, # type: ignore[misc] + converter=components.TensorDataBatch._required, # type: ignore[misc] ) """ The tensor data diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index e22d3b06be9b..8d27a8ba1366 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -20,7 +20,6 @@ class TextDocument(Archetype): """A text element intended to be displayed in its own text-box.""" - @catch_and_log_exceptions() def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8Like | None = None): """ Create a new instance of the TextDocument archetype. @@ -40,11 +39,14 @@ def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8L """ # You can define your own __init__ function as a member of TextDocumentExt in text_document_ext.py - self.__attrs_init__(text=text, media_type=media_type) + with catch_and_log_exceptions("TextDocument"): + self.__attrs_init__(text=text, media_type=media_type) + return + self.__attrs_init__() text: components.TextBatch = field( metadata={"component": "required"}, - converter=components.TextBatch, # type: ignore[misc] + converter=components.TextBatch._required, # type: ignore[misc] ) """ Contents of the text document. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index f4158f670dbe..4c3e2b92046a 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -20,7 +20,6 @@ class TextLog(Archetype): """A log entry in a text log, comprised of a text body and its log level.""" - @catch_and_log_exceptions() def __init__( self: Any, text: datatypes.Utf8Like, @@ -31,11 +30,14 @@ def __init__( """Create a new instance of the TextLog archetype.""" # You can define your own __init__ function as a member of TextLogExt in text_log_ext.py - self.__attrs_init__(text=text, level=level, color=color) + with catch_and_log_exceptions("TextLog"): + self.__attrs_init__(text=text, level=level, color=color) + return + self.__attrs_init__() text: components.TextBatch = field( metadata={"component": "required"}, - converter=components.TextBatch, # type: ignore[misc] + converter=components.TextBatch._required, # type: ignore[misc] ) level: components.TextLogLevelBatch | None = field( metadata={"component": "optional"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index 042ee4b11f26..718a2d9897ac 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -61,7 +61,6 @@ class TimeSeriesScalar(Archetype): ``` """ - @catch_and_log_exceptions() def __init__( self: Any, scalar: components.ScalarLike, @@ -119,11 +118,14 @@ def __init__( """ # You can define your own __init__ function as a member of TimeSeriesScalarExt in time_series_scalar_ext.py - self.__attrs_init__(scalar=scalar, radius=radius, color=color, label=label, scattered=scattered) + with catch_and_log_exceptions("TimeSeriesScalar"): + self.__attrs_init__(scalar=scalar, radius=radius, color=color, label=label, scattered=scattered) + return + self.__attrs_init__() scalar: components.ScalarBatch = field( metadata={"component": "required"}, - converter=components.ScalarBatch, # type: ignore[misc] + converter=components.ScalarBatch._required, # type: ignore[misc] ) """ The scalar value to log. diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index c007f3092de4..1335edaca44e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -54,7 +54,6 @@ class Transform3D(Archetype): """ - @catch_and_log_exceptions() def __init__(self: Any, transform: datatypes.Transform3DLike): """ Create a new instance of the Transform3D archetype. @@ -66,11 +65,14 @@ def __init__(self: Any, transform: datatypes.Transform3DLike): """ # You can define your own __init__ function as a member of Transform3DExt in transform3d_ext.py - self.__attrs_init__(transform=transform) + with catch_and_log_exceptions("Transform3D"): + self.__attrs_init__(transform=transform) + return + self.__attrs_init__() transform: components.Transform3DBatch = field( metadata={"component": "required"}, - converter=components.Transform3DBatch, # type: ignore[misc] + converter=components.Transform3DBatch._required, # type: ignore[misc] ) """ The transform diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index d4d8bc727334..2396dbca38df 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -48,16 +48,18 @@ class ViewCoordinates(ViewCoordinatesExt, Archetype): ``` """ - @catch_and_log_exceptions() def __init__(self: Any, xyz: components.ViewCoordinatesLike): """Create a new instance of the ViewCoordinates archetype.""" # You can define your own __init__ function as a member of ViewCoordinatesExt in view_coordinates_ext.py - self.__attrs_init__(xyz=xyz) + with catch_and_log_exceptions("ViewCoordinates"): + self.__attrs_init__(xyz=xyz) + return + self.__attrs_init__() xyz: components.ViewCoordinatesBatch = field( metadata={"component": "required"}, - converter=components.ViewCoordinatesBatch, # type: ignore[misc] + converter=components.ViewCoordinatesBatch._required, # type: ignore[misc] ) __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index d1bc4d28271d..5db47a214b49 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -117,9 +117,12 @@ class catch_and_log_exceptions: override the global strict mode if provided. """ - def __init__(self, context: str | None = None, depth_to_user_code: int = 0) -> None: + def __init__( + self, context: str | None = None, depth_to_user_code: int = 0, exception_return_value: Any = None + ) -> None: self.depth_to_user_code = depth_to_user_code self.context = context + self.exception_return_value = exception_return_value def __enter__(self) -> catch_and_log_exceptions: # Track the original strict_mode setting in case it's being @@ -145,6 +148,9 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: _rerun_exception_ctx.strict_mode = kwargs["strict"] return func(*args, **kwargs) + # If there was an exception before returning from func + return self.exception_return_value + return cast(_TFunc, wrapper) def __exit__( diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index a604cc22f213..43408bef7268 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -9,16 +9,15 @@ from attrs import define, field from rerun._baseclasses import Archetype +from rerun.error_utils import catch_and_log_exceptions from .. import components, datatypes -from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer1"] @define(str=False, repr=False, init=False) class AffixFuzzer1(Archetype): - @catch_and_log_exceptions() def __init__( self: Any, fuzz1001: datatypes.AffixFuzzer1Like, @@ -46,113 +45,116 @@ def __init__( """Create a new instance of the AffixFuzzer1 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer1Ext in affix_fuzzer1_ext.py - self.__attrs_init__( - fuzz1001=fuzz1001, - fuzz1002=fuzz1002, - fuzz1003=fuzz1003, - fuzz1004=fuzz1004, - fuzz1005=fuzz1005, - fuzz1006=fuzz1006, - fuzz1007=fuzz1007, - fuzz1008=fuzz1008, - fuzz1009=fuzz1009, - fuzz1010=fuzz1010, - fuzz1011=fuzz1011, - fuzz1012=fuzz1012, - fuzz1013=fuzz1013, - fuzz1014=fuzz1014, - fuzz1015=fuzz1015, - fuzz1016=fuzz1016, - fuzz1017=fuzz1017, - fuzz1018=fuzz1018, - fuzz1019=fuzz1019, - fuzz1020=fuzz1020, - fuzz1021=fuzz1021, - ) + with catch_and_log_exceptions("AffixFuzzer1"): + self.__attrs_init__( + fuzz1001=fuzz1001, + fuzz1002=fuzz1002, + fuzz1003=fuzz1003, + fuzz1004=fuzz1004, + fuzz1005=fuzz1005, + fuzz1006=fuzz1006, + fuzz1007=fuzz1007, + fuzz1008=fuzz1008, + fuzz1009=fuzz1009, + fuzz1010=fuzz1010, + fuzz1011=fuzz1011, + fuzz1012=fuzz1012, + fuzz1013=fuzz1013, + fuzz1014=fuzz1014, + fuzz1015=fuzz1015, + fuzz1016=fuzz1016, + fuzz1017=fuzz1017, + fuzz1018=fuzz1018, + fuzz1019=fuzz1019, + fuzz1020=fuzz1020, + fuzz1021=fuzz1021, + ) + return + self.__attrs_init__() fuzz1001: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer1Batch, # type: ignore[misc] + converter=components.AffixFuzzer1Batch._required, # type: ignore[misc] ) fuzz1002: components.AffixFuzzer2Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer2Batch, # type: ignore[misc] + converter=components.AffixFuzzer2Batch._required, # type: ignore[misc] ) fuzz1003: components.AffixFuzzer3Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer3Batch, # type: ignore[misc] + converter=components.AffixFuzzer3Batch._required, # type: ignore[misc] ) fuzz1004: components.AffixFuzzer4Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer4Batch, # type: ignore[misc] + converter=components.AffixFuzzer4Batch._required, # type: ignore[misc] ) fuzz1005: components.AffixFuzzer5Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer5Batch, # type: ignore[misc] + converter=components.AffixFuzzer5Batch._required, # type: ignore[misc] ) fuzz1006: components.AffixFuzzer6Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer6Batch, # type: ignore[misc] + converter=components.AffixFuzzer6Batch._required, # type: ignore[misc] ) fuzz1007: components.AffixFuzzer7Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer7Batch, # type: ignore[misc] + converter=components.AffixFuzzer7Batch._required, # type: ignore[misc] ) fuzz1008: components.AffixFuzzer8Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer8Batch, # type: ignore[misc] + converter=components.AffixFuzzer8Batch._required, # type: ignore[misc] ) fuzz1009: components.AffixFuzzer9Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer9Batch, # type: ignore[misc] + converter=components.AffixFuzzer9Batch._required, # type: ignore[misc] ) fuzz1010: components.AffixFuzzer10Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer10Batch, # type: ignore[misc] + converter=components.AffixFuzzer10Batch._required, # type: ignore[misc] ) fuzz1011: components.AffixFuzzer11Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer11Batch, # type: ignore[misc] + converter=components.AffixFuzzer11Batch._required, # type: ignore[misc] ) fuzz1012: components.AffixFuzzer12Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer12Batch, # type: ignore[misc] + converter=components.AffixFuzzer12Batch._required, # type: ignore[misc] ) fuzz1013: components.AffixFuzzer13Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer13Batch, # type: ignore[misc] + converter=components.AffixFuzzer13Batch._required, # type: ignore[misc] ) fuzz1014: components.AffixFuzzer14Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer14Batch, # type: ignore[misc] + converter=components.AffixFuzzer14Batch._required, # type: ignore[misc] ) fuzz1015: components.AffixFuzzer15Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer15Batch, # type: ignore[misc] + converter=components.AffixFuzzer15Batch._required, # type: ignore[misc] ) fuzz1016: components.AffixFuzzer16Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer16Batch, # type: ignore[misc] + converter=components.AffixFuzzer16Batch._required, # type: ignore[misc] ) fuzz1017: components.AffixFuzzer17Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer17Batch, # type: ignore[misc] + converter=components.AffixFuzzer17Batch._required, # type: ignore[misc] ) fuzz1018: components.AffixFuzzer18Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer18Batch, # type: ignore[misc] + converter=components.AffixFuzzer18Batch._required, # type: ignore[misc] ) fuzz1019: components.AffixFuzzer19Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer19Batch, # type: ignore[misc] + converter=components.AffixFuzzer19Batch._required, # type: ignore[misc] ) fuzz1020: components.AffixFuzzer20Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer20Batch, # type: ignore[misc] + converter=components.AffixFuzzer20Batch._required, # type: ignore[misc] ) fuzz1021: components.AffixFuzzer21Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer21Batch, # type: ignore[misc] + converter=components.AffixFuzzer21Batch._required, # type: ignore[misc] ) __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 97fc373892dc..506dd343250e 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -9,16 +9,15 @@ from attrs import define, field from rerun._baseclasses import Archetype +from rerun.error_utils import catch_and_log_exceptions from .. import components, datatypes -from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer2"] @define(str=False, repr=False, init=False) class AffixFuzzer2(Archetype): - @catch_and_log_exceptions() def __init__( self: Any, fuzz1101: datatypes.AffixFuzzer1ArrayLike, @@ -43,98 +42,101 @@ def __init__( """Create a new instance of the AffixFuzzer2 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer2Ext in affix_fuzzer2_ext.py - self.__attrs_init__( - fuzz1101=fuzz1101, - fuzz1102=fuzz1102, - fuzz1103=fuzz1103, - fuzz1104=fuzz1104, - fuzz1105=fuzz1105, - fuzz1106=fuzz1106, - fuzz1107=fuzz1107, - fuzz1108=fuzz1108, - fuzz1109=fuzz1109, - fuzz1110=fuzz1110, - fuzz1111=fuzz1111, - fuzz1112=fuzz1112, - fuzz1113=fuzz1113, - fuzz1114=fuzz1114, - fuzz1115=fuzz1115, - fuzz1116=fuzz1116, - fuzz1117=fuzz1117, - fuzz1118=fuzz1118, - ) + with catch_and_log_exceptions("AffixFuzzer2"): + self.__attrs_init__( + fuzz1101=fuzz1101, + fuzz1102=fuzz1102, + fuzz1103=fuzz1103, + fuzz1104=fuzz1104, + fuzz1105=fuzz1105, + fuzz1106=fuzz1106, + fuzz1107=fuzz1107, + fuzz1108=fuzz1108, + fuzz1109=fuzz1109, + fuzz1110=fuzz1110, + fuzz1111=fuzz1111, + fuzz1112=fuzz1112, + fuzz1113=fuzz1113, + fuzz1114=fuzz1114, + fuzz1115=fuzz1115, + fuzz1116=fuzz1116, + fuzz1117=fuzz1117, + fuzz1118=fuzz1118, + ) + return + self.__attrs_init__() fuzz1101: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer1Batch, # type: ignore[misc] + converter=components.AffixFuzzer1Batch._required, # type: ignore[misc] ) fuzz1102: components.AffixFuzzer2Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer2Batch, # type: ignore[misc] + converter=components.AffixFuzzer2Batch._required, # type: ignore[misc] ) fuzz1103: components.AffixFuzzer3Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer3Batch, # type: ignore[misc] + converter=components.AffixFuzzer3Batch._required, # type: ignore[misc] ) fuzz1104: components.AffixFuzzer4Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer4Batch, # type: ignore[misc] + converter=components.AffixFuzzer4Batch._required, # type: ignore[misc] ) fuzz1105: components.AffixFuzzer5Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer5Batch, # type: ignore[misc] + converter=components.AffixFuzzer5Batch._required, # type: ignore[misc] ) fuzz1106: components.AffixFuzzer6Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer6Batch, # type: ignore[misc] + converter=components.AffixFuzzer6Batch._required, # type: ignore[misc] ) fuzz1107: components.AffixFuzzer7Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer7Batch, # type: ignore[misc] + converter=components.AffixFuzzer7Batch._required, # type: ignore[misc] ) fuzz1108: components.AffixFuzzer8Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer8Batch, # type: ignore[misc] + converter=components.AffixFuzzer8Batch._required, # type: ignore[misc] ) fuzz1109: components.AffixFuzzer9Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer9Batch, # type: ignore[misc] + converter=components.AffixFuzzer9Batch._required, # type: ignore[misc] ) fuzz1110: components.AffixFuzzer10Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer10Batch, # type: ignore[misc] + converter=components.AffixFuzzer10Batch._required, # type: ignore[misc] ) fuzz1111: components.AffixFuzzer11Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer11Batch, # type: ignore[misc] + converter=components.AffixFuzzer11Batch._required, # type: ignore[misc] ) fuzz1112: components.AffixFuzzer12Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer12Batch, # type: ignore[misc] + converter=components.AffixFuzzer12Batch._required, # type: ignore[misc] ) fuzz1113: components.AffixFuzzer13Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer13Batch, # type: ignore[misc] + converter=components.AffixFuzzer13Batch._required, # type: ignore[misc] ) fuzz1114: components.AffixFuzzer14Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer14Batch, # type: ignore[misc] + converter=components.AffixFuzzer14Batch._required, # type: ignore[misc] ) fuzz1115: components.AffixFuzzer15Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer15Batch, # type: ignore[misc] + converter=components.AffixFuzzer15Batch._required, # type: ignore[misc] ) fuzz1116: components.AffixFuzzer16Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer16Batch, # type: ignore[misc] + converter=components.AffixFuzzer16Batch._required, # type: ignore[misc] ) fuzz1117: components.AffixFuzzer17Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer17Batch, # type: ignore[misc] + converter=components.AffixFuzzer17Batch._required, # type: ignore[misc] ) fuzz1118: components.AffixFuzzer18Batch = field( metadata={"component": "required"}, - converter=components.AffixFuzzer18Batch, # type: ignore[misc] + converter=components.AffixFuzzer18Batch._required, # type: ignore[misc] ) __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index c2d8841858f7..09b9b6ae963f 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -9,16 +9,15 @@ from attrs import define, field from rerun._baseclasses import Archetype +from rerun.error_utils import catch_and_log_exceptions from .. import components, datatypes -from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer3"] @define(str=False, repr=False, init=False) class AffixFuzzer3(Archetype): - @catch_and_log_exceptions() def __init__( self: Any, *, @@ -44,26 +43,29 @@ def __init__( """Create a new instance of the AffixFuzzer3 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer3Ext in affix_fuzzer3_ext.py - self.__attrs_init__( - fuzz2001=fuzz2001, - fuzz2002=fuzz2002, - fuzz2003=fuzz2003, - fuzz2004=fuzz2004, - fuzz2005=fuzz2005, - fuzz2006=fuzz2006, - fuzz2007=fuzz2007, - fuzz2008=fuzz2008, - fuzz2009=fuzz2009, - fuzz2010=fuzz2010, - fuzz2011=fuzz2011, - fuzz2012=fuzz2012, - fuzz2013=fuzz2013, - fuzz2014=fuzz2014, - fuzz2015=fuzz2015, - fuzz2016=fuzz2016, - fuzz2017=fuzz2017, - fuzz2018=fuzz2018, - ) + with catch_and_log_exceptions("AffixFuzzer3"): + self.__attrs_init__( + fuzz2001=fuzz2001, + fuzz2002=fuzz2002, + fuzz2003=fuzz2003, + fuzz2004=fuzz2004, + fuzz2005=fuzz2005, + fuzz2006=fuzz2006, + fuzz2007=fuzz2007, + fuzz2008=fuzz2008, + fuzz2009=fuzz2009, + fuzz2010=fuzz2010, + fuzz2011=fuzz2011, + fuzz2012=fuzz2012, + fuzz2013=fuzz2013, + fuzz2014=fuzz2014, + fuzz2015=fuzz2015, + fuzz2016=fuzz2016, + fuzz2017=fuzz2017, + fuzz2018=fuzz2018, + ) + return + self.__attrs_init__() fuzz2001: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index a6d36a8c7580..b92903171f40 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -9,16 +9,15 @@ from attrs import define, field from rerun._baseclasses import Archetype +from rerun.error_utils import catch_and_log_exceptions from .. import components, datatypes -from ..error_utils import catch_and_log_exceptions __all__ = ["AffixFuzzer4"] @define(str=False, repr=False, init=False) class AffixFuzzer4(Archetype): - @catch_and_log_exceptions() def __init__( self: Any, *, @@ -44,26 +43,29 @@ def __init__( """Create a new instance of the AffixFuzzer4 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer4Ext in affix_fuzzer4_ext.py - self.__attrs_init__( - fuzz2101=fuzz2101, - fuzz2102=fuzz2102, - fuzz2103=fuzz2103, - fuzz2104=fuzz2104, - fuzz2105=fuzz2105, - fuzz2106=fuzz2106, - fuzz2107=fuzz2107, - fuzz2108=fuzz2108, - fuzz2109=fuzz2109, - fuzz2110=fuzz2110, - fuzz2111=fuzz2111, - fuzz2112=fuzz2112, - fuzz2113=fuzz2113, - fuzz2114=fuzz2114, - fuzz2115=fuzz2115, - fuzz2116=fuzz2116, - fuzz2117=fuzz2117, - fuzz2118=fuzz2118, - ) + with catch_and_log_exceptions("AffixFuzzer4"): + self.__attrs_init__( + fuzz2101=fuzz2101, + fuzz2102=fuzz2102, + fuzz2103=fuzz2103, + fuzz2104=fuzz2104, + fuzz2105=fuzz2105, + fuzz2106=fuzz2106, + fuzz2107=fuzz2107, + fuzz2108=fuzz2108, + fuzz2109=fuzz2109, + fuzz2110=fuzz2110, + fuzz2111=fuzz2111, + fuzz2112=fuzz2112, + fuzz2113=fuzz2113, + fuzz2114=fuzz2114, + fuzz2115=fuzz2115, + fuzz2116=fuzz2116, + fuzz2117=fuzz2117, + fuzz2118=fuzz2118, + ) + return + self.__attrs_init__() fuzz2101: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py index 7c3995168bc6..0767d45fb017 100644 --- a/rerun_py/tests/unit/test_exceptions.py +++ b/rerun_py/tests/unit/test_exceptions.py @@ -120,7 +120,7 @@ def test_bad_components() -> None: points = rr.Points3D(positions=[1, 2, 3], colors="RED") assert len(warnings) == 1 assert len(points.positions) == 1 - assert len(points.colors) == 0 + assert len(points.colors) == 0 # type: ignore[arg-type] rr.set_strict_mode(True) with pytest.raises(ValueError): From 2ae155294cc0cd5b1404e7421f2dbbe3ae5603ea Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 04:39:40 +0200 Subject: [PATCH 11/27] Fix rebase --- rerun_py/rerun_sdk/rerun/error_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index 5db47a214b49..5cfea1446910 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -94,7 +94,7 @@ def _send_warning( # TODO(jleibs): Context/stack should be its own component. context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 1) - log("rerun", TextLog(body=f"{message}\n{context_descriptor}", level="WARN"), recording=recording) + log("rerun", TextLog(text=f"{message}\n{context_descriptor}", level="WARN"), recording=recording) _rerun_exception_ctx.sending_warning = False else: warnings.warn( From b31febebc7b03738e29b5147753801c79b9605d7 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 04:39:55 +0200 Subject: [PATCH 12/27] Use classname for context --- crates/re_types_builder/src/codegen/python.rs | 2 +- rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/asset3d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/depth_image.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/image.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/points2d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/points3d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/text_document.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/text_log.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/transform3d.py | 2 +- rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py | 2 +- rerun_py/tests/test_types/archetypes/affix_fuzzer1.py | 2 +- rerun_py/tests/test_types/archetypes/affix_fuzzer2.py | 2 +- rerun_py/tests/test_types/archetypes/affix_fuzzer3.py | 2 +- rerun_py/tests/test_types/archetypes/affix_fuzzer4.py | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index 2688bc8bd842..7b0cc6f8eefe 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -1660,7 +1660,7 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects // Make sure Archetypes catch and log exceptions as a fallback let forwarding_call = if obj.kind == ObjectKind::Archetype { [ - format!("with catch_and_log_exceptions(\"{}\"):", obj.name), + "with catch_and_log_exceptions(context=self.__class__.__name__):".to_owned(), indent::indent_all_by(4, forwarding_call), indent::indent_all_by(4, "return"), "self.__attrs_init__()".to_owned(), diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index a73110752ab6..39dfcb571ebe 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -129,7 +129,7 @@ def __init__(self: Any, context: components.AnnotationContextLike): """Create a new instance of the AnnotationContext archetype.""" # You can define your own __init__ function as a member of AnnotationContextExt in annotation_context_ext.py - with catch_and_log_exceptions("AnnotationContext"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(context=context) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index 94971c2726c9..7e9ec688a46f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -104,7 +104,7 @@ def __init__( """ # You can define your own __init__ function as a member of Asset3DExt in asset3d_ext.py - with catch_and_log_exceptions("Asset3D"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(blob=blob, media_type=media_type, transform=transform) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 902022351bff..3fdf9adc58c7 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -46,7 +46,7 @@ def __init__(self: Any, values: datatypes.TensorDataLike): """ # You can define your own __init__ function as a member of BarChartExt in bar_chart_ext.py - with catch_and_log_exceptions("BarChart"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(values=values) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 29788b7b77cf..9586614f4d00 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -113,7 +113,7 @@ def __init__( """ # You can define your own __init__ function as a member of DepthImageExt in depth_image_ext.py - with catch_and_log_exceptions("DepthImage"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, meter=meter, draw_order=draw_order) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index 3c683d81166a..dc8788449dad 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -47,7 +47,7 @@ def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): """Create a new instance of the DisconnectedSpace archetype.""" # You can define your own __init__ function as a member of DisconnectedSpaceExt in disconnected_space_ext.py - with catch_and_log_exceptions("DisconnectedSpace"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(disconnected_space=disconnected_space) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index 89fdebce9671..013765583a53 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -69,7 +69,7 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component """ # You can define your own __init__ function as a member of ImageExt in image_ext.py - with catch_and_log_exceptions("Image"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, draw_order=draw_order) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index 8bcc0445a27f..bcc5c5c6c3ba 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -132,7 +132,7 @@ def __init__( """ # You can define your own __init__ function as a member of LineStrips2DExt in line_strips2d_ext.py - with catch_and_log_exceptions("LineStrips2D"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( strips=strips, radii=radii, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index 2a6e33f5560d..ae82a8f6bd6e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -154,7 +154,7 @@ def __init__( """ # You can define your own __init__ function as a member of LineStrips3DExt in line_strips3d_ext.py - with catch_and_log_exceptions("LineStrips3D"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( strips=strips, radii=radii, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index 5e37201ed15d..03e9dd9f73db 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -115,7 +115,7 @@ def __init__( """ # You can define your own __init__ function as a member of Points2DExt in points2d_ext.py - with catch_and_log_exceptions("Points2D"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( positions=positions, radii=radii, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 24f1702b0544..02ef4c89690a 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -105,7 +105,7 @@ def __init__( """ # You can define your own __init__ function as a member of Points3DExt in points3d_ext.py - with catch_and_log_exceptions("Points3D"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( positions=positions, radii=radii, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index f89f64dff407..a4c1939012c2 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -70,7 +70,7 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component """ # You can define your own __init__ function as a member of SegmentationImageExt in segmentation_image_ext.py - with catch_and_log_exceptions("SegmentationImage"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, draw_order=draw_order) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index 8d27a8ba1366..bffe0007decb 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -39,7 +39,7 @@ def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8L """ # You can define your own __init__ function as a member of TextDocumentExt in text_document_ext.py - with catch_and_log_exceptions("TextDocument"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(text=text, media_type=media_type) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index 4c3e2b92046a..c0f1a592ffa2 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -30,7 +30,7 @@ def __init__( """Create a new instance of the TextLog archetype.""" # You can define your own __init__ function as a member of TextLogExt in text_log_ext.py - with catch_and_log_exceptions("TextLog"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(text=text, level=level, color=color) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index 718a2d9897ac..478cdc261e87 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -118,7 +118,7 @@ def __init__( """ # You can define your own __init__ function as a member of TimeSeriesScalarExt in time_series_scalar_ext.py - with catch_and_log_exceptions("TimeSeriesScalar"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(scalar=scalar, radius=radius, color=color, label=label, scattered=scattered) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index 1335edaca44e..6f63fb7db02b 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -65,7 +65,7 @@ def __init__(self: Any, transform: datatypes.Transform3DLike): """ # You can define your own __init__ function as a member of Transform3DExt in transform3d_ext.py - with catch_and_log_exceptions("Transform3D"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(transform=transform) return self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index 2396dbca38df..6900702b9713 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -52,7 +52,7 @@ def __init__(self: Any, xyz: components.ViewCoordinatesLike): """Create a new instance of the ViewCoordinates archetype.""" # You can define your own __init__ function as a member of ViewCoordinatesExt in view_coordinates_ext.py - with catch_and_log_exceptions("ViewCoordinates"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(xyz=xyz) return self.__attrs_init__() diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index 43408bef7268..b8f6d497c61b 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -45,7 +45,7 @@ def __init__( """Create a new instance of the AffixFuzzer1 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer1Ext in affix_fuzzer1_ext.py - with catch_and_log_exceptions("AffixFuzzer1"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( fuzz1001=fuzz1001, fuzz1002=fuzz1002, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 506dd343250e..9a4b1328af6f 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -42,7 +42,7 @@ def __init__( """Create a new instance of the AffixFuzzer2 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer2Ext in affix_fuzzer2_ext.py - with catch_and_log_exceptions("AffixFuzzer2"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( fuzz1101=fuzz1101, fuzz1102=fuzz1102, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index 09b9b6ae963f..7df0ab8f1a64 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -43,7 +43,7 @@ def __init__( """Create a new instance of the AffixFuzzer3 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer3Ext in affix_fuzzer3_ext.py - with catch_and_log_exceptions("AffixFuzzer3"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( fuzz2001=fuzz2001, fuzz2002=fuzz2002, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index b92903171f40..63dc545f1a1b 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -43,7 +43,7 @@ def __init__( """Create a new instance of the AffixFuzzer4 archetype.""" # You can define your own __init__ function as a member of AffixFuzzer4Ext in affix_fuzzer4_ext.py - with catch_and_log_exceptions("AffixFuzzer4"): + with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__( fuzz2101=fuzz2101, fuzz2102=fuzz2102, From da2068fd28260f41960c565b576b46f9c81d9e4f Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 05:04:02 +0200 Subject: [PATCH 13/27] Initialize with nones if init fails --- crates/re_types_builder/src/codegen/python.rs | 7 +++++- .../rerun/archetypes/annotation_context.py | 4 +++- .../rerun_sdk/rerun/archetypes/asset3d.py | 6 ++++- .../rerun_sdk/rerun/archetypes/bar_chart.py | 4 +++- .../rerun_sdk/rerun/archetypes/depth_image.py | 6 ++++- .../rerun/archetypes/disconnected_space.py | 4 +++- rerun_py/rerun_sdk/rerun/archetypes/image.py | 5 +++- .../rerun/archetypes/line_strips2d.py | 10 +++++++- .../rerun/archetypes/line_strips3d.py | 9 ++++++- .../rerun_sdk/rerun/archetypes/points2d.py | 11 ++++++++- .../rerun_sdk/rerun/archetypes/points3d.py | 10 +++++++- .../rerun/archetypes/segmentation_image.py | 5 +++- .../rerun/archetypes/text_document.py | 5 +++- .../rerun_sdk/rerun/archetypes/text_log.py | 6 ++++- .../rerun/archetypes/time_series_scalar.py | 8 ++++++- .../rerun_sdk/rerun/archetypes/transform3d.py | 4 +++- .../rerun/archetypes/view_coordinates.py | 4 +++- .../test_types/archetypes/affix_fuzzer1.py | 24 ++++++++++++++++++- .../test_types/archetypes/affix_fuzzer2.py | 21 +++++++++++++++- .../test_types/archetypes/affix_fuzzer3.py | 21 +++++++++++++++- .../test_types/archetypes/affix_fuzzer4.py | 21 +++++++++++++++- 21 files changed, 174 insertions(+), 21 deletions(-) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index 7b0cc6f8eefe..f81afb871d9a 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -1659,11 +1659,16 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects // Make sure Archetypes catch and log exceptions as a fallback let forwarding_call = if obj.kind == ObjectKind::Archetype { + let required_param_nones = obj + .fields + .iter() + .map(|field| format!("{} = None,", field.name)) + .join("\n"); [ "with catch_and_log_exceptions(context=self.__class__.__name__):".to_owned(), indent::indent_all_by(4, forwarding_call), indent::indent_all_by(4, "return"), - "self.__attrs_init__()".to_owned(), + format!("self.__attrs_init__({required_param_nones})"), ] .join("\n") } else { diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index 39dfcb571ebe..bb12d9275e67 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -132,7 +132,9 @@ def __init__(self: Any, context: components.AnnotationContextLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(context=context) return - self.__attrs_init__() + self.__attrs_init__( + context=None, + ) context: components.AnnotationContextBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index 7e9ec688a46f..befad5c5ad39 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -107,7 +107,11 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(blob=blob, media_type=media_type, transform=transform) return - self.__attrs_init__() + self.__attrs_init__( + blob=None, + media_type=None, + transform=None, + ) blob: components.BlobBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 3fdf9adc58c7..39090fb3422b 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -49,7 +49,9 @@ def __init__(self: Any, values: datatypes.TensorDataLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(values=values) return - self.__attrs_init__() + self.__attrs_init__( + values=None, + ) values: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 9586614f4d00..cb4a5bcae788 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -116,7 +116,11 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, meter=meter, draw_order=draw_order) return - self.__attrs_init__() + self.__attrs_init__( + data=None, + meter=None, + draw_order=None, + ) data: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index dc8788449dad..a4e2dcb33c50 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -50,7 +50,9 @@ def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(disconnected_space=disconnected_space) return - self.__attrs_init__() + self.__attrs_init__( + disconnected_space=None, + ) disconnected_space: components.DisconnectedSpaceBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index 013765583a53..df10436b6c57 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -72,7 +72,10 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, draw_order=draw_order) return - self.__attrs_init__() + self.__attrs_init__( + data=None, + draw_order=None, + ) data: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index bcc5c5c6c3ba..95afbaf20c28 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -143,7 +143,15 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__() + self.__attrs_init__( + strips=None, + radii=None, + colors=None, + labels=None, + draw_order=None, + class_ids=None, + instance_keys=None, + ) strips: components.LineStrip2DBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index ae82a8f6bd6e..3a94c0db21b1 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -164,7 +164,14 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__() + self.__attrs_init__( + strips=None, + radii=None, + colors=None, + labels=None, + class_ids=None, + instance_keys=None, + ) strips: components.LineStrip3DBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index 03e9dd9f73db..bc33afbe5f56 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -127,7 +127,16 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__() + self.__attrs_init__( + positions=None, + radii=None, + colors=None, + labels=None, + draw_order=None, + class_ids=None, + keypoint_ids=None, + instance_keys=None, + ) positions: components.Position2DBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 02ef4c89690a..cd3ab62b7669 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -116,7 +116,15 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__() + self.__attrs_init__( + positions=None, + radii=None, + colors=None, + labels=None, + class_ids=None, + keypoint_ids=None, + instance_keys=None, + ) positions: components.Position3DBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index a4c1939012c2..d83132c95c5e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -73,7 +73,10 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, draw_order=draw_order) return - self.__attrs_init__() + self.__attrs_init__( + data=None, + draw_order=None, + ) data: components.TensorDataBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index bffe0007decb..4b0fa40594fc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -42,7 +42,10 @@ def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8L with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(text=text, media_type=media_type) return - self.__attrs_init__() + self.__attrs_init__( + text=None, + media_type=None, + ) text: components.TextBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index c0f1a592ffa2..b90bd9f27934 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -33,7 +33,11 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(text=text, level=level, color=color) return - self.__attrs_init__() + self.__attrs_init__( + text=None, + level=None, + color=None, + ) text: components.TextBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index 478cdc261e87..fa3856e9f2eb 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -121,7 +121,13 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(scalar=scalar, radius=radius, color=color, label=label, scattered=scattered) return - self.__attrs_init__() + self.__attrs_init__( + scalar=None, + radius=None, + color=None, + label=None, + scattered=None, + ) scalar: components.ScalarBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index 6f63fb7db02b..8eff10cb079e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -68,7 +68,9 @@ def __init__(self: Any, transform: datatypes.Transform3DLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(transform=transform) return - self.__attrs_init__() + self.__attrs_init__( + transform=None, + ) transform: components.Transform3DBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index 6900702b9713..697c65bd76c9 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -55,7 +55,9 @@ def __init__(self: Any, xyz: components.ViewCoordinatesLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(xyz=xyz) return - self.__attrs_init__() + self.__attrs_init__( + xyz=None, + ) xyz: components.ViewCoordinatesBatch = field( metadata={"component": "required"}, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index b8f6d497c61b..3a96e008a50b 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -70,7 +70,29 @@ def __init__( fuzz1021=fuzz1021, ) return - self.__attrs_init__() + self.__attrs_init__( + fuzz1001=None, + fuzz1002=None, + fuzz1003=None, + fuzz1004=None, + fuzz1005=None, + fuzz1006=None, + fuzz1007=None, + fuzz1008=None, + fuzz1009=None, + fuzz1010=None, + fuzz1011=None, + fuzz1012=None, + fuzz1013=None, + fuzz1014=None, + fuzz1015=None, + fuzz1016=None, + fuzz1017=None, + fuzz1018=None, + fuzz1019=None, + fuzz1020=None, + fuzz1021=None, + ) fuzz1001: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 9a4b1328af6f..9ffc75d6b698 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -64,7 +64,26 @@ def __init__( fuzz1118=fuzz1118, ) return - self.__attrs_init__() + self.__attrs_init__( + fuzz1101=None, + fuzz1102=None, + fuzz1103=None, + fuzz1104=None, + fuzz1105=None, + fuzz1106=None, + fuzz1107=None, + fuzz1108=None, + fuzz1109=None, + fuzz1110=None, + fuzz1111=None, + fuzz1112=None, + fuzz1113=None, + fuzz1114=None, + fuzz1115=None, + fuzz1116=None, + fuzz1117=None, + fuzz1118=None, + ) fuzz1101: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index 7df0ab8f1a64..6ef470b67cc6 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -65,7 +65,26 @@ def __init__( fuzz2018=fuzz2018, ) return - self.__attrs_init__() + self.__attrs_init__( + fuzz2001=None, + fuzz2002=None, + fuzz2003=None, + fuzz2004=None, + fuzz2005=None, + fuzz2006=None, + fuzz2007=None, + fuzz2008=None, + fuzz2009=None, + fuzz2010=None, + fuzz2011=None, + fuzz2012=None, + fuzz2013=None, + fuzz2014=None, + fuzz2015=None, + fuzz2016=None, + fuzz2017=None, + fuzz2018=None, + ) fuzz2001: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index 63dc545f1a1b..aae299fe54ef 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -65,7 +65,26 @@ def __init__( fuzz2118=fuzz2118, ) return - self.__attrs_init__() + self.__attrs_init__( + fuzz2101=None, + fuzz2102=None, + fuzz2103=None, + fuzz2104=None, + fuzz2105=None, + fuzz2106=None, + fuzz2107=None, + fuzz2108=None, + fuzz2109=None, + fuzz2110=None, + fuzz2111=None, + fuzz2112=None, + fuzz2113=None, + fuzz2114=None, + fuzz2115=None, + fuzz2116=None, + fuzz2117=None, + fuzz2118=None, + ) fuzz2101: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, From 982a15fff7010dd1b27d473c85b9b6e76c66702f Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 05:19:16 +0200 Subject: [PATCH 14/27] Codegen a _clear helper --- crates/re_types_builder/src/codegen/python.rs | 29 +++++++++++++++++++ .../rerun/archetypes/annotation_context.py | 7 +++++ .../rerun_sdk/rerun/archetypes/arrows3d.py | 13 +++++++++ .../rerun_sdk/rerun/archetypes/asset3d.py | 9 ++++++ .../rerun_sdk/rerun/archetypes/bar_chart.py | 7 +++++ .../rerun_sdk/rerun/archetypes/boxes2d.py | 14 +++++++++ .../rerun_sdk/rerun/archetypes/boxes3d.py | 14 +++++++++ rerun_py/rerun_sdk/rerun/archetypes/clear.py | 7 +++++ .../rerun_sdk/rerun/archetypes/depth_image.py | 9 ++++++ .../rerun/archetypes/disconnected_space.py | 7 +++++ rerun_py/rerun_sdk/rerun/archetypes/image.py | 8 +++++ .../rerun/archetypes/line_strips2d.py | 13 +++++++++ .../rerun/archetypes/line_strips3d.py | 12 ++++++++ rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py | 13 +++++++++ .../rerun_sdk/rerun/archetypes/pinhole.py | 9 ++++++ .../rerun_sdk/rerun/archetypes/points2d.py | 14 +++++++++ .../rerun_sdk/rerun/archetypes/points3d.py | 13 +++++++++ .../rerun/archetypes/segmentation_image.py | 8 +++++ rerun_py/rerun_sdk/rerun/archetypes/tensor.py | 7 +++++ .../rerun/archetypes/text_document.py | 8 +++++ .../rerun_sdk/rerun/archetypes/text_log.py | 9 ++++++ .../rerun/archetypes/time_series_scalar.py | 11 +++++++ .../rerun_sdk/rerun/archetypes/transform3d.py | 7 +++++ .../rerun/archetypes/view_coordinates.py | 7 +++++ .../test_types/archetypes/affix_fuzzer1.py | 27 +++++++++++++++++ .../test_types/archetypes/affix_fuzzer2.py | 24 +++++++++++++++ .../test_types/archetypes/affix_fuzzer3.py | 24 +++++++++++++++ .../test_types/archetypes/affix_fuzzer4.py | 24 +++++++++++++++ 28 files changed, 354 insertions(+) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index f81afb871d9a..4adcbab645bf 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -619,6 +619,10 @@ fn code_for_struct( code.push_text(quote_init_method(obj, ext_class, objects), 2, 4); } + if obj.kind == ObjectKind::Archetype { + code.push_text(quote_clear_method(obj), 2, 4); + } + if obj.is_delegating_component() { code.push_text( format!( @@ -1684,6 +1688,31 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects ) } +fn quote_clear_method(obj: &Object) -> String { + let param_nones = obj + .fields + .iter() + .map(|field| format!("{} = None, # type: ignore[arg-type]", field.name)) + .join("\n"); + + let body = [ + r#"""""#.to_owned(), + format!("Produce an empty {}.", obj.name), + r#"""""#.to_owned(), + "return cls(".to_owned(), + param_nones, + ")".to_owned(), + ] + .join("\n"); + + [ + "@classmethod".to_owned(), + format!("def _clear(cls) -> {}:", obj.name), + indent::indent_all_by(4, body), + ] + .join("\n") +} + // --- Arrow registry code generators --- use arrow2::datatypes::{DataType, Field, UnionMode}; diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index bb12d9275e67..a4f3eb4c7519 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -136,6 +136,13 @@ def __init__(self: Any, context: components.AnnotationContextLike): context=None, ) + @classmethod + def _clear(cls) -> AnnotationContext: + """Produce an empty AnnotationContext.""" + return cls( + context=None, # type: ignore[arg-type] + ) + context: components.AnnotationContextBatch = field( metadata={"component": "required"}, converter=components.AnnotationContextBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py index c023bc852b2f..f376807c8196 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py @@ -48,6 +48,19 @@ class Arrows3D(Arrows3DExt, Archetype): # __init__ can be found in arrows3d_ext.py + @classmethod + def _clear(cls) -> Arrows3D: + """Produce an empty Arrows3D.""" + return cls( + vectors=None, # type: ignore[arg-type] + origins=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + vectors: components.Vector3DBatch = field( metadata={"component": "required"}, converter=components.Vector3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index befad5c5ad39..d559ebec82e7 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -113,6 +113,15 @@ def __init__( transform=None, ) + @classmethod + def _clear(cls) -> Asset3D: + """Produce an empty Asset3D.""" + return cls( + blob=None, # type: ignore[arg-type] + media_type=None, # type: ignore[arg-type] + transform=None, # type: ignore[arg-type] + ) + blob: components.BlobBatch = field( metadata={"component": "required"}, converter=components.BlobBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 39090fb3422b..9cf91a547660 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -53,6 +53,13 @@ def __init__(self: Any, values: datatypes.TensorDataLike): values=None, ) + @classmethod + def _clear(cls) -> BarChart: + """Produce an empty BarChart.""" + return cls( + values=None, # type: ignore[arg-type] + ) + values: components.TensorDataBatch = field( metadata={"component": "required"}, converter=BarChartExt.values__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py index 4eccb863b6df..78fc55397f22 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py @@ -36,6 +36,20 @@ class Boxes2D(Boxes2DExt, Archetype): # __init__ can be found in boxes2d_ext.py + @classmethod + def _clear(cls) -> Boxes2D: + """Produce an empty Boxes2D.""" + return cls( + half_sizes=None, # type: ignore[arg-type] + centers=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + draw_order=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + half_sizes: components.HalfSizes2DBatch = field( metadata={"component": "required"}, converter=components.HalfSizes2DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py index e6cc40d811bf..3ea11157e0fa 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py @@ -71,6 +71,20 @@ class Boxes3D(Boxes3DExt, Archetype): # __init__ can be found in boxes3d_ext.py + @classmethod + def _clear(cls) -> Boxes3D: + """Produce an empty Boxes3D.""" + return cls( + half_sizes=None, # type: ignore[arg-type] + centers=None, # type: ignore[arg-type] + rotations=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + half_sizes: components.HalfSizes3DBatch = field( metadata={"component": "required"}, converter=components.HalfSizes3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/clear.py b/rerun_py/rerun_sdk/rerun/archetypes/clear.py index 4a8b79fd28fc..7719fec86a83 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/clear.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/clear.py @@ -63,6 +63,13 @@ class Clear(ClearExt, Archetype): # __init__ can be found in clear_ext.py + @classmethod + def _clear(cls) -> Clear: + """Produce an empty Clear.""" + return cls( + recursive=None, # type: ignore[arg-type] + ) + recursive: components.ClearIsRecursiveBatch = field( metadata={"component": "required"}, converter=components.ClearIsRecursiveBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index cb4a5bcae788..2da5541e23b9 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -122,6 +122,15 @@ def __init__( draw_order=None, ) + @classmethod + def _clear(cls) -> DepthImage: + """Produce an empty DepthImage.""" + return cls( + data=None, # type: ignore[arg-type] + meter=None, # type: ignore[arg-type] + draw_order=None, # type: ignore[arg-type] + ) + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=DepthImageExt.data__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index a4e2dcb33c50..2dfdd9869f9c 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -54,6 +54,13 @@ def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): disconnected_space=None, ) + @classmethod + def _clear(cls) -> DisconnectedSpace: + """Produce an empty DisconnectedSpace.""" + return cls( + disconnected_space=None, # type: ignore[arg-type] + ) + disconnected_space: components.DisconnectedSpaceBatch = field( metadata={"component": "required"}, converter=components.DisconnectedSpaceBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index df10436b6c57..11c8e1dd622f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -77,6 +77,14 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component draw_order=None, ) + @classmethod + def _clear(cls) -> Image: + """Produce an empty Image.""" + return cls( + data=None, # type: ignore[arg-type] + draw_order=None, # type: ignore[arg-type] + ) + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=ImageExt.data__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index 95afbaf20c28..7228bdb91e63 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -153,6 +153,19 @@ def __init__( instance_keys=None, ) + @classmethod + def _clear(cls) -> LineStrips2D: + """Produce an empty LineStrips2D.""" + return cls( + strips=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + draw_order=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + strips: components.LineStrip2DBatch = field( metadata={"component": "required"}, converter=components.LineStrip2DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index 3a94c0db21b1..9b6ceb24fd9c 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -173,6 +173,18 @@ def __init__( instance_keys=None, ) + @classmethod + def _clear(cls) -> LineStrips3D: + """Produce an empty LineStrips3D.""" + return cls( + strips=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + strips: components.LineStrip3DBatch = field( metadata={"component": "required"}, converter=components.LineStrip3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py index e49008bf3178..5c6811f46d58 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py @@ -71,6 +71,19 @@ class Mesh3D(Mesh3DExt, Archetype): # __init__ can be found in mesh3d_ext.py + @classmethod + def _clear(cls) -> Mesh3D: + """Produce an empty Mesh3D.""" + return cls( + vertex_positions=None, # type: ignore[arg-type] + mesh_properties=None, # type: ignore[arg-type] + vertex_normals=None, # type: ignore[arg-type] + vertex_colors=None, # type: ignore[arg-type] + mesh_material=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + vertex_positions: components.Position3DBatch = field( metadata={"component": "required"}, converter=components.Position3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py index 1700e727a9bc..70027729479d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py @@ -43,6 +43,15 @@ class Pinhole(PinholeExt, Archetype): # __init__ can be found in pinhole_ext.py + @classmethod + def _clear(cls) -> Pinhole: + """Produce an empty Pinhole.""" + return cls( + image_from_camera=None, # type: ignore[arg-type] + resolution=None, # type: ignore[arg-type] + camera_xyz=None, # type: ignore[arg-type] + ) + image_from_camera: components.PinholeProjectionBatch = field( metadata={"component": "required"}, converter=components.PinholeProjectionBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index bc33afbe5f56..c8fc8702314f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -138,6 +138,20 @@ def __init__( instance_keys=None, ) + @classmethod + def _clear(cls) -> Points2D: + """Produce an empty Points2D.""" + return cls( + positions=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + draw_order=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + keypoint_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + positions: components.Position2DBatch = field( metadata={"component": "required"}, converter=components.Position2DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index cd3ab62b7669..323d7908f659 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -126,6 +126,19 @@ def __init__( instance_keys=None, ) + @classmethod + def _clear(cls) -> Points3D: + """Produce an empty Points3D.""" + return cls( + positions=None, # type: ignore[arg-type] + radii=None, # type: ignore[arg-type] + colors=None, # type: ignore[arg-type] + labels=None, # type: ignore[arg-type] + class_ids=None, # type: ignore[arg-type] + keypoint_ids=None, # type: ignore[arg-type] + instance_keys=None, # type: ignore[arg-type] + ) + positions: components.Position3DBatch = field( metadata={"component": "required"}, converter=components.Position3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index d83132c95c5e..225d52550be7 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -78,6 +78,14 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component draw_order=None, ) + @classmethod + def _clear(cls) -> SegmentationImage: + """Produce an empty SegmentationImage.""" + return cls( + data=None, # type: ignore[arg-type] + draw_order=None, # type: ignore[arg-type] + ) + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=SegmentationImageExt.data__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/tensor.py b/rerun_py/rerun_sdk/rerun/archetypes/tensor.py index 214fa46abd8f..36770f7c0051 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/tensor.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/tensor.py @@ -70,6 +70,13 @@ class Tensor(TensorExt, Archetype): # __init__ can be found in tensor_ext.py + @classmethod + def _clear(cls) -> Tensor: + """Produce an empty Tensor.""" + return cls( + data=None, # type: ignore[arg-type] + ) + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=components.TensorDataBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index 4b0fa40594fc..4a88c205919b 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -47,6 +47,14 @@ def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8L media_type=None, ) + @classmethod + def _clear(cls) -> TextDocument: + """Produce an empty TextDocument.""" + return cls( + text=None, # type: ignore[arg-type] + media_type=None, # type: ignore[arg-type] + ) + text: components.TextBatch = field( metadata={"component": "required"}, converter=components.TextBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index b90bd9f27934..cfbd7addec53 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -39,6 +39,15 @@ def __init__( color=None, ) + @classmethod + def _clear(cls) -> TextLog: + """Produce an empty TextLog.""" + return cls( + text=None, # type: ignore[arg-type] + level=None, # type: ignore[arg-type] + color=None, # type: ignore[arg-type] + ) + text: components.TextBatch = field( metadata={"component": "required"}, converter=components.TextBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index fa3856e9f2eb..e9ee406c61b2 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -129,6 +129,17 @@ def __init__( scattered=None, ) + @classmethod + def _clear(cls) -> TimeSeriesScalar: + """Produce an empty TimeSeriesScalar.""" + return cls( + scalar=None, # type: ignore[arg-type] + radius=None, # type: ignore[arg-type] + color=None, # type: ignore[arg-type] + label=None, # type: ignore[arg-type] + scattered=None, # type: ignore[arg-type] + ) + scalar: components.ScalarBatch = field( metadata={"component": "required"}, converter=components.ScalarBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index 8eff10cb079e..6c4784571a4a 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -72,6 +72,13 @@ def __init__(self: Any, transform: datatypes.Transform3DLike): transform=None, ) + @classmethod + def _clear(cls) -> Transform3D: + """Produce an empty Transform3D.""" + return cls( + transform=None, # type: ignore[arg-type] + ) + transform: components.Transform3DBatch = field( metadata={"component": "required"}, converter=components.Transform3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index 697c65bd76c9..dee0756308ba 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -59,6 +59,13 @@ def __init__(self: Any, xyz: components.ViewCoordinatesLike): xyz=None, ) + @classmethod + def _clear(cls) -> ViewCoordinates: + """Produce an empty ViewCoordinates.""" + return cls( + xyz=None, # type: ignore[arg-type] + ) + xyz: components.ViewCoordinatesBatch = field( metadata={"component": "required"}, converter=components.ViewCoordinatesBatch._required, # type: ignore[misc] diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index 3a96e008a50b..71bb6bc8858e 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -94,6 +94,33 @@ def __init__( fuzz1021=None, ) + @classmethod + def _clear(cls) -> AffixFuzzer1: + """Produce an empty AffixFuzzer1.""" + return cls( + fuzz1001=None, # type: ignore[arg-type] + fuzz1002=None, # type: ignore[arg-type] + fuzz1003=None, # type: ignore[arg-type] + fuzz1004=None, # type: ignore[arg-type] + fuzz1005=None, # type: ignore[arg-type] + fuzz1006=None, # type: ignore[arg-type] + fuzz1007=None, # type: ignore[arg-type] + fuzz1008=None, # type: ignore[arg-type] + fuzz1009=None, # type: ignore[arg-type] + fuzz1010=None, # type: ignore[arg-type] + fuzz1011=None, # type: ignore[arg-type] + fuzz1012=None, # type: ignore[arg-type] + fuzz1013=None, # type: ignore[arg-type] + fuzz1014=None, # type: ignore[arg-type] + fuzz1015=None, # type: ignore[arg-type] + fuzz1016=None, # type: ignore[arg-type] + fuzz1017=None, # type: ignore[arg-type] + fuzz1018=None, # type: ignore[arg-type] + fuzz1019=None, # type: ignore[arg-type] + fuzz1020=None, # type: ignore[arg-type] + fuzz1021=None, # type: ignore[arg-type] + ) + fuzz1001: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, converter=components.AffixFuzzer1Batch._required, # type: ignore[misc] diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 9ffc75d6b698..0e59f5f4995a 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -85,6 +85,30 @@ def __init__( fuzz1118=None, ) + @classmethod + def _clear(cls) -> AffixFuzzer2: + """Produce an empty AffixFuzzer2.""" + return cls( + fuzz1101=None, # type: ignore[arg-type] + fuzz1102=None, # type: ignore[arg-type] + fuzz1103=None, # type: ignore[arg-type] + fuzz1104=None, # type: ignore[arg-type] + fuzz1105=None, # type: ignore[arg-type] + fuzz1106=None, # type: ignore[arg-type] + fuzz1107=None, # type: ignore[arg-type] + fuzz1108=None, # type: ignore[arg-type] + fuzz1109=None, # type: ignore[arg-type] + fuzz1110=None, # type: ignore[arg-type] + fuzz1111=None, # type: ignore[arg-type] + fuzz1112=None, # type: ignore[arg-type] + fuzz1113=None, # type: ignore[arg-type] + fuzz1114=None, # type: ignore[arg-type] + fuzz1115=None, # type: ignore[arg-type] + fuzz1116=None, # type: ignore[arg-type] + fuzz1117=None, # type: ignore[arg-type] + fuzz1118=None, # type: ignore[arg-type] + ) + fuzz1101: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, converter=components.AffixFuzzer1Batch._required, # type: ignore[misc] diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index 6ef470b67cc6..b52917060214 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -86,6 +86,30 @@ def __init__( fuzz2018=None, ) + @classmethod + def _clear(cls) -> AffixFuzzer3: + """Produce an empty AffixFuzzer3.""" + return cls( + fuzz2001=None, # type: ignore[arg-type] + fuzz2002=None, # type: ignore[arg-type] + fuzz2003=None, # type: ignore[arg-type] + fuzz2004=None, # type: ignore[arg-type] + fuzz2005=None, # type: ignore[arg-type] + fuzz2006=None, # type: ignore[arg-type] + fuzz2007=None, # type: ignore[arg-type] + fuzz2008=None, # type: ignore[arg-type] + fuzz2009=None, # type: ignore[arg-type] + fuzz2010=None, # type: ignore[arg-type] + fuzz2011=None, # type: ignore[arg-type] + fuzz2012=None, # type: ignore[arg-type] + fuzz2013=None, # type: ignore[arg-type] + fuzz2014=None, # type: ignore[arg-type] + fuzz2015=None, # type: ignore[arg-type] + fuzz2016=None, # type: ignore[arg-type] + fuzz2017=None, # type: ignore[arg-type] + fuzz2018=None, # type: ignore[arg-type] + ) + fuzz2001: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, default=None, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index aae299fe54ef..5ac53f61b5fe 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -86,6 +86,30 @@ def __init__( fuzz2118=None, ) + @classmethod + def _clear(cls) -> AffixFuzzer4: + """Produce an empty AffixFuzzer4.""" + return cls( + fuzz2101=None, # type: ignore[arg-type] + fuzz2102=None, # type: ignore[arg-type] + fuzz2103=None, # type: ignore[arg-type] + fuzz2104=None, # type: ignore[arg-type] + fuzz2105=None, # type: ignore[arg-type] + fuzz2106=None, # type: ignore[arg-type] + fuzz2107=None, # type: ignore[arg-type] + fuzz2108=None, # type: ignore[arg-type] + fuzz2109=None, # type: ignore[arg-type] + fuzz2110=None, # type: ignore[arg-type] + fuzz2111=None, # type: ignore[arg-type] + fuzz2112=None, # type: ignore[arg-type] + fuzz2113=None, # type: ignore[arg-type] + fuzz2114=None, # type: ignore[arg-type] + fuzz2115=None, # type: ignore[arg-type] + fuzz2116=None, # type: ignore[arg-type] + fuzz2117=None, # type: ignore[arg-type] + fuzz2118=None, # type: ignore[arg-type] + ) + fuzz2101: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, default=None, From ab56d029e2e9f283fd3e3813b325126dfcaf75c7 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 05:35:58 +0200 Subject: [PATCH 15/27] Handle exceptions in archetype extensions --- .../rerun/archetypes/arrows3d_ext.py | 22 +++-- .../rerun_sdk/rerun/archetypes/asset3d_ext.py | 12 ++- .../rerun/archetypes/bar_chart_ext.py | 3 +- .../rerun_sdk/rerun/archetypes/boxes2d_ext.py | 70 +++++++------ .../rerun_sdk/rerun/archetypes/boxes3d_ext.py | 62 +++++++----- .../rerun/archetypes/depth_image_ext.py | 4 +- .../rerun_sdk/rerun/archetypes/image_ext.py | 4 +- .../rerun_sdk/rerun/archetypes/mesh3d_ext.py | 37 ++++--- .../rerun_sdk/rerun/archetypes/pinhole_ext.py | 99 ++++++++++--------- .../archetypes/segmentation_image_ext.py | 4 +- 10 files changed, 184 insertions(+), 133 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py index 105ac60404ea..3178d7f80a19 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py @@ -3,6 +3,7 @@ from typing import Any from .. import components, datatypes +from ..error_utils import catch_and_log_exceptions class Arrows3DExt: @@ -47,12 +48,15 @@ def __init__( # Custom constructor to remove positional arguments and force use of keyword arguments # while still making vectors required. - self.__attrs_init__( - vectors=vectors, - origins=origins, - radii=radii, - colors=colors, - labels=labels, - class_ids=class_ids, - instance_keys=instance_keys, - ) + with catch_and_log_exceptions(context=self.__class__.__name__): + self.__attrs_init__( + vectors=vectors, + origins=origins, + radii=radii, + colors=colors, + labels=labels, + class_ids=class_ids, + instance_keys=instance_keys, + ) + return + self.__attrs_init__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py index c31ea02a2427..94caba355b77 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py @@ -2,6 +2,8 @@ from typing import TYPE_CHECKING +from ..error_utils import catch_and_log_exceptions + if TYPE_CHECKING: from ..components import MediaType from . import Asset3D @@ -36,8 +38,10 @@ def from_file(path: str) -> Asset3D: """ from . import Asset3D - with open(path, "rb") as file: - return Asset3D.from_bytes(file.read(), guess_media_type(path)) + with catch_and_log_exceptions(context="Asset3D.from_file"): + with open(path, "rb") as file: + return Asset3D.from_bytes(file.read(), guess_media_type(path)) + return Asset3D._clear() @staticmethod def from_bytes(blob: bytes, media_type: MediaType | None) -> Asset3D: @@ -50,4 +54,6 @@ def from_bytes(blob: bytes, media_type: MediaType | None) -> Asset3D: from . import Asset3D # TODO(cmc): we could try and guess using magic bytes here, like rust does. - return Asset3D(blob=blob, media_type=media_type) + with catch_and_log_exceptions(context="Asset3D.from_file"): + return Asset3D(blob=blob, media_type=media_type) + return Asset3D._clear() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart_ext.py index 06e1f0d80d41..380e85401c56 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart_ext.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING -from rerun.error_utils import _send_warning +from ..error_utils import _send_warning, catch_and_log_exceptions if TYPE_CHECKING: from ..components import TensorDataBatch @@ -11,6 +11,7 @@ class BarChartExt: @staticmethod + @catch_and_log_exceptions("BarChart converter") def values__field_converter_override(data: TensorDataArrayLike) -> TensorDataBatch: from ..components import TensorDataBatch diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py index 53449a4c1c19..892b01be950a 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py @@ -4,9 +4,8 @@ import numpy as np -from rerun.error_utils import _send_warning - from .. import components, datatypes +from ..error_utils import _send_warning, catch_and_log_exceptions class Boxes2DExt: @@ -58,33 +57,46 @@ def __init__( Unique identifiers for each individual boxes in the batch. """ - if sizes is not None: - if half_sizes is not None: - _send_warning("Cannot specify both `sizes` and `half_sizes` at the same time.", 1) - - sizes = np.asarray(sizes, dtype=np.float32) - half_sizes = sizes / 2.0 - - if mins is not None: - if centers is not None: - _send_warning("Cannot specify both `mins` and `centers` at the same time.", 1) - - # already converted `sizes` to `half_sizes` - if half_sizes is None: - _send_warning("Cannot specify `mins` without `sizes` or `half_sizes`.", 1) - half_sizes = np.asarray([1, 1], dtype=np.float32) - - mins = np.asarray(mins, dtype=np.float32) - half_sizes = np.asarray(half_sizes, dtype=np.float32) - centers = mins + half_sizes + with catch_and_log_exceptions(context=self.__class__.__name__): + if sizes is not None: + if half_sizes is not None: + _send_warning("Cannot specify both `sizes` and `half_sizes` at the same time.", 1) + + sizes = np.asarray(sizes, dtype=np.float32) + half_sizes = sizes / 2.0 + + if mins is not None: + if centers is not None: + _send_warning("Cannot specify both `mins` and `centers` at the same time.", 1) + + # already converted `sizes` to `half_sizes` + if half_sizes is None: + _send_warning("Cannot specify `mins` without `sizes` or `half_sizes`.", 1) + half_sizes = np.asarray([1, 1], dtype=np.float32) + + mins = np.asarray(mins, dtype=np.float32) + half_sizes = np.asarray(half_sizes, dtype=np.float32) + centers = mins + half_sizes + + self.__attrs_init__( + half_sizes=half_sizes, + centers=centers, + radii=radii, + colors=colors, + labels=labels, + draw_order=draw_order, + class_ids=class_ids, + instance_keys=instance_keys, + ) + return self.__attrs_init__( - half_sizes=half_sizes, - centers=centers, - radii=radii, - colors=colors, - labels=labels, - draw_order=draw_order, - class_ids=class_ids, - instance_keys=instance_keys, + half_sizes=None, + centers=None, + radii=None, + colors=None, + labels=None, + draw_order=None, + class_ids=None, + instance_keys=None, ) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py index 90245c2625d4..54b156efea4c 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py @@ -4,9 +4,8 @@ import numpy as np -from rerun.error_utils import _send_warning - from .. import components, datatypes +from ..error_utils import _send_warning, catch_and_log_exceptions class Boxes3DExt: @@ -55,33 +54,46 @@ def __init__( Unique identifiers for each individual boxes in the batch. """ - if sizes is not None: - if half_sizes is not None: - _send_warning("Cannot specify both `sizes` and `half_sizes` at the same time.", 1) + with catch_and_log_exceptions(context=self.__class__.__name__): + if sizes is not None: + if half_sizes is not None: + _send_warning("Cannot specify both `sizes` and `half_sizes` at the same time.", 1) + + sizes = np.asarray(sizes, dtype=np.float32) + half_sizes = sizes / 2.0 - sizes = np.asarray(sizes, dtype=np.float32) - half_sizes = sizes / 2.0 + if mins is not None: + if centers is not None: + _send_warning("Cannot specify both `mins` and `centers` at the same time.", 1) - if mins is not None: - if centers is not None: - _send_warning("Cannot specify both `mins` and `centers` at the same time.", 1) + # already converted `sizes` to `half_sizes` + if half_sizes is None: + _send_warning("Cannot specify `mins` without `sizes` or `half_sizes`.", 1) + half_sizes = np.asarray([1, 1, 1], dtype=np.float32) - # already converted `sizes` to `half_sizes` - if half_sizes is None: - _send_warning("Cannot specify `mins` without `sizes` or `half_sizes`.", 1) - half_sizes = np.asarray([1, 1, 1], dtype=np.float32) + mins = np.asarray(mins, dtype=np.float32) + half_sizes = np.asarray(half_sizes, dtype=np.float32) + centers = mins + half_sizes - mins = np.asarray(mins, dtype=np.float32) - half_sizes = np.asarray(half_sizes, dtype=np.float32) - centers = mins + half_sizes + self.__attrs_init__( + half_sizes=half_sizes, + centers=centers, + rotations=rotations, + colors=colors, + radii=radii, + labels=labels, + class_ids=class_ids, + instance_keys=instance_keys, + ) + return self.__attrs_init__( - half_sizes=half_sizes, - centers=centers, - rotations=rotations, - colors=colors, - radii=radii, - labels=labels, - class_ids=class_ids, - instance_keys=instance_keys, + half_sizes=None, + centers=None, + rotations=None, + colors=None, + radii=None, + labels=None, + class_ids=None, + instance_keys=None, ) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image_ext.py index 2be9139b072c..badf7dfa5267 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image_ext.py @@ -5,9 +5,8 @@ import numpy as np import pyarrow as pa -from rerun.error_utils import _send_warning - from .._validators import find_non_empty_dim_indices +from ..error_utils import _send_warning, catch_and_log_exceptions if TYPE_CHECKING: from ..components import TensorDataBatch @@ -16,6 +15,7 @@ class DepthImageExt: @staticmethod + @catch_and_log_exceptions("DepthImage converter") def data__field_converter_override(data: TensorDataArrayLike) -> TensorDataBatch: from ..components import TensorDataBatch from ..datatypes import TensorDataType, TensorDimensionType diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/image_ext.py index 14c932cec895..eb9f59e61498 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image_ext.py @@ -5,9 +5,8 @@ import numpy as np import pyarrow as pa -from rerun.error_utils import _send_warning - from .._validators import find_non_empty_dim_indices +from ..error_utils import _send_warning, catch_and_log_exceptions if TYPE_CHECKING: from ..components import TensorDataBatch @@ -16,6 +15,7 @@ class ImageExt: @staticmethod + @catch_and_log_exceptions("Image converter") def data__field_converter_override(data: TensorDataArrayLike) -> TensorDataBatch: from ..components import TensorDataBatch from ..datatypes import TensorDataType, TensorDimensionType diff --git a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py index b202db443213..bf77d804bb85 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py @@ -5,6 +5,7 @@ import numpy.typing as npt from .. import components, datatypes +from ..error_utils import catch_and_log_exceptions class Mesh3DExt: @@ -48,18 +49,30 @@ def __init__( instance_keys: Unique identifiers for each individual vertex in the mesh. """ - if indices is not None: - if mesh_properties is not None: - raise ValueError("indices and mesh_properties are mutually exclusive") - mesh_properties = datatypes.MeshProperties(indices=indices) + with catch_and_log_exceptions(context=self.__class__.__name__): + if indices is not None: + if mesh_properties is not None: + raise ValueError("indices and mesh_properties are mutually exclusive") + mesh_properties = datatypes.MeshProperties(indices=indices) + + # You can define your own __init__ function as a member of Mesh3DExt in mesh3d_ext.py + self.__attrs_init__( + vertex_positions=vertex_positions, + mesh_properties=mesh_properties, + vertex_normals=vertex_normals, + vertex_colors=vertex_colors, + mesh_material=mesh_material, + class_ids=class_ids, + instance_keys=instance_keys, + ) + return - # You can define your own __init__ function as a member of Mesh3DExt in mesh3d_ext.py self.__attrs_init__( - vertex_positions=vertex_positions, - mesh_properties=mesh_properties, - vertex_normals=vertex_normals, - vertex_colors=vertex_colors, - mesh_material=mesh_material, - class_ids=class_ids, - instance_keys=instance_keys, + vertex_positions=None, + mesh_properties=None, + vertex_normals=None, + vertex_colors=None, + mesh_material=None, + class_ids=None, + instance_keys=None, ) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py index 8ac1b8b1593d..0490f4e100cd 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py @@ -4,11 +4,10 @@ import numpy.typing as npt -from rerun.error_utils import _send_warning - from ..components import ViewCoordinatesLike from ..datatypes.mat3x3 import Mat3x3Like from ..datatypes.vec2d import Vec2D, Vec2DLike +from ..error_utils import _send_warning, catch_and_log_exceptions class PinholeExt: @@ -79,51 +78,55 @@ def __init__( Height of the image in pixels. """ - if resolution is None and width is not None and height is not None: - resolution = [width, height] - elif resolution is not None and (width is not None or height is not None): - _send_warning("Can't set both resolution and width/height", 1) - - # TODO(andreas): Use a union type for the Pinhole component instead ~Zof converting to a matrix here - if image_from_camera is None: - # Resolution is needed for various fallbacks/error cases below. - if resolution is None: - resolution = [1.0, 1.0] - resolution = Vec2D(resolution) - width = cast(float, resolution.xy[0]) - height = cast(float, resolution.xy[1]) - - if focal_length is None: - _send_warning("either image_from_camera or focal_length must be set", 1) - focal_length = (width * height) ** 0.5 # a reasonable default - if principal_point is None: - principal_point = [width / 2, height / 2] - if type(focal_length) in (int, float): - fl_x = focal_length - fl_y = focal_length - else: + with catch_and_log_exceptions(context=self.__class__.__name__): + if resolution is None and width is not None and height is not None: + resolution = [width, height] + elif resolution is not None and (width is not None or height is not None): + _send_warning("Can't set both resolution and width/height", 1) + + # TODO(andreas): Use a union type for the Pinhole component instead ~Zof converting to a matrix here + if image_from_camera is None: + # Resolution is needed for various fallbacks/error cases below. + if resolution is None: + resolution = [1.0, 1.0] + resolution = Vec2D(resolution) + width = cast(float, resolution.xy[0]) + height = cast(float, resolution.xy[1]) + + if focal_length is None: + _send_warning("either image_from_camera or focal_length must be set", 1) + focal_length = (width * height) ** 0.5 # a reasonable default + if principal_point is None: + principal_point = [width / 2, height / 2] + if type(focal_length) in (int, float): + fl_x = focal_length + fl_y = focal_length + else: + try: + # TODO(emilk): check that it is 2 elements long + fl_x = focal_length[0] # type: ignore[index] + fl_y = focal_length[1] # type: ignore[index] + except Exception: + _send_warning("Expected focal_length to be one or two floats", 1) + fl_x = width / 2 + fl_y = fl_x + try: - # TODO(emilk): check that it is 2 elements long - fl_x = focal_length[0] # type: ignore[index] - fl_y = focal_length[1] # type: ignore[index] + u_cen = principal_point[0] # type: ignore[index] + v_cen = principal_point[1] # type: ignore[index] except Exception: - _send_warning("Expected focal_length to be one or two floats", 1) - fl_x = width / 2 - fl_y = fl_x - - try: - u_cen = principal_point[0] # type: ignore[index] - v_cen = principal_point[1] # type: ignore[index] - except Exception: - _send_warning("Expected principal_point to be one or two floats", 1) - u_cen = width / 2 - v_cen = height / 2 - - image_from_camera = [[fl_x, 0, u_cen], [0, fl_y, v_cen], [0, 0, 1]] # type: ignore[assignment] - else: - if focal_length is not None: - _send_warning("Both image_from_camera and focal_length set", 1) - if principal_point is not None: - _send_warning("Both image_from_camera and principal_point set", 1) - - self.__attrs_init__(image_from_camera=image_from_camera, resolution=resolution, camera_xyz=camera_xyz) + _send_warning("Expected principal_point to be one or two floats", 1) + u_cen = width / 2 + v_cen = height / 2 + + image_from_camera = [[fl_x, 0, u_cen], [0, fl_y, v_cen], [0, 0, 1]] # type: ignore[assignment] + else: + if focal_length is not None: + _send_warning("Both image_from_camera and focal_length set", 1) + if principal_point is not None: + _send_warning("Both image_from_camera and principal_point set", 1) + + self.__attrs_init__(image_from_camera=image_from_camera, resolution=resolution, camera_xyz=camera_xyz) + return + + self.__attrs_init__(image_from_camera=None, resolution=None, camera_xyz=None) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image_ext.py index 2519c7dfeca1..4ee458f8400d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image_ext.py @@ -5,9 +5,8 @@ import numpy as np import pyarrow as pa -from rerun.error_utils import _send_warning - from .._validators import find_non_empty_dim_indices +from ..error_utils import _send_warning, catch_and_log_exceptions if TYPE_CHECKING: from ..components import TensorDataBatch @@ -16,6 +15,7 @@ class SegmentationImageExt: @staticmethod + @catch_and_log_exceptions("SegmentationImage converter") def data__field_converter_override(data: TensorDataArrayLike) -> TensorDataBatch: from ..components import TensorDataBatch from ..datatypes import TensorDataType, TensorDimensionType From 5fadc2b85c3cc8025865f80d52f148c35749a132 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 05:58:17 +0200 Subject: [PATCH 16/27] Edge cases and docstring --- rerun_py/rerun_sdk/rerun/_log.py | 2 +- rerun_py/rerun_sdk/rerun/error_utils.py | 17 ++++++++++++++--- rerun_py/tests/unit/test_exceptions.py | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/_log.py b/rerun_py/rerun_sdk/rerun/_log.py index d7aa6f9b608c..8375ad68368f 100644 --- a/rerun_py/rerun_sdk/rerun/_log.py +++ b/rerun_py/rerun_sdk/rerun/_log.py @@ -144,7 +144,7 @@ def log( if hasattr(entity, "as_component_batches"): components = entity.as_component_batches() else: - components = entity + components = list(entity) if hasattr(entity, "num_instances"): num_instances = entity.num_instances() diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index 5cfea1446910..7ff40cea8d3b 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -115,10 +115,23 @@ class catch_and_log_exceptions: For functions, this decorator checks for a strict kwarg and uses it to override the global strict mode if provided. + + Parameters + ---------- + context: + A string describing the context of the exception. + If not provided, the function name will be used. + depth_to_user_code: + The number of frames to skip when building the warning context. + This should be the number of frames between the user code and the + context manager. + exception_return_value: + If an exception is caught, this value will be returned instead of + the function's return value. """ def __init__( - self, context: str | None = None, depth_to_user_code: int = 0, exception_return_value: Any = None + self, context: str | None = None, depth_to_user_code: int = 1, exception_return_value: Any = None ) -> None: self.depth_to_user_code = depth_to_user_code self.context = context @@ -136,8 +149,6 @@ def __enter__(self) -> catch_and_log_exceptions: return self def __call__(self, func: _TFunc) -> _TFunc: - self.depth_to_user_code += 1 - if self.context is None: self.context = func.__qualname__ diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py index 0767d45fb017..6401bb598ba6 100644 --- a/rerun_py/tests/unit/test_exceptions.py +++ b/rerun_py/tests/unit/test_exceptions.py @@ -83,7 +83,7 @@ def test_stack_tracking() -> None: with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() - with catch_and_log_exceptions(): + with catch_and_log_exceptions(depth_to_user_code=0): uses_context() expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) @@ -92,7 +92,7 @@ def test_stack_tracking() -> None: with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() - with catch_and_log_exceptions("some context"): + with catch_and_log_exceptions("some context", depth_to_user_code=0): raise ValueError("some value error") expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) From e434b68e314fc0e3fa6defe5e7d42e764cada6c1 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 06:07:08 +0200 Subject: [PATCH 17/27] Need to provide attrs_init values for arrow3d_ext --- rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py index 3178d7f80a19..1ea34f2d18c5 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py @@ -59,4 +59,12 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__() + self.__attrs_init__( + vectors=None, + origins=None, + radii=None, + colors=None, + labels=None, + class_ids=None, + instance_keys=None, + ) From 8241f38768fa735e1c0380b401859b6129788792 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 14:38:22 +0200 Subject: [PATCH 18/27] Handle variations in stack prior to 3.10 for unit-testing --- rerun_py/tests/unit/test_exceptions.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/rerun_py/tests/unit/test_exceptions.py b/rerun_py/tests/unit/test_exceptions.py index 6401bb598ba6..f49d84e6f555 100644 --- a/rerun_py/tests/unit/test_exceptions.py +++ b/rerun_py/tests/unit/test_exceptions.py @@ -2,6 +2,7 @@ import inspect import os +import sys from typing import Any import pytest @@ -83,19 +84,35 @@ def test_stack_tracking() -> None: with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() + value = 0 with catch_and_log_exceptions(depth_to_user_code=0): uses_context() - - expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) + value = 42 + + if sys.version_info < (3, 10): + expected_line = get_line_number() - 3 # the last line of the context block + else: + expected_line = get_line_number() - 7 # the first line of the context block + expected_warnings(warnings, mem, starting_msgs, 1, expected_line) + # value is changed because uses_context its own exception internally + assert value == 42 assert "inner context" in str(warnings[0].message) with pytest.warns(RerunWarning) as warnings: starting_msgs = mem.num_msgs() + value = 0 with catch_and_log_exceptions("some context", depth_to_user_code=0): raise ValueError("some value error") - - expected_warnings(warnings, mem, starting_msgs, 1, get_line_number() - 3) + value = 42 + + if sys.version_info < (3, 10): + expected_line = get_line_number() - 3 # the last line of the context block + else: + expected_line = get_line_number() - 7 # the open of the context manager + expected_warnings(warnings, mem, starting_msgs, 1, expected_line) + # value wasn't changed because an exception was raised + assert value == 0 assert "some context" in str(warnings[0].message) From e81896dc0ca21bbff3ee90b1b31b55681446e23e Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 14:51:29 +0200 Subject: [PATCH 19/27] Start a pattern for testing that certain bad data gives expected warnings --- rerun_py/rerun_sdk/rerun/_validators.py | 2 +- rerun_py/tests/unit/test_expected_warnings.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 rerun_py/tests/unit/test_expected_warnings.py diff --git a/rerun_py/rerun_sdk/rerun/_validators.py b/rerun_py/rerun_sdk/rerun/_validators.py index d766386f235d..960d3eb67475 100644 --- a/rerun_py/rerun_sdk/rerun/_validators.py +++ b/rerun_py/rerun_sdk/rerun/_validators.py @@ -62,7 +62,7 @@ def flat_np_float_array_from_array_like(data: Any, dimension: int) -> npt.NDArra if not valid: raise ValueError( - f"Expected either a flat array with a length a of {dimension} elements, or an array with shape (`num_elements`, {dimension}). Shape of passed array was {array.shape}." + f"Expected either a flat array with a length multiple of {dimension} elements, or an array with shape (`num_elements`, {dimension}). Shape of passed array was {array.shape}." ) return array.reshape((-1,)) diff --git a/rerun_py/tests/unit/test_expected_warnings.py b/rerun_py/tests/unit/test_expected_warnings.py new file mode 100644 index 000000000000..2489804c13f4 --- /dev/null +++ b/rerun_py/tests/unit/test_expected_warnings.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +import pytest +import rerun as rr +from rerun.error_utils import RerunWarning + +rr.init("exceptions", spawn=False) +mem = rr.memory_recording() + + +def test_points_warnings() -> None: + with pytest.warns(RerunWarning) as warnings: + rr.log("points", rr.Points3D([1, 2, 3, 4, 5])) + + assert len(warnings) == 1 + assert ( + "Expected either a flat array with a length a of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,).)" + in str(warnings[0].message) + ) From f0aff688f02b1c5b495b93ac31eb9c51af7975b5 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 14:57:42 +0200 Subject: [PATCH 20/27] Fix the test now that I corrected the warning --- rerun_py/tests/unit/test_expected_warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rerun_py/tests/unit/test_expected_warnings.py b/rerun_py/tests/unit/test_expected_warnings.py index 2489804c13f4..2eadec412af1 100644 --- a/rerun_py/tests/unit/test_expected_warnings.py +++ b/rerun_py/tests/unit/test_expected_warnings.py @@ -14,6 +14,6 @@ def test_points_warnings() -> None: assert len(warnings) == 1 assert ( - "Expected either a flat array with a length a of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,).)" + "Expected either a flat array with a length multiple of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,).)" in str(warnings[0].message) ) From 393f6f519c87a48443c0639cf85bdcf25441a5b1 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 15:00:00 +0200 Subject: [PATCH 21/27] Trailing comma --- rerun_py/tests/unit/test_expected_warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rerun_py/tests/unit/test_expected_warnings.py b/rerun_py/tests/unit/test_expected_warnings.py index 2eadec412af1..dc8fa8132aa6 100644 --- a/rerun_py/tests/unit/test_expected_warnings.py +++ b/rerun_py/tests/unit/test_expected_warnings.py @@ -14,6 +14,6 @@ def test_points_warnings() -> None: assert len(warnings) == 1 assert ( - "Expected either a flat array with a length multiple of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,).)" + "Expected either a flat array with a length multiple of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,)." in str(warnings[0].message) ) From 12ec562d365d5d41772185e8dbe152cffc2b0d28 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 15:22:30 +0200 Subject: [PATCH 22/27] Streamline writing multiple expectred warnings --- rerun_py/tests/unit/test_expected_warnings.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/rerun_py/tests/unit/test_expected_warnings.py b/rerun_py/tests/unit/test_expected_warnings.py index dc8fa8132aa6..1e7a9e1ea798 100644 --- a/rerun_py/tests/unit/test_expected_warnings.py +++ b/rerun_py/tests/unit/test_expected_warnings.py @@ -5,15 +5,25 @@ from rerun.error_utils import RerunWarning rr.init("exceptions", spawn=False) +# Make sure strict mode isn't leaking in from another context mem = rr.memory_recording() -def test_points_warnings() -> None: +def test_expected_warnings() -> None: + # Always set strict mode to false in case it leaked from another test + rr.set_strict_mode(False) with pytest.warns(RerunWarning) as warnings: - rr.log("points", rr.Points3D([1, 2, 3, 4, 5])) + expected_warnings = [ + ( + rr.log("points", rr.Points3D([1, 2, 3, 4, 5])), + "Expected either a flat array with a length multiple of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,).", + ), + ( + rr.log("points", rr.Points2D([1, 2, 3, 4, 5])), + "Expected either a flat array with a length multiple of 2 elements, or an array with shape (`num_elements`, 2). Shape of passed array was (5,).", + ), + ] - assert len(warnings) == 1 - assert ( - "Expected either a flat array with a length multiple of 3 elements, or an array with shape (`num_elements`, 3). Shape of passed array was (5,)." - in str(warnings[0].message) - ) + assert len(warnings) == len(expected_warnings) + for warning, (_, expected) in zip(warnings, expected_warnings): + assert expected in str(warning) From c6333b341415d52e0dccbb2e6f2b6db42f436f62 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 29 Sep 2023 15:28:05 +0200 Subject: [PATCH 23/27] Add a comment --- rerun_py/tests/unit/test_expected_warnings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rerun_py/tests/unit/test_expected_warnings.py b/rerun_py/tests/unit/test_expected_warnings.py index 1e7a9e1ea798..66d266682502 100644 --- a/rerun_py/tests/unit/test_expected_warnings.py +++ b/rerun_py/tests/unit/test_expected_warnings.py @@ -13,6 +13,10 @@ def test_expected_warnings() -> None: # Always set strict mode to false in case it leaked from another test rr.set_strict_mode(False) with pytest.warns(RerunWarning) as warnings: + # Each of these calls will fail as they are executed and aggregate warnings into the single warnings recording. + # We then check that all the warnings were emitted in the expected order. + # If a log-call is expected to produce multiple warnings, add another tuple to the list that doesn't produce a warning, + # or else the offsets will get out of alignment. expected_warnings = [ ( rr.log("points", rr.Points3D([1, 2, 3, 4, 5])), From 6944732abf44fb45150e2a06fa28c19dd5ade267 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Sat, 30 Sep 2023 17:06:05 +0200 Subject: [PATCH 24/27] Refactor as __attrs_clear__ and _clear --- crates/re_types_builder/src/codegen/python.rs | 40 ++++++++++--------- .../rerun/archetypes/annotation_context.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/arrows3d.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/asset3d.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/bar_chart.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/boxes2d.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/boxes3d.py | 14 +++++-- rerun_py/rerun_sdk/rerun/archetypes/clear.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/depth_image.py | 14 +++++-- .../rerun/archetypes/disconnected_space.py | 14 +++++-- rerun_py/rerun_sdk/rerun/archetypes/image.py | 14 +++++-- .../rerun/archetypes/line_strips2d.py | 14 +++++-- .../rerun/archetypes/line_strips3d.py | 14 +++++-- rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/pinhole.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/points2d.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/points3d.py | 14 +++++-- .../rerun/archetypes/segmentation_image.py | 14 +++++-- rerun_py/rerun_sdk/rerun/archetypes/tensor.py | 14 +++++-- .../rerun/archetypes/text_document.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/text_log.py | 14 +++++-- .../rerun/archetypes/time_series_scalar.py | 14 +++++-- .../rerun_sdk/rerun/archetypes/transform3d.py | 14 +++++-- .../rerun/archetypes/view_coordinates.py | 14 +++++-- .../test_types/archetypes/affix_fuzzer1.py | 14 +++++-- .../test_types/archetypes/affix_fuzzer2.py | 14 +++++-- .../test_types/archetypes/affix_fuzzer3.py | 14 +++++-- .../test_types/archetypes/affix_fuzzer4.py | 14 +++++-- 28 files changed, 291 insertions(+), 127 deletions(-) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index 4adcbab645bf..569019739a0d 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -620,7 +620,7 @@ fn code_for_struct( } if obj.kind == ObjectKind::Archetype { - code.push_text(quote_clear_method(obj), 2, 4); + code.push_text(quote_clear_methods(obj), 2, 4); } if obj.is_delegating_component() { @@ -1688,29 +1688,31 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects ) } -fn quote_clear_method(obj: &Object) -> String { +fn quote_clear_methods(obj: &Object) -> String { let param_nones = obj .fields .iter() .map(|field| format!("{} = None, # type: ignore[arg-type]", field.name)) - .join("\n"); + .join("\n "); - let body = [ - r#"""""#.to_owned(), - format!("Produce an empty {}.", obj.name), - r#"""""#.to_owned(), - "return cls(".to_owned(), - param_nones, - ")".to_owned(), - ] - .join("\n"); - - [ - "@classmethod".to_owned(), - format!("def _clear(cls) -> {}:", obj.name), - indent::indent_all_by(4, body), - ] - .join("\n") + let classname = &obj.name; + + unindent::unindent(&format!( + r#" + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( + {param_nones} + ) + + @classmethod + def _clear(cls) -> {classname}: + """Produce an empty {classname}, bypassing `__init__`""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + "# + )) } // --- Arrow registry code generators --- diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index a4f3eb4c7519..2fae695cd761 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -136,13 +136,19 @@ def __init__(self: Any, context: components.AnnotationContextLike): context=None, ) - @classmethod - def _clear(cls) -> AnnotationContext: - """Produce an empty AnnotationContext.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( context=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> AnnotationContext: + """Produce an empty AnnotationContext, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + context: components.AnnotationContextBatch = field( metadata={"component": "required"}, converter=components.AnnotationContextBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py index f376807c8196..fed45982aac3 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d.py @@ -48,10 +48,9 @@ class Arrows3D(Arrows3DExt, Archetype): # __init__ can be found in arrows3d_ext.py - @classmethod - def _clear(cls) -> Arrows3D: - """Produce an empty Arrows3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( vectors=None, # type: ignore[arg-type] origins=None, # type: ignore[arg-type] radii=None, # type: ignore[arg-type] @@ -61,6 +60,13 @@ def _clear(cls) -> Arrows3D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Arrows3D: + """Produce an empty Arrows3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + vectors: components.Vector3DBatch = field( metadata={"component": "required"}, converter=components.Vector3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index d559ebec82e7..99d9324b2adb 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -113,15 +113,21 @@ def __init__( transform=None, ) - @classmethod - def _clear(cls) -> Asset3D: - """Produce an empty Asset3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( blob=None, # type: ignore[arg-type] media_type=None, # type: ignore[arg-type] transform=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Asset3D: + """Produce an empty Asset3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + blob: components.BlobBatch = field( metadata={"component": "required"}, converter=components.BlobBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 9cf91a547660..958d589fc96f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -53,13 +53,19 @@ def __init__(self: Any, values: datatypes.TensorDataLike): values=None, ) - @classmethod - def _clear(cls) -> BarChart: - """Produce an empty BarChart.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( values=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> BarChart: + """Produce an empty BarChart, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + values: components.TensorDataBatch = field( metadata={"component": "required"}, converter=BarChartExt.values__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py index 78fc55397f22..737bd9b009ce 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d.py @@ -36,10 +36,9 @@ class Boxes2D(Boxes2DExt, Archetype): # __init__ can be found in boxes2d_ext.py - @classmethod - def _clear(cls) -> Boxes2D: - """Produce an empty Boxes2D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( half_sizes=None, # type: ignore[arg-type] centers=None, # type: ignore[arg-type] colors=None, # type: ignore[arg-type] @@ -50,6 +49,13 @@ def _clear(cls) -> Boxes2D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Boxes2D: + """Produce an empty Boxes2D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + half_sizes: components.HalfSizes2DBatch = field( metadata={"component": "required"}, converter=components.HalfSizes2DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py index 3ea11157e0fa..cdd9d01dd204 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d.py @@ -71,10 +71,9 @@ class Boxes3D(Boxes3DExt, Archetype): # __init__ can be found in boxes3d_ext.py - @classmethod - def _clear(cls) -> Boxes3D: - """Produce an empty Boxes3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( half_sizes=None, # type: ignore[arg-type] centers=None, # type: ignore[arg-type] rotations=None, # type: ignore[arg-type] @@ -85,6 +84,13 @@ def _clear(cls) -> Boxes3D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Boxes3D: + """Produce an empty Boxes3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + half_sizes: components.HalfSizes3DBatch = field( metadata={"component": "required"}, converter=components.HalfSizes3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/clear.py b/rerun_py/rerun_sdk/rerun/archetypes/clear.py index 7719fec86a83..fce3d32e639f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/clear.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/clear.py @@ -63,13 +63,19 @@ class Clear(ClearExt, Archetype): # __init__ can be found in clear_ext.py - @classmethod - def _clear(cls) -> Clear: - """Produce an empty Clear.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( recursive=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Clear: + """Produce an empty Clear, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + recursive: components.ClearIsRecursiveBatch = field( metadata={"component": "required"}, converter=components.ClearIsRecursiveBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 2da5541e23b9..96d140b0d6e1 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -122,15 +122,21 @@ def __init__( draw_order=None, ) - @classmethod - def _clear(cls) -> DepthImage: - """Produce an empty DepthImage.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( data=None, # type: ignore[arg-type] meter=None, # type: ignore[arg-type] draw_order=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> DepthImage: + """Produce an empty DepthImage, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=DepthImageExt.data__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index 2dfdd9869f9c..61ec910cd51e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -54,13 +54,19 @@ def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): disconnected_space=None, ) - @classmethod - def _clear(cls) -> DisconnectedSpace: - """Produce an empty DisconnectedSpace.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( disconnected_space=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> DisconnectedSpace: + """Produce an empty DisconnectedSpace, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + disconnected_space: components.DisconnectedSpaceBatch = field( metadata={"component": "required"}, converter=components.DisconnectedSpaceBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index 11c8e1dd622f..34bdb11d10f5 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -77,14 +77,20 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component draw_order=None, ) - @classmethod - def _clear(cls) -> Image: - """Produce an empty Image.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( data=None, # type: ignore[arg-type] draw_order=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Image: + """Produce an empty Image, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=ImageExt.data__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index 7228bdb91e63..7a69e1362b0d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -153,10 +153,9 @@ def __init__( instance_keys=None, ) - @classmethod - def _clear(cls) -> LineStrips2D: - """Produce an empty LineStrips2D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( strips=None, # type: ignore[arg-type] radii=None, # type: ignore[arg-type] colors=None, # type: ignore[arg-type] @@ -166,6 +165,13 @@ def _clear(cls) -> LineStrips2D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> LineStrips2D: + """Produce an empty LineStrips2D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + strips: components.LineStrip2DBatch = field( metadata={"component": "required"}, converter=components.LineStrip2DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index 9b6ceb24fd9c..bf6d1c1c3e85 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -173,10 +173,9 @@ def __init__( instance_keys=None, ) - @classmethod - def _clear(cls) -> LineStrips3D: - """Produce an empty LineStrips3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( strips=None, # type: ignore[arg-type] radii=None, # type: ignore[arg-type] colors=None, # type: ignore[arg-type] @@ -185,6 +184,13 @@ def _clear(cls) -> LineStrips3D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> LineStrips3D: + """Produce an empty LineStrips3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + strips: components.LineStrip3DBatch = field( metadata={"component": "required"}, converter=components.LineStrip3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py index 5c6811f46d58..14019594f0dc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d.py @@ -71,10 +71,9 @@ class Mesh3D(Mesh3DExt, Archetype): # __init__ can be found in mesh3d_ext.py - @classmethod - def _clear(cls) -> Mesh3D: - """Produce an empty Mesh3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( vertex_positions=None, # type: ignore[arg-type] mesh_properties=None, # type: ignore[arg-type] vertex_normals=None, # type: ignore[arg-type] @@ -84,6 +83,13 @@ def _clear(cls) -> Mesh3D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Mesh3D: + """Produce an empty Mesh3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + vertex_positions: components.Position3DBatch = field( metadata={"component": "required"}, converter=components.Position3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py index 70027729479d..1814db92ac99 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole.py @@ -43,15 +43,21 @@ class Pinhole(PinholeExt, Archetype): # __init__ can be found in pinhole_ext.py - @classmethod - def _clear(cls) -> Pinhole: - """Produce an empty Pinhole.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( image_from_camera=None, # type: ignore[arg-type] resolution=None, # type: ignore[arg-type] camera_xyz=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Pinhole: + """Produce an empty Pinhole, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + image_from_camera: components.PinholeProjectionBatch = field( metadata={"component": "required"}, converter=components.PinholeProjectionBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index c8fc8702314f..73af7a191374 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -138,10 +138,9 @@ def __init__( instance_keys=None, ) - @classmethod - def _clear(cls) -> Points2D: - """Produce an empty Points2D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( positions=None, # type: ignore[arg-type] radii=None, # type: ignore[arg-type] colors=None, # type: ignore[arg-type] @@ -152,6 +151,13 @@ def _clear(cls) -> Points2D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Points2D: + """Produce an empty Points2D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + positions: components.Position2DBatch = field( metadata={"component": "required"}, converter=components.Position2DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 323d7908f659..00b8e27e1705 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -126,10 +126,9 @@ def __init__( instance_keys=None, ) - @classmethod - def _clear(cls) -> Points3D: - """Produce an empty Points3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( positions=None, # type: ignore[arg-type] radii=None, # type: ignore[arg-type] colors=None, # type: ignore[arg-type] @@ -139,6 +138,13 @@ def _clear(cls) -> Points3D: instance_keys=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Points3D: + """Produce an empty Points3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + positions: components.Position3DBatch = field( metadata={"component": "required"}, converter=components.Position3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index 225d52550be7..b0e4426c4227 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -78,14 +78,20 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component draw_order=None, ) - @classmethod - def _clear(cls) -> SegmentationImage: - """Produce an empty SegmentationImage.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( data=None, # type: ignore[arg-type] draw_order=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> SegmentationImage: + """Produce an empty SegmentationImage, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=SegmentationImageExt.data__field_converter_override, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/tensor.py b/rerun_py/rerun_sdk/rerun/archetypes/tensor.py index 36770f7c0051..50dd66d239ab 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/tensor.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/tensor.py @@ -70,13 +70,19 @@ class Tensor(TensorExt, Archetype): # __init__ can be found in tensor_ext.py - @classmethod - def _clear(cls) -> Tensor: - """Produce an empty Tensor.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( data=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Tensor: + """Produce an empty Tensor, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + data: components.TensorDataBatch = field( metadata={"component": "required"}, converter=components.TensorDataBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index 4a88c205919b..e094134988c4 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -47,14 +47,20 @@ def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8L media_type=None, ) - @classmethod - def _clear(cls) -> TextDocument: - """Produce an empty TextDocument.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( text=None, # type: ignore[arg-type] media_type=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> TextDocument: + """Produce an empty TextDocument, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + text: components.TextBatch = field( metadata={"component": "required"}, converter=components.TextBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index dc71c43bd994..ab49d500c63e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -66,15 +66,21 @@ def __init__( color=None, ) - @classmethod - def _clear(cls) -> TextLog: - """Produce an empty TextLog.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( text=None, # type: ignore[arg-type] level=None, # type: ignore[arg-type] color=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> TextLog: + """Produce an empty TextLog, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + text: components.TextBatch = field( metadata={"component": "required"}, converter=components.TextBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index e9ee406c61b2..11ce03292081 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -129,10 +129,9 @@ def __init__( scattered=None, ) - @classmethod - def _clear(cls) -> TimeSeriesScalar: - """Produce an empty TimeSeriesScalar.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( scalar=None, # type: ignore[arg-type] radius=None, # type: ignore[arg-type] color=None, # type: ignore[arg-type] @@ -140,6 +139,13 @@ def _clear(cls) -> TimeSeriesScalar: scattered=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> TimeSeriesScalar: + """Produce an empty TimeSeriesScalar, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + scalar: components.ScalarBatch = field( metadata={"component": "required"}, converter=components.ScalarBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index 6c4784571a4a..1ed7ce18dcc2 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -72,13 +72,19 @@ def __init__(self: Any, transform: datatypes.Transform3DLike): transform=None, ) - @classmethod - def _clear(cls) -> Transform3D: - """Produce an empty Transform3D.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( transform=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> Transform3D: + """Produce an empty Transform3D, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + transform: components.Transform3DBatch = field( metadata={"component": "required"}, converter=components.Transform3DBatch._required, # type: ignore[misc] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index dee0756308ba..44b6d92d5a75 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -59,13 +59,19 @@ def __init__(self: Any, xyz: components.ViewCoordinatesLike): xyz=None, ) - @classmethod - def _clear(cls) -> ViewCoordinates: - """Produce an empty ViewCoordinates.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( xyz=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> ViewCoordinates: + """Produce an empty ViewCoordinates, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + xyz: components.ViewCoordinatesBatch = field( metadata={"component": "required"}, converter=components.ViewCoordinatesBatch._required, # type: ignore[misc] diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index 71bb6bc8858e..d12b81d30172 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -94,10 +94,9 @@ def __init__( fuzz1021=None, ) - @classmethod - def _clear(cls) -> AffixFuzzer1: - """Produce an empty AffixFuzzer1.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( fuzz1001=None, # type: ignore[arg-type] fuzz1002=None, # type: ignore[arg-type] fuzz1003=None, # type: ignore[arg-type] @@ -121,6 +120,13 @@ def _clear(cls) -> AffixFuzzer1: fuzz1021=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> AffixFuzzer1: + """Produce an empty AffixFuzzer1, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + fuzz1001: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, converter=components.AffixFuzzer1Batch._required, # type: ignore[misc] diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 0e59f5f4995a..0583790f1939 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -85,10 +85,9 @@ def __init__( fuzz1118=None, ) - @classmethod - def _clear(cls) -> AffixFuzzer2: - """Produce an empty AffixFuzzer2.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( fuzz1101=None, # type: ignore[arg-type] fuzz1102=None, # type: ignore[arg-type] fuzz1103=None, # type: ignore[arg-type] @@ -109,6 +108,13 @@ def _clear(cls) -> AffixFuzzer2: fuzz1118=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> AffixFuzzer2: + """Produce an empty AffixFuzzer2, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + fuzz1101: components.AffixFuzzer1Batch = field( metadata={"component": "required"}, converter=components.AffixFuzzer1Batch._required, # type: ignore[misc] diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index b52917060214..1a58179fc088 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -86,10 +86,9 @@ def __init__( fuzz2018=None, ) - @classmethod - def _clear(cls) -> AffixFuzzer3: - """Produce an empty AffixFuzzer3.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( fuzz2001=None, # type: ignore[arg-type] fuzz2002=None, # type: ignore[arg-type] fuzz2003=None, # type: ignore[arg-type] @@ -110,6 +109,13 @@ def _clear(cls) -> AffixFuzzer3: fuzz2018=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> AffixFuzzer3: + """Produce an empty AffixFuzzer3, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + fuzz2001: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, default=None, diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index 5ac53f61b5fe..306a8853e95f 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -86,10 +86,9 @@ def __init__( fuzz2118=None, ) - @classmethod - def _clear(cls) -> AffixFuzzer4: - """Produce an empty AffixFuzzer4.""" - return cls( + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( fuzz2101=None, # type: ignore[arg-type] fuzz2102=None, # type: ignore[arg-type] fuzz2103=None, # type: ignore[arg-type] @@ -110,6 +109,13 @@ def _clear(cls) -> AffixFuzzer4: fuzz2118=None, # type: ignore[arg-type] ) + @classmethod + def _clear(cls) -> AffixFuzzer4: + """Produce an empty AffixFuzzer4, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + fuzz2101: components.AffixFuzzer1Batch | None = field( metadata={"component": "optional"}, default=None, From 5d6d5792757a5ca658afa4317a81be3ba1fa6cf4 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Sat, 30 Sep 2023 17:10:28 +0200 Subject: [PATCH 25/27] Use () inside the generated init --- crates/re_types_builder/src/codegen/python.rs | 20 +++++++--------- .../rerun/archetypes/annotation_context.py | 4 +--- .../rerun_sdk/rerun/archetypes/asset3d.py | 6 +---- .../rerun_sdk/rerun/archetypes/bar_chart.py | 4 +--- .../rerun_sdk/rerun/archetypes/depth_image.py | 6 +---- .../rerun/archetypes/disconnected_space.py | 4 +--- rerun_py/rerun_sdk/rerun/archetypes/image.py | 5 +--- .../rerun/archetypes/line_strips2d.py | 10 +------- .../rerun/archetypes/line_strips3d.py | 9 +------ .../rerun_sdk/rerun/archetypes/points2d.py | 11 +-------- .../rerun_sdk/rerun/archetypes/points3d.py | 10 +------- .../rerun/archetypes/segmentation_image.py | 5 +--- .../rerun/archetypes/text_document.py | 5 +--- .../rerun_sdk/rerun/archetypes/text_log.py | 6 +---- .../rerun/archetypes/time_series_scalar.py | 8 +------ .../rerun_sdk/rerun/archetypes/transform3d.py | 4 +--- .../rerun/archetypes/view_coordinates.py | 4 +--- .../test_types/archetypes/affix_fuzzer1.py | 24 +------------------ .../test_types/archetypes/affix_fuzzer2.py | 21 +--------------- .../test_types/archetypes/affix_fuzzer3.py | 21 +--------------- .../test_types/archetypes/affix_fuzzer4.py | 21 +--------------- 21 files changed, 28 insertions(+), 180 deletions(-) diff --git a/crates/re_types_builder/src/codegen/python.rs b/crates/re_types_builder/src/codegen/python.rs index 569019739a0d..7d6c77446537 100644 --- a/crates/re_types_builder/src/codegen/python.rs +++ b/crates/re_types_builder/src/codegen/python.rs @@ -1663,18 +1663,14 @@ fn quote_init_method(obj: &Object, ext_class: &ExtensionClass, objects: &Objects // Make sure Archetypes catch and log exceptions as a fallback let forwarding_call = if obj.kind == ObjectKind::Archetype { - let required_param_nones = obj - .fields - .iter() - .map(|field| format!("{} = None,", field.name)) - .join("\n"); - [ - "with catch_and_log_exceptions(context=self.__class__.__name__):".to_owned(), - indent::indent_all_by(4, forwarding_call), - indent::indent_all_by(4, "return"), - format!("self.__attrs_init__({required_param_nones})"), - ] - .join("\n") + unindent::unindent(&format!( + r#" + with catch_and_log_exceptions(context=self.__class__.__name__): + {forwarding_call} + return + self.__attrs_clear__() + "# + )) } else { forwarding_call }; diff --git a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py index 2fae695cd761..05a64b9be4d5 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/annotation_context.py @@ -132,9 +132,7 @@ def __init__(self: Any, context: components.AnnotationContextLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(context=context) return - self.__attrs_init__( - context=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index 99d9324b2adb..074489ece88c 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -107,11 +107,7 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(blob=blob, media_type=media_type, transform=transform) return - self.__attrs_init__( - blob=None, - media_type=None, - transform=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py index 958d589fc96f..a492a03cadf1 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/bar_chart.py @@ -49,9 +49,7 @@ def __init__(self: Any, values: datatypes.TensorDataLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(values=values) return - self.__attrs_init__( - values=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py index 96d140b0d6e1..43a31fe315dc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/depth_image.py @@ -116,11 +116,7 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, meter=meter, draw_order=draw_order) return - self.__attrs_init__( - data=None, - meter=None, - draw_order=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index 61ec910cd51e..cfd285e95289 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -50,9 +50,7 @@ def __init__(self: Any, disconnected_space: components.DisconnectedSpaceLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(disconnected_space=disconnected_space) return - self.__attrs_init__( - disconnected_space=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/image.py b/rerun_py/rerun_sdk/rerun/archetypes/image.py index 34bdb11d10f5..8edaa1ca48f9 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/image.py @@ -72,10 +72,7 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, draw_order=draw_order) return - self.__attrs_init__( - data=None, - draw_order=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py index 7a69e1362b0d..531ed50ac8c9 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips2d.py @@ -143,15 +143,7 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__( - strips=None, - radii=None, - colors=None, - labels=None, - draw_order=None, - class_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py index bf6d1c1c3e85..3e1e4839312d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/line_strips3d.py @@ -164,14 +164,7 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__( - strips=None, - radii=None, - colors=None, - labels=None, - class_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py index 73af7a191374..523c0d9a1ec4 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points2d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points2d.py @@ -127,16 +127,7 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__( - positions=None, - radii=None, - colors=None, - labels=None, - draw_order=None, - class_ids=None, - keypoint_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py index 00b8e27e1705..ac719c1cdbeb 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/points3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/points3d.py @@ -116,15 +116,7 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__( - positions=None, - radii=None, - colors=None, - labels=None, - class_ids=None, - keypoint_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py index b0e4426c4227..0b4e50b81b49 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/segmentation_image.py @@ -73,10 +73,7 @@ def __init__(self: Any, data: datatypes.TensorDataLike, *, draw_order: component with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(data=data, draw_order=draw_order) return - self.__attrs_init__( - data=None, - draw_order=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py index e094134988c4..1b46177562f8 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_document.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_document.py @@ -42,10 +42,7 @@ def __init__(self: Any, text: datatypes.Utf8Like, *, media_type: datatypes.Utf8L with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(text=text, media_type=media_type) return - self.__attrs_init__( - text=None, - media_type=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py index ab49d500c63e..8cedf37885df 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/text_log.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/text_log.py @@ -60,11 +60,7 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(text=text, level=level, color=color) return - self.__attrs_init__( - text=None, - level=None, - color=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py index 11ce03292081..c429d5e514cb 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/time_series_scalar.py @@ -121,13 +121,7 @@ def __init__( with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(scalar=scalar, radius=radius, color=color, label=label, scattered=scattered) return - self.__attrs_init__( - scalar=None, - radius=None, - color=None, - label=None, - scattered=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py index 1ed7ce18dcc2..7a35feb2cf02 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/transform3d.py @@ -68,9 +68,7 @@ def __init__(self: Any, transform: datatypes.Transform3DLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(transform=transform) return - self.__attrs_init__( - transform=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py index 44b6d92d5a75..59eed8705575 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/view_coordinates.py @@ -55,9 +55,7 @@ def __init__(self: Any, xyz: components.ViewCoordinatesLike): with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(xyz=xyz) return - self.__attrs_init__( - xyz=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py index d12b81d30172..c1cb1a0c7668 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer1.py @@ -70,29 +70,7 @@ def __init__( fuzz1021=fuzz1021, ) return - self.__attrs_init__( - fuzz1001=None, - fuzz1002=None, - fuzz1003=None, - fuzz1004=None, - fuzz1005=None, - fuzz1006=None, - fuzz1007=None, - fuzz1008=None, - fuzz1009=None, - fuzz1010=None, - fuzz1011=None, - fuzz1012=None, - fuzz1013=None, - fuzz1014=None, - fuzz1015=None, - fuzz1016=None, - fuzz1017=None, - fuzz1018=None, - fuzz1019=None, - fuzz1020=None, - fuzz1021=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py index 0583790f1939..60189b03fa7c 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer2.py @@ -64,26 +64,7 @@ def __init__( fuzz1118=fuzz1118, ) return - self.__attrs_init__( - fuzz1101=None, - fuzz1102=None, - fuzz1103=None, - fuzz1104=None, - fuzz1105=None, - fuzz1106=None, - fuzz1107=None, - fuzz1108=None, - fuzz1109=None, - fuzz1110=None, - fuzz1111=None, - fuzz1112=None, - fuzz1113=None, - fuzz1114=None, - fuzz1115=None, - fuzz1116=None, - fuzz1117=None, - fuzz1118=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py index 1a58179fc088..f876f4006a17 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer3.py @@ -65,26 +65,7 @@ def __init__( fuzz2018=fuzz2018, ) return - self.__attrs_init__( - fuzz2001=None, - fuzz2002=None, - fuzz2003=None, - fuzz2004=None, - fuzz2005=None, - fuzz2006=None, - fuzz2007=None, - fuzz2008=None, - fuzz2009=None, - fuzz2010=None, - fuzz2011=None, - fuzz2012=None, - fuzz2013=None, - fuzz2014=None, - fuzz2015=None, - fuzz2016=None, - fuzz2017=None, - fuzz2018=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" diff --git a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py index 306a8853e95f..882ed32710d3 100644 --- a/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py +++ b/rerun_py/tests/test_types/archetypes/affix_fuzzer4.py @@ -65,26 +65,7 @@ def __init__( fuzz2118=fuzz2118, ) return - self.__attrs_init__( - fuzz2101=None, - fuzz2102=None, - fuzz2103=None, - fuzz2104=None, - fuzz2105=None, - fuzz2106=None, - fuzz2107=None, - fuzz2108=None, - fuzz2109=None, - fuzz2110=None, - fuzz2111=None, - fuzz2112=None, - fuzz2113=None, - fuzz2114=None, - fuzz2115=None, - fuzz2116=None, - fuzz2117=None, - fuzz2118=None, - ) + self.__attrs_clear__() def __attrs_clear__(self) -> None: """Convenience method for calling `__attrs_init__` with all `None`s.""" From dc0ce8c7e64271d7aab55e83c6b822f14a0acead Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Sat, 30 Sep 2023 17:14:13 +0200 Subject: [PATCH 26/27] Migrate extensions to attrs_clear as appropriate --- .../rerun_sdk/rerun/archetypes/arrows3d_ext.py | 10 +--------- .../rerun_sdk/rerun/archetypes/boxes2d_ext.py | 11 +---------- .../rerun_sdk/rerun/archetypes/boxes3d_ext.py | 11 +---------- .../rerun_sdk/rerun/archetypes/mesh3d_ext.py | 10 +--------- .../rerun_sdk/rerun/archetypes/pinhole_ext.py | 2 +- .../rerun_sdk/rerun/archetypes/tensor_ext.py | 16 +++++++++++----- 6 files changed, 16 insertions(+), 44 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py index 1ea34f2d18c5..440b1b670eb7 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/arrows3d_ext.py @@ -59,12 +59,4 @@ def __init__( instance_keys=instance_keys, ) return - self.__attrs_init__( - vectors=None, - origins=None, - radii=None, - colors=None, - labels=None, - class_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py index 74b57389324c..b98668252f1c 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes2d_ext.py @@ -166,13 +166,4 @@ def __init__( ) return - self.__attrs_init__( - half_sizes=None, - centers=None, - radii=None, - colors=None, - labels=None, - draw_order=None, - class_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py index 54b156efea4c..1ebf842bcb4e 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/boxes3d_ext.py @@ -87,13 +87,4 @@ def __init__( ) return - self.__attrs_init__( - half_sizes=None, - centers=None, - rotations=None, - colors=None, - radii=None, - labels=None, - class_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py index bf77d804bb85..53453179d90f 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/mesh3d_ext.py @@ -67,12 +67,4 @@ def __init__( ) return - self.__attrs_init__( - vertex_positions=None, - mesh_properties=None, - vertex_normals=None, - vertex_colors=None, - mesh_material=None, - class_ids=None, - instance_keys=None, - ) + self.__attrs_clear__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py index 0490f4e100cd..55bf68f527d6 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/pinhole_ext.py @@ -129,4 +129,4 @@ def __init__( self.__attrs_init__(image_from_camera=image_from_camera, resolution=resolution, camera_xyz=camera_xyz) return - self.__attrs_init__(image_from_camera=None, resolution=None, camera_xyz=None) + self.__attrs_clear__() diff --git a/rerun_py/rerun_sdk/rerun/archetypes/tensor_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/tensor_ext.py index 1019e50e7ad2..c5de87791fff 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/tensor_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/tensor_ext.py @@ -2,6 +2,8 @@ from typing import TYPE_CHECKING, Any, Sequence +from ..error_utils import catch_and_log_exceptions + if TYPE_CHECKING: from ..datatypes import TensorDataLike from ..datatypes.tensor_data_ext import TensorLike @@ -36,9 +38,13 @@ def __init__( """ from ..datatypes import TensorData - if not isinstance(data, TensorData): - data = TensorData(array=data, dim_names=dim_names) - elif dim_names is not None: - data = TensorData(buffer=data.buffer, dim_names=dim_names) + with catch_and_log_exceptions(context=self.__class__.__name__): + if not isinstance(data, TensorData): + data = TensorData(array=data, dim_names=dim_names) + elif dim_names is not None: + data = TensorData(buffer=data.buffer, dim_names=dim_names) + + self.__attrs_init__(data=data) + return - self.__attrs_init__(data=data) + self.__attrs_clear__() From 41f3a7dae887503cf098e063121e54bcdeb7378d Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Sat, 30 Sep 2023 17:18:15 +0200 Subject: [PATCH 27/27] Rename check_strict_mode --- rerun_py/rerun_sdk/rerun/error_utils.py | 6 +++--- rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rerun_py/rerun_sdk/rerun/error_utils.py b/rerun_py/rerun_sdk/rerun/error_utils.py index 7ff40cea8d3b..183d28a7b8e7 100644 --- a/rerun_py/rerun_sdk/rerun/error_utils.py +++ b/rerun_py/rerun_sdk/rerun/error_utils.py @@ -22,7 +22,7 @@ _rerun_exception_ctx = threading.local() -def check_strict_mode() -> bool: +def strict_mode() -> bool: """ Strict mode enabled. @@ -81,7 +81,7 @@ def _send_warning( from rerun._log import log from rerun.archetypes import TextLog - if check_strict_mode(): + if strict_mode(): raise TypeError(message) # Send the warning to the user first @@ -171,7 +171,7 @@ def __exit__( exc_tb: TracebackType | None, ) -> bool: try: - if exc_type is not None and not check_strict_mode(): + if exc_type is not None and not strict_mode(): if getattr(_rerun_exception_ctx, "pending_warnings", None) is None: _rerun_exception_ctx.pending_warnings = [] diff --git a/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py b/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py index de0dc79f9813..7cd02db7ac45 100644 --- a/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py +++ b/rerun_py/rerun_sdk/rerun/log_deprecated/log_decorator.py @@ -10,7 +10,7 @@ from rerun.archetypes import TextLog from rerun.recording_stream import RecordingStream -from ..error_utils import check_strict_mode +from ..error_utils import strict_mode _TFunc = TypeVar("_TFunc", bound=Callable[..., Any]) @@ -45,7 +45,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: ) return - if check_strict_mode(): + if strict_mode(): # Pass on any exceptions to the caller return func(*args, **kwargs) else: