Skip to content

Commit 5c65c24

Browse files
felps-devclaudeCopilot
authored
URGENT -- fix: Add lxml 6.x compatibility for XML signature namespace handling (#444)
* fix: Add lxml 6.x compatibility for XML signature namespace handling - Reparse XML after signing to ensure namespaces are correctly associated with elements (required for lxml 6.x when using default namespace) - Update dependency constraints to allow lxml >=5.4.0 and signxml >=4.1.0 - Fix certificate test to use platform-independent temp directory lxml 6.0 changed how elements with default namespaces (xmlns without prefix) are handled internally. Elements created with nsmap={None: "..."} no longer have the namespace in their tag property, causing XPath queries with namespace prefixes to fail. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Update pyproject.toml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent a8af34d commit 5c65c24

4 files changed

Lines changed: 18 additions & 10 deletions

File tree

pynfe/processamento/assinatura.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,13 @@ def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree
4848

4949
ref_uri = ("#%s" % reference) if reference else None
5050
signed_root = signer.sign(xml, key=self.key, cert=self.cert, reference_uri=ref_uri)
51+
52+
# Reparse to ensure namespaces are correctly associated with elements
53+
# This is required for lxml 6.x compatibility when using default namespace (None prefix)
54+
signed_xml_str = etree.tostring(signed_root, encoding="unicode", pretty_print=False)
55+
signed_root = etree.fromstring(signed_xml_str)
56+
5157
if retorna_string:
52-
return etree.tostring(signed_root, encoding="unicode", pretty_print=False)
58+
return signed_xml_str
5359
else:
5460
return signed_root

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ line-length = 100
2121

2222
[tool.poetry.dependencies]
2323
requests = "^2.32.4"
24-
signxml = "^4.1.0"
25-
cryptography = "43.0.3"
26-
lxml = "5.4.0"
24+
signxml = ">=4.1.0"
25+
cryptography = ">=43.0.3"
26+
lxml = ">=5.4.0"
2727
pyopenssl = "^25.1.0"
2828

2929
[tool.poetry.group.dev.dependencies]

requirements.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Dependencias basicas
2-
requests
3-
lxml
4-
signxml
5-
cryptography
2+
requests>=2.32.4
3+
lxml>=5.4.0
4+
signxml>=4.1.0
5+
cryptography>=43.0.3
66
# Opcional para NFS-e
77
#-r requirements-nfse.txt
88
# Opcional para Desenvolvimento (Pytest, Ruff, MyPy, etc)

tests/test_certificadoA1.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python
22
# *-* encoding: utf8 *-*
33

4+
import tempfile
45
import unittest
56

67
from pynfe.entidades.certificado import CertificadoA1
@@ -17,8 +18,9 @@ def test_assinatura_com_caminho(self):
1718
self.a1 = CertificadoA1(self.certificado_correto)
1819
cert = self.a1.separar_arquivo(senha=self.senha_correto, caminho=self.certificado_correto)
1920

20-
self.assertTrue(cert[0].startswith("/tmp/"))
21-
self.assertTrue(cert[1].startswith("/tmp/"))
21+
temp_dir = tempfile.gettempdir()
22+
self.assertTrue(cert[0].startswith(temp_dir))
23+
self.assertTrue(cert[1].startswith(temp_dir))
2224

2325
self.a1.excluir()
2426

0 commit comments

Comments
 (0)