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

client: fix import in patient property code #176

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix is only worth a patch version bump, but since main includes some new pagination code, I'm bumping the minor version too.

But let's chat in person about next steps - I might lean towards a small 4.2.x branch for just this patch since more pagination changes are in-flight.

__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