pytypehintweb 1.2.2__tar.gz → 1.3.0__tar.gz
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.
- {pytypehintweb-1.2.2/src/pytypehintweb.egg-info → pytypehintweb-1.3.0}/PKG-INFO +10 -10
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/README.md +8 -8
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/pyproject.toml +1 -1
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/__init__.py +1 -1
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/plan.py +42 -2
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/contract.js +8 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/inputs.js +11 -48
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0/src/pytypehintweb.egg-info}/PKG-INFO +10 -10
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb.egg-info/requires.txt +1 -1
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/LICENSE +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/setup.cfg +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/decode.py +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/demo/__init__.py +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/demo/__main__.py +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/demo/app.py +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/demo/examples.py +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/py.typed +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/defaults.js +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/fields.js +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/form.js +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/icons/select-arrow-dark.svg +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/icons/select-arrow-light.svg +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/icons/trash.svg +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/iso.js +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/normalize.js +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/slider.js +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/widgets.css +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/types.py +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb.egg-info/SOURCES.txt +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb.egg-info/dependency_links.txt +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb.egg-info/entry_points.txt +0 -0
- {pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytypehintweb
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Framework-free browser form layer for pytypehint
|
|
5
5
|
Author: Beltran Offerrall
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Classifier: Typing :: Typed
|
|
|
23
23
|
Requires-Python: >=3.11
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
|
-
Requires-Dist: pytypehint==1.
|
|
26
|
+
Requires-Dist: pytypehint==1.3.0
|
|
27
27
|
Provides-Extra: demo
|
|
28
28
|
Requires-Dist: fastapi; extra == "demo"
|
|
29
29
|
Requires-Dist: uvicorn; extra == "demo"
|
|
@@ -69,14 +69,14 @@ The full documentation is at https://offerrall.github.io/pytypehintweb/.
|
|
|
69
69
|
|
|
70
70
|
## Documentation
|
|
71
71
|
|
|
72
|
-
- [Overview](
|
|
73
|
-
- [Getting started](
|
|
74
|
-
- [Plan contract](
|
|
75
|
-
- [Python API](
|
|
76
|
-
- [JavaScript API](
|
|
77
|
-
- [Architecture](
|
|
78
|
-
- [Limitations](
|
|
72
|
+
- [Overview](https://offerrall.github.io/pytypehintweb/): what the library does, where it stops, its features and its stability promise.
|
|
73
|
+
- [Getting started](https://offerrall.github.io/pytypehintweb/getting-started/): one complete form, from a Python function to the built result.
|
|
74
|
+
- [Plan contract](https://offerrall.github.io/pytypehintweb/plan/): the plan format, every property, default and invariant.
|
|
75
|
+
- [Python API](https://offerrall.github.io/pytypehintweb/python/): `plan_of()`, `decode()`, `WebConfig` and how each annotation maps to a node.
|
|
76
|
+
- [JavaScript API](https://offerrall.github.io/pytypehintweb/javascript/): `compileForm()`, widgets, reading, accessibility, styling and themes.
|
|
77
|
+
- [Architecture](https://offerrall.github.io/pytypehintweb/architecture/): the layers and which layer owns each rule.
|
|
78
|
+
- [Limitations](https://offerrall.github.io/pytypehintweb/limitations/): what a plan cannot represent and why.
|
|
79
79
|
|
|
80
80
|
### Maintaining
|
|
81
81
|
|
|
82
|
-
- [Testing](
|
|
82
|
+
- [Testing](https://offerrall.github.io/pytypehintweb/testing/): how to run the suites, what they guarantee, and CI and release.
|
|
@@ -34,14 +34,14 @@ The full documentation is at https://offerrall.github.io/pytypehintweb/.
|
|
|
34
34
|
|
|
35
35
|
## Documentation
|
|
36
36
|
|
|
37
|
-
- [Overview](
|
|
38
|
-
- [Getting started](
|
|
39
|
-
- [Plan contract](
|
|
40
|
-
- [Python API](
|
|
41
|
-
- [JavaScript API](
|
|
42
|
-
- [Architecture](
|
|
43
|
-
- [Limitations](
|
|
37
|
+
- [Overview](https://offerrall.github.io/pytypehintweb/): what the library does, where it stops, its features and its stability promise.
|
|
38
|
+
- [Getting started](https://offerrall.github.io/pytypehintweb/getting-started/): one complete form, from a Python function to the built result.
|
|
39
|
+
- [Plan contract](https://offerrall.github.io/pytypehintweb/plan/): the plan format, every property, default and invariant.
|
|
40
|
+
- [Python API](https://offerrall.github.io/pytypehintweb/python/): `plan_of()`, `decode()`, `WebConfig` and how each annotation maps to a node.
|
|
41
|
+
- [JavaScript API](https://offerrall.github.io/pytypehintweb/javascript/): `compileForm()`, widgets, reading, accessibility, styling and themes.
|
|
42
|
+
- [Architecture](https://offerrall.github.io/pytypehintweb/architecture/): the layers and which layer owns each rule.
|
|
43
|
+
- [Limitations](https://offerrall.github.io/pytypehintweb/limitations/): what a plan cannot represent and why.
|
|
44
44
|
|
|
45
45
|
### Maintaining
|
|
46
46
|
|
|
47
|
-
- [Testing](
|
|
47
|
+
- [Testing](https://offerrall.github.io/pytypehintweb/testing/): how to run the suites, what they guarantee, and CI and release.
|
|
@@ -11,7 +11,7 @@ license = "MIT"
|
|
|
11
11
|
license-files = ["LICENSE"]
|
|
12
12
|
authors = [{name = "Beltran Offerrall"}]
|
|
13
13
|
requires-python = ">=3.11"
|
|
14
|
-
dependencies = ["pytypehint==1.
|
|
14
|
+
dependencies = ["pytypehint==1.3.0"]
|
|
15
15
|
keywords = ["forms", "type-hints", "dataclasses", "schema", "web", "html"]
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Development Status :: 5 - Production/Stable",
|
|
@@ -480,6 +480,19 @@ def _bound(bound, delta, path: str, what: str):
|
|
|
480
480
|
return inclusive
|
|
481
481
|
|
|
482
482
|
|
|
483
|
+
def _writable_float(value: float, path: str) -> float:
|
|
484
|
+
# JavaScript writes a number below 1e-6 or from 1e21 up in exponent notation,
|
|
485
|
+
# text the float control's own grammar rejects, so the default could never
|
|
486
|
+
# be shown as the value it is.
|
|
487
|
+
if value != 0 and not 1e-6 <= abs(value) < 1e21:
|
|
488
|
+
raise _error(
|
|
489
|
+
path,
|
|
490
|
+
f"Float default: {value!r} is valid in pytypehint but JavaScript "
|
|
491
|
+
f"writes it in exponent notation, which a float control cannot hold")
|
|
492
|
+
|
|
493
|
+
return value
|
|
494
|
+
|
|
495
|
+
|
|
483
496
|
def _file_size(bound, path: str, what: str):
|
|
484
497
|
# A plain int on FileHint, already checked there for being a non-negative
|
|
485
498
|
# int and for min <= max. All that is left is the one thing the core has no
|
|
@@ -1059,6 +1072,11 @@ def _plain_value(shape, value, path: str):
|
|
|
1059
1072
|
_check_slider_default(shape, safe, path)
|
|
1060
1073
|
return safe
|
|
1061
1074
|
|
|
1075
|
+
# A select names its choices and writes no number, so only a text control
|
|
1076
|
+
# is bound by what JavaScript can write.
|
|
1077
|
+
if type(shape) is Float and shape.choices is None:
|
|
1078
|
+
return _writable_float(value, path)
|
|
1079
|
+
|
|
1062
1080
|
# The plan is JSON, so a date/time default travels as canonical ISO text and
|
|
1063
1081
|
# an enum member as its name — the transport their choices already take.
|
|
1064
1082
|
if type(shape) is Date or type(shape) is Time:
|
|
@@ -1140,10 +1158,32 @@ def _field_node(field, config, path: str) -> dict:
|
|
|
1140
1158
|
return node
|
|
1141
1159
|
|
|
1142
1160
|
|
|
1143
|
-
def
|
|
1161
|
+
def _reject_recursion(shapes, path: str, open_structs: tuple) -> None:
|
|
1162
|
+
# A plan is fully expanded, so a dataclass that contains itself has no plan.
|
|
1163
|
+
# Name the field instead of descending until the interpreter's stack ends.
|
|
1164
|
+
for shape in shapes:
|
|
1165
|
+
if type(shape) is List:
|
|
1166
|
+
_reject_recursion(shape.item, f"{path}.item", open_structs)
|
|
1167
|
+
elif type(shape) is Struct:
|
|
1168
|
+
if any(shape is opened for opened in open_structs):
|
|
1169
|
+
raise _error(
|
|
1170
|
+
path,
|
|
1171
|
+
f"{shape.cls.__name__} contains itself; a plan is fully "
|
|
1172
|
+
f"expanded and cannot represent a recursive shape")
|
|
1173
|
+
|
|
1174
|
+
for f in shape.fields:
|
|
1175
|
+
_reject_recursion(
|
|
1176
|
+
f.shape, f"{path}.{f.name}", (*open_structs, shape))
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
def _form_node(name, description, fields, config, root=None) -> dict:
|
|
1144
1180
|
plan = {"v": _PLAN_VERSION, "kind": "form", "name": name,
|
|
1145
1181
|
"description": description}
|
|
1146
1182
|
|
|
1183
|
+
for f in fields:
|
|
1184
|
+
_reject_recursion(
|
|
1185
|
+
f.shape, f"fields.{f.name}", () if root is None else (root,))
|
|
1186
|
+
|
|
1147
1187
|
plan["fields"] = [_field_node(f, config, "fields") for f in fields]
|
|
1148
1188
|
|
|
1149
1189
|
return plan
|
|
@@ -1157,7 +1197,7 @@ def plan_of(obj, *, config: WebConfig | None = None) -> dict:
|
|
|
1157
1197
|
f"config must be WebConfig or None, got {type(config).__name__}")
|
|
1158
1198
|
|
|
1159
1199
|
if type(obj) is Struct:
|
|
1160
|
-
return _form_node(obj.cls.__name__, None, obj.fields, config)
|
|
1200
|
+
return _form_node(obj.cls.__name__, None, obj.fields, config, obj)
|
|
1161
1201
|
|
|
1162
1202
|
if type(obj) is Signature:
|
|
1163
1203
|
return _form_node(obj.name, obj.doc, obj.params, config)
|
|
@@ -623,7 +623,15 @@ function checkFileDefault(options, value, path) {
|
|
|
623
623
|
}
|
|
624
624
|
|
|
625
625
|
|
|
626
|
+
const WRITABLE_FLOAT = /^-?\d+(\.\d+)?$/;
|
|
627
|
+
|
|
628
|
+
|
|
626
629
|
function checkFloatDefault(options, value, path) {
|
|
630
|
+
if (options.choices === null && !WRITABLE_FLOAT.test(String(value))) {
|
|
631
|
+
fail(path, "expected a number JavaScript writes as a simple decimal, "
|
|
632
|
+
+ "not exponent notation");
|
|
633
|
+
}
|
|
634
|
+
|
|
627
635
|
if (options.min !== null) {
|
|
628
636
|
const below = options.minExclusive ? value <= options.min : value < options.min;
|
|
629
637
|
|
|
@@ -20,6 +20,8 @@ const ISO_MINUTES = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
|
20
20
|
|
|
21
21
|
const FLOAT = /^-?\d+(\.\d+)?$/;
|
|
22
22
|
|
|
23
|
+
const FREE_EXTENSION = /\.[a-z0-9]{1,16}$/;
|
|
24
|
+
|
|
23
25
|
function isWritableFloat(value) {
|
|
24
26
|
return typeof value === "number"
|
|
25
27
|
&& Number.isFinite(value)
|
|
@@ -53,7 +55,7 @@ function setAttributes(el, attributes) {
|
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
function withValue(template, value) {
|
|
56
|
-
return template.replace("{value}", String(value));
|
|
58
|
+
return template.replace("{value}", () => String(value));
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
|
|
@@ -443,21 +445,7 @@ export class FileWidget extends Widget {
|
|
|
443
445
|
}
|
|
444
446
|
|
|
445
447
|
setValue(value) {
|
|
446
|
-
|
|
447
|
-
this._clear();
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
this._current = this._asReferences(value);
|
|
452
|
-
this._files = [];
|
|
453
|
-
this._refs = [];
|
|
454
|
-
this._invalid = false;
|
|
455
|
-
this._stashedCurrent = null;
|
|
456
|
-
this.input.value = "";
|
|
457
|
-
|
|
458
|
-
this._renderCurrent();
|
|
459
|
-
this._showMessage();
|
|
460
|
-
this._emitChange();
|
|
448
|
+
this._reset(value === null ? null : this._asReferences(value), null);
|
|
461
449
|
}
|
|
462
450
|
|
|
463
451
|
error() {
|
|
@@ -531,13 +519,13 @@ export class FileWidget extends Widget {
|
|
|
531
519
|
return this.extensions.some((extension) => lower.endsWith(extension));
|
|
532
520
|
}
|
|
533
521
|
|
|
534
|
-
|
|
522
|
+
_reset(current, stashed) {
|
|
523
|
+
this._current = current;
|
|
524
|
+
this._stashedCurrent = stashed;
|
|
535
525
|
this._files = [];
|
|
536
526
|
this._refs = [];
|
|
537
527
|
this._invalid = false;
|
|
538
528
|
this._oversized = null;
|
|
539
|
-
this._current = null;
|
|
540
|
-
this._stashedCurrent = null;
|
|
541
529
|
this.input.value = "";
|
|
542
530
|
|
|
543
531
|
this._renderCurrent();
|
|
@@ -547,37 +535,13 @@ export class FileWidget extends Widget {
|
|
|
547
535
|
}
|
|
548
536
|
|
|
549
537
|
_beginReplace() {
|
|
550
|
-
this.
|
|
551
|
-
this._current = null;
|
|
552
|
-
this._files = [];
|
|
553
|
-
this._refs = [];
|
|
554
|
-
this._invalid = false;
|
|
555
|
-
this._oversized = null;
|
|
556
|
-
this.input.value = "";
|
|
557
|
-
|
|
558
|
-
this._renderCurrent();
|
|
559
|
-
this._renderList();
|
|
560
|
-
this._showMessage();
|
|
561
|
-
this._emitChange();
|
|
538
|
+
this._reset(null, this._current);
|
|
562
539
|
}
|
|
563
540
|
|
|
564
541
|
_restore() {
|
|
565
|
-
if (this._stashedCurrent
|
|
566
|
-
|
|
542
|
+
if (this._stashedCurrent !== null) {
|
|
543
|
+
this._reset(this._stashedCurrent, null);
|
|
567
544
|
}
|
|
568
|
-
|
|
569
|
-
this._current = this._stashedCurrent;
|
|
570
|
-
this._stashedCurrent = null;
|
|
571
|
-
this._files = [];
|
|
572
|
-
this._refs = [];
|
|
573
|
-
this._invalid = false;
|
|
574
|
-
this._oversized = null;
|
|
575
|
-
this.input.value = "";
|
|
576
|
-
|
|
577
|
-
this._renderCurrent();
|
|
578
|
-
this._renderList();
|
|
579
|
-
this._showMessage();
|
|
580
|
-
this._emitChange();
|
|
581
545
|
}
|
|
582
546
|
|
|
583
547
|
_sizeError(file) {
|
|
@@ -608,8 +572,7 @@ export class FileWidget extends Widget {
|
|
|
608
572
|
const lower = name.toLowerCase();
|
|
609
573
|
|
|
610
574
|
if (this.extensions.length === 0) {
|
|
611
|
-
|
|
612
|
-
return dot === -1 ? "" : lower.slice(dot);
|
|
575
|
+
return FREE_EXTENSION.exec(lower)?.[0] ?? "";
|
|
613
576
|
}
|
|
614
577
|
|
|
615
578
|
return this.extensions.find((extension) => lower.endsWith(extension))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytypehintweb
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Framework-free browser form layer for pytypehint
|
|
5
5
|
Author: Beltran Offerrall
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Classifier: Typing :: Typed
|
|
|
23
23
|
Requires-Python: >=3.11
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
|
-
Requires-Dist: pytypehint==1.
|
|
26
|
+
Requires-Dist: pytypehint==1.3.0
|
|
27
27
|
Provides-Extra: demo
|
|
28
28
|
Requires-Dist: fastapi; extra == "demo"
|
|
29
29
|
Requires-Dist: uvicorn; extra == "demo"
|
|
@@ -69,14 +69,14 @@ The full documentation is at https://offerrall.github.io/pytypehintweb/.
|
|
|
69
69
|
|
|
70
70
|
## Documentation
|
|
71
71
|
|
|
72
|
-
- [Overview](
|
|
73
|
-
- [Getting started](
|
|
74
|
-
- [Plan contract](
|
|
75
|
-
- [Python API](
|
|
76
|
-
- [JavaScript API](
|
|
77
|
-
- [Architecture](
|
|
78
|
-
- [Limitations](
|
|
72
|
+
- [Overview](https://offerrall.github.io/pytypehintweb/): what the library does, where it stops, its features and its stability promise.
|
|
73
|
+
- [Getting started](https://offerrall.github.io/pytypehintweb/getting-started/): one complete form, from a Python function to the built result.
|
|
74
|
+
- [Plan contract](https://offerrall.github.io/pytypehintweb/plan/): the plan format, every property, default and invariant.
|
|
75
|
+
- [Python API](https://offerrall.github.io/pytypehintweb/python/): `plan_of()`, `decode()`, `WebConfig` and how each annotation maps to a node.
|
|
76
|
+
- [JavaScript API](https://offerrall.github.io/pytypehintweb/javascript/): `compileForm()`, widgets, reading, accessibility, styling and themes.
|
|
77
|
+
- [Architecture](https://offerrall.github.io/pytypehintweb/architecture/): the layers and which layer owns each rule.
|
|
78
|
+
- [Limitations](https://offerrall.github.io/pytypehintweb/limitations/): what a plan cannot represent and why.
|
|
79
79
|
|
|
80
80
|
### Maintaining
|
|
81
81
|
|
|
82
|
-
- [Testing](
|
|
82
|
+
- [Testing](https://offerrall.github.io/pytypehintweb/testing/): how to run the suites, what they guarantee, and CI and release.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/icons/select-arrow-dark.svg
RENAMED
|
File without changes
|
{pytypehintweb-1.2.2 → pytypehintweb-1.3.0}/src/pytypehintweb/static/icons/select-arrow-light.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|