core-framework 0.12.24__tar.gz → 0.12.26__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 (142) hide show
  1. {core_framework-0.12.24 → core_framework-0.12.26}/PKG-INFO +1 -1
  2. {core_framework-0.12.24 → core_framework-0.12.26}/core/__init__.py +1 -1
  3. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/operations.py +41 -5
  4. {core_framework-0.12.24 → core_framework-0.12.26}/core/routing.py +19 -17
  5. {core_framework-0.12.24 → core_framework-0.12.26}/core/views.py +29 -2
  6. {core_framework-0.12.24 → core_framework-0.12.26}/pyproject.toml +1 -1
  7. {core_framework-0.12.24 → core_framework-0.12.26}/.gitignore +0 -0
  8. {core_framework-0.12.24 → core_framework-0.12.26}/README.md +0 -0
  9. {core_framework-0.12.24 → core_framework-0.12.26}/core/app.py +0 -0
  10. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/__init__.py +0 -0
  11. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/backends.py +0 -0
  12. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/base.py +0 -0
  13. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/decorators.py +0 -0
  14. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/hashers.py +0 -0
  15. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/helpers.py +0 -0
  16. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/middleware.py +0 -0
  17. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/models.py +0 -0
  18. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/permissions.py +0 -0
  19. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/schemas.py +0 -0
  20. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/tokens.py +0 -0
  21. {core_framework-0.12.24 → core_framework-0.12.26}/core/auth/views.py +0 -0
  22. {core_framework-0.12.24 → core_framework-0.12.26}/core/choices.py +0 -0
  23. {core_framework-0.12.24 → core_framework-0.12.26}/core/cli/__init__.py +0 -0
  24. {core_framework-0.12.24 → core_framework-0.12.26}/core/cli/main.py +0 -0
  25. {core_framework-0.12.24 → core_framework-0.12.26}/core/config.py +0 -0
  26. {core_framework-0.12.24 → core_framework-0.12.26}/core/database.py +0 -0
  27. {core_framework-0.12.24 → core_framework-0.12.26}/core/datetime.py +0 -0
  28. {core_framework-0.12.24 → core_framework-0.12.26}/core/dependencies.py +0 -0
  29. {core_framework-0.12.24 → core_framework-0.12.26}/core/deployment/__init__.py +0 -0
  30. {core_framework-0.12.24 → core_framework-0.12.26}/core/deployment/docker.py +0 -0
  31. {core_framework-0.12.24 → core_framework-0.12.26}/core/deployment/kubernetes.py +0 -0
  32. {core_framework-0.12.24 → core_framework-0.12.26}/core/deployment/pm2.py +0 -0
  33. {core_framework-0.12.24 → core_framework-0.12.26}/core/exceptions.py +0 -0
  34. {core_framework-0.12.24 → core_framework-0.12.26}/core/fields.py +0 -0
  35. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/__init__.py +0 -0
  36. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/avro.py +0 -0
  37. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/base.py +0 -0
  38. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/config.py +0 -0
  39. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/confluent/__init__.py +0 -0
  40. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/confluent/consumer.py +0 -0
  41. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/confluent/producer.py +0 -0
  42. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/decorators.py +0 -0
  43. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/kafka/__init__.py +0 -0
  44. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/kafka/admin.py +0 -0
  45. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/kafka/broker.py +0 -0
  46. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/kafka/consumer.py +0 -0
  47. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/kafka/producer.py +0 -0
  48. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/rabbitmq/__init__.py +0 -0
  49. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/rabbitmq/broker.py +0 -0
  50. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/rabbitmq/consumer.py +0 -0
  51. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/rabbitmq/producer.py +0 -0
  52. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/redis/__init__.py +0 -0
  53. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/redis/broker.py +0 -0
  54. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/redis/consumer.py +0 -0
  55. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/redis/producer.py +0 -0
  56. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/registry.py +0 -0
  57. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/topics.py +0 -0
  58. {core_framework-0.12.24 → core_framework-0.12.26}/core/messaging/workers.py +0 -0
  59. {core_framework-0.12.24 → core_framework-0.12.26}/core/middleware.py +0 -0
  60. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/__init__.py +0 -0
  61. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/analyzer.py +0 -0
  62. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/cli.py +0 -0
  63. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/engine.py +0 -0
  64. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/migration.py +0 -0
  65. {core_framework-0.12.24 → core_framework-0.12.26}/core/migrations/state.py +0 -0
  66. {core_framework-0.12.24 → core_framework-0.12.26}/core/models.py +0 -0
  67. {core_framework-0.12.24 → core_framework-0.12.26}/core/permissions.py +0 -0
  68. {core_framework-0.12.24 → core_framework-0.12.26}/core/querysets.py +0 -0
  69. {core_framework-0.12.24 → core_framework-0.12.26}/core/relations.py +0 -0
  70. {core_framework-0.12.24 → core_framework-0.12.26}/core/serializers.py +0 -0
  71. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/__init__.py +0 -0
  72. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/base.py +0 -0
  73. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/config.py +0 -0
  74. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/decorators.py +0 -0
  75. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/registry.py +0 -0
  76. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/scheduler.py +0 -0
  77. {core_framework-0.12.24 → core_framework-0.12.26}/core/tasks/worker.py +0 -0
  78. {core_framework-0.12.24 → core_framework-0.12.26}/core/tenancy.py +0 -0
  79. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/__init__.py +0 -0
  80. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/assertions.py +0 -0
  81. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/client.py +0 -0
  82. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/database.py +0 -0
  83. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/factories.py +0 -0
  84. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/mocks.py +0 -0
  85. {core_framework-0.12.24 → core_framework-0.12.26}/core/testing/plugin.py +0 -0
  86. {core_framework-0.12.24 → core_framework-0.12.26}/core/validation.py +0 -0
  87. {core_framework-0.12.24 → core_framework-0.12.26}/core/validators.py +0 -0
  88. {core_framework-0.12.24 → core_framework-0.12.26}/docs/01-quickstart.md +0 -0
  89. {core_framework-0.12.24 → core_framework-0.12.26}/docs/02-viewsets.md +0 -0
  90. {core_framework-0.12.24 → core_framework-0.12.26}/docs/03-authentication.md +0 -0
  91. {core_framework-0.12.24 → core_framework-0.12.26}/docs/04-messaging.md +0 -0
  92. {core_framework-0.12.24 → core_framework-0.12.26}/docs/05-multi-service.md +0 -0
  93. {core_framework-0.12.24 → core_framework-0.12.26}/docs/06-tasks.md +0 -0
  94. {core_framework-0.12.24 → core_framework-0.12.26}/docs/07-deployment.md +0 -0
  95. {core_framework-0.12.24 → core_framework-0.12.26}/docs/08-complete-example.md +0 -0
  96. {core_framework-0.12.24 → core_framework-0.12.26}/docs/09-settings.md +0 -0
  97. {core_framework-0.12.24 → core_framework-0.12.26}/docs/10-migrations.md +0 -0
  98. {core_framework-0.12.24 → core_framework-0.12.26}/docs/11-permissions.md +0 -0
  99. {core_framework-0.12.24 → core_framework-0.12.26}/docs/12-auth-backends.md +0 -0
  100. {core_framework-0.12.24 → core_framework-0.12.26}/docs/13-validators.md +0 -0
  101. {core_framework-0.12.24 → core_framework-0.12.26}/docs/14-querysets.md +0 -0
  102. {core_framework-0.12.24 → core_framework-0.12.26}/docs/15-routing.md +0 -0
  103. {core_framework-0.12.24 → core_framework-0.12.26}/docs/16-serializers.md +0 -0
  104. {core_framework-0.12.24 → core_framework-0.12.26}/docs/17-datetime.md +0 -0
  105. {core_framework-0.12.24 → core_framework-0.12.26}/docs/18-dependencies.md +0 -0
  106. {core_framework-0.12.24 → core_framework-0.12.26}/docs/19-views.md +0 -0
  107. {core_framework-0.12.24 → core_framework-0.12.26}/docs/20-fields.md +0 -0
  108. {core_framework-0.12.24 → core_framework-0.12.26}/docs/21-tenancy.md +0 -0
  109. {core_framework-0.12.24 → core_framework-0.12.26}/docs/22-replicas.md +0 -0
  110. {core_framework-0.12.24 → core_framework-0.12.26}/docs/23-soft-delete.md +0 -0
  111. {core_framework-0.12.24 → core_framework-0.12.26}/docs/24-relations.md +0 -0
  112. {core_framework-0.12.24 → core_framework-0.12.26}/docs/25-exceptions.md +0 -0
  113. {core_framework-0.12.24 → core_framework-0.12.26}/docs/26-choices.md +0 -0
  114. {core_framework-0.12.24 → core_framework-0.12.26}/docs/27-workers.md +0 -0
  115. {core_framework-0.12.24 → core_framework-0.12.26}/docs/28-avro.md +0 -0
  116. {core_framework-0.12.24 → core_framework-0.12.26}/docs/29-topics.md +0 -0
  117. {core_framework-0.12.24 → core_framework-0.12.26}/docs/30-changelog-0.12.2.md +0 -0
  118. {core_framework-0.12.24 → core_framework-0.12.26}/docs/31-middleware.md +0 -0
  119. {core_framework-0.12.24 → core_framework-0.12.26}/docs/32-migration-guide-0.12.2.md +0 -0
  120. {core_framework-0.12.24 → core_framework-0.12.26}/docs/32-testing.md +0 -0
  121. {core_framework-0.12.24 → core_framework-0.12.26}/docs/33-changelog-0.12.3.md +0 -0
  122. {core_framework-0.12.24 → core_framework-0.12.26}/docs/99-faq-troubleshooting.md +0 -0
  123. {core_framework-0.12.24 → core_framework-0.12.26}/docs/GUIDE.md +0 -0
  124. {core_framework-0.12.24 → core_framework-0.12.26}/docs/README.md +0 -0
  125. {core_framework-0.12.24 → core_framework-0.12.26}/example/__init__.py +0 -0
  126. {core_framework-0.12.24 → core_framework-0.12.26}/example/app.py +0 -0
  127. {core_framework-0.12.24 → core_framework-0.12.26}/example/auth.py +0 -0
  128. {core_framework-0.12.24 → core_framework-0.12.26}/example/models.py +0 -0
  129. {core_framework-0.12.24 → core_framework-0.12.26}/example/schemas.py +0 -0
  130. {core_framework-0.12.24 → core_framework-0.12.26}/example/views.py +0 -0
  131. {core_framework-0.12.24 → core_framework-0.12.26}/libs/__init__.py +0 -0
  132. {core_framework-0.12.24 → core_framework-0.12.26}/main.py +0 -0
  133. {core_framework-0.12.24 → core_framework-0.12.26}/tests/__init__.py +0 -0
  134. {core_framework-0.12.24 → core_framework-0.12.26}/tests/conftest.py +0 -0
  135. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_auth_helpers.py +0 -0
  136. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_imports.py +0 -0
  137. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_issues_fixes.py +0 -0
  138. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_models.py +0 -0
  139. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_permissions.py +0 -0
  140. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_querysets.py +0 -0
  141. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_serializers.py +0 -0
  142. {core_framework-0.12.24 → core_framework-0.12.26}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: core-framework
3
- Version: 0.12.24
3
+ Version: 0.12.26
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
@@ -287,7 +287,7 @@ from core.exceptions import (
287
287
  MissingDependency,
288
288
  )
289
289
 
290
- __version__ = "0.12.24"
290
+ __version__ = "0.12.26"
291
291
  __all__ = [
292
292
  # Models
293
293
  "Model",
@@ -181,19 +181,35 @@ class ColumnDef:
181
181
  return _format_sql_default(result, dialect)
182
182
  return _format_sql_default(self.default, dialect)
183
183
 
184
- def to_sql(self, dialect: str = "sqlite") -> str:
184
+ def to_sql(self, dialect: str = "sqlite", *, include_pk: bool = True) -> str:
185
+ """Generate SQL for column definition.
186
+
187
+ Args:
188
+ dialect: Database dialect
189
+ include_pk: If False, skip PRIMARY KEY clause (for composite PKs)
190
+ """
185
191
  parts = [f'"{self.name}"', self.get_type(dialect)]
186
- if self.primary_key:
192
+
193
+ # Handle primary key
194
+ if self.primary_key and include_pk:
187
195
  parts.append("PRIMARY KEY")
188
196
  if self.autoincrement and dialect == "sqlite":
189
197
  parts.append("AUTOINCREMENT")
198
+
199
+ # NOT NULL (PKs are implicitly NOT NULL)
190
200
  if not self.nullable and not self.primary_key:
191
201
  parts.append("NOT NULL")
202
+ elif self.primary_key and not include_pk:
203
+ # For composite PK, column must be NOT NULL
204
+ parts.append("NOT NULL")
205
+
192
206
  default_sql = self.get_default_sql(dialect)
193
207
  if default_sql:
194
208
  parts.append(default_sql)
209
+
195
210
  if self.unique and not self.primary_key:
196
211
  parts.append("UNIQUE")
212
+
197
213
  return " ".join(parts)
198
214
 
199
215
 
@@ -248,10 +264,30 @@ class CreateTable(Operation):
248
264
  foreign_keys: list[ForeignKeyDef] = field(default_factory=list)
249
265
 
250
266
  async def forward(self, conn: "AsyncConnection", dialect: str) -> None:
251
- cols = ",\n ".join(c.to_sql(dialect) for c in self.columns)
267
+ # Detect composite primary key
268
+ pk_columns = [c for c in self.columns if c.primary_key]
269
+ is_composite_pk = len(pk_columns) > 1
270
+
271
+ # Generate column definitions
272
+ col_defs = []
273
+ for c in self.columns:
274
+ # For composite PK, don't include PRIMARY KEY in column def
275
+ col_sql = c.to_sql(dialect, include_pk=not is_composite_pk)
276
+ col_defs.append(col_sql)
277
+
278
+ parts = col_defs.copy()
279
+
280
+ # Add composite PRIMARY KEY constraint if needed
281
+ if is_composite_pk:
282
+ pk_names = ", ".join(f'"{c.name}"' for c in pk_columns)
283
+ parts.append(f"PRIMARY KEY ({pk_names})")
284
+
285
+ # Add foreign keys
252
286
  if self.foreign_keys:
253
- fks = ",\n ".join(fk.to_sql(self.table_name) for fk in self.foreign_keys)
254
- cols += f",\n {fks}"
287
+ for fk in self.foreign_keys:
288
+ parts.append(fk.to_sql(self.table_name))
289
+
290
+ cols = ",\n ".join(parts)
255
291
  sql = f'CREATE TABLE IF NOT EXISTS "{self.table_name}" (\n {cols}\n)'
256
292
  await conn.execute(text(sql))
257
293
 
@@ -47,42 +47,36 @@ class Router(APIRouter):
47
47
  viewset_class: type["ViewSet"],
48
48
  basename: str | None = None,
49
49
  tags: list[str] | None = None,
50
+ include_crud: bool | None = None,
50
51
  ) -> None:
