From ed2874bb5fbaa2274d2059032602e36e9230707e Mon Sep 17 00:00:00 2001 From: Daniel Townsend Date: Sun, 1 Dec 2024 12:30:48 +0000 Subject: [PATCH 1/4] fix large integers in SQLite --- piccolo/engine/sqlite.py | 2 +- tests/columns/test_integer.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/columns/test_integer.py diff --git a/piccolo/engine/sqlite.py b/piccolo/engine/sqlite.py index 3f7649d76..3c36e5705 100644 --- a/piccolo/engine/sqlite.py +++ b/piccolo/engine/sqlite.py @@ -175,7 +175,7 @@ def convert_int_out(value: str) -> int: """ Make sure Integer values are actually of type int. """ - return int(float(value)) + return int(value) @decode_to_string diff --git a/tests/columns/test_integer.py b/tests/columns/test_integer.py new file mode 100644 index 000000000..b5ec0a591 --- /dev/null +++ b/tests/columns/test_integer.py @@ -0,0 +1,30 @@ +from piccolo.columns.column_types import Integer +from piccolo.table import Table +from piccolo.testing.test_case import AsyncTableTest + + +class MyTable(Table): + integer = Integer() + + +class TestInteger(AsyncTableTest): + tables = [MyTable] + + async def test_large_integer(self): + """ + Make sure large integers can be inserted and retrieved correctly. + + There was a bug with this in SQLite: + + https://github.com/piccolo-orm/piccolo/issues/1127 + + """ + integer = 625757527765811240 + + row = MyTable(integer=integer) + await row.save() + + _row = MyTable.objects().first().run_sync() + assert _row is not None + + self.assertEqual(_row.integer, integer) From 89aa655fffed0f102b17f271ac5e3610b5f20592 Mon Sep 17 00:00:00 2001 From: Daniel Townsend Date: Sun, 1 Dec 2024 17:10:01 +0000 Subject: [PATCH 2/4] make test sqlite only --- tests/columns/test_integer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/columns/test_integer.py b/tests/columns/test_integer.py index b5ec0a591..fe42aaf18 100644 --- a/tests/columns/test_integer.py +++ b/tests/columns/test_integer.py @@ -1,12 +1,14 @@ from piccolo.columns.column_types import Integer from piccolo.table import Table from piccolo.testing.test_case import AsyncTableTest +from tests.base import sqlite_only class MyTable(Table): integer = Integer() +@sqlite_only class TestInteger(AsyncTableTest): tables = [MyTable] From 18c11545936ed1615d00ee7325c95792231943d5 Mon Sep 17 00:00:00 2001 From: Daniel Townsend Date: Sun, 1 Dec 2024 17:20:07 +0000 Subject: [PATCH 3/4] fix integration tests (`httpx` removed `app` argument) --- requirements/test-requirements.txt | 2 +- tests/apps/asgi/commands/files/dummy_server.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements/test-requirements.txt b/requirements/test-requirements.txt index 006d8f2d9..6b8be1348 100644 --- a/requirements/test-requirements.txt +++ b/requirements/test-requirements.txt @@ -1,5 +1,5 @@ coveralls==3.3.1 -httpx==0.27.2 +httpx==0.28.0 pytest-cov==3.0.0 pytest==6.2.5 python-dateutil==2.8.2 diff --git a/tests/apps/asgi/commands/files/dummy_server.py b/tests/apps/asgi/commands/files/dummy_server.py index 9b83470a3..a4807aa66 100644 --- a/tests/apps/asgi/commands/files/dummy_server.py +++ b/tests/apps/asgi/commands/files/dummy_server.py @@ -3,7 +3,7 @@ import sys import typing as t -from httpx import AsyncClient +from httpx import ASGITransport, AsyncClient async def dummy_server(app: t.Union[str, t.Callable] = "app:app"): @@ -24,7 +24,7 @@ async def dummy_server(app: t.Union[str, t.Callable] = "app:app"): module = importlib.import_module(path) app = t.cast(t.Callable, getattr(module, app_name)) - async with AsyncClient(app=app) as client: + async with AsyncClient(transport=ASGITransport(app=app)) as client: response = await client.get("http://localhost:8000") if response.status_code != 200: sys.exit("The app isn't callable!") From c6c2b0480e812bbbd34c1fb6a86ebcc43942d1a0 Mon Sep 17 00:00:00 2001 From: Daniel Townsend Date: Tue, 7 Jan 2025 19:44:00 +0000 Subject: [PATCH 4/4] use `Decimal` --- piccolo/engine/sqlite.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/piccolo/engine/sqlite.py b/piccolo/engine/sqlite.py index 3c36e5705..c8183e336 100644 --- a/piccolo/engine/sqlite.py +++ b/piccolo/engine/sqlite.py @@ -173,9 +173,21 @@ def convert_numeric_out(value: str) -> Decimal: @decode_to_string def convert_int_out(value: str) -> int: """ - Make sure Integer values are actually of type int. + Make sure INTEGER values are actually of type ``int``. + + SQLite doesn't enforce that the values in INTEGER columns are actually + integers - they could be strings ('hello'), or floats (1.0). + + There's not much we can do if the value is something like 'hello' - a + ``ValueError`` is appropriate in this situation. + + For a value like ``1.0``, it seems reasonable to handle this, and return a + value of ``1``. + """ - return int(value) + # We used to use int(float(value)), but it was incorrect, because float has + # limited precision for large numbers. + return int(Decimal(value)) @decode_to_string