Skip to content
Back to top
View this page
Edit this page

# Filtering needs

The filtering of needs and need parts is supported consistently across numerous directives and roles, either by using filter options or by using a filter string.

## Filter options

The following filter options are supported by directives:

> - needlist

> - needtable

> - needflow

> - needpie

> - needextend

Related to the used directive and its representation, the filter options create a list of needs, which match the filters for status, tags, types and filter.

For :status:, :tags: and :types: values are separated by “;”. :filter: gets evaluated.

The logic, if a need belongs to the final result list, is as followed:

    status = (open OR in_progress) AND tags = (user OR login) AND types = (req OR spec) AND eval(filter) is True

### status

Use the status option to filter needs by their status.

You can easily filter for multiple statuses by separating them by “;”. Example: open; in progress; reopen.

Show example

Example 1

    .. needlist::
       :status: open
       :show_status:

xyz_123: My requirement with custom options (open)
S_B4B62: Sub-Need on level 2 with status option set (open)
ID123: User needs to login (open)
SP_INT: Interfaces (open)
JINJAID125: Nested Spec Need (open)
JINJAID126: First Spec Need (open)
STYLE_006: My automatically styled requirement (open)
TEMPL_SPEC: My specification (open)
extend_test_003: needextend Example 3 (open)
extend_test_004: needextend Example 4 (open)
extend_test_005: needextend Example 5 (open)
extend_test_006: needextend Example 6 (open)
EX_ROW_2: Not implemented spec (open)
df_1: my test requirement (open)
copy_1: copy-example (open)
copy_2: copy-example implementation (open)
R_2A9D0: Requirement A (open)
S_01A67: Specification B (open)
R_F4722: My first requirement (open)
EX_CLEAN: CLEAN layout (open)
EX_COMPLETE: COMPLETE layout (open)
EX_FOCUS: FOCUS layout (open)
EX_CLEAN_L: CLEAN_L layout (open)
EX_CLEAN_R: CLEAN_R layout (open)
EX_CLEAN_LP: CLEAN_LP layout (open)
EX_CLEAN_RP: CLEAN_RP layout (open)
EX_FOCUS_F: FOCUS_F layout (open)
EX_FOCUS_L: FOCUS_L layout (open)
EX_FOCUS_R: FOCUS_R layout (open)
EX_DEBUG: DEBUG layout (open)
IMAGE_EXAMPLE: My test spec (open)
EX_REQ_1: A normal requirement (open)
EX_REQ_2: A more complex and highlighted requirement (open)
EX_REQ_3: A focused requirement (open)
EX_REQ_4: A custom requirement with picture (open)
EX_REQ_5: A requirement with a permalink (open)
roles_req_1: Sliced Bread (open)
my_car_1: Car must be awesome (open)
1: Car must be awesome (open)
2: Car must be awesome (open)
awesome_3: Car must be awesome (open)
T_003: Unit test 3 (open)
T_004: Unit test 4 (open)

### tags

tags allows to filter needs by one or multiple tags.

To search for multiple tags, simply separate them by using “;”.

Show example

Example 2

    .. needlist::
       :tags: main_example
       :show_tags:

No needs passed the filters

### types

For :types: the type itself or the human-readable type-title can be used as filter value.

Show example

Example 3

    .. needtable::
       :types: test

ID | Title | Status | Outgoing
--- | --- | --- | ---
copy_3 | test of specification and requirement |  | copy_2; copy_1
copy_4 | test of current_need value |  |
EXTRA_TEST_001 | Test of requirements |  |
NEED-D | Recalculate hash and compare |  |
T_0F2B7 | Level 4 |  |
T_5CCAA | Test 1 |  |
T_C3893 | Test for XY | implemented | OWN_ID_123; IMPL_01
T_EA5AF | Sub-Need on level 3 |  |
test_001 | test a requirement |  | test_req
test_arch_001 | Test Arch |  | req_arch_002; req_arch_003
test_flow_001 | A test case |  | spec_flow_002; spec_flow_001.subspec_1; spec_flow_001.subspec_2

### sort_by

Sorts the result list. Allowed values are `status` or any alphanumerical property.

Show example

Example 4

    .. needtable::
       :sort_by: id
       :status: open

