iceaxe 0.7.0.dev2__tar.gz → 0.7.0.dev3__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.

Potentially problematic release.


This version of iceaxe might be problematic. Click here for more details.

Files changed (80) hide show
  1. {iceaxe-0.7.0.dev2/iceaxe.egg-info → iceaxe-0.7.0.dev3}/PKG-INFO +1 -1
  2. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/schemas/test_actions.py +5 -5
  3. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/schemas/test_db_memory_serializer.py +2 -2
  4. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/schemas/test_db_serializer.py +46 -0
  5. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_comparison.py +27 -0
  6. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/schemas/actions.py +2 -2
  7. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/schemas/db_memory_serializer.py +4 -4
  8. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/sql_types.py +33 -4
  9. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3/iceaxe.egg-info}/PKG-INFO +1 -1
  10. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/pyproject.toml +1 -1
  11. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/LICENSE +0 -0
  12. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/MANIFEST.in +0 -0
  13. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/README.md +0 -0
  14. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__init__.py +0 -0
  15. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/__init__.py +0 -0
  16. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/benchmarks/__init__.py +0 -0
  17. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/benchmarks/test_bulk_insert.py +0 -0
  18. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/benchmarks/test_select.py +0 -0
  19. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/conf_models.py +0 -0
  20. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/conftest.py +0 -0
  21. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/helpers.py +0 -0
  22. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/migrations/__init__.py +0 -0
  23. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/migrations/conftest.py +0 -0
  24. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/migrations/test_action_sorter.py +0 -0
  25. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/migrations/test_generator.py +0 -0
  26. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/migrations/test_generics.py +0 -0
  27. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/mountaineer/__init__.py +0 -0
  28. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/mountaineer/dependencies/__init__.py +0 -0
  29. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/mountaineer/dependencies/test_core.py +0 -0
  30. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/schemas/__init__.py +0 -0
  31. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/schemas/test_cli.py +0 -0
  32. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/schemas/test_db_stubs.py +0 -0
  33. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_alias.py +0 -0
  34. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_base.py +0 -0
  35. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_field.py +0 -0
  36. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_helpers.py +0 -0
  37. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_modifications.py +0 -0
  38. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_queries.py +0 -0
  39. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_queries_str.py +0 -0
  40. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_session.py +0 -0
  41. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/__tests__/test_text_search.py +0 -0
  42. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/alias_values.py +0 -0
  43. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/base.py +0 -0
  44. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/comparison.py +0 -0
  45. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/field.py +0 -0
  46. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/functions.py +0 -0
  47. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/generics.py +0 -0
  48. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/io.py +0 -0
  49. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/logging.py +0 -0
  50. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/__init__.py +0 -0
  51. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/action_sorter.py +0 -0
  52. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/cli.py +0 -0
  53. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/client_io.py +0 -0
  54. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/generator.py +0 -0
  55. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/migration.py +0 -0
  56. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/migrations/migrator.py +0 -0
  57. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/modifications.py +0 -0
  58. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/mountaineer/__init__.py +0 -0
  59. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/mountaineer/cli.py +0 -0
  60. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/mountaineer/config.py +0 -0
  61. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/mountaineer/dependencies/__init__.py +0 -0
  62. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/mountaineer/dependencies/core.py +0 -0
  63. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/postgres.py +0 -0
  64. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/py.typed +0 -0
  65. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/queries.py +0 -0
  66. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/queries_str.py +0 -0
  67. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/schemas/__init__.py +0 -0
  68. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/schemas/cli.py +0 -0
  69. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/schemas/db_serializer.py +0 -0
  70. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/schemas/db_stubs.py +0 -0
  71. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/session.py +0 -0
  72. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/session_optimized.c +0 -0
  73. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/session_optimized.pyx +0 -0
  74. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe/typing.py +0 -0
  75. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe.egg-info/SOURCES.txt +0 -0
  76. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe.egg-info/dependency_links.txt +0 -0
  77. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe.egg-info/requires.txt +0 -0
  78. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/iceaxe.egg-info/top_level.txt +0 -0
  79. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/setup.cfg +0 -0
  80. {iceaxe-0.7.0.dev2 → iceaxe-0.7.0.dev3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iceaxe
3
- Version: 0.7.0.dev2
3
+ Version: 0.7.0.dev3
4
4
  Summary: A modern, fast ORM for Python.
5
5
  Author-email: Pierce Freeman <pierce@freeman.vc>
6
6
  Requires-Python: >=3.11
@@ -263,8 +263,8 @@ async def test_add_column_any_type(
263
263
  (ColumnType.SERIAL, ColumnType.INTEGER),
264
264
  (ColumnType.BIGSERIAL, ColumnType.BIGINT),
265
265
  (ColumnType.CHAR, "character"),
266
- (ColumnType.TIME, "time without time zone"),
267
- (ColumnType.TIMESTAMP, "timestamp without time zone"),
266
+ (ColumnType.TIME_WITHOUT_TIME_ZONE, "time without time zone"),
267
+ (ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE, "timestamp without time zone"),
268
268
  )
269
269
 
270
270
  allowed_values = {enum_value.value}
@@ -365,7 +365,7 @@ async def test_modify_column_type(
365
365
  (ColumnType.VARCHAR, ColumnType.DATE, "2023-01-01", "2023-01-01", True),
366
366
  (
367
367
  ColumnType.TEXT,
368
- ColumnType.TIMESTAMP,
368
+ ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
369
369
  "2023-01-01 12:00:00",
370
370
  "2023-01-01 12:00:00",
371
371
  True,
@@ -443,7 +443,7 @@ async def test_modify_column_type_with_autocast(
443
443
  actual_value = row[column_name]
444
444
  if isinstance(expected_value, str) and to_type in [
445
445
  ColumnType.DATE,
446
- ColumnType.TIMESTAMP,
446
+ ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
447
447
  ]:
448
448
  # For date/timestamp, convert to string for comparison
449
449
  actual_value = str(actual_value)
@@ -1158,7 +1158,7 @@ async def test_modify_column_type_date_to_timestamp(
1158
1158
  await db_backed_actions.modify_column_type(
1159
1159
  table_name,
1160
1160
  column_name,
1161
- explicit_data_type=ColumnType.TIMESTAMP,
1161
+ explicit_data_type=ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
1162
1162
  autocast=False,
1163
1163
  )
1164
1164
 
@@ -750,7 +750,7 @@ def test_enum_column_assignment(clear_all_database_objects):
750
750
  DBColumn(
751
751
  table_name="exampledbmodel",
752
752
  column_name="standard_datetime",
753
- column_type=ColumnType.TIMESTAMP,
753
+ column_type=ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
754
754
  column_is_list=False,
755
755
  nullable=False,
756
756
  ),
@@ -810,7 +810,7 @@ def test_enum_column_assignment(clear_all_database_objects):
810
810
  DBColumn(
811
811
  table_name="exampledbmodel",
812
812
  column_name="standard_time",
813
- column_type=ColumnType.TIME,
813
+ column_type=ColumnType.TIME_WITHOUT_TIME_ZONE,
814
814
  column_is_list=False,
815
815
  nullable=False,
816
816
  ),
@@ -143,6 +143,52 @@ class ValueEnumInt(IntEnum):
143
143
  )
144
144
  ],
145
145
  ),
146
+ # Test PostgreSQL's storage format for timestamp without timezone
147
+ (
148
+ """
149
+ CREATE TABLE exampledbmodel (
150
+ id SERIAL PRIMARY KEY,
151
+ created_at TIMESTAMP NOT NULL
152
+ );
153
+ """,
154
+ [
155
+ (
156
+ DBColumn(
157
+ table_name="exampledbmodel",
158
+ column_name="created_at",
159
+ column_type=ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
160
+ column_is_list=False,
161
+ nullable=False,
162
+ ),
163
+ [
164
+ DBTable(table_name="exampledbmodel"),
165
+ ],
166
+ )
167
+ ],
168
+ ),
169
+ # Test PostgreSQL's storage format for timestamp with timezone
170
+ (
171
+ """
172
+ CREATE TABLE exampledbmodel (
173
+ id SERIAL PRIMARY KEY,
174
+ created_at TIMESTAMPTZ NOT NULL
175
+ );
176
+ """,
177
+ [
178
+ (
179
+ DBColumn(
180
+ table_name="exampledbmodel",
181
+ column_name="created_at",
182
+ column_type=ColumnType.TIMESTAMP_WITH_TIME_ZONE,
183
+ column_is_list=False,
184
+ nullable=False,
185
+ ),
186
+ [
187
+ DBTable(table_name="exampledbmodel"),
188
+ ],
189
+ )
190
+ ],
191
+ ),
146
192
  ],
147
193
  )
148
194
  async def test_simple_db_serializer(
@@ -10,6 +10,7 @@ from iceaxe.base import TableBase
10
10
  from iceaxe.comparison import ComparisonType, FieldComparison
11
11
  from iceaxe.field import DBFieldClassDefinition, DBFieldInfo
12
12
  from iceaxe.queries_str import QueryLiteral
13
+ from iceaxe.sql_types import ColumnType
13
14
  from iceaxe.typing import column
14
15
 
15
16
 
@@ -354,3 +355,29 @@ def test_force_join_constraints(
354
355
  )
355
356
  forced = comparison.force_join_constraints()
356
357
  assert forced.comparison == expected_comparison
358
+
359
+
360
+ @pytest.mark.parametrize(
361
+ "sql_type_string, expected_column_type",
362
+ [
363
+ ("timestamp", ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE), # Tests aliasing
364
+ ("timestamp without time zone", ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE),
365
+ ("timestamp with time zone", ColumnType.TIMESTAMP_WITH_TIME_ZONE),
366
+ ("time", ColumnType.TIME_WITHOUT_TIME_ZONE), # Tests aliasing
367
+ ("time without time zone", ColumnType.TIME_WITHOUT_TIME_ZONE),
368
+ ("time with time zone", ColumnType.TIME_WITH_TIME_ZONE),
369
+ ],
370
+ )
371
+ def test_postgres_datetime_timezone_casting(
372
+ sql_type_string: str, expected_column_type: ColumnType
373
+ ):
374
+ """
375
+ Test that PostgresDateTime fields with different timezone configurations
376
+ are properly handled by the ColumnType enum, specifically testing that
377
+ PostgreSQL's storage format ('timestamp without time zone') can be parsed.
378
+ This also tests that SQL standard aliases like "timestamp" correctly map
379
+ to "timestamp without time zone".
380
+ """
381
+
382
+ # Test that ColumnType enum can handle PostgreSQL's storage formats and aliases
383
+ assert ColumnType(sql_type_string) == expected_column_type
@@ -408,8 +408,8 @@ class DatabaseActions:
408
408
  return f"{column_name}::boolean"
409
409
  elif explicit_data_type in [
410
410
  ColumnType.DATE,
411
- ColumnType.TIMESTAMP,
412
- ColumnType.TIME,
411
+ ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
412
+ ColumnType.TIME_WITHOUT_TIME_ZONE,
413
413
  ]:
414
414
  # Date/time conversions
415
415
  return f"{column_name}::{explicit_data_type.value}"
@@ -454,12 +454,12 @@ class DatabaseHandler:
454
454
  primitive_type=(
455
455
  ColumnType.TIMESTAMP_WITH_TIME_ZONE
456
456
  if info.postgres_config.timezone
457
- else ColumnType.TIMESTAMP
457
+ else ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE
458
458
  )
459
459
  )
