Skip to content

Commit

Permalink
Improvements to unit test generation
Browse files Browse the repository at this point in the history
  • Loading branch information
p2 committed Jan 25, 2015
1 parent eb64f60 commit 9afb813
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 45 deletions.
6 changes: 3 additions & 3 deletions fhirclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ def add_property(self, prop):

def property_for(self, prop_name):
for prop in self.properties:
if prop.name == prop_name:
if prop.orig_name == prop_name:
return prop
if self.superclass:
if self.superclass and self != self.superclass: # Element is its own superclass
return self.superclass.property_for(prop_name)
return None

Expand All @@ -87,7 +87,7 @@ class FHIRClassProperty(object):
"""

def __init__(self, element, type_obj, type_name=None):
assert element and type_obj # and must be instances of FHIRElement and FHIRElementType
assert element and type_obj # and must be instances of FHIRProfileElement and FHIRElementType
spec = element.profile.spec

self.path = element.path
Expand Down
4 changes: 2 additions & 2 deletions fhirrenderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def copy_files(self):
shutil.copyfile(filepath, tgt)

def render(self):
for pname, profile in self.spec.profiles.items():
for profile in self.spec.writable_profiles():
classes = sorted(profile.writable_classes(), key=lambda x: x.name)
if 0 == len(classes):
if profile.filename is not None: # manual profiles have no filename and usually write no classes
Expand All @@ -87,7 +87,7 @@ class FHIRFactoryRenderer(FHIRRenderer):
"""
def render(self):
classes = []
for pname, profile in self.spec.profiles.items():
for profile in self.spec.writable_profiles():
classes.extend(profile.writable_classes())

data = {
Expand Down
76 changes: 40 additions & 36 deletions fhirspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ def read_profiles(self):

if basename:
profile = FHIRProfile(self, prof)
self.found_profile(profile)
if self.found_profile(profile):
profile.process_profile()

def found_profile(self, profile):
if not profile or not profile.name:
raise Exception("No name for profile {}".format(prof))
elif profile.name in self.profiles:
logger.warning('Already have profile "{}", discarding'.format(profile.name))
else:
self.profiles[profile.name] = profile

def has_profile(self, profile_name):
return profile_name in self.profiles
if not profile or not profile.name:
raise Exception("No name for profile {}".format(prof))
if profile.name in self.profiles:
logger.warning('Already have profile "{}", discarding'.format(profile.name))
return False

self.profiles[profile.name] = profile
return True

def handle_manual_profiles(self):
""" Creates in-memory representations for all our manually defined
Expand All @@ -89,11 +89,23 @@ def handle_manual_profiles(self):
for filepath, module, contains in self.settings.manual_profiles:
for contained in contains:
profile = FHIRProfile(self, None)
profile.structure = FHIRProfileStructure(profile, {'type': contained})
self.found_profile(profile)
profile.is_manual = True

prof_dict = {
'type': contained,
'snapshot': {
'element': [{'path': contained}]
}
}

element = FHIRProfileElementManual(profile, contained)
element.create_class(module)
# manual fix for Resource: add id (but not yet text) to make unit test generator happier
if 'Resource' == contained:
prof_dict['snapshot']['element'].append({'path': 'Resource.id', 'type': [{'code': 'id'}]})
#prof_dict['snapshot']['element'].append({'path': 'Resource.text', 'type': [{'code': 'Narrative'}]})

profile.structure = FHIRProfileStructure(profile, prof_dict)
if self.found_profile(profile):
profile.process_profile()

def finalize(self):
""" Should be called after all profiles have been parsed and allows
Expand Down Expand Up @@ -167,6 +179,13 @@ def parse_unit_tests(self):

# MARK: Writing Data

def writable_profiles(self):
profiles = []
for key, profile in self.profiles.items():
if not profile.is_manual:
profiles.append(profile)
return profiles

def write(self):
if self.settings.write_resources:
renderer = fhirrenderer.FHIRProfileRenderer(self, self.settings)
Expand Down Expand Up @@ -214,6 +233,7 @@ class FHIRProfile(object):
"""

def __init__(self, spec, filepath):
self.is_manual = False
self.spec = spec
self.targetname = None
self.structure = None
Expand Down Expand Up @@ -244,12 +264,12 @@ def read_profile(self):
assert 'Profile' == profile['resourceType']

# parse structure
self.structure = FHIRProfileStructure(self, profile)
logger.info('Parsing profile "{}" --> {}'.format(self.filename, self.name))
if self.spec.has_profile(self.name):
return

# extract all elements
self.structure = FHIRProfileStructure(self, profile)

def process_profile(self):
""" Extract all elements and create classes.
"""
struct = self.structure.differential or self.structure.snapshot
if struct is not None:
mapped = {}
Expand Down Expand Up @@ -511,7 +531,7 @@ def as_properties(self):
FHIRClassProperty instances, None otherwise.
"""
assert self._did_resolve_dependencies
if self.definition.prop_name in self.skip_properties:
if self.definition.prop_name in self.skip_properties and not self.profile.is_manual:
return None

if self.is_main_profile_element or self.definition is None:
Expand Down Expand Up @@ -575,18 +595,6 @@ def superclass_name(self):
return self._superclass_name


class FHIRProfileElementManual(FHIRProfileElement):
def __init__(self, profile, path):
super(FHIRProfileElementManual, self).__init__(profile, {'path': path})
self.represents_class = True
self._did_resolve_dependencies = True

def create_class(self, module):
cls, created = fhirclass.FHIRClass.for_element(self)
if created:
cls.module = module


class FHIRElementDefinition(object):
""" The definition of a FHIR element.
"""
Expand Down Expand Up @@ -658,10 +666,6 @@ def __init__(self, type_dict=None):
def parse_from(self, type_dict):
self.code = type_dict.get('code')
self.profile = type_dict.get('profile')

@property
def has_profile(self):
return self.profile is not None


class FHIRElementConstraint(object):
Expand Down
6 changes: 2 additions & 4 deletions fhirunittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,18 @@ def expand(self):
continue

prop = self.klass.property_for(key)
# TODO: some "subclasses" like Age are empty because all their definitons are in their parent (Quantity). This
# means that later on, the property lookup fails to find the properties for "Age", so fix this please.
if prop is None:
path = "{}.{}".format(self.prefix, key) if self.prefix else key
logger.warning('Unknown property "{}" in unit test on {} in {}'
.format(path, self.klass.name, self.filepath))
else:
propclass = fhirclass.FHIRClass.with_name(prop.class_name)
if propclass is None:
path = "{}.{}".format(self.prefix, key) if self.prefix else key
path = "{}.{}".format(self.prefix, prop.name) if self.prefix else prop.name
logger.error('There is no class "{}" for property "{}" in {}'
.format(prop.class_name, path, self.filepath))
else:
path = self.controller.make_path(self.prefix, key)
path = self.controller.make_path(self.prefix, prop.name)

if list == type(val):
i = 0
Expand Down

0 comments on commit 9afb813

Please sign in to comment.