ohmyapi 0.1.0__tar.gz → 0.1.2__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.
Files changed (23) hide show
  1. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/PKG-INFO +30 -7
  2. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/README.md +29 -6
  3. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/pyproject.toml +1 -1
  4. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/builtin/auth/models.py +8 -1
  5. ohmyapi-0.1.2/src/ohmyapi/db/model/model.py +46 -0
  6. ohmyapi-0.1.0/src/ohmyapi/db/model/model.py +0 -80
  7. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/__init__.py +0 -0
  8. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/builtin/auth/__init__.py +0 -0
  9. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/builtin/auth/permissions.py +0 -0
  10. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/builtin/auth/routes.py +0 -0
  11. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/cli.py +0 -0
  12. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/__init__.py +0 -0
  13. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/runtime.py +0 -0
  14. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/scaffolding.py +0 -0
  15. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/templates/app/__init__.py.j2 +0 -0
  16. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/templates/app/models.py.j2 +0 -0
  17. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/templates/app/routes.py.j2 +0 -0
  18. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/templates/project/pyproject.toml.j2 +0 -0
  19. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/core/templates/project/settings.py.j2 +0 -0
  20. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/db/__init__.py +0 -0
  21. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/db/migration_manager.py +0 -0
  22. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/db/model/__init__.py +0 -0
  23. {ohmyapi-0.1.0 → ohmyapi-0.1.2}/src/ohmyapi/router.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ohmyapi
3
- Version: 0.1.0
3
+ Version: 0.1.2
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
@@ -28,8 +28,9 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  > OhMyAPI == Application scaffolding for FastAPI+TortoiseORM.
30
30
 
31
- OhMyAPI is a blazingly fast, async Python web application framework with batteries included.
32
- It is built around FastAPI and TortoiseORM and is thus 100% async.
31
+ OhMyAPI is a Django-flavored web-application scaffolding framework.
32
+ It is blazingly fast, async and has batteries included.
33
+ Built around FastAPI and TortoiseORM makes it 100% async.
33
34
 
34
35
  Features:
35
36
 
@@ -49,7 +50,7 @@ Features:
49
50
  **Creating a Project**
50
51
 
51
52
  ```
52
- pip install ohmyapi # TODO: not yet published
53
+ pip install ohmyapi
53
54
  ohmyapi startproject myproject
54
55
  cd myproject
55
56
  ```
@@ -119,13 +120,13 @@ router = APIRouter(prefix="/myapp")
119
120
 
120
121
  @router.get("/")
121
122
  async def list():
122
- return await Person.all()
123
+ return await Person.Schema.many.from_queryset(Person.all())
123
124
 
124
125
 
125
126
  @router.get("/:id")
126
127
  async def get(id: int):
127
128
  try:
128
- await Person.get(pk=id)
129
+ return await Person.Schema.one(Person.get(pk=id))
129
130
  except DoesNotExist:
130
131
  raise HTTPException(status_code=404, detail="item not found")
131
132
 
@@ -142,7 +143,21 @@ Similar to Django, first run:
142
143
  ohmyapi makemigrations [ <app> ] # no app means all INSTALLED_APPS
143
144
  ```
144
145
 
145
- And the apply your migrations via:
146
+ This will create a `migrations/` folder in you project root.
147
+
148
+ ```
149
+ myproject/
150
+ - myapp/
151
+ - __init__.py
152
+ - models.py
153
+ - routes.py
154
+ - migrations/
155
+ - myapp/
156
+ - pyproject.toml
157
+ - settings.py
158
+ ```
159
+
160
+ Apply your migrations via:
146
161
 
147
162
  ```
148
163
  ohmyapi migrate [ <app> ] # no app means all INSTALLED_APPS
@@ -165,6 +180,7 @@ ohmyapi shell
165
180
  ## Authentication
166
181
 
167
182
  A builtin auth app is available.
183
+
168
184
  Simply add `ohmyapi_auth` to your INSTALLED_APPS and define a JWT_SECRET in your `settings.py`.
169
185
  Remember to `makemigrations` and `migrate` for the auth tables to be created in the database.
170
186
 
@@ -179,3 +195,10 @@ INSTALLED_APPS = [
179
195
  JWT_SECRET = "t0ps3cr3t"
180
196
  ```
181
197
 
198
+ Create a super-user:
199
+
200
+ ```
201
+ ohmyapi createsuperuser
202
+ ```
203
+
204
+
@@ -2,8 +2,9 @@
2
2
 
3
3
  > OhMyAPI == Application scaffolding for FastAPI+TortoiseORM.
4
4
 
5
- OhMyAPI is a blazingly fast, async Python web application framework with batteries included.
6
- It is built around FastAPI and TortoiseORM and is thus 100% async.
5
+ OhMyAPI is a Django-flavored web-application scaffolding framework.
6
+ It is blazingly fast, async and has batteries included.
7
+ Built around FastAPI and TortoiseORM makes it 100% async.
7
8
 
8
9
  Features:
9
10
 
@@ -23,7 +24,7 @@ Features:
23
24
  **Creating a Project**
24
25
 
25
26
  ```
26
- pip install ohmyapi # TODO: not yet published
27
+ pip install ohmyapi
27
28
  ohmyapi startproject myproject
28
29
  cd myproject
29
30
  ```
@@ -93,13 +94,13 @@ router = APIRouter(prefix="/myapp")
93
94
 
94
95
  @router.get("/")
95
96
  async def list():
96
- return await Person.all()
97
+ return await Person.Schema.many.from_queryset(Person.all())
97
98
 
98
99
 
99
100
  @router.get("/:id")
100
101
  async def get(id: int):
101
102
  try:
102
- await Person.get(pk=id)
103
+ return await Person.Schema.one(Person.get(pk=id))
103
104
  except DoesNotExist:
104
105
  raise HTTPException(status_code=404, detail="item not found")
105
106
 
@@ -116,7 +117,21 @@ Similar to Django, first run:
116
117
  ohmyapi makemigrations [ <app> ] # no app means all INSTALLED_APPS
117
118
  ```
118
119
 
119
- And the apply your migrations via:
120
+ This will create a `migrations/` folder in you project root.
121
+
122
+ ```
123
+ myproject/
124
+ - myapp/
125
+ - __init__.py
126
+ - models.py
127
+ - routes.py
128
+ - migrations/
129
+ - myapp/
130
+ - pyproject.toml
131
+ - settings.py
132
+ ```
133
+
134
+ Apply your migrations via:
120
135
 
121
136
  ```
122
137
  ohmyapi migrate [ <app> ] # no app means all INSTALLED_APPS
@@ -139,6 +154,7 @@ ohmyapi shell
139
154
  ## Authentication
140
155
 
141
156
  A builtin auth app is available.
157
+
142
158
  Simply add `ohmyapi_auth` to your INSTALLED_APPS and define a JWT_SECRET in your `settings.py`.
143
159
  Remember to `makemigrations` and `migrate` for the auth tables to be created in the database.
144
160
 
@@ -152,3 +168,10 @@ INSTALLED_APPS = [
152
168
 
153
169
  JWT_SECRET = "t0ps3cr3t"
154
170
  ```
171
+
172
+ Create a super-user:
173
+
174
+ ```
175
+ ohmyapi createsuperuser
176
+ ```
177
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ohmyapi"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "A Django-like but async web-framework based on FastAPI and TortoiseORM."
5
5
  license = "MIT"
6
6
  keywords = ["fastapi", "tortoise", "orm", "async", "web-framework"]
@@ -1,23 +1,30 @@
1
1
  from typing import Optional, List
2
2
  from ohmyapi.db import Model, field
3
3
  from passlib.context import CryptContext
4
+ from tortoise.contrib.pydantic import pydantic_queryset_creator
4
5
 
5
6
  pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
6
7
 
7
8
 
8
9
  class Group(Model):
9
10
  id = field.IntField(pk=True)
10
- name = field.CharField(max_length=42)
11
+ name = field.CharField(max_length=42, index=True)
11
12
 
12
13
 
13
14
  class User(Model):
14
15
  id = field.IntField(pk=True)
16
+ email = CharField(unique=True, index=True)
15
17
  username = field.CharField(max_length=150, unique=True)
16
18
  password_hash = field.CharField(max_length=128)
17
19
  is_admin = field.BooleanField(default=False)
18
20
  is_staff = field.BooleanField(default=False)
19
21
  groups: Optional[List[Group]] = field.ManyToManyField("ohmyapi_auth.Group", related_name="users")
20
22
 
23
+
24
+ class Schema:
25
+ exclude = 'password_hash',
26
+
27
+
21
28
  def set_password(self, raw_password: str) -> None:
22
29
  """Hash and store the password."""
23
30
  self.password_hash = pwd_context.hash(raw_password)
@@ -0,0 +1,46 @@
1
+ from tortoise import fields
2
+ from tortoise.models import Model as TortoiseModel
3
+ from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
4
+
5
+
6
+ class ModelMeta(type(TortoiseModel)):
7
+ def __new__(cls, name, bases, attrs):
8
+ new_cls = super().__new__(cls, name, bases, attrs)
9
+
10
+ schema_opts = getattr(new_cls, "Schema", None)
11
+
12
+ class BoundSchema:
13
+ @property
14
+ def one(self):
15
+ """Return a Pydantic model class for 'one' results."""
16
+ include = getattr(schema_opts, "include", None)
17
+ exclude = getattr(schema_opts, "exclude", None)
18
+ return pydantic_model_creator(
19
+ new_cls,
20
+ name=f"{new_cls.__name__}SchemaOne",
21
+ include=include,
22
+ exclude=exclude,
23
+ exclude_readonly=True,
24
+ )
25
+
26
+ @property
27
+ def many(self):
28
+ """Return a Pydantic queryset class for 'many' results."""
29
+ include = getattr(schema_opts, "include", None)
30
+ exclude = getattr(schema_opts, "exclude", None)
31
+ return pydantic_queryset_creator(
32
+ new_cls,
33
+ name=f"{new_cls.__name__}SchemaMany",
34
+ include=include,
35
+ exclude=exclude,
36
+ )
37
+
38
+ new_cls.Schema = BoundSchema()
39
+ return new_cls
40
+
41
+
42
+ class Model(TortoiseModel, metaclass=ModelMeta):
43
+ class Schema:
44
+ include = None
45
+ exclude = None
46
+
@@ -1,80 +0,0 @@
1
- from tortoise import fields
2
- from tortoise.models import Model as TortoiseModel
3
- from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
4
-
5
-
6
- class Model(TortoiseModel):
7
- """
8
- Base Tortoise model with attached Pydantic schema generators via .Schema
9
- """
10
-
11
- class Schema:
12
- """
13
- Provides convenient access to auto-generated Pydantic schemas.
14
- """
15
-
16
- def __init__(self, model_cls):
17
- self.model_cls = model_cls
18
-
19
- @property
20
- def id(self):
21
- # Minimal schema with just the primary key field
22
- pk_field = self.model_cls._meta.pk_attr
23
- return pydantic_model_creator(
24
- self.model_cls, name=f"{self.model_cls.__name__}SchemaId", include=(pk_field,)
25
- )
26
-
27
- @property
28
- def get(self):
29
- # Full schema for reading
30
- return pydantic_model_creator(
31
- self.model_cls, name=f"{self.model_cls.__name__}SchemaGet"
32
- )
33
-
34
- @property
35
- def post(self):
36
- # Input schema for creation (no readonly fields like ID/PK)
37
- return pydantic_model_creator(
38
- self.model_cls,
39
- name=f"{self.model_cls.__name__}SchemaPost",
40
- exclude_readonly=True,
41
- )
42
-
43
- @property
44
- def put(self):
45
- # Input schema for updating
46
- return pydantic_model_creator(
47
- self.model_cls,
48
- name=f"{self.model_cls.__name__}SchemaPut",
49
- exclude_readonly=True,
50
- )
51
-
52
- @property
53
- def delete(self):
54
- # Schema for delete operations (just PK)
55
- pk_field = self.model_cls._meta.pk_attr
56
- return pydantic_model_creator(
57
- self.model_cls, name=f"{self.model_cls.__name__}SchemaDelete", include=(pk_field,)
58
- )
59
-
60
- @property
61
- def list(self):
62
- # Schema for list endpoints
63
- return pydantic_queryset_creator(self.model_cls)
64
-
65
- def from_fields(self, *fields: str):
66
- # Generate schema restricted to given fields
67
- valid = [f for f in fields if f in self.model_cls._meta.fields_map]
68
- return pydantic_model_creator(
69
- self.model_cls,
70
- name=f"{self.model_cls.__name__}SchemaFields",
71
- include=valid,
72
- )
73
-
74
- def __init_subclass__(cls, **kwargs):
75
- """
76
- Automatically attach .Schema to all subclasses
77
- """
78
- super().__init_subclass__(**kwargs)
79
- cls.Schema = cls.Schema(cls)
80
-
File without changes
File without changes
File without changes