diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml new file mode 100644 index 0000000..c39f350 --- /dev/null +++ b/.github/workflows/python-tests.yml @@ -0,0 +1,27 @@ +name: Python package + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.13"] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + # This case we are only updating pip, but you could add other dependencies if needed. + run: | + python -m pip install --upgrade pip + python -m pip install pytest + # ⚠️⚠️⚠️ FIXME Is there anything else that needs to be installed? + - name: Test with pytest + run: | + pytest \ No newline at end of file diff --git a/README.md b/README.md index 72585a5..ee3a6dd 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ uv add --dev pytest > ``` > > The `time_range` function generates the observation blocks for a given start and end time, a number of intervals and a duration for the gaps. For the first row above, this would be: -> `"2025-06-25 00:00:00", "2025-06-25 00:11:00", 2, 60` +> `"2025-06-01 00:00:00", "2025-06-01 00:11:00", 2, 60` > and for the second: > `"2025-01-01 00:02:00", "2025-01-01 00:12:00", 4, 120`. > And the `compute_overlap_time` should provide: > ```python -> [('2020-01-01 00:02:00', '2020-01-01 00:03:00'), # first interval -> ('2020-01-01 00:08:00', '2020-01-01 00:09:00')] # second interval +> [('2025-01-01 00:02:00', '2025-01-01 00:03:00'), # first interval +> ('2025-01-01 00:08:00', '2025-01-01 00:09:00')] # second interval > ``` ## Step 2: Writing a unit test diff --git a/__pycache__/test_parametrize.cpython-313-pytest-8.4.1.pyc b/__pycache__/test_parametrize.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 0000000..056598a Binary files /dev/null and b/__pycache__/test_parametrize.cpython-313-pytest-8.4.1.pyc differ diff --git a/__pycache__/test_time.cpython-313-pytest-8.4.1.pyc b/__pycache__/test_time.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 0000000..f9ddc37 Binary files /dev/null and b/__pycache__/test_time.cpython-313-pytest-8.4.1.pyc differ diff --git a/__pycache__/times.cpython-313-pytest-8.4.1.pyc b/__pycache__/times.cpython-313-pytest-8.4.1.pyc new file mode 100644 index 0000000..f7d3717 Binary files /dev/null and b/__pycache__/times.cpython-313-pytest-8.4.1.pyc differ diff --git a/__pycache__/times.cpython-313.pyc b/__pycache__/times.cpython-313.pyc new file mode 100644 index 0000000..6b27121 Binary files /dev/null and b/__pycache__/times.cpython-313.pyc differ diff --git a/test_parametrize.py b/test_parametrize.py new file mode 100644 index 0000000..ff381b3 --- /dev/null +++ b/test_parametrize.py @@ -0,0 +1,41 @@ +import pytest +from times import time_range, compute_overlap_time + + +@pytest.mark.parametrize( + "test_input1, test_input2, expected", + [ + pytest.param( + time_range("2010-01-12 10:00:00", "2010-01-12 12:00:00"), + time_range("2010-01-12 10:30:00", "2010-01-12 10:45:00", 2, 60), + [ + ("2010-01-12 10:30:00", "2010-01-12 10:37:00"), + ("2010-01-12 10:38:00", "2010-01-12 10:45:00"), + ], + id="given input", + ), + pytest.param( + time_range("2010-01-12 10:00:00", "2010-01-12 12:00:00"), + time_range("2010-01-13 10:30:00", "2010-01-13 10:45:00", 2, 60), + [], + id="no overlap", + ), + pytest.param( + time_range("2025-01-01 00:00:00", "2025-01-01 00:11:00", 2, 60), + time_range("2025-01-01 00:02:00", "2025-01-01 00:12:00", 4, 120), + [ + ("2025-01-01 00:02:00", "2025-01-01 00:03:00"), + ("2025-01-01 00:08:00", "2025-01-01 00:09:00"), + ], + id="multiple intervals", + ), + pytest.param( + time_range("2025-06-25 00:00:00", "2025-06-25 00:11:00"), + time_range("2025-06-25 00:11:00", "2025-06-25 00:22:00"), + [], + id="edge case", + ), + ], +) +def test_eval(test_input1, test_input2, expected): + assert compute_overlap_time(test_input1, test_input2) == expected diff --git a/test_time.py b/test_time.py new file mode 100644 index 0000000..a8a76fd --- /dev/null +++ b/test_time.py @@ -0,0 +1,48 @@ +from times import time_range, compute_overlap_time +from pytest import raises + + +def test_given_input(): + large = time_range("2010-01-12 10:00:00", "2010-01-12 12:00:00") + short = time_range("2010-01-12 10:30:00", "2010-01-12 10:45:00", 2, 60) + result = compute_overlap_time(large, short) + expected = [ + ("2010-01-12 10:30:00", "2010-01-12 10:37:00"), + ("2010-01-12 10:38:00", "2010-01-12 10:45:00"), + ] + + assert result == expected + + +def test_no_overlap(): + large = time_range("2010-01-12 10:00:00", "2010-01-12 12:00:00") + short = time_range("2010-01-13 10:30:00", "2010-01-13 10:45:00", 2, 60) + result = compute_overlap_time(large, short) + expected = [] + + assert result == expected + + +def test_multi_intervals(): + large = time_range("2025-01-01 00:00:00", "2025-01-01 00:11:00", 2, 60) + short = time_range("2025-01-01 00:02:00", "2025-01-01 00:12:00", 4, 120) + result = compute_overlap_time(large, short) + print(result) + expected = [ + ("2025-01-01 00:02:00", "2025-01-01 00:03:00"), + ("2025-01-01 00:08:00", "2025-01-01 00:09:00"), + ] + assert result == expected + + +def test_edge_case(): + first = time_range("2025-06-25 00:00:00", "2025-06-25 00:11:00") + second = time_range("2025-06-25 00:11:00", "2025-06-25 00:22:00") + result = compute_overlap_time(first, second) + expected = [] + assert result == expected + + +def test_start_ends(): + with raises(ValueError, match=r"Start time must be before end time"): + time_range("2025-01-01 00:01:00", "2025-01-01 00:00:00") diff --git a/times.py b/times.py index d57f401..932a83e 100644 --- a/times.py +++ b/times.py @@ -4,11 +4,26 @@ def time_range(start_time, end_time, number_of_intervals=1, gap_between_intervals_s=0): start_time_s = datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") end_time_s = datetime.datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S") - d = (end_time_s - start_time_s).total_seconds() / number_of_intervals + gap_between_intervals_s * (1 / number_of_intervals - 1) - sec_range = [(start_time_s + datetime.timedelta(seconds=i * d + i * gap_between_intervals_s), - start_time_s + datetime.timedelta(seconds=(i + 1) * d + i * gap_between_intervals_s)) - for i in range(number_of_intervals)] - return [(ta.strftime("%Y-%m-%d %H:%M:%S"), tb.strftime("%Y-%m-%d %H:%M:%S")) for ta, tb in sec_range] + if start_time_s > end_time_s: + raise ValueError("Start time must be before end time") + d = ( + end_time_s - start_time_s + ).total_seconds() / number_of_intervals + gap_between_intervals_s * ( + 1 / number_of_intervals - 1 + ) + sec_range = [ + ( + start_time_s + + datetime.timedelta(seconds=i * d + i * gap_between_intervals_s), + start_time_s + + datetime.timedelta(seconds=(i + 1) * d + i * gap_between_intervals_s), + ) + for i in range(number_of_intervals) + ] + return [ + (ta.strftime("%Y-%m-%d %H:%M:%S"), tb.strftime("%Y-%m-%d %H:%M:%S")) + for ta, tb in sec_range + ] def compute_overlap_time(range1, range2): @@ -17,10 +32,12 @@ def compute_overlap_time(range1, range2): for start2, end2 in range2: low = max(start1, start2) high = min(end1, end2) - overlap_time.append((low, high)) + if low < high: + overlap_time.append((low, high)) return overlap_time + if __name__ == "__main__": large = time_range("2010-01-12 10:00:00", "2010-01-12 12:00:00") short = time_range("2010-01-12 10:30:00", "2010-01-12 10:45:00", 2, 60) - print(compute_overlap_time(large, short)) \ No newline at end of file + print(compute_overlap_time(large, short))