Skip to content

Instantly share code, notes, and snippets.

@brylie
Created January 13, 2024 19:46
Show Gist options
  • Save brylie/bb342f286b2412f7563c15fa5728d237 to your computer and use it in GitHub Desktop.
Save brylie/bb342f286b2412f7563c15fa5728d237 to your computer and use it in GitHub Desktop.
CodeWithBrylie - e48
(...) Hello and welcome to this open source live code hangout. Today we're going to continue a draft pull request to reduce the amount of search page usage.(...) Trying to basically optimize the app and our search page is one of the least performant pages. We don't have a lot of control over that it's just a complicated query that needs to span multiple tables.(...) So rather than try to optimize it which I don't know where to begin I would just rather we not use it for certain things.(...) Part of this issue is that we're getting hit by a lot of crawlers and bots and I don't know what the purpose of them is. Some of them are from Microsoft and Google I think. They're really causing an excessive amount of traffic on our site and queries against the database as well as expenses for example our analytics. We have this open source private(...) preserving analytics service but we're paying for their commercial hosting and we've exceeded our yearly budget of 600,000 hits in less than a month basically or maybe about a month since we got the service and it's because we're being hammered apparently and I installed a CloudFruit layer sort of proxy service to help us mitigate some of these and that's where the issue first became apparent.(...) So in addition to this pull request I'm going to look at some more strategies about how we could just throttle excessive users of the sites typically the bots and I'm thinking of some kind of generic things like if some bot is making more than let's say or some IP address maybe is making more than 500 requests a month maybe we would block them for a month or if they're making more than it's hard to say but 50 requests a day something you know more of the extreme percentile usage there would be blocked for a day that wouldn't help against bots who are using multiple IP addresses so it's not a really trivial thing and the main thing is I don't want the users to be affected by it. We have put some non-invasive(...) mitigations in place for example our forms in addition to a CAPTCHA which has essentially eliminated our form spam which looks good but these crawlers are different type of traffic so I'm not sure what we can do here. Let's continue on with this pull request though and since we're changing some lines of code we're adding a new view and I want to make sure in the new template I just want to make sure that we test this list view and the get context functions so we have coverage there so what we'll do is use chatgpt and since this is only around 70 lines of code I can paste the whole thing in and explain that we want to make a test suite and it's a list view so please help me make a comprehensive test suite for the following Django list view and it's going to look at across our functions and look at the possible code paths and statistically it's able to infer the types of cases we would need to do so we'll have a setup and tear down which is a common pattern so creating a comprehensive test suite for your Django tagged page list view involves testing various aspects of the view including its ability to handle different types of data and edge cases here's a breakdown of your tests you can implement test setup and tear down create a test database and populate it with sample data for a library item magazine article news item WF page and tag test the query set tag filtering test of the view correctly filters items based on the given tag make sure they're ordered correctly make sure the query sets are combined make sure the test context data retrieves the tag and that the pagination works so willing to probably create a number of items so pagination is tested enter that the template renders the correct tag page list of HTML and look for edge cases and error handling no tag provided invalid tag invalid tags should just not return any results results it would be an empty query set invalid invalid could also mean there's any illegal characters in there perhaps I don't know integration with other components user experience to view the test of you with different user inputs different page numbers in the query string responsive browser compatibility testing Wow tools and frameworks Django test case writing a test here's an example of how you might write it test for the tag filtering functionality so it's good we've got some code already and including the setup so what I'll do though is I'll take a step back and let's get a comprehensive setup here it's tricky though you're gonna think of this more strategically but yeah this is a sketch anyway I could include the number of create the number of library items and articles and etc that would cause our pagination you know to break across the query set so in other words we have a 10 item paginator so this would be a bit of a comprehensive setup that's good stuff hydrate so I should mention our what do they call factories we double check here so essentially we're needing to create library item to magazine articles news items and pages and I think after going through a lot of these tests we've created factories for pretty much all of the apps that should let us create the leaf nodes and automatically generate the tree structure that holds the leaves up because that's a bit tricky for you in order to be able to create for example an article you have to have created the magazine issue and the WF pages did I create
(...)
I don't know if we need slug let's see so let's just test this factory method out and see if I can just create a WF page
(...)
development database go back into the shell like our import happening create one of those
(...)
field cannot be no path okay so this is the fundamental problem this path is a path in within a tree tree like structure that's provided by Django Django tree beard and so every time we want to create a model instance that inherits from the tree beard which is inherently actually what the Wagtail page models based on we have to put it in an existing tree so what we've done elsewhere look at the magazine factories for news factories maybe but let me see magazine index page where we had to do on the create a home page so I think it was about its class method on the create that's pretty close but actually I need to import home page that correct page and import these type annotations we're trying to be pretty good about that
(...)
so let's see if this works I think I have to exit the shell and pop back in yes no we have a home okay great we have a WF page factory we've got news factory magazine factory
(...)
in no particular order magazine maybe I should advertise them
(...)
yeah and hopefully again I can just focus at the leaf node but that's not the case
(...)
we have magazine issues but not magazine articles so what we'll do is create class magazine article factory model Django title slug issue sub factory create to make sure the issue exists looking good looking good hopefully we'll get this to work let's exit out here run this shell and again this has to construct a whole page tree excuse me this is tricky because there is a relationship here but it probably isn't a property so let's just see what happens if I comment that out and I'm just gonna see do I have to reload this every time do I have to exit out and re-import that of course I do I don't know if there's a way to refresh the context here that'd be nice maybe what if I would have waited just a second longer
(...)
department cannot be null so we need a magazine department factory which also needs the
(...)
so yeah we need to have everything goes into the magazine index page I should check my code pretty closely when I'm reviewing it this is magazine issue okay let's try this again right now that's got the department then I can do the apartment field here I'll do that to sub factory so it'll create the department boom we've got it and what was the last one pages news pages fact uh magazine articles and something else library items
(...)
um
(...)
okay
(...)
[MUSIC] And okay, this is a bit tricky, but I think I should paste in the factories.
(...)
The relevant parts,(...) which is essentially the title.
(...)
So our context won't get really big, but it'll be big enough.
(...)
[SOUND]
(...)
[MUSIC]
(...)
Problem is the tags, I'm just remembering I've got to get the tags.
(...)
[MUSIC]
(...)
[MUSIC]
(...)
[MUSIC]
(...)
To create a test suite that utilizes the given factories and tests in the tagged page list view, you need to follow these steps. Set up the test data, create instances of library item magazine article, news item and WFPage. Test the query set, verify that the views query set includes one of each factory type and that they are sorted alphabetically by title.(...) So here's the implementation. So we're going to get our imports there, which I'm going to double check. Okay, let's hop over here. [MUSIC] Tags, views, tests is empty. So grab all of our imports.
(...)
[MUSIC] And since I gave it those factory paths earlier, I was able to do those for me correctly.
(...)
I don't have a tag factory, that's an interesting suggestion. But I think that we can just use strings. So it's going to essentially set up, it's going to set us up a tag, from tag and tag,(...) and it's going to create against the class, interesting.
(...)
[MUSIC]
(...)
I don't remember that, I think we usually use self, so not class method. I wonder if this is going to work.
(...)
It's copied in.
(...)
All right.
(...)
[MUSIC] And I got to get the view name. So the view is called, sorry, I got to get the URL.(...) Tag page list, tags, colon, tag page list, that's correct for the test.py.
(...)
It's going to open in the middle there.
(...)
[MUSIC] I think I would put the URL in the setup data.
(...)
[MUSIC] Tags equals self tag. [MUSIC]
(...)
Power class.
(...)
[MUSIC] Slug.
(...)
[MUSIC]
(...)
Self URL.(...) [MUSIC]
(...)
Just giving it a shared reference. [MUSIC]
(...)
So adding the URL in the setup test data is good practice. It simplifies the test methods by avoiding repetitive code. Okay, so it's just going to give me the whole thing again, but that's okay.
(...)
A library item, magazine article. So it's going to test some sorting, use item in WFP.
(...)
Tags, tags, page list, tags, slug tags.
(...)
[MUSIC]
(...)
Very cool, so now we can.
(...)
[MUSIC]
(...)
Now we can take a look at the test, see if it runs, passes, it's going to pass. So,(...) pups.
(...)
[MUSIC] So run the tags test, see what happens.
(...)
[MUSIC](...) We'll clear the database now. I think I've run some migrations recently and I don't know how old this test database is. So at least in this session I'll clear it once. Then I'll try to run keep DB next time. [MUSIC]
(...)
But yeah, I don't like to do this every time because it takes so long to get a new database instance.
(...)
All right, so there we go. We got our first problem, magazine page index create. Now this weird thing is this is coming from within the factory.
(...)
[MUSIC] And this was probably the one that I just created. So,(...) yeah,(...) factory.
(...)
[MUSIC] That should work.
(...)
[MUSIC] Now I think I'll keep DB here so it doesn't have to rerun those migrations. [MUSIC]
(...)
Because we have a factory here.
(...)
Magazine issue factory magazine index page factory, which does have the create method.
(...)
[MUSIC] That was auto generated code and I didn't carefully review it. I sort of just ran with it. I tested it by creating a magazine article.
(...)
[MUSIC]
(...)
For some reason didn't need, it must have, I don't know how it had a magazine issue already. Okay, argument of paginated page with the lighted page range is not iterable. Member nine container, Oikesty. This is an internal thing happening here.
(...)
Type error,(...) argument of paginated page with the lighted range is not iterable.
(...)
[MUSIC]
(...)
So that's like a none issue. [MUSIC] Or.
(...)
[MUSIC](...) In containers, looking in the container. So let me just check the tests here. I'm gonna close down the factories until we know we need them again.
(...)
Just so I don't have so many tabs open.
(...)
Now we'll take a look at our tests and I think so. If we look at,(...) what are we trying to assert here? Tests line 36,(...) library item, query sets. So we're looking in a query set.
(...)
The paginated items is not a query set. That was the thing.
(...)
But it has pages.
(...)
Oops, dot pages, I think it is. That we do use.
(...)
For example, in the template for paginated item page.
(...)
Page.
(...)
Let's see if this helps.
(...)
Yeah, page 101 is kinda strange. Okay, so here we go.
(...)
I didn't give the context that our view is using a helper function.
(...)
And this returns, okay.
(...)
It's a bespoke structure, so there's no way that GPT could have gotten this one. So how am I gonna improve? So essentially this returns this paginated with a lighted page range. Boy,(...) which contains a page, which is a sequence. That's the weird thing.
(...)
It would be nice not to have this bespoke method and just have the ellipses work already, but.
(...)
So this is emulating the paginator. It's kind of a paginator.
(...)
And in a way I could inherit from paginator.(...) We're just adding a new member.
(...)
So all these are good to error.
(...)
And here's our get paginated items.
(...)
It's only like 40 lines, so we might as well do the whole thing.
(...)
So the error you're encountering is because the paginator page with a lighted page range object returned by your get paginated items functions, not directly durable. You know, this is a common issue when dealing with paginated query sets in Django. The paginator thing contains a paginated page object, which holds the items, but it itself is not a collection of items.
(...)
Okay, so this is like a generator.(...) To fix this issue, you need to modify your tests to access the items in the page attribute of the paginator object. Here's how you can update your test.
(...)
So we get the context, then we get the query set items object list.
(...)
That's cool.
(...)
Then we'll make sure it's indented correctly.
(...)
Okay, so the query item not found.
(...)
So the tricky part.
(...)
So let me just see. I would like to just not have this literal string and be able to get that from the tag.
(...)
So now we might need to run this in a debugger. Let's see if GPT spots any omissions.
(...)
We'll step through it. So yeah, this could be the view is working with manual testing, though.
(...)
So the query set might not return the data.
(...)
The views get crease at the database transaction.
(...)
I get committed.
(...)
it was chosen here.
(...)
All right, yeah. Any changes made in the database on one test will not affect data methods.
(...)
Yeah, so if we're not mutating the objects,(...) we should try to use the class method.(...) If your test method needs a fresh environment and you want to ensure that changes by one test do not interfere with others, you set up and your test involve modifying object you set up.
(...)
Give the nature of your test checking the presence of items in the crease set up test data should generally be sufficient. However, if you're finding inconsistencies or if your methods are altering the state of the test data in a way that could affect a test switching to set up could be a good strategy.
(...)
So just shows me how to do that. But I think.
(...)
Yeah,(...) and it didn't mention anything with my class.
(...)
Oh, yeah.
(...)
Tag slugs approach. So that seems legit.
(...)
So maybe like one test, it's kind of weird, but I've been doing this convention where I'll set up some data and then I'll have a test that tests the set of data.
(...)
To make sure things are just how we expect them to be sort of like I learned this one, especially in our work on my day job because a lot of times we can't really run things locally and the testing environment is really kind of a bit awkward. So it's like one of the ways I can have visibility into things are working as expected is just to test the tests data.
(...)
Yeah, then we'll just need our little.
(...)
Imports.
(...)
And we'll comment this one out for now while we just.
(...)
Run that first method, then I'll be able to run these in a debugger here in a moment.
(...)
There we go.
(...)
So that got right to, I think, the heart of the issue.
(...)
The test failure you're encountering suggests that the library item instances not being tagged as expected in your setup. Probably none of them are being tagged as expected.
(...)
This issue could be due to several reasons, such as the factory setup. The way the factory creates the library item instance might not be properly handling the tagging tag assignment. There might be an issue with how the tag is being assigned to the library item instance database transaction. Sometimes the database transactions and tests can behave unexpectedly.(...) OK, probably one of these two.
(...)
Here's an example how you might modify your test to create and tag library item instance directly.
(...)
The problem with this is I have to scaffold the whole tree, so we want to use the factory. We need those factories.
(...)
Let's see, though,(...) if it's just a library item, for example, because that's when it's kind of not coming through.
(...)
There could be some differences in how we're handling the tags. I think I remember the library item having an, they all have an intermediary collection, but I think we defined it explicitly in the library item case, but the other ones might just be using the regular Django tag field, where you just define the field on the model and you don't say that the through.
(...)
Open that back up.
(...)
So I'm just going to see if I can isolate this down to one model.
(...)
Keep database, though. Save some time.
(...)
Oh, you can see.
(...)
Yes, so.
(...)
Yes.
(...)
I think this is the first time I've really ran a test against the tags, non-trivial stuff.
(...)
First, let's run a shell, right?
(...)
So,(...) for example.
(...)
My model is the effectors.
(...)
Oh, I got to do this.
(...)
This is the class. So this, that, and the other thing.
(...)
I have an article.(...) Compare various house collection.
(...)
It worked.
(...)
Let's try this. Article two. I think it's the article save method that we all need to run after adding the tag.
(...)
So, let's do article two.
(...)
Subsection one.
(...)
Okay, so you don't have to save it. So that is working.
(...)
Well, that's cool. So I know I can just assign it a string, right? I don't have to use this sort of test instance. So what I can do is just say,
(...)
comment tag.
(...)
And then down here I'll just say,
(...)
tag.
(...)
Yeah, now this is a string, so it will sluggify it.
(...)
So I can use common space tag.
(...)
And it should still come out as, you know, common tag here.
(...)
Quargh's coming.(...) That's the problem, though.
(...)
It won't.
(...)
sound]
(...)
I don't see why this would be necessary but...
(...)
pocket clang]
(...)
Man.
(...)
Work our way through it.
(...)
So that worked.
(...)
All right. So this should pass.
(...)
And the library item thing should pass.
(...)
But,(...) so these will all pass.
(...)
Then,(...) then...
(...)
Can I use "self"?
(...)
I don't know if this will work. I don't think so.
(...)
Well, it shouldn't matter.
(...)
Because it looks like I'm using "query set" up here.
(...)
All right.
(...)
[music]
(...)
Let's try with the string.
(...)
I don't see why that would help. But if it's some property that's not on the tag...
(...)
Yeah, it's an empty list. So that's...(...) So this part is not working.
(...)
[music] "Your phasing is likely due to the way the tags are being added to the library item instance. The tags add method typically expects tag instances not strings." No, I've tested this. This is wrong.
(...)
[music]
(...)
But if that tag... So nonetheless...
(...)
Just going to un-portrait it. "Wiki."
(...)
I think we're just going to switch to the class base.
(...)
"instance method approach."
(...)
[music] And let's just do "article."
(...)
[music] If it works...
(...)
Then we're good to go. Okay, so I think it's...
(...)
[music]
(...)
"Given that the tagging works correctly in the Django shell but not in your set of test data method, it's possible that the issue lies in how the test environment interacts with the database. This can be due to several reasons, including database transaction behavior and tests, and the order of the operations or the way the test database is set up and torn down."
(...)
"Commit trans-text. Try to force the database to commit after adding the tags.
(...)
Moving tagging to a test method."
(...)
"Use setup and let's try that."
(...)
[music]
(...)
The factories are working good. I just used it here.(...) [music] Although this is less efficient, using setup will ensure that each test method gets a fresh set of data and might behave differently with respect to the database transaction. So that's really strange if that's the case, but okay.
(...)
But let's try this approach. So basically, copy that and comment out all of this.
(...)
Then essentially uncomment this and assign the tags here.
(...)
Including this.
(...)
"Ddent indent here."
(...)
"Tag that and remove this just so."
(...)
"Self-tag is still used."
(...)
"Running it now."
(...)
"Now it's not working." "So let's try switching to the setup method."
(...)
"This is a bummer."
(...)
"It's such a difficult test to write."
(...)
[music]
(...)
"Why is that?"
(...)
"Of course,(...) I'm bad, my bad."
(...)
"Huh."
(...)
"Still an empty list." "What the heck?"
(...)
[music]
(...)
"Tried.(...) Destroying the test database, but this shouldn't be the factor."
(...)
[music]
(...)
[music] So we'll start here.
(...)
This should be a fairly...(...) well, I should have commented this out.
(...)
[music] "Rebuild the database."
(...)
[music]
(...)
[music]
(...)
Okay, so that runs.
(...)
[music]
(...)
So this is almost its own test. Sweet. First we see that things were made by it. Yeah, the test should pass. [music]
(...)
Hey,(...) making progress.
(...)
[music]
(...)
Woo-hoo! Okay, now we want to go on to the...
(...)
to the view test.
(...)
[music]
(...)
That's fantastic news. Your test suite is now quickly set up and successfully verifiable the creation of the tagged items and the proper association between the tags and those items. This is a solid foundation for further testing your tagged page list view. Test the queries that content and order. Test pagination.
(...)
[music]
(...)
We'll just start one at a time. One at a time. One at a time. All right, well, grab a little drink of water real quick. Be right back.
(...)
[music]
(...)
All right, so it looks like we have a test erode for us. It's going to test the content and all the expected items tagged with a specific tag are present in the query set. Make sense? And that the order of the items is correct.
(...)
So we're going to get the URL request from the... response from the URL.
(...)
We get the context.(...) Check the query set item objects list.
(...)
And make sure that when we sort the titles...(...) interesting.
(...)
That the titles are all there. Expected titles sorted. And that they...
(...)
Ha!(...) Assert equals search the sorting order. That's cool.
(...)
This is good stuff, man. Good stuff.
(...)
So I'm going to kind of throw this old one away. Just it's... we're going to go through this one at a time. Get these other tests written with the help of GPT 4.2.(...) Roger.(...) Okay.
(...)
Found two tests. True tests, sunny.
(...)
See? We're going to run them both.
(...)
So it's slower because we had to run the setup each time. And I forgot to keep DB.
(...)
This ectoplasm is too good. I drink it too fast.
(...)
No.
(...)
Okay.
(...)
So...
(...)
Lists differ. A library item, magazine article, news item, WFPH.
(...)
Make sure the URLs...
(...)
This is a bit tricky. The URLs got to be correct.
(...)
Let's make sure we get something back.
(...)
I think the URL is wrong.
(...)
[Music]
(...)
What are we calling this in the URL? Tag.
(...)
And what do we call it here?
(...)
URLs.py.(...) Tag.(...) Okay.
(...)
So again, taking it step by step.
(...)
And we get this.
(...)
So there don't seem to be any...
(...)
Paginated items doesn't have anything.
(...)
How have we tested pagination before? On the search page.
(...)
Tests.
(...)
We set up a bunch.
(...)
[Music]
(...)
Here we call it just page.page.
(...)
So...
(...)
Length.
(...)
Man.
(...)
[Music]
(...)
[Music]
(...)
[Music]
(...)
So, Django tag it.
(...)
Notice we're not using tag it here. Oh, it searches a different thing.
(...)
Ah, this is so frustrating.
(...)
[Music]
(...)
Hmm.
(...)
Now, self to tag model. So perhaps the tag doesn't have a primary key.
(...)
Yeah, it was weird. That was weird.
(...)
Hmm.
(...)
This is interesting.
(...)
Let's see if...
(...)
If gpt picks up on that. The issue you counted is due to the trying to add a tag that hasn't been saved to the database. In Django, before you can establish a relationship like adding a tag to an article, the related object must be saved and have a primary key assigned. This is why you're getting the type error. Model instances is about the primary key. Here's the correct sequence of steps you should follow.
(...)
Create and save the tag. Before you can add the tag to the article, you need to save the instance to the database, which assigns it to a primary key. Add the tag to the article. Once the tag is saved and has a primary key, you can then add it to the article. Here's the revised code. [Music]
(...)
Yeah, that's kind of what we determined here.(...) Excellent. Maybe this is getting us closer.
(...)
I don't know.
(...)
I don't know.
(...)
[Music] Hmm.
(...)
[Music]
(...)
Just see what it intuits about this. I don't know if it's actually thinking or something's happening. Intuition. Does GPT have an intuition? What does it have? Hallucination? Is it a perpetual hallucination that is sometimes reliable?
(...)
Often not reliable? The setup method in your tagged page, this view topic is almost correct, but there's a small redundancy you can remove. When you use the tab, tag objects created automatically saves the tag instance. Oh, yeah. Okay.
(...)
Of course, of course, of course.(...) Never calling self-tag saved adds to the cell difference. But yeah, that's what we're doing wrong.
(...)
All right. Dang.
(...)
That's set up. Yada, yada. [Music] Looks like your tagging is now working correctly. When you add the tag to the article and then query tags all, you're getting the expected output, which shows the tag you added. This confirms that the tag has been successfully associated with the article instance. The successful tagging in Django shell should mirror the behavior in your test environment as well. Now that you've confirmed the tagging process works, you can apply the same logic to your test setup. Make sure that your test data is quickly tagged. Your setup method in tagged page, this view, should function correctly as the factories in your models.(...) Yeah. Plus, we have a test here. [Music] Right here. The tag is in the tags.
(...)
[Music](...) So, I believe it boils down.
(...)
[Music]
(...)
To the URL.
(...)
Okay. To the view or the URL.
(...)
[Music]
(...)
Getting context data, data, data.
(...)
[Music](...) Getting query sets. [Music]
(...)
So, our view.
(...)
I think I'll just try this one more time.
(...)
[Music]
(...)
See if we get some print statements. So, yeah, it did work. Getting query set. Getting context data.(...) Fail.(...) Zero, four.
(...)
Getting query set gets called twice.
(...)
[Music]
(...)
I think I have a debug helper here.
(...)
[Music]
(...)
I don't have it set up. I can.
(...)
Edit it.
(...)
No, I do.
(...)
So, this is...
(...)
Tags.
(...)
Tests.(...) [Music]
(...)
This one.
(...)
Keep DB.
(...)
No break points through our view, essentially. What's going on here? Let's check out the context. That way I can see what the tag slug is, the tag name, page number,
(...)
the result, the paginated items, all that good stuff.
(...)
So, if I run this, it'll run our test suite in it, or case, in a debugger.(...) [Music]
(...)
So, it's not paginated, because there's only a few... [Music] So, the tag name is common tag.
(...)
[Music]
(...)
That's actually expected.
(...)
Tags slug. It's able to get the tag out.
(...)
That's a good sign.
(...)
And then we have paginated items with length seven.
(...)
Interesting. [Music]
(...)
Find another length.
(...)
[Music]
(...)
And can you, in a debugger context,(...) open a shell?
(...)
And try some stuff?
(...)
Like the debug console.
(...)
[Music]
(...)
Let's make it simple.
(...)
Yeah, here we go.
(...)
Yes, very good.
(...)
All right, so I think it's because it's part of context.
(...)
It's a paginator.
(...)
And we are looking in our test. I forget.
(...)
Object list.
(...)
Cool.
(...)
So, that is a good find.
(...)
The view works when I manually test it.
(...)
So, we'll give it a little bit of shared context here.
(...)
So, this shell, I wish Linux wouldn't make you do control shift V. It's such a hangover from Unix epoch era day one.
(...)
But it seems like you're trying to inspect the content of a paginated page and your jingle of your butt encountering some issues. Let's break down the key.
(...)
Object list. You got the error because the correct attribute to access in a page object is object list. Okay, okay.
(...)
Okay.
(...)
It's empty. It's empty.
(...)
This is what the problem has been the whole dang time.
(...)
Let's put the breakpoint here.
(...)
We'll just check all those parts. Let's rerun it again.
(...)
Let me put a breakpoint there. That's okay.
(...)
So,(...) tag item exist right there.
(...)
So, all of our query sets are empty. Yeah.
(...)
And what does the tag have in it? Common tag and it's able to fetch it. So that it's not the view. The view is wired up correctly. It's passing common tag.
(...)
The debug console. Let's say library items.
(...)
Or just library item.
(...)
Yeah.
(...)
So, I get to get a library item. A library item creates it.
(...)
Okay.
(...)
Okay.
(...)
here, not in the context when running the Django debug shell. This is so strange.
(...)
It's intriguing that the library item instance has the associated tag in the test setup data, but not in test queries, a content in order test. This discrepancy can be due to a few reasons. Test isolation and database transactions. Django's test case wraps each test method in a database transaction and rolls back at the end of each test to isolate tests from each other. If the test query set in content order runs before the test setup data changes main and test setup data. I'm getting test tag. Now we didn't do it there though.(...) Sort of clarification.
(...)
Set up method execution. The setup method is executed before every test method. Ensure that there's no code in setup or any other part of your test that might inadvertently remove the tag or alter the thing. Here's our setup.
(...)
This will stay here though.(...) Order test execution. The order of the test executions is not guaranteed. All right. If you have other tests that modified tags or the library items, it could affect this query set. Database caching issues. Sometimes, especially with complex relations like many to many fields, tags in this case, there can be caching issues.(...) Make sure that you're not encountering a situation where the test database isn't properly reflecting the state of relationships. Okay. So maybe I do need to clear it each time.(...) Inspect the setup method. Make sure this setup method correctly sets the data for each test. Isolate the test. Temporarily comment out other test methods and run only in that one to see if this you persist. Refresh from the database.
(...)
Try refreshing the library item instance from the database before checking its tags.(...) I wonder. But this one passes. This passes.
(...)
Honestly, I want to include test coverage in this pull request, but I'm not going to block the pull request from merging because of this weird weirdness. This is just stupid.(...) I don't know if a better word for it.(...) This is not working or something weird. Maybe it's something obvious.(...) That's what I'm doing wrong, completely wrong or just misunderstanding.
(...)
But why this one works.
(...)
And the other doesn't isn't just doesn't make sense.
(...)
(sniffles)
(...)
So let's just go back here.
(...)
So I'm just going in circles here. (soft music)
(...)
(soft music) (soft music)
(...)
I've already tested the factory behavior. I've tested this with factories. I've created them and the tags work.
(...)
(soft music)
(...)
(soft music)
(...)
(soft music) Hmm.
(...)
(soft music)
(...)
(soft music) I don't see why that wouldn't matter. Here, no, that's just complete gas.
(...)
(soft music)
(...)
Hmm.
(...)
(soft music)
(...)
(soft music)
(...)
So I'll just say these tests pass me new. Makes sense, it's just testing the same thing.
(...)
(soft music)
(...)
Sounds like the setup method is working correctly. And each of the instances probably tag.
(...)
Yeah.
(...)
(soft music) It seemed promising.
(...)
(soft music)
(...)
The curious animals.
(...)
(soft music)
(...)
(soft music) (soft music)
(...)
(soft music) (soft music)
(...)
(soft music) (soft music)
(...)
(soft music)
(...)
Double check this, but all of the,
(...)
library item.
(...)
(soft music)
(...)
All of the.
(...)
(soft music)
(...)
(soft music) You know, inferring that there are other ones there, I can test it, it's just.
(...)
(soft music) (soft music)
(...)
(soft music)
(...)
(soft music)
(...)
But again, this has already been an hour and a half.
(...)
At this point, the unit test is not worth the fight. It's a fairly important feature
(...)
in terms of reducing our database load. But it's not a main avenue of navigation for the site, it's a side route, sort of. People can navigate by tag and share tag pages and stuff.
(...)
(soft music) (soft music)
(...)
(soft music) I've been issued with the views, get query set method, filtering and retrieving the items.
(...)
The methods logic doesn't align correctly with the test setup, it could lead to an empty query set, yeah?
(...)
Makes sense.
(...)
So.
(...)
(soft music)
(...)
(soft music) Oh yeah, yeah, yeah. So in the view, I have to tag them.
(...)
(soft music)
(...)
And essentially the tag is the slug.
(...)
Let's see, whoops.
(...)
Gosh dang it.
(...)
(soft music)
(...)
Right, they're the same.
(...)
And that's how it's able to fetch it, right? That's how it's able to fetch it here.
(...)
Yeah, so we could attack item.
(...)
(soft music)
(...)
(soft music)
(...)
It's not about filtering.
(...)
(soft music)
(...)
(keyboard clicking)
(...)
Interesting.
(...)
Browser just went to sleep.(...) Well, it's a good sign. I'm not gonna battle this anymore. It's too much frustration.
(...)
The pull request works as it is. I'll roll back these changes. It works with manual testing.
(...)
Let me just see what we've got here.
(...)
I will commit these factory methods.
(...)
This is just not working. I don't know what's the deal.
(...)
Those aren't meaningful tests.
(...)
These are just kind of debugging things,
(...)
getting context, printing this context.
(...)
Discard those and I guess it didn't hurt to have these factories.
(...)
Perhaps for a later date,(...) try it again.
(...)
Okay, no problem. I'm gonna take a little bit of a break and reassess my plans. It's almost seven o'clock.
(...)
I don't mind wasting a couple hours here and there.
(...)
Battling some strange coding issues. It just happens this way sometimes.
(...)
I'd like to kind of work on something else, another task for Western Friend or else maybe some C++ code. So I might take a little bit of a break
(...)
and regain my thoughts and perhaps take another issue here. I'll just be right back.
(...)
(bell ringing)
(...)
(bell ringing) (piano music)
(...)
(piano music)
(...)
All right, thanks for your patience.
(...)
One thing did occur to me.
(...)
Bringing all this back up.
(...)
When I tested the setup,
(...)
I'm testing against the class instances, right?
(...)
But in our code,(...) it's failing.
(...)
So the test setup data is saying, hey, self tag.
(...)
Exist and the magazine is associated with it. I don't have that test. So what I'm gonna do actually is get magazine.
(...)
I'll get the article or the library.
(...)
Get the first and magazine. I'll get the first.(...) Gonna get the first, get the page, then assert tags in that. There we go. Cause that's where we're failing on the server in the view. If this passes it, I'm gonna be really just, I don't know.
(...)
But essentially this is allowing us to query from the collection.
(...)
And we'll stop the debugger. Cause this one I can just run in the terminal
(...)
and keep DB the first time.
(...)
(piano music)
(...)
Yeah, there we go. So this, I'm able to diagnose it. Okay.
(...)
Which is good. I've isolated it to a test case. We can just kind of figure it out and then in the testing environment.
(...)
Good.
(...)
(piano music)
(...)
(piano music)
(...)
I'm just gonna give this much context to a fresh chat GPD conversation, GPD four.
(...)
(piano music)
(...)
(keyboard clicking) (piano music)
(...)
And this could just be,
(...)
so the factory should return an instance.
(...)
And I've tested it the factory.
(...)
Instances work. (piano music) Yeah, I can actually write that in a test.
(...)
(piano music) (keyboard clicking)
(...)
All right, so what I'm gonna do then
(...)
is get the library item. (keyboard clicking) Now I get it. (piano music) Well, yeah, yeah.
(...)
magazine article, news item,(...) page,(...) add that, add that, add that, add that. (piano music)
(...)
I just see that this,
(...)
that's not the most exciting coding in the world I understand.
(...)
(keyboard clicking)
(...)
Hmm.
(...)
(keyboard clicking)
(...)
(piano music)
(...)
(keyboard clicking) The issue you're experiencing the test setup data method, it seems to relate to the way the test database is interacting with your objects and their tags.
(...)
In your test case, you're creating instances of library item and magazine article, news item, and page associated with the tag. However, when you're retrieving those objects from the database to check their tags, the association appears to be missing several factors of the issue. Database transactions.
(...)
Django's test framework uses database transactions to roll back the database to its original state after each test. If your test setup and actual tests are running in different transactions,
(...)
the changes made in the setup might not be visible in a test. Factory behavior, the factories library item factory, et cetera, might not be handling the many to many relationships correctly. Ensure that your factories are set up to handle many to many relationships properly. Cool, could be that.
(...)
Make sure that the,
(...)
since it's a diagnose and fixes issue, make sure that the creation of objects and the assertion checks are happening within the same transaction scope. Django's test case wraps each test method in a transaction and rolls back the transaction after each test.(...) So changes made in one test won't affect others. Review the factory implementation. Double check how your factories are implemented. Ensure that they handle the creation of the factory and the creation of many to many relationships correctly. So how do I do that? I think I did that here, right?
(...)
I create this thing,
(...)
add a tag.
(...)
(bell ringing)
(...)
(bell ringing) That's basically it. So we're going back through that collection.
(...)
Then we'll test the setup data again.
(...)
So maybe we're zeroing in on the factory.(...) Okay, so this one fails. All right, so there we go. That's the problem, no problem. I've been the factory.
(...)
(keyboard clicking) (soft music)
(...)
(keyboard clicking)
(...)
The factories aren't associating the tag correctly with the instances they create. There are, oh yeah.
(...)
Sorry, do this.
(...)
(bell ringing) All right.
(...)
(keyboard clicking)
(...)
So in this one, I really didn't even
(...)
use the setup method, sort of.
(...)
(soft music)
(...)
(keyboard clicking)
(...)
Okay,(...) sub.tag should just be tag.
(...)
(keyboard clicking)
(...)
Except for now. All right, so we're gonna run this as one test.
(...)
What's going on here?
(...)
I think it's an annotation.
(...)
Oh, no, it's the, that's the problem.
(...)
(soft music)
(...)
Indeed, okay, good. So failing, that's the same thing.(...) Now,(...) let's try the saving.
(...)
(keyboard clicking)
(...)
Damn.
(...)
(laughs)
(...)
(soft music)
(...)
I think I had arrived at that a little bit earlier. I touched on that. I need to save it.
(...)
All right, all right then.
(...)
(soft music)
(...)
No need.
(...)
In the, it's weird, in the shell, I didn't have to save it or something. There was some weirdness that led me to believe I didn't need to save it after each one. But now we know.(...) Knowing is half the battle,(...) just half.
(...)
Now we'll get this.
(...)
And,
(...)
then,
(...)
I don't know if this is still ready.
(...)
At least this far should work. We should know the right amount of items now that they've been saved.
(...)
Oh, man.
(...)
Goodness.(...) I knew it was something silly.
(...)
I was overlooking and feeling frustration. Just needed to step away for a minute.
(...)
And it looks like now we are
(...)
(soft music) I'll just get these, the comments are left, but the,
(...)
oh, I see what happened. The indentation's wrong. The indentation's wrong.
(...)
Yeah, no problem.
(...)
All right, cool. So sometimes,
(...)
things get frustrating, frustrating, man.
(...)
And little changes can be right in front of you, but so far away. So far away.
(...)
So yeah, we've got our working tests.
(...)
For, that was for one thing that I wanted to test, the order and the egg, but that's a really big thing.
(...)
That the query site content in order is correct. Really, that's the main use case. I think there was a couple others.
(...)
Pagination. All right. Okay, so now this is working.
(...)
So,
(...)
well, yeah, this is the first conversation.
(...)
Let's see if I can just do this with Co-Pilot.
(...)
The pagination test is gonna mean I need
(...)
at least 10 items.
(...)
So I would like to test that.
(...)
So what I will do,
(...)
is I will call this mainly, it's mainly to set up query site content over.
(...)
Did this distinguish it from
(...)
the pagination test, which will need sort of a different
(...)
test case, right? No, just testing and the hairs from test case. Okay, we got some suggestions there.
(...)
So pretty close.
(...)
Pretty close, but let's go back. Okay, so pagination requires at least 10 items.
(...)
Enter.
(...)
(soft music)
(...)
So n equals three.
(...)
Now range is,
(...)
let me just test this again.
(...)
(soft music) Okay, zero, one, two.
(...)
So it will be three.
(...)
The tag is a requirement.
(...)
So I might as well do that in the loop, right? So in the tags.
(...)
(soft music)(...) Yeah, just gonna use a little bit of spacing so I can see what's going on here.
(...)
Did I commit my previous tests?
(...)
No,(...) didn't. (soft music)
(...)
Let's just do that while I wasn't on a roll. I'm gonna kind of commit the good stuff.
(...)
Then we'll come back to this one.
(...)
(soft music)
(...)
Cancel that.
(...)
Add some linting. (soft music)(...) Let the CI run on that, but it was failing not relating to tests, but relating to the code quality scanning(...) that I will probably disable.
(...)
Okay, now we're gonna have the URL. I see that, I don't have that, so let's just get that URL right here.
(...)
(soft music)
(...)
And honestly, I should put that at the top of this setup function as well, and so the end sort of stands out a little better. Right after I create the tag, we can see, okay, this is the URL, we're gonna be using that tag slug.
(...)
The rest of the setup follows.
(...)
All right, I think pagination to work, that's like it. You have to just kind of set up the data,
(...)
test pagination.
(...)
Response, paginated items,(...) three equals 10.
(...)
Interesting,(...) that's a lot of assertions it made.
(...)
I'll be surprised if all those pass.
(...)
Yeah.
(...)
I think it's just directly on.
(...)
(soft music)
(...)
(soft music) So I'll look at our template. Where are we getting the number of pages from?
(...)
(soft music)
(...)
Paginator template.
(...)
(soft music)
(...)
Page, paginator number page.
(...)
That's one of the confusing things about the Django paginators, like, got self references or some kind of weirdness going on in there.
(...)
And I think this should be only two pages.
(...)
So we'll see about that. Maybe see if we get the property there.
(...)
Three is not equal to two.
(...)
Page,(...) paginator, yeah, all right, cool.
(...)
Number pages.
(...)
Yule.
(...)
Hey, there you go, because it just didn't do the math up here, which is kind of cool, it's fine, you know, four times three is 12 and somehow the math was like kind of too abstract for as much as it gave me. So it already gave me quite a lot.
(...)
Really remarkable how these can function.
(...)
All right, so.
(...)
(soft music)
(...)
(soft music)
(...)
We've essentially shoved the paginator over to page, so I could have just called it paginator.(...) Next page number.(...) (soft music)
(...)
And again, it's just a page.
(...)
And again, it's just a page.
(...)
And then again, it's just a page, I think. Yeah, it's gotta be page, everything. So really that's the paginator. This other thing is a class that I wrapped around the paginator and it's causing myself to be confused thoroughly.
(...)
Yeah, empty page.(...) Page number is less than one.
(...)
Which one was this?
(...)
(soft music)
(...)
Let's see.
(...)
So that number of pages passed.
(...)
Let me just make this a bit easier to follow.
(...)
We should get the first page.
(...)
Good.
(...)
Then,(...) next page should be two.
(...)
(soft music)
(...)
Previous page number should be none. I think this is the one that failed.
(...)
(soft music)
(...)
(soft music) Well, I'll leave this one out of it.
(...)
(soft music)
(...)
(soft music)(...) Cause this is already a pretty good test.
(...)
(soft music)
(...)
And we sort of have it tested up here.
(...)
I'll just take these two off.(...) (soft music)
(...)
So this works.
(...)
We've got an initial pagination thing. I think we're doing due diligence. It's not like perfect. There are some perhaps meaningful test cases where we've left off, but I don't want to test the whole paginator surface.
(...)
Some of the things that we can assume it works as long as we're checking our...
(...)
(soft music) Kind of like the specific context, which is like the number of pages we expect and things.
(...)
(soft music)
(...)
(soft music)
(...)
Then we don't need like these comments, right? The code is comment. And the good thing about the code being the comment is code changes, comment changes. Whereas that's not always a case when you change code and have a comment, you know, alongside the code, right? It's a little bit of a risk that the comment is not reflecting the status of the code anymore.
(...)
I will attempt to add one more test case inside of this test suite for the page number two. That means we're gonna sort of create the URL here.
(...)
With a query string argument page equals...
(...)
So def,(...) test page and second page.
(...)
Wow.
(...)
What?
(...)
Okay, cool.
(...)
Oh yeah, and this is the same two. Just not doing the math quite,(...) which is all right.
(...)
I mean, it did a lot already. Stuff that would baffle me, confuse me for hours
(...)
with only a minor incident. All right.(...) All right, now this is good.
(...)
I'll call this pull request done.(...) D-U-N.
(...)
(inhales deeply)
(...)
My goodness, that was good stuff.
(...)
About two hours in there, over two hours actually.
(...)
I'm gonna take a break. I'd like to continue, I'm gonna take a walk in the nice snowy weather outside, refresh my brain. And I'd like to continue with some just kind of more casual exploration of audio synthesis.
(...)
Synthesis with vis-a-vis, ra-k-ya.
(...)
Ding, ding, ding.
(...)
Oh, but I just realized my face is mirrored so that I look that way.
(...)
So the book is mirrored here, oh, like that. Make it worse.
(...)
Yep.
(...)
It's a book about a topic that is dear to my heart.
(...)
Called modular synthesis.(...) You could also think of it in a particular manifestation called vcb-rack.
(...)
Super good, so stay tuned, stay tuned. I'll be back.(...) After my walk, I'm gonna work on some vcb-rack.
(...)
Vc-rack is open source on GitHub.
(...)
And it's basically a Euro-rack simulator and it lets you use these kind of, normally what are hardware modules that kind of like are screwed into the rack interface and you plug wires between them and they do different things, wild and crazy things. And there's some really cool people who are doing these crazy things.
(...)
I like to do the things too.
(...)
But basically it's all signals. It's just all simulated electricity voltage. And that voltage is translated into knobs, that term. It's called control voltage. So instead of my hand turning the knob, the voltage turns the knob internally, it doesn't physically turn it, but in most cases, in any case, you plug the voltage in there, it'll either turn a knob, modulate it, or modulate the pitch.(...) And this is called volt per octave. So every volt that increases it, so one volt, two volts is an octave span, a musical octave. These are the two principal things that came together
(...)
through Pioneer Bob Moog.
(...)
The volt per octave I think was only a Bob Moog thing. Not a Don Buechle thing. I think Buechle had a different approach to the voltage pitch relationship. But nonetheless, volt per octave and control voltage, the two paradigms came together and the modular paradigm was born. Some 60 years ago, 50 years ago.
(...)
And now we have new generations coming around in the 1990s and just kind of exploding in popularity in the current times called EuroRack. And so that's what this VCP rack is a EuroRack simulator. So you don't have to actually own all this hardware, but frankly, I'm trying to own less stuff, trying to dematerialize, and especially with supply chain constraints and global issues, pandemics, conflicts.(...) I think less stuff is more. All these components have to be manufactured from rare earth minerals and use petroleum and ship them around and all that stuff. But this concept is, since this is modular, since this is very interesting, so I'm glad we have a virtual way of doing it. So I can just use this already, here's I've already got these electronics that have already been assembled and manufactured(...) and transported and they're already on my desk. I don't have to buy more stuff to share some creativity.(...) So yeah, that's VCWack in a nutshell. I will take a break in, come back and we'll check out some more rack in particular. How can you make your own modules?(...) And maybe just another quick demo of like, how does rack work?
(...)
Okay, so if you'd like to check out this pull request
(...)
that we've got here,
(...)
you can ignore the red X, that's coming from DeepSource.
(...)
But anyway, here it is.
(...)
I'll check the DeepSource areas and see what's going on, but I'll probably merge this soon. Pull request 1015,(...) closing issue number 1014. To try to reduce our reliance on the search page
(...)
in an effort to make our software a little bit more efficient, the resource usage is more efficient reducing the resource consumption and in response to excessive consumption from bots. I don't know what to do about the bots, but at least we'll try to save some resources. All right, this has been a live code hangout. Thanks for joining on Twitch. If you're subscribed on Twitter, let me know your thoughts. If you've got any suggestions or projects you'd like to share,
(...)
add a comment there and I appreciate your time. Have a great day. See you around.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment