Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-nbxmpp for openSUSE:Factory checked in at 2026-02-27 17:12:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-nbxmpp (Old) and /work/SRC/openSUSE:Factory/.python-nbxmpp.new.29461 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-nbxmpp" Fri Feb 27 17:12:32 2026 rev:57 rq:1335420 version:7.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-nbxmpp/python-nbxmpp.changes 2026-02-18 17:12:28.543324728 +0100 +++ /work/SRC/openSUSE:Factory/.python-nbxmpp.new.29461/python-nbxmpp.changes 2026-02-27 17:13:42.213549191 +0100 @@ -1,0 +2,9 @@ +Thu Feb 26 17:51:38 UTC 2026 - Alexei Sorokin <[email protected]> + +- Update to version 7.1.0: + * SASL: Improve logging for GSSAPI errors. + * Fallback: Be more strict in accepting ranges. + * Add Node.topretty(). + * OGP: Accept only data uris as image. + +------------------------------------------------------------------- Old: ---- python-nbxmpp-7.0.0.tar.bz2 New: ---- python-nbxmpp-7.1.0.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-nbxmpp.spec ++++++ --- /var/tmp/diff_new_pack.ZbXUpg/_old 2026-02-27 17:13:42.733570713 +0100 +++ /var/tmp/diff_new_pack.ZbXUpg/_new 2026-02-27 17:13:42.737570879 +0100 @@ -19,7 +19,7 @@ %define _name nbxmpp %{?sle15_python_module_pythons} Name: python-nbxmpp -Version: 7.0.0 +Version: 7.1.0 Release: 0 Summary: XMPP library by Gajim team License: GPL-3.0-or-later ++++++ python-nbxmpp-7.0.0.tar.bz2 -> python-nbxmpp-7.1.0.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/.gitignore new/python-nbxmpp-7.1.0/.gitignore --- old/python-nbxmpp-7.0.0/.gitignore 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/.gitignore 2026-02-25 20:15:32.000000000 +0100 @@ -9,3 +9,4 @@ *~ *.sublime-workspace *.sublime-project +uv.lock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/.gitlab-ci.yml new/python-nbxmpp-7.1.0/.gitlab-ci.yml --- old/python-nbxmpp-7.0.0/.gitlab-ci.yml 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/.gitlab-ci.yml 2026-02-25 20:15:32.000000000 +0100 @@ -38,7 +38,7 @@ rules: - when: always script: - - pip install git+https://github.com/pygobject/pygobject-stubs.git + - pip install pygobject-stubs==2.16.0 - pyright --version - pyright interruptible: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/.pre-commit-config.yaml new/python-nbxmpp-7.1.0/.pre-commit-config.yaml --- old/python-nbxmpp-7.0.0/.pre-commit-config.yaml 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/.pre-commit-config.yaml 2026-02-25 20:15:32.000000000 +0100 @@ -1,12 +1,12 @@ repos: - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.9.7 + rev: v0.14.8 hooks: - id: ruff exclude: ".githooks/" - repo: https://github.com/pycqa/isort - rev: 5.13.2 + rev: 7.0.0 hooks: - id: isort diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/ChangeLog new/python-nbxmpp-7.1.0/ChangeLog --- old/python-nbxmpp-7.0.0/ChangeLog 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/ChangeLog 2026-02-25 20:15:32.000000000 +0100 @@ -1,3 +1,15 @@ +nbxmpp 7.1.0 (22 Feb 2026) + + Improvements + + * SASL: Improve logging for GSSAPI errors + * Fallback: Be more strict in accepting ranges + * Add Node.topretty() + + Change + + * OGP: Accept only data uris as image + nbxmpp 7.0.0 (13 Dec 2025) Change diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/__init__.py new/python-nbxmpp-7.1.0/nbxmpp/__init__.py --- old/python-nbxmpp-7.0.0/nbxmpp/__init__.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/__init__.py 2026-02-25 20:15:32.000000000 +0100 @@ -4,4 +4,4 @@ from .protocol import * # noqa: F403, E402 -__version__: str = "7.0.0" +__version__: str = "7.1.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/modules/fallback.py new/python-nbxmpp-7.1.0/nbxmpp/modules/fallback.py --- old/python-nbxmpp-7.0.0/nbxmpp/modules/fallback.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/modules/fallback.py 2026-02-25 20:15:32.000000000 +0100 @@ -22,8 +22,10 @@ def parse_fallback_indication( - log: logging.Logger | logging.LoggerAdapter[Any], stanza: Message + log: logging.Logger | logging.LoggerAdapter[Any], + stanza: Message, ) -> FallbacksForT | None: + fallbacks = stanza.getTags( "fallback", namespace=Namespace.FALLBACK, @@ -36,10 +38,11 @@ for_ = fallback.getAttr("for") if not for_: log.warning('Missing "for" attribute on fallback indication') - continue + return bodies = fallback.getTags("body") if not bodies: + # No <body> means fallback is for all bodies fallbacks_for[for_] = None continue @@ -51,7 +54,7 @@ if type(start) is not type(end): log.warning("Incorrect range on fallback indication") - continue + return range_ = None if start is not None: @@ -60,7 +63,11 @@ range_ = FallbackRange(start=int(start), end=int(end)) except Exception: log.warning("Incorrect range on fallback indication") - continue + return + + if range_.start < 0 or range_.end < 0: + log.warning("Fallback range with negative numbers: %s", range_) + return fallback_lang_map[lang] = range_ @@ -102,6 +109,10 @@ # No range means the whole body is considered a fallback return "" + if range_.end > len(text): + # Abort processing, because range is invalid + return text + fallbacks.append(range_) if not fallbacks: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/modules/message.py new/python-nbxmpp-7.1.0/nbxmpp/modules/message.py --- old/python-nbxmpp-7.0.0/nbxmpp/modules/message.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/modules/message.py 2026-02-25 20:15:32.000000000 +0100 @@ -95,7 +95,7 @@ def _process_message_after_base( self, _client: Client, stanza: Message, properties: MessageProperties ) -> None: - # This handler runs after decryption handlers had the chance + # This handler runs after decryption, when handlers had the chance # to decrypt the body fallbacks_for = parse_fallback_indication(self._log, stanza) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/modules/ogp.py new/python-nbxmpp-7.1.0/nbxmpp/modules/ogp.py --- old/python-nbxmpp-7.0.0/nbxmpp/modules/ogp.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/modules/ogp.py 2026-02-25 20:15:32.000000000 +0100 @@ -51,7 +51,15 @@ data = OpenGraphData() for field in fields(OpenGraphData): tag = field.name - node = description.getTag(tag, namespace=Namespace.OPEN_GRAPH) - if node is not None: - setattr(data, tag, node.getData()) + if tag == "image": + for node in description.getTags(tag, namespace=Namespace.OPEN_GRAPH): + node_data = node.getData() + if node_data.startswith("data:image"): + setattr(data, tag, node_data) + break + + else: + if node := description.getTag(tag, namespace=Namespace.OPEN_GRAPH): + setattr(data, tag, node.getData()) + return data diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/protocol.py new/python-nbxmpp-7.1.0/nbxmpp/protocol.py --- old/python-nbxmpp-7.0.0/nbxmpp/protocol.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/protocol.py 2026-02-25 20:15:32.000000000 +0100 @@ -1273,7 +1273,7 @@ to: str | None = None, body: str | None = None, xhtml: str | None = None, - typ: Literal["chat"] | Literal["groupchat"] | Literal["error"] | None = None, + typ: Literal["chat", "groupchat", "normal", "headline", "error"] | None = None, subject: MucSubject | None = None, attrs: dict[str, Any] | None = None, frm: JID | str | None = None, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/sasl.py new/python-nbxmpp-7.1.0/nbxmpp/sasl.py --- old/python-nbxmpp-7.0.0/nbxmpp/sasl.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/sasl.py 2026-02-25 20:15:32.000000000 +0100 @@ -7,7 +7,6 @@ from __future__ import annotations from typing import Any -from typing import Optional from typing import TYPE_CHECKING import binascii @@ -39,12 +38,11 @@ try: gssapi = __import__("gssapi") - gssapi_available = True + gssapi_error = None except (ImportError, OSError) as error: - log.info("GSSAPI not available: %s", error) - gssapi_available = False + gssapi_error = error -GSSAPI_AVAILABLE = gssapi_available +GSSAPI_ERROR = gssapi_error class SASL: @@ -106,7 +104,7 @@ def _get_channel_binding_data( self, features: Features - ) -> Optional[ChannelBindingData]: + ) -> ChannelBindingData | None: if self._client.tls_version != Gio.TlsProtocolVersion.TLS_1_3: return None @@ -143,7 +141,8 @@ self._enabled_mechs.discard("SCRAM-SHA-256-PLUS") self._enabled_mechs.discard("SCRAM-SHA-512-PLUS") - if not GSSAPI_AVAILABLE: + if GSSAPI_ERROR is not None: + log.debug("Discard GSSAPI because of error: %s", GSSAPI_ERROR) self._enabled_mechs.discard("GSSAPI") feature_mechs = features.get_mechs() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/simplexml.py new/python-nbxmpp-7.1.0/nbxmpp/simplexml.py --- old/python-nbxmpp-7.0.0/nbxmpp/simplexml.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/simplexml.py 2026-02-25 20:15:32.000000000 +0100 @@ -136,7 +136,7 @@ self.nsd[""] = val elif attr.startswith("xmlns:"): self.nsd[attr[6:]] = val - self.attrs[attr] = attrs[attr] + self.attrs[attr] = val if tag: if node_built: @@ -168,50 +168,71 @@ return "http://www.gajim.org/xmlns/undeclared" return ns - def __str__(self, fancy: int = 0) -> str: + def topretty( + self, + indent: str = "", + addindent: str = " " * 2, + newl: str = "\n", + ) -> str: """ - Method used to dump node into textual representation. If "fancy" - argument is set to True produces indented output for readability + Write an XML element to a string + + string = buffer where output is added + indent = current indentation + addindent = indentation to add to higher levels + newl = newline string """ - s = (fancy - 1) * 2 * " " + "<" + self.name + + string = indent + "<" + self.name + if self.namespace: if not self.parent or self.parent.namespace != self.namespace: if "xmlns" not in self.attrs: - s += ' xmlns="%s"' % self.namespace + string += f' xmlns="{self.namespace}"' + for key in self.attrs: val = str(self.attrs[key]) - s += ' %s="%s"' % (key, XMLescape(val)) + string += f' {key}="{XMLescape(val)}"' - s += ">" - cnt = 0 + count = 0 if self.kids: - if fancy: - s += "\n" - for a in self.kids: - if not fancy and (len(self.data) - 1) >= cnt: - s += XMLescape(self.data[cnt]) - elif (len(self.data) - 1) >= cnt: - s += XMLescape(self.data[cnt].strip()) - if isinstance(a, str): - s += a.__str__() + string += ">" + string += newl + for child in self.kids: + if (len(self.data) - 1) >= count: + data = XMLescape(self.data[count].strip()) + if data: + string += f"{indent + addindent}{XMLescape(self.data[count].strip())}{newl}" + + if isinstance(child, str): + string += child else: - s += a.__str__(fancy and fancy + 1) - cnt += 1 - if not fancy and (len(self.data) - 1) >= cnt: - s += XMLescape(self.data[cnt]) - elif (len(self.data) - 1) >= cnt: - s += XMLescape(self.data[cnt].strip()) - if not self.kids and s.endswith(">"): - s = s[:-1] + " />" - if fancy: - s += "\n" + string += child.topretty(indent + addindent, addindent, newl) + string += newl + + count += 1 + + string += indent + + if (len(self.data) - 1) >= count: + data = XMLescape(self.data[count].strip()) + if data: + string += f"{indent + addindent}{XMLescape(self.data[count].strip())}{newl}" + + string += f"</{self.name}>" + + elif self.data: + string += f">{XMLescape(self.data[0])}</{self.name}>" + else: - if fancy and not self.data: - s += (fancy - 1) * 2 * " " - s += "</" + self.name + ">" - if fancy: - s += "\n" - return s + string += " />" + + return string + + def __str__(self, fancy: int = 0) -> str: + if fancy: + return self.topretty() + return self.topretty(indent="", addindent="", newl="") def addChild( self, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/structs.py new/python-nbxmpp-7.1.0/nbxmpp/structs.py --- old/python-nbxmpp-7.0.0/nbxmpp/structs.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/structs.py 2026-02-25 20:15:32.000000000 +0100 @@ -9,7 +9,6 @@ import typing from typing import Any from typing import NamedTuple -from typing import Optional from typing import TYPE_CHECKING import logging @@ -134,7 +133,7 @@ class MucConfigResult(NamedTuple): jid: JID - form: Optional[Any] = None + form: Any | None = None class MucSubject(NamedTuple): @@ -170,7 +169,7 @@ node: str id: str | None = None item: Node | None = None - data: Optional[Any] = None + data: Any | None = None deleted: bool = False retracted: bool = False purged: bool = False @@ -331,8 +330,8 @@ class RegisterData(NamedTuple): instructions: str | None - form: Optional[Any] - fields_form: Optional[Any] + form: Any | None + fields_form: Any | None oob_url: str | None bob_data: BobData | None @@ -473,7 +472,7 @@ continue return False - def get_field_value(self, form_type: str, var: str) -> Optional[Any]: + def get_field_value(self, form_type: str, var: str) -> Any | None: for dataform in self.dataforms: try: if dataform["FORM_TYPE"].value != form_type: @@ -590,31 +589,31 @@ return None @property - def muc_room_name(self) -> Optional[Any]: + def muc_room_name(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roomconfig_roomname") @property - def muc_description(self) -> Optional[Any]: + def muc_description(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roominfo_description") @property - def muc_log_uri(self) -> Optional[Any]: + def muc_log_uri(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roominfo_logs") @property - def muc_users(self) -> Optional[Any]: + def muc_users(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roominfo_occupants") @property - def muc_contacts(self) -> Optional[Any]: + def muc_contacts(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roominfo_contactjid") @property - def muc_subject(self) -> Optional[Any]: + def muc_subject(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roominfo_subject") @property - def muc_subjectmod(self) -> Optional[Any]: + def muc_subjectmod(self) -> Any | None: # muc#roominfo_changesubject stems from a wrong example in the MUC XEP # Ejabberd and Prosody use this value # muc#roomconfig_changesubject is also used by Prosody @@ -625,7 +624,7 @@ ) @property - def muc_lang(self) -> Optional[Any]: + def muc_lang(self) -> Any | None: return self.get_field_value(Namespace.MUC_INFO, "muc#roominfo_lang") @property @@ -1287,7 +1286,7 @@ type: IqType | None = None jid: JID | None = None id: str | None = None - error: Optional[Any] = None + error: Any | None = None query: Node | None = None payload: Node | None = None http_auth: HTTPAuthData | None = None @@ -1317,7 +1316,7 @@ type: IqType jid: JID id: str - error: Optional[Any] + error: Any | None query: Node | None payload: Node | None @@ -1348,8 +1347,8 @@ timestamp: float = field(default_factory=time.time) user_timestamp: float | None = None idle_timestamp: float | None = None - signed: Optional[Any] = None - error: Optional[Any] = None + signed: Any | None = None + error: Any | None = None avatar_sha: str | None = None avatar_state: AvatarState = AvatarState.IGNORE muc_jid: JID | None = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/nbxmpp/task.py new/python-nbxmpp-7.1.0/nbxmpp/task.py --- old/python-nbxmpp-7.0.0/nbxmpp/task.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/nbxmpp/task.py 2026-02-25 20:15:32.000000000 +0100 @@ -7,7 +7,6 @@ from __future__ import annotations from typing import Any -from typing import Optional from typing import ParamSpec from typing import TYPE_CHECKING from typing import TypeVar @@ -140,7 +139,7 @@ self._sub_task: Task | None = None self._result = None self._error = None - self._user_data: Optional[Any] = None + self._user_data: Any | None = None self._timeout: int | None = None self._timeout_id: int | None = None self._finalize_func: Callable[..., Any] | None = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/pyproject.toml new/python-nbxmpp-7.1.0/pyproject.toml --- old/python-nbxmpp-7.0.0/pyproject.toml 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/pyproject.toml 2026-02-25 20:15:32.000000000 +0100 @@ -25,12 +25,14 @@ dynamic = ["version"] -[project.optional-dependencies] +[dependency-groups] gssapi = ["gssapi"] dev = [ "black==24.10.0", - "isort>=5.13.2", - "ruff>=0.9.7", + "isort>=7.0.0", + "pre-commit", + "pygobject-stubs@git+https://github.com/pygobject/pygobject-stubs.git", + "ruff==0.14.8", ] [project.urls] @@ -204,6 +206,7 @@ "PLR2004",# Magic value used in comparison, consider replacing x with a constant variable "PLR5501",# Consider using `elif` instead of `else` then `if` to remove one indentation level "PLW0603",# Using the global statement to update `x` is discouraged + "PLW1641",# Object does not implement `__hash__` method "PLW2901",# `for` loop variable `x` overwritten by assignment target "RUF001", # AmbiguousUnicodeCharacterString "RUF002", # AmbiguousUnicodeCharacterDocstring diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/test/unit/test_fallback.py new/python-nbxmpp-7.1.0/test/unit/test_fallback.py --- old/python-nbxmpp-7.0.0/test/unit/test_fallback.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/test/unit/test_fallback.py 2026-02-25 20:15:32.000000000 +0100 @@ -50,6 +50,20 @@ self.assertEqual(fallbacks_for, expected) + xml = """ + <message to='[email protected]' id='message-id2' type='groupchat'> + <body>> Anna wrote:\n> Hi, how are you?\nGreat</body> + <fallback xmlns='urn:xmpp:fallback:0' for='urn:xmpp:test:0'> + <body start='-1' end='33' /> + </fallback> + </message> + """ + + message = nbxmpp.Message(node=xml) + fallbacks_for = parse_fallback_indication(log, message) + + self.assertIsNone(fallbacks_for) + def test_strip_fallback(self): fallbacks_for: FallbacksForT = { "urn:xmpp:test:1": { @@ -97,6 +111,13 @@ ) self.assertEqual(stripped_text, "") + text = "> Short text" + + # One Range is bigger then the text, ignore fallback + stripped_text = strip_fallback(fallbacks_for, {"urn:xmpp:test:0"}, None, text) + + self.assertEqual(stripped_text, text) + def test_body_with_fallback(self): text = "> Anna wrote:\n> Hi, how are you?\nGreat" text_de = "> Anna schrieb\n>Hallo, wie geht es dir?\nGut" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/test/unit/test_node.py new/python-nbxmpp-7.1.0/test/unit/test_node.py --- old/python-nbxmpp-7.0.0/test/unit/test_node.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-nbxmpp-7.1.0/test/unit/test_node.py 2026-02-25 20:15:32.000000000 +0100 @@ -0,0 +1,69 @@ +import unittest + +from nbxmpp.simplexml import Node + + +class TestNode(unittest.TestCase): + + def test_topretty(self): + string = """<presence xmlns="jabber:client" xml:lang="en" to="[email protected]"> + <c xmlns="http://jabber.org/protocol/caps" ver="iVeWK58IHqW8e1wc9u4OGClblVo=" /> + <x xmlns="vcard-temp:x:update"> + <photo>bb055be7076edf87c9f89e4e0b829f0624aa1cef</photo> + </x> + <occupant-id xmlns="urn:xmpp:occupant-id:0" id="yAkJlge8v5CxmIAXT1m3jwuXLcRWidERkCGco9XN5z0=" /> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item affiliation="none" role="participant" /> + </x> + <priority>127</priority> +</presence>""" + + node = Node(node=string) + self.assertEqual(node.topretty(), string) + + string = """<a xmlns="http://www.gajim.org/xmlns/undeclared"> + abc + <b /> + <c /> + fgh +</a>""" + + node = Node(node=string) + self.assertEqual(node.topretty(), string) + + string = """<a xmlns="http://www.gajim.org/xmlns/undeclared"> + <b /> + abc + <c /> + fgh +</a>""" + + node = Node(node=string) + self.assertEqual(node.topretty(), string) + + string = """<a xmlns="http://www.gajim.org/xmlns/undeclared"> + <b /> + abc + <c>123</c> + fgh +</a>""" + + node = Node(node=string) + self.assertEqual(node.topretty(), string) + + string = """<a xmlns="http://www.gajim.org/xmlns/undeclared"> + <b> + <c> + <d /> + <e /> + <f /> + </c> + </b> +</a>""" + + node = Node(node=string) + self.assertEqual(node.topretty(), string) + + +if __name__ == "__main__": + unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-7.0.0/test/unit/test_ogp.py new/python-nbxmpp-7.1.0/test/unit/test_ogp.py --- old/python-nbxmpp-7.0.0/test/unit/test_ogp.py 2025-12-13 17:26:58.000000000 +0100 +++ new/python-nbxmpp-7.1.0/test/unit/test_ogp.py 2026-02-25 20:15:32.000000000 +0100 @@ -74,7 +74,7 @@ OpenGraphData( title="Page Title", url="Canonical URL", - image="https://link.to.example.com/image.png", + image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABDoAAAH", type="website", site_name="Some Website", description="Page Description", @@ -95,7 +95,9 @@ ogp = props["https://the.link.example.com/what-was-linked-to"] self.assertEqual(ogp.title, "Page Title") self.assertEqual(ogp.url, "Canonical URL") - self.assertEqual(ogp.image, "https://link.to.example.com/image.png") + self.assertEqual( + ogp.image, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABDoAAAH" + ) self.assertEqual(ogp.type, "website") self.assertEqual(ogp.site_name, "Some Website") self.assertEqual(ogp.description, "Page Description") @@ -111,7 +113,7 @@ <og:title>Page Title</og:title> <og:description>Page Description</og:description> <og:url>Canonical URL</og:url> - <og:image>https://link.to.example.com/image.png</og:image> + <og:image>data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABDoAAAH</og:image> <og:type>website</og:type> <og:site_name>Some Website</og:site_name> </rdf:Description>
