Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.1.3

Requires `metaclass-registry>=0.4.0`, `objectstate>=3.0.1,<4` and
`zmqruntime>=0.6.4,<0.7`.

Changed:

- A type has one inline-widget factory and one preview formatter.
`PreviewFormatterRegistry.register` and the inline-widget factory
registration raise `ValueError` when a different registrant is given for a
type that already has one, instead of replacing it. Registering the same
one again does nothing.

## 0.1.2

Requires ObjectState 3 (`objectstate>=3.0,<4`).
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ keywords = ["forms", "reactive", "dataclass", "ui-bridge", "headless"]

dependencies = [
"docutils>=0.20",
"metaclass-registry>=0.1.5",
"objectstate>=3.0,<4",
"metaclass-registry>=0.4.0",
"objectstate>=3.0.1,<4",
"psutil>=5.9",
"python-introspect>=0.2.7,<0.3",
"pyzmq>=22.0",
"zmqruntime>=0.6,<0.7",
"zmqruntime>=0.6.4,<0.7",
]

[project.optional-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion requirements-ci.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Source candidates needed to validate this checkout before coordinated publication.
# Empty: every first-party dependency is released (objectstate 3.0.0).
# Empty: every first-party dependency is released (objectstate 3.0.1, zmqruntime 0.6.4, metaclass-registry 0.4.0).
2 changes: 1 addition & 1 deletion src/formbridge/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
nothing and loads no GUI toolkit.
"""

__version__ = "0.1.2"
__version__ = "0.1.3"
6 changes: 6 additions & 0 deletions src/formbridge/forms/parameter_info_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ def register(
"Inline dataclass widgets can only be registered for dataclass types; "
f"got {dataclass_type!r}."
)
registered = cls._factories.get(dataclass_type)
if registered is not None and registered is not widget_factory:
raise ValueError(
f"{dataclass_type.__qualname__} already has an inline widget factory "
f"({registered!r}); it cannot also use {widget_factory!r}."
)
cls._factories[dataclass_type] = widget_factory

@classmethod
Expand Down
6 changes: 6 additions & 0 deletions src/formbridge/protocols/preview_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ def register(
config_type: Config class to format
formatter: Formatter function taking (config, field_name) -> str
"""
registered = cls._formatters.get(config_type)
if registered is not None and registered is not formatter:
raise ValueError(
f"{config_type.__qualname__} already has a preview formatter "
f"({registered!r}); it cannot also use {formatter!r}."
)
cls._formatters[config_type] = formatter

@classmethod
Expand Down
15 changes: 15 additions & 0 deletions tests/test_preview_formatter_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ class BaseConfig:
assert PreviewFormatterRegistry.format_field(lazy_type(), "value") == "base"


def test_preview_formatter_registration_rejects_a_second_formatter_for_one_type() -> None:
class OnceConfig:
pass

def formatter(_config: object, field_name: str) -> str:
return f"first:{field_name}"

PreviewFormatterRegistry.register(OnceConfig, formatter)
PreviewFormatterRegistry.register(OnceConfig, formatter)

with pytest.raises(ValueError, match="OnceConfig already has a preview formatter"):
PreviewFormatterRegistry.register(OnceConfig, lambda _config, _field_name: "second")
assert PreviewFormatterRegistry.format_field(OnceConfig(), "value") == "first:value"


def test_group_heading_default_reads_the_objectstate_declaration() -> None:
from objectstate.lazy_factory import abbreviation, get_group_abbreviation

Expand Down
Loading