Skip to content

✨ Add the dynamic function links_from_filter - #1984

Open
PhilipPartsch wants to merge 2 commits into
useblocks:masterfrom
PhilipPartsch:links-from-filter
Open

PhilipPartsch wants to merge 2 commits into
useblocks:masterfrom
PhilipPartsch:links-from-filter

Conversation

@PhilipPartsch

Copy link
Copy Markdown
Contributor

Adds a built-in dynamic function, links_from_filter, which links a need to every need that passes a filter string, and fixes three bugs found while writing it.

.. spec:: Collector
   :id: SPEC_1
   :links: [[links_from_filter("type == 'req' and status == 'open'")]]

links_from_filter

links_from_filter(filter, include_self=False, include_parts=False, allow_empty=False)
  • Which needs are searched: every need, and with include_parts=True also every need's parts. A matching part is linked as <need>.<part>.
  • Self-exclusion: the need that contains the call is left out, and so are its own parts, unless include_self=True.
  • Empty result: if nothing is linked, a new needs.links_from_filter warning is emitted, unless allow_empty=True. It has its own subtype so a project can suppress it without hiding needs.dynamic_function failures. If only the calling need matched, the message says it was excluded and names include_self=True.
  • Empty filter: an empty or blank filter raises (reported as needs.dynamic_function), because it would otherwise link to every need in the project.
  • current_need[...] and c.this_doc() work in the filter. For example, c.this_doc() and sections == current_need["sections"] links to the needs in the same chapter of the same file.
  • Known limitation, stated in the docstring: dynamic functions are resolved need by need. A filter that reads a field which is itself a dynamic function on another need sees it resolved or unresolved, depending on need order.

The docstring is the user documentation, rendered in docs/dynamic_functions.rst, with a syntax-example.

Bug fixes

  • copy with upper=True or lower=True on a list option cased the list's printed form. copy("tags", "SRC_1", upper=True) on tags alpha, beta gave one tag, "['ALPHA', 'BETA']". It now gives ALPHA and BETA. This changes output, and the changelog marks it so.
  • c.this_doc() in copy's filter always failed with this_doc can not be used in this context. copy then silently copied from the current need instead. The filter now gets the current need's document as origin_docname, as links_from_filter does.
  • :ndf: with a function that returns links (links_from_content, and now links_from_filter) printed NeedLink(id='REQ_1', part=None, condition=None). It now prints REQ_1, or REQ_1.p1 for a part.

Tests

All in tests/test_dynamic_functions.py, as inline projects:

  • links_from_filter:
    • several matches in document order, and their back-links;
    • self-exclusion and include_self;
    • parts with and without include_parts, including the calling need's own parts;
    • allow_empty;
    • the empty-filter error;
    • the no-match and only-self warnings;
    • :ndf: output.
  • Two worked examples:
    • linking to every system requirement in the calling need's directory, across files, which replaces a hand-written project function;
    • linking to needs in the same file and chapter with c.this_doc().
  • copy: casing a list, and c.this_doc() in its filter.

Checks

  • uv run poe test-needs -n 4: 1812 passed, 11 skipped; snapshots unchanged
  • UV_PYTHON=3.12 uv run --no-sync poe test-needs-sphinx9 tests/schema: 182 passed
  • uv run poe lint: passed
  • uv run poe typecheck: passed
  • uv run poe docs-needs -E: exit 0

links_from_filter links a need to every need that passes a filter string.
The need that contains the call, and its own parts, are left out unless
include_self=True; parts are only searched with include_parts=True. An
empty result emits a needs.links_from_filter warning unless allow_empty=True.

Also fixes three bugs found on the way:

- copy with upper/lower now cases a list option item by item, instead of
  casing the list's printed form into one value.
- c.this_doc() now works in copy's filter: the filter is evaluated with the
  document of the current need.
- ndf shows the links a dynamic function returns as need IDs, not as
  NeedLink(...) reprs.
@github-actions github-actions Bot added the pkg: sphinx-needs The sphinx-needs distribution (packages/sphinx-needs): its code, tests and docs label Sep 29, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: sphinx-needs The sphinx-needs distribution (packages/sphinx-needs): its code, tests and docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant