TypeDAL 3.0.0b4__py3-none-any.whl → 3.1.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 +1 -1
- typedal/cli.py +6 -20
- typedal/config.py +4 -5
- typedal/core.py +29 -17
- typedal/for_web2py.py +2 -0
- typedal/helpers.py +26 -2
- typedal/mixins.py +135 -0
- typedal/web2py_py4web_shared.py +2 -0
- {typedal-3.0.0b4.dist-info → typedal-3.1.0.dist-info}/METADATA +4 -3
- typedal-3.1.0.dist-info/RECORD +19 -0
- typedal-3.0.0b4.dist-info/RECORD +0 -18
- {typedal-3.0.0b4.dist-info → typedal-3.1.0.dist-info}/WHEEL +0 -0
- {typedal-3.0.0b4.dist-info → typedal-3.1.0.dist-info}/entry_points.txt +0 -0
typedal/__about__.py
CHANGED
typedal/cli.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Typer CLI for TypeDAL.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import fnmatch
|
|
6
5
|
import sys
|
|
7
6
|
import typing
|
|
8
7
|
import warnings
|
|
@@ -14,6 +13,7 @@ from configuraptor import asdict
|
|
|
14
13
|
from configuraptor.alias import is_alias
|
|
15
14
|
from configuraptor.helpers import is_optional
|
|
16
15
|
|
|
16
|
+
from .helpers import match_strings
|
|
17
17
|
from .types import AnyDict
|
|
18
18
|
|
|
19
19
|
try:
|
|
@@ -240,7 +240,7 @@ def generate_migrations(
|
|
|
240
240
|
output_format: OutputFormat_Option = None,
|
|
241
241
|
output_file: Optional[str] = None,
|
|
242
242
|
dry_run: bool = False,
|
|
243
|
-
) -> bool:
|
|
243
|
+
) -> bool: # pragma: no cover
|
|
244
244
|
"""
|
|
245
245
|
Run pydal2sql based on the typedal config.
|
|
246
246
|
"""
|
|
@@ -313,7 +313,7 @@ def run_migrations(
|
|
|
313
313
|
schema: Optional[str] = None,
|
|
314
314
|
create_flag_location: Optional[bool] = None,
|
|
315
315
|
dry_run: bool = False,
|
|
316
|
-
) -> bool:
|
|
316
|
+
) -> bool: # pragma: no cover
|
|
317
317
|
"""
|
|
318
318
|
Run edwh-migrate based on the typedal config.
|
|
319
319
|
"""
|
|
@@ -345,20 +345,6 @@ def run_migrations(
|
|
|
345
345
|
return True
|
|
346
346
|
|
|
347
347
|
|
|
348
|
-
def match_strings(patterns: list[str] | str, string_list: list[str]) -> list[str]:
|
|
349
|
-
"""
|
|
350
|
-
Glob but on a list of strings.
|
|
351
|
-
"""
|
|
352
|
-
if isinstance(patterns, str):
|
|
353
|
-
patterns = [patterns]
|
|
354
|
-
|
|
355
|
-
matches = []
|
|
356
|
-
for pattern in patterns:
|
|
357
|
-
matches.extend([s for s in string_list if fnmatch.fnmatch(s, pattern)])
|
|
358
|
-
|
|
359
|
-
return matches
|
|
360
|
-
|
|
361
|
-
|
|
362
348
|
@app.command(name="migrations.fake")
|
|
363
349
|
@with_exit_code(hide_tb=IS_DEBUG)
|
|
364
350
|
def fake_migrations(
|
|
@@ -370,7 +356,7 @@ def fake_migrations(
|
|
|
370
356
|
db_folder: Optional[str] = None,
|
|
371
357
|
migrate_table: Optional[str] = None,
|
|
372
358
|
dry_run: bool = False,
|
|
373
|
-
) -> int:
|
|
359
|
+
) -> int: # pragma: no cover
|
|
374
360
|
"""
|
|
375
361
|
Mark one or more migrations as completed in the database, without executing the SQL code.
|
|
376
362
|
|
|
@@ -495,7 +481,7 @@ def cache_stats(
|
|
|
495
481
|
fmt: typing.Annotated[
|
|
496
482
|
str, typer.Option("--format", "--fmt", "-f", help="plaintext (default) or json")
|
|
497
483
|
] = "plaintext",
|
|
498
|
-
) -> None:
|
|
484
|
+
) -> None: # pragma: no cover
|
|
499
485
|
"""
|
|
500
486
|
Collect caching stats.
|
|
501
487
|
|
|
@@ -538,7 +524,7 @@ def cache_stats(
|
|
|
538
524
|
def cache_clear(
|
|
539
525
|
connection: typing.Annotated[str, typer.Option("--connection", "-c")] = None,
|
|
540
526
|
purge: typing.Annotated[bool, typer.Option("--all", "--purge", "-p")] = False,
|
|
541
|
-
) -> None:
|
|
527
|
+
) -> None: # pragma: no cover
|
|
542
528
|
"""
|
|
543
529
|
Clear (expired) items from the cache.
|
|
544
530
|
|
typedal/config.py
CHANGED
|
@@ -122,8 +122,7 @@ class TypeDALConfig(TypedConfig):
|
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
def _load_toml(path: str | bool | None = True) -> tuple[str, AnyDict]:
|
|
125
|
+
def _load_toml(path: str | bool | Path | None = True) -> tuple[str, AnyDict]:
|
|
127
126
|
"""
|
|
128
127
|
Path can be a file, a directory, a bool or None.
|
|
129
128
|
|
|
@@ -136,10 +135,10 @@ def _load_toml(path: str | bool | None = True) -> tuple[str, AnyDict]:
|
|
|
136
135
|
toml_path = None
|
|
137
136
|
elif path in (True, None):
|
|
138
137
|
toml_path = find_pyproject_toml()
|
|
139
|
-
elif Path(str(path)).is_file():
|
|
140
|
-
toml_path =
|
|
138
|
+
elif (_p := Path(str(path))) and _p.is_file():
|
|
139
|
+
toml_path = _p
|
|
141
140
|
else:
|
|
142
|
-
toml_path = find_pyproject_toml(path)
|
|
141
|
+
toml_path = find_pyproject_toml(str(path))
|
|
143
142
|
|
|
144
143
|
if not toml_path:
|
|
145
144
|
# nothing to load
|
typedal/core.py
CHANGED
|
@@ -519,7 +519,7 @@ class TypeDAL(pydal.DAL): # type: ignore
|
|
|
519
519
|
if k not in relationships and (new_relationship := to_relationship(cls, k, annotations[k]))
|
|
520
520
|
}
|
|
521
521
|
|
|
522
|
-
cache_dependency = kwargs.pop("cache_dependency", True)
|
|
522
|
+
cache_dependency = self._config.caching and kwargs.pop("cache_dependency", True)
|
|
523
523
|
|
|
524
524
|
table: Table = self.define_table(tablename, *fields.values(), **kwargs)
|
|
525
525
|
|
|
@@ -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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Helpers that work independently of core.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import fnmatch
|
|
5
6
|
import io
|
|
6
7
|
import types
|
|
7
8
|
import typing
|
|
@@ -24,19 +25,28 @@ def is_union(some_type: type | types.UnionType) -> bool:
|
|
|
24
25
|
return typing.get_origin(some_type) in (types.UnionType, typing.Union)
|
|
25
26
|
|
|
26
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
|
+
|
|
27
35
|
def _all_annotations(cls: type) -> ChainMap[str, type]:
|
|
28
36
|
"""
|
|
29
37
|
Returns a dictionary-like ChainMap that includes annotations for all \
|
|
30
38
|
attributes defined in cls or inherited from superclasses.
|
|
31
39
|
"""
|
|
32
|
-
|
|
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__))
|
|
33
43
|
|
|
34
44
|
|
|
35
45
|
def all_dict(cls: type) -> AnyDict:
|
|
36
46
|
"""
|
|
37
47
|
Get the internal data of a class and all it's parents.
|
|
38
48
|
"""
|
|
39
|
-
return dict(ChainMap(*(c.__dict__ for c in
|
|
49
|
+
return dict(ChainMap(*(c.__dict__ for c in reversed_mro(cls)))) # type: ignore
|
|
40
50
|
|
|
41
51
|
|
|
42
52
|
def all_annotations(cls: type, _except: typing.Iterable[str] = None) -> dict[str, type]:
|
|
@@ -241,3 +251,17 @@ def as_lambda(value: T) -> typing.Callable[..., T]:
|
|
|
241
251
|
Wrap value in a callable.
|
|
242
252
|
"""
|
|
243
253
|
return lambda *_, **__: value
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def match_strings(patterns: list[str] | str, string_list: list[str]) -> list[str]:
|
|
257
|
+
"""
|
|
258
|
+
Glob but on a list of strings.
|
|
259
|
+
"""
|
|
260
|
+
if isinstance(patterns, str):
|
|
261
|
+
patterns = [patterns]
|
|
262
|
+
|
|
263
|
+
matches = []
|
|
264
|
+
for pattern in patterns:
|
|
265
|
+
matches.extend([s for s in string_list if fnmatch.fnmatch(s, pattern)])
|
|
266
|
+
|
|
267
|
+
return matches
|
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
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: TypeDAL
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.1.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
|
|
@@ -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'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
typedal/__about__.py,sha256=CN-1Orlz3CG7QijS-1qeKVPqHlDwyfxEQpBei5EcMRU,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.0.dist-info/METADATA,sha256=gCefk7iKuT5OVtj6uj8MpfVJlyu_xTSYF2oEim3ZxJg,7808
|
|
17
|
+
typedal-3.1.0.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
|
|
18
|
+
typedal-3.1.0.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
19
|
+
typedal-3.1.0.dist-info/RECORD,,
|
typedal-3.0.0b4.dist-info/RECORD
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
typedal/__about__.py,sha256=SUF9TxfBN1DcUhWrX9OEqf6k25fMzFQ0el_VEvjx_Mw,213
|
|
2
|
-
typedal/__init__.py,sha256=QQpLiVl9w9hm2LBxey49Y_tCF_VB2bScVaS_mCjYy54,366
|
|
3
|
-
typedal/caching.py,sha256=8UABVAhOlBpL96ykmqhxLaFYOe-XeAh7JoGh57OkxP8,11818
|
|
4
|
-
typedal/cli.py,sha256=5-2U_pQOZNKHmhefiYtkd7g6B0DAXzjf4A1Jh7D37io,18427
|
|
5
|
-
typedal/config.py,sha256=KDJXRsIQuFpSZy5XpSJiC_9WGLlmaOexACW0sWdCw54,11626
|
|
6
|
-
typedal/core.py,sha256=qgJPvlcQYCujsjiiD6SOhWbIr1lxoUDpZUkMnK-mcDQ,95038
|
|
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=BFuGd-1tBA1-QS91C9PEvNY5z5KFHd3gTplxxDWdwSo,6509
|
|
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.0b4.dist-info/METADATA,sha256=5XYmt8o4m4_atdsIPn2hSAQwKgHRIF_qunAe93lsaII,7784
|
|
16
|
-
typedal-3.0.0b4.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
|
|
17
|
-
typedal-3.0.0b4.dist-info/entry_points.txt,sha256=m1wqcc_10rHWPdlQ71zEkmJDADUAnZtn7Jac_6mbyUc,44
|
|
18
|
-
typedal-3.0.0b4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|