Skip to content

Commit

Permalink
Internal log_text_entry_internal to break circular deps (#1488)
Browse files Browse the repository at this point in the history
* Internal log_text_entry_internal to break circular deps

* strict_mode isn't a member of bindings
  • Loading branch information
jleibs authored Mar 2, 2023
1 parent 684a070 commit 7691eee
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 36 deletions.
1 change: 1 addition & 0 deletions rerun_py/rerun_sdk/rerun/log/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"scalar",
"tensor",
"text",
"text_internal",
"transform",
"ext",
]
Expand Down
8 changes: 4 additions & 4 deletions rerun_py/rerun_sdk/rerun/log/error_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import inspect
import logging

from rerun import bindings
from rerun.log.text import LogLevel, log_text_entry
import rerun
from rerun.log.text_internal import LogLevel, log_text_entry_internal

__all__ = [
"_send_warning",
Expand All @@ -24,10 +24,10 @@ def _send_warning(message: str, depth_to_user_code: int) -> None:
or raise an exception and let the @log_decorator handle it instead.
"""

if bindings.strict_mode():
if rerun.strict_mode():
raise TypeError(message)

context_descriptor = _build_warning_context_string(skip_first=depth_to_user_code + 2)
warning = f"{message}\n{context_descriptor}"
log_text_entry("rerun", warning, level=LogLevel.WARN)
log_text_entry_internal("rerun", warning, level=LogLevel.WARN)
logging.warning(warning)
7 changes: 4 additions & 3 deletions rerun_py/rerun_sdk/rerun/log/log_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import traceback
from typing import Any, Callable, TypeVar, cast

import rerun
from rerun import bindings
from rerun.log.text import LogLevel, log_text_entry
from rerun.log.text_internal import LogLevel, log_text_entry_internal

_TFunc = TypeVar("_TFunc", bound=Callable[..., Any])

Expand All @@ -26,15 +27,15 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
if not bindings.is_enabled():
return

if bindings.strict_mode():
if rerun.strict_mode():
# Pass on any exceptions to the caller
return func(*args, **kwargs)
else:
try:
return func(*args, **kwargs)
except Exception as e:
warning = "".join(traceback.format_exception(e.__class__, e, e.__traceback__))
log_text_entry("rerun", warning, level=LogLevel.WARN)
log_text_entry_internal("rerun", warning, level=LogLevel.WARN)
logging.warning(f"Ignoring rerun log call: {warning}")

return cast(_TFunc, wrapper)
30 changes: 1 addition & 29 deletions rerun_py/rerun_sdk/rerun/log/text.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from dataclasses import dataclass
from typing import Any, Dict, Final, Optional, Sequence

# Fully qualified to avoid circular import
Expand All @@ -10,6 +9,7 @@
from rerun.components.text_entry import TextEntryArray
from rerun.log import _normalize_colors
from rerun.log.log_decorator import log_decorator
from rerun.log.text_internal import LogLevel

__all__ = [
"LogLevel",
Expand All @@ -18,34 +18,6 @@
]


@dataclass
class LogLevel:
"""
Represents the standard log levels.
This is a collection of constants rather than an enum because we do support
arbitrary strings as level (e.g. for user-defined levels).
"""

CRITICAL: Final = "CRITICAL"
""" Designates catastrophic failures. """

ERROR: Final = "ERROR"
""" Designates very serious errors. """

WARN: Final = "WARN"
""" Designates hazardous situations. """

INFO: Final = "INFO"
""" Designates useful information. """

DEBUG: Final = "DEBUG"
""" Designates lower priority information. """

TRACE: Final = "TRACE"
""" Designates very low priority, often extremely verbose, information. """


class LoggingHandler(logging.Handler):
"""
Provides a logging handler that forwards all events to the Rerun SDK.
Expand Down
95 changes: 95 additions & 0 deletions rerun_py/rerun_sdk/rerun/log/text_internal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import logging
from dataclasses import dataclass
from typing import Any, Dict, Final, Optional, Sequence

# Fully qualified to avoid circular import
from rerun import bindings
from rerun.components.color import ColorRGBAArray
from rerun.components.instance import InstanceArray
from rerun.components.text_entry import TextEntryArray
from rerun.log import _normalize_colors

__all__ = [
"LogLevel",
"log_text_entry_internal",
]


@dataclass
class LogLevel:
"""
Represents the standard log levels.
This is a collection of constants rather than an enum because we do support
arbitrary strings as level (e.g. for user-defined levels).
"""

CRITICAL: Final = "CRITICAL"
""" Designates catastrophic failures. """

ERROR: Final = "ERROR"
""" Designates very serious errors. """

WARN: Final = "WARN"
""" Designates hazardous situations. """

INFO: Final = "INFO"
""" Designates useful information. """

DEBUG: Final = "DEBUG"
""" Designates lower priority information. """

TRACE: Final = "TRACE"
""" Designates very low priority, often extremely verbose, information. """


def log_text_entry_internal(
entity_path: str,
text: str,
*,
level: Optional[str] = LogLevel.INFO,
color: Optional[Sequence[int]] = None,
timeless: bool = False,
) -> None:
"""
Internal API to log a text entry, with optional level.
This implementation doesn't support extension components, or the exception-capturing decorator
and is intended to be used from inside the other rerun log functions.
Parameters
----------
entity_path:
The object path to log the text entry under.
text:
The text to log.
level:
The level of the text entry (default: `LogLevel.INFO`). Note this can technically
be an arbitrary string, but it's recommended to use one of the constants
from [LogLevel][rerun.log.text.LogLevel]
color:
Optional RGB or RGBA triplet in 0-255 sRGB.
timeless:
Whether the text entry should be timeless.
"""

instanced: Dict[str, Any] = {}
splats: Dict[str, Any] = {}

if text:
instanced["rerun.text_entry"] = TextEntryArray.from_bodies_and_levels([(text, level)])
else:
logging.warning(f"Null text entry in log_text_entry('{entity_path}') will be dropped.")

if color:
colors = _normalize_colors([color])
instanced["rerun.colorrgba"] = ColorRGBAArray.from_numpy(colors)

if splats:
splats["rerun.instance_key"] = InstanceArray.splat()
bindings.log_arrow_msg(entity_path, components=splats, timeless=timeless)

# Always the primary component last so range-based queries will include the other data. See(#1215)
if instanced:
bindings.log_arrow_msg(entity_path, components=instanced, timeless=timeless)

0 comments on commit 7691eee

Please sign in to comment.