Skip to content

Commit

Permalink
[#56] Add spatial_resolution_in_meters
Browse files Browse the repository at this point in the history
This required a new scheming_multiple_number validator, adapted from
scheming_multiple_text
  • Loading branch information
amercader committed Jun 4, 2024
1 parent afb74d1 commit c6fc970
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 9 deletions.
6 changes: 6 additions & 0 deletions ckanext/dcat/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
dcat_auth,
)
from ckanext.dcat import utils
from ckanext.dcat.validators import dcat_validators


CUSTOM_ENDPOINT_CONFIG = 'ckanext.dcat.catalog_endpoint'
Expand All @@ -39,6 +40,7 @@ class DCATPlugin(p.SingletonPlugin, DefaultTranslation):
p.implements(p.ITranslation, inherit=True)
p.implements(p.IClick)
p.implements(p.IBlueprint)
p.implements(p.IValidators)

# IClick

Expand Down Expand Up @@ -102,6 +104,10 @@ def get_auth_functions(self):
'dcat_catalog_search': dcat_auth,
}

# IValidators
def get_validators(self):
return dcat_validators

# IPackageController

# CKAN < 2.10 hooks
Expand Down
9 changes: 4 additions & 5 deletions ckanext/dcat/schemas/dcat_ap_2.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,10 @@ dataset_fields:
- field_name: centroid
label: Centroid

#- field_name: spatial_resolution_in_meters
# label: Spatial resolution in meters
# preset: multiple_text
# validators: ignore_missing scheming_multiple_text
# TODO: scheming_multiple_decimal
- field_name: spatial_resolution_in_meters
label: Spatial resolution in meters
preset: multiple_text
validators: ignore_missing scheming_multiple_number

- field_name: access_rights
label: Access rights
Expand Down
4 changes: 0 additions & 4 deletions ckanext/dcat/tests/test_scheming_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
from ckanext.dcat.tests.utils import BaseSerializeTest, BaseParseTest


# TODO: tests for spatial coverage
# TODO: index "spatial" extra


@pytest.mark.usefixtures("with_plugins", "clean_db")
@pytest.mark.ckan_config("ckan.plugins", "dcat scheming_datasets")
@pytest.mark.ckan_config(
Expand Down
62 changes: 62 additions & 0 deletions ckanext/dcat/tests/test_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import json
import pytest

from ckantoolkit import StopOnError
from ckanext.dcat.validators import scheming_multiple_number


def test_scheming_multiple_number():

expected_value = [1.5, 2.0, 0.345]

key = ("some_number_field",)
errors = {key: []}

values = [
expected_value,
[1.5, 2, 0.345],
["1.5", "2", ".345"],
]
for value in values:
data = {key: value}
scheming_multiple_number({}, {})(key, data, errors, {})

assert data[key] == json.dumps(expected_value)


def test_scheming_multiple_number_single_value():

expected_value = [1.5]

key = ("some_number_field",)
errors = {key: []}

values = [
expected_value,
1.5,
"1.5",
]
for value in values:
data = {key: value}
scheming_multiple_number({}, {})(key, data, errors, {})

assert data[key] == json.dumps(expected_value)


def test_scheming_multiple_number_wrong_value():

key = ("some_number_field",)
errors = {key: []}

values = [
["a", 2, 0.345],
["1..5", "2", ".345"],
]
for value in values:
with pytest.raises(StopOnError):
data = {key: value}
scheming_multiple_number({}, {})(key, data, errors, {})

assert errors[key][0].startswith("invalid type for repeating number")

errors = {key: []}
74 changes: 74 additions & 0 deletions ckanext/dcat/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import numbers
import json

from ckantoolkit import (
missing,
StopOnError,
_,
)
from ckanext.scheming.validation import scheming_validator


@scheming_validator
def scheming_multiple_number(field, schema):
"""
Accept repeating numbers input in the following forms and convert to a
json list of decimal values for storage. Also act like scheming_required
to check for at least one non-empty string when required is true:
1. a list of numbers, eg.
[22, 1.3]
2. a single number value to allow single text fields to be
migrated to repeating numbers
33.4
"""

def _scheming_multiple_number(key, data, errors, context):
# just in case there was an error before our validator,
# bail out here because our errors won't be useful
if errors[key]:
return

value = data[key]
# 1. list of strings or 2. single string
if value is not missing:
if not isinstance(value, list):
try:
value = [float(value)]
except ValueError:
errors[key].append(_("expecting list of numbers"))
raise StopOnError

out = []
for element in value:
if not element:
continue
try:
element = float(element)
except ValueError:
errors[key].append(
_("invalid type for repeating number: %r") % element
)
continue

out.append(element)

if errors[key]:
raise StopOnError

data[key] = json.dumps(out)

if (data[key] is missing or data[key] == "[]") and field.get("required"):
errors[key].append(_("Missing value"))
raise StopOnError

return _scheming_multiple_number


dcat_validators = {
"scheming_multiple_number": scheming_multiple_number,
}

0 comments on commit c6fc970

Please sign in to comment.