edc-vitals 1.0.0__py3-none-any.whl → 1.1.2__py3-none-any.whl

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.
@@ -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
@@ -1,2 +1,5 @@
1
1
  from .blood_pressure_form_validator_mixin import BloodPressureFormValidatorMixin
2
- from .weight_height_bmi_form_validator_mixin import WeightHeightBmiFormValidatorMixin
2
+ from .bmi_form_validator_mixin import BmiFormValidatorMixin
3
+ from .weight_height_with_bmi_form_validator_mixin import (
4
+ WeightHeightBmiFormValidatorMixin,
5
+ )
@@ -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
@@ -1,5 +1,6 @@
1
1
  from django import forms
2
- from edc_reportable import CalculatorError, calculate_bmi
2
+
3
+ from ..calculators import CalculatorError, calculate_bmi
3
4
 
4
5
 
5
6
  class WeightHeightBmiFormValidatorMixin:
@@ -1,6 +1,6 @@
1
1
  from django.db import models
2
- from edc_reportable import calculate_bmi
3
2
 
3
+ from ..calculators import calculate_bmi
4
4
  from ..models import HeightField, WeightField
5
5
 
6
6
 
@@ -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)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: edc-vitals
3
- Version: 1.0.0
3
+ Version: 1.1.2
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
@@ -9,7 +9,7 @@ License: GPL license, see LICENSE
9
9
  Keywords: django edc vitals,clinicedc,clinical trials
10
10
  Classifier: Environment :: Web Environment
11
11
  Classifier: Framework :: Django
12
- Classifier: Framework :: Django :: 5.1
12
+ Classifier: Framework :: Django :: 5.2
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Science/Research
15
15
  Classifier: Operating System :: OS Independent
@@ -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|
@@ -2,13 +2,16 @@ edc_vitals/__init__.py,sha256=k7pm4XmS32dJU4XRYKHJrzEkA7CuQ75_Jj7nLkvUiDY,117
2
2
  edc_vitals/apps.py,sha256=AvV-Dwgo6KRe5VhriAP8CYM6OJG6kGh2_1BwQ6Wmc8o,145
3
3
  edc_vitals/utils.py,sha256=vXid44KUXxeaSyund_y5MNXc5DFJs052_PwUAjszE2k,1384
4
4
  edc_vitals/validators.py,sha256=9bNs-txdfA-v9iPS8mzFy_HLlY12jFcUHoy_bDbEpH0,164
5
- edc_vitals/form_validators/__init__.py,sha256=mNp0jCS5XZW5r-WNMt6yBBqQuP0DnIuVC4PTU_XFWfE,167
5
+ edc_vitals/calculators/__init__.py,sha256=H2gtS_5Aw7r4kELDmNy3AtNqTPbaNUDMM0OzSx3ZiU4,53
6
+ edc_vitals/calculators/bmi.py,sha256=DFJRChDR8zXL7WLNanJPUo6SE3Do44srFgIsb3TiLOQ,2055
7
+ edc_vitals/form_validators/__init__.py,sha256=Kd3uFE_Qe2MOWsyQG72gfG62HGNw-8GyqKmgA8uIjWA,241
6
8
  edc_vitals/form_validators/blood_pressure_form_validator_mixin.py,sha256=RvIGvukC7RubqH7f6DUVArNUL__BVoTdRq1L4vPfX2A,1563
7
- edc_vitals/form_validators/weight_height_bmi_form_validator_mixin.py,sha256=xtPXCNQzSkUN_7zm7XvPex3cOInlECMtAwpShTjS4eI,460
9
+ edc_vitals/form_validators/bmi_form_validator_mixin.py,sha256=dQPb3CrvkRdSXJtDUbZ33Z1dMYrybWwrK9WvPbdjhZA,529
10
+ edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py,sha256=zJZJgyQ1KP5LZMPowf5Rs009Lq2sybm65UoHNP6pBxU,460
8
11
  edc_vitals/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
12
  edc_vitals/model_mixins/__init__.py,sha256=Nvu9-rNd0P5efB7KS74OHUE_AMJL_qtjUepEt0BuT8I,177
10
13
  edc_vitals/model_mixins/blood_pressure_model_mixin.py,sha256=50J3xs3Po5IRaUodFs6qtPWzwOUckWhExVUEM25Ri4g,2052
