Skip to content

Commit

Permalink
feature: add tsm_mapper transmutator
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Feb 28, 2024
1 parent 5928eba commit 70bf325
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 8 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,14 @@ schema = ...
- `tsm_unique_only` - Preserve only unique values from a list. Works only with lists.



The default transmutator must receive at least one mandatory argument - `field` object. Field contains few properties: `field_name`, `value` and `type`.

There is a possibility to provide more arguments to a validator like in `tsm_get_nested`. For this use a nested array with first item transmutator and other - arguments to it.

- `tsm_mapper` - Map current value to the mapping dict

Map a value to another value. The current value must serve as a key within the mapping dictionary, while the new value will represent the updated value

### Keywords
1. `map_to` (`str`) - changes the `field.name` in result dict.
2. `validators` (`list[str]`) - a list of transmutators that will be applied to a `field.value`. A transmutator could be a `string` or a `list` where the first item must be transmutator name and others are arbitrary values. Example:
Expand Down
77 changes: 70 additions & 7 deletions ckanext/transmute/tests/test_transmutators.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ def test_trim_string_transmutator_with_not_integer_length(self):
root="Dataset",
)


def test_concat_transmutator_with_self(self):
data: dict[str, Any] = {
"identifier": "right-to-the-night-results",
Expand Down Expand Up @@ -287,9 +286,7 @@ def test_concat_transmutator_with_field_link_nested(self):
)

for res in result["resources"]:
assert (
res["title"] == f"{result['title']} {res['format'].upper()}"
)
assert res["title"] == f"{result['title']} {res['format'].upper()}"

def test_unique_only(self):
"""You can skip using $self if you want for some reason"""
Expand Down Expand Up @@ -358,9 +355,7 @@ def test_default_allows_falsy_values(self, default):

tsm_schema = build_schema(
{
"field_name": {
"default": default
},
"field_name": {"default": default},
}
)

Expand All @@ -372,3 +367,71 @@ def test_default_allows_falsy_values(self, default):
)

assert result == {"field_name": default}

def test_mapper_with_mapped_value(self):
data: dict[str, Any] = {"language": "eng"}

tsm_schema = build_schema(
{
"language": {
"validators": [
["tsm_mapper", {"eng": "English"}, "Spanish"],
],
},
}
)

result = call_action(
"tsm_transmute",
data=data,
schema=tsm_schema,
root="Dataset",
)

assert result["language"] == "English"


def test_mapper_without_mapped_value(self):
data: dict[str, Any] = {"language": "ua"}

tsm_schema = build_schema(
{
"language": {
"validators": [
["tsm_mapper", {"eng": "English"}, "Spanish"],
],
},
}
)

result = call_action(
"tsm_transmute",
data=data,
schema=tsm_schema,
root="Dataset",
)

assert result["language"] == "Spanish"

def test_mapper_without_default(self):
data: dict[str, Any] = {"language": "ua"}

tsm_schema = build_schema(
{
"language": {
"validators": [
["tsm_mapper", {"eng": "English"}],
],
},
}
)

with pytest.raises(TransmutatorError) as e:
call_action(
"tsm_transmute",
data=data,
schema=tsm_schema,
root="Dataset",
)

assert e.value.error == "mapper() missing 1 required positional argument: 'default'"
22 changes: 22 additions & 0 deletions ckanext/transmute/transmutators.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,25 @@ def unique_only(field: Field) -> Field:
raise df.Invalid(tk._("Field value must be an array"))
field.value = list(set(field.value))
return field


@transmutator
def mapper(field: Field, mapping: dict[Any, Any], default: Any) -> Field:
"""Map a value with a new value. The initial value must serve as a key within
a mapping dictionary, while the dic value will represent the updated value.
In cases where the key does not exist within the mapping, a default value will be employed.
Args:
field (Field): Field object
mapping (dict[Any, Any]): A dictionary representing the mapping of values.
default (Any): The default value to be used when the key is not found in the mapping.
Returns:
Field: the same Field with new value
"""
new_value = mapping.get(field.value, default)

field.value = new_value

return field

0 comments on commit 70bf325

Please sign in to comment.