Skip to content

Commit

Permalink
re-implement view indexing to include parts
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisjsewell committed Sep 30, 2024
1 parent 10bbb01 commit 64a6d92
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 156 deletions.
75 changes: 47 additions & 28 deletions sphinx_needs/filter_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,31 +281,36 @@ def _analyze_and_apply_expr(
:returns: the needs (potentially filtered),
and a boolean denoting if it still requires python eval filtering
"""
if isinstance((name := expr), ast.Name):
if isinstance(expr, (ast.Str, ast.Constant)):
if isinstance(expr.s, (str, bool)):
# "value" / True / False
return needs if expr.s else needs.filter_ids([]), False

elif isinstance(expr, ast.Name):
# x
if name.id == "is_external":
if expr.id == "is_external":
return needs.filter_is_external(True), False

Check warning on line 292 in sphinx_needs/filter_common.py

View check run for this annotation

Codecov / codecov/patch

sphinx_needs/filter_common.py#L292

Added line #L292 was not covered by tests

elif isinstance((compare := expr), ast.Compare):
elif isinstance(expr, ast.Compare):
# <expr1> <comp> <expr2>
if len(compare.ops) == 1 and isinstance(compare.ops[0], ast.Eq):
if len(expr.ops) == 1 and isinstance(expr.ops[0], ast.Eq):
# x == y
if (
isinstance(compare.left, ast.Name)
and len(compare.comparators) == 1
and isinstance(compare.comparators[0], (ast.Str, ast.Constant))
isinstance(expr.left, ast.Name)
and len(expr.comparators) == 1
and isinstance(expr.comparators[0], (ast.Str, ast.Constant))
):
# x == "value"
field = compare.left.id
value = compare.comparators[0].s
field = expr.left.id
value = expr.comparators[0].s
elif (
isinstance(compare.left, (ast.Str, ast.Constant))
and len(compare.comparators) == 1
and isinstance(compare.comparators[0], ast.Name)
isinstance(expr.left, (ast.Str, ast.Constant))
and len(expr.comparators) == 1
and isinstance(expr.comparators[0], ast.Name)
):
# "value" == x
field = compare.comparators[0].id
value = compare.left.s
field = expr.comparators[0].id
value = expr.left.s
else:
return needs, True

Expand All @@ -319,35 +324,35 @@ def _analyze_and_apply_expr(
# status == "value"
return needs.filter_statuses([value]), False

elif len(compare.ops) == 1 and isinstance(compare.ops[0], ast.In):
elif len(expr.ops) == 1 and isinstance(expr.ops[0], ast.In):
# <expr1> in <expr2>
if (
isinstance(compare.left, ast.Name)
and len(compare.comparators) == 1
and isinstance(compare.comparators[0], (ast.List, ast.Tuple, ast.Set))
isinstance(expr.left, ast.Name)
and len(expr.comparators) == 1
and isinstance(expr.comparators[0], (ast.List, ast.Tuple, ast.Set))
and all(
isinstance(elt, (ast.Str, ast.Constant))
for elt in compare.comparators[0].elts
for elt in expr.comparators[0].elts
)
):
values = [elt.s for elt in compare.comparators[0].elts] # type: ignore[attr-defined]
if compare.left.id == "id":
values = [elt.s for elt in expr.comparators[0].elts] # type: ignore[attr-defined]
if expr.left.id == "id":
# id in ["a", "b", ...]
return needs.filter_ids(values), False
if compare.left.id == "status":
if expr.left.id == "status":
# status in ["a", "b", ...]
return needs.filter_statuses(values), False
elif compare.left.id == "type":
elif expr.left.id == "type":

Check warning on line 345 in sphinx_needs/filter_common.py

View check run for this annotation

Codecov / codecov/patch

sphinx_needs/filter_common.py#L345

Added line #L345 was not covered by tests
# type in ["a", "b", ...]
return needs.filter_types(values), False

Check warning on line 347 in sphinx_needs/filter_common.py

View check run for this annotation

Codecov / codecov/patch

sphinx_needs/filter_common.py#L347

Added line #L347 was not covered by tests
elif (
isinstance(compare.left, (ast.Str, ast.Constant))
and len(compare.comparators) == 1
and isinstance(compare.comparators[0], ast.Name)
and compare.comparators[0].id == "tags"
isinstance(expr.left, (ast.Str, ast.Constant))
and len(expr.comparators) == 1
and isinstance(expr.comparators[0], ast.Name)
and expr.comparators[0].id == "tags"
):
# "value" in tags
return needs.filter_has_tag([compare.left.s]), False
return needs.filter_has_tag([expr.left.s]), False

elif isinstance((and_op := expr), ast.BoolOp) and isinstance(and_op.op, ast.And):
# x and y and ...
Expand All @@ -368,6 +373,7 @@ def filter_needs_view(
*,
location: tuple[str, int | None] | nodes.Node | None = None,
append_warning: str = "",
strict_eval: bool = False,
) -> list[NeedsInfoType]:
if not filter_string:
return list(needs.values())
Expand All @@ -382,6 +388,12 @@ def filter_needs_view(
if not requires_eval:
return list(needs.values())

if strict_eval:
# this is mainly used for testing purposes, to check if expression analysis is working
raise RuntimeError(

Check warning on line 393 in sphinx_needs/filter_common.py

View check run for this annotation

Codecov / codecov/patch

sphinx_needs/filter_common.py#L393

Added line #L393 was not covered by tests
f"Strict eval mode, but no simple filter found: {filter_string!r}"
)

return filter_needs(
needs.values(),
config,
Expand All @@ -400,6 +412,7 @@ def filter_needs_parts(
*,
location: tuple[str, int | None] | nodes.Node | None = None,
append_warning: str = "",
strict_eval: bool = False,
) -> list[NeedsInfoType]:
if not filter_string:
return list(needs)
Expand All @@ -414,6 +427,12 @@ def filter_needs_parts(
if not requires_eval:
return list(needs)

if strict_eval:
# this is mainly used for testing purposes, to check if expression analysis is working
raise RuntimeError(

Check warning on line 432 in sphinx_needs/filter_common.py

View check run for this annotation

Codecov / codecov/patch

sphinx_needs/filter_common.py#L432

Added line #L432 was not covered by tests
f"Strict eval mode, but no simple filter found: {filter_string!r}"
)

return filter_needs(
needs,
config,
Expand Down
Loading

0 comments on commit 64a6d92

Please sign in to comment.