Skip to content
This repository has been archived by the owner on Dec 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #51 from JR-1991/include-xmlns
Browse files Browse the repository at this point in the history
Include XML namespaces
  • Loading branch information
JR-1991 authored Feb 22, 2024
2 parents 6302560 + 721ed3d commit d4a3667
Show file tree
Hide file tree
Showing 10 changed files with 449 additions and 376 deletions.
706 changes: 352 additions & 354 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ packages = [{include = "sdRDM"}]

[tool.poetry.dependencies]
python = "^3.9"
pydantic = "2.5.3"
pydantic-xml = "^2.7.0"
pydantic = "^2.6.0"
pydantic-xml = "^2.9.0"
numpy = "^1.26.3"
pandas = "^2.1.4"
jinja2 = "^3.1.3"
Expand All @@ -30,6 +30,7 @@ astropy = "^6.0.0"
markdown-it-py = "^3.0.0"
rich = "^13.7.0"
lxml = "^5.1.0"
python-frontmatter = "^1.1.0"

[tool.poetry.group.dev.dependencies]
coverage = "^7.4.0"
Expand Down
6 changes: 6 additions & 0 deletions sdRDM/generator/classrender.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def render_object(
objects: List[Dict],
enums: List[Dict],
inherits: List[Dict],
namespaces: Dict,
repo: Optional[str] = None,
commit: Optional[str] = None,
small_types: Dict = {},
Expand All @@ -31,6 +32,7 @@ def render_object(
objects=all_objects,
repo=repo,
commit=commit,
namespaces=namespaces,
)
for subtype in small_types.values()
if subtype["origin"] == object["name"]
Expand All @@ -46,6 +48,7 @@ def render_object(
objects=all_objects,
repo=repo,
commit=commit,
namespaces=namespaces,
)

methods_part = render_add_methods(
Expand Down Expand Up @@ -84,6 +87,7 @@ def render_class(
object: Dict,
inherits: List[Dict],
objects: List[Dict],
namespaces: Dict,
repo: Optional[str] = None,
commit: Optional[str] = None,
) -> str:
Expand All @@ -101,6 +105,7 @@ def render_class(
if filtered and len(filtered) == 1:
inherit = filtered[0]["parent"]


return template.render(
name=name,
inherit=inherit,
Expand All @@ -115,6 +120,7 @@ def render_class(
],
repo=repo,
commit=commit,
namespaces=namespaces,
)


Expand Down
31 changes: 17 additions & 14 deletions sdRDM/generator/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ def generate_api_from_parser(

# Write classes to the directory
write_classes(
libpath,
parser.objects,
parser.enums,
parser.inherits,
use_formatter,
url,
commit,
libpath=libpath,
objects=parser.objects,
enums=parser.enums,
inherits=parser.inherits,
use_formatter=use_formatter,
repo=url,
commit=commit,
namespaces=parser.namespaces,
)

# Write init files
Expand Down Expand Up @@ -108,6 +109,7 @@ def write_classes(
enums: List[Dict],
inherits: List[Dict],
use_formatter: bool,
namespaces: Dict,
repo: Optional[str] = None,
commit: Optional[str] = None,
) -> None:
Expand All @@ -122,13 +124,14 @@ def write_classes(

for object in objects:
rendered = render_object(
object,
objects,
enums,
inherits,
repo,
commit,
small_types,
object=object,
objects=objects,
enums=enums,
inherits=inherits,
repo=repo,
commit=commit,
small_types=small_types,
namespaces=namespaces,
)
path = os.path.join(libpath, "core", f"{object['name'].lower()}.py")
save_rendered_to_file(rendered, path, use_formatter)
Expand Down
10 changes: 9 additions & 1 deletion sdRDM/generator/templates/class_template.jinja2
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
@forge_signature
class {{name}}({% if inherit is not none %}
{{inherit}}
{% else %}sdRDM.DataModel{% endif %}, {% if repo %}nsmap={"": "{{ repo }}@{{ commit }}#{{ name }}"},{% endif %}):
{% else %}sdRDM.DataModel{% endif %},
{% if namespaces %}
nsmap = {
{% for key, value in namespaces.items() %}
"{{key}}": "{{value}}",
{% endfor %}
},
{% endif %}
):


{% if docstring is not none %}"""{{ docstring }}"""{% endif %}
Expand Down
37 changes: 36 additions & 1 deletion sdRDM/markdown/markdownparser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from io import StringIO
import re

import frontmatter
from typing import List, Tuple, Dict, IO
from markdown_it import MarkdownIt
from markdown_it.token import Token
Expand All @@ -17,14 +19,17 @@ class MarkdownParser(BaseModel):
inherits: List = []
compositions: List = []
external_objects: Dict = {}
namespaces: Dict = {}

@classmethod
def parse(cls, handle: IO):
"""Parses a given markdown file to a mermaid schema from which code is generated."""

parser = cls()

doc = MarkdownIt().parse(cls.clean_html_tags(handle.readlines()))
content = parser.clean_html_tags(handle.readlines())
doc = MarkdownIt().parse(parser._remove_header(content))
parser.namespaces = parser._extract_namespaces(content)
modules, enumerations = parser.get_objects_and_enumerations(doc)

for module, model in modules.items():
Expand Down Expand Up @@ -62,6 +67,36 @@ def add_model(self, parser: "MarkdownParser"):
self.compositions += parser.compositions
self.external_objects.update(parser.external_objects)

@staticmethod
def _extract_namespaces(content: str):
"""Extracts all namespaces from the model.
Args:
content (str): The content of the model.
Returns:
dict: A dictionary containing the extracted namespaces.
"""

doc = frontmatter.load(StringIO(content))
return doc.get("xmlns", {})

@staticmethod
def _remove_header(text: str):
"""
Removes the header from the given text.
Args:
text (str): The text containing the header.
Returns:
str: The text with the header removed.
"""
header = re.search(r"^---\n.*?\n---\n", text, re.DOTALL)
if header:
text = text.replace(header.group(), "")
return text.strip()

def _has_duplicate_object_names(self, parser):
"""Checks whether there are redundancies within the model"""

Expand Down
17 changes: 16 additions & 1 deletion tests/end2end/test_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


@pytest.mark.e2e
def test_dataset_creation(model_all, model_all_dataset):
def test_dataset_creation(model_all):
"""Tests whether the data that is passed to the model is correctly parsed"""

expected = {
Expand Down Expand Up @@ -70,3 +70,18 @@ def test_dataset_creation(model_all, model_all_dataset):
assert (
dataset.to_dict(mode="python") == expected
), "Dataset does not match expected values"


@pytest.mark.e2e
def test_ns_map(model_all):
"""Tests whether the namespace map is correctly extracted from the model"""

expected = {
"": "http://www.example.com/ns0",
"math": "http://www.example.com/math",
"chem": "http://www.example.com/chem",
}

assert (
model_all.Root.__xml_nsmap__ == expected
), "Namespace map does not match expected values"
2 changes: 1 addition & 1 deletion tests/end2end/test_serialisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ def test_xml_serialisation(model_all_dataset):
expected = open("tests/fixtures/static/model_all_expected.xml").read()
given = model_all_dataset.xml()

assert given == expected, "YAML serialisation does not match"
assert given.strip() == expected.strip(), "XML serialisation does not match"
7 changes: 7 additions & 0 deletions tests/fixtures/static/model_all.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
---
xmlns:
"": "http://www.example.com/ns0"
"math": "http://www.example.com/math"
"chem": "http://www.example.com/chem"
---

# Test

This model tests all methods and types that are present within the sdRDM library.
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/static/model_all_expected.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<Root id="id">
<Root xmlns="http://www.example.com/ns0" xmlns:math="http://www.example.com/math" xmlns:chem="http://www.example.com/chem" id="id">
<str_value>string</str_value>
<float_value>1.5</float_value>
<int_value>1</int_value>
Expand Down Expand Up @@ -27,4 +27,4 @@
<int_value>1</int_value>
</nested>
</nested_multiple_obj>
</Root>
</Root>

0 comments on commit d4a3667

Please sign in to comment.