ctrl-kd 4.5.0__tar.gz → 4.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. {ctrl_kd-4.5.0/src/ctrl_kd.egg-info → ctrl_kd-4.6.0}/PKG-INFO +8 -2
  2. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/README.md +7 -1
  3. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/pyproject.toml +8 -3
  4. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0/src/ctrl_kd.egg-info}/PKG-INFO +8 -2
  5. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrl_kd.egg-info/SOURCES.txt +19 -0
  6. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/__init__.py +1 -1
  7. ctrl_kd-4.6.0/src/ctrlkd/afm.py +742 -0
  8. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/core.py +1172 -24
  9. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/emit.py +191 -42
  10. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/fontmap.py +12 -4
  11. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/info.py +22 -9
  12. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/layout.py +437 -17
  13. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/pdf.py +4519 -538
  14. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/symbolmap.py +28 -0
  15. ctrl_kd-4.6.0/tests/test_bare_tab_modulus8.py +265 -0
  16. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_ctrlkd.py +2038 -140
  17. ctrl_kd-4.6.0/tests/test_fidelity_gate.py +1304 -0
  18. ctrl_kd-4.6.0/tests/test_graphic_cell_ops.py +99 -0
  19. ctrl_kd-4.6.0/tests/test_graphic_cells.py +220 -0
  20. ctrl_kd-4.6.0/tests/test_justification.py +297 -0
  21. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_char_substitution.py +66 -0
  22. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_colour_restore.py +3 -3
  23. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_heading_face.py +3 -2
  24. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_pcl_rectangles.py +3 -2
  25. ctrl_kd-4.6.0/tests/test_load_plugins.py +107 -0
  26. ctrl_kd-4.6.0/tests/test_modern_blank_after_tightened_line.py +130 -0
  27. ctrl_kd-4.6.0/tests/test_modern_centring_clip.py +321 -0
  28. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_modern_line_spacing.py +20 -2
  29. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_modern_lint.py +10 -8
  30. ctrl_kd-4.6.0/tests/test_modern_page_baseline.py +261 -0
  31. ctrl_kd-4.6.0/tests/test_modern_verse_defrow.py +543 -0
  32. ctrl_kd-4.6.0/tests/test_page_parity.py +181 -0
  33. ctrl_kd-4.6.0/tests/test_paper_verdicts.py +90 -0
  34. ctrl_kd-4.6.0/tests/test_pcl_fidelity.py +170 -0
  35. ctrl_kd-4.6.0/tests/test_pcl_page_membership.py +132 -0
  36. ctrl_kd-4.6.0/tests/test_pcl_page_size_eject.py +131 -0
  37. ctrl_kd-4.6.0/tests/test_pcl_tolerance.py +867 -0
  38. ctrl_kd-4.6.0/tests/test_pcl_transparent_print.py +80 -0
  39. ctrl_kd-4.6.0/tests/test_pcl_vertical_wraparound.py +174 -0
  40. ctrl_kd-4.6.0/tests/test_peseta_euro_driver.py +411 -0
  41. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_pictures.py +120 -0
  42. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_pix.py +6 -7
  43. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_polarity_gate.py +1 -1
  44. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_printed_fidelity.py +252 -28
  45. ctrl_kd-4.6.0/tests/test_samples.py +183 -0
  46. ctrl_kd-4.6.0/tests/test_sawyer_corpus.py +261 -0
  47. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_screenplay_detection.py +2 -2
  48. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_style_leading.py +250 -79
  49. ctrl_kd-4.6.0/tests/test_symbol_span_graphic_chars.py +176 -0
  50. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_writer.py +61 -0
  51. ctrl_kd-4.5.0/src/ctrlkd/afm.py +0 -337
  52. ctrl_kd-4.5.0/tests/test_fidelity_gate.py +0 -231
  53. ctrl_kd-4.5.0/tests/test_samples.py +0 -117
  54. ctrl_kd-4.5.0/tests/test_sawyer_corpus.py +0 -209
  55. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/LICENSE +0 -0
  56. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/setup.cfg +0 -0
  57. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrl_kd.egg-info/dependency_links.txt +0 -0
  58. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrl_kd.egg-info/entry_points.txt +0 -0
  59. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrl_kd.egg-info/top_level.txt +0 -0
  60. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/cli.py +0 -0
  61. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/convert.py +0 -0
  62. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/pictures.py +0 -0
  63. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/pix.py +0 -0
  64. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/piximg.py +0 -0
  65. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/samples/LYING.WS +0 -0
  66. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/samples/OCAPTAIN.WS +0 -0
  67. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/samples/TWAINLET.WS +0 -0
  68. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/samples/WARPRAYR.WS +0 -0
  69. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/typestyles.py +0 -0
  70. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/writer.py +0 -0
  71. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/src/ctrlkd/wschange.py +0 -0
  72. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_endnote_leading_gap.py +0 -0
  73. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_flags_toc_inline.py +0 -0
  74. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_glyph_aspect.py +0 -0
  75. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_layout_marks.py +0 -0
  76. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_bullet_glyph.py +0 -0
  77. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_hp_patterns.py +0 -0
  78. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_legend_line_spacing.py +0 -0
  79. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_shading_table_rules.py +0 -0
  80. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_lj6dtp_table_rule_weight.py +0 -0
  81. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_modern_box_regions.py +0 -0
  82. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_note_rulings_20260824.py +0 -0
  83. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_screenplay_pdf.py +0 -0
  84. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_screenplay_rendering.py +0 -0
  85. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_sentence_spacing_n9.py +0 -0
  86. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_verse_quote_couplet.py +0 -0
  87. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_verse_spacing.py +0 -0
  88. {ctrl_kd-4.5.0 → ctrl_kd-4.6.0}/tests/test_wschange.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ctrl-kd
3
- Version: 4.5.0
3
+ Version: 4.6.0
4
4
  Summary: Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done.
5
5
  Author: Jon Michaels
6
6
  License: MIT
@@ -66,6 +66,7 @@ More information: **[FAQ.md](FAQ.md)**, and **[ERAS.md](ERAS.md)**.
66
66
  $ brew install jonmichaels/tap/ctrl-kd # macOS / Linuxbrew
67
67
  $ pipx install ctrl-kd # or: pip install ctrl-kd
68
68
  ```
69
+ Download Windows x86_64: [Latest Version](https://github.com/jonmichaels/ctrl-kd/releases/latest/download/ctrl-kd-windows-x86_64.zip)
69
70
 
70
71
  Python ≥ 3.9, no dependencies. Library API: `ctrlkd.convert(data, to='html')`.
71
72
 
@@ -97,7 +98,12 @@ My own test files are personal and are not distributed — this repo's tests use
97
98
  synthetic fixtures and some public domain docs I retyped in WordStar 4 and
98
99
  WordStar 7 in DOSBox-X, plus Robert J. Sawyer's public WS7 archive (opt-in,
99
100
  `pytest -m sawyer`; see `tests/SAWYER-CORPUS.md`) you can run your own tests
100
- against that if you have a copy.
101
+ against that if you have a copy: download the archive, point
102
+ `CTRLKD_SAWYER_ARCHIVE` at its top-level directory (the one holding
103
+ `CONVERT.WS`, `INSET/`, `ARTICLES/`), and verify the path before arming —
104
+ `tests/SAWYER-CORPUS.md` has a one-line smoke check. A `CTRLKD_PRIVATE_CORPUS`
105
+ variable also exists, for my own private regression fixtures — it has no
106
+ effect unless you're me.
101
107
 
102
108
  ## Credits
103
109
 
@@ -47,6 +47,7 @@ More information: **[FAQ.md](FAQ.md)**, and **[ERAS.md](ERAS.md)**.
47
47
  $ brew install jonmichaels/tap/ctrl-kd # macOS / Linuxbrew
48
48
  $ pipx install ctrl-kd # or: pip install ctrl-kd
49
49
  ```
