Skip to content

Commit d0c78df

Browse files
author
Keng Susumpow
committed
Add GitHub Actions workflows for release and testing, implement comprehensive tests for epidemiological week calculations
1 parent 3cfcb58 commit d0c78df

File tree

10 files changed

+511
-6
lines changed

10 files changed

+511
-6
lines changed

.github/workflows/release.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up Python
15+
uses: actions/setup-python@v4
16+
with:
17+
python-version: '3.11'
18+
19+
- name: Install dependencies
20+
run: |
21+
python -m pip install --upgrade pip
22+
pip install build twine
23+
24+
- name: Build package
25+
run: python -m build
26+
27+
- name: Check distribution
28+
run: twine check dist/*
29+
30+
- name: Create GitHub Release
31+
uses: actions/create-release@v1
32+
env:
33+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34+
with:
35+
tag_name: ${{ github.ref }}
36+
release_name: Release ${{ github.ref }}
37+
draft: false
38+
prerelease: false

.github/workflows/test.yml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v4
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Install dependencies
25+
run: |
26+
python -m pip install --upgrade pip
27+
pip install -r requirements-dev.txt
28+
pip install -e .
29+
30+
- name: Run tests with pytest
31+
run: |
32+
pytest tests/ -v --tb=short --cov=epydem --cov-report=xml --cov-report=term-missing
33+
34+
- name: Test package functionality
35+
run: |
36+
python -c "
37+
import epydem
38+
result = epydem.calculate('2024-01-01')
39+
print(f'2024-01-01 is epidemiological week {result}')
40+
assert result > 0, 'Expected positive week number'
41+
print('Package functionality test passed')
42+
"
43+
44+
- name: Upload coverage to Codecov
45+
uses: codecov/codecov-action@v4
46+
with:
47+
file: ./coverage.xml
48+
flags: unittests
49+
name: codecov-umbrella
50+
fail_ci_if_error: false
51+
52+
lint:
53+
runs-on: ubuntu-latest
54+
steps:
55+
- uses: actions/checkout@v4
56+
57+
- name: Set up Python
58+
uses: actions/setup-python@v4
59+
with:
60+
python-version: '3.11'
61+
62+
- name: Install dependencies
63+
run: |
64+
python -m pip install --upgrade pip
65+
pip install flake8 black isort
66+
67+
- name: Lint with flake8
68+
run: |
69+
# stop the build if there are Python syntax errors or undefined names
70+
flake8 epydem --count --select=E9,F63,F7,F82 --show-source --statistics
71+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
72+
flake8 epydem --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
73+
74+
- name: Check code formatting with black
75+
run: |
76+
black --check epydem
77+
78+
- name: Check import sorting with isort
79+
run: |
80+
isort --check-only epydem
81+
82+
- name: Check tests formatting
83+
run: |
84+
black --check tests/

.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Python bytecode
2+
__pycache__/
3+
*.py[cod]
4+
*.pyo
5+
6+
# Package build artifacts
7+
*egg-info/
8+
build/
9+
dist/
10+
11+
# Testing
12+
.pytest_cache/
13+
14+
# Virtual environments
15+
venv/
16+
.venv/
17+
18+
# IDE
19+
.vscode/
20+
.idea/
21+
22+
# macOS
23+
.DS_Store

CLAUDE.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Epydem is a Python library for epidemiological data analysis, specifically focused on calculating epidemiological week numbers from date strings. The library provides a single main function that converts dates in YYYY-MM-DD format to epidemiological week numbers.
8+
9+
## Development Commands
10+
11+
```bash
12+
# Install the package locally for development
13+
pip install .
14+
15+
# Install from GitHub
16+
pip install git+https://github.com/kengggg/epydem.git
17+
18+
# Build the package
19+
python setup.py build
20+
21+
# Create source distribution
22+
python setup.py sdist
23+
```
24+
25+
## Code Architecture
26+
27+
The library follows a simple, focused architecture:
28+
29+
- **epydem/__init__.py**: Exports the main `calculate` function as the public API
30+
- **epydem/epiweek.py**: Contains the core epidemiological week calculation logic
31+
- `calculate(date_str)`: Main function that takes YYYY-MM-DD date string and returns epidemiological week number
32+
- `_verify_date_str(date_str)`: Private helper function for strict date format validation
33+
34+
## Key Implementation Details
35+
36+
- **Date Format**: Strictly enforces YYYY-MM-DD format using regex validation
37+
- **Epidemiological Week Logic**: Week 1 starts on the Sunday before the first Thursday of the year
38+
- **Error Handling**: Raises ValueError with descriptive messages for invalid date formats
39+
- **Return Values**: Returns week numbers 1-53, or 0 for dates before the start of the epidemiological year
40+
41+
## Code Conventions
42+
43+
- Private functions are prefixed with underscore (e.g., `_verify_date_str`)
44+
- Comprehensive docstrings following Python conventions with Args, Returns, and Raises sections
45+
- Clean public API exposure through `__init__.py`
46+
- No external dependencies - uses only Python standard library
47+
48+
## Testing Notes
49+
50+
Currently no test framework is configured. When adding tests, follow the existing function naming patterns and ensure coverage of:
51+
- Valid date inputs across different years
52+
- Invalid date format handling
53+
- Edge cases around year boundaries
54+
- Week 0 scenarios

README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,45 @@
11
# Epydem
22

3-
`Epydem` is a Python library for epidemiological data analysis.
3+
`Epydem` is a Python library for calculating epidemiological week numbers from date strings.
4+
5+
## Features
6+
7+
- Calculate epidemiological week numbers from YYYY-MM-DD formatted dates
8+
- Follows standard epidemiological week definition where week 1 starts on the Sunday before the first Thursday of the year
9+
- Returns week numbers 1-53, or 0 for dates before the epidemiological year starts
10+
- Strict date format validation with clear error messages
411

512
## Installation
613

714
You can install the library using pip:
815

916
```bash
1017
pip install git+https://github.com/kengggg/epydem.git
18+
```
19+
20+
## Usage
21+
22+
```python
23+
import epydem
24+
25+
# Calculate epidemiological week for a date
26+
week_number = epydem.calculate('2024-01-01')
27+
print(week_number) # Output: 1
28+
29+
# Week 1 starts on the Sunday before the first Thursday
30+
week_number = epydem.calculate('2024-01-04') # First Thursday of 2024
31+
print(week_number) # Output: 1
32+
33+
# Dates before the epidemiological year return 0
34+
week_number = epydem.calculate('2023-12-31') # Before 2024's epi year
35+
print(week_number) # Output: 0
36+
```
37+
38+
## Epidemiological Week Definition
39+
40+
Epidemiological weeks follow the standard definition:
41+
42+
- Week 1 is the first week that contains the first Thursday of the year
43+
- Each epidemiological week starts on Sunday and ends on Saturday
44+
- The epidemiological year may start in the previous calendar year
45+
- Week numbers range from 1-53, with 0 for dates before the epidemiological year begins

epydem/epiweek.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def calculate(date_str):
1313
date_str (str): The date in 'YYYY-MM-DD' format.
1414
1515
Returns:
16-
int: The epidemiological week number. Returns 0 if the date is
16+
int: The epidemiological week number (1-53). Returns 0 if the date is
1717
before the start of the epidemiological year.
1818
1919
Raises:
@@ -23,14 +23,19 @@ def calculate(date_str):
2323
date = datetime.strptime(date_str, '%Y-%m-%d')
2424
year = date.year
2525

26-
year_start = datetime(year, 1, 1)
27-
week_start = year_start - timedelta(days=year_start.weekday() + 1)
26+
# Find the first Thursday of the year
27+
jan_1 = datetime(year, 1, 1)
28+
days_to_thursday = (3 - jan_1.weekday()) % 7
29+
first_thursday = jan_1 + timedelta(days=days_to_thursday)
30+
31+
# The epidemiological week 1 starts on the Sunday before the first Thursday
32+
epi_week_1_start = first_thursday - timedelta(days=3)
2833

2934
# If the date is before the start of the epidemiological year, it's week 0
30-
if date < week_start:
35+
if date < epi_week_1_start:
3136
return 0
3237
else:
33-
return (date - week_start).days // 7
38+
return ((date - epi_week_1_start).days // 7) + 1
3439

3540
def _verify_date_str(date_str):
3641
"""

pytest.ini

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[tool:pytest]
2+
testpaths = tests
3+
python_files = test_*.py
4+
python_functions = test_*
5+
python_classes = Test*
6+
addopts =
7+
-v
8+
--tb=short
9+
--strict-markers
10+
--disable-warnings
11+
minversion = 6.0

requirements-dev.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pytest>=6.0.0
2+
pytest-cov>=2.10.0

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)