11
- edc_vitals/model_mixins/weight_height_bmi_model_mixin.py,sha256=giZSiI38kynfRc4B5L_A4Rc_hreTS1vPKlYVnY2qj-A,1102
14
+ edc_vitals/model_mixins/weight_height_bmi_model_mixin.py,sha256=DjxSSlMLy2FCr1LvJ7ppCZFe4-HxWSs0ZuXta6VtvQc,1101
12
15
  edc_vitals/models/__init__.py,sha256=kojBDnW6CZiBORa4hn7CtVl0D6pku3i7M1t8uVoVhWg,210
13
16
  edc_vitals/models/fields/__init__.py,sha256=2mpaP8hoI0-4c5vlZZVoUFvGuy9rjfT7im3k8jykDyU,327
14
17
  edc_vitals/models/fields/blood_pressure.py,sha256=5MLJcvNf6yOk5LJe1wmPCku4rpaA6JZrHrWoKX5EmiY,1369
@@ -32,13 +35,14 @@ edc_vitals/tests/etc/user-salt-local.key,sha256=8yXyuxh-EstHWMSkwqSNV7gakEQLnQLo
32
35
  edc_vitals/tests/etc/user-salt-restricted.key,sha256=w835r6mLFeL4IIYoovEVU8JfXOw8VR1Moh15gaIJJww,256
33
36
  edc_vitals/tests/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
37
  edc_vitals/tests/tests/test_blood_pressure.py,sha256=dablDybatc_Z_4TxLdJoYzbe1ZVQ7dW3u6gAprAgB3w,7591
38
+ edc_vitals/tests/tests/test_calculators.py,sha256=op0P4WbP-OAAr-73Usaod-xHl3Ptikcf8n0AmoirnsQ,2674
35
39
  edc_vitals/tests/tests/test_heart_rate.py,sha256=0-FpuWg1iDSRw6EmfFhH8u4OmvH9o1Ss_EKYwfOaVXI,1804
36
40
  edc_vitals/tests/tests/test_respiratory_rate.py,sha256=-R7XIIw6gHd0u69AHdOcEgFjLQrjdYdsGbf7B3d_GwU,1906
37
41
  edc_vitals/tests/tests/test_temperature.py,sha256=KYK-PrvCQIsNUPajUhl0R1FmuspwEYhxIZtc-TKgRjc,3518
38
42
  edc_vitals/tests/tests/test_weight_height_bmi.py,sha256=aMlxxvdbeNAKX8IMp6x6zxRmjd3oL_mO8nCE06vyBV4,2322
39
- edc_vitals-1.0.0.dist-info/AUTHORS,sha256=6jjF41GocVpG01NLt55LeDKdjuwuDdA77fb_MENCTOk,38
40
- edc_vitals-1.0.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
41
- edc_vitals-1.0.0.dist-info/METADATA,sha256=teumq6ZayizP9sgiQ7aRLFY4CT6cSoDkwFCv_5wl_ZE,1757
42
- edc_vitals-1.0.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
43
- edc_vitals-1.0.0.dist-info/top_level.txt,sha256=hwo2JnqOF-wcBFoQz-fEhszjPca4sZ9a3QDF7BHGFhI,11
44
- edc_vitals-1.0.0.dist-info/RECORD,,
43
+ edc_vitals-1.1.2.dist-info/licenses/AUTHORS,sha256=cRyIwmYX7rwmqBPh9_4EA9hZ_kw6RWjNSGOW4RpIoiM,102
44
+ edc_vitals-1.1.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
45
+ edc_vitals-1.1.2.dist-info/METADATA,sha256=6HR-4w0SMoMvOHBlgggIOAAXZYFj42mr2RI0w6wrGLc,1779
46
+ edc_vitals-1.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
47
+ edc_vitals-1.1.2.dist-info/top_level.txt,sha256=hwo2JnqOF-wcBFoQz-fEhszjPca4sZ9a3QDF7BHGFhI,11
48
+ edc_vitals-1.1.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,2 @@
1
+ Erik van Widenfelt <ew2789@gmail.com>
2
+ Jonathan Willitts (GitHub: https://github.com/JonathanWillitts)
@@ -1 +0,0 @@
1
- Erik van Widenfelt <ew2789@gmail.com>