def define_ciod_module_relationship(ciod, module): try: usage, conditional_statement = expand_conditional_statement( module['usage']) except KeyError as e: # TODO: Remove try/except block once missing IE column in Table A.85.1-1 is fixed (Related to Issue #17) if 'Common Instance Reference' in module['informationEntity']: # Shift every column right by one and replace missing IE column module['usage'] = module['reference_fragment'] module['reference_fragment'] = module['module'] module['module'] = module['informationEntity'] module[ 'informationEntity'] = "<td align=\"left\" colspan=\"1\" rowspan=\"1\">\n<p>\n<a id=\"para_040bd3bd-9a9f-4066-8431-ea1ded2a909e\" shape=\"rect\"></a>Encapsulated Document</p>\n</td>" usage, conditional_statement = expand_conditional_statement( module['usage']) else: raise e informationEntity = pl.text_from_html_string(module['informationEntity']) # TODO: Remove if block once missing IE column in Table A.32.10-1 is fixed (Issue #17) if (not informationEntity and ciod == 'Real-Time Video Photographic Image' and any( mod in module['module'] for mod in ['Real-Time Acquisition', 'Current Frame Functional Groups'])): # Manually input missing field informationEntity = 'Image' return { "ciodId": pl.create_slug(ciod), "moduleId": pl.create_slug(pl.text_from_html_string(module['module'])), "usage": usage, "conditionalStatement": conditional_statement, "informationEntity": informationEntity }
def define_ciod_macro_relationship(ciod, macro): usage, conditional_statement = expand_conditional_statement(macro['usage']) return { "ciodId": pl.create_slug(ciod), "macroId": pl.create_slug(clean_macro_name(pl.text_from_html_string(macro['macro']))), "usage": usage, "conditionalStatement": conditional_statement }
def define_ciod_module_relationship(ciod, module): usage, conditional_statement = expand_conditional_statement( module['usage']) return { "ciod": pl.create_slug(ciod), "module": pl.create_slug(pl.text_from_html_string(module['module'])), "usage": usage, "conditionalStatement": conditional_statement, "informationEntity": pl.text_from_html_string(module['informationEntity']) }
def table_to_json(table: List[TableDictType]) -> List[TableDictType]: attributes = [] for attr in table: attr['id'] = pl.create_slug(attr['tag']) attr['tag'] = attr['tag'].upper() attributes.append(attr) return attributes
def update_hierarchy_position(attr: Dict[str, str], last_id: List[str], current_level: int) -> Tuple[List[str], int]: attr_id = pl.create_slug(clean_attribute_field(attr['tag'])) attribute_level = get_hierarchy_level(attr['name']) delta_l = attribute_level - current_level if attr_id == 'none': print(attr) raise Exception('this shouldn\'t happen') if delta_l > 1: # Standard workaround: There is a typo in the DICOM standard where two hierarchy # markers are used instead of one. This catches that anomaly. delta_l = 1 # Error can be seen at the following link: # http://dicom.nema.org/medical/dicom/current/output/html/part03.html#para_a3f9cf09-67b7-4645-943a-6d405dc81b93 # raise Exception('Shouldn\'t be skipping levels.') if delta_l == 0: last_id[-1] = attr_id elif delta_l == 1: last_id.append(attr_id) current_level += 1 elif delta_l < 0: last_id = last_id[:(delta_l)] last_id[-1] = attr_id current_level += (delta_l) return last_id, current_level
def get_table_with_metadata( table_with_tdiv: Tuple[List[TableDictType], Tag]) -> MetadataTableType: table, tdiv = table_with_tdiv table_name = pr.table_name(tdiv) clean_name = pl.clean_table_name(table_name) table_description = pr.table_description(tdiv) is_macro = True if MACRO_TABLE_SUFFIX.match(table_name) else False # Standard workaround: Add description to module without a description paragraph # http://dicom.nema.org/dicom/2013/output/chtml/part03/sect_F.3.html#sect_F.3.2.1 if table_description.has_attr( 'class') and 'title' in table_description.get('class'): table_description_str = f'<p>{clean_name} {"Macro" if is_macro else "Module"}.</p>' table_description = BeautifulSoup(table_description_str, 'html.parser') return { 'name': clean_name, 'attributes': table, 'id': pl.create_slug(clean_name), 'description': str(clean_table_description(table_description, is_macro)), 'linkToStandard': fix_nonstandard_section_links(get_short_standard_link(tdiv)), 'isMacro': is_macro, }
def define_ciod_module_relationship(ciod, module): try: usage, conditional_statement = expand_conditional_statement( module['usage']) except KeyError as e: # TODO: Remove try/except block once missing IE column in Table A.85.1-1 is fixed (Related to Issue #17) if 'Common Instance Reference' in module['informationEntity']: # Shift every column right by one and replace missing IE column module['usage'] = module['referenceFragment'] module['referenceFragment'] = module['module'] module['module'] = module['informationEntity'] module[ 'informationEntity'] = "<td align=\"left\" colspan=\"1\" rowspan=\"1\">\n<p>\n<a id=\"para_040bd3bd-9a9f-4066-8431-ea1ded2a909e\" shape=\"rect\"></a>Encapsulated Document</p>\n</td>" usage, conditional_statement = expand_conditional_statement( module['usage']) else: raise e raw_information_entity = module.get('informationEntity') # If the "Information Entity" field doesn't exist, this is probably an single IOD rather than a CIOD, so just use the IOD name information_entity = pl.text_from_html_string( raw_information_entity) if raw_information_entity else ciod # Standard workaround: Fill in missing values in the "Information Entity" field of certain rows in Table A.32.10-1 # http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_A.32.10.2.html#table_A.32.10-1 if (ciod == 'Real-Time Video Photographic Image' and any(mod in module['module'] for mod in ['Real-Time Acquisition', 'Current Frame Functional Groups'])): # Manually input missing field information_entity = 'Image' ciod_id = pl.create_slug(ciod) module_id = pl.create_slug(pl.text_from_html_string(module['module'])) # Standard workaround: Fix inconsistent capitalization in the "Information Entity" field of Rendition Selection Document # http://dicom.nema.org/medical/dicom/2019e/output/chtml/part03/sect_A.35.21.3.html#table_A.35.21-1 if ciod == 'Rendition Selection Document' and module_id == 'synchronization': information_entity = 'Frame of Reference' # Create CIOD-specific "Multi-frame Functional Group" module IDs if module_id == MF_FUNC_GROUP_MODULE_ID: module_id = f'{ciod_id}-{module_id}' # Create CIOD-specific "Current Frame Functional Group" module IDs if module_id == CF_FUNC_GROUP_MODULE_ID: module_id = f'{ciod_id}-{module_id}' return { "ciodId": ciod_id, "moduleId": module_id, "usage": usage, "conditionalStatement": conditional_statement, "informationEntity": information_entity, }
def attribute_table_to_json(table: List[TableDictType]) -> List[TableDictType]: attributes = [] for attr in table: attr['id'] = pl.create_slug(attr['tag']) attr['tag'] = attr['tag'].upper() attr['retired'] = 'Y' if 'RET' in attr['retired'] else 'N' attributes.append(attr) return attributes
def attribute_table_to_json(table): attribute_dict = {} for attr in table: attr_slug = pl.create_slug(attr['tag']) attribute_dict[attr_slug] = attr attribute_dict[attr_slug]['tag'] = attr['tag'].upper() attribute_dict[attr_slug][ 'retired'] = True if attr['retired'] == 'RET' else False return attribute_dict
def get_table_with_metadata(table_with_tdiv): table, tdiv = table_with_tdiv clean_name = pl.clean_table_name(pr.table_name(tdiv)) table_description = get_ciod_description(tdiv) return { 'name': clean_name, 'modules': table, 'id': pl.create_slug(clean_name), 'description': str(table_description), 'linkToStandard': get_short_standard_link(tdiv) }
def get_table_with_metadata( table_with_tdiv: Tuple[List[TableDictType], Tag]) -> MetadataTableType: table, tdiv = table_with_tdiv clean_name = clean_macro_table_name(pr.table_name(tdiv)) table_description = get_table_description(tdiv) return { 'name': clean_name, 'macros': table, 'id': pl.create_slug(clean_name), 'description': str(table_description), 'linkToStandard': get_short_standard_link(tdiv) }
def get_table_with_metadata(table_with_tdiv: Tuple[List[TableDictType], Tag]) -> MetadataTableType: table, tdiv = table_with_tdiv clean_name = clean_macro_table_name(pr.table_name(tdiv)) clean_description = pl.clean_html(str(tdiv.find_previous('p'))) module_type = 'Multi-frame' if 'Multi-frame' in clean_description \ else 'Current Frame' if 'Current Frame' in clean_description \ else None return { 'name': clean_name, 'macros': table, 'id': pl.create_slug(clean_name), 'description': clean_description, 'linkToStandard': get_short_standard_link(tdiv), 'moduleType': module_type, }
def update_hierarchy_position(attr: Dict[str, str], last_id: List[str], current_level: int) -> Tuple[List[str], int]: attr_id = pl.create_slug(clean_attribute_field(attr['tag'])) attribute_level = get_hierarchy_level(attr['name']) delta_l = attribute_level - current_level if attr_id == 'none': print(attr) raise Exception('this shouldn\'t happen') if delta_l > 1: # Standard workaround: Catch typo in Table C.8.25.16-8 where an include # statement uses two hierarchy markers instead of one # http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.8.25.16.8.html delta_l = 1 if delta_l == 0: last_id[-1] = attr_id elif delta_l == 1: last_id.append(attr_id) current_level += 1 elif delta_l < 0: last_id = last_id[:(delta_l)] last_id[-1] = attr_id current_level += (delta_l) return last_id, current_level