`TIMESTAMP`, `TIMESTAMP_NTZ`, `TINYINT` and the other `TypeDecorator`s don't declare `python_type`
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 78/100
Hướng nghiên cứu
Bắt đầu tại src/databricks/sqlalchemy/_types.py, nơi định nghĩa năm lớp con TypeDecorator, rồi đọc phần triển khai và các bài kiểm thử kiểu hiện có. Kiểm tra python_type của từng kiểu có khớp với các giá trị mà nó trả về hay không: datetime cho TIMESTAMP và TIMESTAMP_NTZ, int cho TINYINT, time cho DatabricksTimeType và str cho DatabricksStringType. Hoàn tất khi các kiểu đó báo cáo đúng các lớp Python mong đợi trên những phiên bản SQLAlchemy được hỗ trợ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description of the bug
Our use case
We generate SQLAlchemy ORM models from Databricks tables with sqlacodegen. It reflects the tables through this dialect and annotates each column with the column type's python_type, for example Mapped[str | None] for a STRING column.
For TIMESTAMP, TIMESTAMP_NTZ and TINYINT columns we get Mapped[object | None] instead of Mapped[datetime | None] and Mapped[int | None]. These are the types reflection returns for timestamp, timestamp_ntz and tinyint. Type checkers then accept any value for these attributes, and any code reading them sees object.
The same happens to any other tool that reads python_type, and to the two types the dialect uses in place of Time and String through its colspecs (DatabricksTimeType and DatabricksStringType).
The bug
These five types are sqlalchemy.types.TypeDecorator subclasses that don't declare python_type:
| Type | impl |
Values returned | python_type |
|---|---|---|---|
TIMESTAMP |
DateTime |
datetime |
object |
TIMESTAMP_NTZ |
DateTime |
datetime |
object |
TINYINT |
SmallInteger |
int |
object |
DatabricksTimeType |
Time |
time |
object |
DatabricksStringType |
String |
str |
object |
TypeDecorator doesn't take python_type from its impl, so these types get the TypeEngine default: object in SQLAlchemy 2.1, and a NotImplementedError in 2.0.
The SQLAlchemy maintainers consider this the intended behaviour. A TypeDecorator can return different values from its impl through process_result_value, so only the decorator knows its Python type, and it's expected to declare python_type itself: link to the SQLAlchemy discussion.
Versions
- databricks-sqlalchemy: 2.0.10 (also on
main) - databricks-sql-connector: 4.6.0
- SQLAlchemy: 2.1.4, and 2.0.54
- Python: 3.12
- OS: Linux
To Reproduce
No connection is needed:
import datetime
from importlib.metadata import version
import sqlalchemy as sa
from databricks.sqlalchemy import TIMESTAMP, TIMESTAMP_NTZ, TINYINT, DatabricksDialect
print("SQLAlchemy", sa.__version__)
print("databricks-sqlalchemy", version("databricks-sqlalchemy"))
dialect = DatabricksDialect()
expected = {
# The types reflection returns for timestamp, timestamp_ntz and tinyint.
"TIMESTAMP": (TIMESTAMP(), datetime.datetime),
"TIMESTAMP_NTZ": (TIMESTAMP_NTZ(), datetime.datetime),
"TINYINT": (TINYINT(), int),
# The types the dialect uses in place of Time and String.
"Time": (sa.Time().dialect_impl(dialect), datetime.time),
"String": (sa.String().dialect_impl(dialect), str),
}
for name, (type_, python_type) in expected.items():
print(f"{name:14} {type(type_).__name__:20} python_type: {type_.python_type}")
for name, (type_, python_type) in expected.items():
assert type_.python_type is python_type, name
Output
With SQLAlchemy 2.1.4:
SQLAlchemy 2.1.4
databricks-sqlalchemy 2.0.10
TIMESTAMP TIMESTAMP python_type: <class 'object'>
TIMESTAMP_NTZ TIMESTAMP_NTZ python_type: <class 'object'>
TINYINT TINYINT python_type: <class 'object'>
Time DatabricksTimeType python_type: <class 'object'>
String DatabricksStringType python_type: <class 'object'>
Traceback (most recent call last):
...
AssertionError: TIMESTAMP
With SQLAlchemy 2.0.54, the first python_type raises NotImplementedError.
Expected behaviour
Each type's python_type is the type of the values it returns: datetime for TIMESTAMP and TIMESTAMP_NTZ, int for TINYINT, time for DatabricksTimeType and str for DatabricksStringType.
Possible fix
Declare python_type on each type in src/databricks/sqlalchemy/_types.py, which already imports datetime and time from datetime:
class TIMESTAMP_NTZ(sqlalchemy.types.TypeDecorator):
...
@property
def python_type(self) -> type:
return datetime
The same goes for TIMESTAMP (datetime), TINYINT (int), DatabricksTimeType (time) and DatabricksStringType (str).
Additional context
-
DatabricksArray,DatabricksMapandDatabricksVariantalso reportobject, becauseUserDefinedTypehas the same default. That's right for all three today.VARIANTcan hold any value, andARRAYandMAPhave noresult_processor, so their values are whatever the connector returns, which depends on its settings:databricks-sql-connector 4.6.0 ARRAYMAPdefault numpy.ndarraylistof(key, value)tuplesdisable_pandas=Truelistlistof(key, value)tuples_use_arrow_native_complex_types=Falsestr(JSON)str(JSON)A
result_processorconverting the values tolistanddictwould let these two types declarepython_typetoo, but that changes the values users get, so it's not part of this request. -
Our workaround: when a
TypeDecoratorreportsobject, we use itsimpl'spython_type. That's correct for the five types above, but as the SQLAlchemy maintainers point out, it's only a guess in general.
Thank you!
- Ngôn ngữ chính
- Python
- Star
- 24
- Fork
- 20
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của databricks/databricks-sqlalchemy
-
get_columns() missing @reflection.cache causes a warehouse round-trip on every reflection callCó thể đã có người làm @TangoEnSkai đã nhận 50 ngày trước. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 92/100
-
get_foreign_keys() missing @reflection.cache causes excessive DESCRIBE TABLE EXTENDED queriesCó thể đã có người làm @TangoEnSkai đã nhận 50 ngày trước. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
-
TypeError when using Enum columns with the Databricks dialect (all 2.0.x releases)Có thể đã có người làm @TangoEnSkai đã nhận 50 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 64/100
databricks/databricks-sqlalchemy#77 · 3 bình luận ·
-
Unable to insert Python lists into ARRAY<STRING> columns using pandas to_sqlCó thể đã có người làm @aminghadersohi đã nhận 16 ngày trước. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
databricks/databricks-sqlalchemy#73 · 1 bình luận ·
Tất cả issue của databricks/databricks-sqlalchemy
Issue tương tự
-
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 88/100
gradio-app/gradio#13964 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 93/100
BSData/horus-heresy-3rd-edition#3232 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
jbacalso24/mimry#123 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
p:3-mid pydanty:bug pydanty:is-working
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
pydantic/pydantic-ai#10153 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
good first issue priority: medium size: S testing
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
cubrid-lab/cubrid-cookbook-python#316 ·
Maintainer thường phản hồi trong vòng 1 ngày