piccolo 1.11.0__py3-none-any.whl → 1.12.0__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.
Files changed (38) hide show
  1. piccolo/__init__.py +1 -1
  2. piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja +35 -30
  3. piccolo/apps/asgi/commands/templates/app/_starlette_app.py.jinja +29 -21
  4. piccolo/apps/migrations/auto/migration_manager.py +1 -0
  5. piccolo/apps/migrations/commands/forwards.py +8 -7
  6. piccolo/apps/playground/commands/run.py +11 -0
  7. piccolo/columns/column_types.py +55 -0
  8. {piccolo-1.11.0.dist-info → piccolo-1.12.0.dist-info}/METADATA +15 -15
  9. {piccolo-1.11.0.dist-info → piccolo-1.12.0.dist-info}/RECORD +38 -38
  10. {piccolo-1.11.0.dist-info → piccolo-1.12.0.dist-info}/WHEEL +1 -1
  11. tests/apps/migrations/commands/test_forwards_backwards.py +32 -1
  12. tests/columns/test_array.py +3 -7
  13. tests/columns/test_bigint.py +3 -9
  14. tests/columns/test_boolean.py +3 -7
  15. tests/columns/test_bytea.py +5 -14
  16. tests/columns/test_choices.py +5 -14
  17. tests/columns/test_date.py +5 -13
  18. tests/columns/test_double_precision.py +3 -8
  19. tests/columns/test_interval.py +5 -13
  20. tests/columns/test_json.py +9 -26
  21. tests/columns/test_jsonb.py +3 -11
  22. tests/columns/test_numeric.py +3 -7
  23. tests/columns/test_primary_key.py +11 -33
  24. tests/columns/test_readable.py +5 -7
  25. tests/columns/test_real.py +3 -8
  26. tests/columns/test_reserved_column_names.py +3 -8
  27. tests/columns/test_smallint.py +3 -8
  28. tests/columns/test_time.py +5 -14
  29. tests/columns/test_timestamp.py +5 -13
  30. tests/columns/test_timestamptz.py +5 -13
  31. tests/columns/test_uuid.py +3 -7
  32. tests/columns/test_varchar.py +3 -9
  33. tests/query/functions/base.py +2 -15
  34. tests/query/functions/test_datetime.py +2 -4
  35. tests/query/functions/test_math.py +2 -3
  36. {piccolo-1.11.0.dist-info → piccolo-1.12.0.dist-info}/LICENSE +0 -0
  37. {piccolo-1.11.0.dist-info → piccolo-1.12.0.dist-info}/entry_points.txt +0 -0
  38. {piccolo-1.11.0.dist-info → piccolo-1.12.0.dist-info}/top_level.txt +0 -0
piccolo/__init__.py CHANGED
@@ -1 +1 @@
1
- __VERSION__ = "1.11.0"
1
+ __VERSION__ = "1.12.0"
@@ -1,11 +1,12 @@
1
1
  import typing as t
2
+ from contextlib import asynccontextmanager
2
3
 
3
4
  from fastapi import FastAPI
4
5
  from fastapi.responses import JSONResponse
6
+ from piccolo.engine import engine_finder
5
7
  from piccolo_admin.endpoints import create_admin
6
8
  from piccolo_api.crud.serializers import create_pydantic_model
7
- from piccolo.engine import engine_finder
8
- from starlette.routing import Route, Mount
9
+ from starlette.routing import Mount, Route
9
10
  from starlette.staticfiles import StaticFiles
10
11
 
11
12
  from home.endpoints import HomeEndpoint
@@ -13,6 +14,29 @@ from home.piccolo_app import APP_CONFIG
13
14
  from home.tables import Task
14
15
 
15
16
 
17
+ async def open_database_connection_pool():
18
+ try:
19
+ engine = engine_finder()
20
+ await engine.start_connection_pool()
21
+ except Exception:
22
+ print("Unable to connect to the database")
23
+
24
+
25
+ async def close_database_connection_pool():
26
+ try:
27
+ engine = engine_finder()
28
+ await engine.close_connection_pool()
29
+ except Exception:
30
+ print("Unable to connect to the database")
31
+
32
+
33
+ @asynccontextmanager
34
+ async def lifespan(app: FastAPI):
35
+ await open_database_connection_pool()
36
+ yield
37
+ await close_database_connection_pool()
38
+
39
+
16
40
  app = FastAPI(
17
41
  routes=[
18
42
  Route("/", HomeEndpoint),
@@ -22,21 +46,20 @@ app = FastAPI(
22
46
  tables=APP_CONFIG.table_classes,
23
47
  # Required when running under HTTPS:
24
48
  # allowed_hosts=['my_site.com']
25
- )
49
+ ),
26
50
  ),
27
51
  Mount("/static/", StaticFiles(directory="static")),
28
52
  ],
53
+ lifespan=lifespan,
29
54
  )
30
55
 
31
56
 
32
57
  TaskModelIn: t.Any = create_pydantic_model(
33
58
  table=Task,
34
- model_name='TaskModelIn'
59
+ model_name="TaskModelIn",
35
60
  )
36
61
  TaskModelOut: t.Any = create_pydantic_model(
37
- table=Task,
38
- include_default_columns=True,
39
- model_name='TaskModelOut'
62
+ table=Task, include_default_columns=True, model_name="TaskModelOut"
40
63
  )
41
64
 
42
65
 
@@ -45,16 +68,16 @@ async def tasks():
45
68
  return await Task.select().order_by(Task.id)
46
69
 
47
70
 
48
- @app.post('/tasks/', response_model=TaskModelOut)
71
+ @app.post("/tasks/", response_model=TaskModelOut)
49
72
  async def create_task(task_model: TaskModelIn):
50
73
  task = Task(**task_model.dict())
51
74
  await task.save()
52
75
  return task.to_dict()
53
76
 
54
77
 
55
- @app.put('/tasks/{task_id}/', response_model=TaskModelOut)
78
+ @app.put("/tasks/{task_id}/", response_model=TaskModelOut)
56
79
  async def update_task(task_id: int, task_model: TaskModelIn):
57
- task = await Task.objects().get(Task.id == task_id)
80
+ task = await Task.objects().get(Task._meta.primary_key == task_id)
58
81
  if not task:
59
82
  return JSONResponse({}, status_code=404)
60
83
 
@@ -66,30 +89,12 @@ async def update_task(task_id: int, task_model: TaskModelIn):
66
89
  return task.to_dict()
67
90
 
68
91
 
69
- @app.delete('/tasks/{task_id}/')
92
+ @app.delete("/tasks/{task_id}/")
70
93
  async def delete_task(task_id: int):
71
- task = await Task.objects().get(Task.id == task_id)
94
+ task = await Task.objects().get(Task._meta.primary_key == task_id)
72
95
  if not task:
73
96
  return JSONResponse({}, status_code=404)
74
97
 
75
98
  await task.remove()
76
99
 
77
100
  return JSONResponse({})
78
-
79
-
80
- @app.on_event("startup")
81
- async def open_database_connection_pool():
82
- try:
83
- engine = engine_finder()
84
- await engine.start_connection_pool()
85
- except Exception:
86
- print("Unable to connect to the database")
87
-
88
-
89
- @app.on_event("shutdown")
90
- async def close_database_connection_pool():
91
- try:
92
- engine = engine_finder()
93
- await engine.close_connection_pool()
94
- except Exception:
95
- print("Unable to connect to the database")
@@ -1,8 +1,10 @@
1
+ from contextlib import asynccontextmanager
2
+
3
+ from piccolo.engine import engine_finder
1
4
  from piccolo_admin.endpoints import create_admin
2
5
  from piccolo_api.crud.endpoints import PiccoloCRUD
3
- from piccolo.engine import engine_finder
4
- from starlette.routing import Route, Mount
5
6
  from starlette.applications import Starlette
7
+ from starlette.routing import Mount, Route
6
8
  from starlette.staticfiles import StaticFiles
7
9
 
8
10
  from home.endpoints import HomeEndpoint
@@ -10,24 +12,6 @@ from home.piccolo_app import APP_CONFIG
10
12
  from home.tables import Task
11
13
 
12
14
 
13
- app = Starlette(
14
- routes=[
15
- Route("/", HomeEndpoint),
16
- Mount(
17
- "/admin/",
18
- create_admin(
19
- tables=APP_CONFIG.table_classes,
20
- # Required when running under HTTPS:
21
- # allowed_hosts=['my_site.com']
22
- )
23
- ),
24
- Mount("/static/", StaticFiles(directory="static")),
25
- Mount("/tasks/", PiccoloCRUD(table=Task))
26
- ],
27
- )
28
-
29
-
30
- @app.on_event("startup")
31
15
  async def open_database_connection_pool():
32
16
  try:
33
17
  engine = engine_finder()
@@ -36,10 +20,34 @@ async def open_database_connection_pool():
36
20
  print("Unable to connect to the database")
37
21
 
38
22
 
39
- @app.on_event("shutdown")
40
23
  async def close_database_connection_pool():
41
24
  try:
42
25
  engine = engine_finder()
43
26
  await engine.close_connection_pool()
44
27
  except Exception:
45
28
  print("Unable to connect to the database")
29
+
30
+
31
+ @asynccontextmanager
32
+ async def lifespan(app: Starlette):
33
+ await open_database_connection_pool()
34
+ yield
35
+ await close_database_connection_pool()
36
+
37
+
38
+ app = Starlette(
39
+ routes=[
40
+ Route("/", HomeEndpoint),
41
+ Mount(
42
+ "/admin/",
43
+ create_admin(
44
+ tables=APP_CONFIG.table_classes,
45
+ # Required when running under HTTPS:
46
+ # allowed_hosts=['my_site.com']
47
+ ),
48
+ ),
49
+ Mount("/static/", StaticFiles(directory="static")),
50
+ Mount("/tasks/", PiccoloCRUD(table=Task)),
51
+ ],
52
+ lifespan=lifespan,
53
+ )
@@ -165,6 +165,7 @@ class MigrationManager:
165
165
  raw_backwards: t.List[t.Union[t.Callable, AsyncFunction]] = field(
166
166
  default_factory=list
167
167
  )
168
+ fake: bool = False
168
169
 
169
170
  def add_table(
170
171
  self,
@@ -72,18 +72,19 @@ class ForwardsMigrationManager(BaseMigrationManager):
72
72
  print(f"🚀 Running {n} migration{'s' if n != 1 else ''}:")
73
73
 
74
74
  for _id in subset:
75
- if self.fake:
76
- print(f"- {_id}: faked! ⏭️")
77
- else:
78
- migration_module = migration_modules[_id]
79
- response = await migration_module.forwards()
75
+ migration_module = migration_modules[_id]
76
+ response = await migration_module.forwards()
80
77
 
81
- if isinstance(response, MigrationManager):
78
+ if isinstance(response, MigrationManager):
79
+ if self.fake or response.fake:
80
+ print(f"- {_id}: faked! ⏭️")
81
+ else:
82
82
  if self.preview:
83
83
  response.preview = True
84
84
  await response.run()
85
85
 
86
- print("ok! ✔️")
86
+ print("ok! ✔️")
87
+
87
88
  if not self.preview:
88
89
  await Migration.insert().add(
89
90
  Migration(name=_id, app_name=app_config.app_name)
@@ -19,6 +19,7 @@ from piccolo.columns import (
19
19
  Interval,
20
20
  Numeric,
21
21
  Serial,
22
+ Text,
22
23
  Timestamp,
23
24
  Varchar,
24
25
  )
@@ -55,6 +56,12 @@ class Band(Table):
55
56
  )
56
57
 
57
58
 
59
+ class FanClub(Table):
60
+ id: Serial
61
+ address = Text()
62
+ band = ForeignKey(Band, unique=True)
63
+
64
+
58
65
  class Venue(Table):
59
66
  id: Serial
60
67
  name = Varchar(length=100)
@@ -154,6 +161,7 @@ class Album(Table):
154
161
  TABLES = (
155
162
  Manager,
156
163
  Band,
164
+ FanClub,
157
165
  Venue,
158
166
  Concert,
159
167
  Ticket,
@@ -185,6 +193,9 @@ def populate():
185
193
  pythonistas = Band(name="Pythonistas", manager=guido.id, popularity=1000)
186
194
  pythonistas.save().run_sync()
187
195
 
196
+ fan_club = FanClub(address="1 Flying Circus, UK", band=pythonistas)
197
+ fan_club.save().run_sync()
198
+
188
199
  graydon = Manager(name="Graydon")
189
200
  graydon.save().run_sync()
190
201
 
@@ -2016,6 +2016,61 @@ class ForeignKey(Column, t.Generic[ReferencedTable]):
2016
2016
  if column._meta.name not in excluded_column_names
2017
2017
  ]
2018
2018
 
2019
+ def reverse(self) -> ForeignKey:
2020
+ """
2021
+ If there's a unique foreign key, this function reverses it.
2022
+
2023
+ .. code-block:: python
2024
+
2025
+ class Band(Table):
2026
+ name = Varchar()
2027
+
2028
+ class FanClub(Table):
2029
+ band = ForeignKey(Band, unique=True)
2030
+ address = Text()
2031
+
2032
+ class Treasurer(Table):
2033
+ fan_club = ForeignKey(FanClub, unique=True)
2034
+ name = Varchar()
2035
+
2036
+ It's helpful with ``get_related``, for example:
2037
+
2038
+ .. code-block:: python
2039
+
2040
+ >>> band = await Band.objects().first()
2041
+ >>> await band.get_related(FanClub.band.reverse())
2042
+ <Fan Club: 1>
2043
+
2044
+ It works multiple levels deep:
2045
+
2046
+ .. code-block:: python
2047
+
2048
+ >>> await band.get_related(Treasurer.fan_club._.band.reverse())
2049
+ <Treasurer: 1>
2050
+
2051
+ """
2052
+ if not self._meta.unique or any(
2053
+ not i._meta.unique for i in self._meta.call_chain
2054
+ ):
2055
+ raise ValueError("Only reverse unique foreign keys.")
2056
+
2057
+ foreign_keys = [*self._meta.call_chain, self]
2058
+
2059
+ root_foreign_key = foreign_keys[0]
2060
+ target_column = (
2061
+ root_foreign_key._foreign_key_meta.resolved_target_column
2062
+ )
2063
+ foreign_key = target_column.join_on(root_foreign_key)
2064
+
2065
+ call_chain = []
2066
+ for fk in reversed(foreign_keys[1:]):
2067
+ target_column = fk._foreign_key_meta.resolved_target_column
2068
+ call_chain.append(target_column.join_on(fk))
2069
+
2070
+ foreign_key._meta.call_chain = call_chain
2071
+
2072
+ return foreign_key
2073
+
2019
2074
  def all_related(
2020
2075
  self, exclude: t.Optional[t.List[t.Union[ForeignKey, str]]] = None
2021
2076
  ) -> t.List[ForeignKey]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: piccolo
3
- Version: 1.11.0
3
+ Version: 1.12.0
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
@@ -25,28 +25,28 @@ Requires-Python: >=3.8.0
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
27
  Requires-Dist: black
28
- Requires-Dist: colorama (>=0.4.0)
29
- Requires-Dist: Jinja2 (>=2.11.0)
30
- Requires-Dist: targ (>=0.3.7)
31
- Requires-Dist: inflection (>=0.5.1)
32
- Requires-Dist: typing-extensions (>=4.3.0)
33
- Requires-Dist: pydantic[email] (==2.*)
28
+ Requires-Dist: colorama >=0.4.0
29
+ Requires-Dist: Jinja2 >=2.11.0
30
+ Requires-Dist: targ >=0.3.7
31
+ Requires-Dist: inflection >=0.5.1
32
+ Requires-Dist: typing-extensions >=4.3.0
33
+ Requires-Dist: pydantic[email] ==2.*
34
34
  Provides-Extra: all
35
- Requires-Dist: orjson (>=3.5.1) ; extra == 'all'
35
+ Requires-Dist: orjson >=3.5.1 ; extra == 'all'
36
36
  Requires-Dist: ipython ; extra == 'all'
37
- Requires-Dist: asyncpg (>=0.21.0) ; extra == 'all'
38
- Requires-Dist: aiosqlite (>=0.16.0) ; extra == 'all'
39
- Requires-Dist: uvloop (>=0.12.0) ; (sys_platform != "win32") and extra == 'all'
37
+ Requires-Dist: asyncpg >=0.21.0 ; extra == 'all'
38
+ Requires-Dist: aiosqlite >=0.16.0 ; extra == 'all'
39
+ Requires-Dist: uvloop >=0.12.0 ; (sys_platform != "win32") and extra == 'all'
40
40
  Provides-Extra: orjson
41
- Requires-Dist: orjson (>=3.5.1) ; extra == 'orjson'
41
+ Requires-Dist: orjson >=3.5.1 ; extra == 'orjson'
42
42
  Provides-Extra: playground
43
43
  Requires-Dist: ipython ; extra == 'playground'
44
44
  Provides-Extra: postgres
45
- Requires-Dist: asyncpg (>=0.21.0) ; extra == 'postgres'
45
+ Requires-Dist: asyncpg >=0.21.0 ; extra == 'postgres'
46
46
  Provides-Extra: sqlite
47
- Requires-Dist: aiosqlite (>=0.16.0) ; extra == 'sqlite'
47
+ Requires-Dist: aiosqlite >=0.16.0 ; extra == 'sqlite'
48
48
  Provides-Extra: uvloop
49
- Requires-Dist: uvloop (>=0.12.0) ; (sys_platform != "win32") and extra == 'uvloop'
49
+ Requires-Dist: uvloop >=0.12.0 ; (sys_platform != "win32") and extra == 'uvloop'
50
50
 
51
51
  ![Logo](https://raw.githubusercontent.com/piccolo-orm/piccolo/master/docs/logo_hero.png "Piccolo Logo")
52
52
 
@@ -1,4 +1,4 @@
1
- piccolo/__init__.py,sha256=-4wiKExnJa5IxSz9dOFdTv99ibuBl-uX3D-HM6f-_V8,23
1
+ piccolo/__init__.py,sha256=VUvL_fuJC_-uD36JTR5DMXk6zqaYLgxYWHSlIeRP_aQ,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
@@ -21,10 +21,10 @@ piccolo/apps/asgi/commands/new.py,sha256=ZyYgwpBXb0t-0KQraeja6Y9ANjGEdZCXpu9bmm7
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
24
- piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja,sha256=cCmRVAN8gw6zfHBcLI_NxapwN7LGM5QSXM7K94imDh8,2436
24
+ piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja,sha256=mKnYfUOnYyWJA1jFoRLCUOGQlK6imaxx_1qaauGjeeQ,2627
25
25
  piccolo/apps/asgi/commands/templates/app/_lilya_app.py.jinja,sha256=8rV1p-POGHkFIqvHvlE5wWwWPZweuSnMJhwreLMgLo8,1259
26
26
  piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja,sha256=oMH5KXoEYhf9qgXNj2Kepc6prps1MQECufdUduaiwe4,2815
27
- piccolo/apps/asgi/commands/templates/app/_starlette_app.py.jinja,sha256=YvNUlJuTd4mj-pm3WQKbQq3w3x3VfDb_Wz6aQLUsORo,1271
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
30
  piccolo/apps/asgi/commands/templates/app/main.py.jinja,sha256=azwXyWZGkrIbZv5bZF_4Tvbly7AXkw5yFWGCHYImGeo,421
@@ -60,7 +60,7 @@ piccolo/apps/migrations/piccolo_app.py,sha256=1EcS2ComBPCaMCC2C3WaPR_GqLwt3XiIJN
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
62
  piccolo/apps/migrations/auto/diffable_table.py,sha256=FJ_D7FvL_vaThgIY-zFyW_kFmReOI12saM3DFcaAvfw,7058
63
- piccolo/apps/migrations/auto/migration_manager.py,sha256=3RuQPjnBfAfETkBdDPAVAXK3Bx-GW-37WL7uYNJ_sxI,35127
63
+ piccolo/apps/migrations/auto/migration_manager.py,sha256=kzkIbC9Ow2VoxI5uMcCDG-qVZbTHBtluvdawp-tIi20,35150
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
@@ -71,13 +71,13 @@ piccolo/apps/migrations/commands/backwards.py,sha256=sBLotsdbwX11dji4H7YWgbaonlu
71
71
  piccolo/apps/migrations/commands/base.py,sha256=iuF5-PppAVt6eOo0EOtISKuVGsfR3VVcyXCzRYNOcj4,4484
72
72
  piccolo/apps/migrations/commands/check.py,sha256=JbzKAR_SFEs5dYvW0J_X4jgIpJDAHLIRz364JIZT6eQ,3991
73
73
  piccolo/apps/migrations/commands/clean.py,sha256=JYs9VwvGN45tXM2iiaqGj3UQFZhJETrWahT0tcpGvBk,2864
74
- piccolo/apps/migrations/commands/forwards.py,sha256=Xb_QqkGH3RNaJ256jjLBH8TSykNsnblSw4OPANzmXVA,5413
74
+ piccolo/apps/migrations/commands/forwards.py,sha256=03zGZIG4csf5jFrvl3dos6u0AmNTUkh4q0bf9Zt1Yz8,5427
75
75
  piccolo/apps/migrations/commands/new.py,sha256=k1cXGeydfrr3_kscwtahv7QdJW_DtTlUNHk7WW4Kfr8,7924
76
76
  piccolo/apps/migrations/commands/templates/migration.py.jinja,sha256=wMC8RTIcQj3mjZh3FhuxuIfsqftZ5ivraO9fg-H6fbI,681
77
77
  piccolo/apps/playground/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  piccolo/apps/playground/piccolo_app.py,sha256=zs6nGxt-lgUF8nEwI0uDTNZDKQqjZaNDH8le5RqrMNE,222
79
79
  piccolo/apps/playground/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
- piccolo/apps/playground/commands/run.py,sha256=RhuxsnQj8m7iE2ww_de7Jz-dT25gbqMdx1MWeHQ2mCg,8401
80
+ piccolo/apps/playground/commands/run.py,sha256=S8osLV4s_mWdvvVYGn-49wel-d1SFRB17fO3ZtMcv8Y,8629
81
81
  piccolo/apps/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
82
  piccolo/apps/project/piccolo_app.py,sha256=mT3O0m3QcCfS0oOr3jt0QZ9TX6gUavGPjJeNn2C_fdM,220
83
83
  piccolo/apps/project/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -117,7 +117,7 @@ piccolo/apps/user/piccolo_migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
117
117
  piccolo/columns/__init__.py,sha256=OYhO_n9anMiU9nL-K6ATq9FhAtm8RyMpqYQ7fTVbhxI,1120
118
118
  piccolo/columns/base.py,sha256=sgMiBvq-xLW6_W86g6XZTMc_3cskyeoMF6yIvIlnXsA,32487
119
119
  piccolo/columns/choices.py,sha256=-HNQuk9vMmVZIPZ5PMeXGTfr23o4nzKPSAkvcG1k0y8,723
120
- piccolo/columns/column_types.py,sha256=gwd93EWIULo5pGcuo7wHZdwvFEfFwtBy660pDBVqixw,81921
120
+ piccolo/columns/column_types.py,sha256=82JmKDrZ0bh1Jal0HOeu-Q9HzZaWs4liUoyJa9OoJFQ,83533
121
121
  piccolo/columns/combination.py,sha256=vMXC2dfY7pvnCFhsT71XFVyb4gdQzfRsCMaiduu04Ss,6900
122
122
  piccolo/columns/indexes.py,sha256=NfNok3v_791jgDlN28KmhP9ZCjl6031BXmjxV3ovXJk,372
123
123
  piccolo/columns/m2m.py,sha256=17NY0wU7ta2rUTHYUkeA2HQhTDlJ_lyv9FxqvJiiUbY,14602
@@ -221,7 +221,7 @@ tests/apps/migrations/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
221
221
  tests/apps/migrations/commands/test_base.py,sha256=NgHgVjNd3Hil9eODvW7Ic2D9muTa_grNaH3YpRFfR8I,1829
222
222
  tests/apps/migrations/commands/test_check.py,sha256=hOX_sVk1nfCRfbQ8tJoFEUBFhih9O4QuQLHTp5TQaiY,630
223
223
  tests/apps/migrations/commands/test_clean.py,sha256=lPzLLXhoUyyffY3EQIiyRj-QfP07UVNTha21cEZivfY,1124
224
- tests/apps/migrations/commands/test_forwards_backwards.py,sha256=-rwQ3r61eq6lfoMdM-fajK09SAftPn5cri_gSkF2lMk,7107
224
+ tests/apps/migrations/commands/test_forwards_backwards.py,sha256=VklO8Af6F_ASYWFmSS829ls-mKdwBgdeGG_FFIaYtng,8133
225
225
  tests/apps/migrations/commands/test_new.py,sha256=dKXOuU6t_6zziHHLvX_JdM_Oiee2Lc7FEuADZsMlNQA,4249
226
226
  tests/apps/migrations/commands/test_migrations/2020-03-31T20-38-22.py,sha256=9pYiFNDi-7TJy5TZ3MeNThttjjcUg6cEQ4J5Yv9wQQ8,601
227
227
  tests/apps/migrations/commands/test_migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -244,33 +244,33 @@ tests/apps/user/commands/test_change_permissions.py,sha256=uVKEiT1EKot3VA2TDETdQ
244
244
  tests/apps/user/commands/test_create.py,sha256=iJ3Tti62rHwvdcTwNXrc5JPam6vR1qxKRdMN456vm3o,2250
245
245
  tests/apps/user/commands/test_list.py,sha256=ipPfGdW6fH7q-Jc7JcYUvlioGmH9GQU0WImZGC2m-XQ,2840
246
246
  tests/columns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
247
- tests/columns/test_array.py,sha256=sHYL2hEMwinoGz2u72Db9P3GxNuuH3oPUwzzKWmzX9s,11691
247
+ tests/columns/test_array.py,sha256=QixxML6vRq-PUliqbZSKd_LE5T4fEj5nq5e1NpOhng0,11590
248
248
  tests/columns/test_base.py,sha256=CTqCNcrqAJTjLXe3MCZgTczrmB3jcVRcOpU4FilpLoQ,3918
249
- tests/columns/test_bigint.py,sha256=a0B4y1H02ww5qaW574X2lyenbY6o29ztOhiaqybPC0c,1149
250
- tests/columns/test_boolean.py,sha256=kDESp6FnRtSZhuqIu0dBRwKMSpS5TFbbs3sz2MyZSs8,1720
251
- tests/columns/test_bytea.py,sha256=ji-_GuvpOO4FKjKbhNsxuZTDprjO3y5Oo2BkwxHiTVI,1596
252
- tests/columns/test_choices.py,sha256=5fi5cqiQDbErR3-1JaI_UrUhf6QpdMUO3dhKk1_cfyw,4269
249
+ tests/columns/test_bigint.py,sha256=KqIw6UP3vGs3cyL1I1An8RfXMmjZvfSIuKYhgkqX5zI,1021
250
+ tests/columns/test_boolean.py,sha256=dFqyUnzXU8JSflI511Vt3Gxk62lpIVgH37vnDEz0E2M,1611
251
+ tests/columns/test_bytea.py,sha256=-XCXTKboPSfowhU7nceRnkhVCJ60Kus52b3f67xAlAo,1367
252
+ tests/columns/test_choices.py,sha256=xDWgcguCH4pu8w3JpIcSyurpghPsbc4OQmzjup2iTIw,4029
253
253
  tests/columns/test_combination.py,sha256=BuBwR7k5X1EkOWraZpjqU6gvtb6ow_k-7N1KQBiW2RA,1681
254
- tests/columns/test_date.py,sha256=lz3AF64CkQzulfniGs0fxuvbH2grR3pF2sxipXiyvHU,1243
254
+ tests/columns/test_date.py,sha256=WnwtCS81mYsDpwDrMnZRDjHA7ag-bxMPundRxtTlv1A,1015
255
255
  tests/columns/test_db_column_name.py,sha256=v0QFOQp_atqzMB1n40simVwHeBDi5nyN1N2bSPX5k6w,7670
256
256
  tests/columns/test_defaults.py,sha256=rwlU1fXt3cCl7C51eLlZXqgWkE-K5W0pHvTrwkAKyCo,2896
257
- tests/columns/test_double_precision.py,sha256=CuobfnQnuwqAIuuOPoh2mKHnY9A7gZosoMIGpY-ubfE,639
257
+ tests/columns/test_double_precision.py,sha256=Nx1vgmQqwn1PgBC6KcPO9yHKe9v8lCQXrEA1GcUJIn4,529
258
258
  tests/columns/test_get_sql_value.py,sha256=mKgsInN374jzV99y9mg_ZiG-AvnJgz36SZi89xL7RZM,1768
259
- tests/columns/test_interval.py,sha256=SbeRgTBWPBL5_LYQUdaP3qyN6eTNtTJtu8JXWollhQw,2993
260
- tests/columns/test_json.py,sha256=ErGytVqMVO86YiqGmQIcqb2zUcAUY_ya-cY9tSKKXhQ,3920
261
- tests/columns/test_jsonb.py,sha256=7MeH0h2SJt_uCUL6D5-6DLTBPlaz6qKSJcnyhuwvzHg,6914
262
- tests/columns/test_numeric.py,sha256=ukh7rW3uAOQmLV9m36uyHcwC9te1SLKwUrh4KDXIEbc,845
263
- tests/columns/test_primary_key.py,sha256=6kKYs5qxIe0dJ7FQIFa-7c4LAsPQtiZbBviUiVoaTd0,5572
264
- tests/columns/test_readable.py,sha256=kMuge5X_PfVeE1PjStwEHY-W0zwrxVBXV0CiW2Gw7kE,802
265
- tests/columns/test_real.py,sha256=iM49DhFS2HaDX88NgelJumT-FPqqnVP84Z2m_KfnnQQ,606
259
+ tests/columns/test_interval.py,sha256=R3fyC7IX35neiu64XR7KX58ylpPzeU2zSEbaKdbW4I4,2765
260
+ tests/columns/test_json.py,sha256=nbNXo0CISU8w3CjIF7nxBmRfEdenGFmc0o9YfhMvpKg,3467
261
+ tests/columns/test_jsonb.py,sha256=Np3FZf3AspTGRWCCMrTYEsw6uTJPI8u3SZkOvH5ERRg,6690
262
+ tests/columns/test_numeric.py,sha256=WrilQrWc-_g8DGLUvmllSBL01xqYqDORt3ypplnRizA,736
263
+ tests/columns/test_primary_key.py,sha256=hXnTF-kFgrFNjawvJstmR3YQCM59qJ4NWkMD9vRY8FI,4871
264
+ tests/columns/test_readable.py,sha256=OFK2n_k-eqRLdjEg1X2aOFPNwhtGDPNBli4DAh3i6vw,743
265
+ tests/columns/test_real.py,sha256=bSjACkbnJzrN9dEWVb0UdWqSDfxdGz5HMWc8PUsJUl4,496
266
266
  tests/columns/test_reference.py,sha256=I_gjICtJ7bE2cBrmCv-kz25AvI922A3pizRVIhHpzSE,1508
267
- tests/columns/test_reserved_column_names.py,sha256=NxkrZevxb1GV2fYoWKUVPscCBP39qgpiTyqfBxc8wag,1514
268
- tests/columns/test_smallint.py,sha256=5pknplEbg6o03xJyrcYBRuV5qarOp3TAfR3OKobiaqw,1115
269
- tests/columns/test_time.py,sha256=PfN-1x0eIPu2ULljbhIVJdyrcGXLOUQww_NOSHZXdZI,1810
270
- tests/columns/test_timestamp.py,sha256=3f6-cKTZYWMJK-eLl4z-4eR6ODdAhED2Y6keoXtwQbc,1899
271
- tests/columns/test_timestamptz.py,sha256=CLVoya-2cA8WQWD6DyBI1jhq5iXlF0hwbOT8kmRU1UU,2843
272
- tests/columns/test_uuid.py,sha256=HDh_qvznN7nUjCaJ-TJwRcPjMTYMLhrO_oOHtW9MAAc,466
273
- tests/columns/test_varchar.py,sha256=5IY9J5m1Hmuq1vZ78aApwPYI7J-XZFVtZVHPhlKGn8Y,813
267
+ tests/columns/test_reserved_column_names.py,sha256=BpqN49n_AaiPjaaJ43hLhFXQHb8NV6ig8nvgKvN0Smc,1404
268
+ tests/columns/test_smallint.py,sha256=t-LNX7XXy-k5_lhGXwELyC0LB9Iq4WrBVQdvEYf5EaQ,984
269
+ tests/columns/test_time.py,sha256=qyG4jjSO_B2DfkjQo3nIff2T201c75EI7M6CYspK5QM,1560
270
+ tests/columns/test_timestamp.py,sha256=lkb1pQW41kQ_c7zLjPfls7EgnIMnvG9AK3ePb5izJU0,1671
271
+ tests/columns/test_timestamptz.py,sha256=Py27sx45-xQElhuLVxNtZjBxz3t6VJUbyUGW3H4W7eU,2615
272
+ tests/columns/test_uuid.py,sha256=ifCyIrO6usYO33WM0FgwuPPhYzs4zVKD3MViIT61J7c,357
273
+ tests/columns/test_varchar.py,sha256=Oyt8t7msCfIiZdU9B23zjlV6atFv4sX3iMSDJc565Oc,681
274
274
  tests/columns/m2m/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
275
275
  tests/columns/m2m/base.py,sha256=uH92ECQuY5AjpQXPySwrlruZPZzB4LH2V2FUSXmHRLQ,14563
276
276
  tests/columns/m2m/test_m2m.py,sha256=LtNsHQ8xAzBFLiZVZhWEB56zu25FnaWtzJ62FZH3heI,12647
@@ -303,10 +303,10 @@ tests/query/test_gather.py,sha256=okWANrBoh0Ut1RomWoffiWNpFqiITF6qti-Aa3uYtRk,73
303
303
  tests/query/test_querystring.py,sha256=QrqyjwUlFlf5LrsJ7DgjCruq811I0UvrDFPud6rfZNI,5019
304
304
  tests/query/test_slots.py,sha256=I9ZjAYqAJNSFAWg9UyAqy7bm-Z52KiyQ2C_yHk2qqqI,1010
305
305
  tests/query/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
306
- tests/query/functions/base.py,sha256=RLCzLT7iN_Z5DtIFZqVESTJGES2JKb8VDU25sv5OtN4,811
307
- tests/query/functions/test_datetime.py,sha256=8GG5ERLq6GM8NqA3J6mycNPfCUMOEICGccyZifiwEqw,2987
306
+ tests/query/functions/base.py,sha256=sCIolQlvOMlnrLJJBAfJV-Tg8dCzkGnCs83JqRQpKkk,500
307
+ tests/query/functions/test_datetime.py,sha256=247Vpbyuq0s-SU-883t6W5ghF8xiz44LzdHd2nJ0mZ4,2963
308
308
  tests/query/functions/test_functions.py,sha256=510fqRrOrAZ9NyFoZtlF6lIdiiLriWhZ7vvveWZ8rsc,1984
309
- tests/query/functions/test_math.py,sha256=Qw2MXqgY_y7vGd0bLtPhWW7HB3tJkot1o-Rh9nCmmBk,1273
309
+ tests/query/functions/test_math.py,sha256=nrHrThxurZIvbqlN4mjfxtKqLdBxOrWoeIZ_QCRJuTs,1271
310
310
  tests/query/functions/test_string.py,sha256=RMojkBUzw1Ikrb3nTa7VjJ4FsKfrjpuHUyxQDA-F5Cs,1800
311
311
  tests/query/functions/test_type_conversion.py,sha256=WeYR9UfJnbidle07-akQ1g9hFCd93qT8xUhDF3c58n4,3235
312
312
  tests/query/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -365,9 +365,9 @@ tests/utils/test_sql_values.py,sha256=vzxRmy16FfLZPH-sAQexBvsF9MXB8n4smr14qoEOS5
365
365
  tests/utils/test_sync.py,sha256=9ytVo56y2vPQePvTeIi9lHIouEhWJbodl1TmzkGFrSo,799
366
366
  tests/utils/test_table_reflection.py,sha256=SIzuat-IpcVj1GCFyOWKShI8YkhdOPPFH7qVrvfyPNE,3794
367
367
  tests/utils/test_warnings.py,sha256=NvSC_cvJ6uZcwAGf1m-hLzETXCqprXELL8zg3TNLVMw,269
368
- piccolo-1.11.0.dist-info/LICENSE,sha256=zFIpi-16uIJ420UMIG75NU0JbDBykvrdnXcj5U_EYBI,1059
369
- piccolo-1.11.0.dist-info/METADATA,sha256=th4damYz6EsRNzUVjj7Rkn5Eu3jv1LDiCHAHV-N_piE,5178
370
- piccolo-1.11.0.dist-info/WHEEL,sha256=00yskusixUoUt5ob_CiUp6LsnN5lqzTJpoqOFg_FVIc,92
371
- piccolo-1.11.0.dist-info/entry_points.txt,sha256=SJPHET4Fi1bN5F3WqcKkv9SClK3_F1I7m4eQjk6AFh0,46
372
- piccolo-1.11.0.dist-info/top_level.txt,sha256=-SR74VGbk43VoPy1HH-mHm97yoGukLK87HE5kdBW6qM,24
373
- piccolo-1.11.0.dist-info/RECORD,,
368
+ piccolo-1.12.0.dist-info/LICENSE,sha256=zFIpi-16uIJ420UMIG75NU0JbDBykvrdnXcj5U_EYBI,1059
369
+ piccolo-1.12.0.dist-info/METADATA,sha256=255a7LoWzwC58EKwF0kgMAONG47eqD5AuHdwt8rtEUs,5150
370
+ piccolo-1.12.0.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
371
+ piccolo-1.12.0.dist-info/entry_points.txt,sha256=SJPHET4Fi1bN5F3WqcKkv9SClK3_F1I7m4eQjk6AFh0,46
372
+ piccolo-1.12.0.dist-info/top_level.txt,sha256=-SR74VGbk43VoPy1HH-mHm97yoGukLK87HE5kdBW6qM,24
373
+ piccolo-1.12.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.1)
2
+ Generator: setuptools (70.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -192,7 +192,7 @@ class TestForwardsBackwards(TestCase):
192
192
  @engines_only("postgres")
193
193
  def test_forwards_fake(self):
194
194
  """
195
- Test running the migrations if they've already run.
195
+ Make sure migrations can be faked on the command line.
196
196
  """
197
197
  run_sync(forwards(app_name="music", migration_id="all", fake=True))
198
198
 
@@ -214,9 +214,40 @@ class TestForwardsBackwards(TestCase):
214
214
  "2021-09-06T13:58:23:024723",
215
215
  "2021-11-13T14:01:46:114725",
216
216
  "2024-05-28T23:15:41:018844",
217
+ "2024-06-19T18:11:05:793132",
217
218
  ],
218
219
  )
219
220
 
221
+ @engines_only("postgres")
222
+ @patch("piccolo.apps.migrations.commands.forwards.print")
223
+ def test_hardcoded_fake_migrations(self, print_: MagicMock):
224
+ """
225
+ Make sure that migrations that have been hardcoded as fake aren't
226
+ executed, even without the ``--fake`` command line flag.
227
+
228
+ See tests/example_apps/music/piccolo_migrations/music_2024_06_19t18_11_05_793132.py
229
+
230
+ """ # noqa: E501
231
+ run_sync(forwards(app_name="music", migration_id="all"))
232
+
233
+ # The migration which is hardcoded as fake:
234
+ migration_name = "2024-06-19T18:11:05:793132"
235
+
236
+ self.assertTrue(
237
+ Migration.exists()
238
+ .where(Migration.name == migration_name)
239
+ .run_sync()
240
+ )
241
+
242
+ self.assertNotIn(
243
+ call("Running fake migration"),
244
+ print_.mock_calls,
245
+ )
246
+ self.assertIn(
247
+ call(f"- {migration_name}: faked! ⏭️"),
248
+ print_.mock_calls,
249
+ )
250
+
220
251
  def tearDown(self):
221
252
  for table_class in TABLE_CLASSES + [Migration]:
222
253
  table_class.alter().drop_table(
@@ -14,7 +14,7 @@ from piccolo.columns.column_types import (
14
14
  )
15
15
  from piccolo.querystring import QueryString
16
16
  from piccolo.table import Table
17
- from tests.base import engines_only, engines_skip, sqlite_only
17
+ from tests.base import TableTest, engines_only, engines_skip, sqlite_only
18
18
 
19
19
 
20
20
  class MyTable(Table):
@@ -32,16 +32,12 @@ class TestArrayDefault(TestCase):
32
32
  self.assertTrue(column.default is list)
33
33
 
34
34
 
35
- class TestArray(TestCase):
35
+ class TestArray(TableTest):
36
36
  """
37
37
  Make sure an Array column can be created, and works correctly.
38
38
  """
39
39
 
40
- def setUp(self):
41
- MyTable.create_table().run_sync()
42
-
43
- def tearDown(self):
44
- MyTable.alter().drop_table().run_sync()
40
+ tables = [MyTable]
45
41
 
46
42
  @pytest.mark.cockroach_array_slow
47
43
  def test_storage(self):
@@ -1,10 +1,8 @@
1
1
  import os
2
- from unittest import TestCase
3
2
 
4
3
  from piccolo.columns.column_types import BigInt
5
4
  from piccolo.table import Table
6
-
7
- from ..base import engines_only
5
+ from tests.base import TableTest, engines_only
8
6
 
9
7
 
10
8
  class MyTable(Table):
@@ -12,16 +10,12 @@ class MyTable(Table):
12
10
 
13
11
 
14
12
  @engines_only("postgres", "cockroach")
15
- class TestBigIntPostgres(TestCase):
13
+ class TestBigIntPostgres(TableTest):
16
14
  """
17
15
  Make sure a BigInt column in Postgres can store a large number.
18
16
  """
19
17
 
20
- def setUp(self):
21
- MyTable.create_table().run_sync()
22
-
23
- def tearDown(self):
24
- MyTable.alter().drop_table().run_sync()
18
+ tables = [MyTable]
25
19
 
26
20
  def _test_length(self):
27
21
  # Can store 8 bytes, but split between positive and negative values.