ID | Title | Status | Outgoing
--- | --- | --- | ---
copy_1 | copy-example | open |
copy_2 | copy-example implementation | open | copy_1
df_1 | my test requirement | open |
EX_CLEAN | CLEAN layout | open | EX_COMPLETE; EX_FOCUS
EX_CLEAN_L | CLEAN_L layout | open |
EX_CLEAN_LP | CLEAN_LP layout | open |
EX_CLEAN_R | CLEAN_R layout | open |
EX_CLEAN_RP | CLEAN_RP layout | open |
EX_COMPLETE | COMPLETE layout | open | EX_CLEAN; EX_FOCUS
EX_DEBUG | DEBUG layout | open |
EX_FOCUS | FOCUS layout | open | EX_COMPLETE; EX_CLEAN
EX_FOCUS_F | FOCUS_F layout | open |
EX_FOCUS_L | FOCUS_L layout | open |
EX_FOCUS_R | FOCUS_R layout | open |
EX_REQ_1 | A normal requirement | open |
EX_REQ_2 | A more complex and highlighted requirement | open | EX_REQ_1
EX_REQ_3 | A focused requirement | open |
EX_REQ_4 | A custom requirement with picture | open |
EX_REQ_5 | A requirement with a permalink | open |
EX_ROW_2 | Not implemented spec | open |
extend_test_003 | needextend Example 3 | open | extend_test_004
extend_test_004 | needextend Example 4 | open |
extend_test_005 | needextend Example 5 | open |
extend_test_006 | needextend Example 6 | open | extend_test_003; extend_test_004
ID123 | User needs to login | open |
IMAGE_EXAMPLE | My test spec | open |
JINJAID125 | Nested Spec Need | open | JINJAID126
JINJAID126 | First Spec Need | open |
my_car_1 | Car must be awesome | open |
→ my_car_1.1 | → A top speed of 300 km/h | open |
→ my_car_1.2 | → An acceleration of 200 m/s² or much much more | open |
→ my_car_1.awesome_3 | → a turbo button | open |
R_2A9D0 | Requirement A | open |
R_F4722 | My first requirement | open |
roles_req_1 | Sliced Bread | open |
S_01A67 | Specification B | open |
S_B4B62 | Sub-Need on level 2 with status option set | open |
SP_INT | Interfaces | open |
STYLE_006 | My automatically styled requirement | open |
T_003 | Unit test 3 | open |
T_004 | Unit test 4 | open |
TEMPL_SPEC | My specification | open | STYLE_001; STYLE_002
xyz_123 | My requirement with custom options | open |

### filter

The filter option allows the definition of a complex query string, which gets evaluated via eval() in Python. Please see Filter string for more details.

## Filter string

The usage of a filter string is supported/required by:

- need_count

- needlist

- needtable

- needflow

- needpie

- needbar

- needuml / needarch

The filter string must be a valid Python expression:

Example 5

    :need_count:`type=='spec' and status != 'open'`

31

A filter string gets evaluated on needs and need_parts! A need_part inherits all options from its parent need, if the need_part has no own content for this option. E.g. the need_part content is kept, but the status attribute is taken from its parent need.

Note

The following attributes are kept inside a need_part: id, title, links_back

This allows to perform searches for need_parts, where search options are based on parent attributes.

The following filter will find all need_parts, which are part of a need, which has a tag called important.

Example 6

    :need_count:`is_part and 'car' in tags`

3

Inside a filter string all the fields of `NeedsInfoType` can be used, including.

Additional variables for need_part / np:

- id_parent as Python string, which contains the id of the parent need. (compare like `id_parent == "ABC_01"`)

- id_complete as Python string. Contains the concatenated ids of parent need and need_part. (compare like `id_complete != 'ABC_01.03'`)

Note

If extra options were specified using needs_extra_options then those will be available for use in filter expressions as well.

Finally, the following are available:

- search, as Python function for performing searches with a regular expression

- needs as `NeedsAndPartsListView` object, which contains all needs and need_parts.

If your expression is valid and it’s True, the related need is added to the filter result list. If it is invalid or returns False, the related need is not taken into account for the current filter.

Show example

Example 7: `filter` option

    needs:

    .. req:: Requirement A
       :tags: A; filter_example
       :status: open
       :hide:

    .. req:: Requirement B
       :tags: B; filter_example
       :status: closed
       :hide:

    .. spec:: Specification A
       :tags: A; filter_example
       :status: closed
       :hide:

    .. spec:: Specification B
       :tags: B; filter_example
       :status: open
       :hide:

    .. test:: Test 1
       :tags: filter_example
       :hide:

    .. needlist::
       :filter: "filter_example" in tags and (("B" in tags or ("spec" == type and "closed" == status)) or "test" == type)

