core-framework 0.12.12__py3-none-any.whl → 0.12.14__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/migrations/engine.py +40 -1
- core/migrations/operations.py +59 -21
- {core_framework-0.12.12.dist-info → core_framework-0.12.14.dist-info}/METADATA +1 -1
- {core_framework-0.12.12.dist-info → core_framework-0.12.14.dist-info}/RECORD +7 -7
- {core_framework-0.12.12.dist-info → core_framework-0.12.14.dist-info}/WHEEL +0 -0
- {core_framework-0.12.12.dist-info → core_framework-0.12.14.dist-info}/entry_points.txt +0 -0
core/__init__.py
CHANGED
core/migrations/engine.py
CHANGED
|
@@ -52,6 +52,41 @@ if TYPE_CHECKING:
|
|
|
52
52
|
MIGRATIONS_TABLE = "_core_migrations"
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
def _detect_extra_imports(ops_code: str) -> list[str]:
|
|
56
|
+
"""
|
|
57
|
+
Detect and return extra import statements needed for migration code.
|
|
58
|
+
|
|
59
|
+
Analyzes the generated operation code to find references like:
|
|
60
|
+
- timezone.now -> from core.datetime import timezone
|
|
61
|
+
- AdvancedField.xxx -> from core.fields import AdvancedField
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
ops_code: The generated operation code string
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
List of import statements to add to the migration file
|
|
68
|
+
"""
|
|
69
|
+
imports = set()
|
|
70
|
+
|
|
71
|
+
# Patterns for short-form callable references
|
|
72
|
+
# These match the output of _serialize_default()
|
|
73
|
+
patterns = [
|
|
74
|
+
# timezone.xxx -> from core.datetime import timezone
|
|
75
|
+
# Match timezone.now but not datetime.timezone.now
|
|
76
|
+
(r'(?<![.\w])timezone\.\w+', 'from core.datetime import timezone'),
|
|
77
|
+
# AdvancedField.xxx -> from core.fields import AdvancedField
|
|
78
|
+
(r'(?<![.\w])AdvancedField\.\w+', 'from core.fields import AdvancedField'),
|
|
79
|
+
# datetime.xxx -> from datetime import datetime (for full module path)
|
|
80
|
+
(r'(?<![.\w])datetime\.\w+', 'from datetime import datetime'),
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
for pattern, import_stmt in patterns:
|
|
84
|
+
if re.search(pattern, ops_code):
|
|
85
|
+
imports.add(import_stmt)
|
|
86
|
+
|
|
87
|
+
return sorted(imports)
|
|
88
|
+
|
|
89
|
+
|
|
55
90
|
def _get_migrations_table_sql(dialect: str) -> str:
|
|
56
91
|
"""
|
|
57
92
|
Returns dialect-specific SQL for creating migrations table.
|
|
@@ -442,6 +477,10 @@ class MigrationEngine:
|
|
|
442
477
|
|
|
443
478
|
ops_str = ",\n".join(ops_code) if ops_code else " # No operations"
|
|
444
479
|
|
|
480
|
+
# Detect and add extra imports needed for callable defaults
|
|
481
|
+
extra_imports = _detect_extra_imports(ops_str)
|
|
482
|
+
extra_imports_str = "\n".join(extra_imports) + "\n" if extra_imports else ""
|
|
483
|
+
|
|
445
484
|
return f'''"""
|
|
446
485
|
Migration: {name}
|
|
447
486
|
Generated at: {timezone.now().isoformat()}
|
|
@@ -467,7 +506,7 @@ from core.migrations.operations import (
|
|
|
467
506
|
DropEnum,
|
|
468
507
|
AlterEnum,
|
|
469
508
|
)
|
|
470
|
-
|
|
509
|
+
{extra_imports_str}
|
|
471
510
|
|
|
472
511
|
migration = Migration(
|
|
473
512
|
name="{name}",
|
core/migrations/operations.py
CHANGED
|
@@ -26,7 +26,7 @@ def _serialize_default(value: Any) -> str:
|
|
|
26
26
|
- None -> "None"
|
|
27
27
|
- Strings -> repr()
|
|
28
28
|
- Booleans -> "True"/"False"
|
|
29
|
-
- Callables -> "
|
|
29
|
+
- Callables -> short name (e.g., "timezone.now" not "core.datetime.timezone.now")
|
|
30
30
|
- Other -> repr()
|
|
31
31
|
|
|
32
32
|
Args:
|
|
@@ -41,11 +41,21 @@ def _serialize_default(value: Any) -> str:
|
|
|
41
41
|
if callable(value):
|
|
42
42
|
# Get module and function name for proper serialization
|
|
43
43
|
module = getattr(value, "__module__", "")
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if module and
|
|
47
|
-
#
|
|
48
|
-
|
|
44
|
+
qualname = getattr(value, "__qualname__", "") or getattr(value, "__name__", "")
|
|
45
|
+
|
|
46
|
+
if module and qualname:
|
|
47
|
+
# Use short form for known modules to avoid long paths
|
|
48
|
+
# e.g., "core.datetime.timezone.now" -> "timezone.now"
|
|
49
|
+
# The corresponding import will be added to the migration file
|
|
50
|
+
if module == "core.datetime" and qualname.startswith("timezone."):
|
|
51
|
+
return qualname # Returns "timezone.now"
|
|
52
|
+
if module == "core.fields" and qualname.startswith("AdvancedField."):
|
|
53
|
+
return qualname # Returns "AdvancedField.json_field..."
|
|
54
|
+
if module == "datetime":
|
|
55
|
+
return f"datetime.{qualname}" # Returns "datetime.now"
|
|
56
|
+
|
|
57
|
+
# For other modules, return full path
|
|
58
|
+
return f"{module}.{qualname}"
|
|
49
59
|
|
|
50
60
|
# Fallback for lambdas or unnamed functions
|
|
51
61
|
return "None"
|
|
@@ -139,10 +149,30 @@ class ColumnDef:
|
|
|
139
149
|
|
|
140
150
|
Returns:
|
|
141
151
|
String SQL para o default ou None
|
|
152
|
+
|
|
153
|
+
Note:
|
|
154
|
+
Callable defaults (like timezone.now) cannot be used as SQL DEFAULT.
|
|
155
|
+
They are handled by the application layer when creating records.
|
|
156
|
+
For timestamp defaults, use server-side defaults like CURRENT_TIMESTAMP.
|
|
142
157
|
"""
|
|
143
158
|
if self.default is None:
|
|
144
159
|
return None
|
|
145
160
|
|
|
161
|
+
# Callable defaults cannot be used in SQL - they're Python functions
|
|
162
|
+
# The ORM handles these when creating records
|
|
163
|
+
if callable(self.default):
|
|
164
|
+
# For datetime-related callables, use SQL equivalent
|
|
165
|
+
func_name = getattr(self.default, "__name__", "") or getattr(self.default, "__qualname__", "")
|
|
166
|
+
if "now" in func_name.lower() or "utcnow" in func_name.lower():
|
|
167
|
+
if dialect == "postgresql":
|
|
168
|
+
return "DEFAULT CURRENT_TIMESTAMP"
|
|
169
|
+
elif dialect == "sqlite":
|
|
170
|
+
return "DEFAULT CURRENT_TIMESTAMP"
|
|
171
|
+
elif dialect == "mysql":
|
|
172
|
+
return "DEFAULT CURRENT_TIMESTAMP"
|
|
173
|
+
# For other callables, skip DEFAULT (handled by ORM)
|
|
174
|
+
return None
|
|
175
|
+
|
|
146
176
|
if isinstance(self.default, str):
|
|
147
177
|
return f"DEFAULT '{self.default}'"
|
|
148
178
|
|
|
@@ -260,23 +290,10 @@ class CreateTable(Operation):
|
|
|
260
290
|
return f"Create table '{self.table_name}'"
|
|
261
291
|
|
|
262
292
|
def to_code(self) -> str:
|
|
263
|
-
|
|
264
|
-
"""Serializa valor default para código Python válido."""
|
|
265
|
-
if val is None:
|
|
266
|
-
return "None"
|
|
267
|
-
if callable(val):
|
|
268
|
-
# Funções como datetime.utcnow não podem ser serializadas
|
|
269
|
-
# Usamos None e deixamos o banco lidar com o default
|
|
270
|
-
return "None"
|
|
271
|
-
if isinstance(val, str):
|
|
272
|
-
return f"'{val}'"
|
|
273
|
-
if isinstance(val, bool):
|
|
274
|
-
return str(val)
|
|
275
|
-
return repr(val)
|
|
276
|
-
|
|
293
|
+
# Use global _serialize_default for consistent callable serialization
|
|
277
294
|
cols = ",\n ".join(
|
|
278
295
|
f"ColumnDef(name='{c.name}', type='{c.type}', nullable={c.nullable}, "
|
|
279
|
-
f"default={
|
|
296
|
+
f"default={_serialize_default(c.default)}, primary_key={c.primary_key}, "
|
|
280
297
|
f"autoincrement={c.autoincrement}, unique={c.unique})"
|
|
281
298
|
for c in self.columns
|
|
282
299
|
)
|
|
@@ -459,6 +476,27 @@ class AlterColumn(Operation):
|
|
|
459
476
|
if self.set_default:
|
|
460
477
|
changes.append(f"default to {self.new_default}")
|
|
461
478
|
return f"Alter column '{self.column_name}' in '{self.table_name}': {', '.join(changes)}"
|
|
479
|
+
|
|
480
|
+
def to_code(self) -> str:
|
|
481
|
+
"""Gera código Python para AlterColumn com serialização correta de callables."""
|
|
482
|
+
new_type_str = f"'{self.new_type}'" if self.new_type else "None"
|
|
483
|
+
old_type_str = f"'{self.old_type}'" if self.old_type else "None"
|
|
484
|
+
|
|
485
|
+
# Serializa defaults corretamente (callables, None, strings, etc.)
|
|
486
|
+
new_default_str = _serialize_default(self.new_default)
|
|
487
|
+
old_default_str = _serialize_default(self.old_default)
|
|
488
|
+
|
|
489
|
+
return f"""AlterColumn(
|
|
490
|
+
table_name='{self.table_name}',
|
|
491
|
+
column_name='{self.column_name}',
|
|
492
|
+
new_type={new_type_str},
|
|
493
|
+
new_nullable={self.new_nullable},
|
|
494
|
+
new_default={new_default_str},
|
|
495
|
+
set_default={self.set_default},
|
|
496
|
+
old_type={old_type_str},
|
|
497
|
+
old_nullable={self.old_nullable},
|
|
498
|
+
old_default={old_default_str},
|
|
499
|
+
)"""
|
|
462
500
|
|
|
463
501
|
|
|
464
502
|
@dataclass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-framework
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.14
|
|
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=snols40N_-yCjaz9cgyqalmecS79-JSOyoyRWQJhWKc,12232
|
|
2
2
|
core/app.py,sha256=SsMC5Vlj6PNgACXlfeccOm6CQEKfgh3q3X2p9ubRDlQ,23092
|
|
3
3
|
core/choices.py,sha256=rhcL3p2dB7RK99zIilpmoTFVcibQEIaRpz0CY0kImCE,10502
|
|
4
4
|
core/config.py,sha256=dq4O7QBdrdwj-fZRe2yhX1fKyi_Uetb6sx9-RovJ-9c,14771
|
|
@@ -63,9 +63,9 @@ core/messaging/redis/producer.py,sha256=F9NA1GpYvN-wdW5Ilzi49rrAmxfBmicXX3l6sABW
|
|
|
63
63
|
core/migrations/__init__.py,sha256=OF_7XQ9x9V_BWr3d8vDZk8W5QYT0RO3ZXNFnOg8UgDI,1908
|
|
64
64
|
core/migrations/analyzer.py,sha256=QiwG_Xf_-Mb-Kp4hstkF8xNJD0Tvxgz20vqvYZ6xEXM,27287
|
|
65
65
|
core/migrations/cli.py,sha256=mR3lIFTlXSvupFOPVlfuC-urJyDfNFR9nqYZn4TjIco,12019
|
|
66
|
-
core/migrations/engine.py,sha256=
|
|
66
|
+
core/migrations/engine.py,sha256=UKvD7SAE8A7McL72LdOF6NHx7D90FAPyIwnKLZ5vueo,33125
|
|
67
67
|
core/migrations/migration.py,sha256=Xv5MSNLvGAR9wnuMc4GRwciUSuU22AxWlWZP-hsVliI,2748
|
|
68
|
-
core/migrations/operations.py,sha256=
|
|
68
|
+
core/migrations/operations.py,sha256=zAIusGVLae-K3TX7iDrViWRCEBGS1STpAZ67Ghi9vOM,31728
|
|
69
69
|
core/migrations/state.py,sha256=eb_EYTE1tG-xQIwliS_-QTgr0y8-Jj0Va4C3nfpMrd4,15324
|
|
70
70
|
core/tasks/__init__.py,sha256=rDP4PD7Qtw8qbSbOtxMco9w2wBxRJl5uHiLUEDM0DYI,1662
|
|
71
71
|
core/tasks/base.py,sha256=0EWEzWTez0iF6nlI7Aw3stZtBk0Cr7zZ9btI89YdWPU,11762
|
|
@@ -87,7 +87,7 @@ example/auth.py,sha256=zBpLutb8lVKnGfQqQ2wnyygsSutHYZzeJBuhnFhxBaQ,4971
|
|
|
87
87
|
example/models.py,sha256=xKdx0kJ9n0tZ7sCce3KhV3BTvKvsh6m7G69eFm3ukf0,4549
|
|
88
88
|
example/schemas.py,sha256=wJ9QofnuHp4PjtM_IuMMBLVFVDJ4YlwcF6uQm1ooKiY,6139
|
|
89
89
|
example/views.py,sha256=GQwgQcW6yoeUIDbF7-lsaZV7cs8G1S1vGVtiwVpZIQE,14338
|
|
90
|
-
core_framework-0.12.
|
|
91
|
-
core_framework-0.12.
|
|
92
|
-
core_framework-0.12.
|
|
93
|
-
core_framework-0.12.
|
|
90
|
+
core_framework-0.12.14.dist-info/METADATA,sha256=7mZVblvxKc81kmvMiueoMT7WMG-ZCQuvXyl5uAYHP70,13021
|
|
91
|
+
core_framework-0.12.14.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
92
|
+
core_framework-0.12.14.dist-info/entry_points.txt,sha256=MJytamxHbn0CyH3HbxiP-PqOWekjYUo2CA6EWiKWuSI,78
|
|
93
|
+
core_framework-0.12.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|