Skip to content

Commit

Permalink
Add a warning category and stacklevel to rerun warnings.warn calls (#…
Browse files Browse the repository at this point in the history
…2985)

Resolves: #2408

### What:
Stop overriding the global `warnings.formatwarning`

Instead introduce a RerunWarning category and also set stacklevel
appropriately for better warning context.

Consider this example:
```
import warnings
import rerun as rr

warnings.warn("my warning")
rr.log_points("foo", [1, 2, 3])
rr.init("foo")
rr.log_points("foo", "not a point")
```

Before: wrongly annotated user-warning. No way to identify source of
error.
```
WARNING:rerun:my warning
WARNING:rerun:Rerun is disabled - log_points() call ignored. You must call rerun.init before using log APIs.
WARNING:root:Ignoring rerun log call: Traceback (most recent call last):
  File "/home/jleibs/venv/lib/python3.10/site-packages/rerun_sdk/rerun/log/log_decorator.py", line 47, in wrapper
    return func(*args, **kwargs)
  File "/home/jleibs/venv/lib/python3.10/site-packages/rerun_sdk/rerun/log/points.py", line 228, in log_points
    positions = np.require(positions, dtype="float32")
  File "/home/jleibs/venv/lib/python3.10/site-packages/numpy/core/_asarray.py", line 110, in require
    return asanyarray(a, dtype=dtype)
ValueError: could not convert string to float: 'not a point'
```

After: Consistent pythonic warnings and actionable line-numbers.
```
/home/jleibs/rerun/test.py:4: UserWarning: my warning
  warnings.warn("my warning")
/home/jleibs/rerun/test.py:5: RerunWarning: Rerun is disabled - log_points() call ignored. You must call rerun.init before using log APIs.
  rr.log_points("foo", [1, 2, 3])
/home/jleibs/rerun/test.py:7: RerunWarning: Ignoring rerun log call: Traceback (most recent call last):
  File "/home/jleibs/rerun/rerun_py/rerun_sdk/rerun/log/log_decorator.py", line 51, in wrapper
    return func(*args, **kwargs)
  File "/home/jleibs/rerun/rerun_py/rerun_sdk/rerun/log/points.py", line 208, in log_points
    positions = np.require(positions, dtype="float32")
  File "/home/jleibs/rerun/venv/lib/python3.10/site-packages/numpy/core/_asarray.py", line 106, in require
    return asanyarray(a, dtype=dtype)
ValueError: could not convert string to float: 'not a point'

  rr.log_points("foo", "not a point")
```

### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested [demo.rerun.io](https://demo.rerun.io/pr/2985) (if
applicable)

- [PR Build Summary](https://build.rerun.io/pr/2985)
- [Docs
preview](https://rerun.io/preview/pr%3Ajleibs%2Frerun_warnings/docs)
- [Examples
preview](https://rerun.io/preview/pr%3Ajleibs%2Frerun_warnings/examples)
  • Loading branch information
jleibs authored and emilk committed Aug 17, 2023
1 parent 49926c5 commit 359890e
Showing 1 changed file with 9 additions and 5 deletions.
14 changes: 9 additions & 5 deletions rerun_py/rerun_sdk/rerun/log/log_decorator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import functools
import logging
import traceback
import warnings
from typing import Any, Callable, TypeVar, cast
Expand All @@ -13,8 +12,11 @@

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

# Default formatting for the `warnings` package is... non optimal.
warnings.formatwarning = lambda msg, *args, **kwargs: f"WARNING:rerun:{msg}\n"

class RerunWarning(Warning):
"""A custom warning class that we use to identify warnings that are emitted by the Rerun SDK itself."""

pass


def log_decorator(func: _TFunc) -> _TFunc:
Expand All @@ -35,7 +37,9 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
if not bindings.is_enabled(recording):
# NOTE: use `warnings` which handles runtime deduplication.
warnings.warn(
f"Rerun is disabled - {func.__name__}() call ignored. You must call rerun.init before using log APIs."
f"Rerun is disabled - {func.__name__}() call ignored. You must call rerun.init before using log APIs.",
category=RerunWarning,
stacklevel=2,
)
return

Expand All @@ -48,6 +52,6 @@ def wrapper(*args: Any, **kwargs: Any) -> Any:
except Exception as e:
warning = "".join(traceback.format_exception(e.__class__, e, e.__traceback__))
log_text_entry_internal("rerun", warning, level=LogLevel.WARN, recording=recording)
logging.warning(f"Ignoring rerun log call: {warning}")
warnings.warn(f"Ignoring rerun log call: {warning}", category=RerunWarning, stacklevel=2)

return cast(_TFunc, wrapper)

0 comments on commit 359890e

Please sign in to comment.