Skip to content
51 changes: 51 additions & 0 deletions docs/api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,57 @@ Returns True if the provided object is a function or callable and, if `check_pre

- `check_prefix`: if this boolean is True (default), the prefix will be checked. If False, any function will lead to a `True` result whatever its name.


### `@with_case_tags`
Comment thread
michele-riva marked this conversation as resolved.
Outdated

```python
@with_case_tags(*tags, # type: Any
):
```

This decorator can be applied to a class defining cases to apply multiple
`*tags` to all case methods defined thereby.

```python
@with_case_tags('tag_1', 'tag_2')
class CasesContainerClass:

def case_one(self, ...):
...

@case(tags='another_tag')
def case_two(self, ...):
...

@case(tags='tag_1')
def case_three(self, ...):
...
```

This is equivalent to:


```python
class CasesContainerClass:

@case(tags=('tag_1', 'tag_2'))
def case_one(self, ...):
...

@case(tags=('another_tag', 'tag_1', 'tag_2'))
def case_two(self, ...):
...

@case(tags=('tag_1', 'tag_2'))
def case_three(self, ...):
...
```

**Parameters:**

- `tags`: custom tags to be added to all case methods. See also [`@case(tags=...)`](#case).


### The `filters` submodule

This submodule contains symbols to help you create filters for `@parametrize_with_cases(filter=...)`.
Expand Down
6 changes: 6 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

### 3.8.6 - Add with_case_tags decorator
- Added the `with_case_tags` decorator for applying common tags to all cases
defined in a case class. Fixes [#351](https://github.com/smarie/python-pytest-cases/issues/351).
PR [#361](https://github.com/smarie/python-pytest-cases/issues/361)
by [@michele-riva](https://github.com/michele-riva).

Comment thread
michele-riva marked this conversation as resolved.
Outdated
### 3.8.6 - compatibility fix

- Fixed issue with legacy python 2.7 and 3.5. Fixes [#352](https://github.com/smarie/python-pytest-cases/issues/352).
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def test_bad_datasets(data, err_type, err_msg):
```


- the `has_tag` argument allows you to filter cases based on tags set on case functions using the `@case` decorator. See API reference of [`@case`](./api_reference.md#case) and [`@parametrize_with_cases`](./api_reference.md#parametrize_with_cases).
- the `has_tag` argument allows you to filter cases based on tags set on case functions using the `@case` decorator. See API reference of [`@case`](./api_reference.md#case) and [`@parametrize_with_cases`](./api_reference.md#parametrize_with_cases). Tags shared by multiple cases grouped inside a class may be added automatically to all cases using the [`@with_case_tags`](./api_reference.md#with_case_tags) decorator.


```python
Expand Down
2 changes: 1 addition & 1 deletion src/pytest_cases/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .fixture_parametrize_plus import pytest_parametrize_plus, parametrize_plus, parametrize, fixture_ref

from .case_funcs import case, copy_case_info, set_case_id, get_case_id, get_case_marks, \
get_case_tags, matches_tag_query, is_case_class, is_case_function
get_case_tags, matches_tag_query, is_case_class, is_case_function, with_case_tags
Comment thread
michele-riva marked this conversation as resolved.
from .case_parametrizer_new import parametrize_with_cases, THIS_MODULE, get_all_cases, get_parametrize_args, \
get_current_case_id, get_current_cases, get_current_params, CasesCollectionWarning

Expand Down
27 changes: 27 additions & 0 deletions src/pytest_cases/case_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,3 +366,30 @@ def is_case_function(f, # type: Any
except:
# GH#287: safe fallback
return False


def with_case_tags(*tags):
"""Attach `tags` to all cases defined in the decorated class."""
def _decorator(cls):
if is_case_function(cls):
raise ValueError(
'Cannot use with_case_tags on a case '
'function. Use the @case decorator instead.'
Comment thread
michele-riva marked this conversation as resolved.
Outdated
)
if not is_case_class(cls):
raise ValueError('with_case_tags can only be applied to classes '
Comment thread
michele-riva marked this conversation as resolved.
Outdated
'defining a collection of cases.')
for case_name in dir(cls):
case_ = getattr(cls, case_name)
if not is_case_function(case_): # Not a case
continue
try:
case_info = getattr(case_, CASE_FIELD)
except AttributeError:
# Not explicitly decorated with @case. Do so now.
case_ = case(case_)
case_info = getattr(case_, CASE_FIELD)
Comment thread
michele-riva marked this conversation as resolved.
Outdated
tags_to_add = tuple(t for t in tags if t not in case_info.tags)
case_info.add_tags(tags_to_add)
return cls
return _decorator
Comment thread
michele-riva marked this conversation as resolved.