Skip to content

Commit

Permalink
client: fix import in patient property code
Browse files Browse the repository at this point in the history
This allows client.patient to work again (i.e. to transparently request
client.patient_id from the server).

This was a regression introduced in 4.2.0.
  • Loading branch information
mikix committed Sep 9, 2024
1 parent 9967711 commit c0c838c
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 6 deletions.
12 changes: 6 additions & 6 deletions fhirclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from .server import FHIRServer, FHIRUnauthorizedException, FHIRNotFoundException

__version__ = '4.2.0'
__version__ = '4.3.0'
__author__ = 'SMART Platforms Team'
__license__ = 'APACHE2'
__copyright__ = "Copyright 2017 Boston Children's Hospital"
Expand Down Expand Up @@ -171,16 +171,16 @@ def _handle_launch_context(self, ctx):
@property
def patient(self):
if self._patient is None and self.patient_id is not None and self.ready:
import models.patient
from fhirclient.models.patient import Patient
try:
logger.debug("SMART: Attempting to read Patient {0}".format(self.patient_id))
self._patient = models.patient.Patient.read(self.patient_id, self.server)
except FHIRUnauthorizedException as e:
self._patient = Patient.read(self.patient_id, self.server)
except FHIRUnauthorizedException:
if self.reauthorize():
logger.debug("SMART: Attempting to read Patient {0} after reauthorizing"
.format(self.patient_id))
self._patient = models.patient.Patient.read(self.patient_id, self.server)
except FHIRNotFoundException as e:
self._patient = Patient.read(self.patient_id, self.server)
except FHIRNotFoundException:
logger.warning("SMART: Patient with id {0} not found".format(self.patient_id))
self.patient_id = None
self.save_state()
Expand Down
58 changes: 58 additions & 0 deletions tests/client_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import unittest
from unittest import mock

from fhirclient.client import FHIRClient
from fhirclient.server import FHIRNotFoundException, FHIRUnauthorizedException

# Smallest valid-but-fake client state
MIN_STATE = {
"server": {"base_uri": "http://example.com/fhir"},
}


class TestClient(unittest.TestCase):
Expand Down Expand Up @@ -39,3 +46,54 @@ def test_load_from_state(self):
client.from_state({'app_id': 'NewID', 'server': state['server']})
self.assertEqual('NewID', client.app_id)
self.assertEqual('LaunchToken', client.launch_token)

@mock.patch("fhirclient.models.patient.Patient.read")
def test_patient_property_happy_path(self, mock_read):
save_func = mock.MagicMock()

# Verify that we gracefully handle no patient_id being given
client = FHIRClient(state=MIN_STATE, save_func=save_func)
self.assertIsNone(client.patient)
self.assertEqual(mock_read.call_count, 0)
self.assertEqual(save_func.call_count, 0)

# Verify we expose the provided patient ID as a Patient object
client = FHIRClient(state={"patient_id": "P123", **MIN_STATE}, save_func=save_func)
self.assertIsNotNone(client.patient)
self.assertEqual(mock_read.call_count, 1)
self.assertEqual(mock_read.call_args, mock.call("P123", client.server))
self.assertEqual(save_func.call_count, 1)

@mock.patch("fhirclient.models.patient.Patient.read")
@mock.patch("fhirclient.client.FHIRClient.reauthorize")
def test_patient_property_unauthorized(self, mock_reauthorize, mock_read):
"""We should attempt to reauthorize and re-request the patient"""

client = FHIRClient(state={"patient_id": "P123", **MIN_STATE})

# First try with a failed re-authorize
mock_read.side_effect = FHIRUnauthorizedException("response")
mock_reauthorize.return_value = False
self.assertIsNone(client.patient)
self.assertEqual(mock_read.call_count, 1)
self.assertEqual(mock_reauthorize.call_count, 1)

# Then with a successful re-authorize
mock_read.reset_mock()
mock_read.side_effect = [FHIRUnauthorizedException("response"), mock.MagicMock()]
mock_reauthorize.reset_mock()
mock_reauthorize.return_value = True
self.assertIsNotNone(client.patient)
self.assertEqual(mock_read.call_count, 2)
self.assertEqual(mock_reauthorize.call_count, 1)

@mock.patch("fhirclient.models.patient.Patient.read")
def test_patient_property_not_found(self, mock_read):
"""We should attempt to reauthorize and re-request the patient"""
mock_read.side_effect = FHIRNotFoundException("response")

client = FHIRClient(state={"patient_id": "P123", **MIN_STATE})
self.assertEqual(client.patient_id, "P123") # sanity check before we start

self.assertIsNone(client.patient)
self.assertIsNone(client.patient_id) # we clear out the patient id

0 comments on commit c0c838c

Please sign in to comment.