Skip to content

Commit 29260ec

Browse files
authored
[PRMP-777] Ruff Fixes (#867)
1 parent 481a2c1 commit 29260ec

9 files changed

+602
-374
lines changed

lambdas/handlers/get_fhir_document_reference_handler.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from enums.lambda_error import LambdaError
2-
from enums.mtls import MtlsCommonNames
32
from oauthlib.oauth2 import WebApplicationClient
43
from services.base.ssm_service import SSMService
54
from services.dynamic_configuration_service import DynamicConfigurationService
@@ -9,14 +8,13 @@
98
from utils.audit_logging_setup import LoggingService
109
from utils.decorators.ensure_env_var import ensure_environment_variables
1110
from utils.decorators.handle_lambda_exceptions import handle_lambda_exceptions_fhir
12-
from utils.lambda_handler_utils import extract_bearer_token
13-
from utils.lambda_header_utils import validate_common_name_in_mtls
1411
from utils.decorators.set_audit_arg import set_request_context_for_logging
1512
from utils.exceptions import AuthorisationException, OidcApiException
1613
from utils.lambda_exceptions import (
1714
GetFhirDocumentReferenceException,
1815
SearchPatientException,
1916
)
17+
from utils.lambda_handler_utils import extract_bearer_token
2018
from utils.lambda_response import ApiGatewayResponse
2119

2220
logger = LoggingService(__name__)

lambdas/services/base/dynamo_service.py

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import time
2-
from typing import Iterator, Optional, Sequence
2+
from typing import Optional, Sequence
33

44
import boto3
55
from boto3.dynamodb.conditions import Attr, ConditionBase, Key
66
from botocore.exceptions import ClientError
7-
87
from utils.audit_logging_setup import LoggingService
98
from utils.dynamo_utils import (
109
create_expression_attribute_values,
@@ -120,7 +119,7 @@ def update_item(
120119

121120
if condition_expression:
122121
update_item_args["ConditionExpression"] = condition_expression
123-
122+
124123
return table.update_item(**update_item_args)
125124

126125
def delete_item(self, table_name: str, key: dict):
@@ -157,10 +156,10 @@ def scan_table(
157156
raise e
158157

159158
def scan_whole_table(
160-
self,
161-
table_name: str,
162-
project_expression: Optional[str] = None,
163-
filter_expression: Optional[str] = None,
159+
self,
160+
table_name: str,
161+
project_expression: Optional[str] = None,
162+
filter_expression: Optional[str] = None,
164163
) -> list[dict]:
165164
try:
166165
table = self.get_table(table_name)
@@ -223,7 +222,7 @@ def batch_get_items(self, table_name: str, key_list: list[str]):
223222
)
224223
request_items = unprocessed_keys
225224
retries += 1
226-
time.sleep((2 ** retries) * 0.1)
225+
time.sleep((2**retries) * 0.1)
227226
else:
228227
break
229228

@@ -243,15 +242,13 @@ def get_item(self, table_name: str, key: dict):
243242
)
244243
raise e
245244

246-
def transact_write_items(
247-
self, transact_items: Sequence[dict]
248-
):
245+
def transact_write_items(self, transact_items: Sequence[dict]):
249246
"""
250247
Execute a transactional write operation.
251-
248+
252249
Args:
253250
transact_items: List of transaction items (Put, Update, Delete, ConditionCheck)
254-
251+
255252
Raises:
256253
ClientError: If the transaction fails (e.g., TransactionCanceledException)
257254
"""
@@ -263,55 +260,57 @@ def transact_write_items(
263260
logger.info("Transaction completed successfully")
264261
return response
265262
except ClientError as e:
266-
error_code = e.response.get('Error', {}).get('Code', '')
267-
if error_code == 'TransactionCanceledException':
263+
error_code = e.response.get("Error", {}).get("Code", "")
264+
if error_code == "TransactionCanceledException":
268265
logger.error(f"Transaction cancelled: {str(e)}")
269-
cancellation_reasons = e.response.get('CancellationReasons', [])
266+
cancellation_reasons = e.response.get("CancellationReasons", [])
270267
logger.error(f"Cancellation reasons: {cancellation_reasons}")
271268
else:
272269
logger.error(f"Transaction failed with error: {str(e)}")
273270
raise e
274271

275272
def build_update_transaction_item(
276-
self,
273+
self,
277274
table_name: str,
278-
document_key: dict,
279-
update_fields: dict,
280-
condition_fields: dict
275+
document_key: dict,
276+
update_fields: dict,
277+
condition_fields: dict,
281278
) -> dict:
282279
"""
283280
Build a DynamoDB transaction update item with a conditional expression.
284-
281+
285282
Args:
286283
table_name: The name of the DynamoDB table
287284
document_key: The key of the table to update
288285
update_fields: Dictionary of fields to update (already in DynamoDB format/aliases)
289286
condition_fields: Dictionary of field names and their expected values for the condition to pass
290287
e.g., {"DocStatus": "final", "Version": 1}
291-
288+
292289
Returns:
293290
A transaction item dict ready for transact_write_items
294291
"""
295292
field_names = list(update_fields.keys())
296293
update_expression = create_update_expression(field_names)
297294
_, expression_attribute_names = create_expressions(field_names)
298295
expression_attribute_values = create_expression_attribute_values(update_fields)
299-
296+
300297
# Build condition expression for multiple fields
301298
condition_expressions = []
302299
condition_attribute_names = {}
303300
condition_attribute_values = {}
304-
301+
305302
for field_name, field_value in condition_fields.items():
306303
condition_placeholder = f"#{field_name}_attr"
307304
condition_value_placeholder = f":{field_name}_condition_val"
308-
condition_expressions.append(f"{condition_placeholder} = {condition_value_placeholder}")
305+
condition_expressions.append(
306+
f"{condition_placeholder} = {condition_value_placeholder}"
307+
)
309308
condition_attribute_names[condition_placeholder] = field_name
310309
condition_attribute_values[condition_value_placeholder] = field_value
311-
310+
312311
# Join multiple conditions with AND
313312
condition_expression = " AND ".join(condition_expressions)
314-
313+
315314
return {
316315
"Update": {
317316
"TableName": table_name,
@@ -320,11 +319,11 @@ def build_update_transaction_item(
320319
"ConditionExpression": condition_expression,
321320
"ExpressionAttributeNames": {
322321
**expression_attribute_names,
323-
**condition_attribute_names
322+
**condition_attribute_names,
324323
},
325324
"ExpressionAttributeValues": {
326325
**expression_attribute_values,
327-
**condition_attribute_values
328-
}
326+
**condition_attribute_values,
327+
},
329328
}
330329
}

lambdas/services/put_fhir_document_reference_service.py

Lines changed: 74 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
import os
2-
3-
from utils.audit_logging_setup import LoggingService
1+
from enums.lambda_error import LambdaError
2+
from enums.snomed_codes import SnomedCode
3+
from models.document_reference import DocumentReference
44
from models.fhir.R4.fhir_document_reference import (
55
DocumentReference as FhirDocumentReference,
66
)
7-
from models.document_reference import DocumentReference
8-
from services.fhir_document_reference_service_base import FhirDocumentReferenceServiceBase
9-
from enums.snomed_codes import SnomedCode
10-
from enums.lambda_error import LambdaError
11-
from utils.lambda_exceptions import UpdateFhirDocumentReferenceException
7+
from pydantic import ValidationError
8+
from services.fhir_document_reference_service_base import (
9+
FhirDocumentReferenceServiceBase,
10+
)
11+
from utils.audit_logging_setup import LoggingService
1212
from utils.dynamo_utils import DocTypeTableRouter
13+
from utils.exceptions import FhirDocumentReferenceException, InvalidNhsNumberException
1314
from utils.lambda_exceptions import (
1415
InvalidDocTypeException,
15-
)
16-
from pydantic import ValidationError
17-
from utils.exceptions import (
18-
InvalidNhsNumberException,
19-
FhirDocumentReferenceException,
16+
UpdateFhirDocumentReferenceException,
2017
)
2118

2219
logger = LoggingService(__name__)
2320

21+
2422
class PutFhirDocumentReferenceService(FhirDocumentReferenceServiceBase):
2523
def __init__(self):
2624
super().__init__()
2725
self.doc_router = DocTypeTableRouter()
2826

2927
def process_fhir_document_reference(self, fhir_document: str) -> str:
3028
try:
31-
validated_fhir_doc = FhirDocumentReference.model_validate_json(fhir_document)
29+
validated_fhir_doc = FhirDocumentReference.model_validate_json(
30+
fhir_document
31+
)
3232
except ValidationError as e:
3333
logger.error(f"FHIR document validation error: {str(e)}")
3434
raise UpdateFhirDocumentReferenceException(400, LambdaError.DocRefNoParse)
@@ -38,38 +38,41 @@ def process_fhir_document_reference(self, fhir_document: str) -> str:
3838
doc_type = self._determine_document_type(validated_fhir_doc)
3939
except FhirDocumentReferenceException:
4040
logger.error("Could not determine document type")
41-
raise UpdateFhirDocumentReferenceException(400, LambdaError.DocRefInvalidType)
41+
raise UpdateFhirDocumentReferenceException(
42+
400, LambdaError.DocRefInvalidType
43+
)
4244

4345
# Determine which DynamoDB table to use based on the document type
4446
dynamo_table = self._get_dynamo_table_for_doc_type(doc_type)
4547

4648
# Get the current document from the database
4749
current_doc = self._get_current_doc(validated_fhir_doc, dynamo_table)
48-
50+
4951
# Check that the NHS number in the request matches the one in the stored document
5052
request_nhs_number = self._validate_nhs_number(validated_fhir_doc, current_doc)
51-
53+
5254
# Check that the version number matches the stored document
5355
self._validate_version_number(validated_fhir_doc, current_doc)
54-
56+
5557
# Create a new document reference with the new version number
5658
new_doc_reference = self._create_new_document_reference(
57-
validated_fhir_doc,
58-
current_doc,
59-
request_nhs_number,
60-
doc_type
59+
validated_fhir_doc, current_doc, request_nhs_number, doc_type
6160
)
6261

6362
# Handle binary content if present, otherwise create a pre-signed URL
64-
presigned_url = self._handle_document_save(new_doc_reference, validated_fhir_doc, dynamo_table)
65-
63+
presigned_url = self._handle_document_save(
64+
new_doc_reference, validated_fhir_doc, dynamo_table
65+
)
66+
6667
try:
6768
return self._create_fhir_response(new_doc_reference, presigned_url)
6869
except (ValidationError, InvalidNhsNumberException) as e:
6970
logger.error(f"FHIR document validation error: {str(e)}")
7071
raise UpdateFhirDocumentReferenceException(400, LambdaError.DocRefNoParse)
71-
72-
def _get_current_doc(self, fhir_doc: FhirDocumentReference, dynamo_table: str) -> DocumentReference:
72+
73+
def _get_current_doc(
74+
self, fhir_doc: FhirDocumentReference, dynamo_table: str
75+
) -> DocumentReference:
7376
try:
7477
current_doc = self._get_document_reference(fhir_doc.id, dynamo_table)
7578
except FhirDocumentReferenceException:
@@ -83,10 +86,12 @@ def _get_current_doc(self, fhir_doc: FhirDocumentReference, dynamo_table: str) -
8386
raise UpdateFhirDocumentReferenceException(
8487
400, LambdaError.UpdateDocNotLatestVersion
8588
)
86-
89+
8790
return current_doc
88-
89-
def _validate_nhs_number(self, fhir_doc: FhirDocumentReference, current_doc: DocumentReference):
91+
92+
def _validate_nhs_number(
93+
self, fhir_doc: FhirDocumentReference, current_doc: DocumentReference
94+
):
9095
try:
9196
request_nhs_number = fhir_doc.extract_nhs_number_from_fhir()
9297
except FhirDocumentReferenceException:
@@ -98,30 +103,38 @@ def _validate_nhs_number(self, fhir_doc: FhirDocumentReference, current_doc: Doc
98103
raise UpdateFhirDocumentReferenceException(
99104
400, LambdaError.UpdateDocNHSNumberMismatch
100105
)
101-
106+
102107
return request_nhs_number
103-
104-
def _validate_version_number(self, fhir_doc: FhirDocumentReference, current_doc: DocumentReference):
108+
109+
def _validate_version_number(
110+
self, fhir_doc: FhirDocumentReference, current_doc: DocumentReference
111+
):
105112
if fhir_doc.meta is None:
106113
logger.error("Missing version number")
107-
raise UpdateFhirDocumentReferenceException(400, LambdaError.DocumentReferenceMissingParameters)
108-
114+
raise UpdateFhirDocumentReferenceException(
115+
400, LambdaError.DocumentReferenceMissingParameters
116+
)
117+
109118
if current_doc.version != fhir_doc.meta.versionId:
110119
logger.error("Version does not match current version.")
111-
raise UpdateFhirDocumentReferenceException(400, LambdaError.UpdateDocVersionMismatch)
112-
120+
raise UpdateFhirDocumentReferenceException(
121+
400, LambdaError.UpdateDocVersionMismatch
122+
)
123+
113124
def _create_new_document_reference(
114-
self,
115-
fhir_doc: FhirDocumentReference,
116-
current_doc: DocumentReference,
117-
nhs_number: str,
118-
doc_type: SnomedCode,
119-
) -> DocumentReference:
125+
self,
126+
fhir_doc: FhirDocumentReference,
127+
current_doc: DocumentReference,
128+
nhs_number: str,
129+
doc_type: SnomedCode,
130+
) -> DocumentReference:
120131
try:
121132
patient_details = self._check_nhs_number_with_pds(nhs_number)
122133
except FhirDocumentReferenceException:
123-
raise UpdateFhirDocumentReferenceException(400, LambdaError.DocRefPatientSearchInvalid)
124-
134+
raise UpdateFhirDocumentReferenceException(
135+
400, LambdaError.DocRefPatientSearchInvalid
136+
)
137+
125138
new_doc_version = int(current_doc.version) + 1
126139

127140
# Create a document reference model
@@ -135,13 +148,13 @@ def _create_new_document_reference(
135148
)
136149

137150
return document_reference
138-
151+
139152
def _handle_document_save(
140-
self,
141-
document_reference: DocumentReference,
142-
fhir_doc: FhirDocumentReference,
143-
dynamo_table: str,
144-
) -> str:
153+
self,
154+
document_reference: DocumentReference,
155+
fhir_doc: FhirDocumentReference,
156+
dynamo_table: str,
157+
) -> str:
145158
binary_content = fhir_doc.content[0].attachment.data
146159

147160
presigned_url = None
@@ -150,21 +163,27 @@ def _handle_document_save(
150163
try:
151164
self._store_binary_in_s3(document_reference, binary_content)
152165
except FhirDocumentReferenceException:
153-
raise UpdateFhirDocumentReferenceException(500, LambdaError.DocRefNoParse)
166+
raise UpdateFhirDocumentReferenceException(
167+
500, LambdaError.DocRefNoParse
168+
)
154169
else:
155170
# Create a pre-signed URL for uploading
156171
try:
157172
presigned_url = self._create_s3_presigned_url(document_reference)
158173
except FhirDocumentReferenceException:
159-
raise UpdateFhirDocumentReferenceException(500, LambdaError.InternalServerError)
174+
raise UpdateFhirDocumentReferenceException(
175+
500, LambdaError.InternalServerError
176+
)
160177
try:
161178
# Save document reference to DynamoDB
162179
self._save_document_reference_to_dynamo(dynamo_table, document_reference)
163180
except FhirDocumentReferenceException:
164-
raise UpdateFhirDocumentReferenceException(500, LambdaError.DocRefUploadInternalError)
165-
181+
raise UpdateFhirDocumentReferenceException(
182+
500, LambdaError.DocRefUploadInternalError
183+
)
184+
166185
return presigned_url
167-
186+
168187
def _get_dynamo_table_for_doc_type(self, doc_type: SnomedCode) -> str:
169188
try:
170189
return self.doc_router.resolve(doc_type)

0 commit comments

Comments
 (0)