Skip to content

Commit

Permalink
Version field uses number input type (#278)
Browse files Browse the repository at this point in the history
* Version field uses number input type

* Fix test
  • Loading branch information
mmwinther authored Apr 9, 2024
1 parent 8c11263 commit 56590a2
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 81 deletions.
6 changes: 3 additions & 3 deletions src/datadoc/frontend/components/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,12 @@ def build_dataset_edit_section(
dbc.Form(
[
i.render(
{
component_id={
"type": DATASET_METADATA_INPUT,
"id": i.identifier,
},
language,
dataset,
language=language,
metadata=dataset,
)
for i in metadata_inputs
],
Expand Down
95 changes: 32 additions & 63 deletions src/datadoc/frontend/fields/display_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

import logging
import re
import typing as t
from abc import ABC
from abc import abstractmethod
from dataclasses import dataclass
from dataclasses import field
from typing import TYPE_CHECKING
from typing import Any

import ssb_dash_components as ssb
from dash import dcc

from datadoc import state
from datadoc.enums import SupportedLanguages
Expand All @@ -22,7 +21,6 @@
from enum import Enum

from dash.development.base_component import Component
from datadoc_model import model
from datadoc_model.model import LanguageStringType
from pydantic import BaseModel

Expand Down Expand Up @@ -53,15 +51,6 @@ def get_enum_options_for_language(
return dropdown_options


def empty_kwargs_factory() -> dict[str, t.Any]:
"""Initialize the field extra_kwargs.
We aren't allowed to directly assign a mutable type like a dict to
a dataclass field.
"""
return {}


def get_standard_metadata(metadata: BaseModel, identifier: str) -> MetadataInputTypes:
"""Get a metadata value from the model."""
return getattr(metadata, identifier)
Expand Down Expand Up @@ -117,34 +106,42 @@ def get_comma_separated_string(metadata: BaseModel, identifier: str) -> str:


@dataclass
class DisplayMetadata:
"""Controls for how a given metadata field should be displayed."""
class DisplayMetadata(ABC):
"""Controls how a given metadata field should be displayed."""

identifier: str
display_name: str
description: str
obligatory: bool = False
editable: bool = True
url: bool = False
multiple_language_support: bool = False
value_getter: Callable[[BaseModel, str], Any] = get_metadata_and_stringify
show_description: bool = True

@abstractmethod
def render(
self,
component_id: dict,
language: str,
metadata: BaseModel,
) -> Component:
"""Build a component."""
...


@dataclass
class MetadataInputField(DisplayMetadata):
"""Controls how a input field should be displayed."""
"""Controls how an input field should be displayed."""

type: str = "text"
extra_kwargs: dict[str, Any] = field(default_factory=empty_kwargs_factory)
value_getter: Callable[[BaseModel, str], Any] = get_metadata_and_stringify

def render(
self,
component_id: dict,
language: str, # noqa: ARG002 Required by Dash
language: str, # noqa: ARG002
metadata: BaseModel,
) -> ssb.Input:
"""Build component."""
"""Build an Input component."""
value = self.value_getter(metadata, self.identifier)
return ssb.Input(
label=self.display_name,
Expand All @@ -161,10 +158,8 @@ def render(

@dataclass
class MetadataDropdownField(DisplayMetadata):
"""Control how a Dropdown should be displayed."""
"""Controls how a Dropdown should be displayed."""

extra_kwargs: dict[str, Any] = field(default_factory=empty_kwargs_factory)
value_getter: Callable[[BaseModel, str], Any] = get_metadata_and_stringify
# fmt: off
options_getter: Callable[[SupportedLanguages], list[dict[str, str]]] = lambda _: [] # noqa: E731
# fmt: on
Expand All @@ -173,10 +168,10 @@ def render(
self,
component_id: dict,
language: str,
dataset: BaseModel,
metadata: BaseModel,
) -> ssb.Dropdown:
"""Build Dropdown component."""
value = self.value_getter(dataset, self.identifier)
value = self.value_getter(metadata, self.identifier)
return ssb.Dropdown(
header=self.display_name,
id=component_id,
Expand All @@ -190,30 +185,28 @@ def render(

@dataclass
class MetadataPeriodField(DisplayMetadata):
"""Control how fields which define a time period are displayed for Dataset.
"""Controls how fields which define a time period are displayed.
These are a special case since two fields have a relationship to one another.>
These are a special case since two fields have a relationship to one another.
"""

id_type: str = ""
extra_kwargs: dict[str, Any] = field(default_factory=empty_kwargs_factory)
value_getter: Callable[[BaseModel, str], Any] = get_date_metadata_and_stringify
type: str = "date"

def render(
self,
component_id: dict,
language: str, # noqa: ARG002 Required by Dash
dataset: BaseModel,
language: str, # noqa: ARG002
metadata: BaseModel,
) -> ssb.Input:
"""Build Input date component."""
value = self.value_getter(dataset, self.identifier)
value = self.value_getter(metadata, self.identifier)
component_id["type"] = self.id_type
return ssb.Input(
label=self.display_name,
id=component_id,
debounce=False,
type=self.type,
type="date",
disabled=not self.editable,
showDescription=self.show_description,
description=self.description,
Expand All @@ -226,20 +219,19 @@ def render(
class MetadataCheckboxField(DisplayMetadata):
"""Controls for how a checkbox metadata field should be displayed."""

extra_kwargs: dict[str, Any] = field(default_factory=empty_kwargs_factory)
value_getter: Callable[[BaseModel, str], Any] = get_standard_metadata

def render(
self,
variable_id: dict,
language: str, # noqa: ARG002 Required by Dash
variable: model.Variable,
component_id: dict,
language: str, # noqa: ARG002
metadata: BaseModel,
) -> ssb.Checkbox:
"""Build Checkbox component."""
value = self.value_getter(variable, self.identifier)
value = self.value_getter(metadata, self.identifier)
return ssb.Checkbox(
label=self.display_name,
id=variable_id,
id=component_id,
disabled=not self.editable,
value=value,
showDescription=self.show_description,
Expand All @@ -255,26 +247,3 @@ def render(
)

DatasetFieldTypes = MetadataInputField | MetadataDropdownField | MetadataPeriodField


@dataclass
class DisplayDatasetMetadata(DisplayMetadata):
"""Controls for how a given metadata field should be displayed.
Specific to dataset fields.
"""

extra_kwargs: dict[str, Any] = field(default_factory=empty_kwargs_factory)
component: type[Component] = dcc.Input
value_getter: Callable[[BaseModel, str], Any] = get_metadata_and_stringify


@dataclass
class DisplayDatasetMetadataDropdown(DisplayDatasetMetadata):
"""Include the possible options which a user may choose from."""

# fmt: off
options_getter: Callable[[SupportedLanguages], list[dict[str, str]]] = lambda _: [] # noqa: E731
# fmt: on
extra_kwargs: dict[str, Any] = field(default_factory=empty_kwargs_factory)
component: type[Component] = dcc.Dropdown
10 changes: 3 additions & 7 deletions src/datadoc/frontend/fields/display_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from datadoc import state
from datadoc.frontend.fields.display_base import DATASET_METADATA_DATE_INPUT
from datadoc.frontend.fields.display_base import DatasetFieldTypes
from datadoc.frontend.fields.display_base import DisplayDatasetMetadataDropdown
from datadoc.frontend.fields.display_base import MetadataDropdownField
from datadoc.frontend.fields.display_base import MetadataInputField
from datadoc.frontend.fields.display_base import MetadataPeriodField
Expand Down Expand Up @@ -162,7 +161,6 @@ class DatasetIdentifiers(str, Enum):
display_name="Register URI",
description="Lenke (URI) til register i registeroversikt (oversikt over alle registre meldt Datatilsynet (oppdatering foretas av sikkerhetsrådgiver))",
multiple_language_support=True,
url=True,
type="url",
),
DatasetIdentifiers.POPULATION_DESCRIPTION: MetadataInputField(
Expand All @@ -176,8 +174,8 @@ class DatasetIdentifiers(str, Enum):
identifier=DatasetIdentifiers.VERSION.value,
display_name="Versjon",
description="Versjon",
extra_kwargs={"type": "number", "min": 1},
obligatory=True,
type="number",
),
DatasetIdentifiers.VERSION_DESCRIPTION: MetadataInputField(
identifier=DatasetIdentifiers.VERSION_DESCRIPTION.value,
Expand Down Expand Up @@ -330,10 +328,8 @@ class DatasetIdentifiers(str, Enum):
+ NON_EDITABLE_DATASET_METADATA
)

DISPLAYED_DROPDOWN_DATASET_METADATA: list[DisplayDatasetMetadataDropdown] = [
m
for m in DISPLAYED_DATASET_METADATA
if isinstance(m, DisplayDatasetMetadataDropdown)
DISPLAYED_DROPDOWN_DATASET_METADATA: list[MetadataDropdownField] = [
m for m in DISPLAYED_DATASET_METADATA if isinstance(m, MetadataDropdownField)
]

OBLIGATORY_DATASET_METADATA_IDENTIFIERS: list[str] = [
Expand Down
3 changes: 0 additions & 3 deletions src/datadoc/frontend/fields/display_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ class VariableIdentifiers(str, Enum):
identifier=VariableIdentifiers.DEFINITION_URI.value,
display_name="Definition URI",
description="En lenke (URI) til variabelens definisjon i SSB (Vardok/VarDef)",
url=True,
obligatory=True,
type="url",
),
Expand Down Expand Up @@ -137,14 +136,12 @@ class VariableIdentifiers(str, Enum):
identifier=VariableIdentifiers.CLASSIFICATION_URI.value,
display_name="Kodeverkets URI",
description="Lenke (URI) til gyldige kodeverk (klassifikasjon eller kodeliste) i KLASS",
url=True,
type="url",
),
VariableIdentifiers.SENTINEL_VALUE_URI: MetadataInputField(
identifier=VariableIdentifiers.SENTINEL_VALUE_URI.value,
display_name="Spesialverdienes URI",
description="En lenke (URI) til en oversikt over 'spesialverdier' som inngår i variabelen.",
url=True,
type="url",
),
VariableIdentifiers.INVALID_VALUE_DESCRIPTION: MetadataInputField(
Expand Down
6 changes: 3 additions & 3 deletions tests/frontend/callbacks/test_dataset_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,19 +260,19 @@ def test_change_language_dataset_metadata_options_enums(
value = change_language_dataset_metadata(language)

for options in cast(list[list[dict[str, str]]], value[0:-1]):
assert all(list(d.keys()) == ["label", "value"] for d in options)
assert all(list(d.keys()) == ["title", "id"] for d in options)

member_names = {m.name for m in enum_for_options} # type: ignore [attr-defined]
values = [i for d in options for i in d.values()]
test_without_empty_option = options[1:]
if member_names.intersection(values):
assert {d["label"] for d in test_without_empty_option} == {
assert {d["title"] for d in test_without_empty_option} == {
e.get_value_for_language(
language,
)
for e in enum_for_options # type: ignore [attr-defined]
}
assert {d["value"] for d in test_without_empty_option} == {e.name for e in enum_for_options} # type: ignore [attr-defined]
assert {d["id"] for d in test_without_empty_option} == {e.name for e in enum_for_options} # type: ignore [attr-defined]


@patch(f"{DATASET_CALLBACKS_MODULE}.open_file")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def test_build_dataset_edit_section_input_component_props(
fields = edit_section.children[1].children
input_components = [element for element in fields if isinstance(element, ssb.Input)]
for item in input_components:
assert item.type in ("text", "url", "date")
assert item.type in ("text", "url", "date", "number")
for item in input_components:
if item.type in ("text", "url"):
assert item.debounce is True
Expand Down
1 change: 0 additions & 1 deletion tests/frontend/components/test_build_input_section.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ def test_build_input_fields_type_url(field_list, variable, language):
for element in input_section.children
if isinstance(element, ssb.Input) and element.type == "url"
]
assert all(item.url is True for item in variable_identifier_url)
assert all(item.debounce is True for item in elements_of_input_and_type_url)
for item1, item2 in zip(elements_of_input_and_type_url, variable_identifier_url):
assert item1.label == item2.display_name
Expand Down
11 changes: 11 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"""Tests for the utils module."""

import pathlib

import tomli
from datadoc_model import model

from datadoc.enums import SupportedLanguages
from datadoc.utils import calculate_percentage
from datadoc.utils import get_app_version
from datadoc.utils import get_display_values
from datadoc.utils import running_in_notebook

Expand All @@ -23,3 +27,10 @@ def test_get_display_values(
variable = model.Variable(name=language_object)
values = get_display_values(variable, SupportedLanguages.NORSK_BOKMÅL)
assert values["name"] == bokmål_name


def test_get_app_version():
with (pathlib.Path(__file__).parent.parent / "pyproject.toml").open("rb") as f:
pyproject = tomli.load(f)

assert get_app_version() == pyproject["tool"]["poetry"]["version"]

0 comments on commit 56590a2

Please sign in to comment.