diff --git a/invokeai/app/api/routers/boards.py b/invokeai/app/api/routers/boards.py index 630135f236..cc6fbc4e29 100644 --- a/invokeai/app/api/routers/boards.py +++ b/invokeai/app/api/routers/boards.py @@ -5,8 +5,8 @@ from fastapi.routing import APIRouter from pydantic import BaseModel, Field from invokeai.app.services.board_record_storage import BoardChanges -from invokeai.app.services.image_record_storage import OffsetPaginatedResults from invokeai.app.services.models.board_record import BoardDTO +from invokeai.app.services.shared.pagination import OffsetPaginatedResults from ..dependencies import ApiDependencies diff --git a/invokeai/app/api/routers/images.py b/invokeai/app/api/routers/images.py index 0885403453..faa8eb8bb2 100644 --- a/invokeai/app/api/routers/images.py +++ b/invokeai/app/api/routers/images.py @@ -9,8 +9,8 @@ from pydantic import BaseModel, Field from invokeai.app.invocations.metadata import ImageMetadata from invokeai.app.models.image import ImageCategory, ResourceOrigin -from invokeai.app.services.image_record_storage import OffsetPaginatedResults from invokeai.app.services.models.image_record import ImageDTO, ImageRecordChanges, ImageUrlsDTO +from invokeai.app.services.shared.pagination import OffsetPaginatedResults from ..dependencies import ApiDependencies diff --git a/invokeai/app/api/routers/session_queue.py b/invokeai/app/api/routers/session_queue.py index fb2c98c9f1..89329c153b 100644 --- a/invokeai/app/api/routers/session_queue.py +++ b/invokeai/app/api/routers/session_queue.py @@ -18,7 +18,7 @@ from invokeai.app.services.session_queue.session_queue_common import ( SessionQueueItemDTO, SessionQueueStatus, ) -from invokeai.app.services.shared.models import CursorPaginatedResults +from invokeai.app.services.shared.pagination import CursorPaginatedResults from ...services.graph import Graph from ..dependencies import ApiDependencies diff --git a/invokeai/app/api/routers/sessions.py b/invokeai/app/api/routers/sessions.py index ac6313edce..31a7b952a0 100644 --- a/invokeai/app/api/routers/sessions.py +++ b/invokeai/app/api/routers/sessions.py @@ -6,11 +6,12 @@ from fastapi import Body, HTTPException, Path, Query, Response from fastapi.routing import APIRouter from pydantic.fields import Field +from invokeai.app.services.shared.pagination import PaginatedResults + # Importing * is bad karma but needed here for node detection from ...invocations import * # noqa: F401 F403 from ...invocations.baseinvocation import BaseInvocation from ...services.graph import Edge, EdgeConnection, Graph, GraphExecutionState, NodeAlreadyExecutedError -from ...services.item_storage import PaginatedResults from ..dependencies import ApiDependencies session_router = APIRouter(prefix="/v1/sessions", tags=["sessions"]) diff --git a/invokeai/app/services/board_image_record_storage.py b/invokeai/app/services/board_image_record_storage.py index e8ec803992..b0bc65ba75 100644 --- a/invokeai/app/services/board_image_record_storage.py +++ b/invokeai/app/services/board_image_record_storage.py @@ -3,9 +3,9 @@ import threading from abc import ABC, abstractmethod from typing import Optional, cast -from invokeai.app.services.image_record_storage import OffsetPaginatedResults from invokeai.app.services.models.image_record import ImageRecord, deserialize_image_record from invokeai.app.services.shared.db import SqliteDatabase +from invokeai.app.services.shared.pagination import OffsetPaginatedResults class BoardImageRecordStorageBase(ABC): diff --git a/invokeai/app/services/board_record_storage.py b/invokeai/app/services/board_record_storage.py index 25d79a4214..7e4e44a084 100644 --- a/invokeai/app/services/board_record_storage.py +++ b/invokeai/app/services/board_record_storage.py @@ -5,9 +5,9 @@ from typing import Optional, Union, cast from pydantic import BaseModel, Extra, Field -from invokeai.app.services.image_record_storage import OffsetPaginatedResults from invokeai.app.services.models.board_record import BoardRecord, deserialize_board_record from invokeai.app.services.shared.db import SqliteDatabase +from invokeai.app.services.shared.pagination import OffsetPaginatedResults from invokeai.app.util.misc import uuid_string diff --git a/invokeai/app/services/boards.py b/invokeai/app/services/boards.py index 36f9a3cf32..8b6f70d3e3 100644 --- a/invokeai/app/services/boards.py +++ b/invokeai/app/services/boards.py @@ -2,9 +2,9 @@ from abc import ABC, abstractmethod from invokeai.app.services.board_images import board_record_to_dto from invokeai.app.services.board_record_storage import BoardChanges -from invokeai.app.services.image_record_storage import OffsetPaginatedResults from invokeai.app.services.invoker import Invoker from invokeai.app.services.models.board_record import BoardDTO +from invokeai.app.services.shared.pagination import OffsetPaginatedResults class BoardServiceABC(ABC): diff --git a/invokeai/app/services/image_record_storage.py b/invokeai/app/services/image_record_storage.py index 77f3f6216d..482c5e15f3 100644 --- a/invokeai/app/services/image_record_storage.py +++ b/invokeai/app/services/image_record_storage.py @@ -3,27 +3,12 @@ import sqlite3 import threading from abc import ABC, abstractmethod from datetime import datetime -from typing import Generic, Optional, TypeVar, cast - -from pydantic import BaseModel, Field -from pydantic.generics import GenericModel +from typing import Optional, cast from invokeai.app.models.image import ImageCategory, ResourceOrigin from invokeai.app.services.models.image_record import ImageRecord, ImageRecordChanges, deserialize_image_record from invokeai.app.services.shared.db import SqliteDatabase - -T = TypeVar("T", bound=BaseModel) - - -class OffsetPaginatedResults(GenericModel, Generic[T]): - """Offset-paginated results""" - - # fmt: off - items: list[T] = Field(description="Items") - offset: int = Field(description="Offset from which to retrieve items") - limit: int = Field(description="Limit of items to get") - total: int = Field(description="Total number of items in result") - # fmt: on +from invokeai.app.services.shared.pagination import OffsetPaginatedResults # TODO: Should these excpetions subclass existing python exceptions? diff --git a/invokeai/app/services/images.py b/invokeai/app/services/images.py index 97fdb89118..d68d5479f4 100644 --- a/invokeai/app/services/images.py +++ b/invokeai/app/services/images.py @@ -19,10 +19,10 @@ from invokeai.app.services.image_record_storage import ( ImageRecordDeleteException, ImageRecordNotFoundException, ImageRecordSaveException, - OffsetPaginatedResults, ) from invokeai.app.services.invoker import Invoker from invokeai.app.services.models.image_record import ImageDTO, ImageRecord, ImageRecordChanges, image_record_to_dto +from invokeai.app.services.shared.pagination import OffsetPaginatedResults from invokeai.app.util.metadata import get_metadata_graph_from_raw_session diff --git a/invokeai/app/services/item_storage.py b/invokeai/app/services/item_storage.py index 5fe4eb7456..290035b086 100644 --- a/invokeai/app/services/item_storage.py +++ b/invokeai/app/services/item_storage.py @@ -1,24 +1,13 @@ from abc import ABC, abstractmethod from typing import Callable, Generic, Optional, TypeVar -from pydantic import BaseModel, Field -from pydantic.generics import GenericModel +from pydantic import BaseModel + +from invokeai.app.services.shared.pagination import PaginatedResults T = TypeVar("T", bound=BaseModel) -class PaginatedResults(GenericModel, Generic[T]): - """Paginated results""" - - # fmt: off - items: list[T] = Field(description="Items") - page: int = Field(description="Current Page") - pages: int = Field(description="Total number of pages") - per_page: int = Field(description="Number of items per page") - total: int = Field(description="Total number of items in result") - # fmt: on - - class ItemStorageABC(ABC, Generic[T]): _on_changed_callbacks: list[Callable[[T], None]] _on_deleted_callbacks: list[Callable[[str], None]] diff --git a/invokeai/app/services/session_queue/session_queue_base.py b/invokeai/app/services/session_queue/session_queue_base.py index cbc16f8283..5df6f563ac 100644 --- a/invokeai/app/services/session_queue/session_queue_base.py +++ b/invokeai/app/services/session_queue/session_queue_base.py @@ -18,7 +18,7 @@ from invokeai.app.services.session_queue.session_queue_common import ( SessionQueueItemDTO, SessionQueueStatus, ) -from invokeai.app.services.shared.models import CursorPaginatedResults +from invokeai.app.services.shared.pagination import CursorPaginatedResults class SessionQueueBase(ABC): diff --git a/invokeai/app/services/session_queue/session_queue_sqlite.py b/invokeai/app/services/session_queue/session_queue_sqlite.py index 674593b550..ea9693697d 100644 --- a/invokeai/app/services/session_queue/session_queue_sqlite.py +++ b/invokeai/app/services/session_queue/session_queue_sqlite.py @@ -30,7 +30,7 @@ from invokeai.app.services.session_queue.session_queue_common import ( prepare_values_to_insert, ) from invokeai.app.services.shared.db import SqliteDatabase -from invokeai.app.services.shared.models import CursorPaginatedResults +from invokeai.app.services.shared.pagination import CursorPaginatedResults class SqliteSessionQueue(SessionQueueBase): diff --git a/invokeai/app/services/shared/models.py b/invokeai/app/services/shared/models.py deleted file mode 100644 index 7edde152c3..0000000000 --- a/invokeai/app/services/shared/models.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Generic, TypeVar - -from pydantic import BaseModel, Field -from pydantic.generics import GenericModel - -GenericBaseModel = TypeVar("GenericBaseModel", bound=BaseModel) - - -class CursorPaginatedResults(GenericModel, Generic[GenericBaseModel]): - """Cursor-paginated results""" - - limit: int = Field(..., description="Limit of items to get") - has_more: bool = Field(..., description="Whether there are more items available") - items: list[GenericBaseModel] = Field(..., description="Items") diff --git a/invokeai/app/services/shared/pagination.py b/invokeai/app/services/shared/pagination.py new file mode 100644 index 0000000000..85c8fb984e --- /dev/null +++ b/invokeai/app/services/shared/pagination.py @@ -0,0 +1,42 @@ +from typing import Generic, TypeVar + +from pydantic import BaseModel, Field +from pydantic.generics import GenericModel + +GenericBaseModel = TypeVar("GenericBaseModel", bound=BaseModel) + + +class CursorPaginatedResults(GenericModel, Generic[GenericBaseModel]): + """ + Cursor-paginated results + Generic must be a Pydantic model + """ + + limit: int = Field(..., description="Limit of items to get") + has_more: bool = Field(..., description="Whether there are more items available") + items: list[GenericBaseModel] = Field(..., description="Items") + + +class OffsetPaginatedResults(GenericModel, Generic[GenericBaseModel]): + """ + Offset-paginated results + Generic must be a Pydantic model + """ + + limit: int = Field(description="Limit of items to get") + offset: int = Field(description="Offset from which to retrieve items") + total: int = Field(description="Total number of items in result") + items: list[GenericBaseModel] = Field(description="Items") + + +class PaginatedResults(GenericModel, Generic[GenericBaseModel]): + """ + Paginated results + Generic must be a Pydantic model + """ + + page: int = Field(description="Current Page") + pages: int = Field(description="Total number of pages") + per_page: int = Field(description="Number of items per page") + total: int = Field(description="Total number of items in result") + items: list[GenericBaseModel] = Field(description="Items") diff --git a/invokeai/app/services/sqlite.py b/invokeai/app/services/sqlite.py index 989fa5132e..d0b978ffeb 100644 --- a/invokeai/app/services/sqlite.py +++ b/invokeai/app/services/sqlite.py @@ -5,8 +5,9 @@ from typing import Generic, Optional, TypeVar, get_args from pydantic import BaseModel, parse_raw_as from invokeai.app.services.shared.db import SqliteDatabase +from invokeai.app.services.shared.pagination import PaginatedResults -from .item_storage import ItemStorageABC, PaginatedResults +from .item_storage import ItemStorageABC T = TypeVar("T", bound=BaseModel)