From 8baacf6adf2d81225f6b51f4448323f3321c622f Mon Sep 17 00:00:00 2001 From: Jon Banafato Date: Thu, 16 Sep 2021 18:22:02 -0400 Subject: [PATCH] Second attempt at fixing timezone test issues This is a followup to #10. It turns out that `freezegun` does not yet support `dateutil`'s `tzlocal`, which is used by `timew-report` [here]. [This comment] on the `freezegun` repository provides a context manager solution that can be used for now. This change properly fixes #6. [here]: https://github.com/lauft/timew-report/blob/c972357a44640c7a5f803d79fc77ca597e1b22f0/timewreport/interval.py#L49 [This comment]: https://github.com/lauft/timew-report/blob/c972357a44640c7a5f803d79fc77ca597e1b22f0/timewreport/interval.py#L49 --- Pipfile | 1 - Pipfile.lock | 34 +-------------------- tests/test_invoice.py | 71 +++++++++++++++++++++++++++---------------- tests/testsupport.py | 1 - 4 files changed, 46 insertions(+), 61 deletions(-) diff --git a/Pipfile b/Pipfile index cc2feea..b22ba5e 100644 --- a/Pipfile +++ b/Pipfile @@ -8,7 +8,6 @@ timew-report = "<1.3" [dev-packages] pytest = "*" -pytest-freezegun = "*" [requires] python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock index 539eeca..f602cd4 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "008ea2855063155133d59a7470bd38d965c8028f0b40c74f427c96cccd61ef52" + "sha256": "9041881b029e904d14ec563c5cdde0731eb0ffbc0f28bf37dc5ff30dd22e3556" }, "pipfile-spec": 6, "requires": { @@ -49,14 +49,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.2.0" }, - "freezegun": { - "hashes": [ - "sha256:177f9dd59861d871e27a484c3332f35a6e3f5d14626f2bf91be37891f18927f3", - "sha256:2ae695f7eb96c62529f03a038461afe3c692db3465e215355e1bb4b0ab408712" - ], - "markers": "python_version >= '3.5'", - "version": "==1.1.0" - }, "importlib-metadata": { "hashes": [ "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15", @@ -112,30 +104,6 @@ "index": "pypi", "version": "==6.2.5" }, - "pytest-freezegun": { - "hashes": [ - "sha256:19c82d5633751bf3ec92caa481fb5cffaac1787bd485f0df6436fd6242176949", - "sha256:5318a6bfb8ba4b709c8471c94d0033113877b3ee02da5bfcd917c1889cde99a7" - ], - "index": "pypi", - "version": "==0.4.2" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", diff --git a/tests/test_invoice.py b/tests/test_invoice.py index f85ac38..6d7de4e 100644 --- a/tests/test_invoice.py +++ b/tests/test_invoice.py @@ -1,3 +1,6 @@ +import contextlib +import os +import time import unittest from datetime import datetime, timedelta, timezone from random import randint @@ -11,6 +14,21 @@ from billwarrior.invoice import Invoice, ItemCategory, LineItem +@contextlib.contextmanager +def mock_tz(new_tz): + old_tz = os.environ.get('TZ') + os.environ['TZ'] = new_tz + time.tzset() + try: + yield + finally: + if old_tz is not None: + os.environ['TZ'] = old_tz + else: + del os.environ['TZ'] + time.tzset() + + class BillWarriorConfigFake(BillWarriorConfig): def __init__(self): pass @@ -57,28 +75,28 @@ def test_creates_different_categories_from_interval_tags_and_mapping(self): self.assertEqual(str(expected_a), str(items[0])) self.assertEqual(str(expected_b), str(items[1])) - @pytest.mark.freeze_time(tz_offset=2) def test_groups_intervals_of_same_category(self): - same_day = datetime.today() - a, b, c = ( - tests.give_interval(same_day, tags=["on-site", "coding"]), - tests.give_interval(same_day, tags=["coding", "off-site"]), - tests.give_interval(tags=["coding", "cafe"]), - ) + with mock_tz('UTC'): + same_day = datetime.today() + a, b, c = ( + tests.give_interval(same_day, tags=["on-site", "coding"]), + tests.give_interval(same_day, tags=["coding", "off-site"]), + tests.give_interval(tags=["coding", "cafe"]), + ) - billw_config = BillWarriorConfigFake.build({"coding": "Consulting & Research"}) + billw_config = BillWarriorConfigFake.build({"coding": "Consulting & Research"}) - invoice = Invoice([a, b, c], billw_config) - items = invoice.items() + invoice = Invoice([a, b, c], billw_config) + items = invoice.items() - expected = ItemCategory( - "Consulting & Research", - {same_day.date(): [a, b], c.get_date().date(): [c]}, - 0.0, - ) + expected = ItemCategory( + "Consulting & Research", + {same_day.date(): [a, b], c.get_date().date(): [c]}, + 0.0, + ) - self.assertEqual(len(items), 1) # one category - self.assertEqual(str(items[0]), str(expected)) + self.assertEqual(len(items), 1) # one category + self.assertEqual(str(items[0]), str(expected)) def test_raises_exception_when_interval_sorts_into_more_than_one_category(self): a, b = ( @@ -228,17 +246,18 @@ def test_items_omitted_when_unit_price_is_negative(self): self.assertEqual(str(category), "") def test_line_items_should_be_populated_with_entries_per_day(self): - a_day = datetime.today() - entries = [ - [tests.give_interval(a_day + timedelta(days=1))], - [tests.give_interval(a_day + timedelta(days=2))], - [tests.give_interval(a_day + timedelta(days=3))], - ] - intervals_by_day = {entry[0].get_date().date(): entry for entry in entries} + with mock_tz('UTC'): + a_day = datetime.today() + entries = [ + [tests.give_interval(a_day + timedelta(days=1))], + [tests.give_interval(a_day + timedelta(days=2))], + [tests.give_interval(a_day + timedelta(days=3))], + ] + intervals_by_day = {entry[0].get_date().date(): entry for entry in entries} - category = ItemCategory("arbitray category", intervals_by_day, 0.0) + category = ItemCategory("arbitray category", intervals_by_day, 0.0) - self.assertEqual(len(category.line_items), len(entries)) + self.assertEqual(len(category.line_items), len(entries)) def test_line_items_should_be_sorted_by_date(self): entries = [ diff --git a/tests/testsupport.py b/tests/testsupport.py index aca281e..397cf2f 100644 --- a/tests/testsupport.py +++ b/tests/testsupport.py @@ -15,4 +15,3 @@ def give_interval(day=None, tags=[]): end = start + timedelta(0, randint(60 * 5, 60 * 60 * 2)) # up to 2h return TimeWarriorInterval(start.strftime(DT_FORMAT), end.strftime(DT_FORMAT), tags) -