460
460
  # Assume no timezone if not specified
461
461
  return TypeDeclarationResponse(
462
- primitive_type=ColumnType.TIMESTAMP,
462
+ primitive_type=ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
463
463
  )
464
464
  elif is_type_compatible(annotation, date): # type: ignore
465
465
  return TypeDeclarationResponse(
@@ -471,11 +471,11 @@ class DatabaseHandler:
471
471
  primitive_type=(
472
472
  ColumnType.TIME_WITH_TIME_ZONE
473
473
  if info.postgres_config.timezone
474
- else ColumnType.TIME
474
+ else ColumnType.TIME_WITHOUT_TIME_ZONE
475
475
  ),
476
476
  )
477
477
  return TypeDeclarationResponse(
478
- primitive_type=ColumnType.TIME,
478
+ primitive_type=ColumnType.TIME_WITHOUT_TIME_ZONE,
479
479
  )
480
480
  elif is_type_compatible(annotation, timedelta): # type: ignore
481
481
  return TypeDeclarationResponse(
@@ -8,6 +8,10 @@ class ColumnType(StrEnum):
8
8
  # the column they can be case-insensitive, but when we're casting from
9
9
  # the database to memory they must align with the on-disk representation
10
10
  # which is lowercase.
11
+ #
12
+ # Note: The SQL standard requires that writing just "timestamp" be equivalent
13
+ # to "timestamp without time zone", and PostgreSQL honors that behavior.
14
+ # Similarly, "time" is equivalent to "time without time zone".
11
15
 
12
16
  # Numeric Types
13
17
  SMALLINT = "smallint"
@@ -33,9 +37,9 @@ class ColumnType(StrEnum):
33
37
 
34
38
  # Date/Time Types
35
39
  DATE = "date"
36
- TIME = "time"
40
+ TIME_WITHOUT_TIME_ZONE = "time without time zone"
37
41
  TIME_WITH_TIME_ZONE = "time with time zone"
38
- TIMESTAMP = "timestamp"
42
+ TIMESTAMP_WITHOUT_TIME_ZONE = "timestamp without time zone"
39
43
  TIMESTAMP_WITH_TIME_ZONE = "timestamp with time zone"
40
44
  INTERVAL = "interval"
41
45
 
@@ -85,6 +89,31 @@ class ColumnType(StrEnum):
85
89
  # Object Identifier Type
86
90
  OID = "oid"
87
91
 
92
+ @classmethod
93
+ def _missing_(cls, value: object):
94
+ """
95
+ Handle SQL standard aliases when the exact enum value is not found.
96
+
97
+ The SQL standard requires that "timestamp" be equivalent to "timestamp without time zone"
98
+ and "time" be equivalent to "time without time zone".
99
+ """
100
+ # Only handle string values for SQL type aliases
101
+ if not isinstance(value, str):
102
+ return None
103
+
104
+ aliases = {
105
+ "timestamp": "timestamp without time zone",
106
+ "time": "time without time zone",
107
+ }
108
+
109
+ # Check if this is an alias we can resolve
110
+ if value in aliases:
111
+ # Return the actual enum member for the aliased value
112
+ return cls(aliases[value])
113
+
114
+ # If not an alias, let the default enum behavior handle it
115
+ return None
116
+
88
117
 
89
118
  class ConstraintType(StrEnum):
90
119
  PRIMARY_KEY = "PRIMARY KEY"
@@ -105,9 +134,9 @@ def get_python_to_sql_mapping():
105
134
  bool: ColumnType.BOOLEAN,
106
135
  bytes: ColumnType.BYTEA,
107
136
  UUID: ColumnType.UUID,
108
- datetime: ColumnType.TIMESTAMP,
137
+ datetime: ColumnType.TIMESTAMP_WITHOUT_TIME_ZONE,
109
138
  date: ColumnType.DATE,
110
- time: ColumnType.TIME,
139
+ time: ColumnType.TIME_WITHOUT_TIME_ZONE,
111
140
  timedelta: ColumnType.INTERVAL,
112
141
  }
113
142
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iceaxe
3
- Version: 0.7.0.dev2
3
+ Version: 0.7.0.dev3
4
4
  Summary: A modern, fast ORM for Python.
5
5
  Author-email: Pierce Freeman <pierce@freeman.vc>
6
6
  Requires-Python: >=3.11
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "iceaxe"
3
- version = "0.7.0.dev2"
3
+ version = "0.7.0.dev3"
4
4
  description = "A modern, fast ORM for Python."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes