sanic-openapi icon indicating copy to clipboard operation
sanic-openapi copied to clipboard

openapi.component needlessly inspects properties, gets stuck

Open allComputableThings opened this issue 2 months ago • 1 comments

import dataclasses

from sanic_ext.extensions.openapi import openapi

@dataclasses.dataclass
class Path:
    x: [float]
    y: [float]

    @property
    def reversed(self) -> "Path":  # Recurses
        return Path(
            x=self.x[::-1],
            y=self.y[::-1],
        )
    
openapi.component(Path)   # Infinite loop

...

  File "/home/sir/venv/py3/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 446, in _extract
    hints = get_type_hints(item.fget)
  File "/usr/lib/python3.10/typing.py", line 1871, in get_type_hints
    value = _eval_type(value, globalns, localns)
  File "/usr/lib/python3.10/typing.py", line 327, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
  File "/usr/lib/python3.10/typing.py", line 694, in _evaluate
    eval(self.__forward_code__, globalns, localns),
  File "<string>", line 1, in <module>
RecursionError: maximum recursion depth exceeded while calling a Python object

This is failing due to:

#openapi/types.py

        return cls(
            {
                k: Schema.make(v, **extra.get(k, {}))
                for k, v in _properties(value).items()          # Does not need to inspect properties for dataclass or Pydantic objects
            },
            **kwargs,
        )

It similarly fails without recursion:

import dataclasses
from typing import Tuple, List
from sanic_ext.extensions.openapi import openapi

@dataclasses.dataclass
class Path:
    x: [float]
    y: [float]

    @property
    def points(self) -> List[Tuple[float, float]]:
        pass

openapi.component(Path)

...

Traceback (most recent call last):
  File "/home/sir/venv/py3/lib/python3.10/site-packages/sanic_ext/extensions/openapi/types.py", line 417, in _properties
    annotations = get_type_hints(cls)
  File "/usr/lib/python3.10/typing.py", line 1856, in get_type_hints
    raise TypeError('{!r} is not a module, class, method, '
TypeError: typing.Tuple[float, float] is not a module, class, method, or function.

There's really no need for sanic to inspect property return types to discover model attributes. Dataclasses, Pydantic or type annotations on the class constructor all provide what is needed.

allComputableThings avatar May 01 '24 00:05 allComputableThings