Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve updating of patients #444

Merged
merged 28 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6b8bca4
make pull request
tomaspavlin Feb 12, 2021
38b4b18
Improve donor and recipient update api
tomaspavlin Feb 12, 2021
53c55f1
Finish update api and introduce tests
tomaspavlin Feb 16, 2021
acbdd4d
Generate files
tomaspavlin Feb 16, 2021
796e96b
Improve patient update service in FE to support everything
tomaspavlin Feb 16, 2021
52fab6d
Merge remote-tracking branch master into 418_improve_updating_of_pati…
tomaspavlin Feb 16, 2021
82287a7
Merge remote-tracking branch 'origin/276_pekne_manualni_vkladani_paci…
tomaspavlin Feb 16, 2021
24e39c4
Use new component and create to-generated parsers
tomaspavlin Feb 17, 2021
22e2181
Merge remote-tracking branch 'origin/276_pekne_manualni_vkladani_paci…
tomaspavlin Feb 17, 2021
02dc5c2
Fix some stuff
tomaspavlin Feb 17, 2021
bab3435
Move active switch and recipient requirements to settings components
tomaspavlin Feb 17, 2021
40f5087
Merge remote-tracking branch 'origin/276_pekne_manualni_vkladani_paci…
tomaspavlin Feb 17, 2021
ba5920b
Comment
tomaspavlin Feb 17, 2021
0594b6e
Merge remote-tracking branch 'origin/master' into 418_improve_updatin…
tomaspavlin Feb 18, 2021
3ac0002
Solve some technical depts to make it working
tomaspavlin Feb 18, 2021
161f981
Introduce editing waitingSince and previousTransplants, fix date pars…
tomaspavlin Feb 18, 2021
578b2bd
Show only needed controls
tomaspavlin Feb 18, 2021
f068f22
Improve enums in BE
tomaspavlin Feb 18, 2021
21087d2
Improve enums in BE 2
tomaspavlin Feb 18, 2021
3eacfee
Solve TODOOs
tomaspavlin Feb 18, 2021
16a6be3
Fix lint
tomaspavlin Feb 18, 2021
bcba746
Remove title and fix some tests indention
tomaspavlin Feb 19, 2021
3fb8bc2
Skip recipient api test for swagger issue
tomaspavlin Feb 19, 2021
7580d7b
Fix tests
tomaspavlin Feb 19, 2021
dc5a69e
Move tests and add blood types todos
tomaspavlin Feb 19, 2021
3c35cc8
Merge remote-tracking branch 'origin/master' into 418_improve_updatin…
tomaspavlin Feb 19, 2021
b36d852
Copy deep antigens
tomaspavlin Feb 22, 2021
9eeb8d8
Merge remote-tracking branch 'origin/master' into 418_improve_updatin…
tomaspavlin Feb 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 164 additions & 1 deletion tests/web/test_patient_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
from txmatching.database.services.txm_event_service import \
get_txm_event_complete
from txmatching.database.sql_alchemy_schema import UploadedFileModel
from txmatching.patients.patient import DonorType
from txmatching.patients.hla_model import HLAAntibodies, HLATyping
from txmatching.patients.patient import DonorType, RecipientRequirements
from txmatching.utils.blood_groups import BloodGroup
from txmatching.utils.enums import Sex
from txmatching.utils.get_absolute_path import get_absolute_path
from txmatching.web import API_VERSION, PATIENT_NAMESPACE, TXM_EVENT_NAMESPACE

Expand Down Expand Up @@ -226,3 +229,163 @@ def test_donor_recipient_pair_deletion(self):
headers=self.auth_headers)
self.assertEqual(400, res.status_code)
self.assertEqual('application/json', res.content_type)

def test_update_donor(self):
txm_event_db_id = self.fill_db_with_patients(
get_absolute_path(PATIENT_DATA_OBFUSCATED))
donor_db_id = 10

