Skip to content
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

added Yearly Reading Goals to /stats page #9301

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

kevinc16
Copy link

@kevinc16 kevinc16 commented May 20, 2024

Closes #7352

Added summary and total_yearly_reading_goals functions to yearly_reading_goals.py. Added unit test for total_yearly_reading_goals function. Added Yearly Reading Goals row in openlibrary/templates/admin/index.html.

Let me know if there are things we want to change!

Technical

There are a few things to note:

  1. First, during testing, I found that for some reason the key in the storage object (noted by @scottbarnes in 7352/yearly reading goal stats #7560 (comment), Scott is also right that the other functions are documented incorrectly - they return Storage objects not ints) in the unit test is different from when the application is run (that is the reason in the HTML file the key is 'count' while in the unit test it is 'count(*)')

Application log:

web-1           | total_yearly_reading_goals (<Storage {'count': 1}>,)
web-1           | total_yearly_reading_goals (<Storage {'count': 1}>,)
web-1           | total_yearly_reading_goals (<Storage {'count': 1}>,)

But when I use the key 'count' in the unit tests:

====================================================================================== FAILURES ======================================================================================
_______________________________________________________________ TestYearlyReadingGoals.test_total_yearly_reading_goals _______________________________________________________________
self = <core.test_db.TestYearlyReadingGoals object at 0x7f8426bf9dc0>

    def test_total_yearly_reading_goals(self):
>       assert BookshelvesEvents.total_yearly_reading_goals()['count'] == 3
E       KeyError: 'count'

openlibrary/tests/core/test_db.py:523: KeyError
-------------------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------------------
total_yearly_reading_goals (<Storage {'count(*)': 3}>,)
  1. The second is that I noticed the other stat functions (e.g., total_books_logged in openlibrary/core/bookshelves.py) don't have unit tests - is there a specific reason for that?

Testing

UI changes and docker compose run --rm home make test.

Screenshot

1

Stakeholders

@jimchamp

Copy link
Collaborator

@jimchamp jimchamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kevinc16! This all seems to be working as expected. The only problem is that we asked you to place the new yearly_reading_goals DB functions in the wrong file. Could you move those functions to this file and update their references?

Comment on lines 22 to 34
@classmethod
def summary(cls):
return {
'total_yearly_reading_goals': {
'total': BookshelvesEvents.total_yearly_reading_goals(),
'month': BookshelvesEvents.total_yearly_reading_goals(
since=DATE_ONE_MONTH_AGO
),
'week': BookshelvesEvents.total_yearly_reading_goals(
since=DATE_ONE_WEEK_AGO
),
},
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move this and the total_yearly_reading_goals function to https://github.com/internetarchive/openlibrary/blob/master/openlibrary/core/yearly_reading_goals.py?

"""
oldb = db.get_db()

query = "SELECT count(*) from yearly_reading_goals"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After moving this function to core/yearly_reading_goals.py, please replace the hard-coded table name with TABLENAME:

TABLENAME = 'yearly_reading_goals'

Comment on lines 156 to 157
results = tuple(oldb.query(query, vars={'since': since}))
print('total_yearly_reading_goals', results)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
results = tuple(oldb.query(query, vars={'since': since}))
print('total_yearly_reading_goals', results)
results = list(oldb.query(query, vars={'since': since}))

While casting to a tuple works here, please cast to a list instead. This is how it's done throughout the codebase, and I'm not sure if using tuple here may have unintended side-effects.

Also, remove the print statement.

@jimchamp
Copy link
Collaborator

The second is that I noticed the other stat functions (e.g., total_books_logged in openlibrary/core/bookshelves.py) don't have unit tests - is there a specific reason for that?

We simply don't have good test coverage.

@jimchamp jimchamp added the Needs: Submitter Input Waiting on input from the creator of the issue/pr [managed] label May 31, 2024
@kevinc16 kevinc16 force-pushed the 7352/feature/yearly-reading-goals-stats branch from d5d25cf to 5af03de Compare June 6, 2024 03:46
@github-actions github-actions bot removed the Needs: Submitter Input Waiting on input from the creator of the issue/pr [managed] label Jun 6, 2024
@kevinc16 kevinc16 force-pushed the 7352/feature/yearly-reading-goals-stats branch from 5af03de to 5cf7f6f Compare June 6, 2024 03:51
@kevinc16
Copy link
Author

kevinc16 commented Jun 6, 2024

The second is that I noticed the other stat functions (e.g., total_books_logged in openlibrary/core/bookshelves.py) don't have unit tests - is there a specific reason for that?

We simply don't have good test coverage.

I see - do you think you think we should make an issue for that? I wouldn't mind adding a few more unit tests (for the related functions on the stats page - and also updating the comments 😁).

Also, in terms of the 1st point I raised in my PR, is there anything that should be noted there?

@kevinc16 kevinc16 requested a review from jimchamp June 6, 2024 04:02
Copy link
Collaborator

@jimchamp jimchamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again. @kevinc16! Just make sure that totaly_yearly_reading_goals returns an int, and remove the unit tests. Due to the way that these DB unit tests are currently set up, some functions cannot be tested.

Comment on lines 84 to 85
results = list(oldb.query(query, vars={'since': since}))
return results[0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
results = list(oldb.query(query, vars={'since': since}))
return results[0]
results = oldb.query(query, vars={'since': since})
return results[0]['count'] if results else 0

Just return an int here. This follows the same pattern used in Booknotes.total_booknotes.

Comment on lines 72 to 74
def total_yearly_reading_goals(cls, since: date | None = None) -> int:
"""Returns a Storage object of <Storage {'count': int}> where 'count' specifies the
number reading goals updated. `since` may be used
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def total_yearly_reading_goals(cls, since: date | None = None) -> int:
"""Returns a Storage object of <Storage {'count': int}> where 'count' specifies the
number reading goals updated. `since` may be used
def total_yearly_reading_goals(cls, since: date | None = None) -> int:
"""Returns the number reading goals that were set. `since` may be used

Type hints and docstring are conflicting. Return an int here.

Comment on lines 522 to 531
def test_total_yearly_reading_goals(self):
assert YearlyReadingGoals.total_yearly_reading_goals()['count(*)'] == 3
# Combination of issues
assert (
YearlyReadingGoals.total_yearly_reading_goals(since="2022-12-25")[
'count(*)'
]
== 1
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_total_yearly_reading_goals(self):
assert YearlyReadingGoals.total_yearly_reading_goals()['count(*)'] == 3
# Combination of issues
assert (
YearlyReadingGoals.total_yearly_reading_goals(since="2022-12-25")[
'count(*)'
]
== 1
)

Just remove this test. The DB used for this test is not mocked --- we spin up an instance of sqlite for these tests, but we use Postgres in production. It looks like the key for the counts is different depending on which DB is used.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, that explains why they are different in the 2 places - but if that is the case, why don't we just mock the Postgres DB? Is there a specific reason?

@jimchamp jimchamp added the Needs: Submitter Input Waiting on input from the creator of the issue/pr [managed] label Jun 10, 2024
@jimchamp
Copy link
Collaborator

If you want to add more unit tests, create a feature request proposal issue and outline what test you will be adding.

@kevinc16 kevinc16 force-pushed the 7352/feature/yearly-reading-goals-stats branch from d9ce955 to 4439cc6 Compare June 10, 2024 22:44
@github-actions github-actions bot removed the Needs: Submitter Input Waiting on input from the creator of the issue/pr [managed] label Jun 10, 2024
@kevinc16 kevinc16 requested a review from jimchamp June 10, 2024 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Yearly Reading Goals to /stats
2 participants