TypeDAL 3.6.0__py3-none-any.whl → 3.7.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.

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.6.0"
8
+ __version__ = "3.7.1"
typedal/core.py CHANGED
@@ -8,6 +8,7 @@ import datetime as dt
8
8
  import inspect
9
9
  import json
10
10
  import math
11
+ import sys
11
12
  import types
12
13
  import typing
13
14
  import warnings
@@ -339,6 +340,22 @@ def to_relationship(
339
340
  return Relationship(typing.cast(type[TypedTable], field), condition, typing.cast(JOIN_OPTIONS, join))
340
341
 
341
342
 
343
+ def evaluate_forward_reference(fw_ref: typing.ForwardRef) -> type:
344
+ """
345
+ Extract the original type from a forward reference string.
346
+ """
347
+ kwargs = dict(
348
+ localns=locals(),
349
+ globalns=globals(),
350
+ recursive_guard=frozenset(),
351
+ )
352
+ if sys.version_info >= (3, 13):
353
+ # required since 3.13 and not supported before
354
+ kwargs["type_params"] = ()
355
+
356
+ return fw_ref._evaluate(**kwargs) # type: ignore
357
+
358
+
342
359
  class TypeDAL(pydal.DAL): # type: ignore
343
360
  """
344
361
  Drop-in replacement for pyDAL with layer to convert class-based table definitions to classical pydal define_tables.
@@ -465,6 +482,7 @@ class TypeDAL(pydal.DAL): # type: ignore
465
482
  # when __future__.annotations is implemented, cls.__annotations__ will not work anymore as below.
466
483
  # proper way to handle this would be (but gives error right now due to Table implementing magic methods):
467
484
  # typing.get_type_hints(cls, globalns=None, localns=None)
485
+ # -> ERR e.g. `pytest -svxk cli` -> name 'BestFriend' is not defined
468
486
 
469
487
  # dirty way (with evil eval):
470
488
  # [eval(v) for k, v in cls.__annotations__.items()]
@@ -674,9 +692,8 @@ class TypeDAL(pydal.DAL): # type: ignore
674
692
 
675
693
  if isinstance(ftype, str):
676
694
  # extract type from string
677
- ftype = typing.get_args(Type[ftype])[0]._evaluate(
678
- localns=locals(), globalns=globals(), recursive_guard=frozenset()
679
- )
695
+ fw_ref: typing.ForwardRef = typing.get_args(Type[ftype])[0]
696
+ ftype = evaluate_forward_reference(fw_ref)
680
697
 
681
698
  if mapping := BASIC_MAPPINGS.get(ftype):
682
699
  # basi types
@@ -1144,7 +1161,7 @@ class TableMeta(type):
1144
1161
  """
1145
1162
  Add a before insert hook.
1146
1163
  """
1147
- cls._before_insert.append(fn) # type: ignore
1164
+ cls._before_insert.append(fn)
1148
1165
  return cls
1149
1166
 
1150
1167
  def after_insert(
@@ -1157,7 +1174,7 @@ class TableMeta(type):
1157
1174
  """
1158
1175
  Add an after insert hook.
1159
1176
  """
1160
- cls._after_insert.append(fn) # type: ignore
1177
+ cls._after_insert.append(fn)
1161
1178
  return cls
1162
1179
 
1163
1180
  def before_update(
@@ -1167,7 +1184,7 @@ class TableMeta(type):
1167
1184
  """
1168
1185
  Add a before update hook.
1169
1186
  """
1170
- cls._before_update.append(fn) # type: ignore
1187
+ cls._before_update.append(fn)
1171
1188
  return cls
1172
1189
 
1173
1190
  def after_update(
@@ -1177,7 +1194,7 @@ class TableMeta(type):
1177
1194
  """
1178
1195
  Add an after update hook.
1179
1196
  """
1180
- cls._after_update.append(fn) # type: ignore
1197
+ cls._after_update.append(fn)
1181
1198
  return cls
1182
1199
 
1183
1200
  def before_delete(cls: Type[T_MetaInstance], fn: typing.Callable[[Set], Optional[bool]]) -> Type[T_MetaInstance]:
typedal/helpers.py CHANGED
@@ -10,7 +10,12 @@ import typing
10
10
  from collections import ChainMap
11
11
  from typing import Any
12
12
 
13
- from .types import AnyDict
13
+ from pydal import DAL
14
+
15
+ from .types import AnyDict, Field, Table
16
+
17
+ if typing.TYPE_CHECKING:
18
+ from . import TypeDAL, TypedField, TypedTable # noqa: F401
14
19
 
15
20
  T = typing.TypeVar("T")
16
21
 
@@ -274,3 +279,27 @@ def utcnow() -> dt.datetime:
274
279
  """
275
280
  # return dt.datetime.now(dt.UTC)
276
281
  return dt.datetime.now(dt.timezone.utc)
282
+
283
+
284
+ def get_db(table: "TypedTable | Table") -> "DAL":
285
+ """
286
+ Get the underlying DAL instance for a pydal or typedal table.
287
+ """
288
+ return typing.cast("DAL", table._db)
289
+
290
+
291
+ def get_table(table: "TypedTable | Table") -> "Table":
292
+ """
293
+ Get the underlying pydal table for a typedal table.
294
+ """
295
+ return typing.cast("Table", table._table)
296
+
297
+
298
+ def get_field(field: "TypedField[typing.Any] | Field") -> "Field":
299
+ """
300
+ Get the underlying pydal field from a typedal field.
301
+ """
302
+ return typing.cast(
303
+ "Field",
304
+ field, # Table.field already is a Field, but cast to make sure the editor knows this too.
305
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: TypeDAL
3
- Version: 3.6.0
3
+ Version: 3.7.1
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
@@ -12,16 +12,18 @@ Classifier: Programming Language :: Python
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
15
16
  Classifier: Programming Language :: Python :: Implementation :: CPython
16
17
  Classifier: Programming Language :: Python :: Implementation :: PyPy
17
18
  Requires-Python: >=3.10
18
19
  Requires-Dist: configurable-json
19
20
  Requires-Dist: configuraptor>=1.26.2
20
21
  Requires-Dist: dill
22
+ Requires-Dist: legacy-cgi; python_version >= '3.13'
21
23
  Requires-Dist: pydal
22
24
  Requires-Dist: python-slugify
23
25
  Provides-Extra: all
24
- Requires-Dist: edwh-migrate>=0.8.0; extra == 'all'
26
+ Requires-Dist: edwh-migrate[full]>=0.8.0; extra == 'all'
25
27
  Requires-Dist: py4web; extra == 'all'
26
28
  Requires-Dist: pydal2sql[all]>=1.2.0; extra == 'all'
27
29
  Requires-Dist: questionary; extra == 'all'
@@ -301,6 +303,30 @@ row: TableName = db.table_name(id=1)
301
303
 
302
304
  See [2. Defining Tables](https://typedal.readthedocs.io/en/stable/2_defining_tables/)
303
305
 
306
+ ### Helpers
307
+
308
+ TypeDAL provides some utility functions to interact with the underlying pyDAL objects:
309
+
310
+ - **`get_db(TableName)`**:
311
+ Retrieve the DAL instance associated with a given TypedTable or pyDAL Table.
312
+
313
+ - **`get_table(TableName)`**:
314
+ Access the original PyDAL Table from a TypedTable instance (`db.table_name`).
315
+
316
+ - **`get_field(TableName.fieldname)`**:
317
+ Get the pyDAL Field from a TypedField. This ensures compatibility when interacting directly with PyDAL.
318
+
319
+ These helpers are useful for scenarios where direct access to the PyDAL objects is needed while still using TypeDAL.
320
+ An example of this is when you need to do a `db.commit()` but you can't import `db` directly:
321
+
322
+ ```python
323
+ from typedal.helpers import get_db #, get_table, get_field
324
+
325
+ MyTable.insert(...)
326
+ db = get_db(MyTable)
327
+ db.commit() # this is usually done automatically but sometimes you want to manually commit.
328
+ ```
329
+
304
330
  ## Caveats
305
331
 
306
332
  - This package depends heavily on the current implementation of annotations (which are computed when the class is
@@ -1,19 +1,19 @@
1
- typedal/__about__.py,sha256=6BHlKIfFsDoanUXT6U-wyOOCusiaMl22UUFAVmE4Clg,206
1
+ typedal/__about__.py,sha256=AFKT4KzzNxE4Z-qbuOweWNrXJbURV-eoLAHkdyWY_9I,206
2
2
  typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
3
3
  typedal/caching.py,sha256=SMcJsahLlZ79yykWCveERFx1ZJUNEKhA9SPmCTIuLp8,11798
4
4
  typedal/cli.py,sha256=wzyId6YwRyqfuJ2byxvl6YecDNaKpkLmo-R5HvRuTok,19265
5
5
  typedal/config.py,sha256=0qy1zrTUdtmXPM9jHzFnSR1DJsqGJqcdG6pvhzKQHe0,11625
6
- typedal/core.py,sha256=mbNFMv3NJ2QRDuohs03LCGhVVnffsxjsoe-m887U6c8,98367
6
+ typedal/core.py,sha256=7zIt-_AXv2E-7FRRi4J1tHzkwCIgD31faIatjMtFcqg,98804
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
- typedal/helpers.py,sha256=KbgP4ZRW7KCroyHwTwdErPqylOX4dsqVnKJeZ5TtTFY,7363
10
+ typedal/helpers.py,sha256=uej96exzJ9qVBd6LudP8uJ_7Cmq6vKraerdKvSRBVjc,8128
11
11
  typedal/mixins.py,sha256=OHhVYLBGTzPSJKgp1uovBs1Y6NJa0d-DxHTOk9LyOXA,5414
12
12
  typedal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
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.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,,
16
+ typedal-3.7.1.dist-info/METADATA,sha256=XIXYnqey6KJJxJK6PAbFhdom9aIVjEggISd3mzwVcfk,10463
17
+ typedal-3.7.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
+ typedal-3.7.1.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
19
+ typedal-3.7.1.dist-info/RECORD,,