aioia-core 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aioia_core-0.1.0/PKG-INFO +63 -0
- aioia_core-0.1.0/README.md +39 -0
- aioia_core-0.1.0/aioia_core/__init__.py +47 -0
- aioia_core-0.1.0/aioia_core/auth.py +46 -0
- aioia_core-0.1.0/aioia_core/errors/__init__.py +56 -0
- aioia_core-0.1.0/aioia_core/errors/error_codes.py +26 -0
- aioia_core-0.1.0/aioia_core/errors/error_responses.py +92 -0
- aioia_core-0.1.0/aioia_core/factories/__init__.py +5 -0
- aioia_core-0.1.0/aioia_core/factories/base_manager_factory.py +55 -0
- aioia_core-0.1.0/aioia_core/fastapi/__init__.py +15 -0
- aioia_core-0.1.0/aioia_core/fastapi/base_crud_router.py +566 -0
- aioia_core-0.1.0/aioia_core/managers.py +268 -0
- aioia_core-0.1.0/aioia_core/models.py +49 -0
- aioia_core-0.1.0/aioia_core/protocols.py +134 -0
- aioia_core-0.1.0/aioia_core/py.typed +0 -0
- aioia_core-0.1.0/aioia_core/settings.py +72 -0
- aioia_core-0.1.0/aioia_core/testing/__init__.py +21 -0
- aioia_core-0.1.0/aioia_core/testing/crud_fixtures.py +150 -0
- aioia_core-0.1.0/aioia_core/testing/database_manager.py +90 -0
- aioia_core-0.1.0/pyproject.toml +51 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aioia-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Core infrastructure for AIoIA projects
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Keywords: aioia,infrastructure,database,fastapi
|
|
7
|
+
Author: AIoIA, Inc.
|
|
8
|
+
Author-email: devops@aioia.ai
|
|
9
|
+
Requires-Python: >=3.10,<3.13
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: fastapi (>=0.115.0,<0.116.0)
|
|
16
|
+
Requires-Dist: pydantic (>=2.5.0,<3.0.0)
|
|
17
|
+
Requires-Dist: pydantic-settings (>=2.0.0,<3.0.0)
|
|
18
|
+
Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
|
|
19
|
+
Requires-Dist: python-jose (>=3.3.0,<4.0.0)
|
|
20
|
+
Requires-Dist: sentry-sdk (>=2.0.0,<3.0.0)
|
|
21
|
+
Requires-Dist: sqlalchemy (>=2.0.0,<3.0.0)
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# AIoIA Core (Python)
|
|
25
|
+
|
|
26
|
+
AIoIA 프로젝트 공통 Python 인프라 라이브러리
|
|
27
|
+
|
|
28
|
+
## 설치
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install aioia-core
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 포함 기능
|
|
35
|
+
|
|
36
|
+
- **Database**: SQLAlchemy Base, BaseModel, BaseManager (CRUD)
|
|
37
|
+
- **Errors**: 표준화된 에러 코드 및 응답
|
|
38
|
+
- **Settings**: DatabaseSettings, OpenAIAPISettings, JWTSettings
|
|
39
|
+
- **Testing**: 테스트 인프라 (fixtures, managers)
|
|
40
|
+
|
|
41
|
+
## 사용법
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from aioia_core import BaseModel, BaseManager
|
|
45
|
+
from aioia_core.errors import ErrorResponse, RESOURCE_NOT_FOUND
|
|
46
|
+
|
|
47
|
+
# SQLAlchemy 모델
|
|
48
|
+
class MyModel(BaseModel):
|
|
49
|
+
__tablename__ = "my_table"
|
|
50
|
+
name: Mapped[str] = mapped_column(String)
|
|
51
|
+
|
|
52
|
+
# Manager 사용
|
|
53
|
+
manager = BaseManager(session, MyModel)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 요구사항
|
|
57
|
+
|
|
58
|
+
- Python 3.10-3.12
|
|
59
|
+
|
|
60
|
+
## 라이선스
|
|
61
|
+
|
|
62
|
+
Apache 2.0
|
|
63
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# AIoIA Core (Python)
|
|
2
|
+
|
|
3
|
+
AIoIA 프로젝트 공통 Python 인프라 라이브러리
|
|
4
|
+
|
|
5
|
+
## 설치
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install aioia-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 포함 기능
|
|
12
|
+
|
|
13
|
+
- **Database**: SQLAlchemy Base, BaseModel, BaseManager (CRUD)
|
|
14
|
+
- **Errors**: 표준화된 에러 코드 및 응답
|
|
15
|
+
- **Settings**: DatabaseSettings, OpenAIAPISettings, JWTSettings
|
|
16
|
+
- **Testing**: 테스트 인프라 (fixtures, managers)
|
|
17
|
+
|
|
18
|
+
## 사용법
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from aioia_core import BaseModel, BaseManager
|
|
22
|
+
from aioia_core.errors import ErrorResponse, RESOURCE_NOT_FOUND
|
|
23
|
+
|
|
24
|
+
# SQLAlchemy 모델
|
|
25
|
+
class MyModel(BaseModel):
|
|
26
|
+
__tablename__ = "my_table"
|
|
27
|
+
name: Mapped[str] = mapped_column(String)
|
|
28
|
+
|
|
29
|
+
# Manager 사용
|
|
30
|
+
manager = BaseManager(session, MyModel)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 요구사항
|
|
34
|
+
|
|
35
|
+
- Python 3.10-3.12
|
|
36
|
+
|
|
37
|
+
## 라이선스
|
|
38
|
+
|
|
39
|
+
Apache 2.0
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIoIA Core - Core infrastructure for AIoIA projects.
|
|
3
|
+
|
|
4
|
+
Provides:
|
|
5
|
+
- Database: SQLAlchemy base models and CRUD manager
|
|
6
|
+
- Errors: Standardized error codes and responses
|
|
7
|
+
- Settings: Common settings classes
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__version__ = "0.1.0"
|
|
11
|
+
|
|
12
|
+
from aioia_core.errors import (
|
|
13
|
+
INTERNAL_SERVER_ERROR,
|
|
14
|
+
RESOURCE_NOT_FOUND,
|
|
15
|
+
UNAUTHORIZED,
|
|
16
|
+
VALIDATION_ERROR,
|
|
17
|
+
ErrorResponse,
|
|
18
|
+
extract_error_code_from_exception,
|
|
19
|
+
get_error_detail_from_exception,
|
|
20
|
+
)
|
|
21
|
+
from aioia_core.factories.base_manager_factory import BaseManagerFactory
|
|
22
|
+
from aioia_core.managers import BaseManager
|
|
23
|
+
from aioia_core.models import Base, BaseModel
|
|
24
|
+
from aioia_core.protocols import CrudManagerProtocol, DatabaseManagerProtocol
|
|
25
|
+
from aioia_core.settings import DatabaseSettings, JWTSettings, OpenAIAPISettings
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
# Database
|
|
29
|
+
"Base",
|
|
30
|
+
"BaseModel",
|
|
31
|
+
"BaseManager",
|
|
32
|
+
"BaseManagerFactory",
|
|
33
|
+
"CrudManagerProtocol",
|
|
34
|
+
"DatabaseManagerProtocol",
|
|
35
|
+
# Errors
|
|
36
|
+
"ErrorResponse",
|
|
37
|
+
"UNAUTHORIZED",
|
|
38
|
+
"VALIDATION_ERROR",
|
|
39
|
+
"RESOURCE_NOT_FOUND",
|
|
40
|
+
"INTERNAL_SERVER_ERROR",
|
|
41
|
+
"extract_error_code_from_exception",
|
|
42
|
+
"get_error_detail_from_exception",
|
|
43
|
+
# Settings
|
|
44
|
+
"DatabaseSettings",
|
|
45
|
+
"OpenAIAPISettings",
|
|
46
|
+
"JWTSettings",
|
|
47
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Authentication and authorization utilities for AIoIA projects."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from sqlalchemy.orm import Session
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UserRole(str, Enum):
|
|
10
|
+
"""Standard user roles for all AIoIA projects."""
|
|
11
|
+
|
|
12
|
+
ADMIN = "admin"
|
|
13
|
+
USER = "user"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class UserRoleProvider(Protocol):
|
|
17
|
+
"""
|
|
18
|
+
Protocol for retrieving user roles and context.
|
|
19
|
+
|
|
20
|
+
Projects implement this to integrate their user management system
|
|
21
|
+
with BaseCrudRouter's authentication/authorization.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def get_user_role( # pylint: disable=unnecessary-ellipsis
|
|
25
|
+
self, user_id: str, db: Session
|
|
26
|
+
) -> UserRole | None:
|
|
27
|
+
"""
|
|
28
|
+
Get user's role by ID.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
user_id: User identifier
|
|
32
|
+
db: Database session
|
|
33
|
+
"""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def get_user_context( # pylint: disable=unnecessary-ellipsis
|
|
37
|
+
self, user_id: str, db: Session
|
|
38
|
+
) -> dict | None:
|
|
39
|
+
"""
|
|
40
|
+
Get user context for monitoring/observability tools.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
user_id: User identifier
|
|
44
|
+
db: Database session
|
|
45
|
+
"""
|
|
46
|
+
...
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Error handling infrastructure for AIoIA projects.
|
|
3
|
+
|
|
4
|
+
Provides standardized error codes and responses for FastAPI applications.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Error codes
|
|
8
|
+
from aioia_core.errors.error_codes import (
|
|
9
|
+
DATABASE_ERROR,
|
|
10
|
+
EXTERNAL_SERVICE_ERROR,
|
|
11
|
+
FORBIDDEN,
|
|
12
|
+
INTERNAL_SERVER_ERROR,
|
|
13
|
+
INVALID_JSON,
|
|
14
|
+
INVALID_QUERY_PARAMS,
|
|
15
|
+
INVALID_TOKEN,
|
|
16
|
+
JWT_SECRET_NOT_CONFIGURED,
|
|
17
|
+
MISSING_REQUIRED_FIELD,
|
|
18
|
+
RESOURCE_CREATION_FAILED,
|
|
19
|
+
RESOURCE_DELETE_FAILED,
|
|
20
|
+
RESOURCE_NOT_FOUND,
|
|
21
|
+
RESOURCE_UPDATE_FAILED,
|
|
22
|
+
TOKEN_EXPIRED,
|
|
23
|
+
UNAUTHORIZED,
|
|
24
|
+
VALIDATION_ERROR,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Error responses
|
|
28
|
+
from aioia_core.errors.error_responses import (
|
|
29
|
+
ErrorResponse,
|
|
30
|
+
extract_error_code_from_exception,
|
|
31
|
+
get_error_detail_from_exception,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
# Error codes
|
|
36
|
+
"UNAUTHORIZED",
|
|
37
|
+
"FORBIDDEN",
|
|
38
|
+
"INVALID_TOKEN",
|
|
39
|
+
"TOKEN_EXPIRED",
|
|
40
|
+
"JWT_SECRET_NOT_CONFIGURED",
|
|
41
|
+
"VALIDATION_ERROR",
|
|
42
|
+
"INVALID_JSON",
|
|
43
|
+
"MISSING_REQUIRED_FIELD",
|
|
44
|
+
"INVALID_QUERY_PARAMS",
|
|
45
|
+
"RESOURCE_NOT_FOUND",
|
|
46
|
+
"RESOURCE_CREATION_FAILED",
|
|
47
|
+
"RESOURCE_UPDATE_FAILED",
|
|
48
|
+
"RESOURCE_DELETE_FAILED",
|
|
49
|
+
"INTERNAL_SERVER_ERROR",
|
|
50
|
+
"DATABASE_ERROR",
|
|
51
|
+
"EXTERNAL_SERVICE_ERROR",
|
|
52
|
+
# Error responses
|
|
53
|
+
"ErrorResponse",
|
|
54
|
+
"extract_error_code_from_exception",
|
|
55
|
+
"get_error_detail_from_exception",
|
|
56
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Error codes for consistent error handling across FastAPI endpoints
|
|
2
|
+
# These constants ensure standardized error identification for frontend applications
|
|
3
|
+
|
|
4
|
+
# Authentication & Authorization errors
|
|
5
|
+
UNAUTHORIZED = "UNAUTHORIZED" # User is not authenticated
|
|
6
|
+
FORBIDDEN = "FORBIDDEN" # User lacks permission for the requested resource
|
|
7
|
+
INVALID_TOKEN = "INVALID_TOKEN" # JWT token is invalid or malformed
|
|
8
|
+
TOKEN_EXPIRED = "TOKEN_EXPIRED" # JWT token has expired
|
|
9
|
+
JWT_SECRET_NOT_CONFIGURED = "JWT_SECRET_NOT_CONFIGURED" # Server configuration error
|
|
10
|
+
|
|
11
|
+
# Validation & Request errors
|
|
12
|
+
VALIDATION_ERROR = "VALIDATION_ERROR" # Request data validation failed
|
|
13
|
+
INVALID_JSON = "INVALID_JSON" # Request body contains invalid JSON
|
|
14
|
+
MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD" # Required field is missing
|
|
15
|
+
INVALID_QUERY_PARAMS = "INVALID_QUERY_PARAMS" # Query parameters are invalid
|
|
16
|
+
|
|
17
|
+
# Resource Management errors
|
|
18
|
+
RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND" # Requested resource does not exist
|
|
19
|
+
RESOURCE_CREATION_FAILED = "RESOURCE_CREATION_FAILED" # Failed to create resource
|
|
20
|
+
RESOURCE_UPDATE_FAILED = "RESOURCE_UPDATE_FAILED" # Failed to update resource
|
|
21
|
+
RESOURCE_DELETE_FAILED = "RESOURCE_DELETE_FAILED" # Failed to delete resource
|
|
22
|
+
|
|
23
|
+
# System & Server errors
|
|
24
|
+
INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR" # Unexpected server error
|
|
25
|
+
DATABASE_ERROR = "DATABASE_ERROR" # Database operation failed
|
|
26
|
+
EXTERNAL_SERVICE_ERROR = "EXTERNAL_SERVICE_ERROR" # External service unavailable
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Error response models and utility functions for FastAPI applications."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
|
|
5
|
+
from fastapi import HTTPException
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from aioia_core.errors import error_codes
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ErrorResponse(BaseModel):
|
|
12
|
+
"""
|
|
13
|
+
Standardized error response model following RFC 9457 Problem Details for HTTP APIs.
|
|
14
|
+
This model provides consistent error information across all FastAPI endpoints.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
status: int = Field(
|
|
18
|
+
...,
|
|
19
|
+
description="HTTP status code",
|
|
20
|
+
)
|
|
21
|
+
detail: str = Field(
|
|
22
|
+
...,
|
|
23
|
+
description="Human-readable error message",
|
|
24
|
+
)
|
|
25
|
+
code: str = Field(
|
|
26
|
+
...,
|
|
27
|
+
description="Machine-readable error code for client-side error handling",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
class Config:
|
|
31
|
+
json_schema_extra = {
|
|
32
|
+
"examples": [
|
|
33
|
+
{
|
|
34
|
+
"status": 401,
|
|
35
|
+
"detail": "Invalid authentication credentials",
|
|
36
|
+
"code": "INVALID_TOKEN",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"status": 404,
|
|
40
|
+
"detail": "Resource not found: item_123",
|
|
41
|
+
"code": "RESOURCE_NOT_FOUND",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"status": 422,
|
|
45
|
+
"detail": "Validation error in field 'email': Invalid email format",
|
|
46
|
+
"code": "VALIDATION_ERROR",
|
|
47
|
+
},
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def extract_error_code_from_exception(exc: HTTPException) -> str:
|
|
53
|
+
"""
|
|
54
|
+
HTTPException에서 에러 코드를 추출합니다.
|
|
55
|
+
detail이 dict 형태인 경우 code 필드를 찾고, 없으면 기본값 반환
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
exc: HTTPException 인스턴스
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
str: 에러 코드
|
|
62
|
+
"""
|
|
63
|
+
if isinstance(exc.detail, dict) and "code" in exc.detail:
|
|
64
|
+
return cast(dict[str, Any], exc.detail)["code"]
|
|
65
|
+
|
|
66
|
+
# 상태 코드별 기본 에러 코드 매핑
|
|
67
|
+
default_codes = {
|
|
68
|
+
401: error_codes.UNAUTHORIZED,
|
|
69
|
+
403: error_codes.FORBIDDEN,
|
|
70
|
+
404: error_codes.RESOURCE_NOT_FOUND,
|
|
71
|
+
422: error_codes.VALIDATION_ERROR,
|
|
72
|
+
500: error_codes.INTERNAL_SERVER_ERROR,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return default_codes.get(exc.status_code, error_codes.INTERNAL_SERVER_ERROR)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_error_detail_from_exception(exc: HTTPException) -> str:
|
|
79
|
+
"""
|
|
80
|
+
HTTPException에서 에러 상세 메시지를 추출합니다.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
exc: HTTPException 인스턴스
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
str: 에러 상세 메시지
|
|
87
|
+
"""
|
|
88
|
+
if isinstance(exc.detail, dict) and "detail" in exc.detail:
|
|
89
|
+
return cast(dict[str, Any], exc.detail)["detail"]
|
|
90
|
+
if isinstance(exc.detail, str):
|
|
91
|
+
return exc.detail
|
|
92
|
+
return str(exc.detail)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC
|
|
4
|
+
from typing import Generic, TypeVar
|
|
5
|
+
|
|
6
|
+
from sqlalchemy.orm import Session, sessionmaker
|
|
7
|
+
|
|
8
|
+
from aioia_core.protocols import DatabaseManagerProtocol
|
|
9
|
+
|
|
10
|
+
# ManagerType을 DatabaseManagerProtocol에 바인딩
|
|
11
|
+
ManagerType = TypeVar("ManagerType", bound=DatabaseManagerProtocol)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseManagerFactory(ABC, Generic[ManagerType]):
|
|
15
|
+
"""
|
|
16
|
+
기본 매니저 팩토리 클래스
|
|
17
|
+
|
|
18
|
+
이 클래스는 데이터베이스 저장소를 사용하는 매니저 인스턴스를 생성하기 위한
|
|
19
|
+
기본 팩토리 패턴을 구현합니다.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
db_session_factory: SQLAlchemy 세션 팩토리
|
|
23
|
+
manager_class: 생성할 매니저 클래스
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
db_session_factory: sessionmaker,
|
|
29
|
+
manager_class: type[ManagerType],
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
BaseManagerFactory 초기화
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
db_session_factory: SQLAlchemy 세션 팩토리
|
|
36
|
+
manager_class: 생성할 매니저 클래스
|
|
37
|
+
"""
|
|
38
|
+
self.db_session_factory = db_session_factory
|
|
39
|
+
self.manager_class = manager_class
|
|
40
|
+
|
|
41
|
+
def create_manager(self, db_session: Session | None = None) -> ManagerType:
|
|
42
|
+
"""
|
|
43
|
+
매니저 인스턴스를 생성합니다.
|
|
44
|
+
|
|
45
|
+
이 메서드는 매니저 클래스의 인스턴스를 생성하고 반환합니다.
|
|
46
|
+
db_session이 제공되지 않은 경우 새로운 세션을 생성합니다.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
db_session: 선택적 데이터베이스 세션. None인 경우 새로운 세션을 생성합니다.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
생성된 매니저 인스턴스
|
|
53
|
+
"""
|
|
54
|
+
session = db_session if db_session is not None else self.db_session_factory()
|
|
55
|
+
return self.manager_class(session)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""FastAPI utilities for AIoIA projects."""
|
|
2
|
+
|
|
3
|
+
from aioia_core.fastapi.base_crud_router import (
|
|
4
|
+
BaseCrudRouter,
|
|
5
|
+
DeleteResponse,
|
|
6
|
+
PaginatedResponse,
|
|
7
|
+
SingleItemResponse,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"BaseCrudRouter",
|
|
12
|
+
"PaginatedResponse",
|
|
13
|
+
"SingleItemResponse",
|
|
14
|
+
"DeleteResponse",
|
|
15
|
+
]
|