Coverage for /home/martinb/workspace/client-py/fhirclient/models/fhirreference.py : 11%

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
6import logging
7from . import reference
9logger = logging.getLogger(__name__)
12class FHIRReference(reference.Reference):
13 """ Subclassing FHIR's `Reference` resource to add resolving capabilities.
14 """
16 def resolved(self, klass):
17 """ Resolves the reference and caches the result, returning instance(s)
18 of the referenced classes.
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")
30 refid = self.processedReferenceIdentifier()
31 if not refid:
32 logger.warning("No `reference` set, cannot resolve")
33 return None
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
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
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
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()
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
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
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
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