FastAPI-fastkit 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl

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.
Files changed (127) hide show
  1. fastapi_fastkit/__init__.py +10 -1
  2. fastapi_fastkit/backend/main.py +482 -482
  3. fastapi_fastkit/backend/transducer.py +106 -106
  4. fastapi_fastkit/cli.py +664 -631
  5. fastapi_fastkit/core/settings.py +155 -155
  6. fastapi_fastkit/fastapi_project_template/README.md +90 -90
  7. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.env-tpl +1 -1
  8. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/.gitignore-tpl +30 -30
  9. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +107 -107
  10. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +36 -36
  11. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/format.sh-tpl +5 -5
  12. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/lint.sh-tpl +5 -5
  13. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/run-server.sh-tpl +8 -8
  14. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/scripts/test.sh-tpl +6 -6
  15. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.cfg-tpl +14 -14
  16. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +25 -25
  17. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +9 -9
  18. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +57 -57
  19. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +64 -64
  20. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +21 -21
  21. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +26 -26
  22. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/mocks/mock_items.json-tpl +8 -8
  23. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +22 -22
  24. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +42 -42
  25. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/test_items.py-tpl +48 -48
  26. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.env-tpl +1 -1
  27. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/.gitignore-tpl +191 -191
  28. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/README.md-tpl +156 -156
  29. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +36 -36
  30. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/format.sh-tpl +5 -5
  31. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/lint.sh-tpl +5 -5
  32. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/run-server.sh-tpl +8 -8
  33. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/scripts/test.sh-tpl +6 -6
  34. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.cfg-tpl +12 -12
  35. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +27 -27
  36. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/.DS_Store +0 -0
  37. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +9 -9
  38. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +172 -172
  39. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +64 -64
  40. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +21 -21
  41. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/exceptions.py-tpl +103 -103
  42. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/pagination.py-tpl +72 -72
  43. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +39 -39
  44. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/mocks/mock_items.json-tpl +8 -8
  45. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +49 -49
  46. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +22 -22
  47. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/utils/documents.py-tpl +20 -20
  48. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +42 -42
  49. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/test_items.py-tpl +61 -61
  50. fastapi_fastkit/fastapi_project_template/fastapi-default/README.md-tpl +101 -101
  51. fastapi_fastkit/fastapi_project_template/fastapi-default/scripts/run-server.sh-tpl +8 -8
  52. fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +22 -22
  53. fastapi_fastkit/fastapi_project_template/fastapi-default/src/mocks/mock_items.json-tpl +8 -8
  54. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +30 -30
  55. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +44 -44
  56. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.env-tpl +1 -1
  57. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/.gitignore-tpl +30 -30
  58. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +23 -23
  59. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +119 -119
  60. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +36 -36
  61. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/format.sh-tpl +5 -5
  62. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/lint.sh-tpl +5 -5
  63. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/run-server.sh-tpl +8 -8
  64. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/scripts/test.sh-tpl +6 -6
  65. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.cfg-tpl +13 -13
  66. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +22 -22
  67. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +6 -6
  68. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +54 -54
  69. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +64 -64
  70. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +15 -15
  71. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +26 -26
  72. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/mocks/mock_items.json-tpl +8 -8
  73. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +19 -19
  74. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +30 -30
  75. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +44 -44
  76. fastapi_fastkit/fastapi_project_template/fastapi-empty/.env-tpl +1 -1
  77. fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +22 -22
  78. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +75 -75
  79. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +36 -36
  80. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.env-tpl +9 -9
  81. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.gitignore-tpl +30 -30
  82. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +23 -23
  83. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/README.md-tpl +144 -144
  84. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/alembic.ini-tpl +119 -119
  85. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/docker-compose.yml-tpl +44 -44
  86. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +41 -41
  87. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/format.sh-tpl +5 -5
  88. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/lint.sh-tpl +5 -5
  89. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/pre-start.sh-tpl +16 -16
  90. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/run-server.sh-tpl +8 -8
  91. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/scripts/test.sh-tpl +10 -10
  92. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.cfg-tpl +13 -13
  93. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +25 -25
  94. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/README-tpl +1 -1
  95. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +85 -85
  96. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/script.py.mako-tpl +26 -26
  97. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +37 -37
  98. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +11 -11
  99. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/deps.py-tpl +19 -19
  100. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +109 -109
  101. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +88 -88
  102. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +53 -53
  103. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +102 -102
  104. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +45 -45
  105. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +54 -54
  106. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/backend_pre_start.py-tpl +39 -39
  107. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/init_data.py-tpl +23 -23
  108. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/utils/tests_pre_start.py-tpl +39 -39
  109. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +63 -63
  110. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +44 -44
  111. fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +64 -64
  112. fastapi_fastkit/fastapi_project_template/modules/crud/new_route.py-tpl +29 -29
  113. fastapi_fastkit/fastapi_project_template/modules/schemas/new_route.py-tpl +23 -23
  114. fastapi_fastkit/logs/fastkit_debug_20250702_161423.log +21 -0
  115. fastapi_fastkit/logs/fastkit_debug_20250702_162706.log +20 -0
  116. fastapi_fastkit/logs/fastkit_debug_20250702_163010.log +21 -0
  117. fastapi_fastkit/logs/fastkit_debug_20250702_163526.log +21 -0
  118. fastapi_fastkit/logs/fastkit_debug_20250702_164053.log +21 -0
  119. fastapi_fastkit/logs/fastkit_debug_20250702_165220.log +21 -0
  120. fastapi_fastkit/logs/fastkit_debug_20250702_165647.log +21 -0
  121. fastapi_fastkit/utils/logging.py +112 -1
  122. fastapi_fastkit/utils/main.py +140 -129
  123. {fastapi_fastkit-1.0.1.dist-info → fastapi_fastkit-1.0.2.dist-info}/METADATA +13 -2
  124. {fastapi_fastkit-1.0.1.dist-info → fastapi_fastkit-1.0.2.dist-info}/RECORD +127 -119
  125. {fastapi_fastkit-1.0.1.dist-info → fastapi_fastkit-1.0.2.dist-info}/licenses/LICENSE +21 -21
  126. {fastapi_fastkit-1.0.1.dist-info → fastapi_fastkit-1.0.2.dist-info}/WHEEL +0 -0
  127. {fastapi_fastkit-1.0.1.dist-info → fastapi_fastkit-1.0.2.dist-info}/entry_points.txt +0 -0
