TypeDAL 3.4.0__py3-none-any.whl → 3.6.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.

Potentially problematic release.


This version of TypeDAL might be problematic. Click here for more details.

typedal/__about__.py CHANGED
@@ -5,4 +5,4 @@ This file contains the Version info for this package.
5
5
  # SPDX-FileCopyrightText: 2023-present Robin van der Noord <robinvandernoord@gmail.com>
6
6
  #
7
7
  # SPDX-License-Identifier: MIT
8
- __version__ = "3.4.0"
8
+ __version__ = "3.6.0"
typedal/cli.py CHANGED
@@ -40,7 +40,7 @@ from pydal2sql.types import (
40
40
  OutputFormat_Option,
41
41
  Tables_Option,
42
42
  )
43
- from pydal2sql_core import core_alter, core_create
43
+ from pydal2sql_core import core_alter, core_create, core_stub
44
44
  from typing_extensions import Never
45
45
 
46
46
  from . import caching
@@ -122,7 +122,7 @@ def get_question(prop: str, annotation: typing.Type[T], default: T | None) -> Op
122
122
  question["message"] = question.get("message", f"{prop}? ")
123
123
  default = typing.cast(T, default or question.get("default") or "")
124
124
 
125
- if annotation == int:
125
+ if annotation is int:
126
126
  default = typing.cast(T, str(default))
127
127
 
128
128
  response = questionary.unsafe_prompt([question], default=default)[prop]
@@ -197,9 +197,9 @@ def setup(
197
197
  if isinstance(answer, str):
198
198
  answer = answer.strip()
199
199
 
200
- if annotation == bool:
200
+ if annotation is bool:
201
201
  answer = bool(answer)
202
- elif annotation == int:
202
+ elif annotation is int:
203
203
  answer = int(answer)
204
204
 
205
205
  config.update(**{prop: answer})
@@ -417,6 +417,38 @@ def fake_migrations(
417
417
  return 0
418
418
 
419
419
 
420
+ @app.command(name="migrations.stub")
421
+ @with_exit_code(hide_tb=IS_DEBUG)
422
+ def migrations_stub(
423
+ migration_name: typing.Annotated[str, typer.Argument()] = "stub_migration",
424
+ connection: typing.Annotated[str, typer.Option("--connection", "-c")] = None,
425
+ output_format: OutputFormat_Option = None,
426
+ output_file: Optional[str] = None,
427
+ dry_run: typing.Annotated[bool, typer.Option("--dry", "--dry-run")] = False,
428
+ is_pydal: typing.Annotated[bool, typer.Option("--pydal", "-p")] = False,
429
+ # defaults to is_typedal of course
430
+ ) -> int:
431
+ """
432
+ Create an empty migration via pydal2sql.
433
+ """
434
+ generic_config = load_config(connection)
435
+ pydal2sql_config = generic_config.to_pydal2sql()
436
+ pydal2sql_config.update(
437
+ format=output_format,
438
+ output=output_file,
439
+ _skip_none=True,
440
+ )
441
+
442
+ core_stub(
443
+ migration_name, # raw, without date or number
444
+ output_format=pydal2sql_config.format,
445
+ output_file=pydal2sql_config.output or None,
446
+ dry_run=dry_run,
447
+ is_typedal=not is_pydal,
448
+ )
449
+ return 0
450
+
451
+
420
452
  AnyNestedDict: typing.TypeAlias = dict[str, AnyDict]
421
453
 
422
454
 
typedal/core.py CHANGED
@@ -43,22 +43,19 @@ from .helpers import (
43
43
  )
44
44
  from .serializers import as_json
45
45
  from .types import (
46
- AfterDeleteCallable,
47
- AfterInsertCallable,
48
- AfterUpdateCallable,
49
46
  AnyDict,
50
- BeforeDeleteCallable,
51
- BeforeInsertCallable,
52
- BeforeUpdateCallable,
53
47
  CacheMetadata,
54
48
  Expression,
55
49
  Field,
56
50
  Metadata,
51
+ OpRow,
57
52
  PaginateDict,
58
53
  Pagination,
59
54
  Query,
55
+ Reference,
60
56
  Rows,
61
57
  SelectKwargs,
58
+ Set,
62
59
  Table,
63
60
  Validator,
64
61
  _Types,
@@ -286,7 +283,7 @@ def _generate_relationship_condition(
286
283
  origin = typing.get_origin(field)
287
284
  # else: generic
288
285
 
289
- if origin == list:
286
+ if origin is list:
290
287
  # field = typing.get_args(field)[0] # actual field
291
288
  # return lambda _self, _other: cls[key].contains(field)
292
289
 
@@ -337,7 +334,7 @@ def to_relationship(
337
334
  warnings.warn(f"Invalid relationship for {cls.__name__}.{key}: {field}")
338
335
  return None
339
336
 
340
- join = "left" if optional or typing.get_origin(field) == list else "inner"
337
+ join = "left" if optional or typing.get_origin(field) is list else "inner"
341
338
 
342
339
  return Relationship(typing.cast(type[TypedTable], field), condition, typing.cast(JOIN_OPTIONS, join))
343
340
 
@@ -1139,7 +1136,63 @@ class TableMeta(type):
1139
1136
  table = self._ensure_table_defined()
1140
1137
  return typing.cast(Type[T_MetaInstance], table.with_alias(alias))
1141
1138
 
1142
- # @typing.dataclass_transform()
1139
+ # hooks:
1140
+ def before_insert(
1141
+ cls: Type[T_MetaInstance],
1142
+ fn: typing.Callable[[T_MetaInstance], Optional[bool]] | typing.Callable[[OpRow], Optional[bool]],
1143
+ ) -> Type[T_MetaInstance]:
1144
+ """
1145
+ Add a before insert hook.
1146
+ """
1147
+ cls._before_insert.append(fn) # type: ignore
1148
+ return cls
1149
+
1150
+ def after_insert(
1151
+ cls: Type[T_MetaInstance],
1152
+ fn: (
1153
+ typing.Callable[[T_MetaInstance, Reference], Optional[bool]]
1154
+ | typing.Callable[[OpRow, Reference], Optional[bool]]
1155
+ ),
1156
+ ) -> Type[T_MetaInstance]:
1157
+ """
1158
+ Add an after insert hook.
1159
+ """
1160
+ cls._after_insert.append(fn) # type: ignore
1161
+ return cls
1162
+
1163
+ def before_update(
1164
+ cls: Type[T_MetaInstance],
1165
+ fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
1166
+ ) -> Type[T_MetaInstance]:
1167
+ """
1168
+ Add a before update hook.
1169
+ """
1170
+ cls._before_update.append(fn) # type: ignore
1171
+ return cls
1172
+
1173
+ def after_update(
1174
+ cls: Type[T_MetaInstance],
1175
+ fn: typing.Callable[[Set, T_MetaInstance], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]],
1176
+ ) -> Type[T_MetaInstance]:
1177
+ """
1178
+ Add an after update hook.
1179
+ """
1180
+ cls._after_update.append(fn) # type: ignore
1181
+ return cls
1182
+
1183
+ def before_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
1184
+ """
1185
+ Add a before delete hook.
1186
+ """
1187
+ cls._before_delete.append(fn)
1188
+ return cls
1189
+
1190
+ def after_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
1191
+ """
1192
+ Add an after delete hook.
1193
+ """
1194
+ cls._after_delete.append(fn)
1195
+ return cls
1143
1196
 
1144
1197
 
1145
1198
  class TypedField(Expression, typing.Generic[T_Value]): # pragma: no cover
@@ -1334,12 +1387,14 @@ class _TypedTable:
1334
1387
 
1335
1388
  id: "TypedField[int]"
1336
1389
 
1337
- _before_insert: list[BeforeInsertCallable]
1338
- _after_insert: list[AfterInsertCallable]
1339
- _before_update: list[BeforeUpdateCallable]
1340
- _after_update: list[AfterUpdateCallable]
1341
- _before_delete: list[BeforeDeleteCallable]
1342
- _after_delete: list[AfterDeleteCallable]
1390
+ _before_insert: list[typing.Callable[[Self], Optional[bool]] | typing.Callable[[OpRow], Optional[bool]]]
1391
+ _after_insert: list[
1392
+ typing.Callable[[Self, Reference], Optional[bool]] | typing.Callable[[OpRow, Reference], Optional[bool]]
1393
+ ]
1394
+ _before_update: list[typing.Callable[[Set, Self], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]]]
1395
+ _after_update: list[typing.Callable[[Set, Self], Optional[bool]] | typing.Callable[[Set, OpRow], Optional[bool]]]
1396
+ _before_delete: list[typing.Callable[[Set], Optional[bool]]]
1397
+ _after_delete: list[typing.Callable[[Set], Optional[bool]]]
1343
1398
 
1344
1399
  @classmethod
1345
1400
  def __on_define__(cls, db: TypeDAL) -> None:
typedal/types.py CHANGED
@@ -48,12 +48,35 @@ class Set(_Set): # type: ignore
48
48
  """
49
49
 
50
50
 
51
- class OpRow(_OpRow): # type: ignore
52
- """
53
- Pydal OpRow object.
51
+ if typing.TYPE_CHECKING:
54
52
 
55
- Make mypy happy.
56
- """
53
+ class OpRow:
54
+ """
55
+ Pydal OpRow object for typing (otherwise mypy thinks it's Any).
56
+
57
+ Make mypy happy.
58
+ """
59
+
60
+ def __getitem__(self, item: str) -> typing.Any:
61
+ """
62
+ Dict [] get notation.
63
+ """
64
+
65
+ def __setitem__(self, key: str, value: typing.Any) -> None:
66
+ """
67
+ Dict [] set notation.
68
+ """
69
+
70
+ # ... and more methods
71
+
72
+ else:
73
+
74
+ class OpRow(_OpRow): # type: ignore
75
+ """
76
+ Pydal OpRow object at runtime just uses pydal's version.
77
+
78
+ Make mypy happy.
79
+ """
57
80
 
58
81
 
59
82
  class Reference(_Reference): # type: ignore
@@ -105,14 +128,6 @@ class _Types:
105
128
  NONETYPE = type(None)
106
129
 
107
130
 
108
- BeforeInsertCallable: typing.TypeAlias = typing.Callable[[OpRow], Any]
109
- AfterInsertCallable: typing.TypeAlias = typing.Callable[[OpRow, Reference], Any]
110
- BeforeUpdateCallable: typing.TypeAlias = typing.Callable[[Set, OpRow], Any]
111
- AfterUpdateCallable: typing.TypeAlias = typing.Callable[[Set, OpRow], Any]
112
- BeforeDeleteCallable: typing.TypeAlias = typing.Callable[[Set], Any]
113
- AfterDeleteCallable: typing.TypeAlias = typing.Callable[[Set], Any]
114
-
115
-
116
131
  class Pagination(TypedDict):
117
132
  """
118
133
  Pagination key of a paginate dict has these items.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: TypeDAL
3
- Version: 3.4.0
3
+ Version: 3.6.0
4
4
  Summary: Typing support for PyDAL
5
5
  Project-URL: Documentation, https://typedal.readthedocs.io/
6
6
  Project-URL: Issues, https://github.com/trialandsuccess/TypeDAL/issues
@@ -23,7 +23,7 @@ Requires-Dist: python-slugify
23
23
  Provides-Extra: all
24
24
  Requires-Dist: edwh-migrate>=0.8.0; extra == 'all'
25
25
  Requires-Dist: py4web; extra == 'all'
26
- Requires-Dist: pydal2sql[all]>=1.1.4; extra == 'all'
26
+ Requires-Dist: pydal2sql[all]>=1.2.0; extra == 'all'
27
27
  Requires-Dist: questionary; extra == 'all'
28
28
  Requires-Dist: tabulate; extra == 'all'
29
29
  Requires-Dist: tomlkit; extra == 'all'
@@ -43,7 +43,7 @@ Requires-Dist: types-requests; extra == 'dev'
43
43
  Requires-Dist: types-tabulate; extra == 'dev'
44
44
  Provides-Extra: migrations
45
45
  Requires-Dist: edwh-migrate>=0.8.0; extra == 'migrations'
46
- Requires-Dist: pydal2sql>=1.1.4; extra == 'migrations'
46
+ Requires-Dist: pydal2sql>=1.2.0; extra == 'migrations'
47
47
  Requires-Dist: questionary; extra == 'migrations'
48
48
  Requires-Dist: tabulate; extra == 'migrations'
49
49
  Requires-Dist: tomlkit; extra == 'migrations'
@@ -1,19 +1,19 @@
1
- typedal/__about__.py,sha256=4H4aYxAonMoSZ4TwJQKsDojr3VmwSW8DHN3jahxVVsA,206
1
+ typedal/__about__.py,sha256=6BHlKIfFsDoanUXT6U-wyOOCusiaMl22UUFAVmE4Clg,206
2
2
  typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
3
3
  typedal/caching.py,sha256=SMcJsahLlZ79yykWCveERFx1ZJUNEKhA9SPmCTIuLp8,11798
4
- typedal/cli.py,sha256=BXXu1w9WRRK9GA82xh_JLvvfpNDFWICXKCAWNg4a3-Y,18180
4
+ typedal/cli.py,sha256=wzyId6YwRyqfuJ2byxvl6YecDNaKpkLmo-R5HvRuTok,19265
5
5
  typedal/config.py,sha256=0qy1zrTUdtmXPM9jHzFnSR1DJsqGJqcdG6pvhzKQHe0,11625
6
- typedal/core.py,sha256=b8pFiaORXEC0PWaBSmPkQuPtJfk0mwqUiAqxSmX4ZtM,96318
6
+ typedal/core.py,sha256=mbNFMv3NJ2QRDuohs03LCGhVVnffsxjsoe-m887U6c8,98367
7
7
  typedal/fields.py,sha256=z2PD9vLWqBR_zXtiY0DthqTG4AeF3yxKoeuVfGXnSdg,5197
8
8
  typedal/for_py4web.py,sha256=d07b8hL_PvNDUS26Z5fDH2OxWb-IETBuAFPSzrRwm04,1285
9
9
  typedal/for_web2py.py,sha256=4RHgzGXgKIO_BYB-7adC5e35u52rX-p1t4tPEz-NK24,1867
10
10
  typedal/helpers.py,sha256=KbgP4ZRW7KCroyHwTwdErPqylOX4dsqVnKJeZ5TtTFY,7363
11
11
  typedal/mixins.py,sha256=OHhVYLBGTzPSJKgp1uovBs1Y6NJa0d-DxHTOk9LyOXA,5414
12
12
  typedal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- typedal/types.py,sha256=fyTOAhORFufZsAKnf1dMcWJxLK-UMX6UFl-JbiqFmSk,5161
13
+ typedal/types.py,sha256=W2zsmJSPYbIvhjb5Df_ZANH8riCIJhOOHjI8UCQINls,5239
14
14
  typedal/web2py_py4web_shared.py,sha256=VK9T8P5UwVLvfNBsY4q79ANcABv-jX76YKADt1Zz_co,1539
15
15
  typedal/serializers/as_json.py,sha256=ffo152W-sARYXym4BzwX709rrO2-QwKk2KunWY8RNl4,2229
16
- typedal-3.4.0.dist-info/METADATA,sha256=onWL5IwfJALWrdfIPUQNYrmFdIcMNZqRAlGixK88Tv0,9462
17
- typedal-3.4.0.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
18
- typedal-3.4.0.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
19
- typedal-3.4.0.dist-info/RECORD,,
16
+ typedal-3.6.0.dist-info/METADATA,sha256=yZpPjMmR24Kzh0QRmMrTihEHGNCJFgX4NtyfOIqMf-A,9462
17
+ typedal-3.6.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
+ typedal-3.6.0.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
19
+ typedal-3.6.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.17.1
2
+ Generator: hatchling 1.25.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any