sercomm-printserver 0.1.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 (166) hide show
  1. sercomm_printserver-0.1.0/.gitignore +212 -0
  2. sercomm_printserver-0.1.0/CHANGELOG.md +43 -0
  3. sercomm_printserver-0.1.0/CONFIG.md +610 -0
  4. sercomm_printserver-0.1.0/LICENSE +22 -0
  5. sercomm_printserver-0.1.0/PKG-INFO +355 -0
  6. sercomm_printserver-0.1.0/README.md +296 -0
  7. sercomm_printserver-0.1.0/docs/Manual-PS301.md +370 -0
  8. sercomm_printserver-0.1.0/docs/adr/0001-memory-adapters-in-src.md +29 -0
  9. sercomm_printserver-0.1.0/docs/config-keys.md +193 -0
  10. sercomm_printserver-0.1.0/docs/device-dump/CONFIG.txt +115 -0
  11. sercomm_printserver-0.1.0/docs/device-dump/PSINF.txt +29 -0
  12. sercomm_printserver-0.1.0/docs/device-dump/fw6a10/CONFIG.txt +111 -0
  13. sercomm_printserver-0.1.0/docs/device-dump/telnet-monitor.txt +25 -0
  14. sercomm_printserver-0.1.0/docs/plans/2026-10-23-library-design.md +84 -0
  15. sercomm_printserver-0.1.0/docs/systemdesign/module_reference.md +250 -0
  16. sercomm_printserver-0.1.0/pyproject.toml +305 -0
  17. sercomm_printserver-0.1.0/src/sercomm_printserver/__init__.py +101 -0
  18. sercomm_printserver-0.1.0/src/sercomm_printserver/__init__conf__.py +90 -0
  19. sercomm_printserver-0.1.0/src/sercomm_printserver/__main__.py +9 -0
  20. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/__init__.py +14 -0
  21. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/__init__.py +80 -0
  22. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/__init__.py +49 -0
  23. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/_device.py +166 -0
  24. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/arp.py +232 -0
  25. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/config.py +527 -0
  26. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/device.py +391 -0
  27. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/device_config.py +251 -0
  28. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/discover.py +81 -0
  29. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/info.py +38 -0
  30. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/commands/printing.py +137 -0
  31. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/config_load.py +242 -0
  32. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/constants.py +68 -0
  33. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/context.py +188 -0
  34. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/envelope.py +93 -0
  35. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/exit_codes.py +59 -0
  36. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/main.py +123 -0
  37. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/py.typed +0 -0
  38. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/root.py +166 -0
  39. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/safe_console.py +315 -0
  40. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/cli/typed_click.py +77 -0
  41. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/__init__.py +25 -0
  42. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/defaultconfig.d/40-layered-config.toml +78 -0
  43. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/defaultconfig.d/50-device.toml +64 -0
  44. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/defaultconfig.d/90-logging.toml +448 -0
  45. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/defaultconfig.toml +56 -0
  46. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/deploy.py +135 -0
  47. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/device_settings.py +78 -0
  48. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/display.py +60 -0
  49. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/loader.py +210 -0
  50. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/overrides.py +326 -0
  51. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/config/py.typed +0 -0
  52. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/discovery/__init__.py +7 -0
  53. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/discovery/py.typed +0 -0
  54. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/discovery/scanner.py +98 -0
  55. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/ftp/__init__.py +11 -0
  56. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/ftp/client.py +459 -0
  57. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/ftp/py.typed +0 -0
  58. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/logging/__init__.py +13 -0
  59. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/logging/py.typed +0 -0
  60. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/logging/setup.py +448 -0
  61. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/lpd/__init__.py +11 -0
  62. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/lpd/client.py +252 -0
  63. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/lpd/py.typed +0 -0
  64. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/memory/__init__.py +45 -0
  65. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/memory/config.py +66 -0
  66. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/memory/device.py +190 -0
  67. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/memory/discovery.py +67 -0
  68. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/memory/logging.py +80 -0
  69. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/memory/neighbors.py +58 -0
  70. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/neighbors/__init__.py +7 -0
  71. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/neighbors/py.typed +0 -0
  72. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/neighbors/table.py +102 -0
  73. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/py.typed +0 -0
  74. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/raw/__init__.py +7 -0
  75. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/raw/printer.py +130 -0
  76. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/raw/py.typed +0 -0
  77. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/snmp/__init__.py +7 -0
  78. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/snmp/py.typed +0 -0
  79. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/snmp/uptime.py +118 -0
  80. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/telnet/__init__.py +7 -0
  81. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/telnet/client.py +179 -0
  82. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/telnet/iac.py +114 -0
  83. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/telnet/py.typed +0 -0
  84. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/tftp/__init__.py +11 -0
  85. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/tftp/client.py +264 -0
  86. sercomm_printserver-0.1.0/src/sercomm_printserver/adapters/tftp/py.typed +0 -0
  87. sercomm_printserver-0.1.0/src/sercomm_printserver/application/__init__.py +28 -0
  88. sercomm_printserver-0.1.0/src/sercomm_printserver/application/arp_trick.py +199 -0
  89. sercomm_printserver-0.1.0/src/sercomm_printserver/application/discovery.py +92 -0
  90. sercomm_printserver-0.1.0/src/sercomm_printserver/application/ports.py +244 -0
  91. sercomm_printserver-0.1.0/src/sercomm_printserver/application/print_server.py +339 -0
  92. sercomm_printserver-0.1.0/src/sercomm_printserver/application/py.typed +0 -0
  93. sercomm_printserver-0.1.0/src/sercomm_printserver/composition/__init__.py +185 -0
  94. sercomm_printserver-0.1.0/src/sercomm_printserver/composition/py.typed +0 -0
  95. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/__init__.py +20 -0
  96. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_catalogue.py +351 -0
  97. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_codec.py +146 -0
  98. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_lines.py +89 -0
  99. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_model.py +233 -0
  100. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_reader.py +326 -0
  101. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_types.py +176 -0
  102. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/config_writer.py +206 -0
  103. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/device_files.py +53 -0
  104. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/device_info.py +229 -0
  105. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/endpoint.py +48 -0
  106. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/enums.py +55 -0
  107. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/errors.py +102 -0
  108. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/port_status.py +174 -0
  109. sercomm_printserver-0.1.0/src/sercomm_printserver/domain/py.typed +0 -0
  110. sercomm_printserver-0.1.0/src/sercomm_printserver/entry.py +26 -0
  111. sercomm_printserver-0.1.0/src/sercomm_printserver/py.typed +0 -0
  112. sercomm_printserver-0.1.0/tests/conftest.py +606 -0
  113. sercomm_printserver-0.1.0/tests/fake_ftp_server.py +270 -0
  114. sercomm_printserver-0.1.0/tests/fake_lpd_server.py +179 -0
  115. sercomm_printserver-0.1.0/tests/fake_raw_server.py +100 -0
  116. sercomm_printserver-0.1.0/tests/fake_telnet_server.py +141 -0
  117. sercomm_printserver-0.1.0/tests/fake_tftp_server.py +168 -0
  118. sercomm_printserver-0.1.0/tests/test_adapter_ftp.py +286 -0
  119. sercomm_printserver-0.1.0/tests/test_adapter_lpd.py +223 -0
  120. sercomm_printserver-0.1.0/tests/test_adapter_neighbors.py +98 -0
  121. sercomm_printserver-0.1.0/tests/test_adapter_raw.py +120 -0
  122. sercomm_printserver-0.1.0/tests/test_adapter_snmp.py +166 -0
  123. sercomm_printserver-0.1.0/tests/test_adapter_telnet.py +144 -0
  124. sercomm_printserver-0.1.0/tests/test_adapter_tftp.py +182 -0
  125. sercomm_printserver-0.1.0/tests/test_arp_trick.py +229 -0
  126. sercomm_printserver-0.1.0/tests/test_cache_effectiveness.py +155 -0
  127. sercomm_printserver-0.1.0/tests/test_cli_arp.py +225 -0
  128. sercomm_printserver-0.1.0/tests/test_cli_config.py +886 -0
  129. sercomm_printserver-0.1.0/tests/test_cli_config_errors.py +576 -0
  130. sercomm_printserver-0.1.0/tests/test_cli_core.py +220 -0
  131. sercomm_printserver-0.1.0/tests/test_cli_device.py +383 -0
  132. sercomm_printserver-0.1.0/tests/test_cli_env_file.py +170 -0
  133. sercomm_printserver-0.1.0/tests/test_cli_envelope.py +53 -0
  134. sercomm_printserver-0.1.0/tests/test_cli_exit_codes.py +83 -0
  135. sercomm_printserver-0.1.0/tests/test_cli_main_exit.py +122 -0
  136. sercomm_printserver-0.1.0/tests/test_cli_overrides.py +183 -0
  137. sercomm_printserver-0.1.0/tests/test_cli_validation.py +132 -0
  138. sercomm_printserver-0.1.0/tests/test_config_catalogue.py +168 -0
  139. sercomm_printserver-0.1.0/tests/test_config_codec.py +283 -0
  140. sercomm_printserver-0.1.0/tests/test_config_overrides.py +408 -0
  141. sercomm_printserver-0.1.0/tests/test_coverage_database.py +51 -0
  142. sercomm_printserver-0.1.0/tests/test_declared_dependencies.py +89 -0
  143. sercomm_printserver-0.1.0/tests/test_deploy_mode_safety.py +191 -0
  144. sercomm_printserver-0.1.0/tests/test_deploy_permissions.py +369 -0
  145. sercomm_printserver-0.1.0/tests/test_device_reports.py +161 -0
  146. sercomm_printserver-0.1.0/tests/test_discovery.py +176 -0
  147. sercomm_printserver-0.1.0/tests/test_display.py +186 -0
  148. sercomm_printserver-0.1.0/tests/test_e2e_device.py +312 -0
  149. sercomm_printserver-0.1.0/tests/test_enums.py +78 -0
  150. sercomm_printserver-0.1.0/tests/test_errors.py +14 -0
  151. sercomm_printserver-0.1.0/tests/test_logging.py +82 -0
  152. sercomm_printserver-0.1.0/tests/test_logging_dotenv_isolation.py +545 -0
  153. sercomm_printserver-0.1.0/tests/test_memory_logging.py +120 -0
  154. sercomm_printserver-0.1.0/tests/test_metadata.py +84 -0
  155. sercomm_printserver-0.1.0/tests/test_metadata_sync.py +80 -0
  156. sercomm_printserver-0.1.0/tests/test_module_entry.py +166 -0
  157. sercomm_printserver-0.1.0/tests/test_packaging.py +138 -0
  158. sercomm_printserver-0.1.0/tests/test_permission_defaults.py +672 -0
  159. sercomm_printserver-0.1.0/tests/test_platform_markers.py +31 -0
  160. sercomm_printserver-0.1.0/tests/test_port_status.py +127 -0
  161. sercomm_printserver-0.1.0/tests/test_ports.py +143 -0
  162. sercomm_printserver-0.1.0/tests/test_print_server.py +363 -0
  163. sercomm_printserver-0.1.0/tests/test_property_overrides.py +165 -0
  164. sercomm_printserver-0.1.0/tests/test_public_api.py +33 -0
  165. sercomm_printserver-0.1.0/tests/test_safe_console.py +302 -0
  166. sercomm_printserver-0.1.0/tests/test_settings_dotenv_numbers.py +55 -0
@@ -0,0 +1,212 @@
1
+ # ====================================
2
+ # PYCHARM SPEZIFISCH: Git commands you might run once
3
+ # git add .gitignore && git commit -m "Ignore IDE settings"
4
+ # git push
5
+ # git rm -r --cached .idea
6
+ # git commit -m "Remove .idea and add to .gitignore"
7
+ # git push
8
+ # alternative : BE CAREFUL: overwrites remote history
9
+ # git push origin master --force
10
+
11
+ # ====================================
12
+ # APP
13
+ # ====================================
14
+ website/build/
15
+ website/.docusaurus/
16
+ website/node_modules/
17
+ node_modules/
18
+ web-local-preview/
19
+ translation_app*.log
20
+ translation_web*.log
21
+ tmp_github_web_pages/
22
+ tmp_linkcheck_web_pages/
23
+ .eslintcache
24
+ .vitest/
25
+ npm-debug.log*
26
+ yarn-error.log*
27
+ pnpm-debug.log*
28
+ .env.*
29
+ !.env.example
30
+ todo.md
31
+ tmp_*
32
+
33
+ # ====================================
34
+ # IDEs & Editors
35
+ # ====================================
36
+ # IntelliJ, PyCharm, etc.
37
+ .idea/
38
+ # VS Code workspace settings
39
+ .vscode/
40
+ *.code-workspace
41
+
42
+ # ====================================
43
+ # Python bytecode & caches
44
+ # ====================================
45
+ # __pycache__: compiled .pyc files at any depth
46
+ # *.py[cod]: catches .pyc, .pyo, .pyd
47
+ __pycache__/
48
+ src/sercomm_printserver/__pycache__/
49
+ *.py[cod]
50
+ # other compiled artifacts
51
+ *$py.class
52
+
53
+ # pytest, coverage, MyPy, Hypothesis
54
+ .pytest_cache/
55
+ .mypy_cache/
56
+ .pyright/
57
+ .coverage*
58
+ htmlcov/
59
+ nosetests.xml
60
+ coverage.xml
61
+ *.cover
62
+ .hypothesis/
63
+ .tox/
64
+ .nox/
65
+
66
+ # general cache directories (any project-level caching)
67
+ .cache/
68
+ .run/
69
+ .import_linter_cache/
70
+
71
+ # ====================================
72
+ # Build & distribution artifacts
73
+ # ====================================
74
+ # source/package builds
75
+ build/
76
+ dist/
77
+ # metadata for pip installs
78
+ *.egg-info/
79
+ *.egg
80
+ *.whl
81
+ pip-wheel-metadata/
82
+ # PyInstaller metadata
83
+ *.manifest
84
+ # PyInstaller spec files
85
+ *.spec
86
+
87
+ # Eggs, parts, wheels, sdist, etc.
88
+ develop-eggs/
89
+ .eggs/
90
+ parts/
91
+ sdist/
92
+ wheels/
93
+ downloads/
94
+ var/
95
+
96
+ # pip logs & installer leftovers
97
+ pip-log.txt
98
+ pip-delete-this-directory.txt
99
+ .installed.cfg
100
+
101
+ # ====================================
102
+ # Virtual environments & secrets
103
+ # ====================================
104
+ # common venv folder names
105
+ env/
106
+ venv/
107
+ ENV/
108
+ .venv/
109
+ # backups, alternate names
110
+ env.bak/
111
+ venv.bak/
112
+ # dotenv files with credentials
113
+ .env
114
+
115
+ # ====================================
116
+ # Project-specific & framework files
117
+ # ====================================
118
+ # Django logs & local overrides
119
+ *.log
120
+ local_settings.py
121
+
122
+ # Flask instance folder
123
+ instance/
124
+ .webassets-cache
125
+
126
+ # Scrapy cache
127
+ .scrapy
128
+
129
+ # Sphinx docs
130
+ docs/_build/
131
+
132
+ # PyBuilder output
133
+ target/
134
+
135
+ # Jupyter notebooks checkpoints
136
+ .ipynb_checkpoints
137
+
138
+ # pyenv Python version file
139
+ .python-version
140
+
141
+ # Celery beat schedule
142
+ celerybeat-schedule
143
+
144
+ # SageMath parsed files
145
+ *.sage.py
146
+
147
+ # Spyder IDE
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope IDE
152
+ .ropeproject
153
+
154
+ # MkDocs static site folder
155
+ /site
156
+
157
+ # ====================================
158
+ # OS-specific files
159
+ # ====================================
160
+ # macOS
161
+ .DS_Store
162
+ # Windows
163
+ Thumbs.db
164
+ ehthumbs.db
165
+
166
+ # Archives
167
+ *.zip
168
+
169
+ # Thunderbird build artifact (created temporarily by pack script)
170
+ sources/manifest.json
171
+
172
+ # ====================================
173
+ # Tool-specific extras
174
+ # ====================================
175
+ # Codecov uploader script (downloaded during local uploads)
176
+ codecov.sh
177
+ codecov.xml
178
+
179
+ # Nix build result symlink
180
+ result
181
+
182
+ # Optional lockfiles (for alternative managers)
183
+ poetry.lock
184
+ pdm.lock
185
+
186
+ # div
187
+ # .devcontainer/ # needed for github codespaces
188
+ .claude/
189
+ CLAUDE.md
190
+ prompts.md
191
+ .grimp_cache/
192
+
193
+ # Local, per-developer settings (Claude Code etc.) - never commit
194
+ *.local.json
195
+ # bitranox curated memory (local; CLAUDE.local.md @imports it)
196
+ CLAUDE.local.md
197
+
198
+ # Python virtual environments (managed by bmk)
199
+ .venv-win/
200
+ .venv-bmk/
201
+
202
+ # Python virtual environments (managed by bmk)
203
+ .venv*/
204
+
205
+ # Autonomous-execution decision log (never committed)
206
+ EXECUTION-USER-REVIEW.md
207
+
208
+ # Real values of the local test print server (template: test-device.example.json)
209
+ test-device.json
210
+
211
+ # End-to-end test snapshots of the real device configuration
212
+ .e2e/
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file following
4
+ the [Keep a Changelog](https://keepachangelog.com/) format.
5
+
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] 2026-10-24
10
+
11
+ ### Added
12
+
13
+ - Project created from `bitranox_template_py_cli` and renamed to `sercomm-printserver`.
14
+ - `docs/Manual-PS301.md`: what is known about the SerComm PS301 print server family.
15
+ - Device commands for the SerComm print-server family: `discover` (by the FTP greeting, no login),
16
+ `device-info`, `firmware`, `status`, `queue`, `device-config show/get/set/export/import`, `reset`,
17
+ `password set/clear`, `store-ip`, `factory-default`, and `print lpd/raw`. Every one answers with
18
+ `--json` / `--json-bare`; changes need `--yes`, the dangerous ones also `--confirm-name`.
19
+ `print lpd/raw` report the transport (`lpd` or `raw`) and its queue or printer number as
20
+ separate JSON fields. `discover` lists each local network it left out (more than 4096
21
+ addresses) as a network string in `data.skipped`; the envelope's `skipped` says why.
22
+ - `arp reach/assign-ip/factory-reset`: reach a device by its MAC through a borrowed address (the
23
+ vendor's ARP trick), with the static ARP entry written natively through ipscout and removed
24
+ again in every case. Needs root or `CAP_NET_ADMIN`, root on macOS, Administrator on Windows
25
+ (exit 13 without). `--mac` and `--ip` are checked before anything is written (exit 22).
26
+ - A typed model of the device's CONFIG file, `docs/config-keys.md` with the keys of each model
27
+ and firmware version, and writes that restart the device and wait for it by its SNMP uptime.
28
+ - `print raw` reaches logical printers 1..3, the only ones with a RAW port. Measured on a PS301:
29
+ 9100-9102 and the vendor's 4010/4020/4030 both feed L1..L3 and follow each printer's routing.
30
+ - Python library surface: `open_print_server`, `discover_print_servers`, `PrintServer`,
31
+ `DeviceEndpoint`, `PrintJob`, `arp_trick`, `IpscoutNeighborTable`, `MacAddress`,
32
+ `normalise_mac` and the domain exceptions. The `arp_trick` functions take the borrowed address
33
+ as `ip: IPv4Address`; MACs are normalised once, on entry. `DiscoveryReport.skipped` holds the
34
+ left-out networks as `IPv4Network` values.
35
+ - Claude Code plugin with the `sercomm-printserver` skill.
36
+ - End-to-end tests against a real device (`-m device`, opt-in), which save the device's
37
+ configuration before any change and restore it.
38
+
39
+ ### Fixed
40
+
41
+ - TFTP on Windows: a device that closes its port during a transfer (as it does when a `RESET`
42
+ restarts it) no longer reads as a broken transfer. Windows reports the ICMP "port unreachable"
43
+ on the next read of the UDP socket; it is now treated like the silence Linux and macOS see.