From: Mike Bayer Date: Thu, 21 Mar 2024 06:13:22 +0000 (-0400) Subject: ensure ARRAY.__init__ documents before Comparator X-Git-Tag: rel_2_0_29~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b1bc05d444351c53daa42e827848fbecfb50e7e;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git ensure ARRAY.__init__ documents before Comparator also add note for zero_indexes to generic and PG ARRAY types References: https://github.com/sqlalchemy/sqlalchemy/discussions/11100 Change-Id: I2087da695787a930f325cfb2fa4156d19c8e8f31 (cherry picked from commit 7c70ab8c6b7b9ce1c566862c4ca0438e0b0e9131) --- diff --git a/doc/build/core/type_basics.rst b/doc/build/core/type_basics.rst index a8bb0f84af..f3817fe0c9 100644 --- a/doc/build/core/type_basics.rst +++ b/doc/build/core/type_basics.rst @@ -259,7 +259,9 @@ its exact name in DDL with ``CREATE TABLE`` is issued. .. autoclass:: ARRAY - :members: + :members: __init__, Comparator + :member-order: bysource + .. autoclass:: BIGINT diff --git a/doc/build/dialects/postgresql.rst b/doc/build/dialects/postgresql.rst index e822d069ce..2d377e3623 100644 --- a/doc/build/dialects/postgresql.rst +++ b/doc/build/dialects/postgresql.rst @@ -458,7 +458,7 @@ construction arguments, are as follows: .. autoclass:: ARRAY :members: __init__, Comparator - + :member-order: bysource .. autoclass:: BIT diff --git a/lib/sqlalchemy/dialects/postgresql/array.py b/lib/sqlalchemy/dialects/postgresql/array.py index e88c27d2de..1d63655ee0 100644 --- a/lib/sqlalchemy/dialects/postgresql/array.py +++ b/lib/sqlalchemy/dialects/postgresql/array.py @@ -183,8 +183,9 @@ class ARRAY(sqltypes.ARRAY): mytable.c.data.contains([1, 2]) - The :class:`_postgresql.ARRAY` type may not be supported on all - PostgreSQL DBAPIs; it is currently known to work on psycopg2 only. + Indexed access is one-based by default, to match that of PostgreSQL; + for zero-based indexed access, set + :paramref:`_postgresql.ARRAY.zero_indexes`. Additionally, the :class:`_postgresql.ARRAY` type does not work directly in @@ -224,41 +225,6 @@ class ARRAY(sqltypes.ARRAY): """ - class Comparator(sqltypes.ARRAY.Comparator): - """Define comparison operations for :class:`_types.ARRAY`. - - Note that these operations are in addition to those provided - by the base :class:`.types.ARRAY.Comparator` class, including - :meth:`.types.ARRAY.Comparator.any` and - :meth:`.types.ARRAY.Comparator.all`. - - """ - - def contains(self, other, **kwargs): - """Boolean expression. Test if elements are a superset of the - elements of the argument array expression. - - kwargs may be ignored by this operator but are required for API - conformance. - """ - return self.operate(CONTAINS, other, result_type=sqltypes.Boolean) - - def contained_by(self, other): - """Boolean expression. Test if elements are a proper subset of the - elements of the argument array expression. - """ - return self.operate( - CONTAINED_BY, other, result_type=sqltypes.Boolean - ) - - def overlap(self, other): - """Boolean expression. Test if array has elements in common with - an argument array expression. - """ - return self.operate(OVERLAP, other, result_type=sqltypes.Boolean) - - comparator_factory = Comparator - def __init__( self, item_type: _TypeEngineArgument[Any], @@ -310,6 +276,41 @@ class ARRAY(sqltypes.ARRAY): self.dimensions = dimensions self.zero_indexes = zero_indexes + class Comparator(sqltypes.ARRAY.Comparator): + """Define comparison operations for :class:`_types.ARRAY`. + + Note that these operations are in addition to those provided + by the base :class:`.types.ARRAY.Comparator` class, including + :meth:`.types.ARRAY.Comparator.any` and + :meth:`.types.ARRAY.Comparator.all`. + + """ + + def contains(self, other, **kwargs): + """Boolean expression. Test if elements are a superset of the + elements of the argument array expression. + + kwargs may be ignored by this operator but are required for API + conformance. + """ + return self.operate(CONTAINS, other, result_type=sqltypes.Boolean) + + def contained_by(self, other): + """Boolean expression. Test if elements are a proper subset of the + elements of the argument array expression. + """ + return self.operate( + CONTAINED_BY, other, result_type=sqltypes.Boolean + ) + + def overlap(self, other): + """Boolean expression. Test if array has elements in common with + an argument array expression. + """ + return self.operate(OVERLAP, other, result_type=sqltypes.Boolean) + + comparator_factory = Comparator + @property def hashable(self): return self.as_tuple diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index cdfd0a7c8a..1af3c5e339 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -2766,23 +2766,23 @@ class ARRAY( dimension parameter will generally assume single-dimensional behaviors. SQL expressions of type :class:`_types.ARRAY` have support for "index" and - "slice" behavior. The Python ``[]`` operator works normally here, given - integer indexes or slices. Arrays default to 1-based indexing. - The operator produces binary expression + "slice" behavior. The ``[]`` operator produces expression constructs which will produce the appropriate SQL, both for SELECT statements:: select(mytable.c.data[5], mytable.c.data[2:7]) as well as UPDATE statements when the :meth:`_expression.Update.values` - method - is used:: + method is used:: mytable.update().values({ mytable.c.data[5]: 7, mytable.c.data[2:7]: [1, 2, 3] }) + Indexed access is one-based by default; + for zero-based index conversion, set :paramref:`_types.ARRAY.zero_indexes`. + The :class:`_types.ARRAY` type also provides for the operators :meth:`.types.ARRAY.Comparator.any` and :meth:`.types.ARRAY.Comparator.all`. The PostgreSQL-specific version of @@ -2827,6 +2827,56 @@ class ARRAY( """If True, Python zero-based indexes should be interpreted as one-based on the SQL expression side.""" + def __init__( + self, + item_type: _TypeEngineArgument[Any], + as_tuple: bool = False, + dimensions: Optional[int] = None, + zero_indexes: bool = False, + ): + """Construct an :class:`_types.ARRAY`. + + E.g.:: + + Column('myarray', ARRAY(Integer)) + + Arguments are: + + :param item_type: The data type of items of this array. Note that + dimensionality is irrelevant here, so multi-dimensional arrays like + ``INTEGER[][]``, are constructed as ``ARRAY(Integer)``, not as + ``ARRAY(ARRAY(Integer))`` or such. + + :param as_tuple=False: Specify whether return results + should be converted to tuples from lists. This parameter is + not generally needed as a Python list corresponds well + to a SQL array. + + :param dimensions: if non-None, the ARRAY will assume a fixed + number of dimensions. This impacts how the array is declared + on the database, how it goes about interpreting Python and + result values, as well as how expression behavior in conjunction + with the "getitem" operator works. See the description at + :class:`_types.ARRAY` for additional detail. + + :param zero_indexes=False: when True, index values will be converted + between Python zero-based and SQL one-based indexes, e.g. + a value of one will be added to all index values before passing + to the database. + + """ + if isinstance(item_type, ARRAY): + raise ValueError( + "Do not nest ARRAY types; ARRAY(basetype) " + "handles multi-dimensional arrays of basetype" + ) + if isinstance(item_type, type): + item_type = item_type() + self.item_type = item_type + self.as_tuple = as_tuple + self.dimensions = dimensions + self.zero_indexes = zero_indexes + class Comparator( Indexable.Comparator[Sequence[Any]], Concatenable.Comparator[Sequence[Any]], @@ -2981,56 +3031,6 @@ class ARRAY( comparator_factory = Comparator - def __init__( - self, - item_type: _TypeEngineArgument[Any], - as_tuple: bool = False, - dimensions: Optional[int] = None, - zero_indexes: bool = False, - ): - """Construct an :class:`_types.ARRAY`. - - E.g.:: - - Column('myarray', ARRAY(Integer)) - - Arguments are: - - :param item_type: The data type of items of this array. Note that - dimensionality is irrelevant here, so multi-dimensional arrays like - ``INTEGER[][]``, are constructed as ``ARRAY(Integer)``, not as - ``ARRAY(ARRAY(Integer))`` or such. - - :param as_tuple=False: Specify whether return results - should be converted to tuples from lists. This parameter is - not generally needed as a Python list corresponds well - to a SQL array. - - :param dimensions: if non-None, the ARRAY will assume a fixed - number of dimensions. This impacts how the array is declared - on the database, how it goes about interpreting Python and - result values, as well as how expression behavior in conjunction - with the "getitem" operator works. See the description at - :class:`_types.ARRAY` for additional detail. - - :param zero_indexes=False: when True, index values will be converted - between Python zero-based and SQL one-based indexes, e.g. - a value of one will be added to all index values before passing - to the database. - - """ - if isinstance(item_type, ARRAY): - raise ValueError( - "Do not nest ARRAY types; ARRAY(basetype) " - "handles multi-dimensional arrays of basetype" - ) - if isinstance(item_type, type): - item_type = item_type() - self.item_type = item_type - self.as_tuple = as_tuple - self.dimensions = dimensions - self.zero_indexes = zero_indexes - @property def hashable(self): return self.as_tuple