-
-
Notifications
You must be signed in to change notification settings - Fork 18
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
Add testing and remove unused code #257
Conversation
63d89ee
to
4360178
Compare
1640588
to
8447d57
Compare
cc6d803
to
e4e2edf
Compare
21b3792
to
5f8cebb
Compare
9551458
to
38adb43
Compare
421dfdf
to
15c41cd
Compare
This is needed since the footer links upgrade
412ee7c
to
713b4d2
Compare
b78231e
to
67501dc
Compare
OK. There's a lot going on this this PR and it is a bit hard to grok it all and comment usefully. I have a real mess of questions, feedback and future work. But I will try and say some useful things. 1. TestingOne of the objectives here is to get the code we care about under test to support future modifications. Here's my experience of checking the code out and running the tests locally:
I'll leave some more comments inline on the diff about testing. 2. Removing unused codeOne of the objectives of this PR is to ditch a bunch of code we are not using to make the code easier to work on and reason about. It is always a big productivity sink when you spend hours trying to work out "what does this code do" and the answer turns out to be "nothing". That said, its a slightly nebulous objective to review against because we have not defined up-front what is "used" and "not used". As such, I'm not quite sure how to answer the question "is this finished/right?". That said, there are a number of things I'll pick out that I think might be good to review (and hopefully in some cases delete) under this banner.
Again, I will highlight some more points relating to unused code on the diff where it is more appropriate to use inline comments. If the answer to some of these things is "yes, but not in this PR", that is a fine answer but lets make sure we capture those points. |
electionleaflets/settings/testing.py
Outdated
|
||
MEDIA_ROOT = root("test_media",) # noqa: F405 | ||
MEDIA_ROOT = mktemp() |
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.
Minor, but this creates a new tempdir for every test run and we never clean it up
It would be nice if we could find a way to remove this dir in a post hook after the test suite runs.
Also if we are not using test_media
any more, we can clean up the gitignore entries relating to that directory.
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.
Fixed in 16b30c9
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.
nice 👍
# def item_description(self, item): | ||
# return item.description | ||
|
||
|
||
class ConstituencyFeed(Feed): |
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.
We seem to be dropping most of the constituencies app in this PR. Do we definitely want to keep this?
from django.core.files import File | ||
from django.core.files.storage import default_storage | ||
from slugify import slugify | ||
|
||
from constituencies.models import Constituency | ||
from core.helpers import geocode |
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.
Here we are importing the geocode
function, but this function is not called anywhere in this file and this is the only place where we are importing it.
I think we can actually completely bin the geocode function, which in turn completely removes the dependency on mapit and any related code.
Unused imports is something a linter could help us catch. More on this later..
@@ -1,2 +1,291 @@ | |||
MAPIT_POSTCODE_RETURN = """ |
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.
I think this is already not used anywhere, even before we get rid of geocode()
from electionleaflets.apps.api.views import LeafletFilter | ||
from leaflets.models import Leaflet | ||
from django.utils import timezone | ||
from uk_political_parties.models import Party |
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.
What are your thoughts on the future of this?
At the moment, the uk_political_parties
is a bit of a pain point. The package repo itself is abandoned/archived. One of the problems it is causing us is we can't run makemigrations --check
in CI because there is a missing migration in that package.
electionleaflets/.circleci/config.yml
Lines 68 to 69 in add000d
# TODO: enable this once we drop uk_political_parties package | |
#- run: pipenv run python manage.py makemigrations --check |
I think I would like us to remove the dependency on that package and bring the handful of things we are using from it (I think just the party and emblem models) inline into this application.
If this one is something to address in a future PR, cool. Lets leave it for now.
electionleaflets/storages.py
Outdated
|
||
@abc.abstractmethod | ||
def save_from_temp_upload(self, source_path, target_file_path): | ||
raise NotImplementedError |
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.
This is a really minor point, but you don't need to raise NotImplemented
in an abstract method. You can just pass
import abc
class Parent(abc.ABC):
@abc.abstractmethod
def save_from_temp_upload():
pass
class Child(Parent):
pass
c = Child()
will throw
TypeError: Can't instantiate abstract class Child without an implementation for abstract method 'save_from_temp_upload'
"post": { | ||
"id": "gss:E05013806", | ||
"label": "St James's", | ||
"slug": "st-jamess", | ||
"created": "2022-01-05T11:15:54.795194Z", | ||
"last_updated": "2023-07-11T15:31:13.176989+01:00" | ||
}, |
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.
Another very minor point, but something that jumped out at me here is there's some odd indenting going on here.
Lets not get into trying to add it in this PR, but this seems like something that should be being caught by linting/formatting tools which I guess we are not using.
@@ -53,6 +32,8 @@ def get_context_data(self, **kwargs): | |||
| Q(ynr_party_id=f"party:{id}") | |||
) | |||
|
|||
context["party_name"] = qs.first().ynr_party_name |
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.
qs.first()
can return None
which would cause AttributeError: 'NoneType' object has no attribute ynr_party_name
here
pytest = "*" | ||
pytest-playwright = "*" | ||
pytest-cov = "*" | ||
moto = "*" |
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.
One of the things I was hoping we would cover under the banner of "removing unused code[/stuff]" was unused packages. I think there are 2 big problems we have on this project:
- I am convinced there is a bunch of stuff in the package tree that we actually don't use at all any more
- There is no seperation of prod and dev packages. This is especially problematic for an application deployed to lambda because every time we do a cold boot we are spending time unzipping testing/dev packages that are not used at runtime. Specifically here you are adding playwright, pytest, moto etc into the stuff we have to unzip when we cold boot.
I'd really like us to fix both of these problems.
If the next thing you are going to do is migrate from pipenv to UV, I am happy to just ignore this for now and include it in the UV migration PR. This was one of the things I did as part of that exercise on EE:
- Migrate to UV EveryElection#2282
- DemocracyClub/EveryElection@6d5d0d1
- DemocracyClub/EveryElection@7ad181a
Although the scale of the problem is bigger on this project.
Anyway. If we want to just ignore it for now, fine. Just want to flag it as a thing that needs doing.
@chris48s I think this is good for another look. I've made issues (I think) for most of your comments. I've addresses the ones that relate to new code in this PR, and should have fixed your local tests. |
One thing I'd like to do right before merging this PR is run |
@@ -52,6 +31,10 @@ def get_context_data(self, **kwargs): | |||
| Q(ynr_party_id=self.kwargs["pk"]) | |||
| Q(ynr_party_id=f"party:{id}") | |||
) | |||
if not qs.exists(): | |||
raise Http404 |
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.
I think you need to raise Http404()
or Http404("message")
here. You can't throw a class
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.
I added some tests for this, because clearly it needed them. I'd previously manually tested. The answer is: better to raise the instance of the exception, but it works either way!
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.
TIL you can throw a class
DJANGO_SETTINGS_MODULE = "electionleaflets.settings.testing" | ||
python_files = ["test_*.py", "*_test.py"] | ||
addopts = "--reuse-db --tb=short -p no:warnings" | ||
django_debug_mode = true |
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.
This does fix the tests locally for me 👍
I'm slightly unclear how they worked in CI or for you though. Can you give me a quick explanation of that?
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.
Yes.
pytest-django
's live_server
runs the server with DEBUG=False
. This, mixed with a combination of django-pipeline
and whitenoise
means that assets are not collected in to static
. It's assumed that you've run collectstatic
beforehand.
In CI I'm running collectstatic
, and you could have got your tests working locally by doing this, however I think it's better if this isn't a required step to get tests running.
The change I made gets pytest-django
to turn on DEBUG
in live_server
, meaning whitenoise
will collect static files into static
as part of the request that Playwright is making.
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.
Hmm. This is why I'm confused. As I said in the original post
I tried running
./manage.py collectstatic
to see if that fixed it, but same error
but lets not get too bogged down in it
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.
Ah right, this is per our conversation this morning: collectstatic --settings electionleaflets.settings.testing
isn't the same as not specifying the test settings.
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.
aah that was probably it
Couple of comments inline, one of which needs a small change.
I think I would be in favour of not adding any more stuff to this PR and make a follow up PR where we:
|
7ebdbf9
to
5f7e52d
Compare
This is needed because we don't collect static when playwright interacts with the live_server fixture. Without calling collect static we can't serve some static assets, so we can't test that the front end is working. The downside of this is that the live server might act differently when in debug mode. There isn't a lot we can do about this, and we should rely on deplyed integration testing for things like 404s when DEBUG=False.
5f7e52d
to
64c67b1
Compare
The deploy failed after merging this, due to the Lambda zipfile size being too large. This, in turn is caused by the lack of dev packages (and general package bloat). I'm not going to try to fix that before moving to |
I figured that might happen |
Ref https://app.asana.com/0/1204880927741389/1208159470102409/f
Playwright
tests for the front-end leaflet upload process.TestCase
withpytest
for testing.Django
from 4.2.15 to 4.2.16.Pipenv
.