edc-vitals 1.0.0__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/.pre-commit-config.yaml +4 -4
- edc_vitals-1.1.0/AUTHORS +2 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/PKG-INFO +3 -2
- edc_vitals-1.1.0/edc_vitals/calculators/__init__.py +1 -0
- edc_vitals-1.1.0/edc_vitals/calculators/bmi.py +69 -0
- edc_vitals-1.1.0/edc_vitals/form_validators/__init__.py +5 -0
- edc_vitals-1.1.0/edc_vitals/form_validators/bmi_form_validator_mixin.py +19 -0
- edc_vitals-1.0.0/edc_vitals/form_validators/weight_height_bmi_form_validator_mixin.py → edc_vitals-1.1.0/edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py +2 -1
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/model_mixins/weight_height_bmi_model_mixin.py +1 -1
- edc_vitals-1.1.0/edc_vitals/tests/tests/test_calculators.py +77 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/tests/test_weight_height_bmi.py +1 -2
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals.egg-info/PKG-INFO +3 -2
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals.egg-info/SOURCES.txt +5 -1
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/pyproject.toml +1 -2
- edc_vitals-1.0.0/AUTHORS +0 -1
- edc_vitals-1.0.0/edc_vitals/form_validators/__init__.py +0 -2
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/.coveragerc +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/.editorconfig +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/.github/workflows/build.yml +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/.gitignore +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/.yamllint +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/CHANGES +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/LICENSE +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/MANIFEST.in +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/README.rst +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/codecov.yml +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/apps.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/migrations/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/model_mixins/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/model_mixins/blood_pressure_model_mixin.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/blood_pressure.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/heart_rate.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/height.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/respiratory_rate.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/temperature.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/waist_circumference.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/models/fields/weight.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-aes-local.key +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-aes-restricted.key +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-rsa-local-private.pem +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-rsa-local-public.pem +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-rsa-restricted-private.pem +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-rsa-restricted-public.pem +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-salt-local.key +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/etc/user-salt-restricted.key +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/models.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/test_settings.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/tests/__init__.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/tests/test_blood_pressure.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/tests/test_heart_rate.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/tests/test_respiratory_rate.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/tests/test_temperature.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/tests/urls.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/utils.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals/validators.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals.egg-info/dependency_links.txt +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals.egg-info/not-zip-safe +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/edc_vitals.egg-info/top_level.txt +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/runtests.py +0 -0
- {edc_vitals-1.0.0 → edc_vitals-1.1.0}/setup.cfg +0 -0
@@ -3,20 +3,20 @@ exclude: tests/etc/user-*
|
|
3
3
|
|
4
4
|
repos:
|
5
5
|
- repo: https://github.com/PyCQA/bandit
|
6
|
-
rev: 1.8.
|
6
|
+
rev: 1.8.3
|
7
7
|
hooks:
|
8
8
|
- id: bandit
|
9
9
|
args:
|
10
10
|
- "-x *test*.py"
|
11
11
|
|
12
12
|
- repo: https://github.com/psf/black
|
13
|
-
rev:
|
13
|
+
rev: 25.1.0
|
14
14
|
hooks:
|
15
15
|
- id: black
|
16
16
|
language_version: python3.12
|
17
17
|
|
18
18
|
- repo: https://github.com/pycqa/flake8
|
19
|
-
rev: 7.
|
19
|
+
rev: 7.2.0
|
20
20
|
hooks:
|
21
21
|
- id: flake8
|
22
22
|
args:
|
@@ -45,7 +45,7 @@ repos:
|
|
45
45
|
- id: trailing-whitespace
|
46
46
|
|
47
47
|
- repo: https://github.com/adrienverge/yamllint
|
48
|
-
rev: v1.
|
48
|
+
rev: v1.37.0
|
49
49
|
hooks:
|
50
50
|
- id: yamllint
|
51
51
|
args:
|
edc_vitals-1.1.0/AUTHORS
ADDED
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: edc-vitals
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.1.0
|
4
4
|
Summary: Classes for BP, weight, etc for clinicedc/edc projects
|
5
5
|
Home-page: https://github.com/clinicedc/edc-vitals
|
6
6
|
Author: Erik van Widenfelt
|
@@ -19,6 +19,7 @@ Requires-Python: >=3.12
|
|
19
19
|
Description-Content-Type: text/x-rst
|
20
20
|
License-File: LICENSE
|
21
21
|
License-File: AUTHORS
|
22
|
+
Dynamic: license-file
|
22
23
|
|
23
24
|
|
24
25
|
|pypi| |actions| |codecov| |downloads|
|
@@ -0,0 +1 @@
|
|
1
|
+
from .bmi import BMI, CalculatorError, calculate_bmi
|
@@ -0,0 +1,69 @@
|
|
1
|
+
from dateutil.relativedelta import relativedelta
|
2
|
+
from edc_utils import age, get_utcnow
|
3
|
+
from edc_utils.round_up import round_half_away_from_zero
|
4
|
+
|
5
|
+
__all__ = ["calculate_bmi", "BMI", "CalculatorError"]
|
6
|
+
|
7
|
+
|
8
|
+
class CalculatorError(Exception):
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class BMI:
|
13
|
+
"""Calculate BMI, raise if not adult."""
|
14
|
+
|
15
|
+
def __init__(
|
16
|
+
self,
|
17
|
+
weight_kg=None,
|
18
|
+
height_cm=None,
|
19
|
+
lower_bmi_value=None,
|
20
|
+
upper_bmi_value=None,
|
21
|
+
dob=None,
|
22
|
+
report_datetime=None,
|
23
|
+
**kwargs,
|
24
|
+
):
|
25
|
+
if not weight_kg or not height_cm:
|
26
|
+
raise CalculatorError(f"Unable to calculate BMI. Got {weight_kg}kg, {height_cm}cm")
|
27
|
+
if age(dob, report_datetime).years < 18:
|
28
|
+
raise CalculatorError("Unable to calculate BMI. Got age<18")
|
29
|
+
self.lower = float(lower_bmi_value or 5.0)
|
30
|
+
self.upper = float(upper_bmi_value or 75.0)
|
31
|
+
self.weight = float(weight_kg)
|
32
|
+
self.height = float(height_cm) / 100.0
|
33
|
+
self.raw_bmi_value = self.weight / (self.height**2)
|
34
|
+
if not (self.lower <= self.raw_bmi_value <= self.upper):
|
35
|
+
raise CalculatorError(
|
36
|
+
"BMI value is absurd. "
|
37
|
+
f"Using {self.weight}kg, {self.height}m. Got {self.value}."
|
38
|
+
)
|
39
|
+
|
40
|
+
@property
|
41
|
+
def value(self):
|
42
|
+
return round_half_away_from_zero(self.raw_bmi_value, 4)
|
43
|
+
|
44
|
+
|
45
|
+
def calculate_bmi(
|
46
|
+
weight_kg=None,
|
47
|
+
height_cm=None,
|
48
|
+
lower_bmi_value=None,
|
49
|
+
upper_bmi_value=None,
|
50
|
+
dob=None,
|
51
|
+
report_datetime=None,
|
52
|
+
**kwargs,
|
53
|
+
):
|
54
|
+
"""Returns a BMI instance or None.
|
55
|
+
|
56
|
+
Assumes adult dob (18) if dob not provided."""
|
57
|
+
bmi = None
|
58
|
+
if height_cm and weight_kg:
|
59
|
+
report_datetime = report_datetime or get_utcnow()
|
60
|
+
bmi = BMI(
|
61
|
+
weight_kg=weight_kg,
|
62
|
+
height_cm=height_cm,
|
63
|
+
lower_bmi_value=lower_bmi_value,
|
64
|
+
upper_bmi_value=upper_bmi_value,
|
65
|
+
dob=dob or report_datetime - relativedelta(years=18),
|
66
|
+
report_datetime=report_datetime,
|
67
|
+
**kwargs,
|
68
|
+
)
|
69
|
+
return bmi
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from django import forms
|
2
|
+
|
3
|
+
from ..calculators import CalculatorError, calculate_bmi
|
4
|
+
|
5
|
+
__all__ = ["BmiFormValidatorMixin"]
|
6
|
+
|
7
|
+
|
8
|
+
class BmiFormValidatorMixin:
|
9
|
+
def validate_bmi(self, **kwargs):
|
10
|
+
try:
|
11
|
+
bmi = calculate_bmi(
|
12
|
+
height_cm=self.cleaned_data.get("height"),
|
13
|
+
weight_kg=self.cleaned_data.get("weight"),
|
14
|
+
**self.cleaned_data,
|
15
|
+
**kwargs,
|
16
|
+
)
|
17
|
+
except CalculatorError as e:
|
18
|
+
raise forms.ValidationError(e)
|
19
|
+
return bmi
|
@@ -0,0 +1,77 @@
|
|
1
|
+
from dateutil.relativedelta import relativedelta
|
2
|
+
from django import forms
|
3
|
+
from django.test import TestCase, tag
|
4
|
+
from edc_constants.constants import BLACK, MALE
|
5
|
+
from edc_form_validators import FormValidator
|
6
|
+
from edc_utils import get_utcnow
|
7
|
+
from edc_utils.round_up import round_half_away_from_zero
|
8
|
+
|
9
|
+
from edc_vitals.calculators import BMI, CalculatorError, calculate_bmi
|
10
|
+
from edc_vitals.form_validators import BmiFormValidatorMixin
|
11
|
+
|
12
|
+
|
13
|
+
class TestCalculators(TestCase):
|
14
|
+
@tag("1")
|
15
|
+
def test_bmi_calculator(self):
|
16
|
+
dob = get_utcnow() - relativedelta(years=25)
|
17
|
+
self.assertRaises(CalculatorError, BMI, weight_kg=56, height_cm=None)
|
18
|
+
try:
|
19
|
+
calculate_bmi(weight_kg=56, height_cm=None, dob=dob)
|
20
|
+
except CalculatorError:
|
21
|
+
self.fail("CalculatorError unexpectedly raised ")
|
22
|
+
|
23
|
+
for func in [BMI, calculate_bmi]:
|
24
|
+
with self.subTest(func=func):
|
25
|
+
self.assertRaises(
|
26
|
+
CalculatorError,
|
27
|
+
func,
|
28
|
+
weight_kg=56,
|
29
|
+
height_cm=1.50,
|
30
|
+
dob=dob,
|
31
|
+
report_datetime=get_utcnow(),
|
32
|
+
)
|
33
|
+
try:
|
34
|
+
bmi = func(
|
35
|
+
weight_kg=56, height_cm=150, dob=dob, report_datetime=get_utcnow()
|
36
|
+
)
|
37
|
+
except CalculatorError as e:
|
38
|
+
self.fail(f"CalculatorError unexpectedly raises. Got {e}")
|
39
|
+
else:
|
40
|
+
self.assertEqual(round_half_away_from_zero(bmi.value, 2), 24.89)
|
41
|
+
|
42
|
+
@tag("1")
|
43
|
+
def test_bmi_form_validator(self):
|
44
|
+
data = dict(
|
45
|
+
gender=MALE,
|
46
|
+
ethnicity=BLACK,
|
47
|
+
age_in_years=30,
|
48
|
+
)
|
49
|
+
|
50
|
+
class BmiFormValidator(BmiFormValidatorMixin, FormValidator):
|
51
|
+
pass
|
52
|
+
|
53
|
+
# not enough data
|
54
|
+
form_validator = BmiFormValidator(cleaned_data=data)
|
55
|
+
bmi = form_validator.validate_bmi()
|
56
|
+
self.assertIsNone(bmi)
|
57
|
+
|
58
|
+
# calculates
|
59
|
+
data.update(
|
60
|
+
weight=56,
|
61
|
+
height=150,
|
62
|
+
dob=get_utcnow() - relativedelta(years=30),
|
63
|
+
report_datetime=get_utcnow(),
|
64
|
+
)
|
65
|
+
form_validator = BmiFormValidator(cleaned_data=data)
|
66
|
+
bmi = form_validator.validate_bmi()
|
67
|
+
self.assertEqual(bmi.value, 24.8889)
|
68
|
+
|
69
|
+
# calculation error
|
70
|
+
data.update(
|
71
|
+
weight=56,
|
72
|
+
height=1.5,
|
73
|
+
dob=get_utcnow() - relativedelta(years=25),
|
74
|
+
report_datetime=get_utcnow(),
|
75
|
+
)
|
76
|
+
form_validator = BmiFormValidator(cleaned_data=data)
|
77
|
+
self.assertRaises(forms.ValidationError, form_validator.validate_bmi)
|
@@ -3,11 +3,10 @@ from decimal import Decimal
|
|
3
3
|
from dateutil.relativedelta import relativedelta
|
4
4
|
from django import forms
|
5
5
|
from django.test import TestCase
|
6
|
+
from edc_reportable.forms import WeightHeightBmiFormValidatorMixin
|
6
7
|
from edc_utils import get_utcnow
|
7
8
|
from edc_utils.round_up import round_half_away_from_zero
|
8
9
|
|
9
|
-
from edc_vitals.form_validators import WeightHeightBmiFormValidatorMixin
|
10
|
-
|
11
10
|
from ..models import WeightHeightBmi
|
12
11
|
|
13
12
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: edc-vitals
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.1.0
|
4
4
|
Summary: Classes for BP, weight, etc for clinicedc/edc projects
|
5
5
|
Home-page: https://github.com/clinicedc/edc-vitals
|
6
6
|
Author: Erik van Widenfelt
|
@@ -19,6 +19,7 @@ Requires-Python: >=3.12
|
|
19
19
|
Description-Content-Type: text/x-rst
|
20
20
|
License-File: LICENSE
|
21
21
|
License-File: AUTHORS
|
22
|
+
Dynamic: license-file
|
22
23
|
|
23
24
|
|
24
25
|
|pypi| |actions| |codecov| |downloads|
|
@@ -22,9 +22,12 @@ edc_vitals.egg-info/SOURCES.txt
|
|
22
22
|
edc_vitals.egg-info/dependency_links.txt
|
23
23
|
edc_vitals.egg-info/not-zip-safe
|
24
24
|
edc_vitals.egg-info/top_level.txt
|
25
|
+
edc_vitals/calculators/__init__.py
|
26
|
+
edc_vitals/calculators/bmi.py
|
25
27
|
edc_vitals/form_validators/__init__.py
|
26
28
|
edc_vitals/form_validators/blood_pressure_form_validator_mixin.py
|
27
|
-
edc_vitals/form_validators/
|
29
|
+
edc_vitals/form_validators/bmi_form_validator_mixin.py
|
30
|
+
edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py
|
28
31
|
edc_vitals/migrations/__init__.py
|
29
32
|
edc_vitals/model_mixins/__init__.py
|
30
33
|
edc_vitals/model_mixins/blood_pressure_model_mixin.py
|
@@ -52,6 +55,7 @@ edc_vitals/tests/etc/user-salt-local.key
|
|
52
55
|
edc_vitals/tests/etc/user-salt-restricted.key
|
53
56
|
edc_vitals/tests/tests/__init__.py
|
54
57
|
edc_vitals/tests/tests/test_blood_pressure.py
|
58
|
+
edc_vitals/tests/tests/test_calculators.py
|
55
59
|
edc_vitals/tests/tests/test_heart_rate.py
|
56
60
|
edc_vitals/tests/tests/test_respiratory_rate.py
|
57
61
|
edc_vitals/tests/tests/test_temperature.py
|
@@ -13,7 +13,7 @@ extend-exclude = '''^(.*\/)*\b(migrations)\b($|\/.*$)'''
|
|
13
13
|
[tool.isort]
|
14
14
|
profile = "black"
|
15
15
|
py_version = "312"
|
16
|
-
skip = [".tox", ".eggs", "migrations"]
|
16
|
+
skip = [".tox", ".eggs", "migrations", "_version.py"]
|
17
17
|
|
18
18
|
[tool.coverage.run]
|
19
19
|
parallel = false
|
@@ -84,6 +84,5 @@ commands =
|
|
84
84
|
python --version
|
85
85
|
pip --version
|
86
86
|
pip freeze
|
87
|
-
pre-commit autoupdate
|
88
87
|
pre-commit run --all-files
|
89
88
|
"""
|
edc_vitals-1.0.0/AUTHORS
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Erik van Widenfelt <ew2789@gmail.com>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|