test_step4_underlines.py 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. """投标函字段填充不得把混合格式段落压平到第一个 run。"""
  2. import os
  3. import tempfile
  4. import unittest
  5. import xml.etree.ElementTree as ET
  6. from docx import Document
  7. from docx.enum.text import WD_UNDERLINE
  8. from models import Chapter
  9. from step4_writing import _fill_docx_paragraph_text, _save_chapter_docx, _w_tag
  10. class Step4UnderlineTests(unittest.TestCase):
  11. def test_cross_run_placeholder_keeps_untouched_run_properties(self):
  12. doc = Document()
  13. p = doc.add_paragraph("参加")
  14. for value in ("%%项", "目名称%%"):
  15. run = p.add_run(value)
  16. run.underline = WD_UNDERLINE.DOUBLE
  17. run.bold = True
  18. p.add_run(",承诺")
  19. p.add_run("固定下划线文字").underline = True
  20. p.add_run("。")
  21. xml = ET.fromstring(p._p.xml)
  22. properties = [ET.tostring(r.find(_w_tag("rPr")))
  23. if r.find(_w_tag("rPr")) is not None else None
  24. for r in xml.iter(_w_tag("r"))]
  25. _fill_docx_paragraph_text(xml, "参加示例项目,承诺固定下划线文字。")
  26. texts = [t.text or "" for t in xml.iter(_w_tag("t"))]
  27. self.assertEqual(texts, ["参加", "示例项目", "", ",承诺", "固定下划线文字", "。"],
  28. "字段应在原下划线run内替换,禁止整段压平")
  29. self.assertEqual(properties, [ET.tostring(r.find(_w_tag("rPr")))
  30. if r.find(_w_tag("rPr")) is not None else None
  31. for r in xml.iter(_w_tag("r"))])
  32. def test_deletion_numeric_update_and_non_text_nodes_survive(self):
  33. p = Document().add_paragraph("比例")
  34. p.add_run("15%").underline = True
  35. p.add_run(",包号:%%包号%%")
  36. p.add_run().add_break()
  37. p.add_run("签署:____").italic = True
  38. xml = ET.fromstring(p._p.xml)
  39. _fill_docx_paragraph_text(xml, "比例20%签署:____")
  40. self.assertEqual("".join(t.text or "" for t in xml.iter(_w_tag("t"))),
  41. "比例20%签署:____")
  42. self.assertEqual(len(list(xml.iter(_w_tag("br")))), 1)
  43. underlined = [r for r in xml.iter(_w_tag("r"))
  44. if r.find(_w_tag("rPr") + '/' + _w_tag("u")) is not None]
  45. self.assertEqual("".join(t.text or "" for r in underlined for t in r.iter(_w_tag("t"))), "20%")
  46. def test_native_chapter_docx_preserves_letter_and_cell_underlines(self):
  47. with tempfile.TemporaryDirectory() as directory:
  48. template = Document()
  49. template.add_paragraph("第一章 投标人资格、资信证明", style="Heading 1")
  50. template.add_paragraph("投标函")
  51. paragraphs = [template.add_paragraph(), template.add_table(rows=1, cols=1).cell(0, 0).paragraphs[0]]
  52. for p in paragraphs:
  53. p.add_run("参加")
  54. p.add_run("%%项目").underline = True
  55. p.add_run("名称%%").underline = True
  56. p.add_run(",编号:")
  57. p.add_run("%%项目编号%%").underline = WD_UNDERLINE.DOUBLE
  58. p.add_run(";签署:")
  59. p.add_run(" ").underline = True
  60. p.add_run("。")
  61. template.add_paragraph("第二章 报价", style="Heading 1")
  62. template_path = os.path.join(directory, "template.docx")
  63. template.save(template_path)
  64. path = _save_chapter_docx(
  65. Chapter(id="1", title="投标人资格、资信证明", template_chapter_id="1"),
  66. directory, template_path=template_path,
  67. placeholder_map={"项目名称": "示例项目", "项目编号": "TEST-001"},
  68. )
  69. result = Document(path)
  70. paragraphs = [next(p for p in result.paragraphs if p.text.startswith("参加")),
  71. result.tables[0].cell(0, 0).paragraphs[0]]
  72. for p in paragraphs:
  73. self.assertEqual(p.text, "参加示例项目,编号:TEST-001;签署: 。")
  74. self.assertEqual([(r.text, r.underline) for r in p.runs if r.text], [
  75. ("参加", None), ("示例项目", True), (",编号:", None),
  76. ("TEST-001", WD_UNDERLINE.DOUBLE), (";签署:", None),
  77. (" ", True), ("。", None),
  78. ], "原生段落/单元格填充必须保留字段及签署空白下划线")
  79. if __name__ == "__main__":
  80. unittest.main()