51
52
  """
52
53
  Registra um ViewSet com rotas REST automáticas.
53
54
 
54
- Gera as seguintes rotas (na ordem correta para evitar conflitos):
55
- 1. GET {prefix}/ -> list
56
- 2. POST {prefix}/ -> create
57
- 3. Custom actions com detail=False (ex: /users/types)
58
- 4. GET {prefix}/{id} -> retrieve
59
- 5. PUT {prefix}/{id} -> update
60
- 6. PATCH {prefix}/{id} -> partial_update
61
- 7. DELETE {prefix}/{id} -> destroy
62
- 8. Custom actions com detail=True (ex: /users/{id}/activate)
55
+ Para ViewSet com model: cria rotas CRUD + actions customizadas.
56
+ Para ViewSet sem model: cria apenas actions customizadas.
63
57
 
64
58
  Args:
65
59
  prefix: Prefixo da URL (ex: "/users")
66
60
  viewset_class: Classe do ViewSet
67
61
  basename: Nome base para as rotas (default: nome do model)
68
62
  tags: Tags para OpenAPI
69
-
70
- Note:
71
- Actions detail=False são registradas ANTES das rotas {id} para
72
- evitar conflitos onde /users/types seria interpretado como /users/{id}
73
- com id="types".
63
+ include_crud: Forçar criação de rotas CRUD (default: auto-detecta por model)
74
64
  """
