diff --git a/reflex/utils/console.py b/reflex/utils/console.py index fcdc2df1223..fa1dab1abf0 100644 --- a/reflex/utils/console.py +++ b/reflex/utils/console.py @@ -22,6 +22,7 @@ # Console for pretty printing. _console = Console() +_console_stderr = Console(stderr=True) # The current log level. _LOG_LEVEL = LogLevel.INFO @@ -96,6 +97,21 @@ def print(msg: str, *, dedupe: bool = False, **kwargs): _console.print(msg, **kwargs) +def _print_stderr(msg: str, *, dedupe: bool = False, **kwargs): + """Print a message to stderr. + + Args: + msg: The message to print. + dedupe: If True, suppress multiple console logs of print message. + kwargs: Keyword arguments to pass to the print function. + """ + if dedupe: + if msg in _EMITTED_PRINTS: + return + _EMITTED_PRINTS.add(msg) + _console_stderr.print(msg, **kwargs) + + @once def log_file_console(): """Create a console that logs to a file. @@ -342,7 +358,7 @@ def error(msg: str, *, dedupe: bool = False, **kwargs): if msg in _EMITTED_ERRORS: return _EMITTED_ERRORS.add(msg) - print(f"[red]{msg}[/red]", **kwargs) + _print_stderr(f"[red]{msg}[/red]", **kwargs) if should_use_log_file_console(): print_to_log_file(f"[red]{msg}[/red]", **kwargs) diff --git a/reflex/vars/base.py b/reflex/vars/base.py index d28e98ae72f..2149b49cd62 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -2345,7 +2345,7 @@ def __get__(self, instance: BaseState | None, owner: type): def _check_deprecated_return_type(self, instance: BaseState, value: Any) -> None: if not _isinstance(value, self._var_type, nested=1, treat_var_as_type=False): console.error( - f"Computed var '{type(instance).__name__}.{self._js_expr}' must return" + f"Computed var '{type(instance).__name__}.{self._name}' must return" f" a value of type '{escape(str(self._var_type))}', got '{value!s}' of type {type(value)}." ) @@ -2395,7 +2395,7 @@ def _deps( except Exception as e: console.warn( "Failed to automatically determine dependencies for computed var " - f"{objclass.__name__}.{self._js_expr}: {e}. " + f"{objclass.__name__}.{self._name}: {e}. " "Provide static_deps and set auto_deps=False to suppress this warning." ) return d diff --git a/tests/integration/test_exception_handlers.py b/tests/integration/test_exception_handlers.py index 08c19415d95..8c24cfaa45e 100644 --- a/tests/integration/test_exception_handlers.py +++ b/tests/integration/test_exception_handlers.py @@ -114,7 +114,7 @@ def driver(test_app: AppHarness) -> Generator[WebDriver, None, None]: def test_frontend_exception_handler_during_runtime( driver: WebDriver, - capsys, + capsys: pytest.CaptureFixture[str], ): """Test calling frontend exception handler during runtime. @@ -136,13 +136,13 @@ def test_frontend_exception_handler_during_runtime( time.sleep(2) captured_default_handler_output = capsys.readouterr() - assert "induce_frontend_error" in captured_default_handler_output.out - assert "ReferenceError" in captured_default_handler_output.out + assert "induce_frontend_error" in captured_default_handler_output.err + assert "ReferenceError" in captured_default_handler_output.err def test_backend_exception_handler_during_runtime( driver: WebDriver, - capsys, + capsys: pytest.CaptureFixture[str], ): """Test calling backend exception handler during runtime. @@ -164,14 +164,14 @@ def test_backend_exception_handler_during_runtime( time.sleep(2) captured_default_handler_output = capsys.readouterr() - assert "divide_by_number" in captured_default_handler_output.out - assert "ZeroDivisionError" in captured_default_handler_output.out + assert "divide_by_number" in captured_default_handler_output.err + assert "ZeroDivisionError" in captured_default_handler_output.err def test_frontend_exception_handler_with_react( test_app: AppHarness, driver: WebDriver, - capsys, + capsys: pytest.CaptureFixture[str], ): """Test calling frontend exception handler during runtime. @@ -194,9 +194,9 @@ def test_frontend_exception_handler_with_react( captured_default_handler_output = capsys.readouterr() if isinstance(test_app, AppHarnessProd): - assert "Error: Minified React error #31" in captured_default_handler_output.out + assert "Error: Minified React error #31" in captured_default_handler_output.err else: assert ( "Error: Objects are not valid as a React child (found: object with keys \n{invalid})" - in captured_default_handler_output.out + in captured_default_handler_output.err ) diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 1fe25556a80..d1c728d5e81 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -1625,7 +1625,7 @@ def reset(self): @pytest.mark.asyncio -async def test_state_with_invalid_yield(capsys, mock_app): +async def test_state_with_invalid_yield(capsys: pytest.CaptureFixture[str], mock_app): """Test that an error is thrown when a state yields an invalid value. Args: @@ -1664,7 +1664,7 @@ def invalid_handler(self): token="", ) captured = capsys.readouterr() - assert "must only return/yield: None, Events or other EventHandlers" in captured.out + assert "must only return/yield: None, Events or other EventHandlers" in captured.err @pytest_asyncio.fixture(