malac-hd 0.1.1a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. malac/__init__.py +0 -0
  2. malac/hd/__init__.py +33 -0
  3. malac/hd/__main__.py +98 -0
  4. malac/hd/compiler/__init__.py +0 -0
  5. malac/hd/compiler/fhir/__init__.py +0 -0
  6. malac/hd/compiler/fhir/r4/__init__.py +0 -0
  7. malac/hd/compiler/fhir/r4/generator/__init__.py +4 -0
  8. malac/hd/compiler/fhir/r4/generator/conceptmap.py +348 -0
  9. malac/hd/compiler/fhir/r4/generator/fhirpath.py +930 -0
  10. malac/hd/compiler/fhir/r4/generator/resource.py +168 -0
  11. malac/hd/compiler/fhir/r4/generator/structuredefinition.py +12 -0
  12. malac/hd/compiler/fhir/r4/generator/structuremap.py +1484 -0
  13. malac/hd/compiler/fhir/r4/parser/__init__.py +0 -0
  14. malac/hd/compiler/fhir/r4/parser/fhirpath.g4 +175 -0
  15. malac/hd/compiler/fhir/r4/parser/fhirpath.interp +153 -0
  16. malac/hd/compiler/fhir/r4/parser/fhirpath.tokens +118 -0
  17. malac/hd/compiler/fhir/r4/parser/fhirpathLexer.interp +215 -0
  18. malac/hd/compiler/fhir/r4/parser/fhirpathLexer.py +314 -0
  19. malac/hd/compiler/fhir/r4/parser/fhirpathLexer.tokens +118 -0
  20. malac/hd/compiler/fhir/r4/parser/fhirpathListener.py +381 -0
  21. malac/hd/compiler/fhir/r4/parser/fhirpathParser.py +1916 -0
  22. malac/hd/compiler/fhir/utils.py +1617 -0
  23. malac/models/__init__.py +0 -0
  24. malac/models/cda/__init__.py +0 -0
  25. malac/models/cda/at_ext.py +67064 -0
  26. malac/models/fhir/__init__.py +0 -0
  27. malac/models/fhir/r4.py +259191 -0
  28. malac_hd-0.1.1a1.dist-info/LICENSE +165 -0
  29. malac_hd-0.1.1a1.dist-info/METADATA +301 -0
  30. malac_hd-0.1.1a1.dist-info/RECORD +33 -0
  31. malac_hd-0.1.1a1.dist-info/WHEEL +5 -0
  32. malac_hd-0.1.1a1.dist-info/entry_points.txt +2 -0
  33. malac_hd-0.1.1a1.dist-info/top_level.txt +1 -0
malac/__init__.py ADDED
File without changes
malac/hd/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ __version__ = "0.1.1alpha1"
4
+
5
+ class ConvertMaster(ABC):
6
+ @abstractmethod
7
+ def convert(self, input, o_module): # TODO:sbe adapt - this is not what is implemented/needed in base classes
8
+ pass
9
+ # return mapping_as_py
10
+
11
+ # not sure if this class will be needed, it is only unsed inside the into py converted map
12
+
13
+
14
+ class TransformMaster(ABC):
15
+ @abstractmethod
16
+ def transform(self, source_path, target_path):
17
+ pass
18
+
19
+ list_m_modules = { # this are modules that can be fully created for malac_hd or Subclasses extending modules that are fully generated by generateDS
20
+ # for StructureMapSub, in this module are additionally planned
21
+ # ConceptMapSub & StructureDefinitionSub (this one also uses
22
+ # ElementDefinitionSub with the <map> element)
23
+ ".4.fhir.xml": "fhir.r4.generator.resource",
24
+ #".4.fhir.map": "fhir4fml"
25
+ }
26
+
27
+ list_i_o_modules = { # this are modules that are fully generated by generateDS
28
+ "http://hl7.org/fhir/StructureDefinition":"fhir.r4",
29
+ "http://hl7.org/fhir/4.0/StructureDefinition":"fhir.r4",
30
+ #"http://hl7.org/fhir/StructureDefinition":"fhir5",
31
+ "http://hl7.org/fhir/cda/StructureDefinition":"cda.at_ext",
32
+ "http://hl7.org/cda/stds/core/StructureDefinition":"cda.at_ext"
33
+ }
malac/hd/__main__.py ADDED
@@ -0,0 +1,98 @@
1
+ import argparse
2
+ import os
3
+ import time
4
+ import sys
5
+ import importlib.util
6
+ # dynamic import by init_class()!
7
+
8
+ if __package__ != "malac.hd":
9
+ current = os.path.dirname(os.path.realpath(__file__))
10
+ parent = os.path.dirname(current)
11
+ sys.path.append(parent)
12
+ import malac.hd
13
+
14
+
15
+ description_text = """You are using the MApping LAnguage Compiler for Health Data, short MaLaC-HD.
16
+ We differentiate between two modes, CONVERTING and TRANSFORMING.
17
+ The CONVERTION is done by compiling a given mapping to python code, that itself can be run with its own argument handling for TRANSFORMING input files.
18
+ Additionally, the TRANSFORMATION can also be be done by MaLaC-HD directly after CONVERTION, i.e. for direct testing purposes."""
19
+ auto_detect = "the ressource type is detected by its root node inside the xml"
20
+
21
+
22
+ def init_argparse(script) -> argparse.ArgumentParser:
23
+ if script:
24
+ prog = "malac-hd"
25
+ else:
26
+ prog = "python -m malac.hd"
27
+ parser = argparse.ArgumentParser(prog=prog, description=description_text, formatter_class=argparse.RawTextHelpFormatter)
28
+ parser.add_argument(
29
+ "-m", "--mapping", help='the mapping file path, the conversion/mapping rule language is detected by file ending, right now only FHIR R4 (*.4.fhir.xml) StructureMaps and ConceptMaps can be given as mappings', required=True
30
+ )
31
+ parser.add_argument(
32
+ "-co", "--convert_output", help='the conversion python file path, if not given, saved in the working directory with the map-file name', required=False
33
+ )
34
+
35
+ parser.add_argument(
36
+ "-ti", "--transform_input", help='the transformation input file path, '+auto_detect, required=False
37
+ )
38
+ parser.add_argument(
39
+ "-to", "--transform_output", help='the transformation output file path, '+auto_detect, required=False
40
+ )
41
+
42
+ parser.add_argument(
43
+ "-s", "--silent", action="store_true", help='do not print the converted python mapping to console', required=False
44
+ )
45
+ return parser
46
+
47
+
48
+ def get_standard_by_fileending(filename, list_classes, return_ending_not_class=False):
49
+ for iclass in list_classes:
50
+ if filename.endswith(iclass):
51
+ if return_ending_not_class:
52
+ return iclass
53
+ return list_classes[iclass]
54
+ sys.exit("The classification could not be detected from the file name. \n %s" % description_text)
55
+
56
+
57
+ def main(script) -> None:
58
+ start = time.time()
59
+ print("____________________ MaLaC-HD "+malac.hd.__version__+" started ____________________")
60
+
61
+ parser = init_argparse(script)
62
+ args = parser.parse_args()
63
+
64
+ print("Converting "+args.mapping)
65
+
66
+ module_name = get_standard_by_fileending(args.mapping, malac.hd.list_m_modules)
67
+ module_split = ["malac", "hd", "compiler"] + module_name.split(".")
68
+ m_module = getattr(__import__(".".join(module_split[:-1]), fromlist=[module_split[-1]]), module_split[-1])
69
+ map = m_module.parse(args.mapping, silence=True)
70
+
71
+ py_code = map.convert(silent=args.silent, source=os.path.abspath(args.mapping))
72
+
73
+ # as similar as possible to https://www.hl7.org/fhir/resource-operation-convert.html
74
+ if args.convert_output:
75
+ if os.path.isfile(args.convert_output):
76
+ os.remove(args.convert_output)
77
+ with open(args.convert_output, 'w', newline='', encoding='utf-8') as f:
78
+ f.write(py_code)
79
+
80
+ # as similar as possible to https://www.hl7.org/fhir/structuremap-operation-transform.html
81
+ # if args.output is full file path, then do the transform itself we just created
82
+ if args.transform_output and args.transform_input:
83
+ print("")
84
+ spec = importlib.util.spec_from_loader("mapping", loader=None)
85
+ module = importlib.util.module_from_spec(spec)
86
+ exec(py_code, module.__dict__)
87
+ module.transform(args.transform_input, args.transform_output)
88
+ print("")
89
+
90
+ print("altogether in "+str(round(time.time()-start,3))+" seconds.")
91
+ print("____________________ MaLaC-HD "+malac.hd.__version__+" ended ____________________")
92
+
93
+
94
+ def script_main():
95
+ main(script=True)
96
+
97
+ if __name__ == '__main__':
98
+ main(script=False)
File without changes
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ from .resource import *
2
+ from .structuremap import *
3
+ from .conceptmap import *
4
+ from .structuredefinition import *
@@ -0,0 +1,348 @@
1
+
2
+ import sys
3
+ import json
4
+
5
+ import malac.hd
6
+ from malac.models.fhir import r4 as supermod
7
+
8
+ class PythonGenerator(supermod.ConceptMap, malac.hd.ConvertMaster):
9
+ from collections import defaultdict
10
+ con_map_6d = None
11
+
12
+ def __init__(self, id=None, meta=None, implicitRules=None, language=None, text=None, contained=None, extension=None, modifierExtension=None, url=None, identifier=None, version=None, name=None, title=None, status=None, experimental=None, date=None, publisher=None, contact=None, description=None, useContext=None, jurisdiction=None, purpose=None, copyright=None, sourceUri=None, sourceCanonical=None, targetUri=None, targetCanonical=None, group=None, **kwargs_):
13
+ super(PythonGenerator, self).__init__(id, meta, implicitRules, language, text, contained, extension, modifierExtension, url, identifier, version, name, title, status, experimental, date, publisher, contact, description, useContext, jurisdiction, purpose, copyright, sourceUri, sourceCanonical, targetUri, targetCanonical, group, **kwargs_)
14
+
15
+ # the source param is not beeing handled, because there are no known possbilities of importing/including conceptMaps in other conceptMaps
16
+ def convert(self, silent=True, return_header_and_footer_for_standalone=True, source=".", return_translate_def=True, return_dict_add=True): # TODO:sbe replace source and return_XXX with context/params, to make more generic
17
+ self.py_code = ""
18
+ if return_header_and_footer_for_standalone:
19
+ self._header_standalone()
20
+ if return_translate_def:
21
+ self._header_translate_def()
22
+ if return_dict_add:
23
+ self.con_map_6d = self.nested_dict(5, list)
24
+ for one_group in self.get_group():
25
+ for one_element in one_group.get_element():
26
+ for one_target in one_element.get_target():
27
+ self.con_map_6d \
28
+ [tmp.get_value() if (tmp := self.get_sourceUri()) or (tmp := self.get_sourceCanonical()) else "%"] \
29
+ [tmp.get_value() if (tmp := self.get_targetUri()) or (tmp := self.get_targetCanonical()) else "%"] \
30
+ [tmp.get_value() if (tmp := one_group.get_source()) else "%"] \
31
+ [tmp.get_value() if (tmp := one_group.get_target()) else "%"] \
32
+ [tmp.get_value() if (tmp := one_element.get_code()) else "%"] \
33
+ .append({"equivalence":one_target.get_equivalence().get_value(),
34
+ "concept":{
35
+ "system": tmp.get_value() if (tmp := one_group.get_source()) else "",
36
+ "version": "", # TODO version of codesystem out of url?
37
+ "code": tmp.get_value() if (tmp := one_target.get_code()) else "",
38
+ "display": tmp.get_value() if (tmp := one_target.get_display()) else "",
39
+ "userSelected": False},
40
+ "source": tmp.get_value() if (tmp := self.get_url()) or (tmp := self.get_id()) else "%"})
41
+
42
+ if unmapped := one_group.get_unmapped(): # using as many unsafe url characters here, that really should not be used as system id/url or codes of a real codesystem, like [ ] { } | \ ” % ~ # < >
43
+ tmp_equivalence = "inexact"
44
+ tmp_code = ""
45
+ tmp_display = ""
46
+ tmp_code_lvl = ""
47
+ if unmapped.get_mode().get_value() == "provided":
48
+ tmp_code_lvl = "|"
49
+ tmp_equivalence = "equal"
50
+ tmp_code = "|" + (tmp.get_value() if (tmp := unmapped.get_code()) else "")
51
+ elif unmapped.get_mode().get_value() == "fixed":
52
+ tmp_code_lvl = "~"
53
+ tmp_code = "~"+unmapped.get_code().get_value() # must be given if fixed
54
+ tmp_display = unmapped.get_display().get_value() or ""
55
+ elif unmapped.get_mode().get_value() == "other-map":
56
+ #tmp_match = "lambda: translate(url="+unmapped.get_url()+", conceptMapVersion=conceptMapVersion, code=code, system=system, version=version, source=source, coding=coding, codeableConcept=codeableConcept, target=target, targetsystem=targetsystem, reverse=reverse, silent=silent)" # cant access the varibales inside the dict...
57
+ tmp_code_lvl = "#"
58
+ tmp_code = "#"+unmapped.get_url().get_value()
59
+ else:
60
+ sys.exit(unmapped.get_mode()+" as mode for unmapped is not defined! Please use the modes from https://hl7.org/fhir/R4B/valueset-conceptmap-unmapped-mode.html .")
61
+ self.con_map_6d \
62
+ [tmp.get_value() if (tmp := self.get_sourceUri()) or (tmp := self.get_sourceCanonical()) else "%"] \
63
+ [tmp.get_value() if (tmp := self.get_targetUri()) or (tmp := self.get_targetCanonical()) else "%"] \
64
+ [tmp.get_value() if (tmp := one_group.get_source()) else "%"] \
65
+ [tmp.get_value() if (tmp := one_group.get_target()) else "%"] \
66
+ [tmp_code_lvl] \
67
+ .append({"equivalence":tmp_equivalence,
68
+ "concept":{
69
+ "system": "",
70
+ "version": "", # TODO version of codesystem out of url?
71
+ "code": tmp_code,
72
+ "display": tmp_display,
73
+ "userSelected": False},
74
+ "source": tmp.get_value() if (tmp := self.get_url()) or (tmp := self.get_id()) else "%"})
75
+
76
+ self.py_code += "\n"
77
+ j_dump = json.dumps(self.con_map_6d, indent=4)
78
+ # replace all the json lower case bools to python usual pascal case bools
79
+ j_dump = j_dump.replace(": false",": False").replace(": true",": True")
80
+ self.py_code += 'con_map_7d["'+(tmp.get_value() if (tmp := self.get_url()) or (tmp := self.get_id()) else "%")+'"] = ' + j_dump
81
+
82
+ if return_header_and_footer_for_standalone:
83
+ self._footer_standalone()
84
+
85
+ if not silent:
86
+ print("\n%s" % self.py_code)
87
+
88
+ return self.py_code
89
+
90
+ # from https://stackoverflow.com/a/39819609/6012216
91
+ def nested_dict(self, n, type):
92
+ if n == 1:
93
+ return self.defaultdict(type)
94
+ else:
95
+ return self.defaultdict(lambda: self.nested_dict(n-1, type))
96
+
97
+ def _header_standalone(self):
98
+ self.py_code += '''import argparse
99
+ import time
100
+ import malac.models.fhir.r4 as fhir4
101
+ import sys
102
+
103
+ description_text = "This has been compiled by the MApping LAnguage Compiler for Health Data, short MaLaC-HD. See arguments for more details."
104
+
105
+ def init_argparse() -> argparse.ArgumentParser:
106
+ parser = argparse.ArgumentParser(description=description_text)
107
+ parser.add_argument(
108
+ '-c', '--code', help="""code --
109
+ The code that is to be translated. If a code is provided, a system must be provided""",
110
+ required=True
111
+ )
112
+ parser.add_argument(
113
+ '-sys', '--system', help="""uri --
114
+ The system for the code that is to be translated""",
115
+ required=True
116
+ )
117
+ parser.add_argument(
118
+ '-ver', '--version', help="""string --
119
+ The version of the system, if one was provided in the source data""",
120
+ required=True
121
+ )
122
+ parser.add_argument(
123
+ '-s', '--source', help="""uri --
124
+ Identifies the value set used when the concept (system/code pair) was chosen.
125
+ May be a logical id, or an absolute or relative location.
126
+ The source value set is an optional parameter because in some cases, the client cannot know what the source value set is.
127
+ However, without a source value set, the server may be unable to safely identify an applicable concept map,
128
+ and would return an error. For this reason, a source value set SHOULD always be provided.
129
+ Note that servers may be able to identify an appropriate concept map without a source value set
130
+ if there is a full mapping for the entire code system in the concept map, or by manual intervention""",
131
+ required=True
132
+ )
133
+ parser.add_argument(
134
+ '-cg', '--coding', help="""Coding --
135
+ A coding to translate""",
136
+ required=True
137
+ )
138
+ parser.add_argument(
139
+ '-cc', '--codeableConcept', help="""CodeableConcept --
140
+ A full codeableConcept to validate. The server can translate any of the coding values (e.g. existing translations)
141
+ as it chooses""",
142
+ required=True
143
+ )
144
+ parser.add_argument(
145
+ '-t', '--target', help="""uri --
146
+ Identifies the value set in which a translation is sought. May be a logical id, or an absolute or relative location.
147
+ If there's no target specified, the server should return all known translations, along with their source""",
148
+ required=True
149
+ )
150
+ parser.add_argument(
151
+ '-ts', '--targetsystem', help="""uri --
152
+ Identifies a target code system in which a mapping is sought. This parameter is an alternative to the target parameter -
153
+ only one is required. Searching for any translation to a target code system irrespective of the context (e.g. target valueset)
154
+ may lead to unsafe results, and it is at the discretion of the server to decide when to support this operation""",
155
+ required=True
156
+ )
157
+ parser.add_argument(
158
+ '-r', '--reverse', action="store_true", help="""boolean -- True if stated, else False --
159
+ If this is true, then the operation should return all the codes that might be mapped to this code.
160
+ This parameter reverses the meaning of the source and target parameters""",
161
+ required=True
162
+ )
163
+ parser.add_argument(
164
+ '-st', '--silent', action="store_true", help="""boolean -- True if stated, else False --
165
+ Do not print the converted python mapping to console""",
166
+ required=True
167
+ )
168
+ return parser
169
+ '''
170
+
171
+ def _header_translate_def(self):
172
+ self.py_code += '''
173
+ # output
174
+ # 1..1 result (boolean)
175
+ # 0..1 message with error details for human (string)
176
+ # 0..* match with (list)
177
+ # 0..1 equivalnce (string from https://hl7.org/fhir/R4B/valueset-concept-map-equivalence.html)
178
+ # 0..1 concept
179
+ # 0..1 system
180
+ # 0..1 version
181
+ # 0..1 code
182
+ # 0..1 display
183
+ # 0..1 userSelected will always be false, because this is a translation
184
+ # 0..1 source (conceptMap url)
185
+ # TODO implement reverse
186
+ def translate(url=None, conceptMapVersion=None, code=None, system=None, version=None, source=None, coding=None, codeableConcept=None, target=None, targetsystem=None, reverse=None, silent=False)\
187
+ -> dict [bool, str, list[dict[str, dict[str, str, str, str, bool], str]]]:
188
+ start = time.time()
189
+
190
+ # start validation and recall of translate in simple from
191
+ if codeableConcept:
192
+ if isinstance(codeableConcept, str):
193
+ codeableConcept = fhir4.parseString(codeableConcept, silent)
194
+ elif isinstance(coding, fhir4.CodeableConcept):
195
+ pass
196
+ else:
197
+ sys.exit("The codeableConcept parameter has to be a string or a CodeableConcept Object (called method as library)!")
198
+ # the first fit will be returned, else the last unfitted value will be returned
199
+ # TODO check translate params
200
+ for one_coding in codeableConcept.get_coding:
201
+ if (ret := translate(url=url, source=source, coding=one_coding,
202
+ target=target, targetsystem=targetsystem,
203
+ reverse=reverse, silent=True))[0]:
204
+ return ret
205
+ else: return ret
206
+
207
+ elif coding:
208
+ if isinstance(coding, str):
209
+ coding = fhir4.parseString(coding, silent)
210
+ elif isinstance(coding, fhir4.Coding):
211
+ pass
212
+ else:
213
+ sys.exit("The coding parameter has to be a string or a Coding Object (called method as library)!")
214
+ # TODO check translate params
215
+ return translate(url=url, source=source, coding=one_coding,
216
+ target=target, targetsystem=targetsystem,
217
+ reverse=reverse, silent=True)
218
+
219
+ elif code:
220
+ if not isinstance(code,str):
221
+ sys.exit("The code parameter has to be a string!")
222
+
223
+ elif target:
224
+ if not isinstance(code,str):
225
+ sys.exit("The target parameter has to be a string!")
226
+
227
+ elif targetsystem:
228
+ if not isinstance(code,str):
229
+ sys.exit("The targetsystem parameter has to be a string!")
230
+
231
+ else:
232
+ sys.exit("At least codeableConcept, coding, code, target or targetSystem has to be given!")
233
+ # end validation and recall of translate in simplier from
234
+
235
+ # look for any information from the one ore more generated conceptMaps into con_map_7d
236
+ match = []
237
+ unmapped = []
238
+ if url not in con_map_7d.keys():
239
+ print(' #ERROR# ConceptMap with URL "'+ url +'" is not loaded to this compiled conceptMap #ERROR#')
240
+ else:
241
+ for url_lvl in con_map_7d:
242
+ if url_lvl == "%" or url_lvl == str(url or ""):#+str(("/?version=" and conceptMapVersion) or ""):
243
+ for source_lvl in con_map_7d[url_lvl]:
244
+ if source_lvl == "%" or not source or source_lvl == source:
245
+ for target_lvl in con_map_7d[url_lvl][source_lvl]:
246
+ if target_lvl == "%" or not target or target_lvl == target:
247
+ for system_lvl in con_map_7d[url_lvl][source_lvl][target_lvl]:
248
+ if system_lvl == "%" or not system or system_lvl == system:#+str(("/?version=" and version) or ""):
249
+ for targetsystem_lvl in con_map_7d[url_lvl][source_lvl][target_lvl][system_lvl]:
250
+ if targetsystem_lvl == "%" or not targetsystem or targetsystem_lvl == targetsystem:
251
+ for code_lvl in con_map_7d[url_lvl][source_lvl][target_lvl][system_lvl][targetsystem_lvl]:
252
+ if code_lvl == "|" or code_lvl == "~" or code_lvl == "#":
253
+ unmapped += con_map_7d[url_lvl][source_lvl][target_lvl][system_lvl][targetsystem_lvl][code_lvl]
254
+ if code_lvl == "%" or not code or code_lvl == code:
255
+ match += con_map_7d[url_lvl][source_lvl][target_lvl][system_lvl][targetsystem_lvl][code_lvl]
256
+
257
+ if not match:
258
+ for one_unmapped in unmapped:
259
+ tmp_system = ""
260
+ tmp_version = ""
261
+ tmp_code = ""
262
+ tmp_display = ""
263
+ # replace all "|" values with to translated code (provided from https://hl7.org/fhir/R4B/conceptmap-definitions.html#ConceptMap.group.unmapped.mode)
264
+ if one_unmapped["concept"]["code"].startswith("|"):
265
+ tmp_system = system
266
+ tmp_version = version
267
+ tmp_code = one_unmapped["concept"]["code"][1:] + code
268
+ # replace all "~" values with fixed code (provided from https://hl7.org/fhir/R4B/conceptmap-definitions.html#ConceptMap.group.unmapped.mode)
269
+ elif one_unmapped["concept"]["code"].startswith("~"):
270
+ tmp_code = one_unmapped["concept"]["code"][1:]
271
+ tmp_display = one_unmapped["concept"]["display"]
272
+ elif one_unmapped["concept"]["code"].startswith("#"):
273
+ # TODO detect recursion like conceptMapA -> conceptMapB -> ConceptMapA -> ...
274
+ return translate(one_unmapped["concept"]["code"][1:], None, code, system, version, source,
275
+ coding, codeableConcept, target, targetsystem, reverse, silent)
276
+ match.append({"equivalence": one_unmapped["equivalence"],
277
+ "concept":{
278
+ "system": tmp_system,
279
+ "version": tmp_version, # TODO version of codesystem out of url?
280
+ "code": tmp_code,
281
+ "display": tmp_display,
282
+ "userSelected": False},
283
+ "source": one_unmapped["source"]})
284
+
285
+
286
+ # see if any match is not "unmatched" or "disjoint"
287
+ result = False
288
+ message = ""
289
+ for one_match in match:
290
+ if one_match["equivalence"] != "unmatched" and one_match["equivalence"] != "disjoint":
291
+ result = True
292
+
293
+ if not silent:
294
+ print('Translation in '+str(round(time.time()-start,3))+' seconds for code "'+code+'" with ConceptMap "'+url+'"')
295
+ return {"result": result, "message": message, "match": match}
296
+
297
+ # The con_map_7d is a seven dimensional dictionary, for quickly finding the fitting translation
298
+ # All dimensions except the last are optional, so a explicit NONE value will be used as key and
299
+ # interpreted as the default key, that always will be fitting, no matter what other keys are fitting.
300
+ # If a version is included (purely optional), than the version will be added with a blank before to the key
301
+ #
302
+ # The 0th dimension is mandatory and stating the ConceptMap with its url (including the version).
303
+ #
304
+ # The 1st dimension is optional and stating the SOURCE valueset (including the version), as one conceptMap can only
305
+ # have a maximum of one SOURCE, this is reserved for MaLaC-HD ability to process multiple ConceptMaps in one output.
306
+ #
307
+ # The 2nd dimension is optional and stating the TARGET valueset (including the version), as one conceptMap can only
308
+ # have a maximum of one TARGET, this is reserved for MaLaC-HD ability to process multiple ConceptMaps in one output.
309
+ #
310
+ # The 3th dimension is optional and stating the SYSTEM (including the version) from the source valueset code, as one
311
+ # code could be used in multiple SYSTEMs from the source valueset to translate.
312
+ # Not stating a SYSTEM with a code, is not FHIR compliant and not a whole concept, but still a valid conceptmap.
313
+ # As many conceptMaps exists that are worngly using this SYSTEM element as stating the valueset, that should be
314
+ # stated in source, this case will still be supported by MaLaC-HD. Having a conceptMap with a source valueset
315
+ # and a different SYSTEM valueset will result in an impossible match and an error will not be recognized by MaLaC-HD.
316
+ #
317
+ # The 4th dimension is optional and stating the TARGET SYSTEM (including the version) from the target valueset code, as one
318
+ # code could be used in multiple SYSTEMs from the target valueset to translate.
319
+ # Not stating a TARGET SYSTEM with a code, is not FHIR compliant and not a whole concept, but still a valid conceptmap.
320
+ # As many conceptMaps exists that are worngly using this TARGET SYSTEM element as stating the target valueset, that should be
321
+ # stated in target, this case will still be supported by MaLaC-HD. Having a conceptMap with a target valueset
322
+ # and a different TARGET SYSTEM valueset will result in an impossible match and an error will not be recognized by MaLaC-HD.
323
+ #
324
+ # The 5th dimension is optional and stating the CODE from the source valueset, as one conceptMap can have none or
325
+ # multiple CODEs from the source to translate.
326
+ #
327
+ # The 6th dimension is NOT optional and stating the TARGET CODE from the target valueset. As one source code could be translated
328
+ # in multiple TARGET CODEs, the whole set have to be returend.
329
+ # For a translation with explicitly no TARGET CODE, because of an quivalence of unmatched or disjoint, NONE will be returned.
330
+ #
331
+ # a minimal example, translating "hi" to "servus":
332
+ # con_map_7d = {"myConMap": {None: {None: {"hi": {None: {None: ["equivalent", "<coding><code>servus</code></coding>", "https://my.concept.map/conceptMap/my"]}}}}}
333
+ #
334
+ # TODO add a dimension for a specific dependsOn property
335
+ # TODO add a solution for the unmapped element
336
+ con_map_7d = {}
337
+ '''
338
+
339
+ def _footer_standalone(self):
340
+ self.py_code += '''
341
+
342
+ if __name__ == "__main__":
343
+ parser = init_argparse()
344
+ args = parser.parse_args()
345
+ ret = translate(args.code, args.system, args.version, args.source, args.coding,
346
+ args.codeableConcept, args.target, args.targetsystem, args.reverse, args.silent)'''
347
+
348
+ supermod.ConceptMap.subclass = PythonGenerator