py2tosc 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,99 @@
1
+ # Changelog
2
+
3
+ Notable changes to py2tosc. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project uses [semantic versioning](https://semver.org/spec/v2.0.0.html) -- while the version is below 1.0, a minor bump may break the API.
4
+
5
+ ## [0.1.0]
6
+
7
+ First release: py2tosc is a rewrite of [tosclib](https://github.com/AlbertoV5/tosclib) 0.3.5 by Alberto Valdez; the entries below describe what changed relative to it. Scripts written against tosclib will not run against py2tosc, and there are no compatibility shims. See [Coming from tosclib](https://shakfu.github.io/py2tosc/migrating/) for a name by name mapping.
8
+
9
+ ### Addeds
10
+
11
+ - `Document`, with `load`, `loads`, `save` and `dumps` named after the `json` module's. `load` accepts a `.tosc` or an `.xml` without being told which, and `save` picks the format from the file extension.
12
+
13
+ - `Control` as the node model. Traversal returns controls, not `ET.Element`, so children no longer have to be re-wrapped by hand.
14
+
15
+ - `find`, `find_all` and `walk`, searching by name, by control type or both.
16
+
17
+ - `Control.copy`, duplicating a subtree with fresh node ids.
18
+
19
+ - `save(validate=True)` and `dumps(validate=True)`, which refuse to write a layout that has errors and raise `ValidationError` instead. Off by default.
20
+
21
+ - `validate`, an opt-in check for things TouchOSC rejects or ignores -- children on a control that cannot hold them, duplicate node ids, a property stored under the wrong type, or a format property on a control type that has no use for it. Advisory and never raises; custom properties are left alone. Every rule is corroborated against layouts the editor wrote.
22
+
23
+ - `GamepadMessage`. tosclib 0.3.x had a `ControlElements.GAMEPAD` enum member with no implementation behind it, so a layout containing a gamepad binding could not be read at all.
24
+
25
+ - `Frame` and `Color` named tuples. Colours accept normalised floats, 0-255 integers or hex strings.
26
+
27
+ - `__version__`, and an `__all__` that governs the public namespace.
28
+
29
+ - Support for reading and writing lexml version 6, the format TouchOSC 1.5 writes: the `<includes>` element and the `<noDuplicates>` message flag. Both are omitted from documents that declare an older version.
30
+
31
+ - Frames keep sub-pixel positions. TouchOSC stores frames like `x=417.439`, which earlier releases -- and the first draft of this one -- rounded to integers, moving the control.
32
+
33
+ - A test corpus of 42 layout files, including the twenty examples bundled with TouchOSC 1.5.2, spanning both format versions, and demo scripts that the test suite executes -- including a numpad built from nested layouts, a Lua script and LOCAL message wiring.
34
+
35
+ ### Changed
36
+
37
+ - **The API is `snake_case`.** `setColor` is `control.color = ...`, `findChildByName` is `find`. Property keys stay camelCase in the file, because that is what the format stores; `control.corner_radius` addresses the `cornerRadius` key.
38
+
39
+ - **Property and value data are native Python types**, not strings. `Value.locked` is a `bool`; `Property("textSize", 14).value` is `14`.
40
+
41
+ - **Reading no longer mutates the tree.** tosclib inserted empty `<messages>` and `<children>` elements into any control it wrapped.
42
+
43
+ - **Missing properties raise `AttributeError`** rather than returning `None`. Use `control.get(key)` where absence is expected.
44
+
45
+ - **Layouts are functions, not decorators.** `layout.row`, `layout.column` and `layout.grid` take the parent as an argument and return the controls they made, so nesting is ordinary function composition.
46
+
47
+ - Serialization is written directly rather than through `ElementTree`, so CDATA sections, element order and the XML declaration are preserved. Loading a layout and saving it reproduces the TouchOSC editor's own bytes exactly, in both the compressed and exported forms.
48
+
49
+ - Documentation moved from Sphinx to MkDocs.
50
+
51
+ - Packaging moved to `pyproject.toml` with the `uv_build` backend; `setup.py`, `tox.ini` and the three `requirements*.txt` files are gone.
52
+
53
+ - Releasing and publishing the documentation are driven from the Makefile rather than from CI. `make release-check` gates the declared version, the changelog entry and the state of the working tree; `make dist-check` rebuilds `dist/` from empty and validates it with `twine check --strict`; `make publish` uploads, behind a `CONFIRM=1` guard because a filename PyPI has accepted can never be reused. `make docs-deploy` pushes the documentation to `gh-pages`. Nothing is published automatically.
54
+
55
+ - CI runs the suite on Ubuntu against Python 3.10 through 3.14, and checks types, lint, a strict documentation build, and the built wheel, on every push and pull request.
56
+
57
+ ### Removed
58
+
59
+ - **numpy is no longer a dependency.** py2tosc has no runtime dependencies at all. The layout arithmetic is plain Python.
60
+
61
+ - `ElementTOSC` and the `elements`, `controls` and `tosc` modules.
62
+
63
+ - `asCtrl`, which was declared, exported, and had `pass` for a body.
64
+
65
+ ### Fixed
66
+
67
+ - `import tosclib` failed without `pyparsing`, an undeclared dependency reached by a stray `from pyparsing import Optional` that was never used. In a clean environment, `pip install tosclib` produced an unimportable package.
68
+
69
+ - Building a control with more than one message nested the second message inside the first, because the XML builder rebound its parent element inside a nested loop. An OSC and a MIDI binding on the same control produced a file TouchOSC could not load.
70
+
71
+ - MIDI bindings were written with a trigger's fields in place of the status bytes, from a leaked loop variable, and their values used a `<midivalue>` tag the format does not define. No MIDI binding tosclib produced was valid.
72
+
73
+ - `<dstID>` was written without its CDATA wrapper, unlike every other string in the format.
74
+
75
+ - Generated layouts declared `lexml version=3` and omitted `<includes>`.
76
+
77
+ - Default `connections` was five slots wide; TouchOSC 1.5 uses ten.
78
+
79
+ - Element truth-value testing, deprecated since Python 3.12.
80
+
81
+ - The test suite only passed when run from the repository root.
82
+
83
+ - CI declared its matrix key as `python-versions` but read `matrix.python-version`, so every leg silently tested the same interpreter, and the matrix targeted Python versions the package rejected.
84
+
85
+ - `numpy>=2` broke every layout: numpy 2 changed scalar `repr`, and the frames were stringified through it.
86
+
87
+ - `gridColor` was missing from XY and RADAR defaults, `textClip` and `textWrap` from TEXT, and `lines`/`linesDisplay` from XY.
88
+
89
+ - `GamepadMessage.connections` defaulted to ten characters. The gamepad field counts controllers, not network connections, and is four wide.
90
+
91
+ - `MidiType.NOTE_ON` was spelled `NOTEON`; the format uses `NOTE_ON`.
92
+
93
+ - `PAGER` carried an `x` value instead of `page`, and `ENCODER` was missing its `y`.
94
+
95
+ ## Prior history
96
+
97
+ py2tosc began as a fork of [tosclib](https://github.com/AlbertoV5/tosclib), which had twelve releases between 2022-05-20 and 2022-06-09, ending at 0.3.5. That history belongs to a different distribution and is not restated here; see [the tosclib releases](https://pypi.org/project/tosclib/#history).
98
+
99
+ [0.1.0]: https://github.com/shakfu/py2tosc/releases/tag/v0.1.0
py2tosc-0.1.0/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Alberto Valdez (AlbertoV5) -- original tosclib
4
+ Copyright (c) 2026 Shakeeb Alireza -- py2tosc
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
+
10
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
py2tosc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: py2tosc
3
+ Version: 0.1.0
4
+ Summary: Generate and edit TouchOSC layouts from Python.
5
+ Keywords: touchosc,osc,midi,tosc,hexler
6
+ Author: Shakeeb Alireza
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Multimedia :: Sound/Audio
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Project-URL: Homepage, https://github.com/shakfu/py2tosc
22
+ Project-URL: Documentation, https://shakfu.github.io/py2tosc
23
+ Project-URL: Repository, https://github.com/shakfu/py2tosc
24
+ Project-URL: Issues, https://github.com/shakfu/py2tosc/issues
25
+ Description-Content-Type: text/markdown
26
+
27
+ # py2tosc
28
+
29
+ Generate and edit TouchOSC layouts from Python.
30
+
31
+ ![Tests](https://github.com/shakfu/py2tosc/actions/workflows/tests.yaml/badge.svg) ![PyPI](https://img.shields.io/pypi/v/py2tosc) ![License](https://img.shields.io/github/license/shakfu/py2tosc)
32
+
33
+ py2tosc is a rewrite of [tosclib](https://github.com/AlbertoV5/tosclib) by [Alberto Valdez](https://github.com/AlbertoV5), whose work established the original mapping between the `.tosc` format and Python that this library is built on. The API is new and incompatible, but the knowledge of the format -- the control types, the property tables, the message layouts, and some of the tests and examples -- came from there, and is carried over with thanks. Original copyright is retained in [LICENSE](LICENSE).
34
+
35
+
36
+ **Disclaimer**: This project has no relation to Hexler, the developer of TouchOSC. Back up your layouts before editing them with third party tools.
37
+
38
+ ## [Documentation](https://shakfu.github.io/py2tosc)
39
+
40
+ ```console
41
+ $ pip install py2tosc
42
+ ```
43
+
44
+ No dependencies. Python 3.10 or newer.
45
+
46
+ ## What it does
47
+
48
+ A `.tosc` file is a zlib-compressed XML tree. py2tosc reads that tree into plain Python objects, lets you edit them, and writes it back out -- accurately enough that loading a layout and saving it again reproduces the editor's own bytes exactly, in both the compressed and exported forms.
49
+
50
+ ```python
51
+ import py2tosc
52
+
53
+ doc = py2tosc.load("mixer.tosc")
54
+
55
+ for fader in doc.find_all(type="FADER"):
56
+ fader.color = "#e76f51"
57
+ fader.corner_radius = 2.0
58
+
59
+ doc.save("mixer-restyled.tosc")
60
+ ```
61
+
62
+ Building one from scratch:
63
+
64
+ ```python
65
+ import py2tosc
66
+ from py2tosc import layout
67
+
68
+ doc = py2tosc.Document.new(frame=(0, 0, 1024, 768))
69
+
70
+ strip = py2tosc.group(name="strip", frame=(0, 0, 1024, 768))
71
+ doc.add(strip)
72
+
73
+ for index, fader in enumerate(layout.row(strip, "FADER", sizes=8)):
74
+ fader.name = f"ch{index + 1}"
75
+ fader.messages.append(py2tosc.OscMessage())
76
+
77
+ doc.save("mixer.tosc")
78
+ ```
79
+
80
+ ## Design
81
+
82
+ | Module | Holds |
83
+ |--------|-------|
84
+ | `enums` | TouchOSC's own vocabulary: control types, property types, conversions |
85
+ | `properties` | `Property`, `Frame`, `Color`, and the `snake_case` to camelCase mapping |
86
+ | `messages` | `Value`, `OscMessage`, `MidiMessage`, `LocalMessage`, `GamepadMessage` and their parts |
87
+ | `defaults` | The default property set for each control type |
88
+ | `control` | `Control`, the node model, plus a factory per control type |
89
+ | `codec` | Reading and writing the `.tosc` XML dialect, CDATA included |
90
+ | `document` | `Document`, `load`, `save`, `dumps` |
91
+ | `layout` | Row, column and grid arrangement, in plain arithmetic |
92
+
93
+ Property keys are camelCase in the file because that is what TouchOSC stores. The Python API is `snake_case` and translates at the boundary, so `control.corner_radius` addresses the `cornerRadius` key.
94
+
95
+ ## Contributing
96
+
97
+ ```console
98
+ $ make install # install the package and dev dependencies
99
+ $ make test # run the test suite
100
+ $ make docs-serve # serve the documentation with live reload
101
+ ```
102
+
103
+ `make help` lists the rest. The project uses [uv](https://docs.astral.sh/uv/) for environments, building and publishing.
104
+
105
+ ### Releasing
106
+
107
+ 1. Bump `version` in `pyproject.toml` and `__version__` in `src/py2tosc/__init__.py` -- a test fails if they disagree.
108
+
109
+ 2. Date the release's section in `CHANGELOG.md`.
110
+
111
+ 3. `make release-check`, then `make tag` and `git push origin vX.Y.Z`.
112
+
113
+ 4. `make publish-test` to rehearse against TestPyPI, then `make publish CONFIRM=1`.
114
+
115
+ Publishing is manual and irreversible: a filename PyPI has accepted cannot be reused even after a delete, and no workflow re-checks the tag or the tree first. That makes `make release-check` in step 3 the only gate, so run it on a clean checkout. Both publish targets rebuild `dist/` from scratch and validate it with `twine check --strict` before uploading, and both need credentials in `~/.pypirc` or `TWINE_USERNAME`/`TWINE_PASSWORD`.
116
+
117
+ Documentation is published the same way, with `make docs-deploy`. Nothing deploys it automatically.
118
+
119
+ Bug reports and pull requests are welcome, including for the documentation.
@@ -0,0 +1,93 @@
1
+ # py2tosc
2
+
3
+ Generate and edit TouchOSC layouts from Python.
4
+
5
+ ![Tests](https://github.com/shakfu/py2tosc/actions/workflows/tests.yaml/badge.svg) ![PyPI](https://img.shields.io/pypi/v/py2tosc) ![License](https://img.shields.io/github/license/shakfu/py2tosc)
6
+
7
+ py2tosc is a rewrite of [tosclib](https://github.com/AlbertoV5/tosclib) by [Alberto Valdez](https://github.com/AlbertoV5), whose work established the original mapping between the `.tosc` format and Python that this library is built on. The API is new and incompatible, but the knowledge of the format -- the control types, the property tables, the message layouts, and some of the tests and examples -- came from there, and is carried over with thanks. Original copyright is retained in [LICENSE](LICENSE).
8
+
9
+
10
+ **Disclaimer**: This project has no relation to Hexler, the developer of TouchOSC. Back up your layouts before editing them with third party tools.
11
+
12
+ ## [Documentation](https://shakfu.github.io/py2tosc)
13
+
14
+ ```console
15
+ $ pip install py2tosc
16
+ ```
17
+
18
+ No dependencies. Python 3.10 or newer.
19
+
20
+ ## What it does
21
+
22
+ A `.tosc` file is a zlib-compressed XML tree. py2tosc reads that tree into plain Python objects, lets you edit them, and writes it back out -- accurately enough that loading a layout and saving it again reproduces the editor's own bytes exactly, in both the compressed and exported forms.
23
+
24
+ ```python
25
+ import py2tosc
26
+
27
+ doc = py2tosc.load("mixer.tosc")
28
+
29
+ for fader in doc.find_all(type="FADER"):
30
+ fader.color = "#e76f51"
31
+ fader.corner_radius = 2.0
32
+
33
+ doc.save("mixer-restyled.tosc")
34
+ ```
35
+
36
+ Building one from scratch:
37
+
38
+ ```python
39
+ import py2tosc
40
+ from py2tosc import layout
41
+
42
+ doc = py2tosc.Document.new(frame=(0, 0, 1024, 768))
43
+
44
+ strip = py2tosc.group(name="strip", frame=(0, 0, 1024, 768))
45
+ doc.add(strip)
46
+
47
+ for index, fader in enumerate(layout.row(strip, "FADER", sizes=8)):
48
+ fader.name = f"ch{index + 1}"
49
+ fader.messages.append(py2tosc.OscMessage())
50
+
51
+ doc.save("mixer.tosc")
52
+ ```
53
+
54
+ ## Design
55
+
56
+ | Module | Holds |
57
+ |--------|-------|
58
+ | `enums` | TouchOSC's own vocabulary: control types, property types, conversions |
59
+ | `properties` | `Property`, `Frame`, `Color`, and the `snake_case` to camelCase mapping |
60
+ | `messages` | `Value`, `OscMessage`, `MidiMessage`, `LocalMessage`, `GamepadMessage` and their parts |
61
+ | `defaults` | The default property set for each control type |
62
+ | `control` | `Control`, the node model, plus a factory per control type |
63
+ | `codec` | Reading and writing the `.tosc` XML dialect, CDATA included |
64
+ | `document` | `Document`, `load`, `save`, `dumps` |
65
+ | `layout` | Row, column and grid arrangement, in plain arithmetic |
66
+
67
+ Property keys are camelCase in the file because that is what TouchOSC stores. The Python API is `snake_case` and translates at the boundary, so `control.corner_radius` addresses the `cornerRadius` key.
68
+
69
+ ## Contributing
70
+
71
+ ```console
72
+ $ make install # install the package and dev dependencies
73
+ $ make test # run the test suite
74
+ $ make docs-serve # serve the documentation with live reload
75
+ ```
76
+
77
+ `make help` lists the rest. The project uses [uv](https://docs.astral.sh/uv/) for environments, building and publishing.
78
+
79
+ ### Releasing
80
+
81
+ 1. Bump `version` in `pyproject.toml` and `__version__` in `src/py2tosc/__init__.py` -- a test fails if they disagree.
82
+
83
+ 2. Date the release's section in `CHANGELOG.md`.
84
+
85
+ 3. `make release-check`, then `make tag` and `git push origin vX.Y.Z`.
86
+
87
+ 4. `make publish-test` to rehearse against TestPyPI, then `make publish CONFIRM=1`.
88
+
89
+ Publishing is manual and irreversible: a filename PyPI has accepted cannot be reused even after a delete, and no workflow re-checks the tag or the tree first. That makes `make release-check` in step 3 the only gate, so run it on a clean checkout. Both publish targets rebuild `dist/` from scratch and validate it with `twine check --strict` before uploading, and both need credentials in `~/.pypirc` or `TWINE_USERNAME`/`TWINE_PASSWORD`.
90
+
91
+ Documentation is published the same way, with `make docs-deploy`. Nothing deploys it automatically.
92
+
93
+ Bug reports and pull requests are welcome, including for the documentation.
@@ -0,0 +1,76 @@
1
+ [project]
2
+ name = "py2tosc"
3
+ version = "0.1.0"
4
+ description = "Generate and edit TouchOSC layouts from Python."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ keywords = [
10
+ "touchosc",
11
+ "osc",
12
+ "midi",
13
+ "tosc",
14
+ "hexler",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: Multimedia :: Sound/Audio",
27
+ "Typing :: Typed",
28
+ ]
29
+ dependencies = []
30
+
31
+ [[project.authors]]
32
+ name = "Shakeeb Alireza"
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/shakfu/py2tosc"
36
+ Documentation = "https://shakfu.github.io/py2tosc"
37
+ Repository = "https://github.com/shakfu/py2tosc"
38
+ Issues = "https://github.com/shakfu/py2tosc/issues"
39
+
40
+ [build-system]
41
+ requires = ["uv_build>=0.12.1,<0.13"]
42
+ build-backend = "uv_build"
43
+
44
+ [dependency-groups]
45
+ dev = [
46
+ "pytest>=8.0",
47
+ "pytest-cov>=5.0",
48
+ "mypy>=1.11",
49
+ "pillow>=10.0",
50
+ "ruff>=0.16.1",
51
+ "twine>=7.0.0",
52
+ ]
53
+ docs = [
54
+ "mkdocs>=1.6",
55
+ "mkdocs-material>=9.5",
56
+ "mkdocstrings[python]>=0.26",
57
+ ]
58
+
59
+ [tool.uv]
60
+ default-groups = [
61
+ "dev",
62
+ "docs",
63
+ ]
64
+
65
+ [tool.uv.build-backend]
66
+ source-include = ["CHANGELOG.md"]
67
+
68
+ [tool.pytest.ini_options]
69
+ testpaths = ["tests"]
70
+ addopts = "-W error::DeprecationWarning"
71
+
72
+ [tool.mypy]
73
+ python_version = "3.10"
74
+ packages = ["py2tosc"]
75
+ strict_optional = true
76
+ warn_unused_ignores = true
@@ -0,0 +1,72 @@
1
+ [project]
2
+ name = "py2tosc"
3
+ version = "0.1.0"
4
+ description = "Generate and edit TouchOSC layouts from Python."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Shakeeb Alireza" }]
10
+ keywords = ["touchosc", "osc", "midi", "tosc", "hexler"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Programming Language :: Python :: 3.14",
21
+ "Topic :: Multimedia :: Sound/Audio",
22
+ "Typing :: Typed",
23
+ ]
24
+
25
+ # py2tosc has no runtime dependencies. It needs nothing beyond the standard
26
+ # library, which is the point of dropping numpy in 1.0.
27
+ dependencies = []
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/shakfu/py2tosc"
31
+ Documentation = "https://shakfu.github.io/py2tosc"
32
+ Repository = "https://github.com/shakfu/py2tosc"
33
+ Issues = "https://github.com/shakfu/py2tosc/issues"
34
+
35
+ [build-system]
36
+ requires = ["uv_build>=0.12.1,<0.13"]
37
+ build-backend = "uv_build"
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "pytest>=8.0",
42
+ "pytest-cov>=5.0",
43
+ "mypy>=1.11",
44
+ # Only the image converter demo needs this, but the demo is tested.
45
+ "pillow>=10.0",
46
+ "ruff>=0.16.1",
47
+ "twine>=7.0.0",
48
+ ]
49
+ docs = [
50
+ "mkdocs>=1.6",
51
+ "mkdocs-material>=9.5",
52
+ "mkdocstrings[python]>=0.26",
53
+ ]
54
+
55
+ [tool.uv.build-backend]
56
+ # Ship the changelog in the sdist alongside README and LICENSE.
57
+ source-include = ["CHANGELOG.md"]
58
+
59
+ [tool.uv]
60
+ # Both groups are installed by a bare `uv sync`, so `make docs` and `make test`
61
+ # work without having to name a group.
62
+ default-groups = ["dev", "docs"]
63
+
64
+ [tool.pytest.ini_options]
65
+ testpaths = ["tests"]
66
+ addopts = "-W error::DeprecationWarning"
67
+
68
+ [tool.mypy]
69
+ python_version = "3.10"
70
+ packages = ["py2tosc"]
71
+ strict_optional = true
72
+ warn_unused_ignores = true
@@ -0,0 +1,110 @@
1
+ """Generate and edit TouchOSC layouts from Python.
2
+
3
+ ```python
4
+ import py2tosc
5
+
6
+ doc = py2tosc.load("layout.tosc")
7
+ for fader in doc.find_all(type="FADER"):
8
+ fader.color = "#e76f51"
9
+ doc.save("out.tosc")
10
+ ```
11
+
12
+ This project has no relation to Hexler, the developer of TouchOSC. Back up your
13
+ layouts before editing them with third party tools.
14
+ """
15
+
16
+ from . import layout
17
+ from .control import (
18
+ Control,
19
+ box,
20
+ button,
21
+ encoder,
22
+ fader,
23
+ grid,
24
+ group,
25
+ label,
26
+ pager,
27
+ radar,
28
+ radial,
29
+ radio,
30
+ text,
31
+ xy,
32
+ )
33
+ from .document import Document, dumps, load, loads, save
34
+ from .enums import (
35
+ ControlType,
36
+ Conversion,
37
+ MidiType,
38
+ PartialType,
39
+ PropertyType,
40
+ TriggerCondition,
41
+ )
42
+ from .messages import (
43
+ GamepadMessage,
44
+ LocalMessage,
45
+ Message,
46
+ MidiCommand,
47
+ MidiMessage,
48
+ MidiValue,
49
+ OscMessage,
50
+ Partial,
51
+ Trigger,
52
+ Value,
53
+ )
54
+ from .properties import Color, Frame, Property, to_color, to_frame
55
+ from .validate import Issue, ValidationError, validate
56
+
57
+ #: Keep in step with `version` in pyproject.toml, which the build backend reads
58
+ #: and which `uv_build` requires to be static. `test_version_is_declared_once`
59
+ #: fails if the two drift apart.
60
+ __version__ = "0.1.0"
61
+
62
+ # Sorted rather than grouped by topic, because RUF022 asks for it and the
63
+ # grouping lives in the API reference instead. See docs/api/.
64
+ __all__ = [
65
+ "Color",
66
+ "Control",
67
+ "ControlType",
68
+ "Conversion",
69
+ "Document",
70
+ "Frame",
71
+ "GamepadMessage",
72
+ "Issue",
73
+ "LocalMessage",
74
+ "Message",
75
+ "MidiCommand",
76
+ "MidiMessage",
77
+ "MidiType",
78
+ "MidiValue",
79
+ "OscMessage",
80
+ "Partial",
81
+ "PartialType",
82
+ "Property",
83
+ "PropertyType",
84
+ "Trigger",
85
+ "TriggerCondition",
86
+ "ValidationError",
87
+ "Value",
88
+ "__version__",
89
+ "box",
90
+ "button",
91
+ "dumps",
92
+ "encoder",
93
+ "fader",
94
+ "grid",
95
+ "group",
96
+ "label",
97
+ "layout",
98
+ "load",
99
+ "loads",
100
+ "pager",
101
+ "radar",
102
+ "radial",
103
+ "radio",
104
+ "save",
105
+ "text",
106
+ "to_color",
107
+ "to_frame",
108
+ "validate",
109
+ "xy",
110
+ ]