# 1. update patient
with self.app.test_client() as client:
json_data = {
'db_id': donor_db_id,
'blood_group': 'A',
'hla_typing': {
'hla_types_list': []
},
'sex': 'M',
'height': 200,
'weight': 100,
'year_of_birth': 1990,
'active': True
}
res = client.put(f'{API_VERSION}/{TXM_EVENT_NAMESPACE}/{txm_event_db_id}/'
f'{PATIENT_NAMESPACE}/donor',
headers=self.auth_headers, json=json_data)
self.assertEqual(200, res.status_code)
self.assertEqual('application/json', res.content_type)

# Check that update was working
txm_event = get_txm_event(txm_event_db_id)
donor = txm_event.active_donors_dict[donor_db_id]
self.assertEqual(donor.parameters.blood_group, BloodGroup.A)
self.assertEqual(donor.parameters.hla_typing, HLATyping([]))
self.assertEqual(donor.parameters.sex, Sex.M)
self.assertEqual(donor.parameters.height, 200)
self.assertEqual(donor.parameters.weight, 100)
self.assertEqual(donor.parameters.year_of_birth, 1990)
self.assertEqual(donor.active, True)

# 2. update with unspecified values
with self.app.test_client() as client:
json_data = {
'db_id': donor_db_id,
'blood_group': 'B',
'hla_typing': {
'hla_types_list': []
},
'sex': None,
'height': None,
'weight': None,
'year_of_birth': None,
'active': False
}
res = client.put(f'{API_VERSION}/{TXM_EVENT_NAMESPACE}/{txm_event_db_id}/'
f'{PATIENT_NAMESPACE}/donor',
headers=self.auth_headers, json=json_data)
self.assertEqual(200, res.status_code)
self.assertEqual('application/json', res.content_type)

# Check that update was working
txm_event = get_txm_event(txm_event_db_id)
donor = next(donor for donor in txm_event.all_donors if donor.db_id == donor_db_id)

self.assertEqual(donor.parameters.blood_group, BloodGroup.B)
self.assertEqual(donor.parameters.hla_typing, HLATyping([]))
self.assertEqual(donor.parameters.sex, None)
self.assertEqual(donor.parameters.height, None)
self.assertEqual(donor.parameters.weight, None)
self.assertEqual(donor.parameters.year_of_birth, None)
self.assertEqual(donor.active, False)

def test_update_recipient(self):
txm_event_db_id = self.fill_db_with_patients(
get_absolute_path(PATIENT_DATA_OBFUSCATED))
recipient_db_id = 10

# 1. update patient
with self.app.test_client() as client:
json_data = {
'db_id': recipient_db_id,
'blood_group': 'A',
'hla_typing': {
'hla_types_list': []
},
'sex': 'M',
'height': 200,
'weight': 100,
'year_of_birth': 1990,
'acceptable_blood_groups': ['A', 'B', 'AB'],
'hla_antibodies': {
'hla_antibodies_list': []
},
'recipient_requirements': {
'require_better_match_in_compatibility_index': True,
'require_better_match_in_compatibility_index_or_blood_group': True,
'require_compatible_blood_group': True
},
'cutoff': 42
}
res = client.put(f'{API_VERSION}/{TXM_EVENT_NAMESPACE}/{txm_event_db_id}/'
f'{PATIENT_NAMESPACE}/recipient',
headers=self.auth_headers, json=json_data)
self.assertEqual(200, res.status_code)
self.assertEqual('application/json', res.content_type)

# Check that update was working
txm_event = get_txm_event(txm_event_db_id)
recipient = txm_event.active_recipients_dict[recipient_db_id]
self.assertEqual(recipient.parameters.blood_group, BloodGroup.A)
self.assertEqual(recipient.parameters.hla_typing, HLATyping([]))
self.assertEqual(recipient.parameters.sex, Sex.M)
self.assertEqual(recipient.parameters.height, 200)
self.assertEqual(recipient.parameters.weight, 100)
self.assertEqual(recipient.parameters.year_of_birth, 1990)
self.assertEqual(recipient.acceptable_blood_groups, [BloodGroup.A, BloodGroup.B, BloodGroup.AB])
self.assertEqual(recipient.hla_antibodies, HLAAntibodies())
self.assertEqual(recipient.recipient_requirements, RecipientRequirements(True, True, True))
self.assertEqual(recipient.recipient_cutoff, 42)