50
+ Download Windows x86_64: [Latest Version](https://github.com/jonmichaels/ctrl-kd/releases/latest/download/ctrl-kd-windows-x86_64.zip)
50
51
 
51
52
  Python ≥ 3.9, no dependencies. Library API: `ctrlkd.convert(data, to='html')`.
52
53
 
@@ -78,7 +79,12 @@ My own test files are personal and are not distributed — this repo's tests use
78
79
  synthetic fixtures and some public domain docs I retyped in WordStar 4 and
79
80
  WordStar 7 in DOSBox-X, plus Robert J. Sawyer's public WS7 archive (opt-in,
80
81
  `pytest -m sawyer`; see `tests/SAWYER-CORPUS.md`) you can run your own tests
81
- against that if you have a copy.
82
+ against that if you have a copy: download the archive, point
83
+ `CTRLKD_SAWYER_ARCHIVE` at its top-level directory (the one holding
84
+ `CONVERT.WS`, `INSET/`, `ARTICLES/`), and verify the path before arming —
85
+ `tests/SAWYER-CORPUS.md` has a one-line smoke check. A `CTRLKD_PRIVATE_CORPUS`
86
+ variable also exists, for my own private regression fixtures — it has no
87
+ effect unless you're me.
82
88
 
83
89
  ## Credits
84
90
 
@@ -48,8 +48,11 @@ ctrlkd = ["samples/*.WS"]
48
48
  # DESELECTED here, not skipped: it never even collects into the report, so
49
49
  # a bare run's summary line is an honest denominator.
50
50
  #
51
- # Arming (see tests/sawyer_fixture.py, conftest.py):
52
- # sawyer CTRLKD_SAWYER_ARCHIVE=/path (legacy alias: CTRLKD_CORPUS_SOURCE)
51
+ # Arming (see tests/sawyer_fixture.py, conftest.py, tools/pcl_tolerance.py):
52
+ # sawyer CTRLKD_SAWYER_ARCHIVE=/path
53
+ # pcl CTRLKD_PRIVATE_CORPUS=/path (2026-09-05, planning #197)
54
+ # paper CTRLKD_PRIVATE_CORPUS=/path (2026-09-06, planning #200; verdicts
55
+ # file path itself overridable with CTRLKD_PAPER_VERDICTS)
53
56
  #
54
57
  # tools/run-full-suite.sh overrides this filter (`-o addopts=""`) for an
55
58
  # armed run, where an unarmed gate FAILS instead of silently not running --
@@ -57,5 +60,7 @@ ctrlkd = ["samples/*.WS"]
57
60
  testpaths = ["tests"]
58
61
  markers = [
59
62
  "sawyer: opt-in tier 2 -- an explicit, committed list of documents from Robert J. Sawyer's public WordStar 7 archive (arm with CTRLKD_SAWYER_ARCHIVE)",
63
+ "pcl: opt-in -- coordinate-level fidelity gate against real WordStar 7 LaserJet PCL captures (arm with CTRLKD_PRIVATE_CORPUS); see tools/pcl_tolerance.py and tests/test_pcl_fidelity.py",
64
+ "paper: opt-in -- machine-readable verdicts for the 69 M479fdw paper-scan pages (arm with CTRLKD_PRIVATE_CORPUS); see tools/PAPER-VERDICTS.md and tests/test_paper_verdicts.py",
60
65
  ]
61
- addopts = "-m \"not sawyer\""
66
+ addopts = "-m \"not sawyer and not pcl and not paper\""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ctrl-kd
3
- Version: 4.5.0
3
+ Version: 4.6.0
4
4
  Summary: Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done.
5
5
  Author: Jon Michaels
6
6
  License: MIT
@@ -66,6 +66,7 @@ More information: **[FAQ.md](FAQ.md)**, and **[ERAS.md](ERAS.md)**.
66
66
  $ brew install jonmichaels/tap/ctrl-kd # macOS / Linuxbrew
67
67
  $ pipx install ctrl-kd # or: pip install ctrl-kd
68
68
  ```
69
+ Download Windows x86_64: [Latest Version](https://github.com/jonmichaels/ctrl-kd/releases/latest/download/ctrl-kd-windows-x86_64.zip)
69
70
 
70
71
  Python ≥ 3.9, no dependencies. Library API: `ctrlkd.convert(data, to='html')`.
71
72
 
@@ -97,7 +98,12 @@ My own test files are personal and are not distributed — this repo's tests use
97
98
  synthetic fixtures and some public domain docs I retyped in WordStar 4 and
98
99
  WordStar 7 in DOSBox-X, plus Robert J. Sawyer's public WS7 archive (opt-in,
99
100
  `pytest -m sawyer`; see `tests/SAWYER-CORPUS.md`) you can run your own tests
100
- against that if you have a copy.
101
+ against that if you have a copy: download the archive, point
102
+ `CTRLKD_SAWYER_ARCHIVE` at its top-level directory (the one holding
103
+ `CONVERT.WS`, `INSET/`, `ARTICLES/`), and verify the path before arming —
104
+ `tests/SAWYER-CORPUS.md` has a one-line smoke check. A `CTRLKD_PRIVATE_CORPUS`
105
+ variable also exists, for my own private regression fixtures — it has no
106
+ effect unless you're me.
101
107
 
102
108
  ## Credits
103
109
 
@@ -27,11 +27,15 @@ src/ctrlkd/samples/LYING.WS
27
27
  src/ctrlkd/samples/OCAPTAIN.WS
28
28
  src/ctrlkd/samples/TWAINLET.WS
29
29
  src/ctrlkd/samples/WARPRAYR.WS
30
+ tests/test_bare_tab_modulus8.py
30
31
  tests/test_ctrlkd.py
31
32
  tests/test_endnote_leading_gap.py
32
33
  tests/test_fidelity_gate.py
33
34
  tests/test_flags_toc_inline.py
34
35
  tests/test_glyph_aspect.py
36
+ tests/test_graphic_cell_ops.py
37
+ tests/test_graphic_cells.py
38
+ tests/test_justification.py
35
39
  tests/test_layout_marks.py
36
40
  tests/test_lj6dtp_bullet_glyph.py
37
41
  tests/test_lj6dtp_char_substitution.py
@@ -42,10 +46,24 @@ tests/test_lj6dtp_legend_line_spacing.py
42
46
  tests/test_lj6dtp_pcl_rectangles.py
43
47
  tests/test_lj6dtp_shading_table_rules.py
44
48
  tests/test_lj6dtp_table_rule_weight.py
49
+ tests/test_load_plugins.py
50
+ tests/test_modern_blank_after_tightened_line.py
45
51
  tests/test_modern_box_regions.py
52
+ tests/test_modern_centring_clip.py
46
53
  tests/test_modern_line_spacing.py
47
54
  tests/test_modern_lint.py
55
+ tests/test_modern_page_baseline.py
56
+ tests/test_modern_verse_defrow.py
48
57
  tests/test_note_rulings_20260824.py
58
+ tests/test_page_parity.py
59
+ tests/test_paper_verdicts.py
60
+ tests/test_pcl_fidelity.py
61
+ tests/test_pcl_page_membership.py
62
+ tests/test_pcl_page_size_eject.py
63
+ tests/test_pcl_tolerance.py
64
+ tests/test_pcl_transparent_print.py
65
+ tests/test_pcl_vertical_wraparound.py
66
+ tests/test_peseta_euro_driver.py
49
67
  tests/test_pictures.py
50
68
  tests/test_pix.py
51
69
  tests/test_polarity_gate.py
@@ -57,6 +75,7 @@ tests/test_screenplay_pdf.py
57
75
  tests/test_screenplay_rendering.py
58
76
  tests/test_sentence_spacing_n9.py
59
77
  tests/test_style_leading.py
78
+ tests/test_symbol_span_graphic_chars.py
60
79
  tests/test_verse_quote_couplet.py
61
80
  tests/test_verse_spacing.py
62
81
  tests/test_writer.py
@@ -8,4 +8,4 @@ from .pdf import emit_pdf # registers the 'pdf' format
8
8
  from .convert import convert, select_notes, DEFAULT_NOTE_KINDS, ALL_NOTE_KINDS
9
9
  from .info import document_info
10
10
 
11
- __version__ = '4.5.0'
11
+ __version__ = '4.6.0'