Skip to content

Instantly share code, notes, and snippets.

@brylie
Created January 2, 2024 18:54
Show Gist options
  • Save brylie/44a50ad32d588d40219c021199457110 to your computer and use it in GitHub Desktop.
Save brylie/44a50ad32d588d40219c021199457110 to your computer and use it in GitHub Desktop.
Code with Brylie - e42
(...) Hello and welcome to an open source live code hangout. Today we're going to work on the Jerry Life project.
(...)
And I'm going to try to see if I can fix a strange bug I found yesterday.
(...)
It's a floating point rounding bug.
(...)
Might be a good challenge to tackle with the help of chatgpt.
(...)
Sorry I couldn't find a mute in time.
(...)
We're on the server.
(...)
Got my ectoplasm here.
(...)
On the server.
(...)
Loaded up.
(...)
We'll take a look at this list of homes here.
(...)
What we'll notice is we have 14 plus 14, 28,
(...)
71.(...) So this should be 72.
(...)
Not really great with math and numbers.
(...)
Pretty sure those are not matching.
(...)
So otherwise we're getting pretty far along here. We're doing pretty good.
(...)
So what I'm going to do is find the source where these are calculated.
(...)
Now what's happening is they're actually really long floating point numbers. And I rounded them in the template. Using float format.
(...)
It basically truncates. I'm not even sure. It may be. I don't know how it works internally. But it rounds to like one decimal place or zero in this case. And so it just takes the next one and rounds up or down. But it's not quite working correctly.
(...)
So I'll locate the code.
(...)
It generates the data for this. Chart and the chart's using a couple of places.
(...)
It's coming from the home. Now one thing I might do is migrate this away from the home.
(...)
But I've got a home model here.
(...)
And the function is a few nested functions here for sort of a testability.
(...)
Testability. But here's the top level function.
(...)
Right.
(...)
So the resident counts by activity level.
(...)
And this is where we are.
(...)
So what we do is get a.
(...)
List of the home residents. Where I think it's a query set.
(...)
And each of those resident has a count of the number of activities they participate in. Participated in in the last seven days.
(...)
And we're going to create a counting dictionary.
(...)
And maybe a better way of doing this but we have some weekly activity ranges. And if it falls into that range of each of those will iterate.
(...)
And then if we had a count.
(...)
Total count.
(...)
For that resident.
(...)
Oh after going through all the residents that is. Sorry to say. We're going to look at the total count.
(...)
So this is where.
(...)
We're not normalizing.
(...)
Or to ensure that it is they sum up to 100 percent I believe if I abstract this into a separate yet another helper function.
(...)
That takes a data frame. It has a total count column.
(...)
Pends it.
(...)
There's going to be some logic here.
(...)
And the resident counts back to be level.
(...)
And we'll actually want is the resident percent back to be activity level.
(...)
In the case of this chart.
(...)
And I don't know if normalize is the right word here but normalize means everything is scaled between one and zero. But the means are also that they're.(...) They should sum to one.
(...)
And they were operating at the.
(...)
This is where if I extract these two functions it'll be better because I can. And take this signature.
(...)
If I look at this chart I need to make sure it's now I'm refactoring it.
(...)
Instead of having a list of each of the activity type.
(...)
With the formatting.(...) I have a dictionary so I would have to change.
(...)
The structure of the template and I prefer not to do that so this won't quite work.
(...)
So let's go ahead.
(...)
So we get the activity counts by resident activity activity level.
(...)
But you see this is still.
(...)
Not quite doing it so that's fine.
(...)
Now I have that.
(...)
I believe I need to sum to one.
(...)
And see what it says.
(...)
To ensure that the percentage is some up to one hundred normalize the calculated percentages so they're totally equals one hundred.
(...)
This involves dividing each percentage by the total of all calculated percentages and multiplying by one hundred.
(...)
Here's how you can modify calculate the raw percentages as you're doing some these raw percentages divided raw percentage by the sum.
(...)
And multiply one hundred to get the normalized percentages.
(...)
Interesting.
(...)
Let's try it out.
(...)
So it's like scaling it and rescaling it.
(...)
And then what I'm going to do. Oh boy. Indentation error.(...) It's something that always gets me there's got to be a way I can paste and the tool knows that I'm pasting something that's indented and then it's the second line.
(...)
Now we're going to use this instead on the home detail page.
(...)
And then hopefully we can refresh it to work.
(...)
All right. All right.
(...)
This could be any number of things. First I should test it probably. In a shell environment so I can say from home. Models.
(...)
And some models import home.
(...)
It's like equals to reason internal idea to make it easy and read this new idea there makes it more URL friendly and a bit obscure.
(...)
Then we get that.
(...)
Okay.
(...)
I don't think this is going to work but.
(...)
I guess the function works.
(...)
Let's check the DOM real quick.
(...)
So we have some little.
(...)
There's the bar container.
(...)
It has nothing in it so.
(...)
I didn't read it very closely so.
(...)
Kind of silly to expect it to arbitrarily.
(...)
Were.
(...)
Right.(...) Okay.
(...)
So then the other thing was.
(...)
I'm actually using this help with the chart data so that's all I need to change it and locate this.
(...)
Because the chart data is slightly different.
(...)
Here we are.
(...)
Different shape its key values.
(...)
Localizing it.
(...)
Okay.
(...)
I just need to pull these in.
(...)
And this is already here so I don't need to reevaluate that.
(...)
But I do need to say total count.
(...)
So it's zero will return.
(...)
Now we should have something. It's taking a bit. It's not subscriptable. Okay. Right. So. It's good to do that.
(...)
Run it. Evaluate it. I didn't use it properly.
(...)
I'm a bit inconsistent there. Everything else is a property but.(...) I'm on the cusp. Here we go. 14.
(...)
17. 71.
(...)
It's not as easy.
(...)
You know it's not that big of a bug but.
(...)
I forgot to mention.
(...)
So I like to run into integer.
(...)
Percents I don't need the point percent. It does make so much sense. It's not important information.
(...)
Rounding is percentage to the nearest integer wall and sharing a sum up to one of it can be a bit tricky. Do the rounding errors that may occur. Common approaches to handle this. So use a method that adjusts the rounding of the percentages so that their sum is one hundred remains one hundred.(...) Here's a revised version of your function to achieve this. Calculate the raw percentages as floating point numbers.
(...)
Around these percentages to the nearest integer.(...) Keeping track of the total. If the total sum of the rounded percentages is not 100. Adjust the percentages with the largest fractional parts until the sum is correct. Interesting.
(...)
Man.
(...)
That's why I split it down to a separate function because I figured it would be complicated.
(...)
Is there a Python library that does this for us?
(...)
We have NumPy we've got.
(...)
But yeah it's going around only a single digit. We need the whole thing.
(...)
It's basically the same thing so I don't know if it's perhaps more efficient or legible.
(...)
Slightly less code because mostly it's vectorized.
(...)
Perhaps.
(...)
And.
(...)
Expandatory variables will sort of like say what we're trying to do there. Difference too big difference too small something like that.
(...)
Should increment should decrement. I was thinking of you know it's comparing the size but it's a bit.
(...)
Terse I guess.
(...)
Pretty dang good. Wow.
(...)
So we need to import NumPy. I like the NumPy solution. As far as I know we're going to keep it around because it's a wrap pandas and we're using pandas for some of our visualizations aggregations in it. I mean.
(...)
And we need to fix the indentation.
(...)
And import NumPy as in P.
(...)
Hopefully things will.
(...)
Sort of work out of the box there.
(...)
I saw some wiggling.
(...)
15 14 71. Wow.
(...)
Crazy. Crazy.
(...)
Now it would be nice to start annotating these with it and whether or not it's a query set and things like that or a data frame.
(...)
And keeping things as a query set as long as possible because I believe even passing it into functions the Django ORM can still optimize them.
(...)
So wow that worked.
(...)
78.
(...)
We actually need to commit something. OK well we're gonna read some of those changes then maybe it will let us open up PorePress, it button before.
(...)
Okay, now we're going to work on some unit tests.
(...)
This is an important feature. It's a subtle one, but there's some layers that we're doing here, so...
(...)
Make sure it works.
(...)
Now one fundamental thing is,(...) before I get too far down the road here,
(...)
how much do I want these to be model methods versus just functions?
(...)
How close is their relationship to the home and where are they going to be used?
(...)
We've got several model property methods on the home model.
(...)
And here I'm using a combination of...(...) Well, this is all data frames at this point.
(...)
Here I'm only pivoting in the function.
(...)
Okay.
(...)
Home resident count specs at activity level shouldn't include the percentages.
(...)
Or is it because these are...
(...)
Yeah, it's perhaps just the order.
(...)
It's a bit flaky.
(...)
I've got counts and then percents.
(...)
(piano music) - All right, so good active count is
(...)
the first in our list,(...) but total count is the first in the other list. All right, so I think this is what I need to do.
(...)
There's gotta be a way to make this list brittle.
(...)
(piano music) Total count to total count to good active count and active count.
(...)
Low active count.
(...)
(piano music) Might have to run it in debug mode.
(...)
Assuming good active count and high active count.
(...)
(piano music)
(...)
(piano music) (piano music)
(...)
And it should be 50-50.
(...)
Oh man.
(...)
Inactive present.
(...)
(piano music)
(...)
It's really hard to see the differing values here.
(...)
Let's run it in debug mode.
(...)
(sniffs) (piano music)
(...)
Yeah, I might have to, in any case, rewrite these tests. (piano music)
(...)
(piano music) The resident counts by activity level.
(...)
(piano music)
(...)
Oh, I see totally what I'm doing. Isn't there? Yeah, it shouldn't return the percents. That's correct.(...) Right, I moved that out. Okay, so, so easy. That's clear now. Good, plus, it was literally pointing to me. You did the right thing. There we go.
(...)
Okay, perfect. Much better.(...) More testable.
(...)
(piano music)
(...)
Let's just run everything.
(...)
(piano music)
(...)
Now we're gonna do the same thing.
(...)
At least we have confidence that this...
(...)
(piano music)
(...)
I know this should be a property, that this function works.(...) (piano music)
(...)
Just the name.
(...)
(piano music) But this also includes the counts.
(...)
(piano music) (piano music) Well, this is actually pretty good.
(...)
(piano music)
(...)
It would, however, it would change
(...)
if I had a third resident.
(...)
I think I should do this.
(...)
Now, I don't know if this is deterministic.
(...)
You have 33, 33, 33, how does it determine? (piano music) Which one to round up?
(...)
(piano music) (piano music)
(...)
I suppose as long as they sum to 100,
(...)
not sure if it matters.
(...)
(piano music)
(...)
We'll commit this.
(...)
That way I don't get too far ahead of myself before making a change. I'm gonna make a change to the setup,
(...)
which is gonna essentially break the tests.
(...)
(piano music)
(...)
(piano music) And I'll add a current resident,(...) high active.
(...)
(piano music)
(...)
Well, let's see, we have an inactive
(...)
and we have a low active.
(...)
(piano music)
(...)
So first I need to.
(...)
(piano music)
(...)
Grab all instances of this.
(...)
(piano music) (piano music)
(...)
(piano music)(...) Make sure everything passes.
(...)
(piano music)
(...)
(piano music) (piano music) And I'm gonna get the constant value
(...)
from the activity thresholds. So we're kind of coupling this in case we decide to refactor or change the rules of how we calculate the active. Hopefully it'll be a little bit more robust to that.
(...)
(piano music)
(...)
(piano music)
(...)
So then I need to create a residency.
(...)
(piano music)
(...)
(piano music)
(...)
(piano music) (piano music)
(...)
(piano music)
(...)
We'll come back to this and create several resident activities for that residency.
(...)
Current resident inactive,(...) current resident low active.
(...)
(piano music)
(...)
(piano music) Yeah, no, that was correct.
(...)
(piano music)
(...)
Now,
(...)
(piano music) (groans) (piano music)
(...)
See if that even works.
(...)
(piano music) Main inclusive.
(...)
(piano music)
(...)
So we're just gonna create another number of activities here.
(...)
(piano music)
(...)
(piano music) Yeah.
(...)
(piano music)
(...)
And we'll iterate up to that.
(...)
Now in the range,(...) it takes the stop. So this will stop right before.
(...)
(piano music)
(...)
Oh, man.(...) (piano music)
(...)
(piano music) Or,
(...)
max inclusive, well, whatever.
(...)
(piano music)
(...)
(piano music)
(...)
Yeah, so that's gonna cause our,
(...)
our tests to break.
(...)
So first one is to test the mock data.
(...)
973.
(...)
So we should have four residencies.
(...)
Yes.
(...)
And then how many is that gonna run total to?
(...)
(piano music)
(...)
(piano music) (piano music)
(...)
(piano music)
(...)
So I don't know if this is gonna be brittle.
(...)
(piano music)
(...)
(piano music)
(...)
Yeah, these names are not deterministic, so.
(...)
(piano music)
(...)
(piano music)(...) Alice, Pauline, Bob.
(...)
A, (piano music) P, B.
(...)
(piano music)
(...)
So Bob should not be first, but Bob is second.
(...)
(piano music) A, B, P. (piano music)
(...)
I believe this is the order that they will come out. Oh, we got two Bobs.
(...)
Barbara.
(...)
Barbara.
(...)
Let's see, where's Barbara?
(...)
Alice and Barbara.(...) (piano music)
(...)
So there's that, Alice.
(...)
Call them by their first name and their variable name and it'll be less confusing.
(...)
Okay.
(...)
Less failures, less failures.
(...)
Now we've got some moderate success.
(...)
Moderate.
(...)
Everything in moderation.
(...)
Including moderation, as the saying goes.
(...)
So,
(...)
now here's the interesting thing.
(...)
I guess the first one's always gonna be the worst one.
(...)
It's a pessimistic model.
(...)
33.
(...)
And 33.
(...)
I need to assert that they all sum up to 100.
(...)
(piano music)
(...)
(piano music)
(...)
See if that works there.
(...)
Good.
(...)
It did.
(...)
This one
(...)
is three active residents run one and one. (piano music)
(...)
I mean, knocking them down.
(...)
Oh boy.
(...)
So this was
(...)
first, that.
(...)
Then
(...)
that.
(...)
Then 34.
(...)
33.
(...)
33. This is, I'm a bit worried about that.
(...)
And one more though.
(...)
Her current residence is four.
(...)
Wow.
(...)
That's a good one. Improved the tests.
(...)
Oh no.
(...)
Synchronizing. Synchronizing.
(...)
Reload.
(...)
And this is just time we,(...) it failed in the last run.
(...)
(piano music)
(...)
There is a bit of cognitive complexity.
(...)
New results being calculated.
(...)
All right. Cool with that.
(...)
(piano music)
(...)
(piano music)
(...)
Test coverage 100% on this diff. That's good.
(...)
It's going to improve the test coverage by half a percent. Not bad. Almost 80%. We're really close.
(...)
Really close to 80%.
(...)
I need to do a more systematic
(...)
approach. Basically looking through this test coverage.
(...)
Tackling it.
(...)
I suspect a lot of it is these methods are untested or at least indirectly tested.
(...)
But I'm not going to do that in this pull request. Ah, it looks like we're good to go.
(...)
So now when I go back here,(...) home.(...) 57 plus 43. Yeah, if I do the arithmetic.
(...)
That one we checked.
(...)
13. Oh, I don't want to do the arithmetic on the live stream.
(...)
Oh, wait a minute.
(...)
13. 13 plus 50 is 63.
(...)
Is there a 1%?
(...)
Yeah.
(...)
Man.
(...)
[Music]
(...)
Just trying to think here.(...) There's a way I can just make this simpler.(...) [Music]
(...)
Hmm. [Music]
(...)
So it works in like, you know, the three. Oh, wait a minute.
(...)
That could have been an old refresh. Let me just double check here.
(...)
Please.
(...)
Go back to the homes page. I think that was a cached version of the page.
(...)
57.(...) Yes.
(...)
So we check this one. No 15.
(...)
Oh, 29.
(...)
[Music]
(...)
[Music] Yeah, man.
(...)
[Music]
(...)
Yes, we're good. We're good. Well, I'm getting this has to prove it. All right. This has been another live code hangout. We've been working on the, I forgot to link this in the beginning. We've been working on the Jerry Life caregiving project. If you'd like to check out this project, it's open source on GitHub.
(...)
Oh, yeah, it's down here at the bottom there. Over here. Right there. Boom. The whole time it's been there. So I don't have to do that as much. But there's the project in the chat. And here is the pull request I've been working on. It's where it's at. [Music]
(...)
See the exact changes that we introduced here.(...) You know, a little bit over 100 lines of code. Not bad overall.(...) So it's been a great experience. I think the co-pilot, as you can see, has really,(...) and chat GPT in particular, which I think co-pilot is powered by chat GPT nonetheless.(...) Really transformative in the way I'm working and giving a lot more confidence to doing fairly complicated things,(...) including writing and fixing unit tests, which is kind of tedious at times. But even like ensuring that percentage values always sum up to the 100%. You know, that's a non-trivial thing. Some people out there have figured it out.
(...)
I don't necessarily have the math skills or background in its error prone. So I would prefer if the library actually handled it for me. Without that, that would get some help. And then of course write the unit tests to ensure that it's behaving as we're expecting that.
(...)
That was a pretty sophisticated yet...(...) Yeah, sophisticated method it wrote, function,(...) including using NumPy and writing clean code by using explanatory variables. All right, this has been another live code open source hangout. Hope you're doing well and have a great day.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment