mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-06 08:56:51 -04:00
ensure function classes are not shadowed
Ensure the _FunctionGenerator method do not shadow the function class of the same name Fixed a typing issue where the typed members of :data:`.func` would return the appropriate class of the same name, however this creates an issue for typecheckers such as Zuban and pyrefly that assume :pep:`749` style typechecking even if the file states that it's a :pep:`563` file; they see the returned name as indicating the method object and not the class object. These typecheckers are actually following along with an upcoming test harness that insists on :pep:`749` style name resolution for this case unconditionally. Since :pep:`749` is the way of the future regardless, differently-named type aliases have been added for these return types. Fixes: #13167 Change-Id: If58a3858001c78ab21b2ed343205dfd9ce868576
This commit is contained in:
committed by
Mike Bayer
parent
e7c45bae55
commit
0a185a3bb6
+14
@@ -0,0 +1,14 @@
|
||||
.. change::
|
||||
:tags: bug, typing
|
||||
:tickets: 13167
|
||||
|
||||
Fixed a typing issue where the typed members of :data:`.func` would return
|
||||
the appropriate class of the same name, however this creates an issue for
|
||||
typecheckers such as Zuban and pyrefly that assume :pep:`749` style
|
||||
typechecking even if the file states that it's a :pep:`563` file; they see
|
||||
the returned name as indicating the method object and not the class object.
|
||||
These typecheckers are actually following along with an upcoming test
|
||||
harness that insists on :pep:`749` style name resolution for this case
|
||||
unconditionally. Since :pep:`749` is the way of the future regardless,
|
||||
differently-named type aliases have been added for these return types.
|
||||
|
||||
@@ -22,6 +22,7 @@ from typing import Sequence
|
||||
from typing import Tuple
|
||||
from typing import Type
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TypeAlias
|
||||
from typing import TypeVar
|
||||
from typing import Union
|
||||
|
||||
@@ -62,7 +63,6 @@ from .type_api import TypeEngine
|
||||
from .visitors import InternalTraversal
|
||||
from .. import util
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._typing import _ByArgument
|
||||
from ._typing import _ColumnExpressionArgument
|
||||
@@ -1039,10 +1039,10 @@ class _FunctionGenerator:
|
||||
# statically generated** by tools/generate_sql_functions.py
|
||||
|
||||
@property
|
||||
def aggregate_strings(self) -> Type[aggregate_strings]: ...
|
||||
def aggregate_strings(self) -> Type[_aggregate_strings_func]: ...
|
||||
|
||||
@property
|
||||
def ansifunction(self) -> Type[AnsiFunction[Any]]: ...
|
||||
def ansifunction(self) -> Type[_AnsiFunction_func[Any]]: ...
|
||||
|
||||
# set ColumnElement[_T] as a separate overload, to appease
|
||||
# mypy which seems to not want to accept _T from
|
||||
@@ -1055,7 +1055,7 @@ class _FunctionGenerator:
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> array_agg[_T]: ...
|
||||
) -> _array_agg_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def array_agg(
|
||||
@@ -1063,7 +1063,7 @@ class _FunctionGenerator:
|
||||
col: _ColumnExpressionArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> array_agg[_T]: ...
|
||||
) -> _array_agg_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def array_agg(
|
||||
@@ -1071,20 +1071,20 @@ class _FunctionGenerator:
|
||||
col: _T,
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> array_agg[_T]: ...
|
||||
) -> _array_agg_func[_T]: ...
|
||||
|
||||
def array_agg(
|
||||
self,
|
||||
col: _ColumnExpressionOrLiteralArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> array_agg[_T]: ...
|
||||
) -> _array_agg_func[_T]: ...
|
||||
|
||||
@property
|
||||
def cast(self) -> Type[Cast[Any]]: ...
|
||||
def cast(self) -> Type[_Cast_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def char_length(self) -> Type[char_length]: ...
|
||||
def char_length(self) -> Type[_char_length_func]: ...
|
||||
|
||||
# set ColumnElement[_T] as a separate overload, to appease
|
||||
# mypy which seems to not want to accept _T from
|
||||
@@ -1097,7 +1097,7 @@ class _FunctionGenerator:
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> coalesce[_T]: ...
|
||||
) -> _coalesce_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def coalesce(
|
||||
@@ -1105,7 +1105,7 @@ class _FunctionGenerator:
|
||||
col: _ColumnExpressionArgument[Optional[_T]],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> coalesce[_T]: ...
|
||||
) -> _coalesce_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def coalesce(
|
||||
@@ -1113,53 +1113,53 @@ class _FunctionGenerator:
|
||||
col: Optional[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> coalesce[_T]: ...
|
||||
) -> _coalesce_func[_T]: ...
|
||||
|
||||
def coalesce(
|
||||
self,
|
||||
col: _ColumnExpressionOrLiteralArgument[Optional[_T]],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> coalesce[_T]: ...
|
||||
) -> _coalesce_func[_T]: ...
|
||||
|
||||
@property
|
||||
def concat(self) -> Type[concat]: ...
|
||||
def concat(self) -> Type[_concat_func]: ...
|
||||
|
||||
@property
|
||||
def count(self) -> Type[count]: ...
|
||||
def count(self) -> Type[_count_func]: ...
|
||||
|
||||
@property
|
||||
def cube(self) -> Type[cube[Any]]: ...
|
||||
def cube(self) -> Type[_cube_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def cume_dist(self) -> Type[cume_dist]: ...
|
||||
def cume_dist(self) -> Type[_cume_dist_func]: ...
|
||||
|
||||
@property
|
||||
def current_date(self) -> Type[current_date]: ...
|
||||
def current_date(self) -> Type[_current_date_func]: ...
|
||||
|
||||
@property
|
||||
def current_time(self) -> Type[current_time]: ...
|
||||
def current_time(self) -> Type[_current_time_func]: ...
|
||||
|
||||
@property
|
||||
def current_timestamp(self) -> Type[current_timestamp]: ...
|
||||
def current_timestamp(self) -> Type[_current_timestamp_func]: ...
|
||||
|
||||
@property
|
||||
def current_user(self) -> Type[current_user]: ...
|
||||
def current_user(self) -> Type[_current_user_func]: ...
|
||||
|
||||
@property
|
||||
def dense_rank(self) -> Type[dense_rank]: ...
|
||||
def dense_rank(self) -> Type[_dense_rank_func]: ...
|
||||
|
||||
@property
|
||||
def extract(self) -> Type[Extract]: ...
|
||||
def extract(self) -> Type[_Extract_func]: ...
|
||||
|
||||
@property
|
||||
def grouping_sets(self) -> Type[grouping_sets[Any]]: ...
|
||||
def grouping_sets(self) -> Type[_grouping_sets_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def localtime(self) -> Type[localtime]: ...
|
||||
def localtime(self) -> Type[_localtime_func]: ...
|
||||
|
||||
@property
|
||||
def localtimestamp(self) -> Type[localtimestamp]: ...
|
||||
def localtimestamp(self) -> Type[_localtimestamp_func]: ...
|
||||
|
||||
# set ColumnElement[_T] as a separate overload, to appease
|
||||
# mypy which seems to not want to accept _T from
|
||||
@@ -1172,7 +1172,7 @@ class _FunctionGenerator:
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> max[_T]: ...
|
||||
) -> _max_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def max( # noqa: A001
|
||||
@@ -1180,7 +1180,7 @@ class _FunctionGenerator:
|
||||
col: _ColumnExpressionArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> max[_T]: ...
|
||||
) -> _max_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def max( # noqa: A001
|
||||
@@ -1188,14 +1188,14 @@ class _FunctionGenerator:
|
||||
col: _T,
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> max[_T]: ...
|
||||
) -> _max_func[_T]: ...
|
||||
|
||||
def max( # noqa: A001
|
||||
self,
|
||||
col: _ColumnExpressionOrLiteralArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> max[_T]: ...
|
||||
) -> _max_func[_T]: ...
|
||||
|
||||
# set ColumnElement[_T] as a separate overload, to appease
|
||||
# mypy which seems to not want to accept _T from
|
||||
@@ -1208,7 +1208,7 @@ class _FunctionGenerator:
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> min[_T]: ...
|
||||
) -> _min_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def min( # noqa: A001
|
||||
@@ -1216,7 +1216,7 @@ class _FunctionGenerator:
|
||||
col: _ColumnExpressionArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> min[_T]: ...
|
||||
) -> _min_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def min( # noqa: A001
|
||||
@@ -1224,35 +1224,35 @@ class _FunctionGenerator:
|
||||
col: _T,
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> min[_T]: ...
|
||||
) -> _min_func[_T]: ...
|
||||
|
||||
def min( # noqa: A001
|
||||
self,
|
||||
col: _ColumnExpressionOrLiteralArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> min[_T]: ...
|
||||
) -> _min_func[_T]: ...
|
||||
|
||||
@property
|
||||
def mode(self) -> Type[mode[Any]]: ...
|
||||
def mode(self) -> Type[_mode_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def next_value(self) -> Type[next_value]: ...
|
||||
def next_value(self) -> Type[_next_value_func]: ...
|
||||
|
||||
@property
|
||||
def now(self) -> Type[now]: ...
|
||||
def now(self) -> Type[_now_func]: ...
|
||||
|
||||
@property
|
||||
def orderedsetagg(self) -> Type[OrderedSetAgg[Any]]: ...
|
||||
def orderedsetagg(self) -> Type[_OrderedSetAgg_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def percent_rank(self) -> Type[percent_rank]: ...
|
||||
def percent_rank(self) -> Type[_percent_rank_func]: ...
|
||||
|
||||
@property
|
||||
def percentile_cont(self) -> Type[percentile_cont[Any]]: ...
|
||||
def percentile_cont(self) -> Type[_percentile_cont_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def percentile_disc(self) -> Type[percentile_disc[Any]]: ...
|
||||
def percentile_disc(self) -> Type[_percentile_disc_func[Any]]: ...
|
||||
|
||||
# set ColumnElement[_T] as a separate overload, to appease
|
||||
# mypy which seems to not want to accept _T from
|
||||
@@ -1265,7 +1265,7 @@ class _FunctionGenerator:
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> pow[_T]: ...
|
||||
) -> _pow_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def pow( # noqa: A001
|
||||
@@ -1273,7 +1273,7 @@ class _FunctionGenerator:
|
||||
col: _ColumnExpressionArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> pow[_T]: ...
|
||||
) -> _pow_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def pow( # noqa: A001
|
||||
@@ -1281,26 +1281,26 @@ class _FunctionGenerator:
|
||||
col: _T,
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> pow[_T]: ...
|
||||
) -> _pow_func[_T]: ...
|
||||
|
||||
def pow( # noqa: A001
|
||||
self,
|
||||
col: _ColumnExpressionOrLiteralArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> pow[_T]: ...
|
||||
) -> _pow_func[_T]: ...
|
||||
|
||||
@property
|
||||
def random(self) -> Type[random]: ...
|
||||
def random(self) -> Type[_random_func]: ...
|
||||
|
||||
@property
|
||||
def rank(self) -> Type[rank]: ...
|
||||
def rank(self) -> Type[_rank_func]: ...
|
||||
|
||||
@property
|
||||
def rollup(self) -> Type[rollup[Any]]: ...
|
||||
def rollup(self) -> Type[_rollup_func[Any]]: ...
|
||||
|
||||
@property
|
||||
def session_user(self) -> Type[session_user]: ...
|
||||
def session_user(self) -> Type[_session_user_func]: ...
|
||||
|
||||
# set ColumnElement[_T] as a separate overload, to appease
|
||||
# mypy which seems to not want to accept _T from
|
||||
@@ -1313,7 +1313,7 @@ class _FunctionGenerator:
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> sum[_T]: ...
|
||||
) -> _sum_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def sum( # noqa: A001
|
||||
@@ -1321,7 +1321,7 @@ class _FunctionGenerator:
|
||||
col: _ColumnExpressionArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> sum[_T]: ...
|
||||
) -> _sum_func[_T]: ...
|
||||
|
||||
@overload
|
||||
def sum( # noqa: A001
|
||||
@@ -1329,20 +1329,20 @@ class _FunctionGenerator:
|
||||
col: _T,
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> sum[_T]: ...
|
||||
) -> _sum_func[_T]: ...
|
||||
|
||||
def sum( # noqa: A001
|
||||
self,
|
||||
col: _ColumnExpressionOrLiteralArgument[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> sum[_T]: ...
|
||||
) -> _sum_func[_T]: ...
|
||||
|
||||
@property
|
||||
def sysdate(self) -> Type[sysdate]: ...
|
||||
def sysdate(self) -> Type[_sysdate_func]: ...
|
||||
|
||||
@property
|
||||
def user(self) -> Type[user]: ...
|
||||
def user(self) -> Type[_user_func]: ...
|
||||
|
||||
# END GENERATED FUNCTION ACCESSORS
|
||||
|
||||
@@ -2256,3 +2256,45 @@ class aggregate_strings(GenericFunction[str]):
|
||||
separator: str,
|
||||
) -> None:
|
||||
super().__init__(clause, separator)
|
||||
|
||||
|
||||
# These aliases are required to avoid shadowing the class with the function
|
||||
# name. See https://github.com/sqlalchemy/sqlalchemy/issues/13167
|
||||
# START GENERATED FUNCTION ALIASES
|
||||
_aggregate_strings_func: TypeAlias = aggregate_strings
|
||||
_AnsiFunction_func: TypeAlias = AnsiFunction[_T]
|
||||
_array_agg_func: TypeAlias = array_agg[_T]
|
||||
_Cast_func: TypeAlias = Cast[_T]
|
||||
_char_length_func: TypeAlias = char_length
|
||||
_coalesce_func: TypeAlias = coalesce[_T]
|
||||
_concat_func: TypeAlias = concat
|
||||
_count_func: TypeAlias = count
|
||||
_cube_func: TypeAlias = cube[_T]
|
||||
_cume_dist_func: TypeAlias = cume_dist
|
||||
_current_date_func: TypeAlias = current_date
|
||||
_current_time_func: TypeAlias = current_time
|
||||
_current_timestamp_func: TypeAlias = current_timestamp
|
||||
_current_user_func: TypeAlias = current_user
|
||||
_dense_rank_func: TypeAlias = dense_rank
|
||||
_Extract_func: TypeAlias = Extract
|
||||
_grouping_sets_func: TypeAlias = grouping_sets[_T]
|
||||
_localtime_func: TypeAlias = localtime
|
||||
_localtimestamp_func: TypeAlias = localtimestamp
|
||||
_max_func: TypeAlias = max[_T]
|
||||
_min_func: TypeAlias = min[_T]
|
||||
_mode_func: TypeAlias = mode[_T]
|
||||
_next_value_func: TypeAlias = next_value
|
||||
_now_func: TypeAlias = now
|
||||
_OrderedSetAgg_func: TypeAlias = OrderedSetAgg[_T]
|
||||
_percent_rank_func: TypeAlias = percent_rank
|
||||
_percentile_cont_func: TypeAlias = percentile_cont[_T]
|
||||
_percentile_disc_func: TypeAlias = percentile_disc[_T]
|
||||
_pow_func: TypeAlias = pow[_T]
|
||||
_random_func: TypeAlias = random
|
||||
_rank_func: TypeAlias = rank
|
||||
_rollup_func: TypeAlias = rollup[_T]
|
||||
_session_user_func: TypeAlias = session_user
|
||||
_sum_func: TypeAlias = sum[_T]
|
||||
_sysdate_func: TypeAlias = sysdate
|
||||
_user_func: TypeAlias = user
|
||||
# END GENERATED FUNCTION ALIASES
|
||||
|
||||
@@ -14,134 +14,258 @@ from sqlalchemy import Select
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy import Sequence as SqlAlchemySequence
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy.sql import functions
|
||||
|
||||
# START GENERATED FUNCTION TYPING TESTS
|
||||
|
||||
# code within this block is **programmatically,
|
||||
# statically generated** by tools/generate_sql_functions.py
|
||||
|
||||
stmt1 = select(func.aggregate_strings(column("x", String), ","))
|
||||
|
||||
# test the aggregate_strings() function.
|
||||
# this function is somewhat special case.
|
||||
|
||||
stmt1 = select(func.aggregate_strings(column("x", String), ","))
|
||||
assert_type(stmt1, Select[str])
|
||||
|
||||
|
||||
stmt2 = select(func.array_agg(column("x", Integer)))
|
||||
# test the array_agg() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn2 = func.array_agg(column("x", Integer))
|
||||
assert_type(fn2, functions.array_agg[int])
|
||||
|
||||
stmt2 = select(func.array_agg(column("x", Integer)))
|
||||
assert_type(stmt2, Select[Sequence[int]])
|
||||
|
||||
|
||||
stmt3 = select(func.char_length(column("x")))
|
||||
# test the char_length() function.
|
||||
# this function is fixed to the SQL INTEGER class, or the int type.
|
||||
|
||||
fn3 = func.char_length(column("x"))
|
||||
assert_type(fn3, functions.char_length)
|
||||
|
||||
stmt3 = select(func.char_length(column("x")))
|
||||
assert_type(stmt3, Select[int])
|
||||
|
||||
|
||||
stmt4 = select(func.coalesce(column("x", Integer)))
|
||||
# test the coalesce() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn4 = func.coalesce(column("x", Integer))
|
||||
assert_type(fn4, functions.coalesce[int])
|
||||
|
||||
stmt4 = select(func.coalesce(column("x", Integer)))
|
||||
assert_type(stmt4, Select[int])
|
||||
|
||||
|
||||
stmt5 = select(func.concat())
|
||||
# test the concat() function.
|
||||
# this function is fixed to the SQL VARCHAR class, or the str type.
|
||||
|
||||
fn5 = func.concat()
|
||||
assert_type(fn5, functions.concat)
|
||||
|
||||
stmt5 = select(func.concat())
|
||||
assert_type(stmt5, Select[str])
|
||||
|
||||
|
||||
stmt6 = select(func.count(column("x")))
|
||||
# test the count() function.
|
||||
# this function is fixed to the SQL INTEGER class, or the int type.
|
||||
|
||||
fn6 = func.count(column("x"))
|
||||
assert_type(fn6, functions.count)
|
||||
|
||||
stmt6 = select(func.count(column("x")))
|
||||
assert_type(stmt6, Select[int])
|
||||
|
||||
|
||||
stmt7 = select(func.cume_dist())
|
||||
# test the cume_dist() function.
|
||||
# this function is fixed to the SQL NUMERIC class, or the Decimal type.
|
||||
|
||||
fn7 = func.cume_dist()
|
||||
assert_type(fn7, functions.cume_dist)
|
||||
|
||||
stmt7 = select(func.cume_dist())
|
||||
assert_type(stmt7, Select[Decimal])
|
||||
|
||||
|
||||
stmt8 = select(func.current_date())
|
||||
# test the current_date() function.
|
||||
# this function is fixed to the SQL DATE class, or the date type.
|
||||
|
||||
fn8 = func.current_date()
|
||||
assert_type(fn8, functions.current_date)
|
||||
|
||||
stmt8 = select(func.current_date())
|
||||
assert_type(stmt8, Select[date])
|
||||
|
||||
|
||||
stmt9 = select(func.current_time())
|
||||
# test the current_time() function.
|
||||
# this function is fixed to the SQL TIME class, or the time type.
|
||||
|
||||
fn9 = func.current_time()
|
||||
assert_type(fn9, functions.current_time)
|
||||
|
||||
stmt9 = select(func.current_time())
|
||||
assert_type(stmt9, Select[time])
|
||||
|
||||
|
||||
stmt10 = select(func.current_timestamp())
|
||||
# test the current_timestamp() function.
|
||||
# this function is fixed to the SQL DATETIME class, or the datetime type.
|
||||
|
||||
fn10 = func.current_timestamp()
|
||||
assert_type(fn10, functions.current_timestamp)
|
||||
|
||||
stmt10 = select(func.current_timestamp())
|
||||
assert_type(stmt10, Select[datetime])
|
||||
|
||||
|
||||
stmt11 = select(func.current_user())
|
||||
# test the current_user() function.
|
||||
# this function is fixed to the SQL VARCHAR class, or the str type.
|
||||
|
||||
fn11 = func.current_user()
|
||||
assert_type(fn11, functions.current_user)
|
||||
|
||||
stmt11 = select(func.current_user())
|
||||
assert_type(stmt11, Select[str])
|
||||
|
||||
|
||||
stmt12 = select(func.dense_rank())
|
||||
# test the dense_rank() function.
|
||||
# this function is fixed to the SQL INTEGER class, or the int type.
|
||||
|
||||
fn12 = func.dense_rank()
|
||||
assert_type(fn12, functions.dense_rank)
|
||||
|
||||
stmt12 = select(func.dense_rank())
|
||||
assert_type(stmt12, Select[int])
|
||||
|
||||
|
||||
stmt13 = select(func.localtime())
|
||||
# test the localtime() function.
|
||||
# this function is fixed to the SQL DATETIME class, or the datetime type.
|
||||
|
||||
fn13 = func.localtime()
|
||||
assert_type(fn13, functions.localtime)
|
||||
|
||||
stmt13 = select(func.localtime())
|
||||
assert_type(stmt13, Select[datetime])
|
||||
|
||||
|
||||
stmt14 = select(func.localtimestamp())
|
||||
# test the localtimestamp() function.
|
||||
# this function is fixed to the SQL DATETIME class, or the datetime type.
|
||||
|
||||
fn14 = func.localtimestamp()
|
||||
assert_type(fn14, functions.localtimestamp)
|
||||
|
||||
stmt14 = select(func.localtimestamp())
|
||||
assert_type(stmt14, Select[datetime])
|
||||
|
||||
|
||||
stmt15 = select(func.max(column("x", Integer)))
|
||||
# test the max() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn15 = func.max(column("x", Integer))
|
||||
assert_type(fn15, functions.max[int])
|
||||
|
||||
stmt15 = select(func.max(column("x", Integer)))
|
||||
assert_type(stmt15, Select[int])
|
||||
|
||||
|
||||
stmt16 = select(func.min(column("x", Integer)))
|
||||
# test the min() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn16 = func.min(column("x", Integer))
|
||||
assert_type(fn16, functions.min[int])
|
||||
|
||||
stmt16 = select(func.min(column("x", Integer)))
|
||||
assert_type(stmt16, Select[int])
|
||||
|
||||
|
||||
stmt17 = select(func.next_value(SqlAlchemySequence("x_seq")))
|
||||
# test the next_value() function.
|
||||
# this function is fixed to the SQL INTEGER class, or the int type.
|
||||
|
||||
fn17 = func.next_value(SqlAlchemySequence("x_seq"))
|
||||
assert_type(fn17, functions.next_value)
|
||||
|
||||
stmt17 = select(func.next_value(SqlAlchemySequence("x_seq")))
|
||||
assert_type(stmt17, Select[int])
|
||||
|
||||
|
||||
stmt18 = select(func.now())
|
||||
# test the now() function.
|
||||
# this function is fixed to the SQL DATETIME class, or the datetime type.
|
||||
|
||||
fn18 = func.now()
|
||||
assert_type(fn18, functions.now)
|
||||
|
||||
stmt18 = select(func.now())
|
||||
assert_type(stmt18, Select[datetime])
|
||||
|
||||
|
||||
stmt19 = select(func.percent_rank())
|
||||
# test the percent_rank() function.
|
||||
# this function is fixed to the SQL NUMERIC class, or the Decimal type.
|
||||
|
||||
fn19 = func.percent_rank()
|
||||
assert_type(fn19, functions.percent_rank)
|
||||
|
||||
stmt19 = select(func.percent_rank())
|
||||
assert_type(stmt19, Select[Decimal])
|
||||
|
||||
|
||||
stmt20 = select(func.pow(column("x", Integer)))
|
||||
# test the pow() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn20 = func.pow(column("x", Integer))
|
||||
assert_type(fn20, functions.pow[int])
|
||||
|
||||
stmt20 = select(func.pow(column("x", Integer)))
|
||||
assert_type(stmt20, Select[int])
|
||||
|
||||
|
||||
stmt21 = select(func.rank())
|
||||
# test the rank() function.
|
||||
# this function is fixed to the SQL INTEGER class, or the int type.
|
||||
|
||||
fn21 = func.rank()
|
||||
assert_type(fn21, functions.rank)
|
||||
|
||||
stmt21 = select(func.rank())
|
||||
assert_type(stmt21, Select[int])
|
||||
|
||||
|
||||
stmt22 = select(func.session_user())
|
||||
# test the session_user() function.
|
||||
# this function is fixed to the SQL VARCHAR class, or the str type.
|
||||
|
||||
fn22 = func.session_user()
|
||||
assert_type(fn22, functions.session_user)
|
||||
|
||||
stmt22 = select(func.session_user())
|
||||
assert_type(stmt22, Select[str])
|
||||
|
||||
|
||||
stmt23 = select(func.sum(column("x", Integer)))
|
||||
# test the sum() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn23 = func.sum(column("x", Integer))
|
||||
assert_type(fn23, functions.sum[int])
|
||||
|
||||
stmt23 = select(func.sum(column("x", Integer)))
|
||||
assert_type(stmt23, Select[int])
|
||||
|
||||
|
||||
stmt24 = select(func.sysdate())
|
||||
# test the sysdate() function.
|
||||
# this function is fixed to the SQL DATETIME class, or the datetime type.
|
||||
|
||||
fn24 = func.sysdate()
|
||||
assert_type(fn24, functions.sysdate)
|
||||
|
||||
stmt24 = select(func.sysdate())
|
||||
assert_type(stmt24, Select[datetime])
|
||||
|
||||
|
||||
stmt25 = select(func.user())
|
||||
# test the user() function.
|
||||
# this function is fixed to the SQL VARCHAR class, or the str type.
|
||||
|
||||
fn25 = func.user()
|
||||
assert_type(fn25, functions.user)
|
||||
|
||||
stmt25 = select(func.user())
|
||||
assert_type(stmt25, Select[str])
|
||||
|
||||
# END GENERATED FUNCTION TYPING TESTS
|
||||
|
||||
@@ -39,6 +39,7 @@ def process_functions(filename: str, cmd: code_writer_cmd) -> str:
|
||||
):
|
||||
indent = ""
|
||||
in_block = False
|
||||
alias_mapping: dict[str, str] = {}
|
||||
|
||||
for line in orig_py:
|
||||
m = re.match(
|
||||
@@ -63,7 +64,9 @@ def process_functions(filename: str, cmd: code_writer_cmd) -> str:
|
||||
for key, fn_class in _fns_in_deterministic_order():
|
||||
is_reserved_word = key in builtins
|
||||
|
||||
class_name = f"_{fn_class.__name__}_func"
|
||||
if issubclass(fn_class, ReturnTypeFromArgs):
|
||||
guess_its_generic = True
|
||||
if issubclass(fn_class, ReturnTypeFromOptionalArgs):
|
||||
_TEE = "Optional[_T]"
|
||||
else:
|
||||
@@ -84,7 +87,7 @@ def {key}( {' # noqa: A001' if is_reserved_word else ''}
|
||||
col: ColumnElement[_T],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> {fn_class.__name__}[_T]:
|
||||
) -> {class_name}[_T]:
|
||||
...
|
||||
|
||||
@overload
|
||||
@@ -93,7 +96,7 @@ def {key}( {' # noqa: A001' if is_reserved_word else ''}
|
||||
col: _ColumnExpressionArgument[{_TEE}],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> {fn_class.__name__}[_T]:
|
||||
) -> {class_name}[_T]:
|
||||
...
|
||||
|
||||
@overload
|
||||
@@ -102,7 +105,7 @@ def {key}( {' # noqa: A001' if is_reserved_word else ''}
|
||||
col: {_TEE},
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> {fn_class.__name__}[_T]:
|
||||
) -> {class_name}[_T]:
|
||||
...
|
||||
|
||||
def {key}( {' # noqa: A001' if is_reserved_word else ''}
|
||||
@@ -110,7 +113,7 @@ def {key}( {' # noqa: A001' if is_reserved_word else ''}
|
||||
col: _ColumnExpressionOrLiteralArgument[{_TEE}],
|
||||
*args: _ColumnExpressionOrLiteralArgument[Any],
|
||||
**kwargs: Any,
|
||||
) -> {fn_class.__name__}[_T]:
|
||||
) -> {class_name}[_T]:
|
||||
...
|
||||
|
||||
""",
|
||||
@@ -130,7 +133,7 @@ def {key}( {' # noqa: A001' if is_reserved_word else ''}
|
||||
# to get around the indentation errors
|
||||
# 4. Therefore here I have to concat part of the
|
||||
# string outside of the f-string
|
||||
_type = fn_class.__name__
|
||||
_type = class_name
|
||||
_type += "[Any]" if guess_its_generic else ""
|
||||
_reserved_word = (
|
||||
" # noqa: A001" if is_reserved_word else ""
|
||||
@@ -148,6 +151,11 @@ def {key}(self) -> Type[{_type}]:{_reserved_word}
|
||||
indent,
|
||||
)
|
||||
)
|
||||
orig_name = fn_class.__name__
|
||||
alias_name = class_name
|
||||
if guess_its_generic:
|
||||
orig_name += "[_T]"
|
||||
alias_mapping[orig_name] = alias_name
|
||||
|
||||
m = re.match(
|
||||
r"^( *)# START GENERATED FUNCTION TYPING TESTS",
|
||||
@@ -189,10 +197,17 @@ def {key}(self) -> Type[{_type}]:{_reserved_word}
|
||||
buf.write(
|
||||
textwrap.indent(
|
||||
rf"""
|
||||
stmt{count} = select(func.{key}(column('x', Integer)))
|
||||
|
||||
# test the {key}() function.
|
||||
# this function is a ReturnTypeFromArgs type.
|
||||
|
||||
fn{count} = func.{key}(column('x', Integer))
|
||||
assert_type(fn{count}, functions.{key}[int])
|
||||
|
||||
stmt{count} = select(func.{key}(column('x', Integer)))
|
||||
assert_type(stmt{count}, Select[{coltype}])
|
||||
|
||||
|
||||
""",
|
||||
indent,
|
||||
)
|
||||
@@ -202,8 +217,11 @@ assert_type(stmt{count}, Select[{coltype}])
|
||||
buf.write(
|
||||
textwrap.indent(
|
||||
rf"""
|
||||
stmt{count} = select(func.{key}(column('x', String), ','))
|
||||
|
||||
# test the aggregate_strings() function.
|
||||
# this function is somewhat special case.
|
||||
|
||||
stmt{count} = select(func.{key}(column('x', String), ','))
|
||||
assert_type(stmt{count}, Select[str])
|
||||
|
||||
""",
|
||||
@@ -228,15 +246,33 @@ assert_type(stmt{count}, Select[str])
|
||||
buf.write(
|
||||
textwrap.indent(
|
||||
rf"""
|
||||
stmt{count} = select(func.{key}({args}))
|
||||
|
||||
# test the {key}() function.
|
||||
# this function is fixed to the SQL {fn_class.type} class, or the {python_expr} type.
|
||||
|
||||
fn{count} = func.{key}({args})
|
||||
assert_type(fn{count}, functions.{key})
|
||||
|
||||
stmt{count} = select(func.{key}({args}))
|
||||
assert_type(stmt{count}, Select[{python_expr}])
|
||||
|
||||
""",
|
||||
""", # noqa: E501
|
||||
indent,
|
||||
)
|
||||
)
|
||||
|
||||
m = re.match(
|
||||
r"^( *)# START GENERATED FUNCTION ALIASES",
|
||||
line,
|
||||
)
|
||||
if m:
|
||||
in_block = True
|
||||
buf.write(line)
|
||||
indent = m.group(1)
|
||||
|
||||
for name, alias in alias_mapping.items():
|
||||
buf.write(f"{indent}{alias}: TypeAlias = {name}\n")
|
||||
|
||||
if in_block and line.startswith(
|
||||
f"{indent}# END GENERATED FUNCTION"
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user