api.models ========== .. py:module:: api.models Attributes ---------- .. autoapisummary:: api.models.log Exceptions ---------- .. autoapisummary:: api.models.ApiException api.models.ApiInvalidParamException Classes ------- .. autoapisummary:: api.models.PaginationWithById api.models.ApiEndpointItem api.models.ApiEndpoint api.models.ApiEndpointCollection api.models.AuthEndpoint api.models.ApiKey Module Contents --------------- .. py:class:: PaginationWithById[M: sqlalchemy.orm.DeclarativeBase, IdT: uuid.UUID | str | int] Bases: :py:obj:`Protocol` Base class for protocol classes. Protocol classes are defined as:: class Proto(Protocol): def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing). For example:: class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: class GenProto[T](Protocol): def meth(self) -> T: ... .. py:method:: by_id(id: IdT) -> M | None .. py:attribute:: batch_size :type: int .. py:method:: subset() -> sqlalchemy.orm.Query[M] .. py:property:: cached_subset :type: sqlalchemy.orm.Query[M] .. py:property:: page :type: int | None .. py:property:: page_index :type: int .. py:method:: page_by_index(index: int) -> Self .. py:property:: subset_count :type: int .. py:property:: batch :type: tuple[M, Ellipsis] .. py:property:: offset :type: int .. py:property:: pages_count :type: int .. py:property:: pages :type: collections.abc.Iterator[Self] .. py:property:: previous :type: Self | None .. py:property:: next :type: Self | None .. py:data:: log .. py:exception:: ApiException(message: str = 'Internal Server Error', status_code: int = 500, headers: dict[str, str] | None = None) Bases: :py:obj:`Exception` Base class for all API exceptions. Mainly used to ensure that all exceptions regarding the API are rendered with the correct content type. .. py:attribute:: message :value: 'Internal Server Error' .. py:attribute:: status_code :value: 500 .. py:attribute:: headers .. py:method:: capture_exceptions(default_message: str = 'Internal Server Error', default_status_code: int = 500, headers: dict[str, str] | None = None, exception_type: type[Exception] = Exception) -> collections.abc.Iterator[None] :classmethod: .. py:exception:: ApiInvalidParamException(message: str = 'Invalid Parameter', status_code: int = 400) Bases: :py:obj:`ApiException` Base class for all API exceptions. Mainly used to ensure that all exceptions regarding the API are rendered with the correct content type. .. py:attribute:: message :value: 'Invalid Parameter' .. py:attribute:: status_code :value: 400 .. py:class:: ApiEndpointItem[M: sqlalchemy.orm.DeclarativeBase](request: onegov.core.request.CoreRequest, endpoint: str, id: str) A single instance of an item of a specific endpoint. Passes all functionality to the specific API endpoint and is mainly used for routing. .. py:attribute:: request .. py:attribute:: app .. py:attribute:: endpoint .. py:attribute:: id .. py:property:: api_endpoint :type: ApiEndpoint[M] | None .. py:property:: item :type: M | None .. py:property:: data :type: dict[str, Any] | None .. py:property:: links :type: dict[str, Any] | None .. py:method:: form(request: onegov.core.request.CoreRequest) -> onegov.form.Form | None .. py:class:: ApiEndpoint[M: sqlalchemy.orm.DeclarativeBase](request: onegov.core.request.CoreRequest, extra_parameters: dict[str, str | None] | None = None, page: int | None = None) An API endpoint. API endpoints wrap collection and do some filter mapping. To add a new endpoint, inherit from this class and provide the missing functions and properties at the bottom. Note that the collection is expected to be to provide the functionality of ``onegov.core.collection.Pagination``. .. py:attribute:: endpoint :type: str :value: '' .. py:attribute:: filters :type: ClassVar[set[str]] .. py:attribute:: form_class :type: ClassVar[type[onegov.form.Form] | None] :value: None .. py:attribute:: request .. py:attribute:: app .. py:attribute:: extra_parameters .. py:attribute:: page .. py:attribute:: batch_size :value: 100 .. py:property:: title :type: str | None Return a human readable title for this endpoint .. py:property:: description :type: str | None Return a human readable description for this endpoint .. py:method:: for_page(page: int | None) -> Self | None Return a new endpoint instance with the given page while keeping the current filters. .. py:method:: for_filter(**filters: Any) -> Self Return a new endpoint instance with the given filters while discarding the current filters and page. .. py:method:: for_item(item: None) -> None for_item(item: M) -> ApiEndpointItem[M] Return a new endpoint item instance with the given item. .. py:method:: for_item_id(item_id: None) -> None for_item_id(item_id: Any) -> ApiEndpointItem[Any] Return a new endpoint item instance with the given item id. .. py:method:: get_filter[T1, T2](name: str, default: T1, empty: T2) -> str | T1 | T2 get_filter(name: str, default: T, empty: None = None) -> str | T | None get_filter(name: str, default: None = None, *, empty: T) -> str | T | None get_filter(name: str, default: None = None, empty: None = None) -> str | None Returns the filter value with the given name. .. py:method:: by_id(id: onegov.core.collection.PKType) -> M | None Return the item with the given ID from the collection. .. py:property:: session :type: sqlalchemy.orm.Session .. py:property:: links :type: dict[str, Self | None] Returns a dictionary with pagination instances. .. py:property:: batch :type: dict[ApiEndpointItem[M], M] Returns a dictionary with endpoint item instances and their titles. .. py:method:: item_data(item: M) -> dict[str, Any] :abstractmethod: Return the data properties of the collection item as a dictionary. For example:: { 'name': 'Paul', 'age': 40 } .. py:method:: item_links(item: M) -> dict[str, Any] :abstractmethod: Return the link properties of the collection item as a dictionary. Links can either be string or a linkable object. For example:: { 'website': 'https://onegov.ch', 'friends': FriendsApiEndpoint(app).for_item(paul), 'home': ApiEndpointCollection(app) } .. py:method:: form(item: M | None, request: onegov.core.request.CoreRequest) -> onegov.form.Form | None Return a form for editing items of this collection. .. py:method:: apply_changes(item: M, form: Any) -> None :abstractmethod: Apply the changes to the item based on the given form data. .. py:property:: collection :type: PaginationWithById[M, Any] :abstractmethod: Return an instance of the collection with filters and page set. .. py:method:: assert_valid_filter(param: str) -> None .. py:class:: ApiEndpointCollection(request: onegov.core.request.CoreRequest) A collection of all available API endpoints. .. py:attribute:: request .. py:attribute:: app .. py:property:: endpoints :type: dict[str, ApiEndpoint[Any]] .. py:method:: get_endpoint(name: str, page: int = 0, extra_parameters: dict[str, Any] | None = None) -> ApiEndpoint[Any] | None .. py:class:: AuthEndpoint(app: onegov.core.Framework) This is a Dummy, because morepath requires a model for linking. .. py:attribute:: app .. py:class:: ApiKey Bases: :py:obj:`onegov.core.orm.Base` Base class used for declarative class definitions. The :class:`_orm.DeclarativeBase` allows for the creation of new declarative bases in such a way that is compatible with type checkers:: from sqlalchemy.orm import DeclarativeBase class Base(DeclarativeBase): pass The above ``Base`` class is now usable as the base for new declarative mappings. The superclass makes use of the ``__init_subclass__()`` method to set up new classes and metaclasses aren't used. When first used, the :class:`_orm.DeclarativeBase` class instantiates a new :class:`_orm.registry` to be used with the base, assuming one was not provided explicitly. The :class:`_orm.DeclarativeBase` class supports class-level attributes which act as parameters for the construction of this registry; such as to indicate a specific :class:`_schema.MetaData` collection as well as a specific value for :paramref:`_orm.registry.type_annotation_map`:: from typing_extensions import Annotated from sqlalchemy import BigInteger from sqlalchemy import MetaData from sqlalchemy import String from sqlalchemy.orm import DeclarativeBase bigint = Annotated[int, "bigint"] my_metadata = MetaData() class Base(DeclarativeBase): metadata = my_metadata type_annotation_map = { str: String().with_variant(String(255), "mysql", "mariadb"), bigint: BigInteger(), } Class-level attributes which may be specified include: :param metadata: optional :class:`_schema.MetaData` collection. If a :class:`_orm.registry` is constructed automatically, this :class:`_schema.MetaData` collection will be used to construct it. Otherwise, the local :class:`_schema.MetaData` collection will supersede that used by an existing :class:`_orm.registry` passed using the :paramref:`_orm.DeclarativeBase.registry` parameter. :param type_annotation_map: optional type annotation map that will be passed to the :class:`_orm.registry` as :paramref:`_orm.registry.type_annotation_map`. :param registry: supply a pre-existing :class:`_orm.registry` directly. .. versionadded:: 2.0 Added :class:`.DeclarativeBase`, so that declarative base classes may be constructed in such a way that is also recognized by :pep:`484` type checkers. As a result, :class:`.DeclarativeBase` and other subclassing-oriented APIs should be seen as superseding previous "class returned by a function" APIs, namely :func:`_orm.declarative_base` and :meth:`_orm.registry.generate_base`, where the base class returned cannot be recognized by type checkers without using plugins. **__init__ behavior** In a plain Python class, the base-most ``__init__()`` method in the class hierarchy is ``object.__init__()``, which accepts no arguments. However, when the :class:`_orm.DeclarativeBase` subclass is first declared, the class is given an ``__init__()`` method that links to the :paramref:`_orm.registry.constructor` constructor function, if no ``__init__()`` method is already present; this is the usual declarative constructor that will assign keyword arguments as attributes on the instance, assuming those attributes are established at the class level (i.e. are mapped, or are linked to a descriptor). This constructor is **never accessed by a mapped class without being called explicitly via super()**, as mapped classes are themselves given an ``__init__()`` method directly which calls :paramref:`_orm.registry.constructor`, so in the default case works independently of what the base-most ``__init__()`` method does. .. versionchanged:: 2.0.1 :class:`_orm.DeclarativeBase` has a default constructor that links to :paramref:`_orm.registry.constructor` by default, so that calls to ``super().__init__()`` can access this constructor. Previously, due to an implementation mistake, this default constructor was missing, and calling ``super().__init__()`` would invoke ``object.__init__()``. The :class:`_orm.DeclarativeBase` subclass may also declare an explicit ``__init__()`` method which will replace the use of the :paramref:`_orm.registry.constructor` function at this level:: class Base(DeclarativeBase): def __init__(self, id=None): self.id = id Mapped classes still will not invoke this constructor implicitly; it remains only accessible by calling ``super().__init__()``:: class MyClass(Base): def __init__(self, id=None, name=None): self.name = name super().__init__(id=id) Note that this is a different behavior from what functions like the legacy :func:`_orm.declarative_base` would do; the base created by those functions would always install :paramref:`_orm.registry.constructor` for ``__init__()``. .. py:attribute:: __tablename__ :value: 'api_keys' .. py:attribute:: id :type: sqlalchemy.orm.Mapped[uuid.UUID] .. py:attribute:: user_id :type: sqlalchemy.orm.Mapped[uuid.UUID] .. py:attribute:: user :type: sqlalchemy.orm.Mapped[onegov.user.User] .. py:attribute:: name :type: sqlalchemy.orm.Mapped[str] .. py:attribute:: read_only :type: sqlalchemy.orm.Mapped[bool] .. py:attribute:: last_used :type: sqlalchemy.orm.Mapped[datetime.datetime | None] .. py:attribute:: key :type: sqlalchemy.orm.Mapped[uuid.UUID]