Skip to content
This repository has been archived by the owner on Feb 5, 2024. It is now read-only.

Update fork #10

Merged
merged 2 commits into from
Dec 13, 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
273 changes: 133 additions & 140 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pydantic = "^1.9.2"
typer = {extras = ["all"], version = "^0.6.1"}
fern-fern-generator-exec-sdk = {version = "0.0.489", source = "fern-prod"}
ordered-set = "^4.1.0"
fern-fern-ir-model = "^0.0.2967"
fern-fern-ir-v31 = "^0.0.3275"

[tool.poetry.dev-dependencies]
pytest = "^7.4.2"
Expand Down
6 changes: 6 additions & 0 deletions seed/fastapi/enum-query-params/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file was auto-generated by Fern from our API Definition.

from .resources import MyEnum, svc
from .security import ApiAuth

__all__ = ["ApiAuth", "MyEnum", "svc"]
23 changes: 23 additions & 0 deletions seed/fastapi/enum-query-params/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This file was auto-generated by Fern from our API Definition.

from .datetime_utils import serialize_datetime
from .exceptions import (
FernHTTPException,
UnauthorizedException,
default_exception_handler,
fern_http_exception_handler,
http_exception_handler,
)
from .route_args import route_args
from .security import BearerToken

__all__ = [
"BearerToken",
"FernHTTPException",
"UnauthorizedException",
"default_exception_handler",
"fern_http_exception_handler",
"http_exception_handler",
"route_args",
"serialize_datetime",
]
11 changes: 11 additions & 0 deletions seed/fastapi/enum-query-params/core/abstract_fern_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This file was auto-generated by Fern from our API Definition.

import abc

import fastapi


class AbstractFernService(abc.ABC):
@classmethod
def _init_fern(cls, router: fastapi.APIRouter) -> None:
...
28 changes: 28 additions & 0 deletions seed/fastapi/enum-query-params/core/datetime_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file was auto-generated by Fern from our API Definition.

import datetime as dt


def serialize_datetime(v: dt.datetime) -> str:
"""
Serialize a datetime including timezone info.

Uses the timezone info provided if present, otherwise uses the current runtime's timezone info.

UTC datetimes end in "Z" while all other timezones are represented as offset from UTC, e.g. +05:00.
"""

def _serialize_zoned_datetime(v: dt.datetime) -> str:
if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname(None):
# UTC is a special case where we use "Z" at the end instead of "+00:00"
return v.isoformat().replace("+00:00", "Z")
else:
# Delegate to the typical +/- offset format
return v.isoformat()

if v.tzinfo is not None:
return _serialize_zoned_datetime(v)
else:
local_tz = dt.datetime.now().astimezone().tzinfo
localized_dt = v.replace(tzinfo=local_tz)
return _serialize_zoned_datetime(localized_dt)
13 changes: 13 additions & 0 deletions seed/fastapi/enum-query-params/core/exceptions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This file was auto-generated by Fern from our API Definition.

from .fern_http_exception import FernHTTPException
from .handlers import default_exception_handler, fern_http_exception_handler, http_exception_handler
from .unauthorized import UnauthorizedException