@@ -1,64 +1,64 @@
1
- # --------------------------------------------------------------------------
2
- # Configuration module
3
- # --------------------------------------------------------------------------
4
- import secrets
5
- import warnings
6
- from typing import Annotated, Any, Literal
7
-
8
- from pydantic import AnyUrl, BeforeValidator, computed_field, model_validator
9
- from pydantic_settings import BaseSettings, SettingsConfigDict
10
- from typing_extensions import Self
11
-
12
-
13
- def parse_cors(v: Any) -> list[str] | str:
14
- if isinstance(v, str) and not v.startswith("["):
15
- return [i.strip() for i in v.split(",")]
16
- elif isinstance(v, list | str):
17
- return v
18
- raise ValueError(v)
19
-
20
-
21
- class Settings(BaseSettings):
22
- model_config = SettingsConfigDict(
23
- env_file=".env",
24
- env_ignore_empty=True,
25
- extra="ignore",
26
- )
27
-
28
- SECRET_KEY: str = secrets.token_urlsafe(32)
29
- ENVIRONMENT: Literal["development", "production"] = "development"
30
-
31
- CLIENT_ORIGIN: str = ""
32
-
33
- BACKEND_CORS_ORIGINS: Annotated[list[AnyUrl] | str, BeforeValidator(parse_cors)] = (
34
- []
35
- )
36
-
37
- @computed_field # type: ignore[prop-decorator]
38
- @property
39
- def all_cors_origins(self) -> list[str]:
40
- return [str(origin).rstrip("/") for origin in self.BACKEND_CORS_ORIGINS] + [
41
- self.CLIENT_ORIGIN
42
- ]
43
-
44
- PROJECT_NAME: str = "<project_name>"
45
-
46
- def _check_default_secret(self, var_name: str, value: str | None) -> None:
47
- if value == "changethis":
48
- message = (
49
- f'The value of {var_name} is "changethis", '
50
- "for security, please change it, at least for deployments."
51
- )
52
- if self.ENVIRONMENT == "development":
53
- warnings.warn(message, stacklevel=1)
54
- else:
55
- raise ValueError(message)
56
-
57
- @model_validator(mode="after")
58
- def _enforce_non_default_secrets(self) -> Self:
59
- self._check_default_secret("SECRET_KEY", self.SECRET_KEY)
60
-
61
- return self
62
-
63
-
64
- settings = Settings() # type: ignore
1
+ # --------------------------------------------------------------------------
2
+ # Configuration module
3
+ # --------------------------------------------------------------------------
4
+ import secrets
5
+ import warnings
6
+ from typing import Annotated, Any, Literal
7
+
8
+ from pydantic import AnyUrl, BeforeValidator, computed_field, model_validator
9
+ from pydantic_settings import BaseSettings, SettingsConfigDict
10
+ from typing_extensions import Self
11
+
12
+
13
+ def parse_cors(v: Any) -> list[str] | str:
14
+ if isinstance(v, str) and not v.startswith("["):
15
+ return [i.strip() for i in v.split(",")]
16
+ elif isinstance(v, list | str):
17
+ return v
18
+ raise ValueError(v)
19
+
20
+
21
+ class Settings(BaseSettings):
22
+ model_config = SettingsConfigDict(
23
+ env_file=".env",
24
+ env_ignore_empty=True,
25
+ extra="ignore",
26
+ )
27
+
28
+ SECRET_KEY: str = secrets.token_urlsafe(32)
29
+ ENVIRONMENT: Literal["development", "production"] = "development"
30
+
31
+ CLIENT_ORIGIN: str = ""
32
+
33
+ BACKEND_CORS_ORIGINS: Annotated[list[AnyUrl] | str, BeforeValidator(parse_cors)] = (
34
+ []
35
+ )
36
+
37
+ @computed_field # type: ignore[prop-decorator]
38
+ @property
39
+ def all_cors_origins(self) -> list[str]:
40
+ return [str(origin).rstrip("/") for origin in self.BACKEND_CORS_ORIGINS] + [
41
+ self.CLIENT_ORIGIN
42
+ ]
43
+
44
+ PROJECT_NAME: str = "<project_name>"
45
+
46
+ def _check_default_secret(self, var_name: str, value: str | None) -> None:
47
+ if value == "changethis":
48
+ message = (
49
+ f'The value of {var_name} is "changethis", '
50
+ "for security, please change it, at least for deployments."
51
+ )
52
+ if self.ENVIRONMENT == "development":
53
+ warnings.warn(message, stacklevel=1)
54
+ else:
55
+ raise ValueError(message)
56
+
57
+ @model_validator(mode="after")
58
+ def _enforce_non_default_secrets(self) -> Self:
59
+ self._check_default_secret("SECRET_KEY", self.SECRET_KEY)
60
+
61
+ return self
62
+
63
+
64
+ settings = Settings() # type: ignore
@@ -1,21 +1,21 @@
1
- # --------------------------------------------------------------------------
2
- # Item CRUD method module
3
- # --------------------------------------------------------------------------
4
- import json
5
- import os
6
- from typing import List
7
-
8
- import aiofiles # type: ignore
9
-
10
- MOCK_FILE = os.path.join(os.path.dirname(__file__), "../mocks/mock_items.json")
11
-
12
-
13
- async def read_items():
14
- async with aiofiles.open(MOCK_FILE, mode="r") as file:
15
- contents = await file.read()
16
- return json.loads(contents)
17
-
18
-
19
- async def write_items(items: List[dict]):
20
- async with aiofiles.open(MOCK_FILE, mode="w") as file:
21
- await file.write(json.dumps(items, indent=2))
1
+ # --------------------------------------------------------------------------
2
+ # Item CRUD method module
3
+ # --------------------------------------------------------------------------
4
+ import json
5
+ import os
6
+ from typing import List
7
+
8
+ import aiofiles # type: ignore
9
+
10
+ MOCK_FILE = os.path.join(os.path.dirname(__file__), "../mocks/mock_items.json")
11
+
12
+
13
+ async def read_items():
14
+ async with aiofiles.open(MOCK_FILE, mode="r") as file:
15
+ contents = await file.read()
16
+ return json.loads(contents)
17
+
18
+
19
+ async def write_items(items: List[dict]):
20
+ async with aiofiles.open(MOCK_FILE, mode="w") as file:
21
+ await file.write(json.dumps(items, indent=2))
@@ -1,26 +1,26 @@
1
- # --------------------------------------------------------------------------
2
- # Main server application module
3
- # --------------------------------------------------------------------------
4
- from contextlib import asynccontextmanager
5
-
6
- from fastapi import FastAPI
7
- from starlette.middleware.cors import CORSMiddleware
8
-
9
- from src.api.api import api_router
10
- from src.core.config import settings
11
-
12
- app = FastAPI(
13
- title=settings.PROJECT_NAME,
14
- )
15
-
16
- if settings.all_cors_origins:
17
- app.add_middleware(
18
- CORSMiddleware,
19
- allow_origins=settings.all_cors_origins,
20
- allow_credentials=True,
21
- allow_methods=["*"],
22
- allow_headers=["*"],
23
- )
24
-
25
-
26
- app.include_router(api_router)
1
+ # --------------------------------------------------------------------------
2
+ # Main server application module
3
+ # --------------------------------------------------------------------------
4
+ from contextlib import asynccontextmanager
5
+
6
+ from fastapi import FastAPI
7
+ from starlette.middleware.cors import CORSMiddleware
8
+
9
+ from src.api.api import api_router
10
+ from src.core.config import settings
11
+
12
+ app = FastAPI(
13
+ title=settings.PROJECT_NAME,
14
+ )
15
+
16
+ if settings.all_cors_origins:
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=settings.all_cors_origins,
20
+ allow_credentials=True,
21
+ allow_methods=["*"],
22
+ allow_headers=["*"],
23
+ )
24
+
25
+
26
+ app.include_router(api_router)
@@ -1,8 +1,8 @@
1
- [
2
- {
3
- "id": 1,
4
- "name": "Test Item 1",
5
- "price": 20.0,
6
- "category": "test"
7
- }
8
- ]
1
+ [
2
+ {
3
+ "id": 1,
4
+ "name": "Test Item 1",
5
+ "price": 20.0,
6
+ "category": "test"
7
+ }
8
+ ]
@@ -1,22 +1,22 @@
1
- # --------------------------------------------------------------------------
2
- # Item schema module
3
- # --------------------------------------------------------------------------
4
- from typing import Optional
5
-
6
- from pydantic import BaseModel, ConfigDict
7
-
8
-
9
- class ItemBase(BaseModel):
10
- name: str
11
- description: Optional[str] = None
12
- price: float
13
- category: str
14
-
15
-
16
- class ItemCreate(ItemBase):
17
- pass
18
-
19
-
20
- class ItemResponse(ItemBase):
21
- id: int
22
- model_config = ConfigDict(from_attributes=True)
1
+ # --------------------------------------------------------------------------
2
+ # Item schema module
3
+ # --------------------------------------------------------------------------
4
+ from typing import Optional
5
+
6
+ from pydantic import BaseModel, ConfigDict
7
+
8
+
9
+ class ItemBase(BaseModel):
10
+ name: str
11
+ description: Optional[str] = None
12
+ price: float
13
+ category: str
14
+
15
+
16
+ class ItemCreate(ItemBase):
17
+ pass
18
+
19
+
20
+ class ItemResponse(ItemBase):
21
+ id: int
22
+ model_config = ConfigDict(from_attributes=True)
@@ -1,42 +1,42 @@
1
- # --------------------------------------------------------------------------
2
- # pytest runtime configuration module
3
- # --------------------------------------------------------------------------
4
- import asyncio
5
- import os
6
- import typing
7
- from pathlib import Path
8
-
9
- import pytest
10
- import pytest_asyncio
11
- from httpx import ASGITransport, AsyncClient
12
-
13
- from src.main import app
14
-
15
- MOCK_PATH = os.path.join(os.path.dirname(__file__), "../src/mocks/mock_items.json")
16
-
17
-
18
- @pytest.fixture(scope="session")
19
- def event_loop(request) -> typing.Generator:
20
- loop = asyncio.get_event_loop()
21
- yield loop
22
- loop.close()
23
-
24
-
25
- @pytest_asyncio.fixture(scope="function", autouse=True)
26
- def mock_data_reset():
27
- # Back up original data into memory
28
- mock_path = Path(__file__).parent.parent / "src/mocks/mock_items.json"
29
- original_data = mock_path.read_text()
30
-
31
- yield
32
-
33
- # After test, restore original data
34
- mock_path.write_text(original_data)
35
-
36
-
37
- @pytest_asyncio.fixture(scope="module")
38
- async def client():
39
- async with AsyncClient(
40
- transport=ASGITransport(app=app), base_url="http://test"
41
- ) as ac:
42
- yield ac
1
+ # --------------------------------------------------------------------------
2
+ # pytest runtime configuration module
3
+ # --------------------------------------------------------------------------
4
+ import asyncio
5
+ import os
6
+ import typing
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+ import pytest_asyncio
11
+ from httpx import ASGITransport, AsyncClient
12
+
13
+ from src.main import app
14
+
15
+ MOCK_PATH = os.path.join(os.path.dirname(__file__), "../src/mocks/mock_items.json")
16
+
17
+
18
+ @pytest.fixture(scope="session")
19
+ def event_loop(request) -> typing.Generator:
20
+ loop = asyncio.get_event_loop()
21
+ yield loop
22
+ loop.close()
23
+
24
+
25
+ @pytest_asyncio.fixture(scope="function", autouse=True)
26
+ def mock_data_reset():
27
+ # Back up original data into memory
28
+ mock_path = Path(__file__).parent.parent / "src/mocks/mock_items.json"
29
+ original_data = mock_path.read_text()
30
+
31
+ yield
32
+
33
+ # After test, restore original data
34
+ mock_path.write_text(original_data)
35
+
36
+
37
+ @pytest_asyncio.fixture(scope="module")
38
+ async def client():
39
+ async with AsyncClient(
40
+ transport=ASGITransport(app=app), base_url="http://test"
41
+ ) as ac:
42
+ yield ac
@@ -1,48 +1,48 @@
1
- # --------------------------------------------------------------------------
2
- # Item endpoint testcases (Async version)
3
- # --------------------------------------------------------------------------
4
- import pytest
5
-
6
-
7
- @pytest.mark.asyncio
8
- async def test_read_all_items(client):
9
- response = await client.get("/items")
10
- assert response.status_code == 200
11
- assert len(response.json()) == 1
12
-
13
-
14
- @pytest.mark.asyncio
15
- async def test_read_item_success(client):
16
- response = await client.get("/items/1")
17
- assert response.status_code == 200
18
- assert response.json()["name"] == "Test Item 1"
19
-
20
-
21
- @pytest.mark.asyncio
22
- async def test_read_item_not_found(client):
23
- response = await client.get("/items/999")
24
- assert response.status_code == 404
25
-
26
-
27
- @pytest.mark.asyncio
28
- async def test_create_item(client):
29
- new_item = {"name": "New Item", "price": 30.0, "category": "new"}
30
- response = await client.post("/items", json=new_item)
31
- assert response.status_code == 201
32
- assert response.json()["id"] == 2
33
-
34
-
35
- @pytest.mark.asyncio
36
- async def test_update_item(client):
37
- updated_data = {"name": "Updated Item", "price": 15.0, "category": "updated"}
38
- response = await client.put("/items/1", json=updated_data)
39
- assert response.status_code == 200
40
- assert response.json()["name"] == "Updated Item"
41
-
42
-
43
- @pytest.mark.asyncio
44
- async def test_delete_item(client):
45
- response = await client.delete("/items/1")
46
- assert response.status_code == 200
47
- response = await client.get("/items/1")
48
- assert response.status_code == 404
1
+ # --------------------------------------------------------------------------
2
+ # Item endpoint testcases (Async version)
3
+ # --------------------------------------------------------------------------
4
+ import pytest
5
+
6
+
7
+ @pytest.mark.asyncio
8
+ async def test_read_all_items(client):
9
+ response = await client.get("/items")
10
+ assert response.status_code == 200
11
+ assert len(response.json()) == 1
12
+
13
+
14
+ @pytest.mark.asyncio
15
+ async def test_read_item_success(client):
16
+ response = await client.get("/items/1")
17
+ assert response.status_code == 200
18
+ assert response.json()["name"] == "Test Item 1"
19
+
20
+
21
+ @pytest.mark.asyncio
22
+ async def test_read_item_not_found(client):
23
+ response = await client.get("/items/999")
24
+ assert response.status_code == 404
25
+
26
+
27
+ @pytest.mark.asyncio
28
+ async def test_create_item(client):
29
+ new_item = {"name": "New Item", "price": 30.0, "category": "new"}
30
+ response = await client.post("/items", json=new_item)
31
+ assert response.status_code == 201
32
+ assert response.json()["id"] == 2
33
+
34
+
35
+ @pytest.mark.asyncio
36
+ async def test_update_item(client):
37
+ updated_data = {"name": "Updated Item", "price": 15.0, "category": "updated"}
38
+ response = await client.put("/items/1", json=updated_data)
39
+ assert response.status_code == 200
40
+ assert response.json()["name"] == "Updated Item"
41
+
42
+
43
+ @pytest.mark.asyncio
44
+ async def test_delete_item(client):
45
+ response = await client.delete("/items/1")
46
+ assert response.status_code == 200
47
+ response = await client.get("/items/1")
48
+ assert response.status_code == 404
@@ -1 +1 @@
1
- SECRET_KEY=changethis
1
+ SECRET_KEY=changethis