Skip to content

feat: Add support for embedded images #464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion capellambse/extensions/pvmt/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def __init__(self, attribute: str) -> None:
super().__init__(attribute, default=SelectorRules(""), writable=True)
self.__doc__ = "The element selector rules for this group."

def _from_xml(self, data: str, /) -> SelectorRules:
def _from_xml(
self, data: str, model: capellambse.MelodyModel, /
) -> SelectorRules:
del model
return SelectorRules(data)

def _to_xml(self, value: SelectorRules | str, /) -> str:
Expand Down
56 changes: 46 additions & 10 deletions capellambse/model/_pods.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@

import markupsafe
import typing_extensions as te
from lxml import etree

import capellambse
from capellambse import helpers

from . import E, U
Expand Down Expand Up @@ -77,7 +79,7 @@ def __get__(self, obj, objtype=None):
assert data is None or isinstance(data, str)
if data is None:
return self.default
return self._from_xml(data)
return self._from_xml(data, obj._model)

def __set__(self, obj: t.Any, value: U | None) -> None:
if not self.writable and self.attribute in obj._element.attrib:
Expand All @@ -101,7 +103,9 @@ def __set_name__(self, owner: type[t.Any], name: str) -> None:
self.__objclass__ = owner

@abc.abstractmethod
def _from_xml(self, value: str, /) -> U: ...
def _from_xml(
self, value: str, model: capellambse.MelodyModel, /
) -> U: ...
Comment on lines +106 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor thing: Please change the order to be self, model, value instead of self, value, model, for more consistency overall. (Almost) All functions that require a model expect it as first non-self argument.

It's an API break anyways, as old methods only expect a single argument.

@abc.abstractmethod
def _to_xml(self, value: U, /) -> str | None: ...

Expand All @@ -123,7 +127,8 @@ def __init__(self, attribute: str, /, *, writable: bool = True) -> None:
"""
super().__init__(attribute, default="", writable=writable)

def _from_xml(self, value: str, /) -> str:
def _from_xml(self, value: str, model: capellambse.MelodyModel, /) -> str:
del model
return value

def _to_xml(self, value: str, /) -> str:
Expand Down Expand Up @@ -151,14 +156,38 @@ def __init__(self, attribute: str, /, *, writable: bool = True) -> None:
writable=writable,
)

def _from_xml(self, value: str, /) -> markupsafe.Markup:
def _from_xml(
self,
value: str,
model: capellambse.MelodyModel,
/,
) -> markupsafe.Markup:
if os.getenv("CAPELLAMBSE_XHTML") == "1":
value = helpers.repair_html(value)
return markupsafe.Markup(value)

return self._resolve_embedded_images(value, model)

def _to_xml(self, value: markupsafe.Markup, /) -> str:
return helpers.repair_html(value)

def _resolve_embedded_images(
self, value: str, model: capellambse.MelodyModel, /
) -> markupsafe.Markup:
Comment on lines +173 to +175
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please use self, model, value.

"""Resolve embedded images in HTML markup.

Embedded images in Capella use the project name as prefix. Since
the project name is not part of the real file system path, we
remove the prefix from the image source attribute.
"""

def cb(node: etree._Element) -> None:
if node.tag == "img" and model.info.title:
node.attrib["src"] = node.attrib["src"].removeprefix(
model.info.title + "/"
)

return helpers.process_html_fragments(value, cb)


class BoolPOD(BasePOD[bool]):
"""A POD containing a boolean."""
Expand All @@ -175,7 +204,8 @@ def __init__(self, attribute: str, /) -> None:
"""
super().__init__(attribute, default=False, writable=True)

def _from_xml(self, value: str, /) -> bool:
def _from_xml(self, value: str, model: capellambse.MelodyModel, /) -> bool:
del model
return value == "true"

def _to_xml(self, value: bool, /) -> str:
Expand All @@ -200,7 +230,8 @@ def __init__(self, attribute: str, /, *, writable: bool = True) -> None:
"""
super().__init__(attribute, default=0, writable=writable)

def _from_xml(self, data: str, /) -> int:
def _from_xml(self, data: str, model: capellambse.MelodyModel, /) -> int:
del model
return int(data)

def _to_xml(self, value: int, /) -> str | None:
Expand Down Expand Up @@ -232,7 +263,8 @@ def __init__(self, attribute: str, /, *, writable: bool = True) -> None:
"""
super().__init__(attribute, default=0.0, writable=writable)

def _from_xml(self, data: str, /) -> float:
def _from_xml(self, data: str, model: capellambse.MelodyModel, /) -> float:
del model
return float(data)

def _to_xml(self, value: float, /) -> str | None:
Expand Down Expand Up @@ -278,7 +310,10 @@ def __init__(self, attribute: str, /, *, writable: bool = True) -> None:
"""
super().__init__(attribute, default=None, writable=writable)

def _from_xml(self, value: str, /) -> datetime.datetime:
def _from_xml(
self, value: str, model: capellambse.MelodyModel, /
) -> datetime.datetime:
del model
formatted = self.re_get.sub(":", value)
return datetime.datetime.fromisoformat(formatted)

Expand Down Expand Up @@ -360,7 +395,8 @@ def __init__(
super().__init__(attribute, default=default, writable=writable)
self.enumcls = enumcls

def _from_xml(self, value: str, /) -> E:
def _from_xml(self, value: str, model: capellambse.MelodyModel, /) -> E:
del model
return self.enumcls(value)

def _to_xml(self, value: E | str, /) -> str | None:
Expand Down
Loading