diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..c10780c6 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13.1 diff --git a/docker-compose.yml b/docker-compose.yml index b9f5a375..c437bbb9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,7 @@ services: - ./lung_cancer_screening:/app/lung_cancer_screening restart: unless-stopped + asset_builder: build: context: . diff --git a/tests/.gitkeep b/lung_cancer_screening/calculators/__init__.py similarity index 100% rename from tests/.gitkeep rename to lung_cancer_screening/calculators/__init__.py diff --git a/lung_cancer_screening/calculators/plco.py b/lung_cancer_screening/calculators/plco.py new file mode 100644 index 00000000..dd2c0cf2 --- /dev/null +++ b/lung_cancer_screening/calculators/plco.py @@ -0,0 +1,55 @@ +from decimal import Decimal, getcontext + +getcontext().prec = 999999 + +class Plco: + AGE_COEFFICIENT = Decimal('0.0778868') + AGE_CENTRED_OR_REFERENT_REF_GROUP = Decimal('62') + BMI_COEFFICIENT = Decimal('-0.0274194') + BMI_CENTRED_OR_REFERENT_REF_GROUP = Decimal('27') + COPD_ENPHYSEMA_OR_CHRONIC_BRONCHITIS_COEFFICIENT = Decimal('0.3553063') + PERSONAL_HISTORY_OF_CANCER_COEFFICIENT = Decimal('0.4589971') + FAMILY_HISTORY_OF_CANCER_COEFFICIENT = Decimal('0.587185') + + def __init__(self, + age, + bmi, + copd_enphysema_or_chronic_bronchitis, + personal_history_of_cancer, + family_history_of_cancer): + self.age = Decimal(str(age or 0)) + self.bmi = Decimal(str(bmi or 0)) + self.copd_enphysema_or_chronic_bronchitis = copd_enphysema_or_chronic_bronchitis + self.personal_history_of_cancer = personal_history_of_cancer + self.family_history_of_cancer = family_history_of_cancer + + def age_in_years_contribution_to_estimate(self): + return (self.age - self.AGE_CENTRED_OR_REFERENT_REF_GROUP) * self.AGE_COEFFICIENT + + def bmi_contribution_to_estimate(self): + return (self.bmi - self.BMI_CENTRED_OR_REFERENT_REF_GROUP) * self.BMI_COEFFICIENT + + def copd_enphysema_or_chronic_bronchitis_contribution_to_estimate(self): + if self.copd_enphysema_or_chronic_bronchitis is None: + raise self.InvalidValueError( + "copd_enphysema_or_chronic_bronchitis must be set") + + return self.copd_enphysema_or_chronic_bronchitis * self.COPD_ENPHYSEMA_OR_CHRONIC_BRONCHITIS_COEFFICIENT + + + def personal_history_of_cancer_contribution_to_estimate(self): + if self.personal_history_of_cancer is None: + raise self.InvalidValueError( + "personal_history_of_cancer must be set") + + return self.personal_history_of_cancer * self.PERSONAL_HISTORY_OF_CANCER_COEFFICIENT + + def family_history_of_cancer_contribution_to_estimate(self): + if self.family_history_of_cancer is None: + raise self.InvalidValueError( + "family_history_of_cancer must be set") + + return self.family_history_of_cancer * self.FAMILY_HISTORY_OF_CANCER_COEFFICIENT + + class InvalidValueError(Exception): + pass diff --git a/lung_cancer_screening/calculators/tests/__init__.py b/lung_cancer_screening/calculators/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lung_cancer_screening/calculators/tests/test_plco.py b/lung_cancer_screening/calculators/tests/test_plco.py new file mode 100644 index 00000000..42331bb8 --- /dev/null +++ b/lung_cancer_screening/calculators/tests/test_plco.py @@ -0,0 +1,117 @@ +from django.test import TestCase +from decimal import Decimal + +from lung_cancer_screening.calculators.plco import Plco + +class TestPlco(TestCase): + def setUp(self): + self.defaultArgs = { + "age": 62, + "bmi": 27, + "copd_enphysema_or_chronic_bronchitis": False, + "personal_history_of_cancer": False, + "family_history_of_cancer": False + } + + def test_age_in_years_contribution_to_estimate_when_age_is_none(self): + calculator = Plco(**dict(self.defaultArgs, age=None)) + result = calculator.age_in_years_contribution_to_estimate() + + self.assertEqual(result, Decimal('-4.8289816')) + + def test_age_in_years_contribution_to_estimate_at_74(self): + calculator = Plco(**dict(self.defaultArgs, age=74)) + result = calculator.age_in_years_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.9346416')) + + def test_age_in_years_contribution_to_estimate_at_62(self): + calculator = Plco(**dict(self.defaultArgs, age=58)) + result = calculator.age_in_years_contribution_to_estimate() + + self.assertEqual(result, Decimal('-0.3115472')) + + def test_bmi_contribution_to_estimate_when_bmi_is_none(self): + calculator = Plco(**dict(self.defaultArgs, bmi=None)) + result = calculator.bmi_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.7403238')) + + def test_bmi_contribution_to_estimate_when_bmi_is_23_point_5(self): + calculator = Plco(**dict(self.defaultArgs, bmi=23.5)) + result = calculator.bmi_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.0959679')) + + def test_bmi_contribution_to_estimate_when_bmi_is_a_long_decimal(self): + calculator = Plco(**dict(self.defaultArgs, bmi="26.4749212")) + result = calculator.bmi_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.01439734564872')) + + def test_copd_enphysema_or_chronic_bronchitiscontribution_to_estimate_when_none(self): + calculator = Plco(**dict(self.defaultArgs, copd_enphysema_or_chronic_bronchitis=None)) + + self.assertRaises( + Plco.InvalidValueError, + calculator.copd_enphysema_or_chronic_bronchitis_contribution_to_estimate + ) + + def test_copd_enphysema_or_chronic_bronchitiscontribution_to_estimate_when_true(self): + calculator = Plco(**dict(self.defaultArgs, copd_enphysema_or_chronic_bronchitis=True)) + + result = calculator.copd_enphysema_or_chronic_bronchitis_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.3553063')) + + def test_copd_enphysema_or_chronic_bronchitiscontribution_to_estimate_when_false(self): + calculator = Plco(**dict(self.defaultArgs, copd_enphysema_or_chronic_bronchitis=False)) + + result = calculator.copd_enphysema_or_chronic_bronchitis_contribution_to_estimate() + + self.assertEqual(result, Decimal('0')) + + def test_personal_history_of_cancer_contribution_to_estimate_when_none(self): + calculator = Plco(**dict(self.defaultArgs, personal_history_of_cancer=None)) + + self.assertRaises( + Plco.InvalidValueError, + calculator.personal_history_of_cancer_contribution_to_estimate + ) + + def test_personal_history_of_cancer_contribution_to_estimate_when_true(self): + calculator = Plco(**dict(self.defaultArgs, personal_history_of_cancer=True)) + + result = calculator.personal_history_of_cancer_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.4589971')) + + def test_personal_history_of_cancer_contribution_to_estimate_when_false(self): + calculator = Plco(**dict(self.defaultArgs, personal_history_of_cancer=False)) + + result = calculator.personal_history_of_cancer_contribution_to_estimate() + + self.assertEqual(result, Decimal('0')) + + def test_family_history_of_cancer_contribution_to_estimate_when_none(self): + calculator = Plco(**dict(self.defaultArgs, family_history_of_cancer=None)) + + self.assertRaises( + Plco.InvalidValueError, + calculator.family_history_of_cancer_contribution_to_estimate + ) + + def test_family_history_of_cancer_contribution_to_estimate_when_true(self): + calculator = Plco(**dict(self.defaultArgs, family_history_of_cancer=True)) + + result = calculator.family_history_of_cancer_contribution_to_estimate() + + self.assertEqual(result, Decimal('0.587185')) + + def test_family_history_of_cancer_contribution_to_estimate_when_false(self): + calculator = Plco(**dict(self.defaultArgs, family_history_of_cancer=False)) + + result = calculator.family_history_of_cancer_contribution_to_estimate() + + self.assertEqual(result, Decimal('0')) + diff --git a/lung_cancer_screening/settings.py b/lung_cancer_screening/settings.py index a153d970..68d23928 100644 --- a/lung_cancer_screening/settings.py +++ b/lung_cancer_screening/settings.py @@ -47,7 +47,8 @@ def boolean_env(key, default=None): 'django.contrib.messages', 'django.contrib.staticfiles', 'lung_cancer_screening.core', - 'lung_cancer_screening.questions' + 'lung_cancer_screening.questions', + 'lung_cancer_screening.calculators', ] MIDDLEWARE = [