# 2. update with unspecified values
with self.app.test_client() as client:
json_data = {
'db_id': recipient_db_id,
'blood_group': 'B',
'hla_typing': {
'hla_types_list': []
},
'sex': None,
'height': None,
'weight': None,
'year_of_birth': None,
'acceptable_blood_groups': ['0'],
'hla_antibodies': {
'hla_antibodies_list': []
},
'recipient_requirements': {
'require_better_match_in_compatibility_index': False,
'require_better_match_in_compatibility_index_or_blood_group': False,
'require_compatible_blood_group': False
},
'cutoff': None
}
res = client.put(f'{API_VERSION}/{TXM_EVENT_NAMESPACE}/{txm_event_db_id}/'
f'{PATIENT_NAMESPACE}/recipient',
headers=self.auth_headers, json=json_data)
self.assertEqual(200, res.status_code)
self.assertEqual('application/json', res.content_type)

# Check that update was working
txm_event = get_txm_event(txm_event_db_id)
recipient = next(recipient for recipient in txm_event.all_recipients if recipient.db_id == recipient_db_id)

self.assertEqual(recipient.parameters.blood_group, BloodGroup.B)
self.assertEqual(recipient.parameters.hla_typing, HLATyping([]))
self.assertEqual(recipient.parameters.sex, None)
self.assertEqual(recipient.parameters.height, None)
self.assertEqual(recipient.parameters.weight, None)
self.assertEqual(recipient.parameters.year_of_birth, None)
self.assertEqual(recipient.acceptable_blood_groups, [BloodGroup.ZERO])
self.assertEqual(recipient.hla_antibodies, HLAAntibodies())
self.assertEqual(recipient.recipient_requirements, RecipientRequirements(False, False, False))
self.assertEqual(recipient.recipient_cutoff, 42) # Cutoff is unchanged
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from flask_restx import fields

from txmatching.configuration.configuration import Configuration
from txmatching.data_transfer_objects.matchings.matching_swagger import \
CountryCodeJson
from txmatching.data_transfer_objects.enums_swagger import CountryCodeJson
from txmatching.solvers.solver_from_config import SUPPORTED_SOLVERS
from txmatching.web.api.namespaces import matching_api

Expand Down
27 changes: 27 additions & 0 deletions txmatching/data_transfer_objects/enums_swagger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from txmatching.patients.patient import DonorType
from txmatching.utils.blood_groups import BloodGroup
from txmatching.utils.country_enum import Country
from txmatching.utils.enums import Sex
from txmatching.web.api.namespaces import enums_api

CountryCodeJson = enums_api.schema_model('CountryCode', {
'enum': [country.value for country in Country],
'type': 'string'
})

BloodGroupEnumJson = enums_api.schema_model('BloodGroupEnum', {
'enum': [blood_group.value for blood_group in BloodGroup],
'type': 'string'
})

SexEnumJson = enums_api.schema_model('SexEnum', {
'enum': [sex.value for sex in Sex],
'type': 'string',
'description': 'Sex of the patient.'
})

DonorTypeEnumJson = enums_api.schema_model('DonorType', {
'enum': [donor_type.value for donor_type in DonorType],
'type': 'string',
'description': 'Type of the donor.'
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from txmatching.data_transfer_objects.hla.hla_swagger import (HLAAntibody,
HLAType)
from txmatching.utils.country_enum import Country
from txmatching.utils.enums import (HLA_GROUPS_NAMES_WITH_OTHER,
AntibodyMatchTypes, HLAGroup, MatchTypes)
from txmatching.web.api.namespaces import matching_api
Expand Down Expand Up @@ -84,11 +83,6 @@
cls_or_instance=fields.Nested(DetailedScoreForGroupJson))
})

CountryCodeJson = matching_api.schema_model('CountryCode', {
'enum': [country.value for country in Country],
'type': 'string'
})

CountryInRoundJson = matching_api.model('Country', {
'country_code': fields.String(required=True),
'donor_count': fields.Integer(required=True),
Expand Down
61 changes: 35 additions & 26 deletions txmatching/data_transfer_objects/patients/patient_swagger.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from flask_restx import fields

from txmatching.data_transfer_objects.enums_swagger import (BloodGroupEnumJson,
CountryCodeJson,
DonorTypeEnumJson,
SexEnumJson)
from txmatching.data_transfer_objects.hla.hla_swagger import (
EXAMPLE_HLA_TYPING, HLAAntibodies, HLATyping)
from txmatching.data_transfer_objects.matchings.matching_swagger import (
DESCRIPTION_DETAILED_SCORE, EXAMPLE_DETAILED_SCORE, CountryCodeJson,
DESCRIPTION_DETAILED_SCORE, EXAMPLE_DETAILED_SCORE,
DetailedScoreForGroupJson)
from txmatching.data_transfer_objects.txm_event.txm_event_swagger import (
DonorJsonIn, RecipientJsonIn)
from txmatching.patients.patient import DonorType
from txmatching.utils.blood_groups import BloodGroup
from txmatching.utils.enums import Sex
from txmatching.web.api.namespaces import patient_api

PatientParametersJson = patient_api.model('PatientParameters', {
'blood_group': fields.String(required=False, enum=[blood_group.value for blood_group in BloodGroup]),
'blood_group': fields.Nested(BloodGroupEnumJson, required=True),
'hla_typing': fields.Nested(required=False, model=HLATyping),
'country_code': fields.Nested(CountryCodeJson, required=False),
'sex': fields.String(required=False, enum=[sex.value for sex in Sex]),
'country_code': fields.Nested(CountryCodeJson, required=True),
'sex': fields.Nested(SexEnumJson, required=False),
'height': fields.Integer(required=False),
'weight': fields.Float(required=False),
'year_of_birth': fields.Integer(required=False),
Expand All @@ -33,7 +34,7 @@
'db_id': fields.Integer(required=True, description='Database id of the patient'),
'medical_id': fields.String(required=True, description='Medical id of the patient'),
'parameters': fields.Nested(required=True, model=PatientParametersJson),
'donor_type': fields.String(required=True, enum=[donor_type.value for donor_type in DonorType]),
'donor_type': fields.Nested(DonorTypeEnumJson, required=True),
'related_recipient_db_id': fields.Integer(required=False, description='Database id of the related recipient'),
'score_with_related_recipient': fields.Float(required=False, description='Score calculated with related recipient'),
'compatible_blood_with_related_recipient': fields.Boolean(
Expand All @@ -49,8 +50,7 @@

RecipientJson = patient_api.model('Recipient', {
'db_id': fields.Integer(required=True, description='Database id of the patient'),
'acceptable_blood_groups': fields.List(required=False, cls_or_instance=fields.String(
enum=[blood_group.value for blood_group in BloodGroup])),
'acceptable_blood_groups': fields.List(required=False, cls_or_instance=fields.Nested(BloodGroupEnumJson)),
'medical_id': fields.String(required=True, description='Medical id of the patient'),
'parameters': fields.Nested(required=True, model=PatientParametersJson),
'hla_antibodies': fields.Nested(required=True, model=HLAAntibodies),
Expand Down Expand Up @@ -83,16 +83,28 @@
'hla_antibodies_list': fields.List(required=True, cls_or_instance=fields.Nested(HLAAntibodyToUpdateJson)),
})

RecipientToUpdateJson = patient_api.model('RecipientModelToUpdate', {
PatientToUpdateJson = patient_api.model('PatientModelToUpdate', {
'db_id': fields.Integer(required=True, description='Database id of the patient', example=1),
'acceptable_blood_groups': fields.List(required=False, cls_or_instance=fields.String(
enum=[blood_group.value for blood_group in BloodGroup]),
description='Provide full list of all the acceptable blood groups of the '
'patient, not just the change set'),
'blood_group': fields.Nested(BloodGroupEnumJson, required=False),
'hla_typing': fields.Nested(HLATypingToUpdateJson, required=False,
description='Provide full list of all the HLA types of the patient, not just '
'the change set',
example=EXAMPLE_HLA_TYPING),
'sex': fields.Nested(SexEnumJson, required=False),
'height': fields.Integer(required=False, example=180),
'weight': fields.Float(required=False, example=90),
'year_of_birth': fields.Integer(required=False, example=1990),
})

DonorToUpdateJson = patient_api.inherit('DonorModelToUpdate', PatientToUpdateJson, {
'active': fields.Boolean(required=False, description='Information, whether or not given donor shall be considered'
' in exchange.')
})

RecipientToUpdateJson = patient_api.inherit('RecipientModelToUpdate', PatientToUpdateJson, {
'acceptable_blood_groups': fields.List(required=False, cls_or_instance=fields.Nested(BloodGroupEnumJson),
description='Provide full list of all the acceptable blood groups of the '
'patient, not just the change set'),
'hla_antibodies': fields.Nested(HLAAntibodiesToUpdateJson, required=False,
description='Provide full list of all the HLA antibodies of the patient, not just '
'the change set',
Expand All @@ -106,26 +118,23 @@
description='Provide the whole recipients requirements object, it will be'
' overwritten',
example={'require_better_match_in_compatibility_index': True}),
'waiting_since': fields.Date(required=False,
example='2015-01-17',
description='Date since when the patient has been on waiting list. '
'Use format YYYY-MM-DD.'),
'previous_transplants': fields.Integer(required=False,
example=0,
description='Number of previous kidney transplants.'),
'cutoff': fields.Integer(required=False)
})

DonorToUpdateJson = patient_api.model('DonorModelToUpdate', {
'db_id': fields.Integer(required=True, description='Database id of the patient', example=1),
'hla_typing': fields.Nested(HLATypingToUpdateJson, required=False,
description='Provide full list of all the HLA types of the patient, not just '
'the change set',
example=EXAMPLE_HLA_TYPING),
'active': fields.Boolean(required=False, description='Information, whether or not given donor shall be considered'
' in exchange.')
})

HLAAntibodyPairInJson = patient_api.model('HLAAntibodyPairIn', {
'name': fields.String(required=True, example='A32', description='HLA antibody name.'),
'mfi': fields.Integer(required=True, example=2350, description='Mean fluorescence intensity. Use exact value.'),
})

DonorModelPairInJson = patient_api.model('DonorModelPairIn', {
'country_code': fields.Nested(CountryCodeJson, required=False),
'country_code': fields.Nested(CountryCodeJson, required=True),
'donor': fields.Nested(required=True, model=DonorJsonIn),
'recipient': fields.Nested(required=False, model=RecipientJsonIn)
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@
from txmatching.data_transfer_objects.patients.update_dtos.hla_code_update_dtos import \
HLATypingUpdateDTO
from txmatching.patients.hla_model import HLAType
from txmatching.patients.patient_parameters import Centimeters, Kilograms
from txmatching.utils.blood_groups import BloodGroup
from txmatching.utils.enums import Sex
from txmatching.utils.hla_system.hla_transformations import \
preprocess_hla_code_in


@dataclass
class PatientUpdateDTO:
# pylint: disable=too-many-instance-attributes
# It is reasonable to have many attributes here
db_id: int
blood_group: Optional[BloodGroup] = None
hla_typing: Optional[HLATypingUpdateDTO] = None
sex: Optional[Sex] = None
height: Optional[Centimeters] = None
weight: Optional[Kilograms] = None
year_of_birth: Optional[int] = None

def __post_init__(self):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class RecipientUpdateDTO(PatientUpdateDTO):
hla_antibodies: Optional[HLAAntibodiesDTO] = None
recipient_requirements: Optional[RecipientRequirements] = None
cutoff: Optional[int] = None
waiting_since: Optional[str] = None
previous_transplants: Optional[int] = None

def __post_init__(self):
super().__post_init__()
Expand Down
Loading