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.
@@ -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['exp'] = int(time.time()) + expires_in
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")
@@ -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
- 'ohmyapi_auth.User',
13
+ "ohmyapi_auth.User",
14
14
  related_name="tournament_teams",
15
- through='user_tournament_teams',
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
- 'ohmyapi_demo.Tournament',
36
- related_name='events',
35
+ "ohmyapi_demo.Tournament",
36
+ related_name="events",
37
37
  )
38
38
  participants: field.ManyToManyRelation[Team] = field.ManyToManyField(
39
- 'ohmyapi_demo.Team',
40
- related_name='events',
41
- through='event_team',
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 = ['tournament_id']
47
+ exclude = ["tournament_id"]
48
48
 
49
49
  def __str__(self):
50
50
  return self.name
@@ -11,37 +11,41 @@ from typing import List
11
11
  router = APIRouter(prefix="/tournemant")
12
12
 
13
13
 
14
- @router.get("/",
15
- tags=["tournament"],
16
- response_model=List[models.Tournament.Schema.model])
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(models.Tournament.create(**tournament.model_dump()))
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(models.Tournament.get(id=id))
33
+ return await models.Tournament.Schema.model.from_queryset(
34
+ models.Tournament.get(id=id)
35
+ )
36
36
 
37
37
 
38
- @router.put("/{id}",
39
- tags=["tournament"],
40
- response_model=models.Tournament.Schema.model,
41
- status_code=HTTPStatus.ACCEPTED)
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(models.Tournament.update(**tournament.model_dump()))
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: Optional[APIRouter] = None
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
- router = getattr(routes_mod, "router", None)
230
- if isinstance(router, APIRouter):
231
- self.router = router
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
- # Expose your app's routes via `router = fastapi.APIRouter`.
8
- # Use prefixes wisely to avoid cross-app namespace-collisions.
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
- "typer >=0.19.1,<0.20.0",
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]
@@ -2,6 +2,6 @@
2
2
  PROJECT_NAME = "MyProject"
3
3
  DATABASE_URL = "sqlite://db.sqlite3"
4
4
  INSTALLED_APPS = [
5
- #'ohmyapi_auth',
5
+ #"ohmyapi_auth",
6
6
  ]
7
7
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ohmyapi
3
- Version: 0.1.23
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
- Built around FastAPI and TortoiseORM, it is 100% async.
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-layout and -structure
45
- - Django-like project-level settings.py
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
- - Various optional builtin apps you can hook into your project
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, TortoiseORM and Aerich migrations into a high-productivity web-application framework
58
- - tie everything neatly together into a concise API
59
- - while ***AVOIDING*** any additional abstractions ontop of Tortoise's model-system or FastAPI's routing system
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
- pip install ohmyapi
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
- # Expose your app's routes via `router = fastapi.APIRouter`.
166
- # Use prefixes wisely to avoid cross-app namespace-collisions.
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
- router = APIRouter(prefix="/tournament", tags=['Tournament'])
168
+ #
169
+ tournament_router = APIRouter(prefix="/tournament", tags=['Tournament'])
169
170
 
170
- @router.get("/")
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
- @router.post("/", status_code=HTTPStatus.CREATED)
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
- @router.get("/:id")
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=e6i9AanJqj1RK8VQVXwNV-Pv8R3X8I70SgaDtbCYUIE,6318
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=8Id0dHPuow_Dtt_337UV3VTxvtVAllaVeImvstqiqdE,1403
9
- ohmyapi/builtin/demo/routes.py,sha256=MQaPCz43v4kTv9_oz44up1j77Ra1SqSN9i3vN26xllU,1843
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=i4dI7mC59rw0blMOeVGawUm8v5id3ZllLlP8RLo1GT0,9419
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=dFpmfrfN1pwOsD6MAa_MmI7aP4kKJ2ZiijobWHsfyDs,873
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=X0VS6YT9aL3vpHFKPTfLFsdpD8423nY57ySQpSTMxmQ,895
19
- ohmyapi/core/templates/project/settings.py.j2,sha256=RBKGB8MZWPM3Bp0a57Y1YrSvSXxh502TUnJqbbu48Ig,138
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.23.dist-info/METADATA,sha256=HPmvXFChCOfKmKOn6u6JlcItr_2_UrXk9MoA7aCBl2Y,9727
26
- ohmyapi-0.1.23.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
27
- ohmyapi-0.1.23.dist-info/entry_points.txt,sha256=wb3lw8-meAlpiv1mqcQ3m25ukL7djagU_w89GkrC37k,43
28
- ohmyapi-0.1.23.dist-info/RECORD,,
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,,