pydantic-forms 2.1.2__tar.gz → 2.2.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.
Files changed (80) hide show
  1. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.bumpversion.cfg +1 -1
  2. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/PKG-INFO +1 -1
  3. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/__init__.py +1 -1
  4. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/__init__.py +3 -0
  5. pydantic_forms-2.2.0/pydantic_forms/validators/components/callout.py +76 -0
  6. pydantic_forms-2.2.0/tests/unit_tests/test_callout.py +97 -0
  7. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.coveragerc +0 -0
  8. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.github/dependabot.yml +0 -0
  9. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.github/workflows/publish-release.yaml +0 -0
  10. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.github/workflows/run-linting-tests.yml +0 -0
  11. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.github/workflows/run-unit-tests.yml +0 -0
  12. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.gitignore +0 -0
  13. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.pre-commit-config.yaml +0 -0
  14. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/.stignore +0 -0
  15. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/LICENSE +0 -0
  16. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/README.md +0 -0
  17. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/codecov.yml +0 -0
  18. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/core/__init__.py +0 -0
  19. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/core/asynchronous.py +0 -0
  20. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/core/shared.py +0 -0
  21. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/core/sync.py +0 -0
  22. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/core/translations.py +0 -0
  23. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/exception_handlers/__init__.py +0 -0
  24. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/exception_handlers/fastapi.py +0 -0
  25. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/exceptions.py +0 -0
  26. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/py.typed +0 -0
  27. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/types.py +0 -0
  28. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/utils/__init__.py +0 -0
  29. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/utils/json.py +0 -0
  30. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/utils/schema.py +0 -0
  31. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/__init__.py +0 -0
  32. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/accept.py +0 -0
  33. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/choice.py +0 -0
  34. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/choice_list.py +0 -0
  35. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/contact_person.py +0 -0
  36. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/contact_person_list.py +0 -0
  37. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/display_subscription.py +0 -0
  38. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/divider.py +0 -0
  39. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/hidden.py +0 -0
  40. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/label.py +0 -0
  41. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/list_of_one.py +0 -0
  42. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/list_of_two.py +0 -0
  43. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/long_text.py +0 -0
  44. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/migration_summary.py +0 -0
  45. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/organisation_id.py +0 -0
  46. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/read_only.py +0 -0
  47. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/timestamp.py +0 -0
  48. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/components/unique_constrained_list.py +0 -0
  49. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pydantic_forms/validators/helpers.py +0 -0
  50. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/pyproject.toml +0 -0
  51. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/setup.cfg +0 -0
  52. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/setup.py +0 -0
  53. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/__init__.py +0 -0
  54. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/__init__.py +0 -0
  55. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/exception_handlers/__init__.py +0 -0
  56. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/exception_handlers/test_fastapi.py +0 -0
  57. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/helpers.py +0 -0
  58. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_accept.py +0 -0
  59. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_choice.py +0 -0
  60. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_choice_list.py +0 -0
  61. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_constrained_list.py +0 -0
  62. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_contact_person.py +0 -0
  63. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_contact_person_list.py +0 -0
  64. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_core.py +0 -0
  65. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_core_async.py +0 -0
  66. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_display_subscription.py +0 -0
  67. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_divider.py +0 -0
  68. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_hidden.py +0 -0
  69. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_label.py +0 -0
  70. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_list_of_one.py +0 -0
  71. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_list_of_two.py +0 -0
  72. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_long_text.py +0 -0
  73. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_migration_summary.py +0 -0
  74. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_organisation_id.py +0 -0
  75. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_read_only_field.py +0 -0
  76. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_shared.py +0 -0
  77. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_timestamp.py +0 -0
  78. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_utils_dict_without_none.py +0 -0
  79. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_utils_from_serializable.py +0 -0
  80. {pydantic_forms-2.1.2 → pydantic_forms-2.2.0}/tests/unit_tests/test_utils_to_serializable.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 2.1.2
2
+ current_version = 2.2.0
3
3
  commit = False
4
4
  tag = False
5
5
  parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((\-rc)(?P<build>\d+))?
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-forms
3
- Version: 2.1.2
3
+ Version: 2.2.0
4
4
  Summary: Pydantic-forms engine.
5
5
  Home-page: https://github.com/workfloworchestrator/pydantic-forms
6
6
  Author: SURF
@@ -13,4 +13,4 @@
13
13
 
14
14
  """Pydantic-forms engine."""
15
15
 
16
- __version__ = "2.1.2"
16
+ __version__ = "2.2.0"
@@ -1,4 +1,5 @@
1
1
  from pydantic_forms.validators.components.accept import Accept, AcceptValues
2
+ from pydantic_forms.validators.components.callout import Callout, callout
2
3
  from pydantic_forms.validators.components.choice import Choice
3
4
  from pydantic_forms.validators.components.choice_list import choice_list
4
5
  from pydantic_forms.validators.components.contact_person import ContactPerson, ContactPersonName
@@ -40,4 +41,6 @@ __all__ = (
40
41
  "Timestamp",
41
42
  "unique_conlist",
42
43
  "validate_unique_list",
44
+ "callout",
45
+ "Callout",
43
46
  )
