MatthewFlamm / pytest-homeassistant-custom-component

Package to automatically extract testing plugins from Home Assistant for custom component testing
MIT License
67 stars 10 forks source link

AttributeError: 'async_generator' object has no attribute 'data' #158

Closed Shulyaka closed 1 year ago

Shulyaka commented 1 year ago

Hi! I am having a strange error on my local environment, but not on github CI, even though the software versions are the same. I am not able to find out the source of the error. I have asyncio_mode = auto in my setup.cfg and the following fixture in my conftest.py:

@pytest.fixture(autouse=True)
def auto_enable_custom_integrations(enable_custom_integrations):
    """Enable custom integrations."""
    yield

And this is the error it gives me:

hass = <async_generator object _hass at 0x7f51df37efc0>

    @pytest.fixture
    def enable_custom_integrations(hass: HomeAssistant) -> None:
        """Enable custom integrations defined in the test dir."""
>       hass.data.pop(loader.DATA_CUSTOM_COMPONENTS)
E       AttributeError: 'async_generator' object has no attribute 'data'

.tox/py311/lib/python3.11/site-packages/pytest_homeassistant_custom_component/plugins.py:1145: AttributeError

Some details on the environment:

py311 installed: aiohttp==3.8.4,aiohttp-cors==0.7.0,aiosignal==1.3.1,aiosqlite==0.19.0,anyio==3.6.2,astral==2.2,astroid==2.15.4,async-generator==1.10,async-timeout==4.0.2,atomicwrites-homeas
sistant==1.4.1,attrs==22.2.0,Automat==22.10.0,awesomeversion==22.9.0,bcrypt==4.0.1,bellows==0.35.2,certifi==2022.12.7,cffi==1.15.1,charset-normalizer==3.1.0,ciso8601==2.3.0,click==8.1.3,clic
k-log==0.4.0,colored==1.4.4,coloredlogs==15.0.1,colorzero==2.0,constantly==15.1.0,coverage==7.2.3,crccheck==1.3.0,cryptography==40.0.2,decorator==5.1.1,dill==0.3.6,execnet==1.9.0,flake8==6.0
.0,freezegun==1.2.2,frozenlist==1.3.3,gpiozero==1.6.2,greenlet==2.0.2,h11==0.14.0,home-assistant-bluetooth==1.10.0,homeassistant==2023.5.0b6,httpcore==0.17.0,httpx==0.24.0,humanfriendly==10.
0,hyperlink==21.0.0,idna==3.4,ifaddr==0.1.7,incremental==22.10.0,iniconfig==2.0.0,isort==5.12.0,janus==1.0.0,Jinja2==3.1.2,jsonschema==4.17.3,lazy-object-proxy==1.9.0,lru-dict==1.1.8,MarkupS
afe==2.1.2,mccabe==0.7.0,mock-open==1.4.0,multidict==6.0.4,numpy==1.23.2,orjson==3.8.10,outcome==1.2.0,packaging==23.1,paho-mqtt==1.6.1,pipdeptree==2.7.0,platformdirs==3.5.0,pluggy==1.0.0,pu
re-pcapy3==1.0.1,pyasn1==0.5.0,pyasn1-modules==0.3.0,pycodestyle==2.10.0,pycparser==2.21,pydantic==1.10.7,pyflakes==3.0.1,PyJWT==2.6.0,pylint==2.17.3,pylint-per-file-ignores==1.1.0,pyOpenSSL
==23.1.0,pyrsistent==0.19.3,pyserial==3.5,pyserial-asyncio==0.6,pytest==7.3.1,pytest-aiohttp==1.0.4,pytest-asyncio==0.20.3,pytest-cov==3.0.0,pytest-homeassistant-custom-component==0.13.26,py
test-picked==0.4.6,pytest-socket==0.5.1,pytest-sugar==0.9.6,pytest-test-groups==1.0.3,pytest-timeout==2.1.0,pytest-tornasync==0.6.0.post2,pytest-trio==0.8.0,pytest-twisted==1.14.0,pytest-uno
rdered==0.5.2,pytest-xdist==3.2.1,pytest_freezer==0.4.6,python-dateutil==2.8.2,python-slugify==4.0.1,pytz==2023.3,pyusb==1.2.1,PyYAML==6.0,requests==2.28.2,requests-mock==1.10.0,respx==0.20.
1,service-identity==21.1.0,six==1.16.0,sniffio==1.3.0,sortedcontainers==2.4.0,SQLAlchemy==2.0.12,syrupy==4.0.0,termcolor==2.3.0,text-unidecode==1.3,tomlkit==0.11.8,tornado==6.3.1,tqdm==4.64.
0,trio==0.22.0,Twisted==22.10.0,typing_extensions==4.5.0,ulid-transform==0.7.0,urllib3==1.26.15,voluptuous==0.13.1,voluptuous-serialize==2.6.0,wrapt==1.15.0,xbee-humidifier==0.0.1,yarl==1.9.2,zha-quirks==0.0.98,zigpy==0.55.0,zigpy-deconz==0.21.0,zigpy-xbee==0.18.0,zigpy-zigate==0.11.0,zigpy-znp==0.11.1,zope.interface==6.0
py311 run-test-pre: PYTHONHASHSEED='777911075'
py311 run-test: commands[0] | py.test --cov custom_components/xbee_humidifier --cov-report= --timeout=9 --durations=10 -qq -p no:sugar
MatthewFlamm commented 1 year ago

This makes me think you have some problem with interaction between tests that runs in a different order or possibly a sync/async problem.

Is there a reason that this is not defined as a pytest fixture?

https://github.com/Shulyaka/xbee_humidifier/blob/b4c736f9e4eab958d48248959eba2a15163eb955/tests_ha/conftest.py#L125-L126

Shulyaka commented 1 year ago

Is there a reason that this is not defined as a pytest fixture?

No particular reason, I've done this before I learned about asyncio_mode = auto. I've just changed it to pytest but it made no difference.

This makes me think you have some problem with interaction between tests that runs in a different order or possibly a sync/async problem.

I am not experienced in this. How can I influence the order? Should I always add a sync test as the first test in each file so it could interpret the fixture as sync?

MatthewFlamm commented 1 year ago

You generally cannot influence the order of testing for pytest. If you do this means that your tests aren't properly firewalled from each other. I would try to fix that rather than specifiying an order for your tests.

A cause of this could be sync/async issues across tests, which manifests in weird ways with homeassistant. See #155 as another example. This line seems like it might be problematic, note that you are calling this from a sync function that is never awaited:

https://github.com/Shulyaka/xbee_humidifier/blob/b4c736f9e4eab958d48248959eba2a15163eb955/tests_ha/conftest.py#L85

Edit: Looking into this more, I'm not sure that this is correct interpretation, but this is the sort of mixup that could cause problems.

Shulyaka commented 1 year ago

This is very strange. I've converted one of the tests to sync (https://github.com/Shulyaka/xbee_humidifier/commit/04045476a7ebe13f785e9aa0f53afdbc5ba1ebd2) and surprisingly it worked! Even other unaffected tests that were previously failing!

I've had an impression that I am allowed to mix sync/async fixtures and that pytest should automatically await the async ones.

I don't understand it, but I am ready to close this issue.

Thank you!

MatthewFlamm commented 1 year ago

I'm not so sure that this is the right fix, but you might have confirmed that this is a sync/async issue somewhere in either your tests or your code.

twhittock commented 1 year ago

For others who had a similar issue, I found using --asyncio-mode=auto on the commandline stopped the issue occurring. It seems this only works if you use asyncio only, no other async libs.