menuet 1.0.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,11 @@
1
+ __pycache__/
2
+ *.py[oc]
3
+ build/
4
+ dist/
5
+ site/
6
+ wheels/
7
+ *.egg-info
8
+ .coverage*
9
+ .venv/
10
+ .cache/
11
+ .rumdl_cache/
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ Versions follow [Semantic Versioning](https://semver.org)
4
+ (`<major>.<minor>.<patch>`).
5
+
6
+ This file is managed by [towncrier](https://towncrier.readthedocs.io),
7
+ and its format is based on [keep a changelog](https://keepachangelog.com).
8
+
9
+ Changes for the upcoming release can be found in the
10
+ [changelog.d](https://codeberg.org/tahv/menuet/src/branch/main/changelog.d)
11
+ directory in the repo.
12
+
13
+ <!-- towncrier release notes start -->
14
+
15
+ ## [1.0.0](https://codeberg.org/tahv/menuet/releases/tag/1.0.0) - 2026-04-06
16
+
17
+ ### Enhancements
18
+
19
+ - [!1](https://codeberg.org/tahv/menuet/pulls/1):
20
+ Initial release.
@@ -0,0 +1,79 @@
1
+ # Contributing
2
+
3
+ ## Project commands
4
+
5
+ The easiest way to run project commands is to
6
+ [install just](https://just.systems/man/en/installation.html).
7
+
8
+ For example, the `rust-just` Python package can be installed with
9
+ [`uv`](https://docs.astral.sh/uv/concepts/tools/):
10
+
11
+ ```console
12
+ uv tool install rust-just
13
+ just
14
+ ```
15
+
16
+ Or executed without installation with
17
+ [`uvx`](https://docs.astral.sh/uv/guides/tools/):
18
+
19
+ ```console
20
+ uvx --from rust-just just
21
+ ```
22
+
23
+ Running `just` without any arguments list available recipes in the
24
+ [justfile](./justfile) at the root of the repo.
25
+
26
+ ```console
27
+ just
28
+ ```
29
+
30
+ ## Local development environment
31
+
32
+ The project virtual environment can be created with `uv`:
33
+
34
+ ```console
35
+ uv sync --all-extras
36
+ ```
37
+
38
+ Or with this `just` recipe:
39
+
40
+ ```console
41
+ just sync
42
+ ```
43
+
44
+ If you don't want to use `uv` or `just`, you can use pip 25.1
45
+ (that added support for dependency groups)
46
+ or newer and install the dependencies manually:
47
+
48
+ ```console
49
+ pip install --editable .[copy,qt] --group dev
50
+ ```
51
+
52
+ ## Changelog
53
+
54
+ We use [towncrier](https://towncrier.readthedocs.io/) to manage our
55
+ [CHANGELOG.md](./CHANGELOG.md).
56
+
57
+ To create a news fragment,
58
+ run the following command and follow the instructions:
59
+
60
+ ```console
61
+ towncrier create --no-edit
62
+ ```
63
+
64
+ Or use this `just` recipe:
65
+
66
+ ```console
67
+ just news
68
+ ```
69
+
70
+ Alternatively, you don't need to install towncrier,
71
+ you just have to abide by a few simple rules:
72
+
73
+ For each merge request, add a new file into the `changelog.d` directory with a
74
+ filename adhering to the schema: `mr#.(break|feat|fix|doc|other|chore).md`.
75
+ For example, `changelog.d/123.feat.md` for a feature
76
+ that is proposed in pull request `#123`.
77
+
78
+ See `tool.towncrier.types` in the [`pyproject.toml`](./pyproject.toml)
79
+ for the list of fragment types.
menuet-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thibaud Gambier
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.
menuet-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.4
2
+ Name: menuet
3
+ Version: 1.0.0
4
+ Summary: Declarative menu builder for DCC applications
5
+ Project-URL: Repository, https://codeberg.org/tahv/menuet
6
+ Author: Thibaud Gambier
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: attrs>=26.1.0
12
+ Requires-Dist: tomli>=2.3.0; python_version < '3.11'
13
+ Requires-Dist: typing-extensions>=4.15.0
14
+ Provides-Extra: copy
15
+ Requires-Dist: copykitten>=2.0.0; extra == 'copy'
16
+ Provides-Extra: qt
17
+ Requires-Dist: pyside6>=6.11.0; extra == 'qt'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # menuet
21
+
22
+ [![Source](https://img.shields.io/badge/Codeberg-%232185D0?logo=codeberg&logoColor=white)](https://codeberg.org/tahv/menuet)
23
+ [![Documentation](https://img.shields.io/badge/Documentation-teal)](https://tahv.codeberg.page/menuet/)
24
+
25
+ Menuet (`/mə.nɥɛ/`) is a declarative menu builder for DCC applications.
26
+
27
+ ## Features
28
+
29
+ - Supports, 3ds Max, Maya, MotionBuilder and other any PySide6 application.
30
+ - Load menu from a TOML or JSON configuration, from a dict, from entry points,
31
+ or build it programmatically.
32
+ - Declare one or more menus in a dedicated `.toml` file.
33
+ - Compose menu from multiple `.toml` files.
34
+ - Declare a menu in a `pyproject.toml` directly.
35
+
36
+ ## Installation
37
+
38
+ ```console
39
+ pip install menuet
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ Create a menu configuration in [TOML](https://toml.io/) format.
45
+
46
+ ```toml
47
+ # menu.toml
48
+ [[action]]
49
+ id = "print-hello"
50
+ label = "Print Hello"
51
+ cb = "print('Hello')"
52
+ group = "Some Separator"
53
+
54
+ [[action]]
55
+ id = "open-gui"
56
+ label = "Open GUI"
57
+ cb = "ep:myapp.gui:open_gui"
58
+ menu = ["Foo", "Bar"]
59
+ ```
60
+
61
+ Load the above configuration into a `Model` and pass
62
+ that model to a Menu Builder to create a menu.
63
+
64
+ ```python
65
+ from pathlib import Path
66
+ from menuet.builders.text import Render, TextMenuBuilder
67
+ from menuet.model import Model, loads
68
+
69
+ model = Model()
70
+ loads(Path("menu.toml").read_text(), model)
71
+
72
+ builder = TextMenuBuilder(model, root_menu="Demo", render=Render.UTF8)
73
+ print(builder.build())
74
+ ```
75
+
76
+ ```text
77
+ Demo
78
+ ├── Foo
79
+ │ └── Bar
80
+ │ └── Open GUI
81
+ ├── Some Separator ───
82
+ └── Print Hello
83
+ ```
84
+
85
+ See the [documentation](https://tahv.codeberg.page/menuet/)
86
+ for more advanced patterns.
87
+
88
+ ## Contributing
89
+
90
+ For guidance on setting up a development environment and contributing, see
91
+ [CONTRIBUTING.md](https://codeberg.org/tahv/menuet/src/branch/main/CONTRIBUTING.md).
menuet-1.0.0/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # menuet
2
+
3
+ [![Source](https://img.shields.io/badge/Codeberg-%232185D0?logo=codeberg&logoColor=white)](https://codeberg.org/tahv/menuet)
4
+ [![Documentation](https://img.shields.io/badge/Documentation-teal)](https://tahv.codeberg.page/menuet/)
5
+
6
+ Menuet (`/mə.nɥɛ/`) is a declarative menu builder for DCC applications.
7
+
8
+ ## Features
9
+
10
+ - Supports, 3ds Max, Maya, MotionBuilder and other any PySide6 application.
11
+ - Load menu from a TOML or JSON configuration, from a dict, from entry points,
12
+ or build it programmatically.
13
+ - Declare one or more menus in a dedicated `.toml` file.
14
+ - Compose menu from multiple `.toml` files.
15
+ - Declare a menu in a `pyproject.toml` directly.
16
+
17
+ ## Installation
18
+
19
+ ```console
20
+ pip install menuet
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ Create a menu configuration in [TOML](https://toml.io/) format.
26
+
27
+ ```toml
28
+ # menu.toml
29
+ [[action]]
30
+ id = "print-hello"
31
+ label = "Print Hello"
32
+ cb = "print('Hello')"
33
+ group = "Some Separator"
34
+
35
+ [[action]]
36
+ id = "open-gui"
37
+ label = "Open GUI"
38
+ cb = "ep:myapp.gui:open_gui"
39
+ menu = ["Foo", "Bar"]
40
+ ```
41
+
42
+ Load the above configuration into a `Model` and pass
43
+ that model to a Menu Builder to create a menu.
44
+
45
+ ```python
46
+ from pathlib import Path
47
+ from menuet.builders.text import Render, TextMenuBuilder
48
+ from menuet.model import Model, loads
49
+
50
+ model = Model()
51
+ loads(Path("menu.toml").read_text(), model)
52
+
53
+ builder = TextMenuBuilder(model, root_menu="Demo", render=Render.UTF8)
54
+ print(builder.build())
55
+ ```
56
+
57
+ ```text
58
+ Demo
59
+ ├── Foo
60
+ │ └── Bar
61
+ │ └── Open GUI
62
+ ├── Some Separator ───
63
+ └── Print Hello
64
+ ```
65
+
66
+ See the [documentation](https://tahv.codeberg.page/menuet/)
67
+ for more advanced patterns.
68
+
69
+ ## Contributing
70
+
71
+ For guidance on setting up a development environment and contributing, see
72
+ [CONTRIBUTING.md](https://codeberg.org/tahv/menuet/src/branch/main/CONTRIBUTING.md).
@@ -0,0 +1,27 @@
1
+ {%- if versiondata["version"] == "main" -%}
2
+ ## Changes for the Upcoming Release
3
+ {% else -%}
4
+ ## [{{ versiondata["version"] }}](https://codeberg.org/tahv/menuet/releases/tag/{{ versiondata["version"] }}) - {{ versiondata["date"] }}
5
+ {% endif %}
6
+ {% for section, _ in sections.items() %}
7
+ {% if sections[section] %}
8
+ {% for category, val in definitions.items() if category in sections[section] %}
9
+
10
+ ### {{ definitions[category]['name'] }}
11
+
12
+ {% for text, issues in sections[section][category].items() %}
13
+ {% if ("\n\n" in text)%}
14
+ {%- set t = text.split("\n\n", 1) %}
15
+ {%- set text = [t[0], t[1]|indent(2, true)] | join("\n\n") + "\n" %}
16
+ {% endif %}
17
+ - {{ issues|join(',\n ') }}:
18
+ {{ text }}
19
+ {% endfor %}
20
+ {% endfor %}
21
+
22
+ {% else %}
23
+ No significant changes.
24
+
25
+
26
+ {% endif %}
27
+ {% endfor %}
@@ -0,0 +1,20 @@
1
+ ---
2
+ icon: lucide/code
3
+ ---
4
+
5
+ # API Reference
6
+
7
+ ::: menuet
8
+ options:
9
+ toc_label: "menuet"
10
+ filters: "public"
11
+
12
+ ::: menuet.builders.text
13
+ options:
14
+ toc_label: "menuet.builders.text"
15
+ filters: "public"
16
+
17
+ ::: menuet.builders.qt
18
+ options:
19
+ toc_label: "menuet.builders.qt"
20
+ filters: "public"
@@ -0,0 +1,179 @@
1
+ ---
2
+ icon: lucide/file-cog
3
+ ---
4
+
5
+ # Menu Configuration
6
+
7
+ The [`deserialize`][menuet.deserialize] function accepts a dict of `action`
8
+ and `menu` lists.
9
+
10
+ ```python
11
+ {
12
+ "action": [],
13
+ "menu": [],
14
+ }
15
+ ```
16
+
17
+ /// example
18
+
19
+ ```python
20
+ import menuet
21
+ from menuet.builders.text import Render, TextMenuBuilder
22
+
23
+ model = menuet.Model()
24
+ menuet.deserialize({
25
+ "menu": [
26
+ {
27
+ "label": "Sub-Menu",
28
+ "menu": ["My App"],
29
+ "group": "Separator",
30
+ },
31
+ ],
32
+ "action": [
33
+ {
34
+ "id": "open-gui",
35
+ "label": "Open GUI",
36
+ "cb": "import myapp; myapp.open_gui()",
37
+ "menu": ["My App", "Sub-Menu"],
38
+ },
39
+ {
40
+ "id": "print-hello",
41
+ "label": "Print Hello",
42
+ "cb": 'print("Hello")',
43
+ },
44
+ ],
45
+ model,
46
+ })
47
+
48
+ builder = TextMenuBuilder(model, root_menu="Example", render=Render.UTF8)
49
+ print(builder.build())
50
+ ```
51
+
52
+ <div class="result" markdown>
53
+
54
+ ```text
55
+ Example
56
+ ├── My App
57
+ │ ├── Separator ───
58
+ │ └── Sub-Menu
59
+ │ └── Open GUI
60
+ └── Print Hello
61
+ ```
62
+
63
+ </div>
64
+
65
+ ///
66
+
67
+ ## Action Options
68
+
69
+ The `[[action]]` tables accepts the following options:
70
+
71
+ ```toml { .copy }
72
+ [[action]] # `action` is an array of action tables
73
+ id = "my-action" # unique identifier [required]
74
+ label = "My Action" # display name
75
+ menu = ["Menu", "Sub-Menu"] # parent menus hierarchy
76
+ group = "My Group" # group related menus and actions
77
+ cb = "print('Hello !')" # action callback
78
+ desc = "Print Hello" # tooltip
79
+ icon = "icons/my-icon.png" # path to an icon
80
+ visible = true # display action in menu
81
+ enables = true # allow action to be run
82
+ ```
83
+
84
+ ## Menu Options
85
+
86
+ The `[[menu]]` tables accepts the following options:
87
+
88
+ ```toml { .copy }
89
+ [[menu]] # `menu` is an array of menu tables
90
+ label = "My Menu" # display name [required]
91
+ desc = "My App Scripts" # tooltip
92
+ menu = ["Parent Menu"] # parent menus hierarchy
93
+ group = "My Group" # group related menus and actions
94
+ icon = "icons/my-icon.png" # path to an icon
95
+ ```
96
+
97
+ Menus defined in `[[action]]` tables are created automatically.
98
+ The only reason to configure `[[menu]]` explicitly is to set an `icon`,
99
+ a `group`, or a `desc`.
100
+
101
+ ## `icon` Schemes
102
+
103
+ <!-- TODO(tga): path relative to toml config -->
104
+
105
+ The `icon` option accepts a value in the format `<path>` or `<scheme>:<value>`.
106
+
107
+ The following schemes are available:
108
+
109
+ - `path` *(default)*: takes a path to an icon file.
110
+
111
+ ```toml
112
+ icon = "icons/settings.png"
113
+
114
+ icon = "path:icons/settings.png"
115
+ ```
116
+
117
+ - `res`: load a [resource file][importlib.resources.files].
118
+ Value is in the form `res:importable.module:file.ext`.
119
+
120
+ ```toml
121
+ icon = "res:myapp.data:logo.svg"
122
+ ```
123
+
124
+ ## `cb` Schemes
125
+
126
+ The `cb` option accepts a value in the format `<script>` or `<scheme>:<value>`.
127
+
128
+ The following schemes are available:
129
+
130
+ - `exec` *(default)*: takes a Python script.
131
+
132
+ ```toml
133
+ cb = "print('Hello !')"
134
+
135
+ cb = "exec:import myapp; myapp.open_gui()"
136
+
137
+ cb = """\
138
+ from importlib.metadata import version
139
+ print(version("myapp"))
140
+ """
141
+
142
+ cb = """exec:\
143
+ import myapp
144
+ myapp.open_gui()
145
+ """
146
+ ```
147
+
148
+ - `ep`: loads an [entry point][importlib.metadata.EntryPoint].
149
+ Value is in the form `ep:importable.module:callable`.
150
+
151
+ ```toml
152
+ cb = "res:myapp.my_module:open_gui"
153
+
154
+ cb = "res:myapp:my_function"
155
+ ```
156
+
157
+ - `copy`: copy its value to the clipboard.
158
+
159
+ ```toml
160
+ cb = "copy:Lorem ipsum dolor sit amet"
161
+ ```
162
+
163
+ /// warning
164
+
165
+ The `copy` scheme requires the
166
+ [copykitten](https://github.com/klavionik/copykitten) package,
167
+ available as an extra:
168
+
169
+ ```console { .copy }
170
+ pip install menuet[copy]
171
+ ```
172
+
173
+ ///
174
+
175
+ - `url`: takes a URL and open it in the default browser.
176
+
177
+ ```toml
178
+ cb = "url:https://codeberg.org/tahv/menuet"
179
+ ```
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-music4-icon lucide-music-4"><path d="M9 18V5l12-2v13"/><path d="m9 9 12-2"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>
@@ -0,0 +1,5 @@
1
+ ---
2
+ icon: lucide/home
3
+ ---
4
+
5
+ --8<-- "README.md"