-
Notifications
You must be signed in to change notification settings - Fork 14
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
Update to Django 5.1 #2264
Update to Django 5.1 #2264
Conversation
|
0c3126d
to
bc9c47c
Compare
0f0c70b
to
2629fc7
Compare
Legacy comment:
|
Good progress so far, Steve. I think this is pretty close now! Quick comments, happy to discuss anything that's helpful...
Would be very good to do this before we move on, as it's easiest to do now and will be useful if this is modified or extended at all in future. Could be a separate PR or even Issue if the
Similar.
Could this issue be different-but-related to the issue in the others modules as this test case doesn't seem to be about dynamically creating a database? The exception stacktrace is related to the fixture creation, which does seem to do something dynamically with test case config, in |
NB: the tests ostensibly pass as of 37d1546, but that's because several are commented out, while I got one single coding system base test working. |
Everything passes; time to clean up the mess. |
d837fbb
to
01e44c6
Compare
The stages there:
|
92f13fd
to
f28f914
Compare
Moving the messy branch with all the stages of progress to |
6d671cc
to
a3a0352
Compare
340142f
to
df3f4e1
Compare
Local testing flagged up that logout didn't work in Django 5.1 (until I fixed it). That's another good case for "we should have automated end-to-end tests", as in #2135. |
eb7d79b
to
17c39e4
Compare
dc6c8b9
to
20ebb27
Compare
73b54ae
to
199dca8
Compare
Thanks to Mike and Jon for the helpful review. Based on their comments, I've done the following:
I've also:
The new commits are those following I left these post-review fix commits deliberately separate, and small for easier review. When the review is approved, I could squash these newer commits back to where the relevant code is changed in each case, to keep the history cleaner. The previous commits reviewed typically made all the changes to a single file in a single commit (which makes logical sense as each Python module covers one aspect of the tests). That might also make sense once we've finalised these changes. |
1a316f4
to
e8dd5ed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Steve. I think everything looks good now (one minor docs comment). Phew, good work! I think this is deployable, so approving.
It's up to you whether to rebase further or not.
e8dd5ed
to
e29b8ac
Compare
I've squashed the subsequent post-review commits back in to where they would have gone, if I'd got it looking good the first time. |
This changes `CheckConstraint.check` to `CheckConstraint.condition`. See also opensafely-core/job-server@190a645
This results in a warning if not enabled, but will be the default behaviour in Django 6. Therefore, enable the setting and suppress the deprecation warning resulting from having that setting enabled (which will be removed in Django 6). See https://adamj.eu/tech/2023/12/07/django-fix-urlfield-assume-scheme-warnings/
Using a GET request for logout was seemingly deprecated in Django 5.0. See opensafely-core/job-server#3995.
See #2115 for full details. The problem this refactoring aims to solve is, in short, as quoted from @mikerkelly in #2115: > The [DatabaseOperationForbidden] errors occur because there's a mismatch > between what [these test cases](https://github.com/opensafely-core/opencodelists/blob/main/coding_systems/bnf/tests/test_import_data.py) > that import databases dynamically are > trying to do and how both the Django and `pytest-django` test case > frameworks work. In a multi-database context, the test frameworks want > to declare which databases are available to a test case at > test-case-definition-time, which then triggers those databases being > created, the test case wrapped in a transaction referencing those > databases, and the databases flushed in clean up. Since 5.1 it's > enforced that test cases only open connections to such databases, to > avoid accidental access. But the [coding system release import tests](https://github.com/opensafely-core/opencodelists/blob/main/coding_systems/bnf/tests/test_import_data.py) > do want to access a database that they do not want to exist at the start > of the test. That's in conflict. So maybe we shouldn't be using test cases > this way at all? Mike proposed several ideas to fix this that we looked at, and we found that: amending the test case attribute that defines the allowed databases seems reasonable, and, further, this was the only solution that we had working. Altering this attribute is mentioned in Django's documentation: https://docs.djangoproject.com/en/5.1/topics/testing/tools/#multi-database-support It was decided that refactoring the existing tests was the solution for now, rather than rethinking them or the code under test entirely. This facilitates the upgrade to Django 5.1 without blocking us further. We may have to revisit this code and these tests in future, with a view to a more comprehensive overhaul. The `DynamicDatabaseTestCase class facilitates getting most of the tests working by just moving them into a test class that uses this DynamicDatabaseTestCase class. Those tests have a generalisable pattern for accessing the databases. The tests that need refactoring fall into one of three general patterns: * most tests that do not need a temporary coding system database directory, handled by the `DynamicDatabaseTestCase` class * some tests that need a temporary coding system database directory, handled by the `DynamicDatabaseTestCaseWithTmpPath` class, which extends `DynamicDatabaseTestCase` * a few edge cases that are discussed in subsequent commits; these will be worked around, rather than refactored in this series of commits (though they could be reworked in future): * tests in `coding_systems/base/tests/test_import_data_utils.py` that access the database in fixtures, before the test class' `setUp()` runs; these will be handled in that module specifically * tests in `coding_systems/bnf/tests/test_import_data.py` that uses a pytest fixture to produce import data, instead of fixtures stored in the repository, unlike the other tests Co-authored-by: Mike Kelly <mike.kelly@thedatalab.org>
Note that this, like other commits to get these tests working, uses a slightly unusual pattern of: * having a fixture method that is primarily used to set an attribute on the test instance, with a fixture value * marking that as a fixture to use with `usefixtures` on the test method This is because of pytest's quirks, especially when using `TestCase` classes, which don't seem as well supported as using test functions. (However, we *need* the class because we're overriding Django's `TestCase` behaviour.) Specifically, to my understanding after experimenting and reading: * `pytest.mark.usefixtures` can be used on regular methods, like a test method, but there's no way to access any fixture value that's returned * only fixtures can call other fixtures, and we don't want the test method to be a fixture
These tests mostly fit the general `DynamicDatabaseTestCase` class. One quirk for these tests is that they use an import data *fixture* instead of a path to files, unlike the other tests that use import data. Because of this, there's now a class to handle this case. All the existing tests use the same fixture.
These tests are the most unconventional of the all the coding systems tests that use the dynamic database because: * they uses fixtures to setup databases, and this needs to happen before `setUp()`, so we also have to mangle the `databases` attribute before `setUp()` * one of the tests actually needs to access multiple databases, which breaks the pattern for all other tests After a little bit of trying, it seems overly complicated to try and generalise the setup and teardown pattern here, partly due to the use of pytest fixtures and the limitations in `TestCase` classes, so it's been left as it was in the original code.
This gets converted back into a `Path` in `import_data()`, so this is a simplification.
e29b8ac
to
3d3b72c
Compare
Fixes #2115.
This requires a workaround of the coding systems tests that use databases dynamically, due to changes in Django 5.1. We agreed in #2115 that working around the new restrictions was the best thing to do, to allow the upgrade without delay. In future, we may have to revisit this code and associated tests, either for future Django changes or to make maintenance and improvements easier.
TODO:
repin Django to 5.1.xnot doing thisdjango-upgrade
before merge (maybe there are newer migrations?)