core-framework 0.12.2__py3-none-any.whl → 0.12.4__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.
- core/__init__.py +1 -1
- core/auth/middleware.py +57 -18
- core/auth/models.py +53 -29
- core/middleware.py +5 -0
- core/migrations/engine.py +68 -2
- {core_framework-0.12.2.dist-info → core_framework-0.12.4.dist-info}/METADATA +1 -1
- {core_framework-0.12.2.dist-info → core_framework-0.12.4.dist-info}/RECORD +9 -9
- {core_framework-0.12.2.dist-info → core_framework-0.12.4.dist-info}/WHEEL +0 -0
- {core_framework-0.12.2.dist-info → core_framework-0.12.4.dist-info}/entry_points.txt +0 -0
core/__init__.py
CHANGED
core/auth/middleware.py
CHANGED
|
@@ -182,26 +182,65 @@ class AuthenticationMiddleware(BaseHTTPMiddleware):
|
|
|
182
182
|
if User is None:
|
|
183
183
|
return None
|
|
184
184
|
|
|
185
|
-
# Get database session
|
|
186
|
-
|
|
185
|
+
# Bug #3 & #4 Fix: Get database session correctly
|
|
186
|
+
# The middleware runs outside FastAPI DI context, so we need to
|
|
187
|
+
# handle database session creation carefully
|
|
188
|
+
db = await self._get_db_session()
|
|
189
|
+
if db is None:
|
|
190
|
+
return None
|
|
187
191
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if user is None:
|
|
196
|
-
return None
|
|
197
|
-
|
|
198
|
-
# Check if user is active
|
|
199
|
-
if hasattr(user, "is_active") and not user.is_active:
|
|
200
|
-
return None
|
|
201
|
-
|
|
202
|
-
return user
|
|
203
|
-
except Exception:
|
|
192
|
+
try:
|
|
193
|
+
# Convert user_id to correct type
|
|
194
|
+
user_id_converted = self._convert_user_id(user_id, User)
|
|
195
|
+
|
|
196
|
+
user = await User.objects.using(db).filter(id=user_id_converted).first()
|
|
197
|
+
|
|
198
|
+
if user is None:
|
|
204
199
|
return None
|
|
200
|
+
|
|
201
|
+
# Check if user is active
|
|
202
|
+
if hasattr(user, "is_active") and not user.is_active:
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
return user
|
|
206
|
+
except Exception:
|
|
207
|
+
return None
|
|
208
|
+
finally:
|
|
209
|
+
await db.close()
|
|
210
|
+
|
|
211
|
+
async def _get_db_session(self) -> Any | None:
|
|
212
|
+
"""
|
|
213
|
+
Get a database session for authentication.
|
|
214
|
+
|
|
215
|
+
Bug #3 & #4 Fix: Handles both initialized and uninitialized database states.
|
|
216
|
+
Creates session directly from engine if normal path fails.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
AsyncSession or None if database not available
|
|
220
|
+
"""
|
|
221
|
+
# Try 1: Use the standard get_read_session (if database is initialized)
|
|
222
|
+
try:
|
|
223
|
+
from core.database import get_read_session, _read_session_factory
|
|
224
|
+
|
|
225
|
+
if _read_session_factory is not None:
|
|
226
|
+
return _read_session_factory()
|
|
227
|
+
except (RuntimeError, ImportError):
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
# Try 2: Create session from settings (lazy initialization)
|
|
231
|
+
try:
|
|
232
|
+
from core.config import get_settings
|
|
233
|
+
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
|
|
234
|
+
|
|
235
|
+
settings = get_settings()
|
|
236
|
+
db_url = getattr(settings, 'database_read_url', None) or getattr(settings, 'database_url', None)
|
|
237
|
+
|
|
238
|
+
if db_url:
|
|
239
|
+
engine = create_async_engine(db_url, echo=False)
|
|
240
|
+
session_factory = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
|
241
|
+
return session_factory()
|
|
242
|
+
except Exception:
|
|
243
|
+
pass
|
|
205
244
|
|
|
206
245
|
return None
|
|
207
246
|
|
core/auth/models.py
CHANGED
|
@@ -27,12 +27,14 @@ Uso:
|
|
|
27
27
|
from __future__ import annotations
|
|
28
28
|
|
|
29
29
|
from typing import Any, ClassVar, TYPE_CHECKING
|
|
30
|
+
from uuid import UUID
|
|
30
31
|
|
|
31
32
|
from sqlalchemy import Table, Column, Integer, ForeignKey, inspect
|
|
32
33
|
from sqlalchemy.orm import Mapped, relationship, declared_attr
|
|
33
34
|
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
|
34
35
|
|
|
35
36
|
from core.models import Model, Field
|
|
37
|
+
from core.fields import AdvancedField
|
|
36
38
|
from core.auth.base import get_password_hasher, get_auth_config
|
|
37
39
|
from core.datetime import timezone, DateTime
|
|
38
40
|
|
|
@@ -56,6 +58,7 @@ def _get_pk_column_type(model_class: type) -> type:
|
|
|
56
58
|
Detecta o tipo da coluna PK de um modelo.
|
|
57
59
|
|
|
58
60
|
Bug #3 Fix: Detecção robusta do tipo de PK para FKs.
|
|
61
|
+
Verifica toda a cadeia de herança (MRO) para detectar corretamente.
|
|
59
62
|
|
|
60
63
|
Suporta:
|
|
61
64
|
- Integer (int)
|
|
@@ -69,7 +72,7 @@ def _get_pk_column_type(model_class: type) -> type:
|
|
|
69
72
|
from sqlalchemy import Integer, BigInteger, String
|
|
70
73
|
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
|
71
74
|
from sqlalchemy import Uuid
|
|
72
|
-
import uuid
|
|
75
|
+
import uuid as uuid_module
|
|
73
76
|
|
|
74
77
|
# Verifica cache primeiro
|
|
75
78
|
cache_key = f"{model_class.__module__}.{model_class.__name__}"
|
|
@@ -78,7 +81,30 @@ def _get_pk_column_type(model_class: type) -> type:
|
|
|
78
81
|
|
|
79
82
|
detected_type = Integer # Default
|
|
80
83
|
|
|
81
|
-
# Método
|
|
84
|
+
# Método 0 (MAIS IMPORTANTE): Verifica herança de AbstractUUIDUser
|
|
85
|
+
# Isso é verificado PRIMEIRO porque funciona mesmo durante o mapeamento
|
|
86
|
+
for base in model_class.__mro__:
|
|
87
|
+
base_name = base.__name__
|
|
88
|
+
# Verifica se herda de AbstractUUIDUser ou qualquer classe com UUID no nome
|
|
89
|
+
if base_name == "AbstractUUIDUser":
|
|
90
|
+
detected_type = PG_UUID
|
|
91
|
+
_pk_type_cache[cache_key] = detected_type
|
|
92
|
+
return detected_type
|
|
93
|
+
|
|
94
|
+
# Método 1: Verifica annotations em TODA a cadeia de herança (MRO)
|
|
95
|
+
for base in model_class.__mro__:
|
|
96
|
+
annotations = getattr(base, "__annotations__", {})
|
|
97
|
+
if "id" in annotations:
|
|
98
|
+
ann = annotations["id"]
|
|
99
|
+
ann_str = str(ann)
|
|
100
|
+
|
|
101
|
+
# Detecta UUID (vários formatos)
|
|
102
|
+
if "UUID" in ann_str or "uuid" in ann_str or "Uuid" in ann_str:
|
|
103
|
+
detected_type = PG_UUID
|
|
104
|
+
_pk_type_cache[cache_key] = detected_type
|
|
105
|
+
return detected_type
|
|
106
|
+
|
|
107
|
+
# Método 2: Tenta obter da tabela já mapeada (se existir)
|
|
82
108
|
if hasattr(model_class, "__table__"):
|
|
83
109
|
pk_columns = [c for c in model_class.__table__.columns if c.primary_key]
|
|
84
110
|
if pk_columns:
|
|
@@ -101,40 +127,41 @@ def _get_pk_column_type(model_class: type) -> type:
|
|
|
101
127
|
_pk_type_cache[cache_key] = detected_type
|
|
102
128
|
return detected_type
|
|
103
129
|
|
|
104
|
-
# Método
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
ann = annotations["id"]
|
|
109
|
-
ann_str = str(ann)
|
|
110
|
-
|
|
111
|
-
# Detecta UUID (vários formatos)
|
|
112
|
-
if "UUID" in ann_str or "uuid" in ann_str or "Uuid" in ann_str:
|
|
113
|
-
detected_type = PG_UUID
|
|
114
|
-
# Detecta int
|
|
115
|
-
elif "int" in ann_str.lower() and "uuid" not in ann_str.lower():
|
|
116
|
-
detected_type = Integer
|
|
117
|
-
# Detecta str
|
|
118
|
-
elif "str" in ann_str.lower() and "uuid" not in ann_str.lower():
|
|
119
|
-
detected_type = String
|
|
120
|
-
|
|
121
|
-
# Método 3: Verifica campos na classe (declared_attr ou column_property)
|
|
122
|
-
for attr_name in dir(model_class):
|
|
123
|
-
if attr_name == "id":
|
|
124
|
-
attr = getattr(model_class, attr_name, None)
|
|
130
|
+
# Método 3: Verifica atributo 'id' diretamente na classe e bases
|
|
131
|
+
for base in model_class.__mro__:
|
|
132
|
+
if hasattr(base, "id"):
|
|
133
|
+
attr = getattr(base, "id", None)
|
|
125
134
|
if attr is not None:
|
|
126
|
-
# Pode ser um InstrumentedAttribute
|
|
135
|
+
# Pode ser um InstrumentedAttribute ou MappedColumn
|
|
127
136
|
if hasattr(attr, "type"):
|
|
128
137
|
attr_type = attr.type
|
|
129
138
|
if isinstance(attr_type, (PG_UUID, Uuid)):
|
|
130
139
|
detected_type = PG_UUID
|
|
131
140
|
break
|
|
141
|
+
type_name = type(attr_type).__name__.upper()
|
|
142
|
+
if "UUID" in type_name:
|
|
143
|
+
detected_type = PG_UUID
|
|
144
|
+
break
|
|
132
145
|
# Pode ser um mapped_column
|
|
133
146
|
if hasattr(attr, "property") and hasattr(attr.property, "columns"):
|
|
134
147
|
for col in attr.property.columns:
|
|
135
148
|
if isinstance(col.type, (PG_UUID, Uuid)):
|
|
136
149
|
detected_type = PG_UUID
|
|
137
150
|
break
|
|
151
|
+
type_name = type(col.type).__name__.upper()
|
|
152
|
+
if "UUID" in type_name:
|
|
153
|
+
detected_type = PG_UUID
|
|
154
|
+
break
|
|
155
|
+
# Verifica se é um MappedColumn com tipo definido
|
|
156
|
+
if hasattr(attr, "column") and hasattr(attr.column, "type"):
|
|
157
|
+
col_type = attr.column.type
|
|
158
|
+
if isinstance(col_type, (PG_UUID, Uuid)):
|
|
159
|
+
detected_type = PG_UUID
|
|
160
|
+
break
|
|
161
|
+
type_name = type(col_type).__name__.upper()
|
|
162
|
+
if "UUID" in type_name:
|
|
163
|
+
detected_type = PG_UUID
|
|
164
|
+
break
|
|
138
165
|
|
|
139
166
|
_pk_type_cache[cache_key] = detected_type
|
|
140
167
|
return detected_type
|
|
@@ -790,12 +817,9 @@ class AbstractUUIDUser(AbstractUser):
|
|
|
790
817
|
|
|
791
818
|
__abstract__ = True
|
|
792
819
|
|
|
793
|
-
# Importa aqui para evitar circular import
|
|
794
|
-
from core.fields import AdvancedField
|
|
795
|
-
from uuid import UUID as UUIDType
|
|
796
|
-
|
|
797
820
|
# Override: usa UUID como PK
|
|
798
|
-
|
|
821
|
+
# UUID importado no topo do módulo para resolução correta de tipos
|
|
822
|
+
id: Mapped[UUID] = AdvancedField.uuid_pk()
|
|
799
823
|
|
|
800
824
|
|
|
801
825
|
# =============================================================================
|
core/middleware.py
CHANGED
|
@@ -736,11 +736,16 @@ class SecurityHeadersMiddleware(BaseMiddleware):
|
|
|
736
736
|
# =============================================================================
|
|
737
737
|
|
|
738
738
|
_builtin_middlewares.update({
|
|
739
|
+
# Pre-built middlewares from this module
|
|
739
740
|
"timing": "core.middleware.TimingMiddleware",
|
|
740
741
|
"request_id": "core.middleware.RequestIDMiddleware",
|
|
741
742
|
"logging": "core.middleware.LoggingMiddleware",
|
|
742
743
|
"maintenance": "core.middleware.MaintenanceModeMiddleware",
|
|
743
744
|
"security_headers": "core.middleware.SecurityHeadersMiddleware",
|
|
745
|
+
# Auth middlewares (ensure they're registered even if initial dict failed)
|
|
746
|
+
"auth": "core.auth.middleware.AuthenticationMiddleware",
|
|
747
|
+
"authentication": "core.auth.middleware.AuthenticationMiddleware",
|
|
748
|
+
"optional_auth": "core.auth.middleware.OptionalAuthenticationMiddleware",
|
|
744
749
|
})
|
|
745
750
|
|
|
746
751
|
|
core/migrations/engine.py
CHANGED
|
@@ -255,6 +255,71 @@ class MigrationEngine:
|
|
|
255
255
|
index=col.index,
|
|
256
256
|
)
|
|
257
257
|
|
|
258
|
+
def _topological_sort_tables(self, tables: list[TableState]) -> list[TableState]:
|
|
259
|
+
"""
|
|
260
|
+
Bug #5 Fix: Ordena tabelas em ordem topológica baseada em FKs.
|
|
261
|
+
|
|
262
|
+
Tabelas referenciadas por FKs são criadas ANTES das que as referenciam.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
tables: Lista de TableState a ordenar
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Lista ordenada topologicamente
|
|
269
|
+
"""
|
|
270
|
+
if not tables:
|
|
271
|
+
return []
|
|
272
|
+
|
|
273
|
+
# Mapeia nome -> tabela
|
|
274
|
+
table_map = {t.name: t for t in tables}
|
|
275
|
+
|
|
276
|
+
# Constrói grafo de dependências
|
|
277
|
+
# dependencias[A] = {B, C} significa A depende de B e C (A tem FK para B e C)
|
|
278
|
+
dependencies: dict[str, set[str]] = {t.name: set() for t in tables}
|
|
279
|
+
|
|
280
|
+
for table in tables:
|
|
281
|
+
for fk in table.foreign_keys:
|
|
282
|
+
ref_table = fk.references_table
|
|
283
|
+
# Só adiciona dependência se a tabela referenciada também está sendo criada
|
|
284
|
+
# (tabelas já existentes não precisam ser consideradas)
|
|
285
|
+
if ref_table in table_map:
|
|
286
|
+
dependencies[table.name].add(ref_table)
|
|
287
|
+
|
|
288
|
+
# Algoritmo de Kahn para ordenação topológica
|
|
289
|
+
result = []
|
|
290
|
+
|
|
291
|
+
# Encontra tabelas sem dependências (grau de entrada 0)
|
|
292
|
+
no_deps = [name for name, deps in dependencies.items() if not deps]
|
|
293
|
+
|
|
294
|
+
while no_deps:
|
|
295
|
+
# Remove uma tabela sem dependências
|
|
296
|
+
name = no_deps.pop(0)
|
|
297
|
+
result.append(table_map[name])
|
|
298
|
+
|
|
299
|
+
# Remove esta tabela das dependências de outras
|
|
300
|
+
for other_name, deps in dependencies.items():
|
|
301
|
+
if name in deps:
|
|
302
|
+
deps.remove(name)
|
|
303
|
+
# Se não tem mais dependências, adiciona à fila
|
|
304
|
+
if not deps and other_name not in [t.name for t in result]:
|
|
305
|
+
no_deps.append(other_name)
|
|
306
|
+
|
|
307
|
+
# Verifica ciclo (se sobrou alguma tabela com dependências)
|
|
308
|
+
remaining = [t for t in tables if t not in result]
|
|
309
|
+
if remaining:
|
|
310
|
+
# Há um ciclo - adiciona as tabelas restantes no final
|
|
311
|
+
# (o banco vai falhar, mas pelo menos o erro será claro)
|
|
312
|
+
import warnings
|
|
313
|
+
cycle_tables = [t.name for t in remaining]
|
|
314
|
+
warnings.warn(
|
|
315
|
+
f"Circular FK dependency detected involving tables: {cycle_tables}. "
|
|
316
|
+
"Migration may fail. Consider breaking the cycle with nullable FKs.",
|
|
317
|
+
RuntimeWarning,
|
|
318
|
+
)
|
|
319
|
+
result.extend(remaining)
|
|
320
|
+
|
|
321
|
+
return result
|
|
322
|
+
|
|
258
323
|
def _diff_to_operations(self, diff: SchemaDiff) -> list[Operation]:
|
|
259
324
|
"""Converte SchemaDiff em lista de operações."""
|
|
260
325
|
from core.migrations.operations import CreateEnum, DropEnum, AlterEnum
|
|
@@ -284,8 +349,9 @@ class MigrationEngine:
|
|
|
284
349
|
new_values=new_enum.values,
|
|
285
350
|
))
|
|
286
351
|
|
|
287
|
-
# 3. Criar tabelas
|
|
288
|
-
|
|
352
|
+
# 3. Criar tabelas (BUG #5 FIX: em ordem topológica)
|
|
353
|
+
sorted_tables = self._topological_sort_tables(diff.tables_to_create)
|
|
354
|
+
for table in sorted_tables:
|
|
289
355
|
columns = [self._column_state_to_def(col) for col in table.columns.values()]
|
|
290
356
|
foreign_keys = [
|
|
291
357
|
ForeignKeyDef(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-framework
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.4
|
|
4
4
|
Summary: Core Framework - Django-inspired, FastAPI-powered. Alta performance, baixo acoplamento, produtividade extrema.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SorPuti/core-framework
|
|
6
6
|
Project-URL: Documentation, https://github.com/SorPuti/core-framework#readme
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
core/__init__.py,sha256=
|
|
1
|
+
core/__init__.py,sha256=LpMfN4s5QgM0suYMegcYK7uf2m8dIH90qOsbM5IWSNs,12058
|
|
2
2
|
core/app.py,sha256=sCA3mJI696i7MIjrPxfOr5zEYt0njarQfHHy3EAajk4,21071
|
|
3
3
|
core/choices.py,sha256=rhcL3p2dB7RK99zIilpmoTFVcibQEIaRpz0CY0kImCE,10502
|
|
4
4
|
core/config.py,sha256=2-MVF9nLoYmxpYYH_Gzn4-Sa3MU87YZskRPtlNyhg6Q,14049
|
|
@@ -7,7 +7,7 @@ core/datetime.py,sha256=bzqlAj3foA-lzbhXjlEiDNR2D-nwXu9mpxpdcUb-Pmw,32730
|
|
|
7
7
|
core/dependencies.py,sha256=LrNLbmQhXoCPRvoRPRMGNo0w6_l4NLGWeeTHzpUU36M,11582
|
|
8
8
|
core/exceptions.py,sha256=cdcffeYnMzCbS4hApOYNmPVNbPUpKcrgJbi3nKhqTuI,22702
|
|
9
9
|
core/fields.py,sha256=F2NdToowkJ_LFvPN9KVyxIFES1AlVDy7WkEp-8UiBpA,9327
|
|
10
|
-
core/middleware.py,sha256=
|
|
10
|
+
core/middleware.py,sha256=MZVw7smJ2MiycYvkaYIC2cNpyqYGk3m-eeoDandqZU4,23506
|
|
11
11
|
core/models.py,sha256=jdNdjRPKBZiOBOgg8CmDYBwmuWdD7twCIpqINLGY4Q4,33788
|
|
12
12
|
core/permissions.py,sha256=HQu_eNBEodJyR50CYcFvdCw9LlEfhI5vJbljV5VIs7M,10162
|
|
13
13
|
core/querysets.py,sha256=Z87-U06Un_xA9GKwcjXx0yzw6F_xf_tvG_rBT5UGL9c,22678
|
|
@@ -22,8 +22,8 @@ core/auth/backends.py,sha256=R-siIE8TrNqDHkCx42zXN1WVvvuWOun1nj8D5elrC9g,10425
|
|
|
22
22
|
core/auth/base.py,sha256=Q7vXgwTmgdmyW7G8eJmDket2bKB_8YFnraZ_kK9_gTs,21425
|
|
23
23
|
core/auth/decorators.py,sha256=tmC7prKUvHuzQ3J872nM6r83DR9d82dCLXKLvUB1Os8,12288
|
|
24
24
|
core/auth/hashers.py,sha256=0gIf67TU0k5H744FADpyh9_ugxA7m3mhYPZxLh_lEtc,12808
|
|
25
|
-
core/auth/middleware.py,sha256=
|
|
26
|
-
core/auth/models.py,sha256=
|
|
25
|
+
core/auth/middleware.py,sha256=r4F3AIb4k9Z7gbTwcyG-MVWCyGikQqP54IHNKmyNtdc,10963
|
|
26
|
+
core/auth/models.py,sha256=aEE7deQKPS1aH0Btzzh3Z1Bwuqy8zvLZwu4JFEmiUNk,34058
|
|
27
27
|
core/auth/permissions.py,sha256=v3ykAgNpq5wJ0NkuC_FuveMctOkDfM9Xp11XEnUAuBg,12461
|
|
28
28
|
core/auth/schemas.py,sha256=L0W96dOD348rJDGeu1K5Rz3aJj-GdwMr2vbwwsYfo2g,3469
|
|
29
29
|
core/auth/tokens.py,sha256=jk-TnMRdVGPhy6pWqSF2Ef8RTqLrP6Mkuo5GvRQh9no,8489
|
|
@@ -61,7 +61,7 @@ core/messaging/redis/producer.py,sha256=F9NA1GpYvN-wdW5Ilzi49rrAmxfBmicXX3l6sABW
|
|
|
61
61
|
core/migrations/__init__.py,sha256=OF_7XQ9x9V_BWr3d8vDZk8W5QYT0RO3ZXNFnOg8UgDI,1908
|
|
62
62
|
core/migrations/analyzer.py,sha256=QiwG_Xf_-Mb-Kp4hstkF8xNJD0Tvxgz20vqvYZ6xEXM,27287
|
|
63
63
|
core/migrations/cli.py,sha256=mR3lIFTlXSvupFOPVlfuC-urJyDfNFR9nqYZn4TjIco,12019
|
|
64
|
-
core/migrations/engine.py,sha256=
|
|
64
|
+
core/migrations/engine.py,sha256=jk8-wX8aKNBidUGyQ7ckHcUsukNJYpgSva-Sp-Iu-L4,31590
|
|
65
65
|
core/migrations/migration.py,sha256=Xv5MSNLvGAR9wnuMc4GRwciUSuU22AxWlWZP-hsVliI,2748
|
|
66
66
|
core/migrations/operations.py,sha256=wZLui76zU-MDiJfyn3l3NBRGJw1V4XF8tViSV3kvN6A,28651
|
|
67
67
|
core/migrations/state.py,sha256=eb_EYTE1tG-xQIwliS_-QTgr0y8-Jj0Va4C3nfpMrd4,15324
|
|
@@ -78,7 +78,7 @@ example/auth.py,sha256=zBpLutb8lVKnGfQqQ2wnyygsSutHYZzeJBuhnFhxBaQ,4971
|
|
|
78
78
|
example/models.py,sha256=xKdx0kJ9n0tZ7sCce3KhV3BTvKvsh6m7G69eFm3ukf0,4549
|
|
79
79
|
example/schemas.py,sha256=wJ9QofnuHp4PjtM_IuMMBLVFVDJ4YlwcF6uQm1ooKiY,6139
|
|
80
80
|
example/views.py,sha256=GQwgQcW6yoeUIDbF7-lsaZV7cs8G1S1vGVtiwVpZIQE,14338
|
|
81
|
-
core_framework-0.12.
|
|
82
|
-
core_framework-0.12.
|
|
83
|
-
core_framework-0.12.
|
|
84
|
-
core_framework-0.12.
|
|
81
|
+
core_framework-0.12.4.dist-info/METADATA,sha256=YJACIGfMLNMWJNHuGVX2ltcOvKdZDajmp6GLc_GFzNA,12791
|
|
82
|
+
core_framework-0.12.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
83
|
+
core_framework-0.12.4.dist-info/entry_points.txt,sha256=lQ65IAOpieqU1VcHCUReeyandpyy8IKGix6IkJW_4Is,39
|
|
84
|
+
core_framework-0.12.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|