lxml / lxml-stubs

Type stubs for the lxml package
Other
43 stars 28 forks source link

NSMapArg type definition is incorrect. #76

Open dapper91 opened 1 year ago

dapper91 commented 1 year ago

nsmap argument of Element function is of type Optional[_NSMapArg] where _NSMapArg is Mapping[str, str].

But according to the documentation here namespace key for the default namespace supposed to be None:

...
>>> NSMAP = {None : XHTML_NAMESPACE} # the default namespace (no prefix)

>>> xhtml = etree.Element(XHTML + "html", nsmap=NSMAP) # lxml only!
...

So it seems like _NSMapArg should be Mapping[Optional[str], str]

ajnelson-nist commented 1 year ago

I also just encountered this issue, and agree that the documentation disagrees with the type stubs.

danpascu commented 5 months ago

According to this comment:

# See https://github.com/python/typing/pull/273
# Due to Mapping having invariant key types, Mapping[Union[A, B], ...]
# would fail to validate against either Mapping[A, ...] or Mapping[B, ...]
# Try to settle for simpler solution, encouraging use of empty string ('')
# as default namespace prefix. If too many people complain, it can be
# back-paddled as Mapping[Any, ...]
_NSMapArg = Mapping[str, str]

Mapping[Optional[str], str] doesn't work because of Mapping being invariant in key and the recommendation is to use an empty string as default namespace prefix.

Which is fine by me, except it doesn't work:

In [78]: etree.Element('{foo}test', nsmap={'': 'pr'})
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[78], line 1
----> 1 etree.Element('{foo}test', nsmap={'': 'pr'})

File src/lxml/etree.pyx:3092, in lxml.etree.Element()

File src/lxml/apihelpers.pxi:138, in lxml.etree._makeElement()

File src/lxml/apihelpers.pxi:125, in lxml.etree._makeElement()

File src/lxml/apihelpers.pxi:226, in lxml.etree._setNodeNamespaces()

File src/lxml/apihelpers.pxi:1746, in lxml.etree._prefixValidOrRaise()

ValueError: Invalid namespace prefix ''

Apparently the empty string only works for the find* functions, but not for element creation.

mschoettle commented 3 months ago

I am having exactly this problem as @danpascu as well. For now I'll have to settle with ignoring this (type: ignore[dict-item]).