needs:

R_22EB2: Requirement B
S_D70B0: Specification A
S_01A67: Specification B
T_5CCAA: Test 1

### Filtering for needs on the current page

Added in version 5.0.0.

Additionally, to common Filter string variables, the `c.this_doc()` function is for most directives, to filter for needs only in the same document as the directive.

Example 8

    .. needtable::
       :filter: c.this_doc()
       :style: datatables

ID | Title | Status | Outgoing
--- | --- | --- | ---
IMPL_01 | Implementation for specification |  | OWN_ID_123
OWN_ID_123 | Specification of a requirement |  | R_F4722
R_17EB4 | Set admin e-mail to admin@mycompany.com |  |
R_22EB2 | Requirement B | closed |
R_2A9D0 | Requirement A | open |
R_F4722 | My first requirement | open |
S_01A67 | Specification B | open |
S_D70B0 | Specification A | closed |
T_5CCAA | Test 1 |  |
T_C3893 | Test for XY | implemented | OWN_ID_123; IMPL_01

### search

search(pattern, variable) is based on Pythons re.search() function

The first parameter must be a regular expression pattern. The second parameter should be one of the above variables(status, id, content, ..)

Show example

This example uses a regular expressions to find all needs with an e-mail address in title.

Example 9

    .. req:: Set admin e-mail to admin@mycompany.com

    .. needlist::
       :filter: search("([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", title)

Requirement: Set admin e-mail to admin@mycompany.com R_17EB4

R_17EB4: Set admin e-mail to admin@mycompany.com

### Filter string performance

Added in version 4.0.0.

The filter string is evaluated by default for each need and need part and, therefore, can be become a performance bottleneck for projects with large numbers of needs.

To improve performance, certain common patterns are identified and optimized by the filter engine, and so using such patterns is recommended:

- `is_external` / `is_external == True` / `is_external == False`

- `id == 'value'` / `id == "value"` / `'value' == id` / `"value" == id`

- `id in ['value1', 'value2', ...]` / `id in ("value1", "value2", ...)`

- `type == 'value'` / `type == "value"` / `'value' == type` / `"value" == type`

- `type in ['value1', 'value2', ...]` / `type in ("value1", "value2", ...)`

- `status == 'value'` / `status == "value"` / `'value' == status` / `"value" == status`

- `status in ['value1', 'value2', ...]` / `status in ("value1", "value2", ...)`

- `'value' in tags` / `"value" in tags`

Also filters containing `and` will be split into multiple filters and evaluated separately for the above patterns. For example, `type == 'spec' and other == 'value'` will first be filtered performantly by `type == 'spec'` and then the remaining needs will be filtered by `other == 'value'`.

To guard against long running filters, the needs_filter_max_time configuration option can be used to set a maximum time limit for filter evaluation. Also see needs_uml_process_max_time, to guard against long running `needuml` / `needarch` processes containing filters.

To debug which filters are being used across your project and their run times, you can enable the needs_debug_filters configuration option.

Deprecated since version 4.0.0: The directive option `export_id` was previously used to export filter information in the `needs.json` file. This is deprecated and will be removed in a future version. Instead use the above needs_debug_filters configuration option.

## Filter code

Added in version 0.5.3.

The content of a needlist, needtable or needflow can be used to define own filters with the help of Python.

The used code must define a variable `results`, which must be a list and contains the filtered needs.

The code also has access to a variable called `needs`, which is a `NeedsAndPartsListView` instance.

Example 10

    .. needtable::
       :columns: id, title, type, links, links_back
       :style: table

       # Collect all requirements and specs,
       # which are linked to each other.

       results = []

       for need in needs.filter_types(["req"]):
          for links_id in need['links']:
             linked_need = needs.get_need(links_id)
             if linked_need and linked_need['type'] == 'spec':
                results.append(need)
                results.append(linked_need)

ID | Title | Type | Links | Links Back
--- | --- | --- | --- | ---
R_3C95C | Result 4 | req | sum_input_1; sum_input_3 |
R_D0791 | Result 3 | req | sum_input_1; sum_input_3 |
sum_input_1 | Do this | spec |  | R_D0791; R_3C95C
sum_input_3 | Do too much | spec |  | R_D0791; R_3C95C

This mechanism can also be a good alternative for complex filter strings to save performance. For example if a filter string is using list comprehensions to get access to linked needs.

If `filter code` is used, all other filter related options (like `status` or `filters`) are ignored.

