From a7c2cdf1c16a00de30711df4dc0450c576fd01fb Mon Sep 17 00:00:00 2001 From: Sarah Date: Mon, 29 May 2023 15:25:28 +0100 Subject: [PATCH 01/12] write macros for TSB --- .../test_tex/test-tex/testsbxml/macros.tex | 20 +++++++++ deviser/pytest_files/test_tex/test_tex.py | 26 +++++++----- deviser/pytest_files/xml_files/testsbxml.xml | 2 +- deviser/spec_files/TexMacrosFile.py | 42 ++++++++++++------- 4 files changed, 62 insertions(+), 28 deletions(-) create mode 100644 deviser/pytest_files/test_tex/test-tex/testsbxml/macros.tex diff --git a/deviser/pytest_files/test_tex/test-tex/testsbxml/macros.tex b/deviser/pytest_files/test_tex/test-tex/testsbxml/macros.tex new file mode 100644 index 00000000..ae847c79 --- /dev/null +++ b/deviser/pytest_files/test_tex/test-tex/testsbxml/macros.tex @@ -0,0 +1,20 @@ + +% \newcommand{\fixttspace}{\hspace*{1pt}} +\newcommand{\const}[1]{\texttt{ #1}} + +\newcommand{\TestTSBXMLLibrary}{\textsf{Test TSB XML Library}\xspace} +\newcommand{\Tsb}{\textsf{Test TSB XML Library}\xspace} + +\newcommand{\TODO}[1]{\colorbox{blue}{\textcolor{white}{TODO: #1}}} + + +% commands for classes +\newcommand{\TSBDocument}{\defRef{TSBDocument}{tsbdocument-class}} +\newcommand{\Comment}{\defRef{Comment}{comment-class}} + +% commands for listOfClasses +\newcommand{\ListOfComments}{\defRef{ListOfComments}{listofcomments-class}} + +% commands for types + +% commands for plugins diff --git a/deviser/pytest_files/test_tex/test_tex.py b/deviser/pytest_files/test_tex/test_tex.py index 8500b343..7ec2b64e 100644 --- a/deviser/pytest_files/test_tex/test_tex.py +++ b/deviser/pytest_files/test_tex/test_tex.py @@ -28,18 +28,22 @@ def teardown(): # @pytest.mark.skipif(sys.version_info < (3,6), # reason="requires python3.6") + + @pytest.mark.parametrize("name, test_type", [ - ('spatial', 'body'), - ('qual', 'apdx-validation'), - ('groups', 'macros'), - ('groups', 'apdx-validation'), - ('groups', 'body'), - ('unknown_type', 'apdx-validation'), - ('test_sidrefs', 'apdx-validation'), - ('test_sidrefs', 'body'), - ('test_lists', 'apdx-validation'), - ('test_lists', 'body'), - ('test_att', 'apdx-validation'), + # ('spatial', 'body'), + # ('qual', 'apdx-validation'), + # ('groups', 'macros'), + # ('groups', 'apdx-validation'), + # ('groups', 'body'), + # ('unknown_type', 'apdx-validation'), + # ('test_sidrefs', 'apdx-validation'), + # ('test_sidrefs', 'body'), + # ('test_lists', 'apdx-validation'), + # ('test_lists', 'body'), + # ('test_att', 'apdx-validation'), + # ('testsbxml', 'apdx-validation'), + ('testsbxml', 'macros'), ]) def test_tex(name, test_type): assert rtt.run_test(name, test_type) == 0 diff --git a/deviser/pytest_files/xml_files/testsbxml.xml b/deviser/pytest_files/xml_files/testsbxml.xml index 1518e444..310b23ba 100644 --- a/deviser/pytest_files/xml_files/testsbxml.xml +++ b/deviser/pytest_files/xml_files/testsbxml.xml @@ -1,5 +1,5 @@ - + diff --git a/deviser/spec_files/TexMacrosFile.py b/deviser/spec_files/TexMacrosFile.py index a6e298e0..d0f3b54f 100644 --- a/deviser/spec_files/TexMacrosFile.py +++ b/deviser/spec_files/TexMacrosFile.py @@ -41,7 +41,7 @@ import re from ..base_files import BaseTexFile -from ..util import strFunctions +from ..util import strFunctions, global_variables class TexMacrosFile(BaseTexFile.BaseTexFile): @@ -81,6 +81,8 @@ def write_macro_for_listof(self, sbml_class): and sbml_class['lo_elementName'] != '': lo_name = strFunctions.upper_first( sbml_class['lo_elementName']) + elif global_variables.language != 'sbml': + lo_name = strFunctions.cap_list_of_name(sbml_class['name'], False) else: lo_name = strFunctions.cap_list_of_name(sbml_class['name']) self.write_text_line('\\newcommand{0}\\{1}{2}{0}\\defRef{0}{1}{2}' @@ -128,25 +130,33 @@ def write_general_commands(self): self.write_text_line('\\newcommand{0}\\const{1}[1]{0}\\texttt{0} #1{1}{1}' .format(self.start_b, self.end_b)) self.skip_line() - self.write_text_line('\\newcommand{0}\\sbmlthreecore{1}{0}SBML Level~{2} ' - 'Version~{3} Core\\xspace{1}'.format(self.start_b, - self.end_b, - self.level, - self.version)) - self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}' - '{2} package\\xspace{2}'.format(self.start_b, - self.full_pkg_command, - self.end_b, - self.fullname)) + if global_variables.language == 'sbml': + self.write_text_line('\\newcommand{0}\\sbmlthreecore{1}{0}SBML Level~{2} ' + 'Version~{3} Core\\xspace{1}'.format(self.start_b, + self.end_b, + self.level, + self.version)) + self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}' + '{2} package\\xspace{2}'.format(self.start_b, + self.full_pkg_command, + self.end_b, + self.fullname)) + else: + self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}' + '{2}\\xspace{2}'.format(self.start_b, + self.full_pkg_command, + self.end_b, + self.fullname)) + self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}{2}' - '\\xspace{2}' + '\\xspace{2}' .format(self.start_b, - self.brief_pkg_command, - self.end_b, - self.fullname)) + self.brief_pkg_command, + self.end_b, + self.fullname)) self.skip_line() self.write_text_line('\\newcommand{0}\\TODO{1}[1]{0}\\colorbox{0}blue{1}' - '{0}\\textcolor{0}white{1}{0}TODO: #1{1}{1}{1}' + '{0}\\textcolor{0}white{1}{0}TODO: #1{1}{1}{1}' .format(self.start_b, self.end_b)) self.skip_line() From 1813537b368230cf6e9e364b7e48a81d85c986d6 Mon Sep 17 00:00:00 2001 From: Sarah Date: Mon, 29 May 2023 15:26:06 +0100 Subject: [PATCH 02/12] WRITE MACROS.TEX --- deviser/base_files/BaseTexFile.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/deviser/base_files/BaseTexFile.py b/deviser/base_files/BaseTexFile.py index d0eeae27..e1182310 100644 --- a/deviser/base_files/BaseTexFile.py +++ b/deviser/base_files/BaseTexFile.py @@ -40,7 +40,7 @@ from . import BaseFile -from ..util import strFunctions +from ..util import strFunctions, global_variables class BaseTexFile(BaseFile.BaseFile): @@ -86,7 +86,11 @@ def __init__(self, name, extension, object_desc): self.sort_attribute_names(self.sbml_classes) self.sort_enum_names(self.enums) - self.full_pkg_command = '\\{0}Package'.format(self.fulltexname) + if global_variables.language == 'sbml': + self.full_pkg_command = '\\{0}Package'.format(self.fulltexname) + else: + self.full_pkg_command = '\\{0}'.format(self.fulltexname) + self.brief_pkg_command = '\\{0}'.format(self.upper_package) ######################################################################## From 4a17dd3d43a970d21f2bd36b960228fe39f0654f Mon Sep 17 00:00:00 2001 From: Sarah Date: Mon, 29 May 2023 15:47:41 +0100 Subject: [PATCH 03/12] linting --- deviser/spec_files/TexMacrosFile.py | 219 ++++++++++++++++------------ 1 file changed, 128 insertions(+), 91 deletions(-) diff --git a/deviser/spec_files/TexMacrosFile.py b/deviser/spec_files/TexMacrosFile.py index d0f3b54f..554bc69b 100644 --- a/deviser/spec_files/TexMacrosFile.py +++ b/deviser/spec_files/TexMacrosFile.py @@ -41,123 +41,160 @@ import re from ..base_files import BaseTexFile -from ..util import strFunctions, global_variables +from ..util import global_variables, strFunctions class TexMacrosFile(BaseTexFile.BaseTexFile): """Class for the definition of class name macros in LaTeX""" def __init__(self, object_desc): - # derived members for description - self.brief_description = 'Macros definition for specification' - - BaseTexFile.BaseTexFile.__init__(self, 'macros', 'tex', object_desc) - - # self.full_pkg_command = '\\{}Package'.format(self.fulltexname) - # self.brief_pkg_command = '\\{}'.format(self.upper_package) - - self.core_classes = ['Model', 'Compartment', 'Species', 'Parameter', - 'Rule', 'InitialAssignment', 'Reaction', 'Event', - 'Constraint', 'SpeciesReference', - 'EventAssignment', - 'KineticLaw', 'LocalParameter'] + self.brief_description = "Macros definition for specification" + + BaseTexFile.BaseTexFile.__init__(self, "macros", "tex", object_desc) + + self.core_classes = [ + "Model", + "Compartment", + "Species", + "Parameter", + "Rule", + "InitialAssignment", + "Reaction", + "Event", + "Constraint", + "SpeciesReference", + "EventAssignment", + "KineticLaw", + "LocalParameter", + ] ######################################################################## # Write the command for each class def write_macro_for_class(self, sbml_class): - self.write_text_line('\\newcommand{0}\\{1}{2}{0}\\defRef{0}{4}{2}' - '{0}{3}{2}{2}' - .format(self.start_b, sbml_class['texname'], - self.end_b, - strFunctions.make_tex_class(sbml_class['texname']), - sbml_class['name'])) + self.write_text_line( + "\\newcommand{0}\\{1}{2}{0}\\defRef{0}{4}{2}" + "{0}{3}{2}{2}".format( + self.start_b, + sbml_class["texname"], + self.end_b, + strFunctions.make_tex_class(sbml_class["texname"]), + sbml_class["name"], + ) + ) # Write commands for each ListOf class def write_macro_for_listof(self, sbml_class): - if sbml_class['hasListOf']: - if 'lo_elementName' in sbml_class \ - and sbml_class['lo_elementName'] != '': - lo_name = strFunctions.upper_first( - sbml_class['lo_elementName']) - elif global_variables.language != 'sbml': - lo_name = strFunctions.cap_list_of_name(sbml_class['name'], False) + if sbml_class["hasListOf"]: + if "lo_elementName" in sbml_class and sbml_class["lo_elementName"] != "": + lo_name = strFunctions.upper_first(sbml_class["lo_elementName"]) + elif global_variables.language != "sbml": + lo_name = strFunctions.cap_list_of_name(sbml_class["name"], False) else: - lo_name = strFunctions.cap_list_of_name(sbml_class['name']) - self.write_text_line('\\newcommand{0}\\{1}{2}{0}\\defRef{0}{1}{2}' - '{0}{3}{2}{2}' - .format(self.start_b, lo_name, self.end_b, - strFunctions.make_tex_class(lo_name))) + lo_name = strFunctions.cap_list_of_name(sbml_class["name"]) + self.write_text_line( + "\\newcommand{0}\\{1}{2}{0}\\defRef{0}{1}{2}" + "{0}{3}{2}{2}".format( + self.start_b, + lo_name, + self.end_b, + strFunctions.make_tex_class(lo_name), + ) + ) # hack for render - if sbml_class['name'] == 'GradientBase': - self.write_text_line('\\newcommand{0}\\{4}{2}{0}\\defRef{0}{1}{2}' - '{0}{3}{2}{2}' - .format(self.start_b, lo_name, self.end_b, - strFunctions.make_tex_class(lo_name), - 'ListOfGradientBases')) - elif sbml_class['name'] == 'RenderPoint': - self.write_text_line('\\newcommand{0}\\{4}{2}{0}\\defRef{0}{1}{2}' - '{0}{3}{2}{2}' - .format(self.start_b, lo_name, self.end_b, - strFunctions.make_tex_class(lo_name), - 'ListOfRenderPoints')) + if sbml_class["name"] == "GradientBase": + self.write_text_line( + "\\newcommand{0}\\{4}{2}{0}\\defRef{0}{1}{2}" + "{0}{3}{2}{2}".format( + self.start_b, + lo_name, + self.end_b, + strFunctions.make_tex_class(lo_name), + "ListOfGradientBases", + ) + ) + elif sbml_class["name"] == "RenderPoint": + self.write_text_line( + "\\newcommand{0}\\{4}{2}{0}\\defRef{0}{1}{2}" + "{0}{3}{2}{2}".format( + self.start_b, + lo_name, + self.end_b, + strFunctions.make_tex_class(lo_name), + "ListOfRenderPoints", + ) + ) # Write commands for each primitive type def write_macro_for_enum(self, enum): # check for underscores - cmd_name = re.sub('_t', 't', enum['name']) - self.write_text_line('\\newcommand{0}\\{1}{2}{0}\\defRef{0}{3}{2}' - '{0}{4}{2}{2}' - .format(self.start_b, cmd_name, - self.end_b, enum['name'], - 'primitive-types')) + cmd_name = re.sub("_t", "t", enum["name"]) + self.write_text_line( + "\\newcommand{0}\\{1}{2}{0}\\defRef{0}{3}{2}" + "{0}{4}{2}{2}".format( + self.start_b, cmd_name, self.end_b, enum["name"], "primitive-types" + ) + ) # Write commands for each plugin def write_macro_for_plugin(self, plugin): - if plugin['sbase'] not in self.core_classes: - self.write_text_line('\\newcommand{0}\\{1}{2}{0}\\defRef{0}{4}{2}' - '{0}{3}{2}{2}' - .format(self.start_b, plugin['sbase'], - self.end_b, - strFunctions.make_tex_class(plugin['sbase']), - plugin['sbase'])) + if plugin["sbase"] not in self.core_classes: + self.write_text_line( + "\\newcommand{0}\\{1}{2}{0}\\defRef{0}{4}{2}" + "{0}{3}{2}{2}".format( + self.start_b, + plugin["sbase"], + self.end_b, + strFunctions.make_tex_class(plugin["sbase"]), + plugin["sbase"], + ) + ) # Write general commands def write_general_commands(self): - self.write_comment_line('\\newcommand{\\fixttspace}{\\hspace*{1pt}}') + self.write_comment_line("\\newcommand{\\fixttspace}{\\hspace*{1pt}}") - self.write_text_line('\\newcommand{0}\\const{1}[1]{0}\\texttt{0} #1{1}{1}' - .format(self.start_b, self.end_b)) + self.write_text_line( + "\\newcommand{0}\\const{1}[1]{0}\\texttt{0} #1{1}{1}".format( + self.start_b, self.end_b + ) + ) self.skip_line() - if global_variables.language == 'sbml': - self.write_text_line('\\newcommand{0}\\sbmlthreecore{1}{0}SBML Level~{2} ' - 'Version~{3} Core\\xspace{1}'.format(self.start_b, - self.end_b, - self.level, - self.version)) - self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}' - '{2} package\\xspace{2}'.format(self.start_b, - self.full_pkg_command, - self.end_b, - self.fullname)) + if global_variables.language == "sbml": + self.write_text_line( + "\\newcommand{0}\\sbmlthreecore{1}{0}SBML Level~{2} " + "Version~{3} Core\\xspace{1}".format( + self.start_b, self.end_b, self.level, self.version + ) + ) + self.write_text_line( + "\\newcommand{0}{1}{2}{0}\\textsf{0}{3}" + "{2} package\\xspace{2}".format( + self.start_b, self.full_pkg_command, self.end_b, self.fullname + ) + ) else: - self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}' - '{2}\\xspace{2}'.format(self.start_b, - self.full_pkg_command, - self.end_b, - self.fullname)) - - self.write_text_line('\\newcommand{0}{1}{2}{0}\\textsf{0}{3}{2}' - '\\xspace{2}' - .format(self.start_b, - self.brief_pkg_command, - self.end_b, - self.fullname)) + self.write_text_line( + "\\newcommand{0}{1}{2}{0}\\textsf{0}{3}" + "{2}\\xspace{2}".format( + self.start_b, self.full_pkg_command, self.end_b, self.fullname + ) + ) + + self.write_text_line( + "\\newcommand{0}{1}{2}{0}\\textsf{0}{3}{2}" + "\\xspace{2}".format( + self.start_b, self.brief_pkg_command, self.end_b, self.fullname + ) + ) self.skip_line() - self.write_text_line('\\newcommand{0}\\TODO{1}[1]{0}\\colorbox{0}blue{1}' - '{0}\\textcolor{0}white{1}{0}TODO: #1{1}{1}{1}' - .format(self.start_b, self.end_b)) + self.write_text_line( + "\\newcommand{0}\\TODO{1}[1]{0}\\colorbox{0}blue{1}" + "{0}\\textcolor{0}white{1}{0}TODO: #1{1}{1}{1}".format( + self.start_b, self.end_b + ) + ) self.skip_line() ######################################################################### @@ -167,23 +204,23 @@ def write_file(self): BaseTexFile.BaseTexFile.write_file(self) self.write_general_commands() self.skip_line() - self.write_comment_line('commands for classes') + self.write_comment_line("commands for classes") for i in range(0, len(self.sbml_classes)): # hack for render - if self.sbml_classes[i]['name'] != "RelAbsVector": + if self.sbml_classes[i]["name"] != "RelAbsVector": self.write_macro_for_class(self.sbml_classes[i]) self.skip_line() - self.write_comment_line('commands for listOfClasses') + self.write_comment_line("commands for listOfClasses") for i in range(0, len(self.sbml_classes)): self.write_macro_for_listof(self.sbml_classes[i]) self.skip_line() - self.write_comment_line('commands for types') + self.write_comment_line("commands for types") for i in range(0, len(self.enums)): self.write_macro_for_enum(self.enums[i]) for i in range(0, len(self.prim_class)): self.write_macro_for_enum(self.prim_class[i]) self.skip_line() - self.write_comment_line('commands for plugins') + self.write_comment_line("commands for plugins") for i in range(0, len(self.plugins)): self.write_macro_for_plugin(self.plugins[i]) From db71fe6a38349d3dad2fe6c1092b5b6ef284ad95 Mon Sep 17 00:00:00 2001 From: Sarah Date: Mon, 29 May 2023 15:51:49 +0100 Subject: [PATCH 04/12] linting --- deviser/base_files/BaseTexFile.py | 90 +++++++++++++------------------ 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/deviser/base_files/BaseTexFile.py b/deviser/base_files/BaseTexFile.py index e1182310..43e7e971 100644 --- a/deviser/base_files/BaseTexFile.py +++ b/deviser/base_files/BaseTexFile.py @@ -39,8 +39,8 @@ # ------------------------------------------------------------------------ --> +from ..util import global_variables, strFunctions from . import BaseFile -from ..util import strFunctions, global_variables class BaseTexFile(BaseFile.BaseFile): @@ -57,27 +57,27 @@ def __init__(self, name, extension, object_desc): BaseFile.BaseFile.__init__(self, name, extension) # change the comment delimiter and line length - self.comment = '%' + self.comment = "%" self.line_length = 72 - self.package = object_desc['name'] - self.fullname = object_desc['fullname'] - self.sbml_classes = object_desc['baseElements'] - self.offset = object_desc['offset'] - self.plugins = object_desc['plugins'] - self.enums = object_desc['enums'] - self.level = object_desc['base_level'] - self.version = object_desc['base_version'] - self.pkg_version = object_desc['pkg_version'] - if object_desc['required']: - self.reqd_status = 'true' + self.package = object_desc["name"] + self.fullname = object_desc["fullname"] + self.sbml_classes = object_desc["baseElements"] + self.offset = object_desc["offset"] + self.plugins = object_desc["plugins"] + self.enums = object_desc["enums"] + self.level = object_desc["base_level"] + self.version = object_desc["base_version"] + self.pkg_version = object_desc["pkg_version"] + if object_desc["required"]: + self.reqd_status = "true" else: - self.reqd_status = 'false' + self.reqd_status = "false" self.prim_class = [] - self.start_b = '{' - self.end_b = '}' + self.start_b = "{" + self.end_b = "}" # expand the information for the classes self.fulltexname = strFunctions.texify(self.fullname) @@ -86,12 +86,12 @@ def __init__(self, name, extension, object_desc): self.sort_attribute_names(self.sbml_classes) self.sort_enum_names(self.enums) - if global_variables.language == 'sbml': - self.full_pkg_command = '\\{0}Package'.format(self.fulltexname) + if global_variables.language == "sbml": + self.full_pkg_command = "\\{0}Package".format(self.fulltexname) else: - self.full_pkg_command = '\\{0}'.format(self.fulltexname) + self.full_pkg_command = "\\{0}".format(self.fulltexname) - self.brief_pkg_command = '\\{0}'.format(self.upper_package) + self.brief_pkg_command = "\\{0}".format(self.upper_package) ######################################################################## @@ -103,14 +103,14 @@ def sort_class_names(self, classes): """ if classes is not None: for i in range(0, len(classes)): - name = classes[i]['name'] + name = classes[i]["name"] texname = strFunctions.texify(name) - classes[i]['texname'] = texname + classes[i]["texname"] = texname # hack for render - if name == 'Ellipse' or name == 'Rectangle': - texname = 'Render' + name - classes[i]['texname'] = texname - if name == 'RelAbsVector': + if name == "Ellipse" or name == "Rectangle": + texname = "Render" + name + classes[i]["texname"] = texname + if name == "RelAbsVector": self.prim_class.append(classes[i]) @staticmethod @@ -122,28 +122,12 @@ def sort_attribute_names(classes): """ if classes is not None: for i in range(0, len(classes)): - attribs = classes[i]['attribs'] + attribs = classes[i]["attribs"] BaseTexFile.update_attrib_dicts(attribs) - # for j in range(0, len(attribs)): - # if attribs[j]['type'] in ['lo_element', 'element', - # 'inline_lo_element']: - # name = attribs[j]['element'] - # else: - # name = attribs[j]['name'] - # texname = strFunctions.texify(name) - # attribs[j]['texname'] = texname for i in range(0, len(classes)): - if 'lo_attribs' in classes[i]: - lo_attribs = classes[i]['lo_attribs'] + if "lo_attribs" in classes[i]: + lo_attribs = classes[i]["lo_attribs"] BaseTexFile.update_attrib_dicts(lo_attribs) - # for j in range(0, len(lo_attribs)): - # if lo_attribs[j]['type'] in ['lo_element', 'element', - # 'inline_lo_element']: - # name = lo_attribs[j]['element'] - # else: - # name = lo_attribs[j]['name'] - # texname = strFunctions.texify(name) - # lo_attribs[j]['texname'] = texname @staticmethod def update_attrib_dicts(my_list): @@ -153,13 +137,12 @@ def update_attrib_dicts(my_list): :param my_list: the list which we update. """ for j in range(0, len(my_list)): - if my_list[j]['type'] in ['lo_element', 'element', - 'inline_lo_element']: - name = my_list[j]['element'] + if my_list[j]["type"] in ["lo_element", "element", "inline_lo_element"]: + name = my_list[j]["element"] else: - name = my_list[j]['name'] + name = my_list[j]["name"] texname = strFunctions.texify(name) - my_list[j]['texname'] = texname + my_list[j]["texname"] = texname @staticmethod def sort_enum_names(enums): @@ -170,9 +153,9 @@ def sort_enum_names(enums): """ if enums is not None: for i in range(0, len(enums)): - name = enums[i]['name'] + name = enums[i]["name"] texname = strFunctions.texify(name) - enums[i]['texname'] = texname + enums[i]["texname"] = texname def write_to_do(self, text): """ @@ -181,8 +164,7 @@ def write_to_do(self, text): :param text: the text describing the TODO. """ - self.write_text_line('\\TODO{0}{1}{2}'.format(self.start_b, text, - self.end_b)) + self.write_text_line("\\TODO{0}{1}{2}".format(self.start_b, text, self.end_b)) self.skip_line() def write_text_line(self, line): From d1cd80ee0f05a0e71a62e293e99840c154aafb3d Mon Sep 17 00:00:00 2001 From: Sarah Date: Fri, 9 Jun 2023 15:14:25 +0100 Subject: [PATCH 05/12] dont print files when fail comparison --- deviser/pytest_files/functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deviser/pytest_files/functions.py b/deviser/pytest_files/functions.py index 512e2349..bcc4440a 100644 --- a/deviser/pytest_files/functions.py +++ b/deviser/pytest_files/functions.py @@ -102,8 +102,8 @@ def compare_files(infile, outfile, fails, not_tested): else: fails.append(infile) print('{0}=================>> FAILED'.format(outfile)) - print('\n\nEXPECTED:\n{0}'.format(indata.strip())) - print('=================\n\nGOT:\n{0}'.format(out.strip())) +# print('\n\nEXPECTED:\n{0}'.format(indata.strip())) +# print('=================\n\nGOT:\n{0}'.format(out.strip())) print('=================') ret = 1 return ret From 02399666977af4b20e6c29461a1752cb71be9345 Mon Sep 17 00:00:00 2001 From: Sarah Date: Fri, 9 Jun 2023 15:16:41 +0100 Subject: [PATCH 06/12] no offset for other libraries --- deviser/pytest_files/xml_files/testsbxml.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deviser/pytest_files/xml_files/testsbxml.xml b/deviser/pytest_files/xml_files/testsbxml.xml index 310b23ba..224a1b57 100644 --- a/deviser/pytest_files/xml_files/testsbxml.xml +++ b/deviser/pytest_files/xml_files/testsbxml.xml @@ -1,5 +1,5 @@ - + From 0d05cf2cc173afa111699410dda19959e673a363 Mon Sep 17 00:00:00 2001 From: Sarah Date: Fri, 9 Jun 2023 15:19:01 +0100 Subject: [PATCH 07/12] names for other libraries --- deviser/spec_files/TexValidationRulesFile.py | 14 +++++++++++--- deviser/util/global_variables.py | 5 +++++ deviser/validation/ValidationRulesForClass.py | 8 ++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/deviser/spec_files/TexValidationRulesFile.py b/deviser/spec_files/TexValidationRulesFile.py index 632cd3ef..5f311b73 100644 --- a/deviser/spec_files/TexValidationRulesFile.py +++ b/deviser/spec_files/TexValidationRulesFile.py @@ -41,6 +41,7 @@ import re from ..base_files import BaseTexFile +from ..util import global_variables from ..validation import ValidationRulesForClass from ..validation import ValidationRulesForPlugin from ..validation import ValidationRulesGeneral @@ -62,9 +63,16 @@ def __init__(self, object_desc): self.full_pkg_command = '\\{0}Package'.format(self.fulltexname) self.brief_pkg_command = '\\{0}'.format(self.upper_package) - self.pkg_ref = 'SBML Level~{0} Specification for {1}, ' \ - 'Version~{2}'.format(self.level, - self.fullname, self.pkg_version) + if global_variables.is_sbml: + self.pkg_ref = 'SBML Level~{0} Specification for {1}, ' \ + 'Version~{2}'.format(self.level, + self.fullname, self.pkg_version) + else: + self.pkg_ref = '{3} Level~{0} Specification for {1}, ' \ + 'Version~{2}'.format(self.level, + self.fullname, self.version, + global_variables.language) + self.reqd_status = object_desc['required'] ######################################################################## diff --git a/deviser/util/global_variables.py b/deviser/util/global_variables.py index 023f0614..a952fd55 100644 --- a/deviser/util/global_variables.py +++ b/deviser/util/global_variables.py @@ -59,6 +59,8 @@ global language language = 'sbml' +global is_sbml +is_sbml = True global baseClass baseClass = 'SBase' global std_base @@ -192,6 +194,9 @@ def set_globals(lang, base, doc, prfix, lib, is_pack, pkg_prefix, use_name_1=True, ast=False, xml=False, top_name=''): global language language = lang + if language != 'sbml': + global is_sbml + is_sbml = False global namespaces global has_level_version diff --git a/deviser/validation/ValidationRulesForClass.py b/deviser/validation/ValidationRulesForClass.py index e566879c..91ca8c36 100644 --- a/deviser/validation/ValidationRulesForClass.py +++ b/deviser/validation/ValidationRulesForClass.py @@ -59,8 +59,12 @@ def __init__(self, object_desc, spec_name, number, package, pkg_ref): self.start_b = '{' self.end_b = '}' - self.lower_name = strFunctions.lower_first(strFunctions.remove_prefix(self.name)) - self.formatted_name = r'\{0}'.format(strFunctions.remove_prefix(self.name)) + if global_variables.is_sbml: + self.lower_name = strFunctions.lower_first(strFunctions.remove_prefix(self.name)) + self.formatted_name = r'\{0}'.format(strFunctions.remove_prefix(self.name)) + else + self.lower_name = strFunctions.lower_first(self.name) + self.formatted_name = r'\{0}'.format(self.name) self.indef = strFunctions.get_indefinite(self.lower_name) self.indef_u = strFunctions.upper_first(self.indef) From baf4b34b71b5ab022c1b36ce59b3e59603913739 Mon Sep 17 00:00:00 2001 From: Sarah Date: Thu, 15 Jun 2023 11:31:38 +0100 Subject: [PATCH 08/12] almost sorted validation --- deviser/base_files/BaseTexFile.py | 37 ++- .../test-tex/testsbxml/apdx-validation.tex | 190 ++++++++++++++++ deviser/spec_files/TexValidationRulesFile.py | 88 +++++-- deviser/validation/ValidationRulesForClass.py | 108 ++++++--- deviser/validation/ValidationRulesGeneral.py | 214 ++++++++++++++---- 5 files changed, 533 insertions(+), 104 deletions(-) create mode 100644 deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex diff --git a/deviser/base_files/BaseTexFile.py b/deviser/base_files/BaseTexFile.py index 43e7e971..20999604 100644 --- a/deviser/base_files/BaseTexFile.py +++ b/deviser/base_files/BaseTexFile.py @@ -60,20 +60,33 @@ def __init__(self, name, extension, object_desc): self.comment = "%" self.line_length = 72 - self.package = object_desc["name"] - self.fullname = object_desc["fullname"] - self.sbml_classes = object_desc["baseElements"] - self.offset = object_desc["offset"] - self.plugins = object_desc["plugins"] - self.enums = object_desc["enums"] - self.level = object_desc["base_level"] - self.version = object_desc["base_version"] - self.pkg_version = object_desc["pkg_version"] - if object_desc["required"]: - self.reqd_status = "true" + if global_variables.is_sbml: + self.package = object_desc["name"] + self.fullname = object_desc["fullname"] + self.sbml_classes = object_desc["baseElements"] + self.offset = object_desc["offset"] + self.plugins = object_desc["plugins"] + self.enums = object_desc["enums"] + self.level = object_desc["base_level"] + self.version = object_desc["base_version"] + self.pkg_version = object_desc["pkg_version"] + if object_desc["required"]: + self.reqd_status = "true" + else: + self.reqd_status = "false" else: + self.package = '' + self.fullname = global_variables.package_full_name + self.sbml_classes = object_desc["baseElements"] + self.offset = object_desc["offset"] + self.plugins = [] + self.enums = object_desc["enums"] + self.level = object_desc["base_level"] + self.version = object_desc["base_version"] + self.pkg_version = 0 self.reqd_status = "false" + self.prim_class = [] self.start_b = "{" @@ -86,7 +99,7 @@ def __init__(self, name, extension, object_desc): self.sort_attribute_names(self.sbml_classes) self.sort_enum_names(self.enums) - if global_variables.language == "sbml": + if global_variables.is_sbml: self.full_pkg_command = "\\{0}Package".format(self.fulltexname) else: self.full_pkg_command = "\\{0}".format(self.fulltexname) diff --git a/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex b/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex new file mode 100644 index 00000000..9c453a76 --- /dev/null +++ b/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex @@ -0,0 +1,190 @@ +% -*- TeX-master: "main"; fill-column: 72 -*- + +\section{Validation of SBML documents} +\label{apdx-validation} + +\subsection{Validation and consistency rules} +\label{validation-rules} + +This section summarizes all the conditions that must (or in some cases, +at least \emph{should}) be true of an SBML Level~1 Version~1 model that +uses the \TestTSBXMLLibraryPackage. We use the same conventions as are +used in the SBML Level~1 Version~1 Core specification document. In +particular, there are different degrees of rule strictness. Formally, +the differences are expressed in the statement of a rule: either a rule +states that a condition \emph{must} be true, or a rule states that it +\emph{should} be true. Rules of the former kind are strict SBML +validation rules---a model encoded in SBML must conform to all of them +in order to be considered valid. Rules of the latter kind are +consistency rules. To help highlight these differences, we use the +following three symbols next to the rule numbers: + +\begin{description} + +\item[\hspace*{6.5pt}\vSymbol\vsp] A \vSymbolName indicates a +\emph{requirement} for SBML conformance. If a model does not follow this +rule, it does not conform to the \TestTSBXMLLibraryPackage +specification. (Mnemonic intention behind the choice of symbol: ``This +must be checked.'') + +\item[\hspace*{6.5pt}\cSymbol\csp] A \cSymbolName indicates a +\emph{recommendation} for model consistency. If a model does not follow +this rule, it is not considered strictly invalid as far as the +\TestTSBXMLLibraryPackage specification is concerned; however, it +indicates that the model contains a physical or conceptual +inconsistency. (Mnemonic intention behind the choice of symbol: ``This +is a cause for warning.'') + +\item[\hspace*{6.5pt}\mSymbol\msp] A \mSymbolName indicates a strong +recommendation for good modeling practice. This rule is not strictly a +matter of SBML encoding, but the recommendation comes from logical +reasoning. As in the previous case, if a model does not follow this +rule, it is not strictly considered an invalid SBML encoding. (Mnemonic +intention behind the choice of symbol: ``You're a star if you heed +this.'') + +\end{description} + +The validation rules listed in the following subsections are all stated +or implied in the rest of this specification document. They are +enumerated here for convenience. Unless explicitly stated, all +validation rules concern objects and attributes specifically defined in +the \TestTSBXMLLibraryPackage package. + +For \notice convenience and brevity, we use the shorthand +``\token{tsb:\-x}'' to stand for an attribute or element name \token{x} +in the namespace for the \TestTSBXMLLibraryPackage package, using the +namespace prefix \token{tsb}. In reality, the prefix string may be +different from the literal ``\token{tsb}'' used here (and indeed, it can +be any valid XML namespace prefix that the modeler or software chooses). +We use ``\token{tsb:\-x}'' because it is shorter than to write a full +explanation everywhere we refer to an attribute or element in the +\TestTSBXMLLibraryPackage namespace. + +\subsubsection*{General rules about this language.} + +\validRule{tsb-10101}{To conform to the \TestTSBXMLLibrary specification +for TSB Level~1 Version~1, an TSB document must declare +\uri{http://testsbxml.org/l1v1} as the XMLNamespace to use for elements +of this package. (Reference: TSB Level~1 Specification for Test TSB XML +Library, Version~1 \sec{xml-namespace}.)} + +\validRule{tsb-10102}{Wherever they appear in a TSB document, elements +and attributes from the \TestTSBXMLLibrary must use the +\uri{http://testsbxml.org/l1v1} namespace, declaring so either +explicitly or implicitly. (Reference: TSB Level~1 Specification for Test +TSB XML Library, Version~1 \sec{xml-namespace}.)} + +\subsubsection*{General rules about identifiers} + +\validRule{tsb-10201}{The value of a \token{tsb:\-metaid} must conform +to the syntax of the XML Type ID (Reference: )} + + + +\subsubsection*{General rules for \TestAnnotation elements} + +\validRule{tsb-10301}{Every top-level XML element within an +\TestAnnotation object must have an XML namespace declared. (Reference: +TSB Level~1 Specification for Test TSB XML Library, Version~1 +\sec{annotation-use}.)} + +\validRule{tsb-10302}{A given XML namespace cannot be the namespace of +more than one top-levelelement within a given \TestAnnotation object. +(Reference: TSB Level~1 Specification for Test TSB XML Library, +Version~1 \sec{annotation-use}.)} + +\validRule{tsb-10303}{A given TSB element may contain at most one +\TestAnnotation subobject. (Reference: TSB Level~1 Specification for +Test TSB XML Library, Version~1 \sec{annotation-use}.)} + +\subsubsection*{General rules for \notes elements} + +\validRule{tsb-10401}{The contents of a \Notes object must be explicitly +placed in the XHTML XML namespace. (Reference: TSB Level~1 Specification +for Test TSB XML Library, Version~1 \sec{notes}.)} + +\validRule{tsb-10402}{The contents of a \Notes object must not contain +an XML declaration, \ie a string of the form \val{} or similar. (Reference: TSB Level~1 Specification +for Test TSB XML Library, Version~1 \sec{notes}.)} + +\validRule{tsb-10403}{The content of a \Notes object must not contain an +XML DOCTYPE declaration, \ie a string beginning with the characters +\val{ 0: self.number += 1 rule = self.write_optional_lo_rule() @@ -431,9 +438,16 @@ def write_package_attribute_rule(self): return reqd = self.parse_required(self, self.reqd_att) opt = self.parse_optional(self, self.opt_att) - no_other_statement = 'No other attributes from the SBML Level~3 {0} ' \ - 'namespaces are permitted on {1} {2} object. '\ - .format(self.fullname, self.indef, self.formatted_name) + if global_variables.is_sbml: + no_other_statement = 'No other attributes from the SBML Level~3 {0} ' \ + 'namespaces are permitted on {1} {2} object. '\ + .format(self.fullname, self.indef, self.formatted_name) + else: + no_other_statement = 'No other attributes from the {3} Level~{4} Version~{5} ' \ + 'namespaces are permitted on {1} {2} object. ' \ + .format(self.fullname, self.indef, self.formatted_name, global_variables.language.upper(), + global_variables.namespaces[0]['level'], global_variables.namespaces[0]['version']) + if len(opt) == 0 and len(reqd) > 0: text = '{0} {1} object must have {2}. {3}'\ .format(self.indef_u, self.formatted_name, @@ -465,21 +479,43 @@ def write_package_object_rule(self): return reqd = self.parse_required_elements(self.reqd_elem) opt = self.parse_optional_elements(self.opt_elem) - no_other_statement = 'No other elements from the SBML Level~3 {0} ' \ - 'namespaces are permitted on {1} {2} object. '\ - .format(self.fullname, self.indef, self.formatted_name) - if len(opt) == 0 and len(reqd) > 0: - text = '{0} {1} object must contain {2}. {3}'\ - .format(self.indef_u, self.formatted_name, - reqd, no_other_statement) - elif len(reqd) == 0 and len(opt) > 0: - text = '{0} {1} object may contain {2}. {3}'\ - .format(self.indef_u, self.formatted_name, - opt, no_other_statement) + if global_variables.is_sbml: + no_other_statement = 'No other elements from the SBML Level~3 {0} ' \ + 'namespaces are permitted on {1} {2} object. '\ + .format(self.fullname, self.indef, self.formatted_name) + if len(opt) == 0 and len(reqd) > 0: + text = '{0} {1} object must contain {2}. {3}'\ + .format(self.indef_u, self.formatted_name, + reqd, no_other_statement) + elif len(reqd) == 0 and len(opt) > 0: + text = '{0} {1} object may contain {2}. {3}'\ + .format(self.indef_u, self.formatted_name, + opt, no_other_statement) + else: + text = '{0} {1} object must contain {2}, and may contain {3}. {4}'\ + .format(self.indef_u, self.formatted_name, + reqd, opt, no_other_statement) else: - text = '{0} {1} object must contain {2}, and may contain {3}. {4}'\ - .format(self.indef_u, self.formatted_name, - reqd, opt, no_other_statement) + common = 'Apart from the general \\{0} and \\{1} subobjects permitted ' \ + 'on all {2} components,'.format('Notes', global_variables.annot_element, + global_variables.language.upper()) + no_other_statement = 'No other objects from the {3} Level~{4} Version~{5} ' \ + 'namespaces are permitted on {1} {2} object. ' \ + .format(self.fullname, self.indef, self.formatted_name, global_variables.language.upper(), + global_variables.namespaces[0]['level'], global_variables.namespaces[0]['version']) + if len(opt) == 0 and len(reqd) > 0: + text = '{4} {0} {1} object must contain {2}. {3}'\ + .format(self.indef_u, self.formatted_name, + reqd, no_other_statement, common) + elif len(reqd) == 0 and len(opt) > 0: + text = '{4} {0} {1} object may contain {2}. {3}'\ + .format(self.indef_u, self.formatted_name, + opt, no_other_statement, common) + else: + text = '{5} {0} {1} object must contain {2}, and may contain {3}. {4}'\ + .format(self.indef_u, self.formatted_name, + reqd, opt, no_other_statement, common) + ref = '{0}, {1}.'\ .format(self.pkg_ref, strFunctions.wrap_section(self.name)) sev = 'ERROR' @@ -686,6 +722,10 @@ def write_reqd_lo_rule(self): # parse the required attribute sentence @staticmethod def parse_required(self, attributes): + if global_variables.is_sbml: + prefix = self.package + else: + prefix = global_variables.language for attrib in attributes: if 'texname' not in attrib or attrib['texname'] == 'RelAbsVector': attrib['texname'] = attrib['name'] @@ -695,25 +735,31 @@ def parse_required(self, attributes): elif num == 1: return 'the required attribute {0}'\ .format(strFunctions.wrap_token(attributes[0]['texname'], - self.package)) + prefix)) else: required_statement = 'the required attributes {0}'\ .format(strFunctions.wrap_token(attributes[0]['texname'], - self.package)) + prefix)) i = 1 while i < num - 1: required_statement += ', {0}'\ .format(strFunctions.wrap_token(attributes[i]['texname'], - self.package)) + prefix)) i += 1 required_statement += ' and {0}'\ .format(strFunctions.wrap_token(attributes[i]['texname'], - self.package)) + prefix)) return required_statement # parse the optional attribute sentence @staticmethod def parse_optional(self, attributes): + if global_variables.is_sbml: + prefix = self.package + else: + prefix = global_variables.language + metaid = {'name': 'metaid', 'type': 'string'} + attributes.append(metaid) for attrib in attributes: if 'texname' not in attrib or attrib['texname'] == 'RelAbsVector': attrib['texname'] = attrib['name'] @@ -723,20 +769,20 @@ def parse_optional(self, attributes): elif num == 1: return 'the optional attribute {0}' \ .format(strFunctions.wrap_token(attributes[0]['texname'], - self.package)) + prefix)) else: optional_statement = 'the optional attributes {0}' \ .format(strFunctions.wrap_token(attributes[0]['texname'], - self.package)) + prefix)) i = 1 while i < num - 1: optional_statement += ', {0}' \ .format(strFunctions.wrap_token(attributes[i]['texname'], - self.package)) + prefix)) i += 1 optional_statement += ' and {0}' \ .format(strFunctions.wrap_token(attributes[i]['texname'], - self.package)) + prefix)) return optional_statement # parse the required elements sentence diff --git a/deviser/validation/ValidationRulesGeneral.py b/deviser/validation/ValidationRulesGeneral.py index 0fb4f9ea..cfabbbec 100644 --- a/deviser/validation/ValidationRulesGeneral.py +++ b/deviser/validation/ValidationRulesGeneral.py @@ -40,11 +40,11 @@ from ..util import strFunctions, global_variables -class ValidationRulesGeneral(): +class ValidationRulesGeneral: """Class for creating the general validation rules""" def __init__(self, spec_name, number, package, pkg_ref, level, version, - pkg_version, reqd_status): + pkg_version, reqd_status, full_pkg_command): # members from object self.fullname = spec_name self.number = number @@ -57,8 +57,7 @@ def __init__(self, spec_name, number, package, pkg_ref, level, version, else: self.reqd_status = 'false' - self.full_pkg_command = \ - '\\{0}Package'.format(strFunctions.texify(self.fullname)) + self.full_pkg_command = full_pkg_command # useful repeated text strings self.valid = '\\validRule{' self.start_b = '{' @@ -77,53 +76,98 @@ def __init__(self, spec_name, number, package, pkg_ref, level, version, def determine_rules(self): # write rules increasing the number - self.number += 10100 - rule = self.write_unknown_rule(self) - self.add_rule(rule) + if global_variables.is_sbml: + self.number += 10100 + rule = self.write_unknown_rule(self) + self.add_rule(rule) - self.number += 1 - rule = self.write_ns_rule(self) - self.add_rule(rule) + self.number += 1 + rule = self.write_ns_rule(self) + self.add_rule(rule) - self.number += 1 - rule = self.write_element_not_ns_rule(self) - self.add_rule(rule) + self.number += 1 + rule = self.write_element_not_ns_rule(self) + self.add_rule(rule) - self.number = self.offset + 10301 - rule = self.write_id_rule(self) - self.add_rule(rule) + self.number = self.offset + 10301 + rule = self.write_id_rule(self) + self.add_rule(rule) - self.number += 1 - rule = self.write_id_syntax_rule(self) - self.add_rule(rule) + self.number += 1 + rule = self.write_id_syntax_rule(self) + self.add_rule(rule) - if global_variables.is_package: - self.number = self.offset + 20101 - rule = self.write_reqd_rule(self) + if global_variables.is_package: + self.number = self.offset + 20101 + rule = self.write_reqd_rule(self) + self.add_rule(rule) + + self.number += 1 + rule = self.write_reqd_bool_rule(self) + self.add_rule(rule) + + self.number += 1 + rule = self.write_reqd_value_rule(self) + self.add_rule(rule) + else: + self.number += 1 + rule = self.write_metaid_syntax_rule(self) + self.add_rule(rule) + + self.number = self.offset + 20101 + rule = self.write_valid_ns_rule(self) + self.add_rule(rule) + + self.number += 1 + rule = self.write_allowed_attributes_rule(self) + self.add_rule(rule) + + self.number += 1 + rule = self.write_empty_list_rule(self) + self.add_rule(rule) + else: + self.number += 10100 + rule = self.write_unknown_rule(self) self.add_rule(rule) self.number += 1 - rule = self.write_reqd_bool_rule(self) + rule = self.write_ns_rule(self) self.add_rule(rule) self.number += 1 - rule = self.write_reqd_value_rule(self) + rule = self.write_element_not_ns_rule(self) self.add_rule(rule) - else: - self.number += 1 + + self.number = 10201 rule = self.write_metaid_syntax_rule(self) self.add_rule(rule) - self.number = self.offset + 20101 - rule = self.write_valid_ns_rule(self) + self.number = 10301 + rule = self.write_annotation_rule(self, 1) self.add_rule(rule) self.number += 1 - rule = self.write_allowed_attributes_rule(self) + rule = self.write_annotation_rule(self, 2) self.add_rule(rule) self.number += 1 - rule = self.write_empty_list_rule(self) + rule = self.write_annotation_rule(self, 3) + self.add_rule(rule) + + self.number = 10401 + rule = self.write_notes_rule(self, 1) + self.add_rule(rule) + + self.number += 1 + rule = self.write_notes_rule(self, 2) + self.add_rule(rule) + + self.number += 1 + rule = self.write_notes_rule(self, 3) + self.add_rule(rule) + + self.number += 1 + rule = self.write_notes_rule(self, 4) self.add_rule(rule) def add_rule(self, rule): @@ -154,13 +198,24 @@ def write_unknown_rule(self): # write rules about ns @staticmethod def write_ns_rule(self): - text = 'To conform to the {0} specification for SBML Level~{1} ' \ - 'Version~{2}, an SBML document must declare ' \ - '\\uri{3}http://www.sbml.org/sbml/' \ - 'level{1}/version{2}/{4}/version{5}{6} as the XMLNamespace ' \ - 'to use for elements of this package.'\ - .format(self.full_pkg_command, self.level, self.version, - self.start_b, self.package, self.pkg_version, self.end_b) + if global_variables.is_sbml: + text = 'To conform to the {0} specification for {7} Level~{1} ' \ + 'Version~{2}, an {7} document must declare ' \ + '\\uri{3}http://www.sbml.org/sbml/' \ + 'level{1}/version{2}/{4}/version{5}{6} as the XMLNamespace ' \ + 'to use for elements of this package.'\ + .format(self.full_pkg_command, self.level, self.version, + self.start_b, self.package, self.pkg_version, self.end_b, + global_variables.language.upper()) + else: + text = 'To conform to the {0} specification for {7} Level~{1} ' \ + 'Version~{2}, an {7} document must declare ' \ + '\\uri{3}{8}{6} as the XMLNamespace ' \ + 'to use for elements of this package.'\ + .format(self.full_pkg_command, self.level, self.version, + self.start_b, self.package, self.pkg_version, self.end_b, + global_variables.language.upper(), global_variables.namespaces[0]['namespace']) + ref = '{0} {1}.'\ .format(self.pkg_ref, strFunctions.wrap_section('xml-namespace', False)) @@ -176,13 +231,22 @@ def write_ns_rule(self): @staticmethod def write_element_not_ns_rule(self): - text = 'Wherever they appear in an SBML document, elements and ' \ - 'attributes from the {0} must use the ' \ - '\\uri{1}http://www.sbml.org/sbml/level{2}/version{3}' \ - '/{4}/version{5}{6} namespace, declaring so either explicitly ' \ - 'or implicitly.'\ - .format(self.full_pkg_command, self.start_b, self.level, - self.version, self.package, self.pkg_version, self.end_b) + if global_variables.is_sbml: + text = 'Wherever they appear in an SBML document, elements and ' \ + 'attributes from the {0} must use the ' \ + '\\uri{1}http://www.sbml.org/sbml/level{2}/version{3}' \ + '/{4}/version{5}{6} namespace, declaring so either explicitly ' \ + 'or implicitly.'\ + .format(self.full_pkg_command, self.start_b, self.level, + self.version, self.package, self.pkg_version, self.end_b) + else: + text = 'Wherever they appear in a {7} document, elements and ' \ + 'attributes from the {0} must use the ' \ + '\\uri{1}{8}{6} namespace, declaring so either explicitly ' \ + 'or implicitly.' \ + .format(self.full_pkg_command, self.start_b, self.level, + self.version, self.package, self.pkg_version, self.end_b, + global_variables.language.upper(), global_variables.namespaces[0]['namespace']) ref = '{0} {1}.'\ .format(self.pkg_ref, strFunctions.wrap_section('xml-namespace', False)) @@ -347,3 +411,65 @@ def write_empty_list_rule(self): 'reference': ref, 'severity': sev, 'typecode': tc, 'lib_sev': lib_sev, 'short': short, 'lib_ref': lib_ref}) + @staticmethod + def write_annotation_rule(self, num): + if num == 1: + text = 'Every top-level XML element within an \\{0} object must ' \ + 'have an XML namespace declared.'.format(global_variables.annot_element) + short = 'No ns for {0}'.format(global_variables.annot_element) + tc = '{0}NoAnnotationNS'.format(global_variables.prefix) + elif num == 2: + text = 'A given XML namespace cannot be the namespace of more than one top-level' \ + 'element within a given \\{0} object.'.format(global_variables.annot_element) + short = 'Repeat ns for {0}'.format(global_variables.annot_element) + tc = '{0}RepeatAnnotationNS'.format(global_variables.prefix) + else: + text = 'A given {0} element may contain at most one \\{1} ' \ + 'subobject.'.format(global_variables.up_full_lib, global_variables.annot_element) + short = 'Only one {0}'.format(global_variables.annot_element) + tc = '{0}OnlyOneAnnotation'.format(global_variables.prefix) + + ref = '{0} {1}.' \ + .format(self.pkg_ref, + strFunctions.wrap_section('annotation-use', False)) + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + lib_ref = 'L3V1 {0} V1 Section'.format(self.up_package) + return dict({'number': self.number, 'text': text, + 'reference': ref, 'severity': sev, 'typecode': tc, + 'lib_sev': lib_sev, 'short': short, 'lib_ref': lib_ref}) + + @staticmethod + def write_notes_rule(self, num): + if num == 1: + text = 'The contents of a \\{0} object must be explicitly placed in the ' \ + 'XHTML XML namespace. '.format('Notes') + short = 'Notes not in XHTML' + tc = 'NotesInXHTML' + elif num == 2: + text = 'The contents of a \\{0} object must not contain an XML declaration, ' \ + '\\ie a string of the form \\val{1}{2} or ' \ + 'similar.'.format('Notes', '{', '}') + short = 'No XML decl in Notes' + tc = 'XMLDeclNotes' + elif num == 3: + text = 'The content of a \\{0} object must not contain an XML DOCTYPE declaration, ' \ + '\\ie a string beginning with the characters \\val{1} Date: Wed, 21 Jun 2023 10:38:06 +0100 Subject: [PATCH 09/12] amend metaid rule --- deviser/validation/ValidationRulesGeneral.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/deviser/validation/ValidationRulesGeneral.py b/deviser/validation/ValidationRulesGeneral.py index cfabbbec..ff52acb9 100644 --- a/deviser/validation/ValidationRulesGeneral.py +++ b/deviser/validation/ValidationRulesGeneral.py @@ -350,10 +350,17 @@ def write_reqd_value_rule(self): @staticmethod def write_metaid_syntax_rule(self): - text = 'The value of a {0} must conform to the syntax of ' \ - 'the XML Type ID'\ - .format(strFunctions.wrap_token('metaid', self.package)) - ref = 'SBML Level~3 Version~1 Core, Section~3.1.6.' + if global_variables.is_sbml: + text = 'The value of a {0} must conform to the syntax of ' \ + 'the XML Type ID'\ + .format(strFunctions.wrap_token('metaid', self.package)) + ref = 'SBML Level~3 Version~1 Core, Section~3.1.6.' + else: + text = 'The value of a {0} must conform to the syntax of ' \ + 'the XML Type ID'\ + .format(strFunctions.wrap_token('metaid', self.package)) + ref = 'metaid' + # ref = '{0} {1}.'\ # .format(self.pkg_ref, # strFunctions.wrap_section('primitive-types', False)) From 1b4059d8e1864bd2c7fe445e038cdb0ca09fb581 Mon Sep 17 00:00:00 2001 From: Sarah Date: Wed, 21 Jun 2023 10:47:58 +0100 Subject: [PATCH 10/12] sort notes/annotations --- deviser/validation/ValidationRulesGeneral.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deviser/validation/ValidationRulesGeneral.py b/deviser/validation/ValidationRulesGeneral.py index ff52acb9..ca56e6a0 100644 --- a/deviser/validation/ValidationRulesGeneral.py +++ b/deviser/validation/ValidationRulesGeneral.py @@ -432,7 +432,7 @@ def write_annotation_rule(self, num): tc = '{0}RepeatAnnotationNS'.format(global_variables.prefix) else: text = 'A given {0} element may contain at most one \\{1} ' \ - 'subobject.'.format(global_variables.up_full_lib, global_variables.annot_element) + 'subobject.'.format(global_variables.language.upper(), global_variables.annot_element) short = 'Only one {0}'.format(global_variables.annot_element) tc = '{0}OnlyOneAnnotation'.format(global_variables.prefix) @@ -466,7 +466,7 @@ def write_notes_rule(self, num): tc = 'DOCTYPEInNotes' else: text = 'A given {0} element may contain at most one \\{1} ' \ - 'subobject.'.format(global_variables.up_full_lib, 'Notes') + 'subobject.'.format(global_variables.language.upper(), 'Notes') short = 'Only one {0}'.format('Notes') tc = '{0}OnlyOneNotes'.format(global_variables.prefix) From df3c0b9893ed055758e58313e8ce468ed53acad2 Mon Sep 17 00:00:00 2001 From: Sarah Date: Sat, 24 Jun 2023 10:04:50 +0100 Subject: [PATCH 11/12] sort validation rules --- .../test-tex/testsbxml/apdx-validation.tex | 62 +++--- deviser/spec_files/TexValidationRulesFile.py | 7 +- deviser/validation/ValidationRulesForClass.py | 195 ++++++++++++------ 3 files changed, 165 insertions(+), 99 deletions(-) diff --git a/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex b/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex index 9c453a76..66db3160 100644 --- a/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex +++ b/deviser/pytest_files/test_tex/test-tex/testsbxml/apdx-validation.tex @@ -52,16 +52,16 @@ \subsection{Validation and consistency rules} the \TestTSBXMLLibraryPackage package. For \notice convenience and brevity, we use the shorthand -``\token{tsb:\-x}'' to stand for an attribute or element name \token{x} -in the namespace for the \TestTSBXMLLibraryPackage package, using the -namespace prefix \token{tsb}. In reality, the prefix string may be -different from the literal ``\token{tsb}'' used here (and indeed, it can -be any valid XML namespace prefix that the modeler or software chooses). -We use ``\token{tsb:\-x}'' because it is shorter than to write a full +``\token{:\-x}'' to stand for an attribute or element name \token{x} in +the namespace for the \TestTSBXMLLibraryPackage package, using the +namespace prefix \token{}. In reality, the prefix string may be +different from the literal ``\token{}'' used here (and indeed, it can be +any valid XML namespace prefix that the modeler or software chooses). We +use ``\token{:\-x}'' because it is shorter than to write a full explanation everywhere we refer to an attribute or element in the \TestTSBXMLLibraryPackage namespace. -\subsubsection*{General rules about this language.} +\subsubsection*{General rules about this package} \validRule{tsb-10101}{To conform to the \TestTSBXMLLibrary specification for TSB Level~1 Version~1, an TSB document must declare @@ -77,10 +77,8 @@ \subsubsection*{General rules about this language.} \subsubsection*{General rules about identifiers} -\validRule{tsb-10201}{The value of a \token{tsb:\-metaid} must conform -to the syntax of the XML Type ID (Reference: )} - - +\validRule{tsb-10201}{The value of a \token{metaid} must conform to the +syntax of the XML Type ID (Reference: metaid)} \subsubsection*{General rules for \TestAnnotation elements} @@ -114,8 +112,8 @@ \subsubsection*{General rules for \notes elements} \val{ 0: @@ -353,39 +352,77 @@ def write_attribute_type_rule(self, attribute, lo=None): @staticmethod # write core attribute rule def write_core_attribute_rule(self, lo_child=None): - if lo_child is None: - text = '{0} {1} object may have the optional SBML Level~3 ' \ - 'Core attributes {2} and {3}. No other attributes from the ' \ - 'SBML Level~3 Core namespaces are permitted on {4} {1}.'\ - .format(self.indef_u, self.formatted_name, - strFunctions.wrap_token('metaid'), - strFunctions.wrap_token('sboTerm'), self.indef) - ref = 'SBML Level~3 Version~1 Core, Section~3.2.' - sev = 'ERROR' - lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) - tc = '{0}{1}AllowedCoreAttributes'.format(self.up_package, - self.name) - short = 'Core attributes allowed on <{0}>.'.format(self.lower_name) - lo = False + if global_variables.is_sbml: + if lo_child is None: + text = '{0} {1} object may have the optional SBML Level~3 ' \ + 'Core attributes {2} and {3}. No other attributes from the ' \ + 'SBML Level~3 Core namespaces are permitted on {4} {1}.'\ + .format(self.indef_u, self.formatted_name, + strFunctions.wrap_token('metaid'), + strFunctions.wrap_token('sboTerm'), self.indef) + ref = 'SBML Level~3 Version~1 Core, Section~3.2.' + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}AllowedCoreAttributes'.format(self.up_package, + self.name) + short = 'Core attributes allowed on <{0}>.'.format(self.lower_name) + lo = False + else: + loname = strFunctions.get_tex_element_name(lo_child, leave_pkg_prefix=False) + temp = strFunctions.remove_prefix(lo_child['element']) + lo_name = loname[7:] #strFunctions.plural(temp) + text = 'A {0} object may have the optional SBML Level~3 ' \ + 'Core attributes {1} and {2}. No other attributes from the ' \ + 'SBML Level~3 Core namespaces are permitted on a {0} object.'\ + .format(strFunctions.get_tex_element_name(lo_child, False), + strFunctions.wrap_token('metaid'), + strFunctions.wrap_token('sboTerm')) + sec_name = 'listof' + lo_name.lower() + ref = '{0}, {1}.'\ + .format(self.pkg_ref, strFunctions.wrap_section(sec_name)) + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}LO{2}AllowedCoreAttributes'.format(self.up_package, + self.name, lo_name) + lo = True + short = 'Core attributes allowed on .'.format(lo_name) else: - loname = strFunctions.get_tex_element_name(lo_child, leave_pkg_prefix=False) - temp = strFunctions.remove_prefix(lo_child['element']) - lo_name = loname[7:] #strFunctions.plural(temp) - text = 'A {0} object may have the optional SBML Level~3 ' \ - 'Core attributes {1} and {2}. No other attributes from the ' \ - 'SBML Level~3 Core namespaces are permitted on a {0} object.'\ - .format(strFunctions.get_tex_element_name(lo_child, False), - strFunctions.wrap_token('metaid'), - strFunctions.wrap_token('sboTerm')) - sec_name = 'listof' + lo_name.lower() - ref = '{0}, {1}.'\ - .format(self.pkg_ref, strFunctions.wrap_section(sec_name)) - sev = 'ERROR' - lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) - tc = '{0}{1}LO{2}AllowedCoreAttributes'.format(self.up_package, - self.name, lo_name) - lo = True - short = 'Core attributes allowed on .'.format(lo_name) + if lo_child is None: + text = '{0} {1} object may have the optional SBML Level~3 ' \ + 'Core attributes {2} and {3}. No other attributes from the ' \ + 'SBML Level~3 Core namespaces are permitted on {4} {1}.'\ + .format(self.indef_u, self.formatted_name, + strFunctions.wrap_token('metaid'), + strFunctions.wrap_token('sboTerm'), self.indef) + ref = 'SBML Level~3 Version~1 Core, Section~3.2.' + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}AllowedCoreAttributes'.format(self.up_package, + self.name) + short = 'Core attributes allowed on <{0}>.'.format(self.lower_name) + lo = False + else: + loname = strFunctions.get_tex_element_name(lo_child, leave_pkg_prefix=False) + temp = strFunctions.remove_prefix(lo_child['element']) + lo_name = loname[7:] #strFunctions.plural(temp) + text = 'A {0} object may have the optional attribute {1}. No other attributes from the ' \ + '{2} Level~{3} Version~{4} namespaces are permitted on a {0} object.'\ + .format(strFunctions.get_tex_element_name(lo_child, False), + strFunctions.wrap_token('metaid'), + global_variables.language.upper(), + global_variables.namespaces[0]['level'], + global_variables.namespaces[0]['version'] + ) + sec_name = 'listof' + lo_name.lower() + ref = '{0}, {1}.'\ + .format(self.pkg_ref, strFunctions.wrap_section(sec_name)) + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}LO{2}AllowedCoreAttributes'.format(self.up_package, + self.name, lo_name) + lo = True + short = 'Core attributes allowed on .'.format(lo_name) + lib_ref = 'L3V1 {0} V1 Section'.format(self.up_package) return dict({'number': self.number, 'text': text, 'reference': ref, 'severity': sev, 'typecode': tc, @@ -396,36 +433,68 @@ def write_core_attribute_rule(self, lo_child=None): # write core subobjects rule @staticmethod def write_core_subobject_rule(self, lo_child=None): - if lo_child is None: - text = '{0} {1} object may have the optional SBML Level~3 ' \ - 'Core subobjects for notes and annotations. No other ' \ - 'elements from the SBML Level~3 Core namespaces are ' \ - 'permitted on {2} {1}.'\ - .format(self.indef_u, self.formatted_name, self.indef) - ref = 'SBML Level~3 Version~1 Core, Section~3.2.' - sev = 'ERROR' - lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) - tc = '{0}{1}AllowedCoreElements'.format(self.up_package, self.name) - short = 'Core elements allowed on <{0}>.'.format(self.lower_name) - lo = False + if global_variables.is_sbml: + if lo_child is None: + text = '{0} {1} object may have the optional SBML Level~3 ' \ + 'Core subobjects for notes and annotations. No other ' \ + 'elements from the SBML Level~3 Core namespaces are ' \ + 'permitted on {2} {1}.'\ + .format(self.indef_u, self.formatted_name, self.indef) + ref = 'SBML Level~3 Version~1 Core, Section~3.2.' + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}AllowedCoreElements'.format(self.up_package, self.name) + short = 'Core elements allowed on <{0}>.'.format(self.lower_name) + lo = False + else: + loname = strFunctions.get_tex_element_name(lo_child, leave_pkg_prefix=False) + temp = strFunctions.remove_prefix(lo_child['element']) + lo_name = loname[7:] #strFunctions.plural(temp) + text = r'Apart from the general notes and annotations subobjects ' \ + r'permitted on all SBML objects, a {0} container object ' \ + r'may only contain \{1} objects.'\ + .format(loname, temp) + sec_name = 'listof' + lo_name.lower() + ref = '{0}, {1}.'\ + .format(self.pkg_ref, strFunctions.wrap_section(sec_name)) + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}LO{2}AllowedCoreElements'.format(self.up_package, self.name, + lo_name) + lo = True + short = 'Core elements allowed on .'.format(lo_name) + lib_ref = 'L3V1 {0} V1 Section'.format(self.up_package) else: - loname = strFunctions.get_tex_element_name(lo_child, leave_pkg_prefix=False) - temp = strFunctions.remove_prefix(lo_child['element']) - lo_name = loname[7:] #strFunctions.plural(temp) - text = r'Apart from the general notes and annotations subobjects ' \ - r'permitted on all SBML objects, a {0} container object ' \ - r'may only contain \{1} objects.'\ - .format(loname, temp) - sec_name = 'listof' + lo_name.lower() - ref = '{0}, {1}.'\ - .format(self.pkg_ref, strFunctions.wrap_section(sec_name)) - sev = 'ERROR' - lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) - tc = '{0}{1}LO{2}AllowedCoreElements'.format(self.up_package, self.name, - lo_name) - lo = True - short = 'Core elements allowed on .'.format(lo_name) - lib_ref = 'L3V1 {0} V1 Section'.format(self.up_package) + if lo_child is None: + text = '{0} {1} object may have the optional SBML Level~3 ' \ + 'Core subobjects for notes and annotations. No other ' \ + 'elements from the SBML Level~3 Core namespaces are ' \ + 'permitted on {2} {1}.'\ + .format(self.indef_u, self.formatted_name, self.indef) + ref = 'SBML Level~3 Version~1 Core, Section~3.2.' + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}AllowedCoreElements'.format(self.up_package, self.name) + short = 'Core elements allowed on <{0}>.'.format(self.lower_name) + lo = False + else: + child = strFunctions.remove_prefix(lo_child['element']) + loname = strFunctions.list_of_name(child, False) + text = r'Apart from the general \notes and \{2} subobjects ' \ + r'permitted on all {3} objects, a \{0} container object ' \ + r'may only contain \{1} objects.' \ + .format(loname, child, global_variables.annot_element, + global_variables.language.upper()) + sec_name = loname.lower() + ref = '{0}, {1}.' \ + .format(self.pkg_ref, strFunctions.wrap_section(sec_name)) + sev = 'ERROR' + lib_sev = '{0}_SEV_ERROR'.format(global_variables.up_full_lib) + tc = '{0}{1}LO{2}AllowedCoreElements'.format(self.up_package, self.name, child) + lo = True + short = 'Core elements allowed on .'.format(child) + lib_ref = 'L3V1 {0} V1 Section'.format(self.up_package) + return dict({'number': self.number, 'text': text, 'reference': ref, 'severity': sev, 'typecode': tc, 'lib_sev': lib_sev, 'short': short, 'lib_ref': lib_ref, From 906baabbfb22480115092c1c7933af58566a957e Mon Sep 17 00:00:00 2001 From: Sarah Date: Sat, 24 Jun 2023 10:06:59 +0100 Subject: [PATCH 12/12] put back tests --- deviser/pytest_files/test_tex/test_tex.py | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/deviser/pytest_files/test_tex/test_tex.py b/deviser/pytest_files/test_tex/test_tex.py index 7ec2b64e..27b6cb80 100644 --- a/deviser/pytest_files/test_tex/test_tex.py +++ b/deviser/pytest_files/test_tex/test_tex.py @@ -31,19 +31,19 @@ def teardown(): @pytest.mark.parametrize("name, test_type", [ - # ('spatial', 'body'), - # ('qual', 'apdx-validation'), - # ('groups', 'macros'), - # ('groups', 'apdx-validation'), - # ('groups', 'body'), - # ('unknown_type', 'apdx-validation'), - # ('test_sidrefs', 'apdx-validation'), - # ('test_sidrefs', 'body'), - # ('test_lists', 'apdx-validation'), - # ('test_lists', 'body'), - # ('test_att', 'apdx-validation'), - # ('testsbxml', 'apdx-validation'), - ('testsbxml', 'macros'), + ('spatial', 'body'), + ('qual', 'apdx-validation'), + ('groups', 'macros'), + ('groups', 'apdx-validation'), + ('groups', 'body'), + ('unknown_type', 'apdx-validation'), + ('test_sidrefs', 'apdx-validation'), + ('test_sidrefs', 'body'), + ('test_lists', 'apdx-validation'), + ('test_lists', 'body'), + ('test_att', 'apdx-validation'), + ('testsbxml', 'apdx-validation'), + # ('testsbxml', 'macros'), ]) def test_tex(name, test_type): assert rtt.run_test(name, test_type) == 0