75
65
  viewset = viewset_class()
76
66
 
67
+ # Detecta se tem model (para decidir sobre CRUD routes)
68
+ has_model = hasattr(viewset_class, "model") and viewset_class.model is not None
69
+
70
+ # Auto-detecta include_crud baseado em model, ou usa valor explícito
71
+ if include_crud is None:
72
+ include_crud = has_model
73
+
77
74
  # Infer basename from model or class name
78
75
  if basename is None:
79
76
  model = getattr(viewset_class, "model", None)
80
77
  if model is not None:
81
- # Use model's tablename or class name
82
78
  basename = getattr(model, "__tablename__", None) or model.__name__.lower()
83
79
  else:
84
- # Fallback: infer from ViewSet class name
85
- # UserViewSet -> user, EventViewSet -> event
86
80
  class_name = viewset_class.__name__
87
81
  basename = class_name.lower().replace("viewset", "").replace("view", "") or "api"
88
82
 
@@ -94,6 +88,14 @@ class Router(APIRouter):
94
88
  # Normaliza o prefixo
95
89
  prefix = prefix.rstrip("/")
96
90
 
91
+ # Se não tem model e não forçou CRUD, registra apenas actions customizadas
92
+ if not include_crud:
93
+ self._register_custom_actions(
94
+ prefix, viewset_class, basename, tags, lookup_url_kwarg,
95
+ detail_filter=None # Registra todas as actions
96
+ )
97
+ return
98
+
97
99
  # 1. Rota de lista (GET)
