summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/engine
diff options
context:
space:
mode:
authorFederico Caselli <cfederico87@gmail.com>2021-12-22 21:45:45 +0100
committerMike Bayer <mike_mp@zzzcomputing.com>2021-12-30 18:07:26 -0500
commite913ec8155b64e055f3a88ca9c1bb7f112202c76 (patch)
treeb0847baac43de628cd74bc2ff70cc352bbcb0270 /lib/sqlalchemy/engine
parent54875c21601eaca01e3217d5b22fab6f6cf50992 (diff)
downloadsqlalchemy-e913ec8155b64e055f3a88ca9c1bb7f112202c76.tar.gz
Properly type _generative, decorator, public_factory
Good new is that pylance likes it and copies over the singature and everything. Bad news is that mypy does not support this yet https://github.com/python/mypy/issues/8645 Other minor bad news is that non_generative is not typed. I've tried using a protocol like the one in the comment but the signature is not ported over by pylance, so it's probably best to just live without it to have the correct signature. notes from mike: these three decorators are at the core of getting the library to be typed, more good news is that pylance will do all the things we like re: public_factory, see https://github.com/microsoft/pyright/issues/2758#issuecomment-1002788656 . For @_generative, we will likely move to using pep 673 once mypy supports it which may be soon. but overall having the explicit "return self" in the methods, while a little inconvenient, makes the typing more straightforward and locally present in the files rather than being decided at a distance. having "return self" present, or not, both have problems, so maybe we will be able to change it again if things change as far as decorator support. As it is, I feel like we are barely squeaking by with our decorators, the typing is already pretty out there. Change-Id: Ic77e13fc861def76a5925331df85c0aa48d77807 References: #6810
Diffstat (limited to 'lib/sqlalchemy/engine')
-rw-r--r--lib/sqlalchemy/engine/cursor.py1
-rw-r--r--lib/sqlalchemy/engine/result.py39
2 files changed, 32 insertions, 8 deletions
diff --git a/lib/sqlalchemy/engine/cursor.py b/lib/sqlalchemy/engine/cursor.py
index 794b9d2c7..50d854f82 100644
--- a/lib/sqlalchemy/engine/cursor.py
+++ b/lib/sqlalchemy/engine/cursor.py
@@ -1702,6 +1702,7 @@ class CursorResult(BaseCursorResult, Result):
def yield_per(self, num):
self._yield_per = num
self.cursor_strategy.yield_per(self, self.cursor, num)
+ return self
ResultProxy = CursorResult
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 7d496838a..f8e255e92 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -7,11 +7,11 @@
"""Define generic result set constructs."""
-
import collections.abc as collections_abc
import functools
import itertools
import operator
+import typing
from .row import Row
from .. import exc
@@ -257,6 +257,10 @@ def result_tuple(fields, extra=None):
# filter is applied to rows.
_NO_ROW = util.symbol("NO_ROW")
+SelfResultInternal = typing.TypeVar(
+ "SelfResultInternal", bound="ResultInternal"
+)
+
class ResultInternal(InPlaceGenerative):
_real_result = None
@@ -614,7 +618,9 @@ class ResultInternal(InPlaceGenerative):
return row
@_generative
- def _column_slices(self, indexes):
+ def _column_slices(
+ self: SelfResultInternal, indexes
+ ) -> SelfResultInternal:
real_result = self._real_result if self._real_result else self
if real_result._source_supports_scalars and len(indexes) == 1:
@@ -623,6 +629,8 @@ class ResultInternal(InPlaceGenerative):
self._generate_rows = True
self._metadata = self._metadata._reduce(indexes)
+ return self
+
@HasMemoized.memoized_attribute
def _unique_strategy(self):
uniques, strategy = self._unique_filter_state
@@ -668,6 +676,9 @@ class _WithKeys:
return self._metadata.keys
+SelfResult = typing.TypeVar("SelfResult", bound="Result")
+
+
class Result(_WithKeys, ResultInternal):
"""Represent a set of database results.
@@ -732,7 +743,7 @@ class Result(_WithKeys, ResultInternal):
self._soft_close(hard=True)
@_generative
- def yield_per(self, num):
+ def yield_per(self: SelfResult, num) -> SelfResult:
"""Configure the row-fetching strategy to fetch num rows at a time.
This impacts the underlying behavior of the result when iterating over
@@ -766,9 +777,10 @@ class Result(_WithKeys, ResultInternal):
"""
self._yield_per = num
+ return self
@_generative
- def unique(self, strategy=None):
+ def unique(self: SelfResult, strategy=None) -> SelfResult:
"""Apply unique filtering to the objects returned by this
:class:`_engine.Result`.
@@ -806,8 +818,11 @@ class Result(_WithKeys, ResultInternal):
"""
self._unique_filter_state = (set(), strategy)
+ return self
- def columns(self, *col_expressions):
+ def columns(
+ self: SelfResultInternal, *col_expressions
+ ) -> SelfResultInternal:
r"""Establish the columns that should be returned in each row.
This method may be used to limit the columns returned as well
@@ -845,7 +860,7 @@ class Result(_WithKeys, ResultInternal):
"""
return self._column_slices(col_expressions)
- def scalars(self, index=0):
+ def scalars(self, index=0) -> "ScalarResult":
"""Return a :class:`_result.ScalarResult` filtering object which
will return single elements rather than :class:`_row.Row` objects.
@@ -892,7 +907,7 @@ class Result(_WithKeys, ResultInternal):
)
return self._metadata._row_as_tuple_getter(keys)
- def mappings(self):
+ def mappings(self) -> "MappingResult":
"""Apply a mappings filter to returned rows, returning an instance of
:class:`_result.MappingResult`.
@@ -1653,6 +1668,11 @@ def null_result():
return IteratorResult(SimpleResultMetaData([]), iter([]))
+SelfChunkedIteratorResult = typing.TypeVar(
+ "SelfChunkedIteratorResult", bound="ChunkedIteratorResult"
+)
+
+
class ChunkedIteratorResult(IteratorResult):
"""An :class:`.IteratorResult` that works from an iterator-producing callable.
@@ -1684,7 +1704,9 @@ class ChunkedIteratorResult(IteratorResult):
self.dynamic_yield_per = dynamic_yield_per
@_generative
- def yield_per(self, num):
+ def yield_per(
+ self: SelfChunkedIteratorResult, num
+ ) -> SelfChunkedIteratorResult:
# TODO: this throws away the iterator which may be holding
# onto a chunk. the yield_per cannot be changed once any
# rows have been fetched. either find a way to enforce this,
@@ -1693,6 +1715,7 @@ class ChunkedIteratorResult(IteratorResult):
self._yield_per = num
self.iterator = itertools.chain.from_iterable(self.chunks(num))
+ return self
def _soft_close(self, **kw):
super(ChunkedIteratorResult, self)._soft_close(**kw)