Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ assert MonthEvents('active', now.year, now.month).has_events_marked() == True
How many users have been active this week?:

```python
print(len(WeekEvents('active', now.year, now.isocalendar()[1])))
iso_year, iso_week, _ = now.isocalendar()
print(len(WeekEvents('active', iso_year, iso_week)))
```

Iterate over all users active this week:
Expand Down Expand Up @@ -111,7 +112,8 @@ MonthEvents('active').from_date(now) == MonthEvents('active', now.year, now.mont
Get the list of these users (user ids):

```python
print(list(WeekEvents('active', now.year, now.isocalendar()[1])))
iso_year, iso_week, _ = now.isocalendar()
print(list(WeekEvents('active', iso_year, iso_week)))
```

There are special methods `prev` and `next` returning "sibling" events and
Expand Down
3 changes: 2 additions & 1 deletion bitmapist/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@

How many users have been active this week?::

print len(WeekEvents('active', now.year, now.isocalendar()[1]))
iso_year, iso_week, _ = now.isocalendar()
print len(WeekEvents('active', iso_year, iso_week))

Perform bit operations. Which users that have been active last month are still active this month?::

Expand Down
3 changes: 2 additions & 1 deletion bitmapist/cohort/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,8 @@ def _day_events_fn(key: str, date: date, system: str):

def _weeks_events_fn(key: str, date: date, system: str):
cls = WeekEvents
cls_args = (date.year, date.isocalendar()[1], system)
iso_year, iso_week, _ = date.isocalendar()
cls_args = (iso_year, iso_week, system)
return _dispatch(key, cls, cls_args)


Expand Down
5 changes: 3 additions & 2 deletions test/test_bitmapist.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ def test_mark_with_diff_days():
assert 124 not in MonthEvents("active", now.year, now.month)

# Week
assert 123 in WeekEvents("active", now.year, now.isocalendar()[1])
assert 124 not in WeekEvents("active", now.year, now.isocalendar()[1])
iso_year, iso_week, _ = now.isocalendar()
assert 123 in WeekEvents("active", iso_year, iso_week)
assert 124 not in WeekEvents("active", iso_year, iso_week)

# Day
assert 123 in DayEvents("active", now.year, now.month, now.day)
Expand Down
37 changes: 29 additions & 8 deletions test/test_cohort.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from datetime import datetime, timedelta, timezone
from datetime import date, datetime, timedelta, timezone

import pytest

from bitmapist import mark_event
from bitmapist.cohort import get_dates_data
from bitmapist.cohort import _weeks_events_fn, get_dates_data


@pytest.fixture
Expand Down Expand Up @@ -35,22 +35,16 @@ def events():
("active", None, "active", None, [2, 100, 50]),
("active", None, "unknown", None, [2, "", ""]),
("unknown", None, "active", None, [0, "", ""]),

# Tests with select1b (AND conditions for select1)
("signup", "active", "active", None, [2, 100, 50]),

# Tests with both select1b and select2b
("task1", "task2", "task2", "task1", [2, 100, 100]),

# When select1 has no events but select1b has events, result should be 0
("unknown", "active", "active", None, [0, "", ""]),

# When select1 has events but select2 AND select2b results in 0
("active", None, "unknown", "active", [2, "", ""]),

# When select1 has events but select1b has no events (no overlap)
("active", "unknown", "active", None, [0, "", ""]),

# When select2 has events but select2b has no events (no overlap)
("active", None, "active", "unknown", [2, "", ""]),
],
Expand All @@ -67,3 +61,30 @@ def test_cohort(select1, select1b, select2, select2b, expected, events):
num_of_rows=1,
)
assert r[0][1:] == expected


def test_weeks_events_fn_iso_year_boundary():
"""Test that _weeks_events_fn uses ISO year, not calendar year.

At year boundaries, a date's calendar year can differ from its ISO year.
For example, Dec 30, 2024 is in ISO week 1 of 2025.
"""
# Dec 30, 2024 is a Monday in ISO week 1 of 2025
dec_30_2024 = date(2024, 12, 30)
iso_year, iso_week, _ = dec_30_2024.isocalendar()
assert iso_year == 2025 # Verify our test date assumption
assert iso_week == 1

event = _weeks_events_fn("test_event", dec_30_2024, "default")
# Should use ISO year (2025), not calendar year (2024)
assert event.year == 2025
assert event.week == 1

# Jan 1, 2025 is also in ISO week 1 of 2025
jan_1_2025 = date(2025, 1, 1)
event2 = _weeks_events_fn("test_event", jan_1_2025, "default")
assert event2.year == 2025
assert event2.week == 1

# Both dates should produce the same week event
assert event.redis_key == event2.redis_key