Skip to content

Commit

Permalink
chore(BACK-8009): update slices support (#144)
Browse files Browse the repository at this point in the history
- start and end are optional
- end is exclusive
  • Loading branch information
jnicoulaud-ledger authored Nov 15, 2024
1 parent dd4ef92 commit 0f0228b
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 10 deletions.
20 changes: 13 additions & 7 deletions src/erc7730/model/paths/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,30 @@ class ArraySlice(Model):
description="The path component type identifier (discriminator for path components discriminated union).",
)

start: ArrayIndex = PydanticField(
start: ArrayIndex | None = PydanticField(
default=None,
title="Slice Start Index",
description="The start index of the slice. Must be lower than the end index.",
description="The start index of the slice (inclusive). Must be lower than the end index. If unset, slice "
"starts from the beginning of the array.",
)

end: ArrayIndex = PydanticField(
end: ArrayIndex | None = PydanticField(
default=None,
title="Slice End Index",
description="The end index of the slice. Must be greater than the start index.",
description="The end index of the slice (exclusive). Must be greater than the start index. If unset, slice "
"ends at the end of the array.",
)

@model_validator(mode="after")
def _validate(self) -> Self:
if self.start > self.end:
raise ValueError("Array slice start index must be lower than end index.")
if (start := self.start) is None or (end := self.end) is None:
return self
if 0 <= end <= start or end <= start < 0:
raise ValueError("Array slice start index must be strictly lower than end index.")
return self

def __str__(self) -> str:
return f"[{self.start}:{self.end}]"
return f"[{'' if self.start is None else self.start}:{'' if self.end is None else self.end}]"


class Array(Model):
Expand Down
9 changes: 8 additions & 1 deletion src/erc7730/model/paths/path_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
array: "[]"
array_index: /-?[0-9]+/
array_element: "[" array_index "]"
array_slice: "[" array_index ":" array_index "]"
slice_array_index: array_index?
array_slice: "[" slice_array_index ":" slice_array_index "]"
""",
start="path",
)
Expand All @@ -60,6 +61,12 @@ def array_element(self, ast: Any) -> ArrayElement:
(value,) = ast
return ArrayElement(index=value)

def slice_array_index(self, ast: Any) -> ArrayIndex | None:
if len(ast) == 1:
(value,) = ast
return value
return None

def array_slice(self, ast: Any) -> ArraySlice:
(start, end) = ast
return ArraySlice(start=start, end=end)
Expand Down
8 changes: 6 additions & 2 deletions tests/model/paths/test_path_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ def test_valid_input_container_path() -> None:

def test_valid_input_data_path_absolute() -> None:
_test_valid_input_path(
string="#.params.[].[-2].[1:5].amountIn",
string="#.params.[].[-2].[1:5].[:5].[5:].amountIn",
obj=DataPath(
absolute=True,
elements=[
Field(identifier="params"),
Array(),
ArrayElement(index=-2),
ArraySlice(start=1, end=5),
ArraySlice(start=None, end=5),
ArraySlice(start=5, end=None),
Field(identifier="amountIn"),
],
),
Expand All @@ -62,6 +64,8 @@ def test_valid_input_data_path_absolute() -> None:
{ "type": "array" },
{ "type": "array_element", "index": -2 },
{ "type": "array_slice", "start": 1, "end": 5 },
{ "type": "array_slice", "end": 5 },
{ "type": "array_slice", "start": 5 },
{ "type": "field", "identifier": "amountIn" }
]
}
Expand Down Expand Up @@ -211,7 +215,7 @@ def test_invalid_array_slice_inverted() -> None:
message = str(e.value)
assert "Invalid path" in message
assert "#.[1:0]" in message
assert "Array slice start index must be lower than end index" in message
assert "Array slice start index must be strictly lower than end index" in message


def test_invalid_array_slice_used_in_descriptor_path() -> None:
Expand Down

0 comments on commit 0f0228b

Please sign in to comment.