From 5319ffca4719c9ca6129aa648a4c2694fcd8d1ab Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 28 Aug 2024 19:57:40 +0200 Subject: [PATCH 1/2] Chore: Add and validate type hinting using mypy --- pyproject.toml | 2 +- src/sqlalchemy_cratedb/compat/api13.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 12a831e6..560acf19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -259,7 +259,7 @@ tasks.lint = [ { cmd = "ruff format --check" }, { cmd = "ruff check" }, { cmd = "validate-pyproject pyproject.toml" }, - # { cmd = "mypy" }, + { cmd = "mypy" }, ] tasks.release = [ { cmd = "python -m build" }, diff --git a/src/sqlalchemy_cratedb/compat/api13.py b/src/sqlalchemy_cratedb/compat/api13.py index 8e716f4a..48d2ceef 100644 --- a/src/sqlalchemy_cratedb/compat/api13.py +++ b/src/sqlalchemy_cratedb/compat/api13.py @@ -34,6 +34,7 @@ """ import collections.abc as collections_abc +import typing as t from sqlalchemy import exc from sqlalchemy.sql import Select @@ -42,7 +43,7 @@ # `_distill_params_20` copied from SA14's `sqlalchemy.engine.{base,util}`. _no_tuple = () -_no_kw = immutabledict() +_no_kw: immutabledict = immutabledict() def _distill_params_20(params): @@ -87,11 +88,11 @@ def monkeypatch_add_exec_driver_sql(): from sqlalchemy.engine.base import Connection, Engine # Add `exec_driver_sql` method to SA's `Connection` and `Engine` classes. - Connection.exec_driver_sql = exec_driver_sql - Engine.exec_driver_sql = exec_driver_sql + Connection.exec_driver_sql = exec_driver_sql # type: ignore[method-assign] + Engine.exec_driver_sql = exec_driver_sql # type: ignore[attr-defined] -def select_sa14(*columns, **kw) -> Select: +def select_sa14(*columns, **kw) -> Select[t.Any]: """ Adapt SA14/SA20's calling semantics of `sql.select()` to SA13. From e305e8cf586c26ac39f4c501842d719cabe0f241 Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Wed, 3 Jun 2026 00:00:56 +0200 Subject: [PATCH 2/2] Chore: Migrate type hint validation from `mypy` to `ty` --- pyproject.toml | 16 +------- src/sqlalchemy_cratedb/__init__.py | 4 +- src/sqlalchemy_cratedb/compat/api13.py | 14 +++---- src/sqlalchemy_cratedb/compat/core10.py | 20 +++++----- src/sqlalchemy_cratedb/compat/core14.py | 17 +++++---- src/sqlalchemy_cratedb/compat/core20.py | 12 +++--- src/sqlalchemy_cratedb/compiler.py | 12 +++--- src/sqlalchemy_cratedb/dialect.py | 44 ++++++++++++++++------ src/sqlalchemy_cratedb/support/pandas.py | 3 +- src/sqlalchemy_cratedb/support/polyfill.py | 4 +- src/sqlalchemy_cratedb/support/util.py | 3 +- src/sqlalchemy_cratedb/type/array.py | 5 ++- src/sqlalchemy_cratedb/type/geo.py | 15 +++++--- src/sqlalchemy_cratedb/type/vector.py | 2 +- src/sqlalchemy_cratedb/util.py | 2 +- 15 files changed, 97 insertions(+), 76 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 560acf19..5fafe6bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,10 +94,10 @@ optional-dependencies.all = [ "sqlalchemy-cratedb[vector]", ] optional-dependencies.develop = [ - "mypy<1.20", "poethepoet<1", "pyproject-fmt<3", "ruff<0.16", + "ty==0.0.42", "validate-pyproject<1", ] optional-dependencies.doc = [ @@ -187,18 +187,6 @@ lint.per-file-ignores."tests/*" = [ "W293", # Blank line contains whitespace ] -[tool.mypy] -mypy_path = "src" -packages = [ "sqlalchemy_cratedb" ] -exclude = [] -namespace_packages = true -explicit_package_bases = true -ignore_missing_imports = true -check_untyped_defs = true -implicit_optional = true -install_types = true -non_interactive = true - [tool.pytest] ini_options.minversion = "2.0" ini_options.testpaths = [ @@ -259,7 +247,7 @@ tasks.lint = [ { cmd = "ruff format --check" }, { cmd = "ruff check" }, { cmd = "validate-pyproject pyproject.toml" }, - { cmd = "mypy" }, + { cmd = "ty check src/" }, ] tasks.release = [ { cmd = "python -m build" }, diff --git a/src/sqlalchemy_cratedb/__init__.py b/src/sqlalchemy_cratedb/__init__.py index 502816be..d987caed 100644 --- a/src/sqlalchemy_cratedb/__init__.py +++ b/src/sqlalchemy_cratedb/__init__.py @@ -53,9 +53,9 @@ try: - from importlib.metadata import PackageNotFoundError, version + from importlib.metadata import PackageNotFoundError, version # ty: ignore[unresolved-import] except (ImportError, ModuleNotFoundError): # pragma:nocover - from importlib_metadata import ( # type: ignore[assignment,no-redef,unused-ignore] + from importlib_metadata import ( # ty: ignore[unresolved-import] PackageNotFoundError, version, ) diff --git a/src/sqlalchemy_cratedb/compat/api13.py b/src/sqlalchemy_cratedb/compat/api13.py index 48d2ceef..ca62703e 100644 --- a/src/sqlalchemy_cratedb/compat/api13.py +++ b/src/sqlalchemy_cratedb/compat/api13.py @@ -88,8 +88,8 @@ def monkeypatch_add_exec_driver_sql(): from sqlalchemy.engine.base import Connection, Engine # Add `exec_driver_sql` method to SA's `Connection` and `Engine` classes. - Connection.exec_driver_sql = exec_driver_sql # type: ignore[method-assign] - Engine.exec_driver_sql = exec_driver_sql # type: ignore[attr-defined] + Connection.exec_driver_sql = exec_driver_sql # ty: ignore[invalid-assignment] + Engine.exec_driver_sql = exec_driver_sql # ty: ignore[unresolved-attribute] def select_sa14(*columns, **kw) -> Select[t.Any]: @@ -111,7 +111,7 @@ def select_sa14(*columns, **kw) -> Select[t.Any]: ) columns, whereclause = columns kw["whereclause"] = whereclause - return original_select(columns, **kw) + return original_select(columns, **kw) # ty: ignore[no-matching-overload] def monkeypatch_amend_select_sa14(): @@ -124,9 +124,9 @@ def monkeypatch_amend_select_sa14(): """ import sqlalchemy - sqlalchemy.select = select_sa14 - sqlalchemy.sql.select = select_sa14 - sqlalchemy.sql.expression.select = select_sa14 + sqlalchemy.select = select_sa14 # ty: ignore[invalid-assignment] + sqlalchemy.sql.select = select_sa14 # ty: ignore[invalid-assignment] + sqlalchemy.sql.expression.select = select_sa14 # ty: ignore[invalid-assignment] @property @@ -150,4 +150,4 @@ def connectionfairy_driver_connection_sa14(self): def monkeypatch_add_connectionfairy_driver_connection(): import sqlalchemy.pool.base - sqlalchemy.pool.base._ConnectionFairy.driver_connection = connectionfairy_driver_connection_sa14 + sqlalchemy.pool.base._ConnectionFairy.driver_connection = connectionfairy_driver_connection_sa14 # ty: ignore[invalid-assignment] diff --git a/src/sqlalchemy_cratedb/compat/core10.py b/src/sqlalchemy_cratedb/compat/core10.py index aae9c526..5fdc93a6 100644 --- a/src/sqlalchemy_cratedb/compat/core10.py +++ b/src/sqlalchemy_cratedb/compat/core10.py @@ -25,8 +25,8 @@ REQUIRED, _create_bind_param, _extend_values_for_multiparams, - _get_multitable_params, - _get_stmt_parameters_params, + _get_multitable_params, # ty: ignore[unresolved-import] + _get_stmt_parameters_params, # ty: ignore[unresolved-import] _key_getters_for_crud_column, _scan_cols, _scan_insert_from_select_cols, @@ -36,13 +36,13 @@ class CrateCompilerSA10(CrateCompiler): - def returning_clause(self, stmt, returning_cols): + def returning_clause(self, stmt, returning_cols): # ty: ignore[invalid-method-override] """ Generate RETURNING clause, PostgreSQL-compatible. """ - return PGCompiler.returning_clause(self, stmt, returning_cols) + return PGCompiler.returning_clause(self, stmt, returning_cols) # ty: ignore[missing-argument] - def visit_update(self, update_stmt, **kw): + def visit_update(self, update_stmt, **kw): # ty: ignore[invalid-method-override] """ used to compile expressions Parts are taken from the SQLCompiler base class. @@ -93,7 +93,7 @@ def visit_update(self, update_stmt, **kw): if self.returning or update_stmt._returning: if not self.returning: - self.returning = update_stmt._returning + self.returning = update_stmt._returning # ty: ignore[invalid-assignment] if self.returning_precedes_values: text += " " + self.returning_clause(update_stmt, self.returning) @@ -154,7 +154,7 @@ def _get_crud_params(compiler, stmt, **kw): _column_as_key, _getattr_col_key, _col_bind_name, - ) = _key_getters_for_crud_column(compiler, stmt) + ) = _key_getters_for_crud_column(compiler, stmt) # ty: ignore[missing-argument] # if we have statement parameters - set defaults in the # compiled params @@ -192,7 +192,7 @@ def _get_crud_params(compiler, stmt, **kw): ) if compiler.isinsert and stmt.select_names: - _scan_insert_from_select_cols( + _scan_insert_from_select_cols( # ty: ignore[missing-argument] compiler, stmt, parameters, @@ -204,7 +204,7 @@ def _get_crud_params(compiler, stmt, **kw): kw, ) else: - _scan_cols( + _scan_cols( # ty: ignore[missing-argument] compiler, stmt, parameters, @@ -248,6 +248,6 @@ def _get_crud_params(compiler, stmt, **kw): """ if stmt._has_multi_parameters: - values = _extend_values_for_multiparams(compiler, stmt, values, kw) + values = _extend_values_for_multiparams(compiler, stmt, values, kw) # ty: ignore[invalid-argument-type,missing-argument] return values diff --git a/src/sqlalchemy_cratedb/compat/core14.py b/src/sqlalchemy_cratedb/compat/core14.py index 15377f43..3f1452fe 100644 --- a/src/sqlalchemy_cratedb/compat/core14.py +++ b/src/sqlalchemy_cratedb/compat/core14.py @@ -19,6 +19,8 @@ # with Crate these terms will supersede the license and you may use the # software solely pursuant to the terms of the relevant commercial agreement. +import typing as t + import sqlalchemy as sa from sqlalchemy.dialects.postgresql.base import PGCompiler from sqlalchemy.sql import selectable @@ -37,13 +39,13 @@ class CrateCompilerSA14(CrateCompiler): - def returning_clause(self, stmt, returning_cols): + def returning_clause(self, stmt, returning_cols): # ty: ignore[invalid-method-override] """ Generate RETURNING clause, PostgreSQL-compatible. """ - return PGCompiler.returning_clause(self, stmt, returning_cols) + return PGCompiler.returning_clause(self, stmt, returning_cols) # ty: ignore[missing-argument] - def visit_update(self, update_stmt, **kw): + def visit_update(self, update_stmt, **kw): # ty: ignore[invalid-method-override] compile_state = update_stmt._compile_state_factory(update_stmt, self, **kw) update_stmt = compile_state.statement @@ -196,6 +198,7 @@ def _get_crud_params(compiler, stmt, compile_state, **kw): for c in stmt.table.columns ] + spd: t.Iterable if compile_state._has_multi_parameters: spd = compile_state._multi_parameters[0] stmt_parameter_tuples = list(spd.items()) @@ -206,7 +209,7 @@ def _get_crud_params(compiler, stmt, compile_state, **kw): spd = compile_state._dict_parameters stmt_parameter_tuples = list(spd.items()) else: - stmt_parameter_tuples = spd = None + stmt_parameter_tuples = spd = [] # if we have statement parameters - set defaults in the # compiled params @@ -251,7 +254,7 @@ def _get_crud_params(compiler, stmt, compile_state, **kw): ) if compile_state.isinsert and stmt._select_names: - _scan_insert_from_select_cols( + _scan_insert_from_select_cols( # ty: ignore[missing-argument] compiler, stmt, compile_state, @@ -264,7 +267,7 @@ def _get_crud_params(compiler, stmt, compile_state, **kw): kw, ) else: - _scan_cols( + _scan_cols( # ty: ignore[missing-argument] compiler, stmt, compile_state, @@ -314,7 +317,7 @@ def _get_crud_params(compiler, stmt, compile_state, **kw): stmt, compile_state, values, - _column_as_key, + _column_as_key, # ty: ignore[invalid-argument-type] kw, ) elif not values and compiler.for_executemany and compiler.dialect.supports_default_metavalue: diff --git a/src/sqlalchemy_cratedb/compat/core20.py b/src/sqlalchemy_cratedb/compat/core20.py index 3d8cbc21..331347a1 100644 --- a/src/sqlalchemy_cratedb/compat/core20.py +++ b/src/sqlalchemy_cratedb/compat/core20.py @@ -167,7 +167,7 @@ def visit_update(self, update_stmt, visiting_cte=None, **kw): # SA 2.1 renamed update_limit_clause to update_post_criteria_clause. if SA_VERSION >= SA_2_1: - limit_clause = self.update_post_criteria_clause(update_stmt, **kw) + limit_clause = self.update_post_criteria_clause(update_stmt, **kw) # ty: ignore[unresolved-attribute] else: limit_clause = self.update_limit_clause(update_stmt) if limit_clause: @@ -416,14 +416,14 @@ def _get_crud_params( compiler, stmt, compile_state, - cast( + cast( # ty: ignore[invalid-argument-type] "Sequence[_CrudParamElementStr]", - values, + values, # ty: ignore[invalid-argument-type] ), - cast("Callable[..., str]", _column_as_key), + cast("Callable[..., str]", _column_as_key), # ty: ignore[invalid-argument-type] kw, ) - return _CrudParams(values, multi_extended_values) + return _CrudParams(values, multi_extended_values) # ty: ignore[invalid-argument-type] elif not values and compiler.for_executemany and compiler.dialect.supports_default_metavalue: # convert an "INSERT DEFAULT VALUES" # into INSERT (firstcol) VALUES (DEFAULT) which can be turned @@ -438,4 +438,4 @@ def _get_crud_params( ) ] - return _CrudParams(values, []) + return _CrudParams(values, []) # ty: ignore[invalid-argument-type] diff --git a/src/sqlalchemy_cratedb/compiler.py b/src/sqlalchemy_cratedb/compiler.py index 851e8ebb..4614658d 100644 --- a/src/sqlalchemy_cratedb/compiler.py +++ b/src/sqlalchemy_cratedb/compiler.py @@ -24,6 +24,8 @@ from collections import defaultdict import sqlalchemy as sa +import sqlalchemy.event +import sqlalchemy.exc from sqlalchemy.dialects.postgresql.base import RESERVED_WORDS as POSTGRESQL_RESERVED_WORDS from sqlalchemy.dialects.postgresql.base import PGCompiler from sqlalchemy.sql import compiler @@ -143,7 +145,7 @@ def get_column_specification(self, column, **kwargs): return colspec - def visit_computed_column(self, generated): + def visit_computed_column(self, generated): # ty: ignore[invalid-method-override] if generated.persisted is False: raise sa.exc.CompileError( "Virtual computed columns are not supported, set 'persisted' to None or True" @@ -276,7 +278,7 @@ def visit_ilike_case_insensitive_operand(self, element, **kw): """ Use native `ILIKE` operator, like PostgreSQL's `PGCompiler`. """ - if self.dialect.has_ilike_operator(): + if self.dialect.has_ilike_operator(): # ty: ignore[unresolved-attribute] return element.element._compiler_dispatch(self, **kw) else: return super().visit_ilike_case_insensitive_operand(element, **kw) @@ -290,7 +292,7 @@ def visit_ilike_op_binary(self, binary, operator, **kw): """ if binary.modifiers.get("escape", None) is not None: raise NotImplementedError("Unsupported feature: ESCAPE is not supported") - if self.dialect.has_ilike_operator(): + if self.dialect.has_ilike_operator(): # ty: ignore[unresolved-attribute] return "%s ILIKE %s" % ( self.process(binary.left, **kw), self.process(binary.right, **kw), @@ -307,7 +309,7 @@ def visit_not_ilike_op_binary(self, binary, operator, **kw): """ if binary.modifiers.get("escape", None) is not None: raise NotImplementedError("Unsupported feature: ESCAPE is not supported") - if self.dialect.has_ilike_operator(): + if self.dialect.has_ilike_operator(): # ty: ignore[unresolved-attribute] return "%s NOT ILIKE %s" % ( self.process(binary.left, **kw), self.process(binary.right, **kw), @@ -319,7 +321,7 @@ def limit_clause(self, select, **kw): """ Generate OFFSET / LIMIT clause, PostgreSQL-compatible. """ - return PGCompiler.limit_clause(self, select, **kw) + return PGCompiler.limit_clause(self, select, **kw) # ty: ignore[invalid-argument-type] def for_update_clause(self, select, **kw): # CrateDB does not support the `INSERT ... FOR UPDATE` clause. diff --git a/src/sqlalchemy_cratedb/dialect.py b/src/sqlalchemy_cratedb/dialect.py index d78306c0..165c4212 100644 --- a/src/sqlalchemy_cratedb/dialect.py +++ b/src/sqlalchemy_cratedb/dialect.py @@ -22,7 +22,9 @@ import logging import warnings from datetime import date, datetime +from typing import TYPE_CHECKING, Any, List, Optional, cast +from sqlalchemy import Connection from sqlalchemy import types as sqltypes from sqlalchemy.engine import default, reflection from sqlalchemy.exc import SQLAlchemyError @@ -38,6 +40,9 @@ from .type import FloatVector, ObjectArray, ObjectType from .util import SSLMode +if TYPE_CHECKING: + from sqlalchemy.engine.interfaces import ReflectedIndex, ReflectedPrimaryKeyConstraint + TYPES_MAP = { "boolean": sqltypes.Boolean, "short": sqltypes.SmallInteger, @@ -99,7 +104,7 @@ def process(value): if not value: return None try: - return datetime.utcfromtimestamp(value / 1e3).date() + return datetime.utcfromtimestamp(value / 1e3).date() # ty: ignore[deprecated] except TypeError: pass @@ -135,7 +140,7 @@ def process(value): if not value: return None try: - return datetime.utcfromtimestamp(value / 1e3) + return datetime.utcfromtimestamp(value / 1e3) # ty: ignore[deprecated] except TypeError: pass @@ -214,7 +219,7 @@ def initialize(self, connection): # get default schema name self.default_schema_name = self._get_default_schema_name(connection) - def do_rollback(self, connection): + def do_rollback(self, dbapi_connection): # if any exception is raised by the dbapi, sqlalchemy by default # attempts to do a rollback crate doesn't support rollbacks. # implementing this as noop seems to cause sqlalchemy to propagate the @@ -259,10 +264,10 @@ def connect(self, host=None, port=None, *args, **kwargs): kwargs["verify_ssl_cert"] = False if not servers: - servers = [self.dbapi.http.Client.default_server.replace("http://", "")] + servers = [self.dbapi.http.Client.default_server.replace("http://", "")] # ty: ignore[unresolved-attribute] if use_ssl: servers = ["https://" + server for server in servers] - return self.dbapi.connect(servers=servers, **kwargs) + return self.dbapi.connect(servers=servers, **kwargs) # ty: ignore[unresolved-attribute] def do_execute(self, cursor, statement, parameters, context=None): """ @@ -313,8 +318,8 @@ def import_dbapi(cls): def dbapi(cls): return cls.import_dbapi() - def has_schema(self, connection, schema, **kw): - return schema in self.get_schema_names(connection, **kw) + def has_schema(self, connection: Connection, schema_name: str, **kw: Any) -> bool: + return schema_name in self.get_schema_names(connection, **kw) def has_table(self, connection, table_name, schema=None, **kw): return table_name in self.get_table_names(connection, schema=schema, **kw) @@ -367,8 +372,15 @@ def get_columns(self, connection, table_name, schema=None, **kw): return [self._create_column_info(row) for row in cursor.fetchall()] @reflection.cache - def get_pk_constraint(self, engine, table_name, schema=None, **kw): - if self.server_version_info >= (3, 0, 0): + def get_pk_constraint( + self, + connection: Connection, + table_name: str, + schema: Optional[str] = None, + **kw: Any, + ) -> "ReflectedPrimaryKeyConstraint": + server_version_info = cast(tuple, self.server_version_info) + if server_version_info >= (3, 0, 0): query = """SELECT column_name FROM information_schema.key_column_usage WHERE table_name = ? AND table_schema = ?""" @@ -377,7 +389,7 @@ def result_fun(result): rows = result.fetchall() return set(map(lambda el: el[0], rows)) - elif self.server_version_info >= (2, 3, 0): + elif server_version_info >= (2, 3, 0): query = """SELECT column_name FROM information_schema.key_column_usage WHERE table_name = ? AND table_catalog = ?""" @@ -397,7 +409,9 @@ def result_fun(result): rows = result.fetchone() return set(rows[0] if rows else []) - pk_result = engine.exec_driver_sql(query, (table_name, schema or self.default_schema_name)) + pk_result = connection.exec_driver_sql( + query, (table_name, schema or self.default_schema_name) + ) pks = result_fun(pk_result) return {"constrained_columns": sorted(pks), "name": "PRIMARY KEY"} @@ -409,7 +423,13 @@ def get_foreign_keys( return [] @reflection.cache - def get_indexes(self, connection, table_name, schema, **kw): + def get_indexes( + self, + connection: Connection, + table_name: str, + schema: Optional[str] = None, + **kw: Any, + ) -> List["ReflectedIndex"]: return [] @property diff --git a/src/sqlalchemy_cratedb/support/pandas.py b/src/sqlalchemy_cratedb/support/pandas.py index 1a20b65b..ebb395b9 100644 --- a/src/sqlalchemy_cratedb/support/pandas.py +++ b/src/sqlalchemy_cratedb/support/pandas.py @@ -24,6 +24,7 @@ from unittest.mock import patch import sqlalchemy as sa +import sqlalchemy.sql.schema from sqlalchemy_cratedb.sa_version import SA_2_0, SA_VERSION @@ -89,7 +90,7 @@ def table_kwargs(**kwargs): """ if SA_VERSION < SA_2_0: - _init_dist = sa.sql.schema.Table._init + _init_dist = sa.sql.schema.Table._init # ty: ignore[unresolved-attribute] def _init(self, name, metadata, *args, **kwargs_effective): kwargs_effective.update(kwargs) diff --git a/src/sqlalchemy_cratedb/support/polyfill.py b/src/sqlalchemy_cratedb/support/polyfill.py index 13c040f5..641a851c 100644 --- a/src/sqlalchemy_cratedb/support/polyfill.py +++ b/src/sqlalchemy_cratedb/support/polyfill.py @@ -1,6 +1,8 @@ import typing as t import sqlalchemy as sa +import sqlalchemy.event +import sqlalchemy.orm from sqlalchemy.event import listen from sqlalchemy_cratedb.support.util import refresh_dirty, refresh_table @@ -26,7 +28,7 @@ def __init__(self, *args, **kwargs): kwargs["default"] = sa.func.now() init_dist(self, *args, **kwargs) - schema.Column.__init__ = __init__ # type: ignore[method-assign] + schema.Column.__init__ = __init__ # ty: ignore[invalid-assignment] def check_uniqueness_factory(sa_entity, *attribute_names): diff --git a/src/sqlalchemy_cratedb/support/util.py b/src/sqlalchemy_cratedb/support/util.py index c66e67ea..3592b6e3 100644 --- a/src/sqlalchemy_cratedb/support/util.py +++ b/src/sqlalchemy_cratedb/support/util.py @@ -2,6 +2,7 @@ import typing as t import sqlalchemy as sa +import sqlalchemy.sql.selectable from sqlalchemy_cratedb.dialect import CrateDialect @@ -46,7 +47,7 @@ def refresh_dirty(session, flush_context=None): dirty_entities = itertools.chain(session.new, session.dirty, session.deleted) dirty_classes = {entity.__class__ for entity in dirty_entities} for class_ in dirty_classes: - refresh_table(session, class_) + refresh_table(session, class_) # ty: ignore[invalid-argument-type] def quote_relation_name(ident: str) -> str: diff --git a/src/sqlalchemy_cratedb/type/array.py b/src/sqlalchemy_cratedb/type/array.py index 7798692c..d2539234 100644 --- a/src/sqlalchemy_cratedb/type/array.py +++ b/src/sqlalchemy_cratedb/type/array.py @@ -24,6 +24,7 @@ import sqlalchemy.types as sqltypes from sqlalchemy.ext.mutable import Mutable from sqlalchemy.sql import default_comparator, expression, operators +from sqlalchemy.sql.operators import ColumnOperators class MutableList(Mutable, list): @@ -100,8 +101,8 @@ class _ObjectArray(sqltypes.UserDefinedType): cache_ok = True class Comparator(sqltypes.TypeEngine.Comparator): - def __getitem__(self, key): - return default_comparator._binary_operate(self.expr, operators.getitem, key) + def __getitem__(self, index: Any) -> ColumnOperators: + return default_comparator._binary_operate(self.expr, operators.getitem, index) def any(self, other, operator=operators.eq): """Return ``other operator ANY (array)`` clause. diff --git a/src/sqlalchemy_cratedb/type/geo.py b/src/sqlalchemy_cratedb/type/geo.py index 6bf84147..9eca4756 100644 --- a/src/sqlalchemy_cratedb/type/geo.py +++ b/src/sqlalchemy_cratedb/type/geo.py @@ -1,16 +1,19 @@ +from typing import Any + import geojson from sqlalchemy import types as sqltypes from sqlalchemy.sql import default_comparator, operators +from sqlalchemy.sql.operators import ColumnOperators class Geopoint(sqltypes.UserDefinedType): cache_ok = True class Comparator(sqltypes.TypeEngine.Comparator): - def __getitem__(self, key): - return default_comparator._binary_operate(self.expr, operators.getitem, key) + def __getitem__(self, index: Any) -> ColumnOperators: + return default_comparator._binary_operate(self.expr, operators.getitem, index) - def get_col_spec(self): + def get_col_spec(self, **kw: Any) -> str: return "GEO_POINT" def bind_processor(self, dialect): @@ -31,10 +34,10 @@ class Geoshape(sqltypes.UserDefinedType): cache_ok = True class Comparator(sqltypes.TypeEngine.Comparator): - def __getitem__(self, key): - return default_comparator._binary_operate(self.expr, operators.getitem, key) + def __getitem__(self, index: Any) -> ColumnOperators: + return default_comparator._binary_operate(self.expr, operators.getitem, index) - def get_col_spec(self): + def get_col_spec(self, **kw: Any) -> str: return "GEO_SHAPE" def result_processor(self, dialect, coltype): diff --git a/src/sqlalchemy_cratedb/type/vector.py b/src/sqlalchemy_cratedb/type/vector.py index 7fc6447f..2fafeb8b 100644 --- a/src/sqlalchemy_cratedb/type/vector.py +++ b/src/sqlalchemy_cratedb/type/vector.py @@ -101,7 +101,7 @@ class FloatVector(sa.TypeDecorator): impl = sa.ARRAY - def __init__(self, dimensions: int = None): + def __init__(self, dimensions: t.Optional[int] = None): super().__init__(sa.FLOAT, dimensions=dimensions) def as_generic(self, allow_nulltype=False): diff --git a/src/sqlalchemy_cratedb/util.py b/src/sqlalchemy_cratedb/util.py index 1c34b33e..ec7cb8d8 100644 --- a/src/sqlalchemy_cratedb/util.py +++ b/src/sqlalchemy_cratedb/util.py @@ -24,4 +24,4 @@ def parse(cls, sslmode): @classproperty def modes(cls): - return [m.name.replace("_", "-") for m in cls] + return [m.name.replace("_", "-") for m in cls] # ty: ignore[not-iterable]