TypeDAL 3.0.1__py3-none-any.whl → 3.1.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 +1 -1
- typedal/core.py +28 -16
- typedal/for_web2py.py +2 -0
- typedal/helpers.py +11 -2
- typedal/mixins.py +135 -0
- typedal/web2py_py4web_shared.py +2 -0
- {typedal-3.0.1.dist-info → typedal-3.1.1.dist-info}/METADATA +47 -10
- typedal-3.1.1.dist-info/RECORD +19 -0
- {typedal-3.0.1.dist-info → typedal-3.1.1.dist-info}/WHEEL +1 -1
- typedal-3.0.1.dist-info/RECORD +0 -18
- {typedal-3.0.1.dist-info → typedal-3.1.1.dist-info}/entry_points.txt +0 -0
typedal/__about__.py
CHANGED
typedal/core.py
CHANGED
|
@@ -1317,15 +1317,16 @@ class TypedField(typing.Generic[T_Value]): # pragma: no cover
|
|
|
1317
1317
|
return typing.cast(Expression, ~self._field)
|
|
1318
1318
|
|
|
1319
1319
|
|
|
1320
|
-
class
|
|
1320
|
+
class _TypedTable:
|
|
1321
1321
|
"""
|
|
1322
|
-
|
|
1323
|
-
"""
|
|
1324
|
-
|
|
1325
|
-
# set up by 'new':
|
|
1326
|
-
_row: Row | None = None
|
|
1322
|
+
This class is a final shared parent between TypedTable and Mixins.
|
|
1327
1323
|
|
|
1328
|
-
|
|
1324
|
+
This needs to exist because otherwise the __on_define__ of Mixins are not executed.
|
|
1325
|
+
Notably, this class exists at a level ABOVE the `metaclass=TableMeta`,
|
|
1326
|
+
because otherwise typing gets confused when Mixins are used and multiple types could satisfy
|
|
1327
|
+
generic 'T subclass of TypedTable'
|
|
1328
|
+
-> Setting 'TypedTable' as the parent for Mixin does not work at runtime (and works semi at type check time)
|
|
1329
|
+
"""
|
|
1329
1330
|
|
|
1330
1331
|
id: "TypedField[int]"
|
|
1331
1332
|
|
|
@@ -1336,6 +1337,26 @@ class TypedTable(metaclass=TableMeta):
|
|
|
1336
1337
|
_before_delete: list[BeforeDeleteCallable]
|
|
1337
1338
|
_after_delete: list[AfterDeleteCallable]
|
|
1338
1339
|
|
|
1340
|
+
@classmethod
|
|
1341
|
+
def __on_define__(cls, db: TypeDAL) -> None:
|
|
1342
|
+
"""
|
|
1343
|
+
Method that can be implemented by tables to do an action after db.define is completed.
|
|
1344
|
+
|
|
1345
|
+
This can be useful if you need to add something like requires=IS_NOT_IN_DB(db, "table.field"),
|
|
1346
|
+
where you need a reference to the current database, which may not exist yet when defining the model.
|
|
1347
|
+
"""
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
class TypedTable(_TypedTable, metaclass=TableMeta):
|
|
1351
|
+
"""
|
|
1352
|
+
Enhanded modeling system on top of pydal's Table that adds typing and additional functionality.
|
|
1353
|
+
"""
|
|
1354
|
+
|
|
1355
|
+
# set up by 'new':
|
|
1356
|
+
_row: Row | None = None
|
|
1357
|
+
|
|
1358
|
+
_with: list[str]
|
|
1359
|
+
|
|
1339
1360
|
def _setup_instance_methods(self) -> None:
|
|
1340
1361
|
self.as_dict = self._as_dict # type: ignore
|
|
1341
1362
|
self.__json__ = self.as_json = self._as_json # type: ignore
|
|
@@ -1382,15 +1403,6 @@ class TypedTable(metaclass=TableMeta):
|
|
|
1382
1403
|
inst._setup_instance_methods()
|
|
1383
1404
|
return inst
|
|
1384
1405
|
|
|
1385
|
-
@classmethod
|
|
1386
|
-
def __on_define__(cls, db: TypeDAL) -> None:
|
|
1387
|
-
"""
|
|
1388
|
-
Method that can be implemented by tables to do an action after db.define is completed.
|
|
1389
|
-
|
|
1390
|
-
This can be useful if you need to add something like requires=IS_NOT_IN_DB(db, "table.field"),
|
|
1391
|
-
where you need a reference to the current database, which may not exist yet when defining the model.
|
|
1392
|
-
"""
|
|
1393
|
-
|
|
1394
1406
|
def __iter__(self) -> typing.Generator[Any, None, None]:
|
|
1395
1407
|
"""
|
|
1396
1408
|
Allows looping through the columns.
|
typedal/for_web2py.py
CHANGED
typedal/helpers.py
CHANGED
|
@@ -25,19 +25,28 @@ def is_union(some_type: type | types.UnionType) -> bool:
|
|
|
25
25
|
return typing.get_origin(some_type) in (types.UnionType, typing.Union)
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def reversed_mro(cls: type) -> typing.Iterable[type]:
|
|
29
|
+
"""
|
|
30
|
+
Get the Method Resolution Order (mro) for a class, in reverse order to be used with ChainMap.
|
|
31
|
+
"""
|
|
32
|
+
return reversed(getattr(cls, "__mro__", []))
|
|
33
|
+
|
|
34
|
+
|
|
28
35
|
def _all_annotations(cls: type) -> ChainMap[str, type]:
|
|
29
36
|
"""
|
|
30
37
|
Returns a dictionary-like ChainMap that includes annotations for all \
|
|
31
38
|
attributes defined in cls or inherited from superclasses.
|
|
32
39
|
"""
|
|
33
|
-
|
|
40
|
+
# chainmap reverses the iterable, so reverse again beforehand to keep order normally:
|
|
41
|
+
|
|
42
|
+
return ChainMap(*(c.__annotations__ for c in reversed_mro(cls) if "__annotations__" in c.__dict__))
|
|
34
43
|
|
|
35
44
|
|
|
36
45
|
def all_dict(cls: type) -> AnyDict:
|
|
37
46
|
"""
|
|
38
47
|
Get the internal data of a class and all it's parents.
|
|
39
48
|
"""
|
|
40
|
-
return dict(ChainMap(*(c.__dict__ for c in
|
|
49
|
+
return dict(ChainMap(*(c.__dict__ for c in reversed_mro(cls)))) # type: ignore
|
|
41
50
|
|
|
42
51
|
|
|
43
52
|
def all_annotations(cls: type, _except: typing.Iterable[str] = None) -> dict[str, type]:
|
typedal/mixins.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file contains example Mixins.
|
|
3
|
+
|
|
4
|
+
Mixins can add reusable fields and behavior (optimally both, otherwise it doesn't add much).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import base64
|
|
8
|
+
import os
|
|
9
|
+
import typing
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from slugify import slugify
|
|
14
|
+
|
|
15
|
+
from .core import TypedTable # noqa F401 - used by example in docstring
|
|
16
|
+
from .core import TypeDAL, _TypedTable
|
|
17
|
+
from .fields import DatetimeField, StringField
|
|
18
|
+
from .types import OpRow, Set
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Mixin(_TypedTable):
|
|
22
|
+
"""
|
|
23
|
+
A mixin should be derived from this class.
|
|
24
|
+
|
|
25
|
+
The mixin base class itself doesn't do anything,
|
|
26
|
+
but using it makes sure the mixin fields are placed AFTER the table's normal fields (instead of before)
|
|
27
|
+
|
|
28
|
+
During runtime, mixin should not have a base class in order to prevent MRO issues
|
|
29
|
+
('inconsistent method resolution' or 'metaclass conflicts')
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TimestampsMixin(Mixin):
|
|
34
|
+
"""
|
|
35
|
+
A Mixin class for adding timestamp fields to a model.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
created_at = DatetimeField(default=datetime.now, writable=False)
|
|
39
|
+
updated_at = DatetimeField(default=datetime.now, writable=False)
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def __on_define__(cls, db: TypeDAL) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Hook called when defining the model to initialize timestamps.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
db (TypeDAL): The database layer.
|
|
48
|
+
"""
|
|
49
|
+
super().__on_define__(db)
|
|
50
|
+
|
|
51
|
+
def set_updated_at(_: Set, row: OpRow) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Callback function to update the 'updated_at' field before saving changes.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
_: Set: Unused parameter.
|
|
57
|
+
row (OpRow): The row to update.
|
|
58
|
+
"""
|
|
59
|
+
row["updated_at"] = datetime.now()
|
|
60
|
+
|
|
61
|
+
cls._before_update.append(set_updated_at)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def slug_random_suffix(length: int = 8) -> str:
|
|
65
|
+
"""
|
|
66
|
+
Generate a random suffix to make slugs unique, even when titles are the same.
|
|
67
|
+
|
|
68
|
+
UUID4 uses 16 bytes, but 8 is probably more than enough given you probably don't have THAT much duplicate titles.
|
|
69
|
+
Strip away '=' to make it URL-safe
|
|
70
|
+
(even though 'urlsafe_b64encode' sounds like it should already be url-safe - it is not)
|
|
71
|
+
"""
|
|
72
|
+
return base64.urlsafe_b64encode(os.urandom(length)).rstrip(b"=").decode().strip("=")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SlugMixin(Mixin):
|
|
76
|
+
"""
|
|
77
|
+
(Opinionated) example mixin to add a 'slug' field, which depends on a user-provided other field.
|
|
78
|
+
|
|
79
|
+
Some random bytes are added at the end to prevent duplicates.
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
>>> class MyTable(TypedTable, SlugMixin, slug_field="some_name"):
|
|
83
|
+
>>> some_name: str
|
|
84
|
+
>>> ...
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# pub:
|
|
88
|
+
slug = StringField(unique=True)
|
|
89
|
+
# priv:
|
|
90
|
+
__settings__: typing.TypedDict( # type: ignore
|
|
91
|
+
"SlugFieldSettings",
|
|
92
|
+
{
|
|
93
|
+
"slug_field": str,
|
|
94
|
+
"slug_suffix": int,
|
|
95
|
+
},
|
|
96
|
+
) # set via init subclass
|
|
97
|
+
|
|
98
|
+
def __init_subclass__(cls, slug_field: str = None, slug_suffix: int = 8, **kw: Any) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Bind 'slug field' option to be used later (on_define).
|
|
101
|
+
|
|
102
|
+
You can control the length of the random suffix with the `slug_suffix` option (0 is no suffix).
|
|
103
|
+
"""
|
|
104
|
+
# unfortunately, PyCharm and mypy do not recognize/autocomplete/typecheck init subclass (keyword) arguments.
|
|
105
|
+
if slug_field is None:
|
|
106
|
+
raise ValueError(
|
|
107
|
+
"SlugMixin requires a valid slug_field setting: "
|
|
108
|
+
"e.g. `class MyClass(TypedTable, SlugMixin, slug_field='title'): ...`"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
cls.__settings__ = {
|
|
112
|
+
"slug_field": slug_field,
|
|
113
|
+
"slug_suffix": slug_suffix,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def __on_define__(cls, db: TypeDAL) -> None:
|
|
118
|
+
"""
|
|
119
|
+
When db is available, include a before_insert hook to generate and include a slug.
|
|
120
|
+
"""
|
|
121
|
+
super().__on_define__(db)
|
|
122
|
+
|
|
123
|
+
# slugs should not be editable (for SEO reasons), so there is only a before insert hook:
|
|
124
|
+
def generate_slug_before_insert(row: OpRow) -> None:
|
|
125
|
+
settings = cls.__settings__
|
|
126
|
+
|
|
127
|
+
text_input = row[settings["slug_field"]]
|
|
128
|
+
generated_slug = slugify(text_input)
|
|
129
|
+
|
|
130
|
+
if suffix_len := settings["slug_suffix"]:
|
|
131
|
+
generated_slug += f"-{slug_random_suffix(suffix_len)}"
|
|
132
|
+
|
|
133
|
+
row["slug"] = slugify(generated_slug)
|
|
134
|
+
|
|
135
|
+
cls._before_insert.append(generate_slug_before_insert)
|
typedal/web2py_py4web_shared.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: TypeDAL
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1.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
|
|
@@ -19,8 +19,9 @@ Requires-Dist: configurable-json
|
|
|
19
19
|
Requires-Dist: configuraptor>=1.26.2
|
|
20
20
|
Requires-Dist: dill
|
|
21
21
|
Requires-Dist: pydal
|
|
22
|
+
Requires-Dist: python-slugify
|
|
22
23
|
Provides-Extra: all
|
|
23
|
-
Requires-Dist: edwh-migrate>=0.8.
|
|
24
|
+
Requires-Dist: edwh-migrate>=0.8.0; extra == 'all'
|
|
24
25
|
Requires-Dist: py4web; extra == 'all'
|
|
25
26
|
Requires-Dist: pydal2sql[all]>=1.1.3; extra == 'all'
|
|
26
27
|
Requires-Dist: questionary; extra == 'all'
|
|
@@ -37,7 +38,7 @@ Requires-Dist: su6[all]; extra == 'dev'
|
|
|
37
38
|
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
38
39
|
Requires-Dist: types-tabulate; extra == 'dev'
|
|
39
40
|
Provides-Extra: migrations
|
|
40
|
-
Requires-Dist: edwh-migrate>=0.8.
|
|
41
|
+
Requires-Dist: edwh-migrate>=0.8.0; extra == 'migrations'
|
|
41
42
|
Requires-Dist: pydal2sql>=1.1.3; extra == 'migrations'
|
|
42
43
|
Requires-Dist: questionary; extra == 'migrations'
|
|
43
44
|
Requires-Dist: tabulate; extra == 'migrations'
|
|
@@ -59,7 +60,7 @@ Description-Content-Type: text/markdown
|
|
|
59
60
|
Typing support for [PyDAL](http://web2py.com/books/default/chapter/29/6).
|
|
60
61
|
This package aims to improve the typing support for PyDAL. By using classes instead of the define_table method,
|
|
61
62
|
type hinting the result of queries can improve the experience while developing. In the background, the queries are still
|
|
62
|
-
generated and executed by pydal itself, this package only
|
|
63
|
+
generated and executed by pydal itself, this package only provides some logic to properly pass calls from class methods to
|
|
63
64
|
the underlying `db.define_table` pydal Tables.
|
|
64
65
|
|
|
65
66
|
- `TypeDAL` is the replacement class for DAL that manages the code on top of DAL.
|
|
@@ -75,13 +76,49 @@ the underlying `db.define_table` pydal Tables.
|
|
|
75
76
|
|
|
76
77
|
Version 2.0 also introduces more ORM-like funcionality.
|
|
77
78
|
Most notably, a Typed Query Builder that sees your table classes as models with relationships to each other.
|
|
78
|
-
See [3. Building Queries](https://
|
|
79
|
+
See [3. Building Queries](https://typedal.readthedocs.io/en/stable/3_building_queries/) for more
|
|
79
80
|
details.
|
|
80
81
|
|
|
81
|
-
##
|
|
82
|
+
## CLI
|
|
83
|
+
The Typedal CLI provides a convenient interface for generating SQL migrations for [edwh-migrate](https://github.com/educationwarehouse/migrate#readme)
|
|
84
|
+
from PyDAL or TypeDAL configurations using [pydal2sql](https://github.com/robinvandernoord/pydal2sql).
|
|
85
|
+
It offers various commands to streamline database management tasks.
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
### Usage
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
typedal --help
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Options
|
|
94
|
+
|
|
95
|
+
- `--show-config`: Toggle to show configuration details. Default is `no-show-config`.
|
|
96
|
+
- `--version`: Toggle to display version information. Default is `no-version`.
|
|
97
|
+
- `--install-completion`: Install completion for the current shell.
|
|
98
|
+
- `--show-completion`: Show completion for the current shell, for copying or customization.
|
|
99
|
+
- `--help`: Display help message and exit.
|
|
100
|
+
|
|
101
|
+
## Commands
|
|
102
|
+
|
|
103
|
+
- `cache.clear`: Clear expired items from the cache.
|
|
104
|
+
- `cache.stats`: Show caching statistics.
|
|
105
|
+
- `migrations.fake`: Mark one or more migrations as completed in the database without executing the SQL code.
|
|
106
|
+
- `migrations.generate`: Run `pydal2sql` based on the TypeDAL configuration.
|
|
107
|
+
- `migrations.run`: Run `edwh-migrate` based on the TypeDAL configuration.
|
|
108
|
+
- `setup`: Interactively setup a `[tool.typedal]` entry in the local `pyproject.toml`.
|
|
109
|
+
|
|
110
|
+
### Configuration
|
|
111
|
+
|
|
112
|
+
TypeDAL and its CLI can be configured via `pyproject.toml`.
|
|
113
|
+
See [6. Migrations](https://typedal.readthedocs.io/en/stable/6_migrations/) for more information about configuration.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
## TypeDAL for PyDAL users - Quick Overview
|
|
117
|
+
|
|
118
|
+
Below you'll find a quick overview of translation from pydal to TypeDAL.
|
|
119
|
+
For more info, see **[the docs](https://typedal.readthedocs.io/en/latest/)**.
|
|
120
|
+
|
|
121
|
+
---
|
|
85
122
|
|
|
86
123
|
### Translations from pydal to typedal
|
|
87
124
|
|
|
@@ -258,7 +295,7 @@ row: TableName = db.table_name(id=1)
|
|
|
258
295
|
|
|
259
296
|
### All Types
|
|
260
297
|
|
|
261
|
-
See [2. Defining Tables](
|
|
298
|
+
See [2. Defining Tables](https://typedal.readthedocs.io/en/stable/2_defining_tables/)
|
|
262
299
|
|
|
263
300
|
## Caveats
|
|
264
301
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
typedal/__about__.py,sha256=OTBqn2XOHv_4-hOGbfVC29HOywMZOEFQS_8L6KP94Y4,206
|
|
2
|
+
typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
|
|
3
|
+
typedal/caching.py,sha256=8UABVAhOlBpL96ykmqhxLaFYOe-XeAh7JoGh57OkxP8,11818
|
|
4
|
+
typedal/cli.py,sha256=3tge8B-YjgjMC6425-RMczmWvpOTfWV5QYPXRY23IWA,18200
|
|
5
|
+
typedal/config.py,sha256=jS1K0_1F5rwJtvwTZ-qR29ZCX7WlyORGEIFvfSnusko,11645
|
|
6
|
+
typedal/core.py,sha256=zkjuSmfkDAagahiOE43__dpd3cYNwqlIXnX-qGz1VDQ,95613
|
|
7
|
+
typedal/fields.py,sha256=z2PD9vLWqBR_zXtiY0DthqTG4AeF3yxKoeuVfGXnSdg,5197
|
|
8
|
+
typedal/for_py4web.py,sha256=d07b8hL_PvNDUS26Z5fDH2OxWb-IETBuAFPSzrRwm04,1285
|
|
9
|
+
typedal/for_web2py.py,sha256=4RHgzGXgKIO_BYB-7adC5e35u52rX-p1t4tPEz-NK24,1867
|
|
10
|
+
typedal/helpers.py,sha256=mtRYPFlS0dx2wK8kYSJ4vm1wsTXRkdPumFRlOAjF_xU,7177
|
|
11
|
+
typedal/mixins.py,sha256=stGjFBWPtRHteGJa3F6c-z9SPcYzFa2ToEbS9qlXEB0,4345
|
|
12
|
+
typedal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
typedal/types.py,sha256=1kGkNX6vfGg6ln84AG558C4Zx5ACRz-emrUTnuy-rRY,3410
|
|
14
|
+
typedal/web2py_py4web_shared.py,sha256=VK9T8P5UwVLvfNBsY4q79ANcABv-jX76YKADt1Zz_co,1539
|
|
15
|
+
typedal/serializers/as_json.py,sha256=ffo152W-sARYXym4BzwX709rrO2-QwKk2KunWY8RNl4,2229
|
|
16
|
+
typedal-3.1.1.dist-info/METADATA,sha256=TlBsIu6-i1xGFDGHPw76tFtE8I4oambuIGOVEbt2dyE,9270
|
|
17
|
+
typedal-3.1.1.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
|
|
18
|
+
typedal-3.1.1.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
19
|
+
typedal-3.1.1.dist-info/RECORD,,
|
typedal-3.0.1.dist-info/RECORD
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
typedal/__about__.py,sha256=8UfBCir8PsjPHcCRJyA0FLS1a3orteNLkZd6vHHlXjc,206
|
|
2
|
-
typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
|
|
3
|
-
typedal/caching.py,sha256=8UABVAhOlBpL96ykmqhxLaFYOe-XeAh7JoGh57OkxP8,11818
|
|
4
|
-
typedal/cli.py,sha256=3tge8B-YjgjMC6425-RMczmWvpOTfWV5QYPXRY23IWA,18200
|
|
5
|
-
typedal/config.py,sha256=jS1K0_1F5rwJtvwTZ-qR29ZCX7WlyORGEIFvfSnusko,11645
|
|
6
|
-
typedal/core.py,sha256=nHJ2Iq67rFIB4j43KCCD-tLIjvvvf4oJhT9T6tjXqxU,95063
|
|
7
|
-
typedal/fields.py,sha256=z2PD9vLWqBR_zXtiY0DthqTG4AeF3yxKoeuVfGXnSdg,5197
|
|
8
|
-
typedal/for_py4web.py,sha256=d07b8hL_PvNDUS26Z5fDH2OxWb-IETBuAFPSzrRwm04,1285
|
|
9
|
-
typedal/for_web2py.py,sha256=zvd5xC-SmuKc0JLDqT3hMIs6COaYnwTFXD_BIeC1vug,1832
|
|
10
|
-
typedal/helpers.py,sha256=n9dpIjXIjPpVFQnLBQreTWqRDR6hIsoNt8vGdEHGo_s,6871
|
|
11
|
-
typedal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
typedal/types.py,sha256=1kGkNX6vfGg6ln84AG558C4Zx5ACRz-emrUTnuy-rRY,3410
|
|
13
|
-
typedal/web2py_py4web_shared.py,sha256=cEbjkK0WOS9Q0nTyZuQaJWffeP4bjrL79Bx0xGy_UOs,1504
|
|
14
|
-
typedal/serializers/as_json.py,sha256=ffo152W-sARYXym4BzwX709rrO2-QwKk2KunWY8RNl4,2229
|
|
15
|
-
typedal-3.0.1.dist-info/METADATA,sha256=GTmtFnSnOhgJI-P_hriMxRSZJf1EkEu9cT6eV2APM0s,7782
|
|
16
|
-
typedal-3.0.1.dist-info/WHEEL,sha256=uNdcs2TADwSd5pVaP0Z_kcjcvvTUklh2S7bxZMF8Uj0,87
|
|
17
|
-
typedal-3.0.1.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
18
|
-
typedal-3.0.1.dist-info/RECORD,,
|
|
File without changes
|