libera 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. libera-0.1.0/PKG-INFO +131 -0
  2. libera-0.1.0/README.md +121 -0
  3. libera-0.1.0/pyproject.toml +82 -0
  4. libera-0.1.0/pyproject.toml.orig +98 -0
  5. libera-0.1.0/src/libera/__init__.py +5 -0
  6. libera-0.1.0/src/libera/__main__.py +15 -0
  7. libera-0.1.0/src/libera/cli/__init__.py +14 -0
  8. libera-0.1.0/src/libera/cli/commands.py +259 -0
  9. libera-0.1.0/src/libera/cli/dispatch.py +116 -0
  10. libera-0.1.0/src/libera/gui.py +280 -0
  11. libera-0.1.0/src/libera/host/__init__.py +30 -0
  12. libera-0.1.0/src/libera/host/app.py +227 -0
  13. libera-0.1.0/src/libera/host/apps.py +189 -0
  14. libera-0.1.0/src/libera/host/convert.py +290 -0
  15. libera-0.1.0/src/libera/host/desktop.py +91 -0
  16. libera-0.1.0/src/libera/host/hooks.py +89 -0
  17. libera-0.1.0/src/libera/host/menu/__init__.py +34 -0
  18. libera-0.1.0/src/libera/host/menu/actions.py +246 -0
  19. libera-0.1.0/src/libera/host/menu/build.py +332 -0
  20. libera-0.1.0/src/libera/host/opening.py +40 -0
  21. libera-0.1.0/src/libera/host/recents.py +79 -0
  22. libera-0.1.0/src/libera/host/server/__init__.py +65 -0
  23. libera-0.1.0/src/libera/host/server/bridge-desktop.js +501 -0
  24. libera-0.1.0/src/libera/host/server/bridge-page.js +180 -0
  25. libera-0.1.0/src/libera/host/server/bridge-runtime.js +172 -0
  26. libera-0.1.0/src/libera/host/server/get.py +162 -0
  27. libera-0.1.0/src/libera/host/server/handler.py +245 -0
  28. libera-0.1.0/src/libera/host/server/post.py +275 -0
  29. libera-0.1.0/src/libera/host/server/start.html +354 -0
  30. libera-0.1.0/src/libera/host/server/state.py +43 -0
  31. libera-0.1.0/src/libera/host/session.py +362 -0
  32. libera-0.1.0/src/libera/host/shortcuts.py +60 -0
  33. libera-0.1.0/src/libera/host/window/__init__.py +65 -0
  34. libera-0.1.0/src/libera/host/window/dialogs.py +374 -0
  35. libera-0.1.0/src/libera/host/window/windows.py +280 -0
  36. libera-0.1.0/src/libera/icon.svg +32 -0
  37. libera-0.1.0/src/libera/logs.py +105 -0
  38. libera-0.1.0/src/libera/manifest.json +59 -0
  39. libera-0.1.0/src/libera/payload/__init__.py +57 -0
  40. libera-0.1.0/src/libera/payload/generate.py +85 -0
  41. libera-0.1.0/src/libera/payload/installer.py +234 -0
  42. libera-0.1.0/src/libera/payload/locate.py +198 -0
libera-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.3
2
+ Name: libera
3
+ Version: 0.1.0
4
+ Summary: Libera Suite — Abilian's desktop office suite
5
+ Author: Stefane Fermigier
6
+ Author-email: Stefane Fermigier <sf@abilian.com>
7
+ Requires-Dist: pywebview>=6.2.1
8
+ Requires-Python: >=3.12
9
+ Description-Content-Type: text/markdown
10
+
11
+ # Libera Suite
12
+
13
+ **A desktop office suite you can own.** Libera Suite opens the documents other people send you (`.docx`, `.xlsx`, `.pptx`, ODF), edits them on your machine and saves them back. It runs on your own computer, with no account to create and nothing in it that phones home.
14
+
15
+ Four editors share one application. The file picks the editor, so there is nothing to choose.
16
+
17
+ | | |
18
+ | :--- | :--- |
19
+ | **Libera Words** | `.docx` `.odt` `.rtf` `.txt` `.md` |
20
+ | **Libera Tables** | `.xlsx` `.ods` `.csv` |
21
+ | **Libera Slides** | `.pptx` `.odp` |
22
+ | **Libera Diagrams** | opens `.vsdx` to read |
23
+
24
+ Abilian builds it as free software under the AGPL. The editors inside it are [Euro-Office](https://github.com/Euro-Office), an AGPL fork of ONLYOFFICE by Ascensio System SIA, running locally and unmodified.
25
+
26
+ ## Using it
27
+
28
+ ```sh
29
+ libera report.docx # a window, in Words, because the file says so
30
+ libera budget.xlsx # Tables
31
+ libera *.pptx # one window each
32
+ libera # the start window: new, open, recent
33
+ ```
34
+
35
+ [What works today](docs/src/guide/status.md) sets out the full list with its gaps: editing, saving and exporting (the Save As popup offers PDF), a blank document of any of the four kinds, images, printing, spell check in six languages, crash recovery and a Recent list.
36
+
37
+ ```sh
38
+ libera -v FILE # what it is doing; -vv how; -vvv every request
39
+ libera --diagnose # everything worth pasting into a bug report
40
+ libera --payload-status # which editors are in use, and the revisions they were built from
41
+ ```
42
+
43
+ ## How it works
44
+
45
+ The editors are a web application. Everything they cannot do in a browser (read a file from disk, convert it, save it, list the fonts, put a dialog on screen) they ask of one injected JavaScript object, `window.AscDesktopEditor`. That object is the whole of the integration.
46
+
47
+ We implement it in Python, behind the webview your system already ships. The host serves the editor over a loopback HTTP server and defines `AscDesktopEditor` before the editor's own code runs, so nothing about the editor itself changes.
48
+
49
+ | | |
50
+ | :--- | :--- |
51
+ | **The payload** | The editors: `sdkjs`, `web-apps`, the `x2t` converter, fonts, dictionaries. Built from upstream sources pinned by SHA, plus our patch queue. ~120 MB, installed out of tree or shipped inside the bundle. |
52
+ | **The host** | `src/libera/`: the loopback HTTP server, the webview, the file dialogs, the menu bar and the converter calls, in about 4,700 lines of Python across 32 modules. All of the desktop application is here. |
53
+ | **The bridge** | Three small JavaScript files, spliced into the `<head>` of every page the host serves. Our code and theirs never share a file. |
54
+
55
+ Five thousand lines is a codebase a small team can read in an afternoon and still be maintaining in ten years.
56
+
57
+ **We do not fork the engine.** The patch queue is 28 patches across three upstream repositories: 24 of them make it build on macOS, 3 are configuration and branding, 1 fixes an upstream UI bug. **None touches the editing engine**, so following upstream means rebasing build configuration. Every release records the exact revisions it was built from, so the corresponding source is a commit plus a series that provably reapplies to it, and `make patches` checks that it still does.
58
+
59
+ Everything we ship, we build. [`build/`](build/README.md) compiles the editors and the native converter from pinned upstream sources, including on macOS, where upstream publishes no binaries of its own.
60
+
61
+ ## Where it stands
62
+
63
+ **Early, and running.** All four editors work today on **macOS** (Apple Silicon) and **Linux** (x86_64 and arm64). Windows is not started.
64
+
65
+ Linux has no menu bar yet. Tabs, file locking, signing and notarisation on macOS, the PyPI upload and the payload origin are all still to come. [What works today](docs/src/guide/status.md) lists the known issues, so nobody need waste an evening reporting one. [The roadmap](docs/src/develop/roadmap.md) says what comes next and what we have decided against.
66
+
67
+ The most useful thing you can send us is a document that renders wrongly, attached. The layout engine is upstream's and mature, so where output is wrong it is far more likely to be our packaging (a font we did not ship, a resource we failed to serve) than the engine.
68
+
69
+ ## Installing it
70
+
71
+ [Install](docs/src/guide/install.md) gives the full instructions for each platform.
72
+
73
+ **Linux: the Flatpak.** The bundle carries the editors, GTK and WebKit, so there is nothing else to fetch and nothing to get wrong:
74
+
75
+ ```sh
76
+ flatpak install --user libera-0.1.0-amd64.flatpak # or -arm64
77
+ flatpak run eu.liberasuite.Libera
78
+ ```
79
+
80
+ **macOS, and Linux without Flatpak.** The `libera` command comes from PyPI and fetches the editors on first run:
81
+
82
+ ```sh
83
+ uv tool install libera # macOS
84
+ pipx install --system-site-packages libera # Linux: the flag is not optional
85
+ libera --payload-install
86
+ ```
87
+
88
+ > **Neither is published yet.** `libera` is not on PyPI and the payload origin is not up, so today the working routes are a Flatpak someone hands you, or a checkout. Publishing both is the shortest path to a beta, and the top of [the roadmap](docs/src/develop/roadmap.md).
89
+
90
+ ## Building it
91
+
92
+ ```sh
93
+ git clone https://github.com/abilian/libera-suite && cd libera-suite
94
+ uv sync
95
+ make payload-all # fetch, patch, build, assemble, smoke-test (long: V8 alone is ~30 min)
96
+ export LIBERA_PAYLOAD="$BUILD_ROOT/out/payload"
97
+ uv run libera document.docx
98
+ ```
99
+
100
+ ```sh
101
+ make verify # everything below, in the order that fails fastest
102
+ make test # 314 tests: unit, the host over HTTP, the editor in headless Chromium
103
+ make lint # ruff, ty, pyrefly, mypy, biome — green, and expected to stay that way
104
+ make smoke # the converter: fonts, docx -> odt -> docx, docx -> pdf
105
+ make patches # does the patch queue still apply to the pinned SHAs?
106
+ ```
107
+
108
+ The test suite enforces one house rule: **assert on content, never on exit codes.** A converter that writes an empty document exits zero. A PDF with no glyphs in it is the right size. So the end-to-end run photographs the editor's own canvas and measures the ink on it.
109
+
110
+ | | |
111
+ | :--- | :--- |
112
+ | [`docs/`](docs/src/index.md) | The documentation site, at <https://docs.liberasuite.eu/>. Start at [Developers](docs/src/develop/index.md). |
113
+ | [`notes/`](notes/01-vision.md) | Where the reasoning lives: vision, specs, architecture, packaging, and our relationship with upstream. |
114
+ | [`notes/lessons-learned.md`](notes/lessons-learned.md) | Bugs that escaped to a user, and what each generalises to. Read before touching the host or the bridge. |
115
+ | [`notes/euro-office-map.md`](notes/euro-office-map.md) | How Euro-Office is put together, and the `AscDesktopEditor` contract. The survey everything else is built on. |
116
+ | [`build/`](build/README.md) | Building the editors and the native binaries from pinned source plus our patches. |
117
+ | [`CLAUDE.md`](CLAUDE.md) | The orientation an agent gets, which happens to be the fastest one for a human too. |
118
+
119
+ The package and the command are `libera`. The repository directory is `local-office`.
120
+
121
+ ## Credit
122
+
123
+ Libera Suite is based on [Euro-Office](https://github.com/Euro-Office), itself based on [ONLYOFFICE](https://www.onlyoffice.com/) by Ascensio System SIA. The same line appears in Help ▸ About inside the application.
124
+
125
+ The editors, the document engine and the format support are theirs. That is the hard part: twenty years of correctly reading a `.docx` written by somebody else's software. The host, the packaging and the desktop integration are ours. We are grateful for both.
126
+
127
+ ## Licence
128
+
129
+ Libera Suite is **AGPL-3.0**, as is the Euro-Office code it is built from (GUI assets are CC-BY-SA-4.0). The host loads upstream's JavaScript in-process and injects code into their runtime, which reads as a combined work. The whole of it is therefore AGPL, and stays that way.
130
+
131
+ [Licence and attribution](docs/src/licence.md) has the corresponding-source detail: what each release records, and where to fetch it.
libera-0.1.0/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # Libera Suite
2
+
3
+ **A desktop office suite you can own.** Libera Suite opens the documents other people send you (`.docx`, `.xlsx`, `.pptx`, ODF), edits them on your machine and saves them back. It runs on your own computer, with no account to create and nothing in it that phones home.
4
+
5
+ Four editors share one application. The file picks the editor, so there is nothing to choose.
6
+
7
+ | | |
8
+ | :--- | :--- |
9
+ | **Libera Words** | `.docx` `.odt` `.rtf` `.txt` `.md` |
10
+ | **Libera Tables** | `.xlsx` `.ods` `.csv` |
11
+ | **Libera Slides** | `.pptx` `.odp` |
12
+ | **Libera Diagrams** | opens `.vsdx` to read |
13
+
14
+ Abilian builds it as free software under the AGPL. The editors inside it are [Euro-Office](https://github.com/Euro-Office), an AGPL fork of ONLYOFFICE by Ascensio System SIA, running locally and unmodified.
15
+
16
+ ## Using it
17
+
18
+ ```sh
19
+ libera report.docx # a window, in Words, because the file says so
20
+ libera budget.xlsx # Tables
21
+ libera *.pptx # one window each
22
+ libera # the start window: new, open, recent
23
+ ```
24
+
25
+ [What works today](docs/src/guide/status.md) sets out the full list with its gaps: editing, saving and exporting (the Save As popup offers PDF), a blank document of any of the four kinds, images, printing, spell check in six languages, crash recovery and a Recent list.
26
+
27
+ ```sh
28
+ libera -v FILE # what it is doing; -vv how; -vvv every request
29
+ libera --diagnose # everything worth pasting into a bug report
30
+ libera --payload-status # which editors are in use, and the revisions they were built from
31
+ ```
32
+
33
+ ## How it works
34
+
35
+ The editors are a web application. Everything they cannot do in a browser (read a file from disk, convert it, save it, list the fonts, put a dialog on screen) they ask of one injected JavaScript object, `window.AscDesktopEditor`. That object is the whole of the integration.
36
+
37
+ We implement it in Python, behind the webview your system already ships. The host serves the editor over a loopback HTTP server and defines `AscDesktopEditor` before the editor's own code runs, so nothing about the editor itself changes.
38
+
39
+ | | |
40
+ | :--- | :--- |
41
+ | **The payload** | The editors: `sdkjs`, `web-apps`, the `x2t` converter, fonts, dictionaries. Built from upstream sources pinned by SHA, plus our patch queue. ~120 MB, installed out of tree or shipped inside the bundle. |
42
+ | **The host** | `src/libera/`: the loopback HTTP server, the webview, the file dialogs, the menu bar and the converter calls, in about 4,700 lines of Python across 32 modules. All of the desktop application is here. |
43
+ | **The bridge** | Three small JavaScript files, spliced into the `<head>` of every page the host serves. Our code and theirs never share a file. |
44
+
45
+ Five thousand lines is a codebase a small team can read in an afternoon and still be maintaining in ten years.
46
+
47
+ **We do not fork the engine.** The patch queue is 28 patches across three upstream repositories: 24 of them make it build on macOS, 3 are configuration and branding, 1 fixes an upstream UI bug. **None touches the editing engine**, so following upstream means rebasing build configuration. Every release records the exact revisions it was built from, so the corresponding source is a commit plus a series that provably reapplies to it, and `make patches` checks that it still does.
48
+
49
+ Everything we ship, we build. [`build/`](build/README.md) compiles the editors and the native converter from pinned upstream sources, including on macOS, where upstream publishes no binaries of its own.
50
+
51
+ ## Where it stands
52
+
53
+ **Early, and running.** All four editors work today on **macOS** (Apple Silicon) and **Linux** (x86_64 and arm64). Windows is not started.
54
+
55
+ Linux has no menu bar yet. Tabs, file locking, signing and notarisation on macOS, the PyPI upload and the payload origin are all still to come. [What works today](docs/src/guide/status.md) lists the known issues, so nobody need waste an evening reporting one. [The roadmap](docs/src/develop/roadmap.md) says what comes next and what we have decided against.
56
+
57
+ The most useful thing you can send us is a document that renders wrongly, attached. The layout engine is upstream's and mature, so where output is wrong it is far more likely to be our packaging (a font we did not ship, a resource we failed to serve) than the engine.
58
+
59
+ ## Installing it
60
+
61
+ [Install](docs/src/guide/install.md) gives the full instructions for each platform.
62
+
63
+ **Linux: the Flatpak.** The bundle carries the editors, GTK and WebKit, so there is nothing else to fetch and nothing to get wrong:
64
+
65
+ ```sh
66
+ flatpak install --user libera-0.1.0-amd64.flatpak # or -arm64
67
+ flatpak run eu.liberasuite.Libera
68
+ ```
69
+
70
+ **macOS, and Linux without Flatpak.** The `libera` command comes from PyPI and fetches the editors on first run:
71
+
72
+ ```sh
73
+ uv tool install libera # macOS
74
+ pipx install --system-site-packages libera # Linux: the flag is not optional
75
+ libera --payload-install
76
+ ```
77
+
78
+ > **Neither is published yet.** `libera` is not on PyPI and the payload origin is not up, so today the working routes are a Flatpak someone hands you, or a checkout. Publishing both is the shortest path to a beta, and the top of [the roadmap](docs/src/develop/roadmap.md).
79
+
80
+ ## Building it
81
+
82
+ ```sh
83
+ git clone https://github.com/abilian/libera-suite && cd libera-suite
84
+ uv sync
85
+ make payload-all # fetch, patch, build, assemble, smoke-test (long: V8 alone is ~30 min)
86
+ export LIBERA_PAYLOAD="$BUILD_ROOT/out/payload"
87
+ uv run libera document.docx
88
+ ```
89
+
90
+ ```sh
91
+ make verify # everything below, in the order that fails fastest
92
+ make test # 314 tests: unit, the host over HTTP, the editor in headless Chromium
93
+ make lint # ruff, ty, pyrefly, mypy, biome — green, and expected to stay that way
94
+ make smoke # the converter: fonts, docx -> odt -> docx, docx -> pdf
95
+ make patches # does the patch queue still apply to the pinned SHAs?
96
+ ```
97
+
98
+ The test suite enforces one house rule: **assert on content, never on exit codes.** A converter that writes an empty document exits zero. A PDF with no glyphs in it is the right size. So the end-to-end run photographs the editor's own canvas and measures the ink on it.
99
+
100
+ | | |
101
+ | :--- | :--- |
102
+ | [`docs/`](docs/src/index.md) | The documentation site, at <https://docs.liberasuite.eu/>. Start at [Developers](docs/src/develop/index.md). |
103
+ | [`notes/`](notes/01-vision.md) | Where the reasoning lives: vision, specs, architecture, packaging, and our relationship with upstream. |
104
+ | [`notes/lessons-learned.md`](notes/lessons-learned.md) | Bugs that escaped to a user, and what each generalises to. Read before touching the host or the bridge. |
105
+ | [`notes/euro-office-map.md`](notes/euro-office-map.md) | How Euro-Office is put together, and the `AscDesktopEditor` contract. The survey everything else is built on. |
106
+ | [`build/`](build/README.md) | Building the editors and the native binaries from pinned source plus our patches. |
107
+ | [`CLAUDE.md`](CLAUDE.md) | The orientation an agent gets, which happens to be the fastest one for a human too. |
108
+
109
+ The package and the command are `libera`. The repository directory is `local-office`.
110
+
111
+ ## Credit
112
+
113
+ Libera Suite is based on [Euro-Office](https://github.com/Euro-Office), itself based on [ONLYOFFICE](https://www.onlyoffice.com/) by Ascensio System SIA. The same line appears in Help ▸ About inside the application.
114
+
115
+ The editors, the document engine and the format support are theirs. That is the hard part: twenty years of correctly reading a `.docx` written by somebody else's software. The host, the packaging and the desktop integration are ours. We are grateful for both.
116
+
117
+ ## Licence
118
+
119
+ Libera Suite is **AGPL-3.0**, as is the Euro-Office code it is built from (GUI assets are CC-BY-SA-4.0). The host loads upstream's JavaScript in-process and injects code into their runtime, which reads as a combined work. The whole of it is therefore AGPL, and stays that way.
120
+
121
+ [Licence and attribution](docs/src/licence.md) has the corresponding-source detail: what each release records, and where to fetch it.
@@ -0,0 +1,82 @@
1
+ [project]
2
+ name = "libera"
3
+ version = "0.1.0"
4
+ description = "Libera Suite — Abilian's desktop office suite"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = ["pywebview>=6.2.1"]
8
+
9
+ [[project.authors]]
10
+ name = "Stefane Fermigier"
11
+ email = "sf@abilian.com"
12
+
13
+ [project.scripts]
14
+ libera = "libera:main"
15
+
16
+ [build-system]
17
+ requires = ["uv_build>=0.12.7,<0.13.0"]
18
+ build-backend = "uv_build"
19
+
20
+ [dependency-groups]
21
+ dev = [
22
+ "abilian-devtools>=0.9.4",
23
+ "mypy>=2.3.1",
24
+ "nox>=2026.8.17",
25
+ "pre-commit>=4.6.2",
26
+ "pyrefly>=1.2.0",
27
+ "pytest>=9.1.1",
28
+ "pytest-cov>=7.1.0",
29
+ "pytest-playwright>=0.9.0",
30
+ "ruff>=0.16.6",
31
+ "ty>=0.0.79",
32
+ "zensical>=0.0.60",
33
+ ]
34
+
35
+ [tool.mypy]
36
+ mypy_path = "stubs"
37
+
38
+ [tool.pyrefly]
39
+ search-path = [
40
+ "src",
41
+ "stubs",
42
+ ]
43
+
44
+ [tool.ty.environment]
45
+ extra-paths = ["stubs"]
46
+
47
+ [tool.pytest.ini_options]
48
+ testpaths = ["tests"]
49
+ markers = [
50
+ "unit: fast and isolated",
51
+ "integration: component interactions, file I/O",
52
+ "e2e: full app or CLI workflows",
53
+ ]
54
+
55
+ [tool.tepyd]
56
+ src_root = "src/libera"
57
+ src_package = "libera"
58
+ units = [
59
+ "*",
60
+ "*.py",
61
+ ]
62
+
63
+ [[tool.tepyd.tiers]]
64
+ name = "a_unit"
65
+ root = "tests/a_unit"
66
+ label = "unit"
67
+ target_share = 0.6
68
+
69
+ [[tool.tepyd.tiers]]
70
+ name = "b_integration"
71
+ root = "tests/b_integration"
72
+ label = "integration"
73
+ expects = ["host"]
74
+
75
+ [[tool.tepyd.tiers]]
76
+ name = "c_e2e"
77
+ root = "tests/c_e2e"
78
+ label = "e2e"
79
+ expects = [
80
+ "host",
81
+ "cli",
82
+ ]
@@ -0,0 +1,98 @@
1
+ [project]
2
+ name = "libera"
3
+ version = "0.1.0"
4
+ description = "Libera Suite — Abilian's desktop office suite"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Stefane Fermigier", email = "sf@abilian.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "pywebview>=6.2.1",
12
+ ]
13
+
14
+ [project.scripts]
15
+ libera = "libera:main"
16
+
17
+ [build-system]
18
+ requires = ["uv_build>=0.12.7,<0.13.0"]
19
+ build-backend = "uv_build"
20
+
21
+ [dependency-groups]
22
+ dev = [
23
+ "abilian-devtools>=0.9.4",
24
+ "mypy>=2.3.1",
25
+ "nox>=2026.8.17",
26
+ "pre-commit>=4.6.2",
27
+ "pyrefly>=1.2.0",
28
+ "pytest>=9.1.1",
29
+ "pytest-cov>=7.1.0",
30
+ "pytest-playwright>=0.9.0",
31
+ "ruff>=0.16.6",
32
+ "ty>=0.0.79",
33
+ "zensical>=0.0.60",
34
+ ]
35
+
36
+ [tool.mypy]
37
+ # The same stubs ty and pyrefly use. See stubs/README.md.
38
+ mypy_path = "stubs"
39
+
40
+ [tool.pyrefly]
41
+ # The same stubs ty uses. See stubs/README.md.
42
+ search-path = ["src", "stubs"]
43
+
44
+ [tool.ty.environment]
45
+ # stubs/ holds the pyobjc names the host uses -- see stubs/README.md for why
46
+ # this is a stub directory and not a rule turned off.
47
+ extra-paths = ["stubs"]
48
+
49
+ [tool.pytest.ini_options]
50
+ testpaths = ["tests"]
51
+ # conftest.py applies these by directory; registering them silences the warning.
52
+ markers = [
53
+ "unit: fast and isolated",
54
+ "integration: component interactions, file I/O",
55
+ "e2e: full app or CLI workflows",
56
+ ]
57
+
58
+ [tool.tepyd]
59
+ # Generated by `tepyd init` — review and adjust.
60
+ src_root = "src/libera"
61
+ src_package = "libera"
62
+ units = ["*", "*.py"]
63
+ # counter = "internal" # or "cloc"
64
+
65
+ # Source units to exclude from analysis (a reason is required):
66
+ # [tool.tepyd.exclude]
67
+ # faker = "why this is not tested"
68
+
69
+ # Tiers, cheapest first. Add `expects = [...]` to a tier to scope it to
70
+ # the source units it should test (glob patterns over unit names); units
71
+ # outside the scope are reported n/a, not as gaps. Use it when layers map
72
+ # to tiers — e.g. integration `expects = ["repositories/*", "infra/*"]`,
73
+ # e2e `expects = ["web/*"]`. Omit it and the tier is checked against all.
74
+
75
+ [[tool.tepyd.tiers]]
76
+ name = "a_unit"
77
+ root = "tests/a_unit"
78
+ label = "unit"
79
+ target_share = 0.6
80
+
81
+ [[tool.tepyd.tiers]]
82
+ name = "b_integration"
83
+ root = "tests/b_integration"
84
+ label = "integration"
85
+ # The integration tier is the host over HTTP with a real payload behind it.
86
+ # gui, logs and payload have nothing to integrate: gui asks whether GTK is
87
+ # importable, logs configures a handler, and payload is exercised against real
88
+ # tarballs at the unit tier. Scoping this says "not applicable" rather than
89
+ # reporting three gaps that should never be filled.
90
+ expects = ["host"]
91
+
92
+ [[tool.tepyd.tiers]]
93
+ name = "c_e2e"
94
+ root = "tests/c_e2e"
95
+ label = "e2e"
96
+ # End to end means the shipped command or the editor in a browser, which is
97
+ # host and cli. Nothing else has an end to run to.
98
+ expects = ["host", "cli"]
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from libera.cli import main
4
+
5
+ __all__ = ["main"]
@@ -0,0 +1,15 @@
1
+ """`python -m libera` -- the same entry point as the `libera` command.
2
+
3
+ Libera.app's launcher uses this rather than the console script: the script
4
+ lives in a virtualenv's bin directory, which is not where the bundle can be
5
+ sure to find it, while the interpreter path is baked into the launcher.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import sys
11
+
12
+ from libera.cli import main
13
+
14
+ if __name__ == "__main__":
15
+ sys.exit(main())
@@ -0,0 +1,14 @@
1
+ """The libera command line.
2
+
3
+ commands one function per thing libera can be asked to do
4
+ dispatch the argument parser, and which command each spelling reaches
5
+
6
+ `main` is the console script named in pyproject.toml, so it is re-exported
7
+ here and `libera.cli.main` still resolves.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from libera.cli.dispatch import main
13
+
14
+ __all__ = ["main"]