ohmyapi 0.1.23__py3-none-any.whl → 0.1.25__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.
- ohmyapi/builtin/auth/routes.py +2 -4
- ohmyapi/builtin/demo/models.py +8 -8
- ohmyapi/builtin/demo/routes.py +21 -18
- ohmyapi/core/runtime.py +7 -4
- ohmyapi/core/templates/app/routes.py.j2 +6 -3
- ohmyapi/core/templates/project/pyproject.toml.j2 +1 -12
- ohmyapi/core/templates/project/settings.py.j2 +1 -1
- {ohmyapi-0.1.23.dist-info → ohmyapi-0.1.25.dist-info}/METADATA +33 -21
- {ohmyapi-0.1.23.dist-info → ohmyapi-0.1.25.dist-info}/RECORD +11 -11
- {ohmyapi-0.1.23.dist-info → ohmyapi-0.1.25.dist-info}/WHEEL +0 -0
- {ohmyapi-0.1.23.dist-info → ohmyapi-0.1.25.dist-info}/entry_points.txt +0 -0
ohmyapi/builtin/auth/routes.py
CHANGED
@@ -64,9 +64,7 @@ class TokenType(str, Enum):
|
|
64
64
|
refresh = "refresh"
|
65
65
|
|
66
66
|
|
67
|
-
def claims(
|
68
|
-
token_type: TokenType, user: User, groups: List[Group] = []
|
69
|
-
) -> Claims:
|
67
|
+
def claims(token_type: TokenType, user: User, groups: List[Group] = []) -> Claims:
|
70
68
|
return Claims(
|
71
69
|
type=token_type,
|
72
70
|
sub=str(user.id),
|
@@ -83,7 +81,7 @@ def claims(
|
|
83
81
|
|
84
82
|
def create_token(claims: Claims, expires_in: int) -> str:
|
85
83
|
to_encode = claims.model_dump()
|
86
|
-
to_encode[
|
84
|
+
to_encode["exp"] = int(time.time()) + expires_in
|
87
85
|
token = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM)
|
88
86
|
if isinstance(token, bytes):
|
89
87
|
token = token.decode("utf-8")
|
ohmyapi/builtin/demo/models.py
CHANGED
@@ -10,9 +10,9 @@ class Team(Model):
|
|
10
10
|
id: UUID = field.data.UUIDField(primary_key=True)
|
11
11
|
name: str = field.TextField()
|
12
12
|
members: field.ManyToManyRelation[User] = field.ManyToManyField(
|
13
|
-
|
13
|
+
"ohmyapi_auth.User",
|
14
14
|
related_name="tournament_teams",
|
15
|
-
through=
|
15
|
+
through="user_tournament_teams",
|
16
16
|
)
|
17
17
|
|
18
18
|
def __str__(self):
|
@@ -32,19 +32,19 @@ class Event(Model):
|
|
32
32
|
id: UUID = field.data.UUIDField(primary_key=True)
|
33
33
|
name: str = field.TextField()
|
34
34
|
tournament: field.ForeignKeyRelation[Tournament] = field.ForeignKeyField(
|
35
|
-
|
36
|
-
related_name=
|
35
|
+
"ohmyapi_demo.Tournament",
|
36
|
+
related_name="events",
|
37
37
|
)
|
38
38
|
participants: field.ManyToManyRelation[Team] = field.ManyToManyField(
|
39
|
-
|
40
|
-
related_name=
|
41
|
-
through=
|
39
|
+
"ohmyapi_demo.Team",
|
40
|
+
related_name="events",
|
41
|
+
through="event_team",
|
42
42
|
)
|
43
43
|
modified: datetime = field.DatetimeField(auto_now=True)
|
44
44
|
prize: Decimal = field.DecimalField(max_digits=10, decimal_places=2, null=True)
|
45
45
|
|
46
46
|
class Schema:
|
47
|
-
exclude = [
|
47
|
+
exclude = ["tournament_id"]
|
48
48
|
|
49
49
|
def __str__(self):
|
50
50
|
return self.name
|
ohmyapi/builtin/demo/routes.py
CHANGED
@@ -11,37 +11,41 @@ from typing import List
|
|
11
11
|
router = APIRouter(prefix="/tournemant")
|
12
12
|
|
13
13
|
|
14
|
-
@router.get(
|
15
|
-
|
16
|
-
|
14
|
+
@router.get(
|
15
|
+
"/", tags=["tournament"], response_model=List[models.Tournament.Schema.model]
|
16
|
+
)
|
17
17
|
async def list():
|
18
18
|
"""List all tournaments."""
|
19
|
-
return await models.Tournament.Schema.model.from_queryset(Tournament.all())
|
19
|
+
return await models.Tournament.Schema.model.from_queryset(models.Tournament.all())
|
20
20
|
|
21
21
|
|
22
|
-
@router.post("/",
|
23
|
-
tags=["tournament"],
|
24
|
-
status_code=HTTPStatus.CREATED)
|
22
|
+
@router.post("/", tags=["tournament"], status_code=HTTPStatus.CREATED)
|
25
23
|
async def post(tournament: models.Tournament.Schema.readonly):
|
26
24
|
"""Create tournament."""
|
27
|
-
return await models.Tournament.Schema.model.from_queryset(
|
25
|
+
return await models.Tournament.Schema.model.from_queryset(
|
26
|
+
models.Tournament.create(**tournament.model_dump())
|
27
|
+
)
|
28
28
|
|
29
29
|
|
30
|
-
@router.get("/{id}",
|
31
|
-
tags=["tournament"],
|
32
|
-
response_model=models.Tournament.Schema.model)
|
30
|
+
@router.get("/{id}", tags=["tournament"], response_model=models.Tournament.Schema.model)
|
33
31
|
async def get(id: str):
|
34
32
|
"""Get tournament by id."""
|
35
|
-
return await models.Tournament.Schema.model.from_queryset(
|
33
|
+
return await models.Tournament.Schema.model.from_queryset(
|
34
|
+
models.Tournament.get(id=id)
|
35
|
+
)
|
36
36
|
|
37
37
|
|
38
|
-
@router.put(
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
@router.put(
|
39
|
+
"/{id}",
|
40
|
+
tags=["tournament"],
|
41
|
+
response_model=models.Tournament.Schema.model,
|
42
|
+
status_code=HTTPStatus.ACCEPTED,
|
43
|
+
)
|
42
44
|
async def put(tournament: models.Tournament.Schema.model):
|
43
45
|
"""Update tournament."""
|
44
|
-
return await models.Tournament.Schema.model.from_queryset(
|
46
|
+
return await models.Tournament.Schema.model.from_queryset(
|
47
|
+
models.Tournament.update(**tournament.model_dump())
|
48
|
+
)
|
45
49
|
|
46
50
|
|
47
51
|
@router.delete("/{id}", tags=["tournament"])
|
@@ -51,4 +55,3 @@ async def delete(id: str):
|
|
51
55
|
return await tournament.delete()
|
52
56
|
except DoesNotExist:
|
53
57
|
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="not found")
|
54
|
-
|
ohmyapi/core/runtime.py
CHANGED
@@ -211,7 +211,7 @@ class App:
|
|
211
211
|
self.model_modules: List[str] = []
|
212
212
|
|
213
213
|
# The APIRouter
|
214
|
-
self.router:
|
214
|
+
self.router: APIRouter = APIRouter()
|
215
215
|
|
216
216
|
# Import the app, so its __init__.py runs.
|
217
217
|
importlib.import_module(self.name)
|
@@ -226,9 +226,12 @@ class App:
|
|
226
226
|
# Locate the APIRouter
|
227
227
|
try:
|
228
228
|
routes_mod = importlib.import_module(f"{self.name}.routes")
|
229
|
-
|
230
|
-
|
231
|
-
|
229
|
+
for attr_name in dir(routes_mod):
|
230
|
+
if attr_name.startswith("__"):
|
231
|
+
continue
|
232
|
+
attr = getattr(routes_mod, attr_name)
|
233
|
+
if isinstance(attr, APIRouter):
|
234
|
+
self.router.include_router(attr)
|
232
235
|
except ModuleNotFoundError:
|
233
236
|
pass
|
234
237
|
|
@@ -4,13 +4,16 @@ from . import models
|
|
4
4
|
|
5
5
|
from typing import List
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# OhMyAPI will automatically pick up all instances of `fastapi.APIRouter` and
|
8
|
+
# add their routes to the main project router.
|
9
|
+
#
|
10
|
+
# Note:
|
11
|
+
# Use prefixes wisely to avoid cross-app namespace-collisions!
|
9
12
|
# Tags improve the UX of the OpenAPI docs at /docs.
|
13
|
+
#
|
10
14
|
router = APIRouter(prefix="/{{ app_name }}", tags=['{{ app_name }}'])
|
11
15
|
|
12
16
|
|
13
|
-
|
14
17
|
@router.get("/")
|
15
18
|
async def list():
|
16
19
|
"""List all ..."""
|
@@ -10,18 +10,7 @@ readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
11
11
|
|
12
12
|
dependencies = [
|
13
|
-
"
|
14
|
-
"jinja2 >=3.1.6,<4.0.0",
|
15
|
-
"fastapi >=0.117.1,<0.118.0",
|
16
|
-
"tortoise-orm >=0.25.1,<0.26.0",
|
17
|
-
"aerich >=0.9.1,<0.10.0",
|
18
|
-
"uvicorn >=0.36.0,<0.37.0",
|
19
|
-
"ipython >=9.5.0,<10.0.0",
|
20
|
-
"passlib >=1.7.4,<2.0.0",
|
21
|
-
"pyjwt >=2.10.1,<3.0.0",
|
22
|
-
"python-multipart >=0.0.20,<0.0.21",
|
23
|
-
"crypto >=1.4.1,<2.0.0",
|
24
|
-
"argon2-cffi >=25.1.0,<26.0.0",
|
13
|
+
"ohmyapi (>=0.1.0,<0.2.0)"
|
25
14
|
]
|
26
15
|
|
27
16
|
[tool.poetry.group.dev.dependencies]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ohmyapi
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.25
|
4
4
|
Summary: A Django-like but async web-framework based on FastAPI and TortoiseORM.
|
5
5
|
License-Expression: MIT
|
6
6
|
Keywords: fastapi,tortoise,orm,async,web-framework
|
@@ -34,29 +34,26 @@ Description-Content-Type: text/markdown
|
|
34
34
|
|
35
35
|
> Think: Django RestFramework, but less clunky and 100% async.
|
36
36
|
|
37
|
-
OhMyAPI is a Django-flavored web-application scaffolding framework and management layer
|
38
|
-
|
37
|
+
OhMyAPI is a Django-flavored web-application scaffolding framework and management layer,
|
38
|
+
built around FastAPI and TortoiseORM and is thus 100% async.
|
39
39
|
|
40
|
-
It is ***blazingly fast***, ***fun to use*** and comes with ***batteries included***!
|
40
|
+
It is ***blazingly fast***, extremely ***fun to use*** and comes with ***batteries included***!
|
41
41
|
|
42
42
|
**Features**
|
43
43
|
|
44
|
-
- Django-like project
|
45
|
-
- Django-like
|
46
|
-
- Django-like models via TortoiseORM
|
47
|
-
- Django-like `Model.Meta` class for model configuration
|
48
|
-
- Easily convert your query results to `pydantic` models via `Model.Schema`
|
49
|
-
- Django-like migrations (`makemigrations` & `migrate`) via Aerich
|
44
|
+
- Django-like project structure and application directories
|
45
|
+
- Django-like per-app migrations (`makemigrations` & `migrate`) via Aerich
|
50
46
|
- Django-like CLI tooling (`startproject`, `startapp`, `shell`, `serve`, etc)
|
51
|
-
-
|
47
|
+
- Customizable pydantic model serializer built-in
|
48
|
+
- Various optional built-in apps you can hook into your project
|
52
49
|
- Highly configurable and customizable
|
53
50
|
- 100% async
|
54
51
|
|
55
52
|
**Goals**
|
56
53
|
|
57
|
-
- combine FastAPI
|
58
|
-
- tie everything neatly together into a concise API
|
59
|
-
-
|
54
|
+
- combine `FastAPI`, `TortoiseORM`, `Aerich` migrations and `Pydantic` into a high-productivity web-application framework
|
55
|
+
- tie everything neatly together into a concise and straight-forward API
|
56
|
+
- ***AVOID*** adding any abstractions on top, unless they make things extremely convenient
|
60
57
|
|
61
58
|
---
|
62
59
|
|
@@ -65,7 +62,7 @@ It is ***blazingly fast***, ***fun to use*** and comes with ***batteries include
|
|
65
62
|
**Creating a Project**
|
66
63
|
|
67
64
|
```
|
68
|
-
|
65
|
+
pipx install ohmyapi
|
69
66
|
ohmyapi startproject myproject
|
70
67
|
cd myproject
|
71
68
|
```
|
@@ -162,24 +159,29 @@ from ohmyapi.db.exceptions import DoesNotExist
|
|
162
159
|
|
163
160
|
from .models import Tournament
|
164
161
|
|
165
|
-
#
|
166
|
-
#
|
162
|
+
# OhMyAPI will automatically pick up all instances of `fastapi.APIRouter` and
|
163
|
+
# add their routes to the main project router.
|
164
|
+
#
|
165
|
+
# Note:
|
166
|
+
# Use prefixes wisely to avoid cross-app namespace-collisions!
|
167
167
|
# Tags improve the UX of the OpenAPI docs at /docs.
|
168
|
-
|
168
|
+
#
|
169
|
+
tournament_router = APIRouter(prefix="/tournament", tags=['Tournament'])
|
169
170
|
|
170
|
-
|
171
|
+
|
172
|
+
@tournament_router.get("/")
|
171
173
|
async def list():
|
172
174
|
queryset = Tournament.all()
|
173
175
|
return await Tournament.Schema.model.from_queryset(queryset)
|
174
176
|
|
175
177
|
|
176
|
-
@
|
178
|
+
@tournament_router.post("/", status_code=HTTPStatus.CREATED)
|
177
179
|
async def post(tournament: Tournament.Schema.readonly):
|
178
180
|
queryset = Tournament.create(**payload.model_dump())
|
179
181
|
return await Tournament.Schema.model.from_queryset(queryset)
|
180
182
|
|
181
183
|
|
182
|
-
@
|
184
|
+
@tournament_router.get("/:id")
|
183
185
|
async def get(id: str):
|
184
186
|
try:
|
185
187
|
queryset = Tournament.get(id=id)
|
@@ -187,6 +189,16 @@ async def get(id: str):
|
|
187
189
|
except DoesNotExist:
|
188
190
|
raise HTTPException(status_code=404, detail="not found")
|
189
191
|
|
192
|
+
|
193
|
+
@tournament_router.delete("/:id")
|
194
|
+
async def delete(id: str):
|
195
|
+
try:
|
196
|
+
tournament = await Tournament.get(id=id)
|
197
|
+
return await Tournament.Schema.model.from_queryset(tournament.delete())
|
198
|
+
except DoesNotExist:
|
199
|
+
raise HTTPException(status_code=404, detail="not found")
|
200
|
+
|
201
|
+
|
190
202
|
...
|
191
203
|
```
|
192
204
|
|
@@ -3,26 +3,26 @@ ohmyapi/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
3
3
|
ohmyapi/builtin/auth/__init__.py,sha256=vOVCSJX8BALzs8h5ZW9507bjoscP37bncMjdMmBXcMM,42
|
4
4
|
ohmyapi/builtin/auth/models.py,sha256=Fggg3GDVydKoZQOlXXNDsWKxehvsp8BXC1xedv0Qr34,1729
|
5
5
|
ohmyapi/builtin/auth/permissions.py,sha256=mxsnhF_UGesTFle7v1JHORkNODtQ0qanAL3FtOcMCEY,145
|
6
|
-
ohmyapi/builtin/auth/routes.py,sha256=
|
6
|
+
ohmyapi/builtin/auth/routes.py,sha256=rhQJ1GnBJctB6jrKAl415bwoaMFypDqoVQ9ZpHyi9v4,6312
|
7
7
|
ohmyapi/builtin/demo/__init__.py,sha256=k1rGtOmMPVZJ1fMPELY0v3k70WyzSp18pstJTkCdFr0,42
|
8
|
-
ohmyapi/builtin/demo/models.py,sha256=
|
9
|
-
ohmyapi/builtin/demo/routes.py,sha256=
|
8
|
+
ohmyapi/builtin/demo/models.py,sha256=N3LnHLEa5wYBvaQBImCR4SdZvRYGuwM_iyLCeh9QY8s,1403
|
9
|
+
ohmyapi/builtin/demo/routes.py,sha256=DQ-wO9O0lTJkYqAjVSp0jBs9pavs5vS9IlHXRePU-Ng,1806
|
10
10
|
ohmyapi/cli.py,sha256=dJVNgpW5S4rCc619AEEKBKuEIAmQs153Ls0ZVaea48w,4173
|
11
11
|
ohmyapi/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
ohmyapi/core/runtime.py,sha256=
|
12
|
+
ohmyapi/core/runtime.py,sha256=i-yeFN_mwk2EIisKWM78yO09lPvApX9J_gr_OXmXlGc,9553
|
13
13
|
ohmyapi/core/scaffolding.py,sha256=SA0SYFd7VcqkOn9xuXgj-yOoVqCZMJo68GGFbm34GE4,2663
|
14
14
|
ohmyapi/core/templates/app/__init__.py.j2,sha256=QwVIQVUGZVhdH1d4NrvL7NTsK4-T4cihzYs8UVX2dt4,43
|
15
15
|
ohmyapi/core/templates/app/models.py.j2,sha256=_3w-vFJ5fgsmncsCv34k_wyCMF78jufbSSglns4gbb0,119
|
16
|
-
ohmyapi/core/templates/app/routes.py.j2,sha256=
|
16
|
+
ohmyapi/core/templates/app/routes.py.j2,sha256=HQOf_9VqMgP3CCtf5IHNePubomiWKEf8D6qed33uLBI,948
|
17
17
|
ohmyapi/core/templates/project/README.md.j2,sha256=SjR4JIrg-8XRE-UntUDwiw8jDpYitD_UjwoKkYJ7GLw,22
|
18
|
-
ohmyapi/core/templates/project/pyproject.toml.j2,sha256=
|
19
|
-
ohmyapi/core/templates/project/settings.py.j2,sha256=
|
18
|
+
ohmyapi/core/templates/project/pyproject.toml.j2,sha256=3ZqO6FX9Bhq8OAZl8nHPXCiWxl3gAffIF-LsC_-K9Us,538
|
19
|
+
ohmyapi/core/templates/project/settings.py.j2,sha256=So6w1OiL_jU-FyeT8IHueDjGNuEoSkYhabhHpne2fUU,140
|
20
20
|
ohmyapi/db/__init__.py,sha256=5QKUycxnN83DOUD_Etoee9tEOYjnZ74deqrSOOx_MiQ,204
|
21
21
|
ohmyapi/db/exceptions.py,sha256=vb4IIUoeYAY6sK42zRtjMy-39IFVi_Qb6mWySTY0jYw,34
|
22
22
|
ohmyapi/db/model/__init__.py,sha256=k3StTNuKatpwZo_Z5JBFa-927eJrzibFE8U4SA82asc,32
|
23
23
|
ohmyapi/db/model/model.py,sha256=WTf41ByCtfk9c_O6QCsO9KA0avHL3zGMZ6SEdw5GOuc,2420
|
24
24
|
ohmyapi/router.py,sha256=6Exv6sVPVyiIYxxAQbxQhFRX74MKTUPWXIBwC7UZ-ww,82
|
25
|
-
ohmyapi-0.1.
|
26
|
-
ohmyapi-0.1.
|
27
|
-
ohmyapi-0.1.
|
28
|
-
ohmyapi-0.1.
|
25
|
+
ohmyapi-0.1.25.dist-info/METADATA,sha256=diqmmkix3alQdWz3CHtZBvOZeFMPJHGJsx6-UTRSN1U,10040
|
26
|
+
ohmyapi-0.1.25.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
|
27
|
+
ohmyapi-0.1.25.dist-info/entry_points.txt,sha256=wb3lw8-meAlpiv1mqcQ3m25ukL7djagU_w89GkrC37k,43
|
28
|
+
ohmyapi-0.1.25.dist-info/RECORD,,
|
File without changes
|
File without changes
|