@@ -0,0 +1,76 @@
1
+ # Copyright 2019-2025 SURF.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ from enum import Enum
14
+ from functools import partial
15
+ from types import new_class
16
+ from typing import Annotated, Any, ClassVar, TypedDict, Union
17
+
18
+ from pydantic import BaseModel, Field
19
+
20
+
21
+ class CalloutMessageType(str, Enum):
22
+ PRIMARY = "primary"
23
+ SUCCESS = "success"
24
+ WARNING = "warning"
25
+ DANGER = "danger"
26
+ ACCENT = "accent"
27
+
28
+
29
+ class CalloutData(TypedDict, total=False):
30
+ header: Union[str, None]
31
+ message: Union[str, None]
32
+ icon_type: Union[str, None]
33
+ message_type: Union[CalloutMessageType, str]
34
+
35
+
36
+ class _Callout(BaseModel):
37
+ data: ClassVar[Union[CalloutData, None]] = None
38
+
39
+
40
+ Callout = Annotated[_Callout, Field(frozen=True, default=None, validate_default=False)]
41
+
42
+
43
+ def create_callout_schema(data: CalloutData, schema: dict[str, Any]) -> None:
44
+ schema.update(
45
+ {
46
+ "format": "callout",
47
+ "type": "string",
48
+ "default": data,
49
+ }
50
+ )
51
+
52
+
53
+ def callout(
54
+ *,
55
+ header: Union[str, None] = None,
56
+ message: Union[str, None] = None,
57
+ icon_type: Union[str, None] = "info",
58
+ message_type: Union[CalloutMessageType, str] = CalloutMessageType.PRIMARY,
59
+ ) -> type[Callout]:
60
+
61
+ data: CalloutData = {
62
+ "header": header,
63
+ "message": message,
64
+ "icon_type": icon_type,
65
+ "message_type": message_type,
66
+ }
67
+
68
+ namespace = {"data": data}
69
+ klass: type[Callout] = new_class("CalloutValue", (_Callout,), {}, lambda ns: ns.update(namespace))
70
+
71
+ json_schema_extra = partial(create_callout_schema, data)
72
+
73
+ return Annotated[
74
+ klass,
75
+ Field(frozen=True, default=None, validate_default=False, json_schema_extra=json_schema_extra),
76
+ ] # type: ignore
@@ -0,0 +1,97 @@
1
+ from uuid import uuid4
2
+
3
+ from pydantic_forms.core import FormPage
4
+ from pydantic_forms.validators import DisplaySubscription, Label
5
+ from pydantic_forms.validators.components.callout import CalloutMessageType, callout
6
+ from tests.unit_tests.helpers import PYDANTIC_VERSION
7
+
8
+
9
+ def test_callout_default():
10
+ """Ensure Callout default is None and schema defaults are correctly injected."""
11
+ CalloutField = callout(
12
+ header="Test header",
13
+ message="This is a test message",
14
+ icon_type="info",
15
+ message_type=CalloutMessageType.SUCCESS,
16
+ )
17
+
18
+ some_sub_id = uuid4()
19
+
20
+ class Form(FormPage):
21
+ display_sub: DisplaySubscription = some_sub_id
22
+ label: Label = "bla"
23
+ callout_field: CalloutField
24
+
25
+ # The field itself should default to None (display-only)
26
+ assert Form().model_dump() == {
27
+ "display_sub": some_sub_id,
28
+ "label": "bla",
29
+ "callout_field": None,
30
+ }
31
+
32
+ # And the field accepts no input (display only)
33
+ assert Form(display_sub="").model_dump() == {
34
+ "display_sub": some_sub_id,
35
+ "label": "bla",
36
+ "callout_field": None,
37
+ }
38
+
39
+
40
+ def test_callout_schema():
41
+ """Ensure the callout field generates a correct JSON schema with default data."""
42
+ CalloutField = callout(
43
+ header="Header",
44
+ message="A message",
45
+ icon_type="bell",
46
+ message_type="danger",
47
+ )
48
+
49
+ class Form(FormPage):
50
+ callout_field: CalloutField
51
+
52
+ if PYDANTIC_VERSION == "2.8":
53
+ callout_field_ref = {"allOf": [{"$ref": "#/$defs/CalloutValue"}]}
54
+ else:
55
+ callout_field_ref = {"$ref": "#/$defs/CalloutValue"}
56
+
57
+ expected = {
58
+ "$defs": {"CalloutValue": {"properties": {}, "title": "CalloutValue", "type": "object"}},
59
+ "additionalProperties": False,
60
+ "properties": {
61
+ "callout_field": {
62
+ **callout_field_ref,
63
+ "default": {
64
+ "header": "Header",
65
+ "message": "A message",
66
+ "icon_type": "bell",
67
+ "message_type": "danger",
68
+ },
69
+ "format": "callout",
70
+ "type": "string",
71
+ },
72
+ },
73
+ "title": "unknown",
74
+ "type": "object",
75
+ }
76
+
77
+ assert Form.model_json_schema() == expected
78
+
79
+
80
+ def test_callout_accepts_custom_message_type():
81
+ """Ensure custom (non-enum) message_type values are accepted and serialized correctly."""
82
+ CalloutField = callout(
83
+ header="Custom",
84
+ message="Supports custom color values",
85
+ icon_type="iInCircle",
86
+ message_type="neutral", # custom
87
+ )
88
+
89
+ class Form(FormPage):
90
+ callout_field: CalloutField
91
+
92
+ schema = Form.model_json_schema()
93
+
94
+ default_data = schema["properties"]["callout_field"]["default"]
95
+ assert default_data["message_type"] == "neutral"
96
+ assert default_data["header"] == "Custom"
97
+ assert default_data["icon_type"] == "iInCircle"
File without changes
File without changes
File without changes
File without changes
File without changes