NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #2741 most downloaded on PyPI
Complete lxml external type annotation
Last release 7 months ago
17 Feb 2026
Ships fairly regularly
a new release about every 2 months
Nearly every release is documented
notes for 20 of 20 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
20 releases · first in 2022
One column per quarter.
(mypy plugin) Supports ElementDefaultClassLookup
ElementDefaultClassLookupty type checkerHtmlElement.head and .body can be NoneElementDefaultClassLookup into Generic classResolver methods args mostly position only_ResolverRegistry.copy()CHANGELOG.md to help searching among past changesmypy.stubtest"if KEYWORD:" usagepyright 1.1.408+ and basedpyright 1.37.1+pyright 1.1.406 and basedpyright 1.31.6mypy.stubtest as standalone testsHtmlElement sequence tests, DocInfo, ResolverHtmlElement sequence tests to _ElementElement factory annotation testpre-commit usage to help running actionlint[dev] extrasgit-cliffty to compat checks, and add more versionsubuntu-slim GitHub runner for lightweight workflowsreviewdog for PR checkci-annotation-converter as submodule to support type checker reportingSupports facebook's pyrefly type checker ( #106 , #107 )
pyrefly type checker (#106, #107)XMLParser.set_element_class_lookup() behaviorHtmlElement.label to None is disallowedTypeAlias usage caused requirement of Python 3.10HtmlMixin properties and .set() method tests to runtimetypes-lxml[dev] extras is installable againIt is possible to verify all release files indeed originate from GitHub and not altered elsewhere using GitHub CLI. For example, after downloading wheel file, run the following command in terminal to validate:
gh at verify types_lxml-2026.1.1-py3-none-any.whl --repo abelcheung/types-lxml
Drop deprecated collection-related typing aliases
@disjoint_base)
typing_extensionslibxml2 error constants from lxml 6.0.1+io.Reader and io.Writer from Python 3.14, replacing SupportsRead and SupportsWrite from typeshed.__init__() with __new__() for all XMLParser subclasses, overriding XMLParser.__new__(). Due to CustomTargetParser change in fdf2a81, XMLParser uses __new__() instead of __init__(). That commit brought in undesirable effect: pyright treats all XMLParser / HTMLParser subclasses instances as base class instances.@type_check_only to some protocols and genericsLiteralString with Literal constants when value is fixedassignment error code in testsHTMLParser.__init__() and XMLParser.__init__() to allowlist, due to #100Brings in full lxml 6.0.x support. Additional exported constants were already present in earlier types-lxml release, here are the remaining features:
lxml 6.0.x support. Additional exported constants were already present in earlier types-lxml release, here are the remaining features:
types-lxml completely matches 4.9.x API over time.mypy.stubtest check to help guarantee stub implementation doesn't deviate too much from runtime signatures and types, except intentional ones. Helps finding many of the bug fixes below.mypy 1.16+ and pyright 1.1.399+ParserTarget as target object, and CustomTargetParser as stub-only variant of XMLParser)
fromstring(), parse(), _ElementTree.parse(), ElementTree(), fromstringlist(), HTML(), XML().start() methodXMLParser and HTMLParser, and drop target= param from all parser subclasses (such as lxml.html ones)C14NWriterTarget inherits from ParserTarget__all__ in various submoduleslxml.etreecleanup_namespaces() shouldn't warn without keep_ns_prefixes argoutput_parent arg for XSLTExtension.apply_template() and .process_children()_Attrib as finalXMLSyntaxAssertionError.__init__()set_default_parser() arg missing default valuestrip_elements() with_tail arg should be keyword-onlyXSLTExtension overloadsXSLTExtension method arguments, such as using _Element to approximately represent _ReadOnlyElementProxy. Avoids creating even more stub-only classes and requiring user to poke into themlxml.htmlFormElement._name is a method, not propertylxml.isoschematronlxml.objectifyenable_recursive_str() arg missing default valueparse() file parameter name was wrongcanonicalize(), etree.tostring() and Extension() overloads to avoid confusionobjectify.NumberElement after all, in rare case where somebody wants to implement new type of number related to DataElementNumberElement._setValueParser() to subclasses_AnyStr_ElementTree.write() overloads, with the most generic overload presented first for UXXMLParser and HTMLParser API doc linksC14NWriterTarget_HtmlElemParser alias( #82 ) Add buffer type support for upcoming lxml 6.0.
HtmlElement.text_content() result will become plain str since lxml 6.0. This change shouldn't break much compatibility for users of previous lxml versions.str input and guess_charset combo bug in html.html5parser functions.extend() argumentLIBXML_COMPILED_FEATURES constantbytearrayQName construction argument were actually disallowed; second argument can't be QName or _Element if first argument is non-emptyResolver class
_ResolverRegistry.resolve() which can't possibly appear in user land codeResolver.resolve_file() keyword argumentsResolver.resolve() arguments can be Noneiterparse() html mode overloadnamespaces arg of .xpath() method accepts tuple form. Change for XPath classes already done earlier.ElementBase) class attributes_Element.findtext() didn't allow default argument in certain overload formRelaxNG.from_rnc_string() base_url argument accepts byteshtml.html5parser guess_charset bug revisited
parse() is not affected as it always open files/URL in binary modeguess_charset=False triggers the bughtml5parser.HTMLParser initialisation arguments should be keyword onlytyping.Never in html module and html.html5parser submodule.extend() and __setitem__() of _Element and HtmlElement support iterator as value_Element.index() had wrong parameter namebytearray:
_Element .text and .tail propertiesXPath input expression_IDDict mixin argumentsxmlfile.write*() methods and encoding argument_ElemClsLookupArg alias, which is almost unused_StrictNSMap to more aptly named _StrOnlyNSMapParseError definition_AnyStr in most placesFinalDTD, RelaxNG, ISO Schematron (XMLSchema done in earlier release)_Element method / property tests and content-only elementshtml.html5parser submoduleXMLID() and friendsQName_Element properties and methodsDepends on beautifulsoup4 itself because version 4.13 has bundled inline annotation. Dropping types-beautifulsoup4 dependency as result.
beautifulsoup4 itself because version 4.13 has bundled inline annotation. Dropping types-beautifulsoup4 dependency as result.CSSSelector resultErrorTypes constants as enumtype: ignores that improve compatibility with older versions of mypy and pyrightsoupparser submodule input arguments, copy definition from beautifulsoup4 code directlyhtml.fragment_fromstring create_parent argument can be string (#83, thanks to @sciyoshi)XPath namespaces argument can accept namespace tuplesbytes not allowed as html.diff.htmldiff() argumentencoding arguments do support bytearray_ListErrorLog.filter_from_level() supports real numbersbeautifulsoup and ErrorLog tests to property basedcssselect and XMLSchema tests to runtime onesurllib3 and pook as test dependencyDeprecate some Memdebug methods
Add basedpyright type checker support
Incorporate changes from lxml 5.3.1 and (pending) 6.0
html.builder shorthandslibxml feature constantsetree.DTD(external_id=...) support str nowMemdebug methodshtml.submit_form() always return HTTPResponse for default handler
Instance attributes are converted to properties because they are not deletable:
html.SelectElement.multiplehtml.InputElement.typeMore function arguments supports bytearray:
register_namespace()inclusive_ns_prefixes parameter of etree.tostring()etree module function overloads_AnyStr from etree module level functionsWarn IDE users via warnings.deprecated about exception upon certain argument combinations in HTML link functions
bytearray accepted as tag names, attribute names and attribute values
_TextArg type alias to slowly replace existing _AnyStr (#71)warnings.deprecated about exception upon certain argument combinations in HTML link functionsetree.strip_attributes() support bytes and QName as inputhtml.rewrite_links()etree.canonicalize() shouldn't accept bytes as inputhypothesis for extensive tests on function arguments, currently used in _Attrib and HTML link function tests (#75)reveal_type() injector has been split into its own project and pulled via dependency_HANDLE_FAILURES type alias and show values directly to usersSupportsLaxedItems to SupportsLaxItemsFull Changelog: 2024.11.08...2024.12.13
pyright users (and IDE that can make use of pyright ) will see warning if a single string is supplied where collection of string is expected ( tuple ,
pyright users (and IDE that can make use of pyright) will see warning if a single string is supplied where collection of string is expected (tuple, set, list etc). In terms of typing, a single str itself is valid as a Sequence, so type checkers normally would not raise alarm when using str in such function parameters, but can induce unexpected runtime behavior. (#64)
_ElementTree.write(), etree.fromstringlist(), etree.tostring(), html.soupparser.fromstring(), html.soupparser.parse()mypy results, therefore officially making static stub tests obsoletebytearray. This is discovered via hypothesis testing, which is intended to be utilized in next releasepyright ⩾ 1.1.378, which imposes additional overload warning for etree.iterparse()lxml.ElementInclude, otherwise mypy triggers --install-type behavior.ObjectifiedElement __getitem()__ and __setitem()__ should accept str as key, which behaves mostly like __getattr__() and __setattr__(). That means, elem["foo"] is equivalent to elem.foo for non-repeating subelements._Element.tag property is not just a str. It is str after initial document or string parsing, but can be set manually to any type supported by tag name and returns the same object.QName is initialized with first argument set to None, _Element can be used as second argument (which is promoted to first argument in implementation)_Element.iter*() method family, doesn't need tag= keyword when argument is NoneFunctionNamespace() should generate an _XPathFunctionNamespaceRegistry object, not its superclass_XPathFunctionNamespaceRegistry and _ClassNamespaceRegistry, decorator signature included an extraneous argument, though it doesn't affect any existing correct usage.indent() first parameter has wrong namesoupparser.parse() should accept pathlib.Path object as input.value property of SelectElement can't be set to bytes.action property of FormElement can have a value of None, and can be set to None. They have different meanings though.pyright and mypy ignore comments: in previous releases # type: ignore[code] was enabled in pyright settings. Now it only uses # pyright: ignore[code] so mypy comment won't affect pyright behavior.._name property to html.FormElement for form nametyping.TypeAlias usage (declared obsolete, and we can do without it)etree._Element methods, now only .makeelement() and .xpath() left in stub testElementNamespaceClassLookup()tox config migrated to pyproject.toml, thus requiring tox ⩾ 4.22test-rt folder due to python/mypy#8400mypy deficienciesuv as well as related tox plugin to speed up test environment recreationtox-gh-actions when checkout out repository, it is only useful for GitHub workflowsetree submodule: parse(), fromstringlist(), tostring(), indent(), iselement(), adopt_external_document(), DocInfo properties, QName, CData, some exception classeshtml.soupparser submodule: fromstring(), parse(), convert_tree()Namespace argument in Elementpath methods should allow None ( #60 thanks to @cukiernick )
None (#60 thanks to @cukiernick)lxml 5.3Mypy 1.11 required, which introduced backward incompatible @typing.overload changes.
Mypy 1.11 required, which introduced backward incompatible @typing.overload changes.lxml.html.clean stub depreated, lxml 5.2.0 completely removes the submodule due to multiple security issues. Corresponding code and type definitions are split into a new independent repo.typing.TypeGuard with typing.TypeIsElementMaker factory function typinglxml.etree.ICONV_COMPILED_VERSION exported since 5.2.2ObjectifiedElement and HTMLElement in lxml.cssselect.CSSSelector and various cssselect() methodshtml.builder shorthands return more precise element type for certain HTML elements. For example, html.builder.LABEL(), corresponding to <LABEL> tag, yields LabelElement.etree.Extension() annotation depending on supplied namespace_Element ElementPath methodslxml.builder.ElementMaker class:
__call__() argumentnsmap argumentlxml.sax module:
ElementTreeContentHandler class, as method arguments names are different from superclass onesetree.HTMLParser users to remove deprecated strip_cdata argument_Element related input arguments fixed to use typing.Sequence instead of Interable, as _Element is already an Iterable itself. Supplying _Element where a proper Iterable is expected would cause problem.str or byte in tag selector argument; use typing.Collection to alert user more clearly.None can't be used as etree.strip_*() argumentetree.DocInfo read-only properties can't be Noneetree.Resolver method return typeshtml.html5parser.HTMLParser_Element tests and its find*() methods_Attrib testsruff to replace black and isort as code formatterpytest-mypy-plugins ⩾ 2.0pdm-backend as build backend due to its more versatile versioning supportMypy 1.9 is required, dropping 1.5 support. 1.6 - 1.8 was never supported.
Mypy 1.9 is required, dropping 1.5 support. 1.6 - 1.8 was never supported.lxml.ElementInclude completely reworkedlxml.html parser constructor signatures can be removed..._Comment.text property (and those of similar elements) is always str (#46, thanks to @eemeli)html.fragments_fromstring() should receive same fix as html.html5parser.fragments_fromstring() do (#43, thanks to @Wuestengecko)@overload for etree.SubElement() on handling of HtmlElement and ObjectifiedElementlxml.ElementInclude stubhtml.soupparser module functions return type depends on makeelement argumenthtml.soupparser module functions are explicitly listed now (instead of generic **kwargs before)html.diff.html_annotate() should align their annotation typeshtml.submit_form() return type depends on the result of open_http function argumentlxml.isoschematronlxml.html.soupparser, lxml.ElementInclude, various exported constantsRequires cssselect ⩾ 1.2 for annotation in lxml.cssselect, since cssselect is now inline annotated.
cssselect ⩾ 1.2 for annotation in lxml.cssselect, since cssselect is now inline annotated.pyright ⩾ 1.1.353etree.clean_* functions, first argument (the Element or ElementTree to be processed) must be strictly positionaletree._LogEntry.filename property is never empty, as it uses the value <string> as fallbacketree._BaseErrorLog.receive() argument name was wrongSupportsReadClose protocol dropped, replacing with more standardized SupportsReadhtml.html5parser.parse() should support data stream as inputhtml.html5parser.fragments_fromstring() return type is dependent on no_leading_text argumentencoding arguments in various methods / functions used to only support ASCII and UTF-8 as byte encodings, now the restriction is liftedtyping usage under python version check (if sys.version_info >= (3, x))etree.PyErrorLog constructor shouldn't accept 2 logger arguments simultaneouslyetree.PyErrorLog.level_map property reverted to vanilla type (int) instead of our fake enumAdd back HtmlProcessingInstruction element (#28, thanks to @eliotwrobson)
HtmlProcessingInstruction element (#28, thanks to @eliotwrobson)pyright ⩾ 1.1.345 warning on overriding read-write property with read-only one (ObjectifyElement.text)mypy ⩾ 1.6 does not support PEP702, thus shouldn't be used with types-lxmlmypy 1.5.x nowTypes for emitted events and values in iterparse() were not optimal (issue #19, thanks to @Daverball)
iterparse() were not optimal (issue #19, thanks to @Daverball)html link and clean functions should be unable to process ElementTree, except Cleaner.clean_html()lxml fully covered (sans a few submodules that will never be implemented):
lxml.html.difflxml.ElementIncludelxml 5.0
Schematron constructor argumentstypeguard and pyrightsetuptools_scm in place of pdm-backend as package build backendHere is the list of change since last release. Besides, please check out release notes for previous release as well, since it contains substantial changes.
Re-added most deprecated methods in various places, with help from provisional PEP 702 support (@deprecated) in pyright
The list of changes since last release is huge, be it visible by users or not.
html.HtmlComment and friends have changed to deviate from source code. Now they are 'thought' to inherit from html.HtmlElement within stubs, like the XML etree._Element counterpart. Refer to wiki document on how and why this change is done.target= argument), as current python typing system is deemed insufficient to get it working without plugins.lxml is no longer pulled in when installing types-lxml.etree.SmartStr reverted back to its original class nameetree._ErrorLog is now made a function that generates etree._ListErrorLog (despite the fact that it is a class in source code), according to actual created instance typetypes-lxml package:
lxml.etree proper:
etree.iterparse and etree.iterwalkElementClassLookup typeslxml.objectify
DataElement subtypes and type annotation supportlxml.isoschematrontypes-lxml is external stub package and doesn't affect source code. Such as:
mypy and pyright type checkers have strict mode turned on when verifying stub source_Element.sourceline property becomes read-only@deprecated) in pyrightlxml classes, in case IDEs can display them in user interface._XPathEvaluatorBase subclasses to make __call__ available, by explicitly declaring it as abstract method within _XPathEvaluatorBasehttp.open_http_urllib, which is only intended as a fallback callback function for html.submit_form() without user interventionlibxml2 error constants become integer enum in stubetree.PyErrorLog.copy(), because it is only intended for smoother internal lxml error handling.file= argument in parse() and friends) requirement relaxedhtml.(X)HtmlParser __init__ was missing some argumentsiter* methods of Elements and some tag cleanup functions into @overload, to better reflect its original intended arguments usageetree.ElementBase and similar public base element classes lacked __init__etree.DocInfo text properties now accepts bytesname= argument of html.HtmlElementClassLookup() doesn't accept None_Comment, _Entity, _ProcessingInstruction, and their subclasses
.tag attribute now returns correct value (the basic etree element factory function)_Element do, such as treating them as parent elements and insert children element into themUser visible change since previous release:
User visible change since previous release:
User visible changes for this release since last one (2022.4.10):
User visible changes for this release since last one (2022.4.10):
etree.indent()_Attrib.pop(), etree.fromstring() and objectify.fromstring()Thanks to @muued and @wRAR for issue reports and improvements!
Release files are signed with my GPG key.
This is the second release of types-lxml. Followings are enhancements on top of lxml-stubs 0.4.0:
This is the second release of types-lxml. Followings are enhancements on top of lxml-stubs 0.4.0:
lxml.builderlxml.saxlxml.html.builderlxml.html.cleanlxml.html.soupparser (adapter for BeautifulSoup 4)lxml.html.html5parser (adapter for html5lib)lxml.etree.DTD and lxml.etree.RelaxNG classes are complete in this releasePyright support (guarantees error-free under basic checking mode)There are still some missing puzzle pieces before whole annotation package can be deemed complete and escape its partial status.
Release files are signed with my GPG signature.
First release to stand in its own right. There are still some missing puzzle pieces before whole annotation package can be deemed complete and escape
First release to stand in its own right. There are still some missing puzzle pieces before whole annotation package can be deemed complete and escape its partial status. Followings are enhancements done so far:
lxml.builderlxml.saxlxml.html.builderlxml.html.cleanlxml.html.soupparser (adapter for BeautifulSoup)Your coding agent can read these notes before it upgrades. Set up the MCP server →