pytest-django icon indicating copy to clipboard operation
pytest-django copied to clipboard

Add option to not setup Django in pytest_load_initial_conftests already

Open blueyed opened this issue 6 years ago • 11 comments
trafficstars

pytest-django sets up Django in pytest_load_initial_conftests already, which requires you to use a pytest plugin yourself if you want to do anything before it, e.g. changing project settings for tests in the environment, before the settings get imported. Using a pytest plugin has its issues though (https://github.com/pytest-dev/pytest/issues/5190).

To keep it backward compatible I think a new option could be used here, to either defer this to pytest_configure, or skip it completely (but providing a way to call it manually).

Ref: https://github.com/pytest-dev/pytest-django/pull/719

blueyed avatar Apr 30 '19 17:04 blueyed

I have similar issues when trying to call django-compat-patcher setup before django.setup().

Is it necessary that django.setup() gets called so early in pytest loading system ? Isn't it psosible to put that setup later, after conftests and the likes have been loaded, so that it's easier to override that behaviour, and benefit from other plugins like pytest-pythonpath ?

Else, how about a new setting which would point to a callable to be called INSTEAD of django.setup() ? Thus this new callable could peacefully do pre/post setup tweaks around the django environement, and still benefit from other pytest-django options (like "--ds").

I could work on a patch if we agree on the best strategy here to allow pre/post django.setup() in pytest. :)

pakal avatar May 28 '19 06:05 pakal

It is not really possible / easy, since you might want to use models already in your conftest etc.

A new setting might make sense though, and it's default could even be changed then in a non-backward-compatible way maybe even - after all it is easier to just call django.setup() (or a wrapper provided by pytest-django) in your conftest than the other way around.

Have you looked at #719, and the dealbreaker therein especially? (https://github.com/pytest-dev/pytest-django/pull/719/files#r277162947)

blueyed avatar May 28 '19 11:05 blueyed

OK I see the point of having django already setup at conftest stage then.

I don't think we need to make anything backwards incompatible, this new setting ("--django-setup" ?) would defaut to "django.setup", could be changed to something else, and could be left to a special value ("null" ?) to say that no setup must occur.

Does this behaviour sound OK to you ? If so, I might have a look at a PR for this.

pakal avatar May 30 '19 09:05 pakal

Sounds like a good idea in general.. it could be an "importable string" then, which should be a callable.

btw: have you seen https://pytest-django.readthedocs.io/en/latest/configuring_django.html#changing-your-app-before-django-gets-set-up (for a way to do something before django.setup)? Given that your use case appears to be a plugin, it should be trivial to use this hook then.

blueyed avatar May 30 '19 15:05 blueyed

Yes I did use this instruction for changing app before django sets up, but since nothing is configured (no python paths, no conftests...), it forces me to keep a pytest plugin at the root of my project, or to set PYTHONPATH in advance.

I'm seeking a generic solution to this problem, and came up with this PR on Django itself, what do you think about it ? It would solve the "changing environment before django.setup()" for all test runners at once (django settings must be importable though, but imho it's not a problem): https://code.djangoproject.com/ticket/30536

pakal avatar Jun 01 '19 20:06 pakal

I'm just thinking : why not add an option, in pytest-django, similar to that of pytest-pythonpath ? Since it sets up very early, maybe pytest-django shouldbe able to configure python paths so that settings and apps are found even in more complex source repositories.

pakal avatar Jun 02 '19 10:06 pakal

As of now I don't know if this way of solving the problem would not be more generic: https://github.com/pytest-dev/pytest-django/issues/764

pakal avatar Sep 24 '19 14:09 pakal

I'd also love to have a solution for this that's more lightweight than "implement an entire pytest plugin". We're running into an issue where using freezegun in our tests breaks PyMySQL. freezegun has a workaround that monkeypatches PyMySQL but by the time our tests import freezegun the database connection has already been created and it's too late.

luser avatar Oct 07 '19 17:10 luser

The plugin can be quite short, but the big issue for me was that all this happens long before python paths are auto-detected, so I've opened a PR in the ticket #764 above to have early pythonpath tweaks, allowing to put django settings and early plugins wherever we want, without a need for "pip -e" or similar (but more complex) "poetry" equivalent.

@luser - would this solve your problem?

pakal avatar Oct 07 '19 18:10 pakal

Well my experiments so far with early pythonpaths have failed, and I still encounter that issue of early patching of django, in my new projects.

So I guess the best attempt now would be to add a "--django-setup" option, which would be the dotted path of a callable to use instead of django.setup() ?

pakal avatar Jul 29 '20 11:07 pakal

Beeing able to make pytest-django compatible with alternative SQL drivers like e.g. PyMySQL would be great. ATM there is need for a workaround.

fkromer avatar Mar 09 '21 10:03 fkromer