Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] @beartype + Django = *a whole lotta nuthin'* #322

Open
leycec opened this issue Feb 10, 2024 · 6 comments
Open

[Feature Request] @beartype + Django = *a whole lotta nuthin'* #322

leycec opened this issue Feb 10, 2024 · 6 comments

Comments

@leycec
Copy link
Member

leycec commented Feb 10, 2024

Boss-tier @harvymudd ML guru @sunildkumar (Sunil Kumar) reports over at @beartype's sister pytest-beartype project that @beartype import hooks silently reduce to noops in Django-driven web apps:

For more context, I'm trying to use your tool to add beartype during testing of a django project (unfortunately this repo is private 😞 ). A django project is broken into "django apps" (see docs) which are like submodules within the django project. I tried to add testing to a single "django app" inside my project. The project has a single pyproject toml, where I specified the submodule to add beartype to, and each application within the django project has an __init__.py. I tried to solve this problem by writing my own pytest plugin that would import beartype before django had a chance to init, but that didn't work unfortunately. I understand this is very niche, but any insights or suggestions on how to better integrate pytest-beartype with django would be very appreciated!

Unfortunately the dark magic failed, as django practices a darker insidious magic 😞. I was able to verify this, as manually annotating functions with @beartype worked. So something with beartype_this_package() doesn't play nice with how django initializes stuff.

Django probably imports Django apps in a non-standard manner circumventing Python's standard importlib machinery... probably. In short, we have utterly no idea what is happening here. We only know that Django hates @beartype and that my face hurts. 😮‍💨

@jhassine
Copy link

jhassine commented Jul 4, 2024

There is a workaround to make Beartype work with pytest and Django by making a wrapper script for pytest e.g. in this fashion:

pytest-with-beartype.py:

#!/usr/bin/env python
"""Pytest wrapper which instruments it with Beartype's type annotation checks.

Why is this needed?
------------------

Because if you run pytest with the pytest-beartype plugin with command:
`pytest --beartype-packages='src'`
it will emit the following type warning:
  BeartypePytestWarning: Previously imported packages "..." not checkable by beartype.

This is because the Beartype plugin is not able to instrument the packages
that are already imported somehow by pytest.
Refs:
- https://github.com/beartype/beartype/issues/322
- https://github.com/beartype/pytest-beartype/issues/3

So this wrapper script provides the workaround for this issue.

"""

import pytest
from beartype import BeartypeConf
from beartype.claw import beartype_package

type_check_instrumented_packages: list[str] = ["src"] # add here the packages

for package in type_check_instrumented_packages:
    beartype_package(package_name=package, conf=BeartypeConf())


# Running pytest tests:
pytest.main()

Then you would run it like:

./pytest-with-beartype.py

Seems that also the pytest CLI arguments and switches work with this wrapper script so it seems to provide pretty much all that is needed working with pytest. For example:

./pytest-with-beartype.py --cov src 

@leycec
Copy link
Member Author

leycec commented Jul 5, 2024

Ho, ho, ho. Thanks so much for the miracle cure, @jhassine. Finland delivers yet again. Indeed, that's an excellent workaround for this long-standing issue. But... why, Django!? Why do you make @beartype look bad?

It's mystifying, honestly. The pytest-beartype plugin hooks into the pytest_configure() hook, which official pytest documentation states should be called before test collection and package importation. This StackOverflow answer confirms this behaviour. The pytest-beartype plugin should thus behave as expected... but it doesn't. This is why I am bald.

Here's What We Goin' Do, Homies

Let's at least document @jhassine's clever kludge with:

Thanks again, @jhassine. Since I am lazy, this may not happen for a few days weeks months years lifetimes. Please prod me with a stick if I fail to do anything. 😅

@jhassine
Copy link

jhassine commented Jul 5, 2024

@leycec I was actually surprised as well why Django stuff was loaded prior to the pytest-beartype plugin. I am now suspecting it might be caused by another pytest plugin which Django pytesters like me might use - pytest-django. It might load Django stuff prior when pytest-beartype starts kick in. I did not verify if this theory is true.

@leycec
Copy link
Member Author

leycec commented Jul 5, 2024

Exactly! Exactly my thoughts. I didn't even know pytest-django existed, but I knew it had to. Of course that's the problem.

Is there any way for pytest-beartype to tell pytest that it needs to cut in front of the line and forcefully "go first" ahead of every other plugin? Probably not, huh? We are asking too much here. This is why I bang on my keyboard.


pretty sure that's not a keyboard. pretty sure that's also not @leycec.

Wait. I Just Found a Super-Relevant Upstream Pytest Issue...

...but everybody's gonna hate it. To quote @pytest dev @RonnyPfannschmidt:

So far nobody came up with a good solution in the upstream project pluggy

It's been on my radar before I had kids, now not so much

😆 -> 🥹

@RonnyPfannschmidt
Copy link

i recommend a more nuanced approach to mentioning people,

a) the org on github for pytest is pytest-dev
b) pinging me wont expedite a Solution , im stretched

@leycec
Copy link
Member Author

leycec commented Jul 6, 2024

...ok. Pinging with the @ sign is the more nuanced approach to mentioning people, though. I never mention someone without prefixing their username with @. That's just common courtesy and community standards across social media, right? Most people wanna know when they're being talked about. It's a good thing – not a bad thing. Well, usually... anyway. I sigh.

I didn't even expect or desire a response, honestly. You're stretched. That's cool. No worries. I'm stretched, too. We're all stretched. I like being stretched, because this bad back ain't gonna stretch itself. That was a bad joke, people – yet a joke nonetheless. 😮‍💨

There's no expectation of a resolution here. We're all just chillin' in the comfy @beartype space. Please unsubscribe to avoid further comment churn that you will undoubtedly hate. Please accept my apologies, too. Nobody meant to make bad feels!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants