From: Mike Bayer Date: Thu, 21 Apr 2022 17:27:16 +0000 (-0400) Subject: warn for result.columns() method X-Git-Tag: rel_1_4_36~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f1a409ecdd5f0377b9c00a859ab14e9005e873da;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git warn for result.columns() method A warning is emitted when calling upon the :meth:`.Result.columns` method with only one index, in particular ORM related cases, indicating that the current behavior of :meth:`.Result.columns` is broken in this case and will be changed in 2.0. To receive a collection of scalar values, use the :meth:`.Result.scalars` method. Fixes: #7953 Change-Id: I3c4ca3eecc2bfc85ad1c38000e5990d6dde80d22 (cherry picked from commit fe2045fb1c767436ed1e32359fe005dabead504a) --- diff --git a/doc/build/changelog/unreleased_14/7953.rst b/doc/build/changelog/unreleased_14/7953.rst new file mode 100644 index 0000000000..d4e5037dcd --- /dev/null +++ b/doc/build/changelog/unreleased_14/7953.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, engine + :tickets: 7953 + + A warning is emitted when calling upon the :meth:`.Result.columns` method + with only one index, in particular ORM related cases, indicating that the + current behavior of :meth:`.Result.columns` is broken in this case and + will be changed in 2.0. To receive a collection of scalar values, + use the :meth:`.Result.scalars` method. + diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py index f8006ac53d..cb6906f036 100644 --- a/lib/sqlalchemy/engine/result.py +++ b/lib/sqlalchemy/engine/result.py @@ -648,6 +648,15 @@ class ResultInternal(InPlaceGenerative): real_result = self._real_result if self._real_result else self if real_result._source_supports_scalars and len(indexes) == 1: + util.warn_deprecated( + "The Result.columns() method has a bug in SQLAlchemy 1.4 that " + "is causing it to yield scalar values, rather than Row " + "objects, in the case where a single index is passed and the " + "result is against ORM mapped objects. In SQLAlchemy 2.0, " + "Result will continue yield Row objects in this scenario. " + "Use the Result.scalars() method to yield scalar values.", + "2.0", + ) self._generate_rows = False else: self._generate_rows = True diff --git a/test/base/test_result.py b/test/base/test_result.py index 8c9eb398e1..76156db1c3 100644 --- a/test/base/test_result.py +++ b/test/base/test_result.py @@ -5,6 +5,7 @@ from sqlalchemy.engine.row import Row from sqlalchemy.testing import assert_raises from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import eq_ +from sqlalchemy.testing import expect_deprecated from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_false from sqlalchemy.testing import is_true @@ -1054,12 +1055,49 @@ class OnlyScalarsTest(fixtures.TestBase): metadata, no_tuple_fixture, source_supports_scalars=True ) - r = r.columns(0).mappings() + with expect_deprecated( + r"The Result.columns\(\) method has a bug in SQLAlchemy 1.4 " + r"that is causing it to yield scalar values" + ): + r = r.columns(0).mappings() eq_( list(r), [{"a": 1}, {"a": 2}, {"a": 1}, {"a": 1}, {"a": 4}], ) + def test_scalar_mode_columns0_plain(self, no_tuple_fixture): + """test #7953""" + + metadata = result.SimpleResultMetaData(["a", "b", "c"]) + + r = result.ChunkedIteratorResult( + metadata, no_tuple_fixture, source_supports_scalars=True + ) + + with expect_deprecated( + r"The Result.columns\(\) method has a bug in SQLAlchemy 1.4 " + r"that is causing it to yield scalar values" + ): + r = r.columns(0) + eq_( + list(r), + [1, 2, 1, 1, 4], + # [(1,), (2,), (1,), (1,), (4,)], # correct result + ) + + def test_scalar_mode_scalars0(self, no_tuple_fixture): + metadata = result.SimpleResultMetaData(["a", "b", "c"]) + + r = result.ChunkedIteratorResult( + metadata, no_tuple_fixture, source_supports_scalars=True + ) + + r = r.scalars(0) + eq_( + list(r), + [1, 2, 1, 1, 4], + ) + def test_scalar_mode_but_accessed_nonscalar_result(self, no_tuple_fixture): metadata = result.SimpleResultMetaData(["a", "b", "c"])