From patchwork Fri Sep 18 09:33:15 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Volk X-Patchwork-Id: 98671 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4AF4CC982D7 for ; Fri, 18 Sep 2026 09:33:27 +0000 (UTC) Received: from mailout08.t-online.de (mailout08.t-online.de [194.25.134.20]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.7232.1789724005293008657 for ; Fri, 18 Sep 2026 02:33:25 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=f_l_k@t-online.de header.s=20260216 header.b=I/DXhsQ/; spf=pass (domain: t-online.de, ip: 194.25.134.20, mailfrom: f_l_k@t-online.de) Received: from fwd76.aul.t-online.de (fwd76.aul.t-online.de [10.223.144.102]) by mailout08.t-online.de (Postfix) with SMTP id D8764E4B4 for ; Fri, 18 Sep 2026 11:33:22 +0200 (CEST) Received: from intel-corei7-64.fritz.box ([84.154.164.121]) by fwd76.t-online.de with (TLSv1.3:TLS_AES_256_GCM_SHA384 encrypted) esmtp id 1x7UyA-0EP8qm0; Fri, 18 Sep 2026 11:33:22 +0200 From: Markus Volk To: openembedded-devel@lists.openembedded.org Subject: [meta-python][PATCH] python3-html5lib: drop the six dependency Date: Fri, 18 Sep 2026 11:33:15 +0200 Message-ID: <20260918093315.337468-1-f_l_k@t-online.de> X-Mailer: git-send-email 2.55.0 MIME-Version: 1.0 X-TOI-EXPURGATEID: 150726::1789724002-4D7F99BC-B9845707/0/0 CLEAN NORMAL X-TOI-MSGID: ffe4be8d-7033-4125-8e62-b6e0d0e8654f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=t-online.de; s=20260216; t=1789724002; i=f_l_k@t-online.de; bh=C89fCtDu0uAaxrDdmku+hVrpyLp35qm51+NTAznRynQ=; h=From:To:Subject:Date; b=I/DXhsQ//cNY0jF/bmNPDLUHJS9f4C6KmF321IDD/NFZReubBGRld/HjWT8/HT0HN Hkv5dZgwKCa6ybXVMZXqdoT6Bc3vjdCZkaB+dt2bq0o3t7YoIP7g8uOG19AP8xLW5z A/li8Mb/15fH8yOdbTQog+FqG0i14qbkppttCb+7ru4ClcN0xjgALsC3TXzi487bb0 oRUsPLhU596t6S6kptYf70nJDB7k7WbCd0Wp2S7ZigB1Xxk4DETpUGDatN5Q/+isjB 1b3B1c4AXQMV9z92BZlrgQJ1X2bWKWtz4pK/QSUvgLCT39Y9lmGPo+kcvgyWg9JN/H XMUNyTGsWB6YQ== List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 18 Sep 2026 09:33:27 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/130112 openembedded-core removed python3-six, so the recipe no longer resolves. html5lib 1.1 only used six as a Python 2 compatibility layer; patch the imports over to the Python 3 builtins and drop the runtime dependency. Signed-off-by: Markus Volk AI-Generated: Uses Claude Code (Claude Fable 5.1) --- .../0001-Drop-the-six-dependency.patch | 397 ++++++++++++++++++ .../python/python3-html5lib_1.1.bb | 2 +- 2 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 meta-python/recipes-devtools/python/python3-html5lib/0001-Drop-the-six-dependency.patch diff --git a/meta-python/recipes-devtools/python/python3-html5lib/0001-Drop-the-six-dependency.patch b/meta-python/recipes-devtools/python/python3-html5lib/0001-Drop-the-six-dependency.patch new file mode 100644 index 0000000000..f83c7de34e --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-html5lib/0001-Drop-the-six-dependency.patch @@ -0,0 +1,397 @@ +From 2d62ee4926f2597839b59201504a6075651b2978 Mon Sep 17 00:00:00 2001 +From: Markus Volk +Date: Fri, 18 Sep 2026 11:22:50 +0200 +Subject: [PATCH] Drop the six dependency + +html5lib only runs on Python 3 nowadays, so the six shims can be replaced by +their builtins: text_type/string_types by str, binary_type by bytes, unichr by +chr, viewkeys by dict.keys, with_metaclass by the metaclass keyword and the +six.moves imports by http.client, urllib.response and urllib.parse. The PY3 +branches collapse to their Python 3 half. + +Upstream-Status: Submitted [https://github.com/html5lib/html5lib-python/pull/581] +Signed-off-by: Markus Volk +--- + html5lib/_inputstream.py | 8 ++++---- + html5lib/_tokenizer.py | 1 - + html5lib/_trie/py.py | 3 +-- + html5lib/_utils.py | 14 +++----------- + html5lib/filters/lint.py | 29 ++++++++++++++--------------- + html5lib/filters/sanitizer.py | 2 +- + html5lib/html5parser.py | 5 ++--- + html5lib/serializer.py | 5 ++--- + html5lib/treebuilders/base.py | 5 ++--- + html5lib/treebuilders/etree.py | 3 +-- + html5lib/treebuilders/etree_lxml.py | 6 +----- + html5lib/treewalkers/etree.py | 3 +-- + html5lib/treewalkers/etree_lxml.py | 3 +-- + setup.py | 1 - + 14 files changed, 33 insertions(+), 55 deletions(-) + +diff --git a/html5lib/_inputstream.py b/html5lib/_inputstream.py +index 0207dd2..5a2fc8c 100644 +--- a/html5lib/_inputstream.py ++++ b/html5lib/_inputstream.py +@@ -1,7 +1,7 @@ + from __future__ import absolute_import, division, unicode_literals + +-from six import text_type +-from six.moves import http_client, urllib ++import http.client as http_client ++import urllib.response + + import codecs + import re +@@ -131,9 +131,9 @@ def HTMLInputStream(source, **kwargs): + isinstance(source.fp, http_client.HTTPResponse))): + isUnicode = False + elif hasattr(source, "read"): +- isUnicode = isinstance(source.read(0), text_type) ++ isUnicode = isinstance(source.read(0), str) + else: +- isUnicode = isinstance(source, text_type) ++ isUnicode = isinstance(source, str) + + if isUnicode: + encodings = [x for x in kwargs if x.endswith("_encoding")] +diff --git a/html5lib/_tokenizer.py b/html5lib/_tokenizer.py +index 4748a19..5b20f49 100644 +--- a/html5lib/_tokenizer.py ++++ b/html5lib/_tokenizer.py +@@ -1,6 +1,5 @@ + from __future__ import absolute_import, division, unicode_literals + +-from six import unichr as chr + + from collections import deque, OrderedDict + from sys import version_info +diff --git a/html5lib/_trie/py.py b/html5lib/_trie/py.py +index c2ba3da..cfe7513 100644 +--- a/html5lib/_trie/py.py ++++ b/html5lib/_trie/py.py +@@ -1,5 +1,4 @@ + from __future__ import absolute_import, division, unicode_literals +-from six import text_type + + from bisect import bisect_left + +@@ -8,7 +7,7 @@ from ._base import Trie as ABCTrie + + class Trie(ABCTrie): + def __init__(self, data): +- if not all(isinstance(x, text_type) for x in data.keys()): ++ if not all(isinstance(x, str) for x in data.keys()): + raise TypeError("All keys must be strings") + + self._data = data +diff --git a/html5lib/_utils.py b/html5lib/_utils.py +index 9ea5794..5bc56ec 100644 +--- a/html5lib/_utils.py ++++ b/html5lib/_utils.py +@@ -7,15 +7,7 @@ try: + except ImportError: + from collections import Mapping + +-from six import text_type, PY3 +- +-if PY3: +- import xml.etree.ElementTree as default_etree +-else: +- try: +- import xml.etree.cElementTree as default_etree +- except ImportError: +- import xml.etree.ElementTree as default_etree ++import xml.etree.ElementTree as default_etree + + + __all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair", +@@ -31,10 +23,10 @@ __all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair", + # escapes. + try: + _x = eval('"\\uD800"') # pylint:disable=eval-used +- if not isinstance(_x, text_type): ++ if not isinstance(_x, str): + # We need this with u"" because of http://bugs.jython.org/issue2039 + _x = eval('u"\\uD800"') # pylint:disable=eval-used +- assert isinstance(_x, text_type) ++ assert isinstance(_x, str) + except Exception: + supports_lone_surrogates = False + else: +diff --git a/html5lib/filters/lint.py b/html5lib/filters/lint.py +index acd4d7a..e012fb8 100644 +--- a/html5lib/filters/lint.py ++++ b/html5lib/filters/lint.py +@@ -1,6 +1,5 @@ + from __future__ import absolute_import, division, unicode_literals + +-from six import text_type + + from . import base + from ..constants import namespaces, voidElements +@@ -33,9 +32,9 @@ class Filter(base.Filter): + if type in ("StartTag", "EmptyTag"): + namespace = token["namespace"] + name = token["name"] +- assert namespace is None or isinstance(namespace, text_type) ++ assert namespace is None or isinstance(namespace, str) + assert namespace != "" +- assert isinstance(name, text_type) ++ assert isinstance(name, str) + assert name != "" + assert isinstance(token["data"], dict) + if (not namespace or namespace == namespaces["html"]) and name in voidElements: +@@ -45,18 +44,18 @@ class Filter(base.Filter): + if type == "StartTag" and self.require_matching_tags: + open_elements.append((namespace, name)) + for (namespace, name), value in token["data"].items(): +- assert namespace is None or isinstance(namespace, text_type) ++ assert namespace is None or isinstance(namespace, str) + assert namespace != "" +- assert isinstance(name, text_type) ++ assert isinstance(name, str) + assert name != "" +- assert isinstance(value, text_type) ++ assert isinstance(value, str) + + elif type == "EndTag": + namespace = token["namespace"] + name = token["name"] +- assert namespace is None or isinstance(namespace, text_type) ++ assert namespace is None or isinstance(namespace, str) + assert namespace != "" +- assert isinstance(name, text_type) ++ assert isinstance(name, str) + assert name != "" + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + assert False, "Void element reported as EndTag token: %(tag)s" % {"tag": name} +@@ -66,26 +65,26 @@ class Filter(base.Filter): + + elif type == "Comment": + data = token["data"] +- assert isinstance(data, text_type) ++ assert isinstance(data, str) + + elif type in ("Characters", "SpaceCharacters"): + data = token["data"] +- assert isinstance(data, text_type) ++ assert isinstance(data, str) + assert data != "" + if type == "SpaceCharacters": + assert data.strip(spaceCharacters) == "" + + elif type == "Doctype": + name = token["name"] +- assert name is None or isinstance(name, text_type) +- assert token["publicId"] is None or isinstance(name, text_type) +- assert token["systemId"] is None or isinstance(name, text_type) ++ assert name is None or isinstance(name, str) ++ assert token["publicId"] is None or isinstance(name, str) ++ assert token["systemId"] is None or isinstance(name, str) + + elif type == "Entity": +- assert isinstance(token["name"], text_type) ++ assert isinstance(token["name"], str) + + elif type == "SerializerError": +- assert isinstance(token["data"], text_type) ++ assert isinstance(token["data"], str) + + else: + assert False, "Unknown token type: %(type)s" % {"type": type} +diff --git a/html5lib/filters/sanitizer.py b/html5lib/filters/sanitizer.py +index 70ef906..b949127 100644 +--- a/html5lib/filters/sanitizer.py ++++ b/html5lib/filters/sanitizer.py +@@ -12,7 +12,7 @@ import re + import warnings + from xml.sax.saxutils import escape, unescape + +-from six.moves import urllib_parse as urlparse ++import urllib.parse as urlparse + + from . import base + from ..constants import namespaces, prefixes +diff --git a/html5lib/html5parser.py b/html5lib/html5parser.py +index 74d829d..653f49a 100644 +--- a/html5lib/html5parser.py ++++ b/html5lib/html5parser.py +@@ -1,5 +1,4 @@ + from __future__ import absolute_import, division, unicode_literals +-from six import with_metaclass, viewkeys + + import types + +@@ -423,7 +422,7 @@ def getPhases(debug): + return type + + # pylint:disable=unused-argument +- class Phase(with_metaclass(getMetaclass(debug, log))): ++ class Phase(metaclass=getMetaclass(debug, log)): + """Base class for helper object that implements each phase of processing + """ + __slots__ = ("parser", "tree", "__startTagCache", "__endTagCache") +@@ -2776,7 +2775,7 @@ def getPhases(debug): + + + def adjust_attributes(token, replacements): +- needs_adjustment = viewkeys(token['data']) & viewkeys(replacements) ++ needs_adjustment = token['data'].keys() & replacements.keys() + if needs_adjustment: + token['data'] = type(token['data'])((replacements.get(k, k), v) + for k, v in token['data'].items()) +diff --git a/html5lib/serializer.py b/html5lib/serializer.py +index c66df68..e3b8ea5 100644 +--- a/html5lib/serializer.py ++++ b/html5lib/serializer.py +@@ -1,5 +1,4 @@ + from __future__ import absolute_import, division, unicode_literals +-from six import text_type + + import re + +@@ -222,14 +221,14 @@ class HTMLSerializer(object): + self.strict = False + + def encode(self, string): +- assert(isinstance(string, text_type)) ++ assert(isinstance(string, str)) + if self.encoding: + return string.encode(self.encoding, "htmlentityreplace") + else: + return string + + def encodeStrict(self, string): +- assert(isinstance(string, text_type)) ++ assert(isinstance(string, str)) + if self.encoding: + return string.encode(self.encoding, "strict") + else: +diff --git a/html5lib/treebuilders/base.py b/html5lib/treebuilders/base.py +index e4a3d71..24759e9 100644 +--- a/html5lib/treebuilders/base.py ++++ b/html5lib/treebuilders/base.py +@@ -1,5 +1,4 @@ + from __future__ import absolute_import, division, unicode_literals +-from six import text_type + + from ..constants import scopingElements, tableInsertModeElements, namespaces + +@@ -199,7 +198,7 @@ class TreeBuilder(object): + # match any node with that name + exactNode = hasattr(target, "nameTuple") + if not exactNode: +- if isinstance(target, text_type): ++ if isinstance(target, str): + target = (namespaces["html"], target) + assert isinstance(target, tuple) + +@@ -322,7 +321,7 @@ class TreeBuilder(object): + + def insertElementNormal(self, token): + name = token["name"] +- assert isinstance(name, text_type), "Element %s not unicode" % name ++ assert isinstance(name, str), "Element %s not unicode" % name + namespace = token.get("namespace", self.defaultNamespace) + element = self.elementClass(name, namespace) + element.attributes = token["data"] +diff --git a/html5lib/treebuilders/etree.py b/html5lib/treebuilders/etree.py +index 086bed4..eb1f026 100644 +--- a/html5lib/treebuilders/etree.py ++++ b/html5lib/treebuilders/etree.py +@@ -1,7 +1,6 @@ + from __future__ import absolute_import, division, unicode_literals + # pylint:disable=protected-access + +-from six import text_type + + import re + +@@ -222,7 +221,7 @@ def getETreeBuilder(ElementTreeImplementation, fullTree=False): + elif element.tag == ElementTreeCommentType: + rv.append("|%s" % (' ' * indent, element.text)) + else: +- assert isinstance(element.tag, text_type), \ ++ assert isinstance(element.tag, str), \ + "Expected unicode, got %s, %s" % (type(element.tag), element.tag) + nsmatch = tag_regexp.match(element.tag) + +diff --git a/html5lib/treebuilders/etree_lxml.py b/html5lib/treebuilders/etree_lxml.py +index e73de61..b13b23b 100644 +--- a/html5lib/treebuilders/etree_lxml.py ++++ b/html5lib/treebuilders/etree_lxml.py +@@ -28,7 +28,6 @@ from . import etree as etree_builders + from .. import _ihatexml + + import lxml.etree as etree +-from six import PY3, binary_type + + + fullTree = True +@@ -207,10 +206,7 @@ class TreeBuilder(base.TreeBuilder): + return name + + def __getitem__(self, key): +- value = self._element._element.attrib[self._coerceKey(key)] +- if not PY3 and isinstance(value, binary_type): +- value = value.decode("ascii") +- return value ++ return self._element._element.attrib[self._coerceKey(key)] + + def __setitem__(self, key, value): + self._element._element.attrib[self._coerceKey(key)] = value +diff --git a/html5lib/treewalkers/etree.py b/html5lib/treewalkers/etree.py +index 4465337..0bfd81f 100644 +--- a/html5lib/treewalkers/etree.py ++++ b/html5lib/treewalkers/etree.py +@@ -3,7 +3,6 @@ from __future__ import absolute_import, division, unicode_literals + from collections import OrderedDict + import re + +-from six import string_types + + from . import base + from .._utils import moduleFactoryFactory +@@ -51,7 +50,7 @@ def getETreeBuilder(ElementTreeImplementation): + return base.COMMENT, node.text + + else: +- assert isinstance(node.tag, string_types), type(node.tag) ++ assert isinstance(node.tag, str), type(node.tag) + # This is assumed to be an ordinary element + match = tag_regexp.match(node.tag) + if match: +diff --git a/html5lib/treewalkers/etree_lxml.py b/html5lib/treewalkers/etree_lxml.py +index a614ac5..9514f57 100644 +--- a/html5lib/treewalkers/etree_lxml.py ++++ b/html5lib/treewalkers/etree_lxml.py +@@ -1,5 +1,4 @@ + from __future__ import absolute_import, division, unicode_literals +-from six import text_type + + from collections import OrderedDict + +@@ -14,7 +13,7 @@ from .. import _ihatexml + def ensure_str(s): + if s is None: + return None +- elif isinstance(s, text_type): ++ elif isinstance(s, str): + return s + else: + return s.decode("ascii", "strict") +diff --git a/setup.py b/setup.py +index f84c128..b195d30 100644 +--- a/setup.py ++++ b/setup.py +@@ -104,7 +104,6 @@ setup(name='html5lib', + maintainer_email='james@hoppipolla.co.uk', + packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), + install_requires=[ +- 'six>=1.9', + 'webencodings', + ], + python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", +-- +2.55.0 + diff --git a/meta-python/recipes-devtools/python/python3-html5lib_1.1.bb b/meta-python/recipes-devtools/python/python3-html5lib_1.1.bb index 9c92164546..2447acde39 100644 --- a/meta-python/recipes-devtools/python/python3-html5lib_1.1.bb +++ b/meta-python/recipes-devtools/python/python3-html5lib_1.1.bb @@ -4,13 +4,13 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=1ba5ada9e6fead1fdc32f43c9f10ba7c" SRC_URI += "file://0001-setup.py-fix-version-parsing-on-Python-3.14-ast.Str-.patch" SRC_URI += "file://0001-setup.py-make-pkg_resources-import-optional-for-Pyth.patch" +SRC_URI += "file://0001-Drop-the-six-dependency.patch" SRC_URI[sha256sum] = "b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f" inherit pypi setuptools3 RDEPENDS:${PN} += "\ python3-lxml \ - python3-six \ python3-webencodings \ python3-xml \ "