Skip to content

Bug with Callable type for duplicate fixture detection #47

@Sanchoyzer

Description

@Sanchoyzer

It seems that the plugin doesn't fully support the Callable type for duplicate fixture detection. For all fixtures with Callable return type, the plugin displays a warning that there are duplicate fixtures.

Source code

from collections.abc import Callable

import pytest
from faker import Faker


class A:
    x: int

    def __init__(self, x: int) -> None:
        self.x = x


class B:
    y: str

    def __init__(self, y: str) -> None:
        self.y = y


@pytest.fixture(scope='session')
def faker() -> Faker:
    return Faker()


@pytest.fixture
def factory_A(faker: Faker) -> Callable[[], A]:
    def inner() -> A:
        return A(x=faker.pyint())

    return inner


@pytest.fixture
def factory_B(faker: Faker) -> Callable[[], B]:
    def inner() -> B:
        return B(y=faker.pystr())

    return inner


def test_factories(factory_A: Callable[[], A], factory_B: Callable[[], B]) -> None:
    object_a = factory_A()
    object_b = factory_B()
    assert object_a.x != object_b.y

Run

pytest test_1.py --dup-fixtures

You may have some duplicate fixtures:
Fixture name: factory_B, location: test_1.py:35
Fixture name: factory_A, location: test_1.py:27

Versions

pytest==8.1.1
pytest-deadfixtures==2.2.1

Maybe the same_fixture function should be changed. From

def same_fixture(one, two):
    def result_same_type(a, b):
        return isinstance(a.result, type(b.result))

    def same_result(a, b):
        if not a.result or not b.result:
            return False
        if hasattr(a.result, "__dict__") or hasattr(b.result, "__dict__"):
            return a.result.__dict__ == b.result.__dict__
        return a.result == b.result

    def same_loc(a, b):
        return a.relpath == b.relpath

    return result_same_type(one, two) and same_result(one, two) and not same_loc(one, two)

to

def same_fixture(one, two):
    def result_same_type(a, b):
        return isinstance(a.result, type(b.result))

    def same_result(a, b):
        if not a.result or not b.result:
            return False
        if getattr(a.result, "__dict__", None) and getattr(b.result, "__dict__", None):  # here
            return a.result.__dict__ == b.result.__dict__
        return a.result == b.result

    def same_loc(a, b):
        return a.relpath == b.relpath

    return result_same_type(one, two) and same_result(one, two) and not same_loc(one, two)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions