terminator-dbus 0.1.0__py3-none-any.whl

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,29 @@
1
+ # SPDX-License-Identifier: ISC
2
+ #
3
+ # ISC License
4
+ #
5
+ # Copyright (c) 2026, Timothée Mazzucotelli and contributors
6
+ #
7
+ # Permission to use, copy, modify, and/or distribute this software for any
8
+ # purpose with or without fee is hereby granted, provided that the above
9
+ # copyright notice and this permission notice appear in all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+
19
+ """Terminator D-Bus package.
20
+
21
+ Python library to interact with Terminator through D-Bus.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from terminator_dbus._internal.cli import get_parser, main
27
+ from terminator_dbus._internal.client import BUS_BASE, BUS_PATH, Terminator, get_bus_name
28
+
29
+ __all__: list[str] = ["BUS_BASE", "BUS_PATH", "Terminator", "get_bus_name", "get_parser", "main"]
@@ -0,0 +1,32 @@
1
+ # SPDX-License-Identifier: ISC
2
+ #
3
+ # ISC License
4
+ #
5
+ # Copyright (c) 2026, Timothée Mazzucotelli and contributors
6
+ #
7
+ # Permission to use, copy, modify, and/or distribute this software for any
8
+ # purpose with or without fee is hereby granted, provided that the above
9
+ # copyright notice and this permission notice appear in all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+
19
+ """Entry-point module, in case you use `python -m terminator_dbus`.
20
+
21
+ Why does this file exist, and why `__main__`? For more info, read:
22
+
23
+ - https://www.python.org/dev/peps/pep-0338/
24
+ - https://docs.python.org/3/using/cmdline.html#cmdoption-m
25
+ """
26
+
27
+ import sys
28
+
29
+ from terminator_dbus._internal.cli import main
30
+
31
+ if __name__ == "__main__":
32
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,17 @@
1
+ # SPDX-License-Identifier: ISC
2
+ #
3
+ # ISC License
4
+ #
5
+ # Copyright (c) 2026, Timothée Mazzucotelli and contributors
6
+ #
7
+ # Permission to use, copy, modify, and/or distribute this software for any
8
+ # purpose with or without fee is hereby granted, provided that the above
9
+ # copyright notice and this permission notice appear in all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # SPDX-License-Identifier: ISC
2
+ #
3
+ # ISC License
4
+ #
5
+ # Copyright (c) 2026, Timothée Mazzucotelli and contributors
6
+ #
7
+ # Permission to use, copy, modify, and/or distribute this software for any
8
+ # purpose with or without fee is hereby granted, provided that the above
9
+ # copyright notice and this permission notice appear in all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+
19
+ # Why does this file exist, and why not put this in `__main__`?
20
+ #
21
+ # You might be tempted to import things from `__main__` later,
22
+ # but that will cause problems: the code will get executed twice:
23
+ #
24
+ # - When you run `python -m terminator_dbus` python will execute
25
+ # `__main__.py` as a script. That means there won't be any
26
+ # `terminator_dbus.__main__` in `sys.modules`.
27
+ # - When you import `__main__` it will get executed again (as a module) because
28
+ # there's no `terminator_dbus.__main__` in `sys.modules`.
29
+
30
+ from __future__ import annotations
31
+
32
+ import argparse
33
+ import sys
34
+ from typing import Any
35
+
36
+ from terminator_dbus._internal import debug
37
+
38
+
39
+ class _DebugInfo(argparse.Action):
40
+ def __init__(self, nargs: int | str | None = 0, **kwargs: Any) -> None:
41
+ super().__init__(nargs=nargs, **kwargs)
42
+
43
+ def __call__(self, *args: Any, **kwargs: Any) -> None: # noqa: ARG002
44
+ debug._print_debug_info()
45
+ sys.exit(0)
46
+
47
+
48
+ def get_parser() -> argparse.ArgumentParser:
49
+ """Return the CLI argument parser.
50
+
51
+ Returns:
52
+ An argparse parser.
53
+ """
54
+ parser = argparse.ArgumentParser(prog="terminator-dbus")
55
+ parser.add_argument("-V", "--version", action="version", version=f"%(prog)s {debug._get_version()}")
56
+ parser.add_argument("--debug-info", action=_DebugInfo, help="Print debug information.")
57
+ return parser
58
+
59
+
60
+ def main(args: list[str] | None = None) -> int:
61
+ """Run the main program.
62
+
63
+ This function is executed when you type `terminator-dbus` or `python -m terminator_dbus`.
64
+
65
+ Parameters:
66
+ args: Arguments passed from the command line.
67
+
68
+ Returns:
69
+ An exit code.
70
+ """
71
+ parser = get_parser()
72
+ opts = parser.parse_args(args=args)
73
+ print(opts)
74
+ return 0
@@ -0,0 +1,294 @@
1
+ # SPDX-License-Identifier: ISC
2
+ #
3
+ # ISC License
4
+ #
5
+ # Copyright (c) 2026, Timothée Mazzucotelli and contributors
6
+ #
7
+ # Permission to use, copy, modify, and/or distribute this software for any
8
+ # purpose with or without fee is hereby granted, provided that the above
9
+ # copyright notice and this permission notice appear in all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+
19
+ from __future__ import annotations
20
+
21
+ import hashlib
22
+ import os
23
+ from typing import TYPE_CHECKING, Any, Final
24
+
25
+ import dbus
26
+
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Mapping
29
+
30
+ from dbus.bus import BusConnection
31
+
32
+
33
+ BUS_BASE: Final = "net.tenshu.Terminator2"
34
+ """Base name of Terminator's D-Bus service and interface."""
35
+
36
+ BUS_PATH: Final = "/net/tenshu/Terminator2"
37
+ """Object path of Terminator's D-Bus service."""
38
+
39
+
40
+ def _default_display() -> str | None:
41
+ backend = os.environ.get("GDK_BACKEND", "").split(",", maxsplit=1)[0]
42
+ if backend == "wayland":
43
+ return os.environ.get("WAYLAND_DISPLAY") or os.environ.get("DISPLAY")
44
+ if backend == "x11":
45
+ return os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")
46
+ if os.environ.get("XDG_SESSION_TYPE") == "wayland":
47
+ return os.environ.get("WAYLAND_DISPLAY") or os.environ.get("DISPLAY")
48
+ return os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")
49
+
50
+
51
+ def get_bus_name(display: str | None = None) -> str:
52
+ """Return the D-Bus service and interface name for a display.
53
+
54
+ Terminator appends the MD5 digest of its GDK display name to
55
+ `net.tenshu.Terminator2`. It removes the screen suffix before it creates
56
+ the digest. For example, `:0` and `:0.0` use the same D-Bus name.
57
+
58
+ Parameters:
59
+ display: GDK display name. The current desktop display is used when
60
+ this argument is not set.
61
+
62
+ Returns:
63
+ The display-specific name, or the base name when no display is known.
64
+ """
65
+ if display is None:
66
+ display = _default_display()
67
+ if not display:
68
+ return BUS_BASE
69
+
70
+ display_without_screen = display.partition(".")[0]
71
+ display_digest = hashlib.md5(display_without_screen.encode(), usedforsecurity=False).hexdigest()
72
+ return f"{BUS_BASE}{display_digest}"
73
+
74
+
75
+ def _options(values: Mapping[str, str] | None = None) -> dbus.Dictionary:
76
+ return dbus.Dictionary({} if values is None else values, signature="ss")
77
+
78
+
79
+ def _optional_string(value: object) -> str | None:
80
+ if value is None:
81
+ return None
82
+ return str(value)
83
+
84
+
85
+ class Terminator:
86
+ """Provide Python methods for Terminator's complete D-Bus interface.
87
+
88
+ The client keeps one session-bus connection and one proxy. It sends known
89
+ method signatures directly, so `dbus-python` does not need an
90
+ introspection request before the first method call.
91
+
92
+ Parameters:
93
+ bus: An existing D-Bus connection. A session-bus connection is created
94
+ when this argument is not set.
95
+ display: GDK display name used to calculate Terminator's D-Bus name.
96
+ bus_name: Exact D-Bus service name. Use this argument for a custom or
97
+ already discovered Terminator service.
98
+
99
+ Raises:
100
+ ValueError: Both `display` and `bus_name` were specified.
101
+ dbus.DBusException: The session bus or Terminator service is not
102
+ available.
103
+ """
104
+
105
+ def __init__(
106
+ self,
107
+ *,
108
+ bus: BusConnection | None = None,
109
+ display: str | None = None,
110
+ bus_name: str | None = None,
111
+ ) -> None:
112
+ if display is not None and bus_name is not None:
113
+ raise ValueError("display and bus_name cannot both be specified")
114
+
115
+ self._bus_name = get_bus_name(display) if bus_name is None else bus_name
116
+ self._bus = dbus.SessionBus() if bus is None else bus
117
+ proxy = self._bus.get_object(self.bus_name, BUS_PATH, introspect=False)
118
+ self._interface = dbus.Interface(proxy, self.bus_name)
119
+
120
+ @property
121
+ def bus_name(self) -> str:
122
+ """Return the D-Bus service and interface name used by this client."""
123
+ return self._bus_name
124
+
125
+ def _call(self, method_name: str, *args: object, signature: str) -> Any:
126
+ method = self._interface.get_dbus_method(method_name)
127
+ return method(*args, signature=signature)
128
+
129
+ def new_window_cmdline(self, options: Mapping[str, str]) -> None:
130
+ """Create a window from serialized Terminator command-line options.
131
+
132
+ Parameters:
133
+ options: Complete option mapping produced by Terminator's command
134
+ line parser. Keys and values must be strings.
135
+ """
136
+ self._call("new_window_cmdline", _options(options), signature="a{ss}")
137
+
138
+ def new_tab_cmdline(self, options: Mapping[str, str]) -> None:
139
+ """Create a tab from serialized Terminator command-line options.
140
+
141
+ Parameters:
142
+ options: Complete option mapping produced by Terminator's command
143
+ line parser. Keys and values must be strings.
144
+ """
145
+ self._call("new_tab_cmdline", _options(options), signature="a{ss}")
146
+
147
+ def toggle_visibility_cmdline(self, options: Mapping[str, str]) -> None:
148
+ """Toggle the visibility of every Terminator window.
149
+
150
+ Parameters:
151
+ options: Serialized command-line options. Terminator currently
152
+ ignores the values.
153
+ """
154
+ self._call("toggle_visibility_cmdline", _options(options), signature="a{ss}")
155
+
156
+ def unhide_cmdline(self, options: Mapping[str, str]) -> None:
157
+ """Show every hidden Terminator window.
158
+
159
+ Parameters:
160
+ options: Serialized command-line options. Terminator currently
161
+ ignores the values.
162
+ """
163
+ self._call("unhide_cmdline", _options(options), signature="a{ss}")
164
+
165
+ def new_window(self) -> str:
166
+ """Create a window and return its first terminal UUID."""
167
+ return str(self._call("new_window", signature=""))
168
+
169
+ def new_tab(self, uuid: str) -> str:
170
+ """Create a tab beside a terminal and return the new terminal UUID.
171
+
172
+ Parameters:
173
+ uuid: UUID of a terminal in the target window.
174
+
175
+ Returns:
176
+ The new terminal UUID or an error string from Terminator.
177
+ """
178
+ return str(self._call("new_tab", uuid, signature="v"))
179
+
180
+ def reload_configuration(self) -> None:
181
+ """Reload the configuration of all terminals."""
182
+ self._call("reload_configuration", signature="")
183
+
184
+ def bg_img_all(self, options: Mapping[str, str]) -> None:
185
+ """Set the background image of all terminals.
186
+
187
+ Parameters:
188
+ options: Mapping with the image path in the `file` key.
189
+ """
190
+ self._call("bg_img_all", _options(options), signature="v")
191
+
192
+ def bg_img(self, uuid: str, options: Mapping[str, str]) -> None:
193
+ """Set the background image of one terminal.
194
+
195
+ Parameters:
196
+ uuid: Target terminal UUID.
197
+ options: Mapping with the image path in the `file` key.
198
+ """
199
+ self._call("bg_img", uuid, _options(options), signature="vv")
200
+
201
+ def hsplit(self, uuid: str, options: Mapping[str, str] | None = None) -> str:
202
+ """Split a terminal horizontally and return the new terminal UUID.
203
+
204
+ Parameters:
205
+ uuid: Target terminal UUID.
206
+ options: Optional `execute` command and `title` for the new
207
+ terminal.
208
+
209
+ Returns:
210
+ The new terminal UUID or an error string from Terminator.
211
+ """
212
+ return str(self._call("hsplit", uuid, _options(options), signature="vv"))
213
+
214
+ def vsplit(self, uuid: str, options: Mapping[str, str] | None = None) -> str:
215
+ """Split a terminal vertically and return the new terminal UUID.
216
+
217
+ Parameters:
218
+ uuid: Target terminal UUID.
219
+ options: Optional `execute` command and `title` for the new
220
+ terminal.
221
+
222
+ Returns:
223
+ The new terminal UUID or an error string from Terminator.
224
+ """
225
+ return str(self._call("vsplit", uuid, _options(options), signature="vv"))
226
+
227
+ def get_terminals(self) -> list[str]:
228
+ """Return the UUID of every terminal."""
229
+ return [str(uuid) for uuid in self._call("get_terminals", signature="")]
230
+
231
+ def get_focused_terminal(self) -> str | None:
232
+ """Return the focused terminal UUID, if a terminal has focus."""
233
+ return _optional_string(self._call("get_focused_terminal", signature=""))
234
+
235
+ def get_window(self, uuid: str) -> str:
236
+ """Return the parent window UUID of a terminal.
237
+
238
+ Parameters:
239
+ uuid: Target terminal UUID.
240
+ """
241
+ return str(self._call("get_window", uuid, signature="v"))
242
+
243
+ def get_window_title(self, uuid: str) -> str:
244
+ """Return the parent window title of a terminal.
245
+
246
+ Parameters:
247
+ uuid: Target terminal UUID.
248
+ """
249
+ return str(self._call("get_window_title", uuid, signature="v"))
250
+
251
+ def get_tab(self, uuid: str) -> str | None:
252
+ """Return the parent tab identifier of a terminal.
253
+
254
+ Terminator does not assign UUIDs to tabs. It currently returns an
255
+ empty string for a terminal in a notebook and no value otherwise.
256
+
257
+ Parameters:
258
+ uuid: Target terminal UUID.
259
+ """
260
+ return _optional_string(self._call("get_tab", uuid, signature="v"))
261
+
262
+ def get_tab_title(self, uuid: str) -> str | None:
263
+ """Return the parent tab title of a terminal, if it has one.
264
+
265
+ Parameters:
266
+ uuid: Target terminal UUID.
267
+ """
268
+ return _optional_string(self._call("get_tab_title", uuid, signature="v"))
269
+
270
+ def set_tab_title(self, uuid: str, options: Mapping[str, str]) -> None:
271
+ """Set a terminal's parent tab title.
272
+
273
+ Parameters:
274
+ uuid: Target terminal UUID.
275
+ options: Mapping with the new title in the `tab-title` key.
276
+ """
277
+ self._call("set_tab_title", uuid, _options(options), signature="vv")
278
+
279
+ def switch_profile(self, uuid: str, options: Mapping[str, str]) -> None:
280
+ """Switch one terminal to a profile.
281
+
282
+ Parameters:
283
+ uuid: Target terminal UUID.
284
+ options: Mapping with the profile name in the `profile` key.
285
+ """
286
+ self._call("switch_profile", uuid, _options(options), signature="vv")
287
+
288
+ def switch_profile_all(self, options: Mapping[str, str]) -> None:
289
+ """Switch all terminals to a profile.
290
+
291
+ Parameters:
292
+ options: Mapping with the profile name in the `profile` key.
293
+ """
294
+ self._call("switch_profile_all", _options(options), signature="v")
@@ -0,0 +1,125 @@
1
+ # SPDX-License-Identifier: ISC
2
+ #
3
+ # ISC License
4
+ #
5
+ # Copyright (c) 2026, Timothée Mazzucotelli and contributors
6
+ #
7
+ # Permission to use, copy, modify, and/or distribute this software for any
8
+ # purpose with or without fee is hereby granted, provided that the above
9
+ # copyright notice and this permission notice appear in all copies.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
+
19
+ from __future__ import annotations
20
+
21
+ import os
22
+ import platform
23
+ import sys
24
+ from dataclasses import dataclass
25
+ from importlib import metadata
26
+
27
+
28
+ @dataclass
29
+ class _Variable:
30
+ """Dataclass describing an environment variable."""
31
+
32
+ name: str
33
+ """Variable name."""
34
+ value: str
35
+ """Variable value."""
36
+
37
+
38
+ @dataclass
39
+ class _Package:
40
+ """Dataclass describing a Python package."""
41
+
42
+ name: str
43
+ """Package name."""
44
+ version: str
45
+ """Package version."""
46
+
47
+
48
+ @dataclass
49
+ class _Environment:
50
+ """Dataclass to store environment information."""
51
+
52
+ interpreter_name: str
53
+ """Python interpreter name."""
54
+ interpreter_version: str
55
+ """Python interpreter version."""
56
+ interpreter_path: str
57
+ """Path to Python executable."""
58
+ platform: str
59
+ """Operating System."""
60
+ packages: list[_Package]
61
+ """Installed packages."""
62
+ variables: list[_Variable]
63
+ """Environment variables."""
64
+
65
+
66
+ def _interpreter_name_version() -> tuple[str, str]:
67
+ if hasattr(sys, "implementation"):
68
+ impl = sys.implementation.version
69
+ version = f"{impl.major}.{impl.minor}.{impl.micro}"
70
+ kind = impl.releaselevel
71
+ if kind != "final":
72
+ version += kind[0] + str(impl.serial)
73
+ return sys.implementation.name, version
74
+ return "", "0.0.0"
75
+
76
+
77
+ def _get_version(dist: str = "terminator-dbus") -> str:
78
+ """Get version of the given distribution.
79
+
80
+ Parameters:
81
+ dist: A distribution name.
82
+
83
+ Returns:
84
+ A version number.
85
+ """
86
+ try:
87
+ return metadata.version(dist)
88
+ except metadata.PackageNotFoundError:
89
+ return "0.0.0"
90
+
91
+
92
+ def _get_debug_info() -> _Environment:
93
+ """Get debug/environment information.
94
+
95
+ Returns:
96
+ Environment information.
97
+ """
98
+ py_name, py_version = _interpreter_name_version()
99
+ packages = ["terminator-dbus"]
100
+ variables = ["PYTHONPATH", *[var for var in os.environ if var.startswith("TERMINATOR_DBUS")]]
101
+ return _Environment(
102
+ interpreter_name=py_name,
103
+ interpreter_version=py_version,
104
+ interpreter_path=sys.executable,
105
+ platform=platform.platform(),
106
+ variables=[_Variable(var, val) for var in variables if (val := os.getenv(var))],
107
+ packages=[_Package(pkg, _get_version(pkg)) for pkg in packages],
108
+ )
109
+
110
+
111
+ def _print_debug_info() -> None:
112
+ """Print debug/environment information."""
113
+ info = _get_debug_info()
114
+ print(f"- __System__: {info.platform}")
115
+ print(f"- __Python__: {info.interpreter_name} {info.interpreter_version} ({info.interpreter_path})")
116
+ print("- __Environment variables__:")
117
+ for var in info.variables:
118
+ print(f" - `{var.name}`: `{var.value}`")
119
+ print("- __Installed packages__:")
120
+ for pkg in info.packages:
121
+ print(f" - `{pkg.name}` v{pkg.version}")
122
+
123
+
124
+ if __name__ == "__main__":
125
+ _print_debug_info()
File without changes
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: terminator-dbus
3
+ Version: 0.1.0
4
+ Summary: Python library to interact with Terminator through D-Bus.
5
+ Author-Email: =?utf-8?q?Timoth=C3=A9e_Mazzucotelli?= <dev@pawamoy.fr>
6
+ License-Expression: ISC
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
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 :: Documentation
19
+ Classifier: Topic :: Software Development
20
+ Classifier: Topic :: Utilities
21
+ Classifier: Typing :: Typed
22
+ Project-URL: Homepage, https://pawamoy.github.io/terminator-dbus
23
+ Project-URL: Documentation, https://pawamoy.github.io/terminator-dbus
24
+ Project-URL: Changelog, https://pawamoy.github.io/terminator-dbus/changelog
25
+ Project-URL: Repository, https://github.com/pawamoy/terminator-dbus
26
+ Project-URL: Issues, https://github.com/pawamoy/terminator-dbus/issues
27
+ Project-URL: Discussions, https://github.com/pawamoy/terminator-dbus/discussions
28
+ Project-URL: Gitter, https://gitter.im/terminator-dbus/community
29
+ Project-URL: Funding, https://github.com/sponsors/pawamoy
30
+ Requires-Python: >=3.10
31
+ Requires-Dist: dbus-python>=1.3.2
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Terminator D-Bus
35
+
36
+
37
+ [![ci](https://github.com/pawamoy/terminator-dbus/workflows/ci/badge.svg)](https://github.com/pawamoy/terminator-dbus/actions?query=workflow%3Aci)
38
+ [![documentation](https://img.shields.io/badge/docs-zensical-FF9100.svg?style=flat)](https://pawamoy.github.io/terminator-dbus/)
39
+ [![pypi version](https://img.shields.io/pypi/v/terminator-dbus.svg)](https://pypi.org/project/terminator-dbus/)
40
+ [![gitter](https://img.shields.io/badge/matrix-chat-4DB798.svg?style=flat)](https://app.gitter.im/#/room/#terminator-dbus:gitter.im)
41
+
42
+
43
+ Python library to interact with Terminator through D-Bus.
44
+
45
+
46
+ ## Installation
47
+
48
+
49
+ ```bash
50
+ pip install terminator-dbus
51
+ ```
52
+
53
+
54
+ With [`uv`](https://docs.astral.sh/uv/):
55
+
56
+
57
+ ```bash
58
+ uv tool install terminator-dbus
59
+ ```
60
+
61
+
62
+ `dbus-python` needs the D-Bus development files when no system package or wheel is available.
63
+
64
+
65
+ ## Usage
66
+
67
+
68
+ Create one client and reuse it for all calls:
69
+
70
+
71
+ ```python
72
+ from terminator_dbus import Terminator
73
+
74
+ terminator = Terminator()
75
+ terminal = terminator.get_focused_terminal()
76
+
77
+ if terminal is not None:
78
+ new_terminal = terminator.vsplit(
79
+ terminal,
80
+ {"execute": "htop", "title": "Processes"},
81
+ )
82
+ terminator.switch_profile(new_terminal, {"profile": "work"})
83
+ ```
84
+
85
+
86
+ The client uses the current X11 or Wayland display by default. Pass `display` if the current environment does not identify the correct display:
87
+
88
+
89
+ ```python
90
+ terminator = Terminator(display=":1")
91
+ ```
92
+
93
+
94
+ Pass `bus_name` when you already know the complete D-Bus service name:
95
+
96
+
97
+ ```python
98
+ terminator = Terminator(bus_name="net.tenshu.Terminator2...")
99
+ ```
100
+
101
+
102
+ `dbus.DBusException` reports connection and remote method failures. Terminator itself returns strings that start with `ERROR:` for some tab and split failures.
103
+
104
+
105
+ ## D-Bus interface
106
+
107
+
108
+ This package follows the interface in [Terminator 2.1.6 `ipc.py`](https://github.com/gnome-terminator/terminator/blob/v2.1.6/terminatorlib/ipc.py).
109
+
110
+
111
+ - Base service and interface name: `net.tenshu.Terminator2`
112
+ - Object path: `/net/tenshu/Terminator2`
113
+ - Display-specific name: the base name followed by the MD5 digest of the GDK display name
114
+
115
+
116
+ Terminator removes the screen suffix before it creates the digest. Thus, `:0` and `:0.0` use the same service name.
117
+
118
+
119
+ The `Terminator` class exposes every method in the service:
120
+
121
+
122
+ | Python method | D-Bus input | Purpose | Result |
123
+ | --- | --- | --- | --- |
124
+ | `new_window_cmdline(options)` | `a{ss}` | Create a window from serialized command-line options. | `None` |
125
+ | `new_tab_cmdline(options)` | `a{ss}` | Create a tab from serialized command-line options. | `None` |
126
+ | `toggle_visibility_cmdline(options)` | `a{ss}` | Toggle all window visibility. | `None` |
127
+ | `unhide_cmdline(options)` | `a{ss}` | Show all hidden windows. | `None` |
128
+ | `new_window()` | empty | Create a window. | New terminal UUID or error string |
129
+ | `new_tab(uuid)` | `v` | Create a tab in a terminal's window. | New terminal UUID or error string |
130
+ | `reload_configuration()` | empty | Reload configuration for all terminals. | `None` |
131
+ | `bg_img_all(options)` | `v` | Set all background images from the `file` option. | `None` |
132
+ | `bg_img(uuid, options)` | `vv` | Set one background image from the `file` option. | `None` |
133
+ | `hsplit(uuid, options=None)` | `vv` | Split a terminal horizontally. | New terminal UUID or error string |
134
+ | `vsplit(uuid, options=None)` | `vv` | Split a terminal vertically. | New terminal UUID or error string |
135
+ | `get_terminals()` | empty | Get all terminal UUIDs. | `list[str]` |
136
+ | `get_focused_terminal()` | empty | Get the focused terminal UUID. | `str \| None` |
137
+ | `get_window(uuid)` | `v` | Get a terminal's window UUID. | `str` |
138
+ | `get_window_title(uuid)` | `v` | Get a terminal's window title. | `str` |
139
+ | `get_tab(uuid)` | `v` | Get a terminal's tab identifier. | `str \| None` |
140
+ | `get_tab_title(uuid)` | `v` | Get a terminal's tab title. | `str \| None` |
141
+ | `set_tab_title(uuid, options)` | `vv` | Set a tab title from the `tab-title` option. | `None` |
142
+ | `switch_profile(uuid, options)` | `vv` | Set one profile from the `profile` option. | `None` |
143
+ | `switch_profile_all(options)` | `v` | Set all profiles from the `profile` option. | `None` |
144
+
145
+
146
+ Terminator does not assign identifiers to tabs. Its `get_tab` method returns an empty string for a terminal in a notebook.
147
+
148
+
149
+ The four `*_cmdline` methods require string-to-string dictionaries. The window and tab creation methods require the complete option mapping from Terminator's command-line parser.
150
+
151
+
152
+ Terminator does not declare D-Bus output signatures. `dbus-python` infers each output signature from the value returned by the service method.
153
+
154
+
155
+ ## Sponsors
156
+
157
+
158
+ <!-- sponsors-start -->
159
+ <!-- sponsors-end -->
@@ -0,0 +1,12 @@
1
+ terminator_dbus-0.1.0.dist-info/METADATA,sha256=ZIBNR-ltKtm_viLdTwCF40e7AUcgijgMMFdEpfFFbW8,6207
2
+ terminator_dbus-0.1.0.dist-info/WHEEL,sha256=Y8xFLOH-FrS4gLE6ON4ti06sl2W_9QUDiRaTK3tfwig,91
3
+ terminator_dbus-0.1.0.dist-info/entry_points.txt,sha256=DZGbTVz8MoUuz56ejS6uA5L40r5cNGLW3XVgifiQx8A,73
4
+ terminator_dbus-0.1.0.dist-info/licenses/LICENSE,sha256=I3KB1-ErGw-w8Lv5cPRgpAQKNKPv_CpOJvpYunP93-E,771
5
+ terminator_dbus/__init__.py,sha256=2__lOnprDspKWl2Wmx0MCBjZDNFoDO8BpM6rJ69dZGM,1209
6
+ terminator_dbus/__main__.py,sha256=QXkwKNVavUPbXObqIR3r29pvZ3xDdDMGeeJTFej11cQ,1197
7
+ terminator_dbus/_internal/__init__.py,sha256=LH7HQJydqOYIxZva6Nc0p5zeUpQAxcvUyEwiajkZkdQ,831
8
+ terminator_dbus/_internal/cli.py,sha256=4vW6wRTVncUcHsTsjErEAmFi-FcjytOmGhDO8DnWjBA,2563
9
+ terminator_dbus/_internal/client.py,sha256=SgBYyGQnXoR64Yws_Etv4wbtTbnHLtrgM7N9FLQYb-c,11016
10
+ terminator_dbus/_internal/debug.py,sha256=xrgL0cQWdtOrxh8lFYhwQPTRW-Wfe0Y-YOzE4-d3YZE,3665
11
+ terminator_dbus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ terminator_dbus-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: pdm-backend (2.4.10)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ terminator-dbus = terminator_dbus:main
3
+
4
+ [gui_scripts]
5
+
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026, Timothée Mazzucotelli and contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.