98
100
  @self.get(
99
101
  f"{prefix}/",
@@ -174,7 +174,20 @@ class APIView:
174
174
  method.upper(),
175
175
  self.permission_classes,
176
176
  )
177
- return [perm() for perm in perm_classes]
177
+
178
+ # Validate and instantiate permissions
179
+ instances = []
180
+ for i, perm in enumerate(perm_classes):
181
+ if not isinstance(perm, type):
182
+ class_name = type(perm).__name__
183
+ source = f"permission_classes_by_method['{method.upper()}']" if method.upper() in self.permission_classes_by_method else "permission_classes"
184
+ raise TypeError(
185
+ f"{source}[{i}] contains an instance of {class_name} instead of a class. "
186
+ f"Use [{class_name}] instead of [{class_name}()]"
187
+ )
188
+ instances.append(perm())
189
+
190
+ return instances
178
191
 
179
192
  async def check_permissions(self, request: Request, method: str) -> None:
180
193
  """Verifica permissões antes de executar o handler."""
@@ -361,7 +374,21 @@ class ViewSet(Generic[ModelT, InputT, OutputT]):
361
374
  action,
362
375
  self.permission_classes,
363
376
  )
364
- return [perm() for perm in perm_classes]
377
+
378
+ # Validate and instantiate permissions
379
+ instances = []
380
+ for i, perm in enumerate(perm_classes):
381
+ if not isinstance(perm, type):
382
+ # Already an instance - raise clear error
383
+ class_name = type(perm).__name__
384
+ source = f"permission_classes_by_action['{action}']" if action in self.permission_classes_by_action else "permission_classes"
385
+ raise TypeError(
386
+ f"{source}[{i}] contains an instance of {class_name} instead of a class. "
387
+ f"Use [{class_name}] instead of [{class_name}()]"
388
+ )
389
+ instances.append(perm())
390
+
391
+ return instances
365
392
 
366
393
  async def check_permissions(self, request: Request, action: str) -> None:
367
394
  """Verifica permissões antes de executar a action."""
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "core-framework"
3
- version = "0.12.24"
3
+ version = "0.12.26"
4
4
  description = "Core Framework - Django-inspired, FastAPI-powered. Alta performance, baixo acoplamento, produtividade extrema."
5
5
  requires-python = ">=3.10,<4.0"
6
6
  readme = "README.md"