piccolo 1.16.0__py3-none-any.whl → 1.17.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
piccolo/__init__.py CHANGED
@@ -1 +1 @@
1
- __VERSION__ = "1.16.0"
1
+ __VERSION__ = "1.17.1"
@@ -9,13 +9,13 @@ import colorama
9
9
  from jinja2 import Environment, FileSystemLoader
10
10
 
11
11
  TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates/app/")
12
- SERVERS = ["uvicorn", "Hypercorn"]
12
+ SERVERS = ["uvicorn", "Hypercorn", "granian"]
13
13
  ROUTER_DEPENDENCIES = {
14
14
  "starlette": ["starlette"],
15
- "fastapi": ["fastapi>=0.100.0"],
15
+ "fastapi": ["fastapi>=0.112.1"],
16
16
  "blacksheep": ["blacksheep"],
17
17
  "litestar": ["litestar"],
18
- "esmerald": ["esmerald"],
18
+ "esmerald": ["esmerald==3.3.0"],
19
19
  "lilya": ["lilya"],
20
20
  }
21
21
  ROUTERS = list(ROUTER_DEPENDENCIES.keys())
@@ -18,4 +18,8 @@ if __name__ == "__main__":
18
18
  asyncio.run(serve(app, CustomConfig()))
19
19
 
20
20
  serve(app)
21
+ {% elif server == 'granian' %}
22
+ import granian
23
+
24
+ granian.Granian("app:app", interface="asgi").serve()
21
25
  {% endif %}
@@ -40,10 +40,17 @@ def compare_dicts(
40
40
 
41
41
  for key, value in dict_1.items():
42
42
  dict_2_value = dict_2.get(key, ...)
43
+
43
44
  if (
44
- dict_2_value is not ...
45
- and dict_2_value != value
46
- or dict_2_value is ...
45
+ # If the value is `...` then it means no value was found.
46
+ (dict_2_value is ...)
47
+ # We have to compare the types, because if we just use equality
48
+ # then 1.0 == 1 is True.
49
+ # See this issue:
50
+ # https://github.com/piccolo-orm/piccolo/issues/1071
51
+ or (type(value) is not type(dict_2_value))
52
+ # Finally compare the actual values.
53
+ or (dict_2_value != value)
47
54
  ):
48
55
  output[key] = value
49
56
 
@@ -130,11 +130,27 @@ class AlterColumnCollection:
130
130
  AsyncFunction = t.Callable[[], t.Coroutine]
131
131
 
132
132
 
133
+ class SkippedTransaction:
134
+ async def __aenter__(self):
135
+ print("Automatic transaction disabled")
136
+
137
+ async def __aexit__(self, *args, **kwargs):
138
+ pass
139
+
140
+
133
141
  @dataclass
134
142
  class MigrationManager:
135
143
  """
136
144
  Each auto generated migration returns a MigrationManager. It contains
137
145
  all of the schema changes that migration wants to make.
146
+
147
+ :param wrap_in_transaction:
148
+ By default, the migration is wrapped in a transaction, so if anything
149
+ fails, the whole migration will get rolled back. You can disable this
150
+ behaviour if you want - for example, in a manual migration you might
151
+ want to create the transaction yourself (perhaps you're using
152
+ savepoints), or you may want multiple transactions.
153
+
138
154
  """
139
155
 
140
156
  migration_id: str = ""
@@ -166,6 +182,7 @@ class MigrationManager:
166
182
  default_factory=list
167
183
  )
168
184
  fake: bool = False
185
+ wrap_in_transaction: bool = True
169
186
 
170
187
  def add_table(
171
188
  self,
@@ -935,7 +952,11 @@ class MigrationManager:
935
952
  if not engine:
936
953
  raise Exception("Can't find engine")
937
954
 
938
- async with engine.transaction():
955
+ async with (
956
+ engine.transaction()
957
+ if self.wrap_in_transaction
958
+ else SkippedTransaction()
959
+ ):
939
960
  if not self.preview:
940
961
  if direction == "backwards":
941
962
  raw_list = self.raw_backwards
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: piccolo
3
- Version: 1.16.0
3
+ Version: 1.17.1
4
4
  Summary: A fast, user friendly ORM and query builder which supports asyncio.
5
5
  Home-page: https://github.com/piccolo-orm/piccolo
6
6
  Author: Daniel Townsend
@@ -1,4 +1,4 @@
1
- piccolo/__init__.py,sha256=ysxGt_oXPqT-SJ1UbC7NdyUSaoEEi94z0BdzyvNNY2Y,23
1
+ piccolo/__init__.py,sha256=LHM-IUVB0dp8WEkvdMoZPznVSxU-UEwiRDYV3iBGA4w,23
2
2
  piccolo/custom_types.py,sha256=7HMQAze-5mieNLfbQ5QgbRQgR2abR7ol0qehv2SqROY,604
3
3
  piccolo/main.py,sha256=1VsFV67FWTUikPTysp64Fmgd9QBVa_9wcwKfwj2UCEA,5117
4
4
  piccolo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -17,7 +17,7 @@ piccolo/apps/app/commands/templates/tables.py.jinja,sha256=revzdrvDDwe78VedBKz0z
17
17
  piccolo/apps/asgi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  piccolo/apps/asgi/piccolo_app.py,sha256=7VUvqQJbB-ScO0A62S6MiJmQL9F5DS-SdlqlDLbAblE,217
19
19
  piccolo/apps/asgi/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- piccolo/apps/asgi/commands/new.py,sha256=ZyYgwpBXb0t-0KQraeja6Y9ANjGEdZCXpu9bmm7_cPc,4230
20
+ piccolo/apps/asgi/commands/new.py,sha256=Y9-uw9BdrL_wY_zJhKVTNuVHIE6hDa52YcDgBBA2yII,4248
21
21
  piccolo/apps/asgi/commands/templates/app/README.md.jinja,sha256=As3gNEZt9qcRmTVkjCzNtXJ8r4-3g0fCSe7Q-P39ezI,214
22
22
  piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja,sha256=bgAGe0a9nWk0LAqK3VNDhPcKGqg0z8V-eIX2YmMoZLk,3117
23
23
  piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja,sha256=S-oYY6OFhwJA8PEYnrklQUkqtot3aXTmd7QGrW8Ufn4,2670
@@ -27,7 +27,7 @@ piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja,sha256=oMH5KXoEY
27
27
  piccolo/apps/asgi/commands/templates/app/_starlette_app.py.jinja,sha256=vHcAzsS9I3OevYoznwZp8zucI4OEyUjj-EOAtscmlSE,1443
28
28
  piccolo/apps/asgi/commands/templates/app/app.py.jinja,sha256=gROY-LbHl8NtHDM_ntkI7Rjcbtg2ypDZ1FunBvpdjE4,458
29
29
  piccolo/apps/asgi/commands/templates/app/conftest.py.jinja,sha256=ZG1pRVMv3LhIfOsO3_08c_fF3EV4_EApuDHiIFFPJdk,497
30
- piccolo/apps/asgi/commands/templates/app/main.py.jinja,sha256=azwXyWZGkrIbZv5bZF_4Tvbly7AXkw5yFWGCHYImGeo,421
30
+ piccolo/apps/asgi/commands/templates/app/main.py.jinja,sha256=QxMpsevsxGQdL_xwfvcNalGLXGswgqiVvApitkP1TuQ,533
31
31
  piccolo/apps/asgi/commands/templates/app/piccolo_conf.py.jinja,sha256=f9Nb08_yipi0_mDUYrUvVoGCz7MRRS5QjCdUGBHN760,379
32
32
  piccolo/apps/asgi/commands/templates/app/piccolo_conf_test.py.jinja,sha256=ZB32IZQFjA67U7N7hD_wwZdbTdxAofj3-66EnX8Gqd0,235
33
33
  piccolo/apps/asgi/commands/templates/app/requirements.txt.jinja,sha256=w4FXnehMNsauBjf1OcJ547SL8uymhTKcjvSH60Nns7I,149
@@ -59,8 +59,8 @@ piccolo/apps/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
59
59
  piccolo/apps/migrations/piccolo_app.py,sha256=1EcS2ComBPCaMCC2C3WaPR_GqLwt3XiIJNfm5D2hMgo,593
60
60
  piccolo/apps/migrations/tables.py,sha256=jqBnK-Rk545v1Eu6GaLHTVz7-uwBTUnz2m58OA-mxTc,799
61
61
  piccolo/apps/migrations/auto/__init__.py,sha256=eYb1rZQaalumv_bhbcEe6x3dUglmpFtw7Egg6k7597U,316
62
- piccolo/apps/migrations/auto/diffable_table.py,sha256=FJ_D7FvL_vaThgIY-zFyW_kFmReOI12saM3DFcaAvfw,7058
63
- piccolo/apps/migrations/auto/migration_manager.py,sha256=kzkIbC9Ow2VoxI5uMcCDG-qVZbTHBtluvdawp-tIi20,35150
62
+ piccolo/apps/migrations/auto/diffable_table.py,sha256=1HdqGeWFUYVJ2cJg6DZWOCh67SbgCxFVc554uD7N71A,7405
63
+ piccolo/apps/migrations/auto/migration_manager.py,sha256=tyAE1Xk6Xb58igbuHw3FGHhKkVjv_Vr5qBH4AbvVb8k,35856
64
64
  piccolo/apps/migrations/auto/operations.py,sha256=169IrCLR3FtTRxHsEHNg6dTG45lcEM7Aoyy3SwgX_hU,1329
65
65
  piccolo/apps/migrations/auto/schema_differ.py,sha256=VA1rK-_wNSdyZZgfA3ZOlpVGJCcvLyouKtT9k2YKhiA,26266
66
66
  piccolo/apps/migrations/auto/schema_snapshot.py,sha256=ZqUg4NpChOeoACKF2gkhqsz1BW3wOWFnzJCccq-CNNQ,4719
@@ -211,13 +211,13 @@ tests/apps/meta/commands/test_version.py,sha256=GxBeoC6O3OGICVOWtcCdP3bZza1MR2v9
211
211
  tests/apps/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
212
212
  tests/apps/migrations/test_migration.py,sha256=JmPLtf2BCWX3Yofe0GQe40m8I_yWa_-3vk1lDfFDfIo,308
213
213
  tests/apps/migrations/auto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
214
- tests/apps/migrations/auto/test_diffable_table.py,sha256=bok3G9pwEYnE3AL6UG4iEHrVBZJQ_ovYCdKC3we5JVQ,2932
215
- tests/apps/migrations/auto/test_migration_manager.py,sha256=NTNx4y5B0bMVLUR9BybX3zS4jxFI3_weLej8zOn3BkI,34798
214
+ tests/apps/migrations/auto/test_diffable_table.py,sha256=p0cKDkfhmu96-rB9bonOlg5bmfQ7U9S2kRppOt4YxyU,3338
215
+ tests/apps/migrations/auto/test_migration_manager.py,sha256=L2raSuhZybRyK-BEh-G-nDndAgl4sLynekHQFqyrteY,35719
216
216
  tests/apps/migrations/auto/test_schema_differ.py,sha256=UdsaZisA02j15wr1bXkXD6Cqu3p0A23NwFQLXsJdQL4,19391
217
217
  tests/apps/migrations/auto/test_schema_snapshot.py,sha256=ZyvGZqn3N3cwd-3S-FME5AJ8buDSHesw7yPIvY6mE5k,6196
218
218
  tests/apps/migrations/auto/test_serialisation.py,sha256=EFkhES1w9h51UCamWrhxs3mf4I718ggeP7Yl5J_UID4,13548
219
219
  tests/apps/migrations/auto/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
- tests/apps/migrations/auto/integration/test_migrations.py,sha256=t6QK3sSYovc4K68tySUo51H3a6LpubM442agiBYQxZ4,46753
220
+ tests/apps/migrations/auto/integration/test_migrations.py,sha256=e4GCAfMWvo5-6EM8f-EmAiLLGR62dxCZ8Tp-0bZ_kDQ,47285
221
221
  tests/apps/migrations/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
222
222
  tests/apps/migrations/commands/test_base.py,sha256=NgHgVjNd3Hil9eODvW7Ic2D9muTa_grNaH3YpRFfR8I,1829
223
223
  tests/apps/migrations/commands/test_check.py,sha256=hOX_sVk1nfCRfbQ8tJoFEUBFhih9O4QuQLHTp5TQaiY,630
@@ -367,9 +367,9 @@ tests/utils/test_sql_values.py,sha256=vzxRmy16FfLZPH-sAQexBvsF9MXB8n4smr14qoEOS5
367
367
  tests/utils/test_sync.py,sha256=9ytVo56y2vPQePvTeIi9lHIouEhWJbodl1TmzkGFrSo,799
368
368
  tests/utils/test_table_reflection.py,sha256=SIzuat-IpcVj1GCFyOWKShI8YkhdOPPFH7qVrvfyPNE,3794
369
369
  tests/utils/test_warnings.py,sha256=NvSC_cvJ6uZcwAGf1m-hLzETXCqprXELL8zg3TNLVMw,269
370
- piccolo-1.16.0.dist-info/LICENSE,sha256=zFIpi-16uIJ420UMIG75NU0JbDBykvrdnXcj5U_EYBI,1059
371
- piccolo-1.16.0.dist-info/METADATA,sha256=qsjW9UTKSwkT62sKfdGnTFyllEcn8bE1yKIj54iu4Ek,5178
372
- piccolo-1.16.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
373
- piccolo-1.16.0.dist-info/entry_points.txt,sha256=SJPHET4Fi1bN5F3WqcKkv9SClK3_F1I7m4eQjk6AFh0,46
374
- piccolo-1.16.0.dist-info/top_level.txt,sha256=-SR74VGbk43VoPy1HH-mHm97yoGukLK87HE5kdBW6qM,24
375
- piccolo-1.16.0.dist-info/RECORD,,
370
+ piccolo-1.17.1.dist-info/LICENSE,sha256=zFIpi-16uIJ420UMIG75NU0JbDBykvrdnXcj5U_EYBI,1059
371
+ piccolo-1.17.1.dist-info/METADATA,sha256=TZvCpeVtvGuvBWlyeNvBGPXN7dFZNSrRVuvUwyCOGRs,5178
372
+ piccolo-1.17.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
373
+ piccolo-1.17.1.dist-info/entry_points.txt,sha256=SJPHET4Fi1bN5F3WqcKkv9SClK3_F1I7m4eQjk6AFh0,46
374
+ piccolo-1.17.1.dist-info/top_level.txt,sha256=-SR74VGbk43VoPy1HH-mHm97yoGukLK87HE5kdBW6qM,24
375
+ piccolo-1.17.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -888,6 +888,25 @@ class TestMigrations(MigrationTestCase):
888
888
  ]
889
889
  )
890
890
 
891
+ def test_column_type_conversion_integer_float(self):
892
+ """
893
+ Make sure conversion between ``Integer`` and ``Real`` works - related
894
+ to this bug:
895
+
896
+ https://github.com/piccolo-orm/piccolo/issues/1071
897
+
898
+ """
899
+ self._test_migrations(
900
+ table_snapshots=[
901
+ [self.table(column)]
902
+ for column in [
903
+ Real(default=1.0),
904
+ Integer(default=1),
905
+ Real(default=1.0),
906
+ ]
907
+ ]
908
+ )
909
+
891
910
  def test_column_type_conversion_json(self):
892
911
  self._test_migrations(
893
912
  table_snapshots=[
@@ -73,6 +73,19 @@ class TestCompareDicts(TestCase):
73
73
  response = compare_dicts(dict_1, dict_2)
74
74
  self.assertEqual(response, {"a": OnDelete.set_default})
75
75
 
76
+ def test_numeric_values(self):
77
+ """
78
+ Make sure that if we have two numbers which are equal, but different
79
+ types, then they are identified as being different.
80
+
81
+ https://github.com/piccolo-orm/piccolo/issues/1071
82
+
83
+ """
84
+ dict_1 = {"a": 1}
85
+ dict_2 = {"a": 1.0}
86
+ response = compare_dicts(dict_1, dict_2)
87
+ self.assertEqual(response, {"a": 1})
88
+
76
89
 
77
90
  class TestDiffableTable(TestCase):
78
91
  def test_subtract(self):
@@ -2,7 +2,7 @@ import asyncio
2
2
  import random
3
3
  import typing as t
4
4
  from io import StringIO
5
- from unittest import TestCase
5
+ from unittest import IsolatedAsyncioTestCase, TestCase
6
6
  from unittest.mock import MagicMock, patch
7
7
 
8
8
  from piccolo.apps.migrations.auto.migration_manager import MigrationManager
@@ -11,6 +11,7 @@ from piccolo.columns import Text, Varchar
11
11
  from piccolo.columns.base import OnDelete, OnUpdate
12
12
  from piccolo.columns.column_types import ForeignKey
13
13
  from piccolo.conf.apps import AppConfig
14
+ from piccolo.engine import engine_finder
14
15
  from piccolo.table import Table, sort_table_classes
15
16
  from piccolo.utils.lazy_loader import LazyLoader
16
17
  from tests.base import AsyncMock, DBTestCase, engine_is, engines_only
@@ -1052,3 +1053,37 @@ class TestMigrationManager(DBTestCase):
1052
1053
  output,
1053
1054
  ' - 1 [preview forwards]... CREATE SCHEMA IF NOT EXISTS "schema_1"\nALTER TABLE "manager" SET SCHEMA "schema_1"\n', # noqa: E501
1054
1055
  )
1056
+
1057
+
1058
+ class TestWrapInTransaction(IsolatedAsyncioTestCase):
1059
+
1060
+ async def test_enabled(self):
1061
+ """
1062
+ Make sure we can wrap the migration in a transaction if we want to.
1063
+ """
1064
+
1065
+ async def run():
1066
+ db = engine_finder()
1067
+ assert db
1068
+ assert db.transaction_exists() is True
1069
+
1070
+ manager = MigrationManager(wrap_in_transaction=True)
1071
+ manager.add_raw(run)
1072
+
1073
+ await manager.run()
1074
+
1075
+ async def test_disabled(self):
1076
+ """
1077
+ Make sure we can stop the migration being wrapped in a transaction if
1078
+ we want to.
1079
+ """
1080
+
1081
+ async def run():
1082
+ db = engine_finder()
1083
+ assert db
1084
+ assert db.transaction_exists() is False
1085
+
1086
+ manager = MigrationManager(wrap_in_transaction=False)
1087
+ manager.add_raw(run)
1088
+
1089
+ await manager.run()