__all__ = [
"FernHTTPException",
"UnauthorizedException",
"default_exception_handler",
"fern_http_exception_handler",
"http_exception_handler",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This file was auto-generated by Fern from our API Definition.

import abc
import typing

import fastapi


class FernHTTPException(abc.ABC, fastapi.HTTPException):
def __init__(
self, status_code: int, name: typing.Optional[str] = None, content: typing.Optional[typing.Any] = None
):
super().__init__(status_code=status_code)
self.name = name
self.status_code = status_code
self.content = content

def to_json_response(self) -> fastapi.responses.JSONResponse:
content = fastapi.encoders.jsonable_encoder(self.content, exclude_none=True)
return fastapi.responses.JSONResponse(content=content, status_code=self.status_code)
32 changes: 32 additions & 0 deletions seed/fastapi/enum-query-params/core/exceptions/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This file was auto-generated by Fern from our API Definition.

import logging

import fastapi
import starlette

from .fern_http_exception import FernHTTPException


def fern_http_exception_handler(
request: fastapi.requests.Request, exc: FernHTTPException, skip_log: bool = False
) -> fastapi.responses.JSONResponse:
if not skip_log:
logging.getLogger(__name__).error(f"{exc.__class__.__name__} in {request.url.path}", exc_info=exc)
return exc.to_json_response()


def http_exception_handler(
request: fastapi.requests.Request, exc: starlette.exceptions.HTTPException, skip_log: bool = False
) -> fastapi.responses.JSONResponse:
if not skip_log:
logging.getLogger(__name__).error(f"{exc.__class__.__name__} in {request.url.path}", exc_info=exc)
return FernHTTPException(status_code=exc.status_code, content=exc.detail).to_json_response()


def default_exception_handler(
request: fastapi.requests.Request, exc: Exception, skip_log: bool = False
) -> fastapi.responses.JSONResponse:
if not skip_log:
logging.getLogger(__name__).error(f"{exc.__class__.__name__} in {request.url.path}", exc_info=exc)
return FernHTTPException(status_code=500, content="Internal Server Error").to_json_response()
15 changes: 15 additions & 0 deletions seed/fastapi/enum-query-params/core/exceptions/unauthorized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This file was auto-generated by Fern from our API Definition.

import typing

from .fern_http_exception import FernHTTPException


class UnauthorizedException(FernHTTPException):
"""
This is the exception that is thrown by Fern when auth is not present on a
request.
"""

def __init__(self, content: typing.Optional[str] = None) -> None:
super().__init__(status_code=401, content=content)
63 changes: 63 additions & 0 deletions seed/fastapi/enum-query-params/core/route_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# This file was auto-generated by Fern from our API Definition.

import enum
import inspect
import typing

import typing_extensions

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

FERN_CONFIG_KEY = "__fern"


class RouteArgs(typing_extensions.TypedDict):
openapi_extra: typing.Optional[typing.Dict[str, typing.Any]]
tags: typing.Optional[typing.List[typing.Union[str, enum.Enum]]]
include_in_schema: bool


DEFAULT_ROUTE_ARGS = RouteArgs(openapi_extra=None, tags=None, include_in_schema=True)


def get_route_args(endpoint_function: typing.Callable[..., typing.Any], *, default_tag: str) -> RouteArgs:
unwrapped = inspect.unwrap(endpoint_function, stop=(lambda f: hasattr(f, FERN_CONFIG_KEY)))
route_args = typing.cast(RouteArgs, getattr(unwrapped, FERN_CONFIG_KEY, DEFAULT_ROUTE_ARGS))
if route_args["tags"] is None:
return RouteArgs(
openapi_extra=route_args["openapi_extra"],
tags=[default_tag],
include_in_schema=route_args["include_in_schema"],
)
return route_args


def route_args(
openapi_extra: typing.Optional[typing.Dict[str, typing.Any]] = None,
tags: typing.Optional[typing.List[typing.Union[str, enum.Enum]]] = None,
include_in_schema: bool = True,
) -> typing.Callable[[T], T]:
"""
this decorator allows you to forward certain args to the FastAPI route decorator.

usage:
@route_args(openapi_extra=...)
def your_endpoint_method(...

currently supported args:
- openapi_extra
- tags

if there's another FastAPI route arg you need to pass through, please
contact the Fern team!
"""

def decorator(endpoint_function: T) -> T:
setattr(
endpoint_function,
FERN_CONFIG_KEY,
RouteArgs(openapi_extra=openapi_extra, tags=tags, include_in_schema=include_in_schema),
)
return endpoint_function

return decorator
5 changes: 5 additions & 0 deletions seed/fastapi/enum-query-params/core/security/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This file was auto-generated by Fern from our API Definition.

from .bearer import BearerToken

__all__ = ["BearerToken"]
22 changes: 22 additions & 0 deletions seed/fastapi/enum-query-params/core/security/bearer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This file was auto-generated by Fern from our API Definition.

import fastapi

from ..exceptions import UnauthorizedException


class BearerToken:
def __init__(self, token: str):
self.token = token


def HTTPBearer(request: fastapi.requests.Request) -> BearerToken:
authorization_header_value = request.headers.get("Authorization")
if not authorization_header_value:
raise UnauthorizedException("Missing Authorization header")
scheme, _, token = authorization_header_value.partition(" ")
if scheme.lower() != "bearer":
raise UnauthorizedException("Authorization header scheme is not bearer")
if not token:
raise UnauthorizedException("Authorization header is missing a token")
return BearerToken(token)
44 changes: 44 additions & 0 deletions seed/fastapi/enum-query-params/register.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This file was auto-generated by Fern from our API Definition.

import glob
import importlib
import os
import types
import typing

import fastapi
import starlette
from fastapi import params

from .core.abstract_fern_service import AbstractFernService
from .core.exceptions import default_exception_handler, fern_http_exception_handler, http_exception_handler
from .core.exceptions.fern_http_exception import FernHTTPException
from .resources.svc.service.service import AbstractSvcService


def register(
_app: fastapi.FastAPI,
*,
svc: AbstractSvcService,
dependencies: typing.Optional[typing.Sequence[params.Depends]] = None
) -> None:
_app.include_router(__register_service(svc), dependencies=dependencies)

_app.add_exception_handler(FernHTTPException, fern_http_exception_handler)
_app.add_exception_handler(starlette.exceptions.HTTPException, http_exception_handler)
_app.add_exception_handler(Exception, default_exception_handler)


def __register_service(service: AbstractFernService) -> fastapi.APIRouter:
router = fastapi.APIRouter()
type(service)._init_fern(router)
return router


def register_validators(module: types.ModuleType) -> None:
validators_directory: str = os.path.dirname(module.__file__) # type: ignore
for path in glob.glob(os.path.join(validators_directory, "**/*.py"), recursive=True):
if os.path.isfile(path):
relative_path = os.path.relpath(path, start=validators_directory)
module_path = ".".join([module.__name__] + relative_path[:-3].split("/"))
importlib.import_module(module_path)
6 changes: 6 additions & 0 deletions seed/fastapi/enum-query-params/resources/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file was auto-generated by Fern from our API Definition.

from . import svc
from .svc import MyEnum

__all__ = ["MyEnum", "svc"]
5 changes: 5 additions & 0 deletions seed/fastapi/enum-query-params/resources/svc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This file was auto-generated by Fern from our API Definition.

from .types import MyEnum

__all__ = ["MyEnum"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This file was auto-generated by Fern from our API Definition.

from .service import AbstractSvcService

__all__ = ["AbstractSvcService"]
73 changes: 73 additions & 0 deletions seed/fastapi/enum-query-params/resources/svc/service/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# This file was auto-generated by Fern from our API Definition.

import abc
import functools
import inspect
import logging
import typing

import fastapi

from ....core.abstract_fern_service import AbstractFernService
from ....core.exceptions.fern_http_exception import FernHTTPException
from ....core.route_args import get_route_args
from ..types.my_enum import MyEnum


class AbstractSvcService(AbstractFernService):
"""
AbstractSvcService is an abstract class containing the methods that you should implement.

Each method is associated with an API route, which will be registered
with FastAPI when you register your implementation using Fern's register()
function.
"""

@abc.abstractmethod
def test(self, *, some_enum: typing.Optional[typing.List[MyEnum]] = None) -> str:
...

"""
Below are internal methods used by Fern to register your implementation.
You can ignore them.
"""

@classmethod
def _init_fern(cls, router: fastapi.APIRouter) -> None:
cls.__init_test(router=router)

@classmethod
def __init_test(cls, router: fastapi.APIRouter) -> None:
endpoint_function = inspect.signature(cls.test)
new_parameters: typing.List[inspect.Parameter] = []
for index, (parameter_name, parameter) in enumerate(endpoint_function.parameters.items()):
if index == 0:
new_parameters.append(parameter.replace(default=fastapi.Depends(cls)))
elif parameter_name == "some_enum":
new_parameters.append(parameter.replace(default=fastapi.Query(default=None, alias="some-enum")))
else:
new_parameters.append(parameter)
setattr(cls.test, "__signature__", endpoint_function.replace(parameters=new_parameters))

@functools.wraps(cls.test)
def wrapper(*args: typing.Any, **kwargs: typing.Any) -> str:
try:
return cls.test(*args, **kwargs)
except FernHTTPException as e:
logging.getLogger(f"{cls.__module__}.{cls.__name__}").warn(
f"Endpoint 'test' unexpectedly threw {e.__class__.__name__}. "
+ f"If this was intentional, please add {e.__class__.__name__} to "
+ "the endpoint's errors list in your Fern Definition."
)
raise e

# this is necessary for FastAPI to find forward-ref'ed type hints.
# https://github.com/tiangolo/fastapi/pull/5077
wrapper.__globals__.update(cls.test.__globals__)

router.get(
path="//test",
response_model=str,
description=AbstractSvcService.test.__doc__,
**get_route_args(cls.test, default_tag="svc"),
)(wrapper)
Loading