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

[BUG] TypeError not callable : rich.print_exception #1492

Closed
yoann9344 opened this issue Sep 16, 2021 · 6 comments · Fixed by #1496
Closed

[BUG] TypeError not callable : rich.print_exception #1492

yoann9344 opened this issue Sep 16, 2021 · 6 comments · Fixed by #1496
Labels
bug Something isn't working

Comments

@yoann9344
Copy link

yoann9344 commented Sep 16, 2021

Hello !

Describe the bug
I use print_exception with uvicorn and print_exception got an exception "Field not Callable", I patched uvicorn/protocols/http/httptools_impl.py:404 this way

        except BaseException as exc:
            msg = "Exception in ASGI application\n"
            # PATCH start
            from rich.console import Console

            self.console = Console()
            self.console.print_exception(extra_lines=5, show_locals=True)
            # PATCH end
            self.logger.error(msg, exc_info=exc)
            if not self.response_started:
                await self.send_500_response()
            else:
                self.transport.close()

The exception which occured (the first part is the error in my side ; the second is the error in rich, both printed by uvicorn)

future: <Task finished name='Task-5' coro=<RequestResponseCycle.run_asgi() done, defined at .venv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py:396> exception=TypeError("'Field' object is not callable")>
Traceback (most recent call last):
  File ".venv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 398, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File ".venv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File ".venv/lib/python3.9/site-packages/fastapi/applications.py", line 199, in __call__
    await super().__call__(scope, receive, send)
  File ".venv/lib/python3.9/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File ".venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File ".venv/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File ".venv/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File ".venv/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File ".venv/lib/python3.9/site-packages/starlette/routing.py", line 580, in __call__
    await route.handle(scope, receive, send)
  File ".venv/lib/python3.9/site-packages/starlette/routing.py", line 241, in handle
    await self.app(scope, receive, send)
  File ".venv/lib/python3.9/site-packages/starlette/routing.py", line 52, in app
    response = await func(request)
  File ".venv/lib/python3.9/site-packages/fastapi/routing.py", line 201, in app
    raw_response = await run_endpoint_function(
  File ".venv/lib/python3.9/site-packages/fastapi/routing.py", line 148, in run_endpoint_function
    return await dependant.call(**values)
  File "./openapi_server/utils/routes.py", line 26, in filter_fields
    response = await func(*args, **kwargs)
  File "./openapi_server/apis/geographic_address_api.py", line 74, in list_geographic_address
    return await handler.objects()
  File "business/business/handlers/handler.py", line 39, in objects
    query_set = await self.query_set.limit(self.limit)
  File ".venv/lib/python3.9/site-packages/tortoise/queryset.py", line 900, in __await__
    self._make_query()
  File ".venv/lib/python3.9/site-packages/tortoise/queryset.py", line 862, in _make_query
    self.resolve_filters(
  File ".venv/lib/python3.9/site-packages/tortoise/queryset.py", line 129, in resolve_filters
    modifier &= node.resolve(model, annotations, custom_filters, model._meta.basetable)
  File ".venv/lib/python3.9/site-packages/tortoise/query_utils.py", line 390, in resolve
    return self._resolve_kwargs(model, table)
  File ".venv/lib/python3.9/site-packages/tortoise/query_utils.py", line 344, in _resolve_kwargs
    key, value = self._get_actual_filter_params(model, raw_key, raw_value)
  File ".venv/lib/python3.9/site-packages/tortoise/query_utils.py", line 338, in _get_actual_filter_params
    raise FieldError(f"Unknown filter param '{key}'. Allowed base values are {allowed}")
tortoise.exceptions.FieldError: Unknown filter param 'buildings__id'. Allowed base values are ['X', 'Y', 'buildings_FR', 'coverage_infra_ftto_FR', 'id', 'numéro', 'répétiteur', 'voie', 'voie_id']

Traceback (most recent call last):
  File ".venv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 404, in run_asgi
    self.console.print_exception(extra_lines=5, show_locals=True)
  File ".venv/lib/python3.9/site-packages/rich/console.py", line 1719, in print_exception
    traceback = Traceback(
  File ".venv/lib/python3.9/site-packages/rich/traceback.py", line 223, in __init__
    trace = self.extract(
  File ".venv/lib/python3.9/site-packages/rich/traceback.py", line 350, in extract
    locals={
  File ".venv/lib/python3.9/site-packages/rich/traceback.py", line 351, in <dictcomp>
    key: pretty.traverse(
  File ".venv/lib/python3.9/site-packages/rich/pretty.py", line 686, in traverse
    node = _traverse(_object, root=True)
  File ".venv/lib/python3.9/site-packages/rich/pretty.py", line 672, in _traverse
    child_node = _traverse(child)
  File ".venv/lib/python3.9/site-packages/rich/pretty.py", line 509, in _traverse
    args = list(iter_rich_args(obj.__rich_repr__()))
TypeError: 'Field' object is not callable

To Reproduce
It is complex to reproduce it :/ Maybe I could reproduce it, it seems to come from tortoise orm, I will try later.

Platform
Linux

Diagnose
I quickly fixed the problem (but it seems to reduce the quantity of details) by patching rich this way (rich/pretty.py:509) :

            # PATCH start
            # args = list(iter_rich_args(obj.__rich_repr__()))  # replaced line
            try:
                args = list(iter_rich_args(obj.__rich_repr__()))
            except TypeError:
                args = []
                # print("FAILLED")
            # PATCH end
@yoann9344 yoann9344 changed the title [BUG] [BUG] TypeError not callable : rich.print_exception Sep 16, 2021
@willmcgugan
Copy link
Collaborator

I'm guessing that Tortoise ORM does some magic which breaks the pretty printing. It appears as though __rich_repr__ exists and is not callable. Have you added a __rich_repr__ callable anywhere?

@yoann9344
Copy link
Author

yoann9344 commented Sep 16, 2021

No, I have not used __rich_repr__ :

grep -r "__rich_repr__" .
./.venv/lib/python3.9/site-packages/rich/layout.py: ...
./.venv/lib/python3.9/site-packages/rich/color.py: ...
...

Then might it be a __getattr__ or __getattribute from Tortoise ORM ?

ps:

ic| obj: Table('FR_Addresses')
ic| obj.__dict__: {'_for': None,
                   '_for_portion': None,
                   '_query_cls': <class 'pypika.queries.Query'>,
                   '_schema': None,
                   '_table_name': 'FR_Addresses',
                   'alias': None}

pypika.queries.Table inherits from pypike.queries.Selectable which has a __getattr__ which try to convert the given name to a Field (our type error).
__getattr__ is decored by ignore_copy which prevents copy.

@willmcgugan willmcgugan added bug Something isn't working and removed Needs triage labels Sep 17, 2021
@yoann9344
Copy link
Author

To reproduce the error :

from rich.console import Console

console = Console()


class Field:
    def __init__(self, name):
        self.name = name


class Table:
    def __getattr__(self, name):
        return Field(name)


if __name__ == "__main__":
    try:
        t = Table()
        raise BaseException("Whatever")
    except BaseException:
        console.print_exception(extra_lines=5, show_locals=True)

@github-actions
Copy link

Did I solve your problem?

Consider sponsoring the ongoing work on Rich and Textual.

Or buy me a coffee to say thanks.

Will McGugan

@willmcgugan
Copy link
Collaborator

Please try v10.10.0 Fixes your example code.

@yoann9344
Copy link
Author

Perfect ! I tried, it works smooth, thx :)

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue Sep 19, 2021
10.10.0

Added

Added stdin support to rich.json

Fixed

Fixed pretty printing of objects with fo magic with getattr Textualize/rich#1492
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants