seymourlib 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Richard Berg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,215 @@
1
+ Metadata-Version: 2.4
2
+ Name: seymourlib
3
+ Version: 0.1.0
4
+ Summary: Python client for Seymour masking screens, connected via direct serial or Global Caché iTach IP2SL
5
+ Author-email: Richard Berg <ars@richardberg.net>
6
+ License-Expression: MIT
7
+ Project-URL: omepage, https://github.com/richard-berg/seymourlib
8
+ Project-URL: source, https://github.com/richard-berg/seymourlib.git
9
+ Project-URL: issues, https://github.com/richard-berg/seymourlib/issues
10
+ Keywords: seymour,masking,screen,serial,itach,ip2sl,home-assistant
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Home Automation
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: anyio>=3.4
21
+ Requires-Dist: attrs>=25.4.0
22
+ Requires-Dist: tenacity>=8.0
23
+ Requires-Dist: async-typer>=0.1.10
24
+ Provides-Extra: serial
25
+ Requires-Dist: pyserial_asyncio>=0.6; extra == "serial"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7; extra == "dev"
28
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
29
+ Requires-Dist: pytest-timeout>=2; extra == "dev"
30
+ Requires-Dist: coverage>=7; extra == "dev"
31
+ Requires-Dist: mypy>=1.10; extra == "dev"
32
+ Requires-Dist: ruff>=0.6; extra == "dev"
33
+ Requires-Dist: types-setuptools; extra == "dev"
34
+ Requires-Dist: pyserial_asyncio>=0.6; extra == "dev"
35
+ Provides-Extra: lint
36
+ Requires-Dist: ruff>=0.6; extra == "lint"
37
+ Provides-Extra: typecheck
38
+ Requires-Dist: mypy>=1.10; extra == "typecheck"
39
+ Provides-Extra: test
40
+ Requires-Dist: pytest>=7; extra == "test"
41
+ Requires-Dist: pytest-asyncio>=0.23; extra == "test"
42
+ Requires-Dist: pytest-timeout>=2; extra == "test"
43
+ Requires-Dist: coverage>=7; extra == "test"
44
+ Requires-Dist: pyserial_asyncio>=0.6; extra == "test"
45
+ Dynamic: license-file
46
+
47
+ # seymourlib
48
+
49
+ [![CI](https://img.shields.io/github/actions/workflow/status/richard-berg/seymourlib/ci.yml?label=CI&logo=github)](https://github.com/richard-berg/seymourlib/actions/workflows/ci.yml)
50
+ [![Coverage](https://img.shields.io/codecov/c/github/richard-berg/seymourlib?logo=codecov)](https://codecov.io/gh/richard-berg/seymourlib)
51
+ [![PyPI](https://img.shields.io/pypi/v/seymourlib?logo=pypi)](https://pypi.org/project/seymourlib/)
52
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
53
+
54
+ Python client for Seymour masking screens, connected via direct serial or Global Caché iTach IP2SL. Built for rock-solid control loops, [Home Assistant](https://www.home-assistant.io/) integrations, and quick bench testing. 😎
55
+
56
+ ---
57
+
58
+ ## Highlights
59
+
60
+ - Async-first client and transport abstractions (TCP/IP2SL vs native serial) with consistent APIs.
61
+ - Protocol helpers that mirror the official Seymour RS232 spec, including parsing/validation utilities.
62
+ - `seymourctl` CLI for one-off commands, scripting, and smoke tests in CI.
63
+ - Batteries-included retry logic (`tenacity`), timeout handling, and graceful cancellation via `anyio`.
64
+
65
+ ## Architecture at a Glance
66
+
67
+ ```mermaid
68
+ flowchart TB
69
+ App[Your automation / HA stack] -->|async API| Client[SeymourClient]
70
+ Client --> Protocol[Protocol helpers]
71
+ Client --> Transport
72
+ Transport -->|TCP 4999| IP2SL[Global Caché IP2SL]
73
+ Transport -->|RS232| Screen[Seymour Masking Screen]
74
+ IP2SL -->|RS232| Screen
75
+ ```
76
+
77
+ ## Installation
78
+
79
+ ### Requirements
80
+
81
+ - Python 3.11+
82
+ - `uv` >= 0.2 (recommended) or classic `pip`
83
+
84
+ ### Using uv (dev + extras)
85
+
86
+ ```bash
87
+ uv sync --all-extras
88
+ ```
89
+
90
+ ### Using pip (runtime only)
91
+
92
+ ```bash
93
+ python -m venv .venv
94
+ source .venv/bin/activate # or .venv\Scripts\activate on Windows
95
+ pip install "seymourlib[serial]"
96
+ ```
97
+
98
+ > 💡 The optional `serial` extra pulls in `pyserial-asyncio` so the same client works over USB/RS232 without the IP bridge.
99
+
100
+ ---
101
+
102
+ ## First-Time Setup Checklist
103
+
104
+ 1. **Clone & bootstrap**
105
+ - `git clone https://github.com/richard-berg/seymourlib && cd seymourlib`
106
+ - `uv sync --all-extras`
107
+ 2. **Sanity-test the library**
108
+ - `uv run pytest` for local regression.
109
+ - `uv run seymourctl -v status` to hit your target once hardware is reachable.
110
+ 3. **Wire up hardware**
111
+ - Confirm straight-through RS232 between IP2SL and the Seymour control port.
112
+ - For direct USB serial, a FTDI-based adapter keeps timing stable.
113
+ 4. **Pick your transport**
114
+ - `TCPTransport(host, port=4999)` for IP2SL.
115
+ - `SerialTransport(port="COM5")` for direct connection (requires `[serial]`).
116
+
117
+ ---
118
+
119
+ ## Usage Examples
120
+
121
+ ### Python API
122
+
123
+ ```python
124
+ import asyncio
125
+ from seymourlib.client import SeymourClient
126
+ from seymourlib.transport import TCPTransport
127
+
128
+ async def main() -> None:
129
+ async with SeymourClient(TCPTransport("192.168.1.70")) as client:
130
+ status = await client.get_status()
131
+ print(status)
132
+
133
+ asyncio.run(main())
134
+ ```
135
+
136
+ ### CLI
137
+
138
+ ```bash
139
+ uv run seymourctl --host 192.168.1.70 status
140
+ uv run seymourctl --host 192.168.1.70 preset apply 235
141
+ uv run seymourctl --help
142
+ ```
143
+
144
+ ---
145
+
146
+ ## IP2SL Setup & Diagnostics
147
+
148
+ ### 1. Test direct serial first
149
+
150
+ - Connect a laptop directly to the Seymour RS232 port with a known-good USB adapter.
151
+ - Use `RealTerm`, `CoolTerm`, or any tty tool (115200 8N1 by default - verify via Seymour docs) to send a `PS?` (position status) command.
152
+ - Once commands succeed locally, you know the projector + cable + command syntax are correct before adding the network hop.
153
+
154
+ ### 2. Discover the IP2SL via iHelp
155
+
156
+ - Download [Global Caché iHelp](https://www.globalcache.com/files/software/iHelp.zip) and run it on the same subnet.
157
+ - Press **Scan** to locate the IP2SL; note the MAC, firmware, and current IP.
158
+ - If nothing shows up, temporarily disable host firewalls or plug directly into a laptop + small DHCP scope.
159
+
160
+ ### 3. Pin the network configuration
161
+
162
+ - Point a browser at `http://<your-ip>/` (from step 2) if you want a point-and-click GUI for DHCP/static IP, firmware, and reboot controls.
163
+ - Otherwise, install [Global Caché iTest](https://www.globalcache.com/files/software/iTest.zip).
164
+ - Use iTest or telnet into port **4998** (the configuration/control port).
165
+ - Send `set dhcp 0`, `set ip <static>`, `set mask <subnet>`, `set gateway <gw>`, then `save` to burn settings.
166
+ - Reboot (power cycle or `reboot` command) and confirm the device responds on the static IP.
167
+ - Document the MAC/IP in your DHCP reservations to avoid future collisions.
168
+
169
+ ### 4. Lock the serial parameters
170
+
171
+ - Open the IP2SL web UI and switch to the **Serial** tab, or telnet/iTest into port **4998** for command-line configuration.
172
+ - Ensure the port is set to **115200 baud, 8 data bits, no parity, 1 stop bit** to match Seymour’s RS232 spec.
173
+ - Saving via the UI writes immediately; if you used the control port, run `set baud 115200`, `set data 8`, `set parity 0`, `set stop 1`, then `save` and reboot so the bridge always boots with the correct framing.
174
+
175
+ ### 5. Exercise the serial bridge with iTest
176
+
177
+ - Open iTest (or `telnet`)
178
+ - Target port **4999** on the static IP, choose **RAW** mode, and click **Connect**.
179
+ - Send a few simple commands (e.g. `[01S]`, `[01P]`). The response should echo immediately.
180
+ - If latency creeps in, verify telnet keep-alives/device busy LEDs. Keep the window open while you walk through automation flows to watch the live traffic.
181
+
182
+ ### 6. Promote to seymourlib
183
+
184
+ - Update your `.env` / config with the same host/port verified above.
185
+ - Start with `uv run seymourctl -v status` (verbose logging shows full request/response frames).
186
+ - Flip to automation ([Home Assistant](https://www.home-assistant.io/), Homebridge, etc.) once CLI calls are boringly reliable.
187
+
188
+ ---
189
+
190
+ ## Troubleshooting & Field Notes
191
+
192
+ - ⚡ **No response over TCP but serial works** - Ensure port 4999 is open on local firewalls and that the IP2SL LED blinks on connect; if not, recheck the static IP settings from step 3.
193
+ - 🔌 **Commands hang after a day** - The IP2SL can queue stale sockets; send `set rs232disconnect 1` over port 4998 so idle TCP clients auto-close.
194
+ - 🔁 **Race conditions from HA automations** - Wrap your automations with seymourlib's async context manager so only one command pipeline exists per transport.
195
+ - 🧪 **Need deeper diagnostics** - Add `--verbose` to `seymourctl` to dump protocol frames, or [enable debug logging](https://docs.python.org/3/library/logging.html) to capture per-request timestamps.
196
+ - 🛠️ **Firmware drift** - Global Caché publishes release notes; mismatched firmware sometimes defaults back to DHCP on reboot. Always export a config snapshot in iHelp after upgrades.
197
+
198
+ ---
199
+
200
+ ## Related Docs & Inspiration
201
+
202
+ - [Seymour Screen Excellence RS232 Protocol PDF](https://www.seymourscreenexcellence.com/) (request via dealer portal).
203
+ - [Global Caché Knowledge Base](https://globalcache.zendesk.com/).
204
+ - [Home Assistant Template Switch Cookbook](https://www.home-assistant.io/integrations/template/) for inspiration on wiring seymourlib into HA.
205
+ - [CoolTerm Serial Terminal](https://freeware.the-meiers.org/) - handy for the direct-serial smoke test.
206
+
207
+ ---
208
+
209
+ ## Contributing
210
+
211
+ - Fork, create a feature branch, and open a PR (tests + type checks 🚦 required).
212
+ - `pre-commit run` before pushing.
213
+ - Issues and hardware findings are welcome - real-world serial logs are gold for regression tests.
214
+
215
+ Need something else? Open a discussion or ping via Issues and we’ll figure it out together. 🙌
@@ -0,0 +1,169 @@
1
+ # seymourlib
2
+
3
+ [![CI](https://img.shields.io/github/actions/workflow/status/richard-berg/seymourlib/ci.yml?label=CI&logo=github)](https://github.com/richard-berg/seymourlib/actions/workflows/ci.yml)
4
+ [![Coverage](https://img.shields.io/codecov/c/github/richard-berg/seymourlib?logo=codecov)](https://codecov.io/gh/richard-berg/seymourlib)
5
+ [![PyPI](https://img.shields.io/pypi/v/seymourlib?logo=pypi)](https://pypi.org/project/seymourlib/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
7
+
8
+ Python client for Seymour masking screens, connected via direct serial or Global Caché iTach IP2SL. Built for rock-solid control loops, [Home Assistant](https://www.home-assistant.io/) integrations, and quick bench testing. 😎
9
+
10
+ ---
11
+
12
+ ## Highlights
13
+
14
+ - Async-first client and transport abstractions (TCP/IP2SL vs native serial) with consistent APIs.
15
+ - Protocol helpers that mirror the official Seymour RS232 spec, including parsing/validation utilities.
16
+ - `seymourctl` CLI for one-off commands, scripting, and smoke tests in CI.
17
+ - Batteries-included retry logic (`tenacity`), timeout handling, and graceful cancellation via `anyio`.
18
+
19
+ ## Architecture at a Glance
20
+
21
+ ```mermaid
22
+ flowchart TB
23
+ App[Your automation / HA stack] -->|async API| Client[SeymourClient]
24
+ Client --> Protocol[Protocol helpers]
25
+ Client --> Transport
26
+ Transport -->|TCP 4999| IP2SL[Global Caché IP2SL]
27
+ Transport -->|RS232| Screen[Seymour Masking Screen]
28
+ IP2SL -->|RS232| Screen
29
+ ```
30
+
31
+ ## Installation
32
+
33
+ ### Requirements
34
+
35
+ - Python 3.11+
36
+ - `uv` >= 0.2 (recommended) or classic `pip`
37
+
38
+ ### Using uv (dev + extras)
39
+
40
+ ```bash
41
+ uv sync --all-extras
42
+ ```
43
+
44
+ ### Using pip (runtime only)
45
+
46
+ ```bash
47
+ python -m venv .venv
48
+ source .venv/bin/activate # or .venv\Scripts\activate on Windows
49
+ pip install "seymourlib[serial]"
50
+ ```
51
+
52
+ > 💡 The optional `serial` extra pulls in `pyserial-asyncio` so the same client works over USB/RS232 without the IP bridge.
53
+
54
+ ---
55
+
56
+ ## First-Time Setup Checklist
57
+
58
+ 1. **Clone & bootstrap**
59
+ - `git clone https://github.com/richard-berg/seymourlib && cd seymourlib`
60
+ - `uv sync --all-extras`
61
+ 2. **Sanity-test the library**
62
+ - `uv run pytest` for local regression.
63
+ - `uv run seymourctl -v status` to hit your target once hardware is reachable.
64
+ 3. **Wire up hardware**
65
+ - Confirm straight-through RS232 between IP2SL and the Seymour control port.
66
+ - For direct USB serial, a FTDI-based adapter keeps timing stable.
67
+ 4. **Pick your transport**
68
+ - `TCPTransport(host, port=4999)` for IP2SL.
69
+ - `SerialTransport(port="COM5")` for direct connection (requires `[serial]`).
70
+
71
+ ---
72
+
73
+ ## Usage Examples
74
+
75
+ ### Python API
76
+
77
+ ```python
78
+ import asyncio
79
+ from seymourlib.client import SeymourClient
80
+ from seymourlib.transport import TCPTransport
81
+
82
+ async def main() -> None:
83
+ async with SeymourClient(TCPTransport("192.168.1.70")) as client:
84
+ status = await client.get_status()
85
+ print(status)
86
+
87
+ asyncio.run(main())
88
+ ```
89
+
90
+ ### CLI
91
+
92
+ ```bash
93
+ uv run seymourctl --host 192.168.1.70 status
94
+ uv run seymourctl --host 192.168.1.70 preset apply 235
95
+ uv run seymourctl --help
96
+ ```
97
+
98
+ ---
99
+
100
+ ## IP2SL Setup & Diagnostics
101
+
102
+ ### 1. Test direct serial first
103
+
104
+ - Connect a laptop directly to the Seymour RS232 port with a known-good USB adapter.
105
+ - Use `RealTerm`, `CoolTerm`, or any tty tool (115200 8N1 by default - verify via Seymour docs) to send a `PS?` (position status) command.
106
+ - Once commands succeed locally, you know the projector + cable + command syntax are correct before adding the network hop.
107
+
108
+ ### 2. Discover the IP2SL via iHelp
109
+
110
+ - Download [Global Caché iHelp](https://www.globalcache.com/files/software/iHelp.zip) and run it on the same subnet.
111
+ - Press **Scan** to locate the IP2SL; note the MAC, firmware, and current IP.
112
+ - If nothing shows up, temporarily disable host firewalls or plug directly into a laptop + small DHCP scope.
113
+
114
+ ### 3. Pin the network configuration
115
+
116
+ - Point a browser at `http://<your-ip>/` (from step 2) if you want a point-and-click GUI for DHCP/static IP, firmware, and reboot controls.
117
+ - Otherwise, install [Global Caché iTest](https://www.globalcache.com/files/software/iTest.zip).
118
+ - Use iTest or telnet into port **4998** (the configuration/control port).
119
+ - Send `set dhcp 0`, `set ip <static>`, `set mask <subnet>`, `set gateway <gw>`, then `save` to burn settings.
120
+ - Reboot (power cycle or `reboot` command) and confirm the device responds on the static IP.
121
+ - Document the MAC/IP in your DHCP reservations to avoid future collisions.
122
+
123
+ ### 4. Lock the serial parameters
124
+
125
+ - Open the IP2SL web UI and switch to the **Serial** tab, or telnet/iTest into port **4998** for command-line configuration.
126
+ - Ensure the port is set to **115200 baud, 8 data bits, no parity, 1 stop bit** to match Seymour’s RS232 spec.
127
+ - Saving via the UI writes immediately; if you used the control port, run `set baud 115200`, `set data 8`, `set parity 0`, `set stop 1`, then `save` and reboot so the bridge always boots with the correct framing.
128
+
129
+ ### 5. Exercise the serial bridge with iTest
130
+
131
+ - Open iTest (or `telnet`)
132
+ - Target port **4999** on the static IP, choose **RAW** mode, and click **Connect**.
133
+ - Send a few simple commands (e.g. `[01S]`, `[01P]`). The response should echo immediately.
134
+ - If latency creeps in, verify telnet keep-alives/device busy LEDs. Keep the window open while you walk through automation flows to watch the live traffic.
135
+
136
+ ### 6. Promote to seymourlib
137
+
138
+ - Update your `.env` / config with the same host/port verified above.
139
+ - Start with `uv run seymourctl -v status` (verbose logging shows full request/response frames).
140
+ - Flip to automation ([Home Assistant](https://www.home-assistant.io/), Homebridge, etc.) once CLI calls are boringly reliable.
141
+
142
+ ---
143
+
144
+ ## Troubleshooting & Field Notes
145
+
146
+ - ⚡ **No response over TCP but serial works** - Ensure port 4999 is open on local firewalls and that the IP2SL LED blinks on connect; if not, recheck the static IP settings from step 3.
147
+ - 🔌 **Commands hang after a day** - The IP2SL can queue stale sockets; send `set rs232disconnect 1` over port 4998 so idle TCP clients auto-close.
148
+ - 🔁 **Race conditions from HA automations** - Wrap your automations with seymourlib's async context manager so only one command pipeline exists per transport.
149
+ - 🧪 **Need deeper diagnostics** - Add `--verbose` to `seymourctl` to dump protocol frames, or [enable debug logging](https://docs.python.org/3/library/logging.html) to capture per-request timestamps.
150
+ - 🛠️ **Firmware drift** - Global Caché publishes release notes; mismatched firmware sometimes defaults back to DHCP on reboot. Always export a config snapshot in iHelp after upgrades.
151
+
152
+ ---
153
+
154
+ ## Related Docs & Inspiration
155
+
156
+ - [Seymour Screen Excellence RS232 Protocol PDF](https://www.seymourscreenexcellence.com/) (request via dealer portal).
157
+ - [Global Caché Knowledge Base](https://globalcache.zendesk.com/).
158
+ - [Home Assistant Template Switch Cookbook](https://www.home-assistant.io/integrations/template/) for inspiration on wiring seymourlib into HA.
159
+ - [CoolTerm Serial Terminal](https://freeware.the-meiers.org/) - handy for the direct-serial smoke test.
160
+
161
+ ---
162
+
163
+ ## Contributing
164
+
165
+ - Fork, create a feature branch, and open a PR (tests + type checks 🚦 required).
166
+ - `pre-commit run` before pushing.
167
+ - Issues and hardware findings are welcome - real-world serial logs are gold for regression tests.
168
+
169
+ Need something else? Open a discussion or ping via Issues and we’ll figure it out together. 🙌
@@ -0,0 +1,114 @@
1
+ [build-system]
2
+ requires = ["setuptools>=65", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "seymourlib"
7
+ version = "0.1.0"
8
+ description = "Python client for Seymour masking screens, connected via direct serial or Global Caché iTach IP2SL"
9
+ keywords = ["seymour", "masking", "screen", "serial", "itach", "ip2sl", "home-assistant"]
10
+ authors = [{name = "Richard Berg", email = "ars@richardberg.net"}]
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "Programming Language :: Python :: 3 :: Only",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Topic :: Home Automation",
18
+ ]
19
+ license = "MIT"
20
+ license-files = ["LICENSE"]
21
+ readme = "README.md"
22
+ requires-python = ">=3.11"
23
+ dependencies = [
24
+ "anyio>=3.4",
25
+ "attrs>=25.4.0",
26
+ "tenacity>=8.0",
27
+ "async-typer>=0.1.10",
28
+ ]
29
+
30
+ [project.urls]
31
+ omepage = "https://github.com/richard-berg/seymourlib"
32
+ source = "https://github.com/richard-berg/seymourlib.git"
33
+ issues = "https://github.com/richard-berg/seymourlib/issues"
34
+
35
+
36
+ [project.optional-dependencies]
37
+ serial = [
38
+ "pyserial_asyncio>=0.6",
39
+ ]
40
+ dev = [
41
+ "pytest>=7",
42
+ "pytest-asyncio>=0.23",
43
+ "pytest-timeout>=2",
44
+ "coverage>=7",
45
+ "mypy>=1.10",
46
+ "ruff>=0.6",
47
+ "types-setuptools",
48
+ "pyserial_asyncio>=0.6",
49
+ ]
50
+ lint = [
51
+ "ruff>=0.6",
52
+ ]
53
+ typecheck = [
54
+ "mypy>=1.10",
55
+ ]
56
+ test = [
57
+ "pytest>=7",
58
+ "pytest-asyncio>=0.23",
59
+ "pytest-timeout>=2",
60
+ "coverage>=7",
61
+ "pyserial_asyncio>=0.6",
62
+ ]
63
+
64
+ [project.scripts]
65
+ seymourctl = "seymourlib.cli:main"
66
+
67
+ [tool.ruff]
68
+ line-length = 100
69
+ target-version = "py312"
70
+ fix = true
71
+ unsafe-fixes = false
72
+ lint.select = [
73
+ "E", # pycodestyle errors
74
+ "F", # pyflakes
75
+ "W", # warnings
76
+ "I", # import sorting
77
+ "UP", # pyupgrade
78
+ "B", # bugbear
79
+ "ASYNC", # async best practices
80
+ ]
81
+ lint.ignore = [
82
+ "E501", # line length handled separately
83
+ ]
84
+
85
+ [tool.ruff.format]
86
+ quote-style = "double"
87
+ indent-style = "space"
88
+ line-ending = "lf"
89
+
90
+ # ----------------------------------------
91
+ # mypy configuration
92
+ # ----------------------------------------
93
+ [tool.mypy]
94
+ python_version = "3.12"
95
+ warn_unused_configs = true
96
+ warn_redundant_casts = true
97
+ warn_unused_ignores = true
98
+ warn_return_any = true
99
+ warn_unreachable = true
100
+ strict = true
101
+
102
+ # Ignore missing type hints in dependencies, except ours
103
+ ignore_missing_imports = true
104
+
105
+ [tool.setuptools.package-data]
106
+ "seymourlib" = ["py.typed"]
107
+
108
+ # ----------------------------------------
109
+ # Pytest configuration
110
+ # ----------------------------------------
111
+ [tool.pytest.ini_options]
112
+ addopts = "-q --timeout=10"
113
+ asyncio_mode = "auto"
114
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes