Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal log_text_entry_internal to break circular deps #1488

Merged
merged 3 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)