Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3# 

4# Subclassing FHIR's reference to add resolving capabilities 

5 

6import logging 

7from . import reference 

8 

9logger = logging.getLogger(__name__) 

10 

11 

12class FHIRReference(reference.Reference): 

13 """ Subclassing FHIR's `Reference` resource to add resolving capabilities. 

14 """ 

15 

16 def resolved(self, klass): 

17 """ Resolves the reference and caches the result, returning instance(s) 

18 of the referenced classes. 

19  

20 :param klass: The expected class of the resource 

21 :returns: An instance (or list thereof) of the resolved reference if 

22 dereferencing was successful, `None` otherwise 

23 """ 

24 owning_resource = self.owningResource() 

25 if owning_resource is None: 

26 raise Exception("Cannot resolve reference without having an owner (which must be a `DomainResource`)") 

27 if klass is None: 

28 raise Exception("Cannot resolve reference without knowing the class") 

29 

30 refid = self.processedReferenceIdentifier() 

31 if not refid: 

32 logger.warning("No `reference` set, cannot resolve") 

33 return None 

34 

35 # already resolved and cached? 

36 resolved = owning_resource.resolvedReference(refid) 

37 if resolved is not None: 

38 if isinstance(resolved, klass): 

39 return resolved 

40 logger.warning("Referenced resource {} is not a {} but a {}".format(refid, klass, resolved.__class__)) 

41 return None 

42 

43 # not yet resolved, see if it's a contained resource 

44 if owning_resource.contained is not None: 

45 for contained in owning_resource.contained: 

46 if contained.id == refid: 

47 owning_resource.didResolveReference(refid, contained) 

48 if isinstance(contained, klass): 

49 return contained 

50 logger.warning("Contained resource {} is not a {} but a {}".format(refid, klass, contained.__class__)) 

51 return None 

52 

53 # are we in a bundle? 

54 ref_is_relative = '://' not in self.reference and 'urn:' != self.reference[:4] 

55 bundle = self.owningBundle() 

56 while bundle is not None: 

57 if bundle.entry is not None: 

58 fullUrl = self.reference 

59 if ref_is_relative: 

60 base = bundle.origin_server.base_uri if bundle.origin_server else '' 

61 fullUrl = base + self.reference 

62 

63 for entry in bundle.entry: 

64 if entry.fullUrl == fullUrl: 

65 found = entry.resource 

66 if isinstance(found, klass): 

67 return found 

68 logger.warning("Bundled resource {} is not a {} but a {}".format(refid, klass, found.__class__)) 

69 return None 

70 bundle = bundle.owningBundle() 

71 

72 # relative references, use the same server 

73 server = None 

74 if ref_is_relative: 

75 server = owning_resource.origin_server if owning_resource else None 

76 

77 # TODO: instantiate server for absolute resource 

78 if server is None: 

79 logger.warning("Not implemented: resolving absolute reference to resource {}" 

80 .format(self.reference)) 

81 return None 

82 

83 # fetch remote resource; unable to verify klass since we use klass.read_from() 

84 relative = klass.read_from(self.reference, server) 

85 owning_resource.didResolveReference(refid, relative) 

86 return relative 

87 

88 def processedReferenceIdentifier(self): 

89 """ Normalizes the reference-id. 

90 """ 

91 if self.reference and '#' == self.reference[0]: 

92 return self.reference[1:] 

93 return self.reference 

94