Warning

This feature executes every given Python code. So be sure to trust the input/writers.

## Filter function

Added in version 0.7.3.

Nearly same behavior as Filter code, but the code gets read from an external python file and a function must be referenced.

option name:

  filter-func

default:

  None

Usage inside a rst file:

    .. needtable:: Filter function example
       :filter-func: filter_file.own_filter_code

The code of the referenced file `filter_file.py` with function `own_filter_code`:

    def own_filter_code(needs, results, **kwargs):
        for need in needs:
            if need["type"] == "test":
                results.append(need)

The function gets executed by Sphinx-Needs and it must provide two keyword arguments: `needs` and `results`.

Also the given package/module must be importable by the used Python environment. So it must be part of the Python Path variable. To update this, add `sys.path.insert(0, os.path.abspath("folder/to/filter_files"))` to your conf.py file.

### Arguments

Added in version 0.7.6.

Filter function are supporting arguments: `filter_file.own_filter_code(value_1,value_2)`.

Please note, that the part between `(...)` is just a comma separated list and each element will be given as string to the function.

The functions get the values as part of `**kwargs` with the name is `arg<pos>`, starting from `1`.

Example:

    .. needtable:: Filter function example
       :filter-func: filter_file.own_filter_code(1,2.5,open)

    def own_filter_code(needs, results, **kwargs):
        for need in needs:
            if int(need["price"]) > int(kwargs["arg1"]) or need["status"] == kwargs["arg3"]:
                results.append(need)

The function developer is responsible to perform any needed typecast.

### Needpie

needpie also supports filter-code. But instead of needs, a list of resulting numbers must be returned.

Example:

    .. needpie:: Filter code func pie
       :labels: new,done
       :filter-func: filter_code_func.my_pie_filter_code_args(new,done)

    def my_pie_filter_code_args(needs, results, **kwargs):
        cnt_x = 0
        cnt_y = 0
        for need in needs:
            if need["status"] == kwargs['arg1']:
                cnt_x += 1
            if need["status"] == kwargs['arg2']:
                cnt_y += 1

       results.append(cnt_x)
       results.append(cnt_y)

## Filter matches nothing

Depending on the directive used a filter that matches no needs may add text to inform that no needs are found.

The default text “No needs passed the filter”.

If this is not intended, add the option

### filter_warning

Add specific text with this option or add no text to display nothing. The default text will not be shown.

The specified output could be styled with the css class `needs_filter_warning`

## More Examples

Setup

Example 11

    .. req:: My first requirement
       :status: open
       :tags: requirement; test; awesome

       This is my **first** requirement!!

       .. note:: You can use any rst code inside it :)

    .. spec:: Specification of a requirement
       :id: OWN_ID_123
       :links: R_F4722

       Outgoing links of this spec: :need_outgoing:`OWN_ID_123`.

    .. impl:: Implementation for specification
       :id: IMPL_01
       :links: OWN_ID_123

       Incoming links of this spec: :need_incoming:`IMPL_01`.

    .. test:: Test for XY
       :status: implemented
       :tags: test; user_interface; python27
       :links: OWN_ID_123; IMPL_01

       This test checks :need:`IMPL_01` for :need:`OWN_ID_123` inside a
       Python 2.7 environment.

Requirement: My first requirement R_F4722
status: open tags: requirement, test, awesome links incoming: OWN_ID_123
This is my first requirement!! Note You can use any rst code inside it :)

Specification: Specification of a requirement OWN_ID_123
links outgoing: R_F4722 links incoming: IMPL_01, T_C3893
Outgoing links of this spec: R_F4722.

Implementation: Implementation for specification IMPL_01
links outgoing: OWN_ID_123 links incoming: T_C3893
Incoming links of this spec: T_C3893.

Test Case: Test for XY T_C3893
status: implemented tags: test, user_interface, python27 links outgoing: OWN_ID_123, IMPL_01
This test checks Implementation for specific... (IMPL_01) for Specification of a requirement (OWN_ID_123) inside a Python 2.7 environment.

Example 12: Filter result as table

    .. needtable::
       :tags: test
       :status: implemented; open

ID | Title | Status | Outgoing
--- | --- | --- | ---
df_1 | my test requirement | open |
R_F4722 | My first requirement | open |
T_C3893 | Test for XY | implemented | OWN_ID_123; IMPL_01

Example 13: Filter result as diagram

    .. needflow::
       :filter: "More Examples" == section_name