Answer
Pytest does not allow the ids argument together with indirect=True in a single @pytest.mark.parametrize call.
Why the restriction exists
The ids list is processed before pytest resolves the fixture indicated by indirect. When indirect=True is set, the values passed to the test are the results of calling the fixture, not the raw parameters. Because the identifier must be known before the fixture runs, pytest treats the combination as unsupported and raises ValueError: 'indirect' cannot be used with 'ids'.
Recommended pattern
Embed the identifier directly in each parameter using pytest.param. This works with indirect=True because the identifier is attached to the raw value before the fixture is invoked.
import pytest
from datetime import datetime, timezone, timedelta
def make_tz_aware(offset_hours):
tz = timezone(timedelta(hours=offset_hours))
return lambda: datetime.now(tz)
@pytest.fixture
def tz_now(request):
# request.param is the factory returned by make_tz_aware
return request.param()
@pytest.mark.parametrize(
"tz_now",
[
pytest.param(make_tz_aware(-5), id="EST"),
pytest.param(make_tz_aware(0), id="UTC"),
pytest.param(make_tz_aware(9), id="JST"),
],
indirect=True,
)
def test_cross_region_date(tz_now):
assert tz_now.tzinfo is not None
# … assertions that depend on the zone …
Each test case now appears in the output as test_cross_region_date[EST], [UTC], [JST].
Alternative: fixture‑level ids
If the identifier depends only on the raw parameter (not on the fixture result), you can move the ids to the fixture definition:
@pytest.fixture(params=[-5, 0, 9], ids=lambda o: { -5: "EST", 0: "UTC", 9: "JST" }[o])
def tz_now(request):
offset = request.param
tz = timezone(timedelta(hours=offset))
return datetime.now(tz)
def test_cross_region_date(tz_now):
assert tz_now.tzinfo is not None
This achieves the same readable names without needing indirect in the parametrize decorator.
Checking your environment
To confirm that the workaround works for you, run:
pytest --collect-only test_example.py::test_cross_region_date
You should see the three test variants with the expected IDs.
Future support
As of pytest 8.0 the restriction remains; the development team has indicated that combining ids with indirect would require a redesign of the parametrization pipeline. No timeline has been announced, so relying on a future lift is not advisable.
If you are using a version older than pytest 6.0 and notice different behavior, please let us know the exact pytest version and the full traceback; that information would change the recommendation.