pi-sessions-tui 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 (36) hide show
  1. pi_sessions_tui-0.1.0/.github/workflows/ci.yml +32 -0
  2. pi_sessions_tui-0.1.0/.github/workflows/publish.yml +35 -0
  3. pi_sessions_tui-0.1.0/.gitignore +31 -0
  4. pi_sessions_tui-0.1.0/CHANGELOG.md +49 -0
  5. pi_sessions_tui-0.1.0/LICENSE +22 -0
  6. pi_sessions_tui-0.1.0/PKG-INFO +153 -0
  7. pi_sessions_tui-0.1.0/README.md +126 -0
  8. pi_sessions_tui-0.1.0/SPECS.md +467 -0
  9. pi_sessions_tui-0.1.0/pi_sessions/__init__.py +1 -0
  10. pi_sessions_tui-0.1.0/pi_sessions/__main__.py +22 -0
  11. pi_sessions_tui-0.1.0/pi_sessions/core/__init__.py +0 -0
  12. pi_sessions_tui-0.1.0/pi_sessions/core/aliases.py +57 -0
  13. pi_sessions_tui-0.1.0/pi_sessions/core/cache.py +81 -0
  14. pi_sessions_tui-0.1.0/pi_sessions/core/discovery.py +131 -0
  15. pi_sessions_tui-0.1.0/pi_sessions/core/export.py +264 -0
  16. pi_sessions_tui-0.1.0/pi_sessions/core/live.py +23 -0
  17. pi_sessions_tui-0.1.0/pi_sessions/core/manage.py +121 -0
  18. pi_sessions_tui-0.1.0/pi_sessions/core/models.py +106 -0
  19. pi_sessions_tui-0.1.0/pi_sessions/core/parser.py +304 -0
  20. pi_sessions_tui-0.1.0/pi_sessions/core/resume.py +65 -0
  21. pi_sessions_tui-0.1.0/pi_sessions/core/settings.py +24 -0
  22. pi_sessions_tui-0.1.0/pi_sessions/core/watch.py +160 -0
  23. pi_sessions_tui-0.1.0/pi_sessions/ui/__init__.py +0 -0
  24. pi_sessions_tui-0.1.0/pi_sessions/ui/app.py +1555 -0
  25. pi_sessions_tui-0.1.0/pyproject.toml +56 -0
  26. pi_sessions_tui-0.1.0/tests/conftest.py +100 -0
  27. pi_sessions_tui-0.1.0/tests/test_aliases.py +67 -0
  28. pi_sessions_tui-0.1.0/tests/test_cache.py +41 -0
  29. pi_sessions_tui-0.1.0/tests/test_discovery.py +118 -0
  30. pi_sessions_tui-0.1.0/tests/test_export.py +189 -0
  31. pi_sessions_tui-0.1.0/tests/test_manage.py +99 -0
  32. pi_sessions_tui-0.1.0/tests/test_parser.py +165 -0
  33. pi_sessions_tui-0.1.0/tests/test_resume.py +28 -0
  34. pi_sessions_tui-0.1.0/tests/test_settings.py +33 -0
  35. pi_sessions_tui-0.1.0/tests/test_ui.py +455 -0
  36. pi_sessions_tui-0.1.0/tests/test_watch.py +149 -0
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ # a newer push supersedes a pending run on the same branch
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ test:
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest, macos-latest]
19
+ python-version: ["3.10", "3.13"]
20
+ runs-on: ${{ matrix.os }}
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+ - name: Install
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install -e .
30
+ pip install pytest
31
+ - name: Test
32
+ run: pytest -v
@@ -0,0 +1,35 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-python@v5
13
+ with:
14
+ python-version: "3.12"
15
+ - name: Build distributions
16
+ run: |
17
+ python -m pip install --upgrade pip build
18
+ python -m build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ environment: pypi
28
+ permissions:
29
+ id-token: write # required for PyPI Trusted Publishing (OIDC)
30
+ steps:
31
+ - uses: actions/download-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+
9
+ # Environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Tooling
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .coverage
18
+
19
+ # OS
20
+ .DS_Store
21
+
22
+ # Claude Code local settings
23
+ .claude/
24
+
25
+ # pi-sessions live documents
26
+ _session_*.md
27
+ _session_*.html
28
+ _session_*_files/
29
+
30
+ # generated by extras/make-nord-light-theme.py
31
+ nord-light.theme
@@ -0,0 +1,49 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## [0.1.0] — 2026-11-04
6
+
7
+ First release. pi-sessions is a fork of
8
+ [ccsessions](https://github.com/miskiewiczm/ccsessions) 0.4.0 by Marek
9
+ Miśkiewicz (MIT), adapted from Claude Code to the
10
+ [pi](https://github.com/earendil-works/pi) coding agent. The history of
11
+ ccsessions is kept in this repository.
12
+
13
+ ### Changed from ccsessions
14
+ - Reads pi sessions (`~/.pi/agent/sessions/--<cwd>--/<timestamp>_<id>.jsonl`,
15
+ format v3) instead of `~/.claude/projects`. The sessions root follows pi's
16
+ own settings (`PI_CODING_AGENT_SESSION_DIR`, `PI_CODING_AGENT_DIR`), or
17
+ `PI_SESSIONS_ROOT`.
18
+ - pi keeps no session index: titles (`/name`), first prompt, working directory,
19
+ token and cost totals are read from the session file and cached per file
20
+ (mtime + size).
21
+ - pi keeps no record of running sessions: ● means modified in the last
22
+ `PI_SESSIONS_LIVE_SECONDS` (default 120).
23
+ - Resume runs `pi --session <file>` (`PI_SESSIONS_PI_BIN` picks the command,
24
+ `PI_SESSIONS_RESUME_ROOT` rewrites the path for a pi running in a container).
25
+ - Preview and export follow the active branch of pi's session tree, and show
26
+ `!` commands, compactions and displayed extension messages.
27
+ - Project archive is `sessions-archive/` next to the sessions root; session
28
+ delete can go through `trash` (`PI_SESSIONS_TRASH=1`).
29
+ - Command `pisessions`, package `pi-sessions-tui`, settings in
30
+ `~/.config/pi-sessions/`, cache in `~/.cache/pi-sessions/`, env vars
31
+ `PI_SESSIONS_*` instead of `CCSESSIONS_*`.
32
+
33
+ ### Added
34
+ - Cost (USD, as recorded by pi) in the details pane and Markdown export.
35
+ - Model, fork origin (⑂) and branch count for each session.
36
+ - Resizable panes: drag the bars between panes; sizes are remembered per
37
+ layout (wide / narrow), double-click a bar to reset it, "Reset layout" in the
38
+ command palette.
39
+ - The focused pane's border uses the accent colour.
40
+
41
+ ### Removed
42
+ - Claude Code specifics: `sessions-index.json`, sessions whose file lives on
43
+ another machine (✕), sidechains, git branch, worktree labels, legacy alias
44
+ keys.
45
+
46
+ ### Fixed
47
+ - The details pane advertised `w` for the live document; the key is `l`.
48
+ - A session id read from a crafted session header can no longer steer where
49
+ the live document is written.
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marek Miśkiewicz (ccsessions)
4
+ Copyright (c) 2026 Psychobarge (pi-sessions)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.5
2
+ Name: pi-sessions-tui
3
+ Version: 0.1.0
4
+ Summary: Terminal UI for browsing, previewing, resuming and managing pi coding agent sessions
5
+ Project-URL: Homepage, https://github.com/psychobarge/pi-sessions
6
+ Project-URL: Issues, https://github.com/psychobarge/pi-sessions/issues
7
+ Author: Psychobarge, Marek Miśkiewicz
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: pi,pi-coding-agent,sessions,terminal,textual,tui
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Terminals
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: textual>=0.80
26
+ Description-Content-Type: text/markdown
27
+
28
+ # pi-sessions
29
+
30
+ A fast terminal UI for browsing, previewing, resuming and managing
31
+ [pi](https://github.com/earendil-works/pi) coding agent sessions.
32
+
33
+ A fork of [ccsessions](https://github.com/miskiewiczm/ccsessions) by Marek
34
+ Miśkiewicz, which does the same for Claude Code. The full behaviour is
35
+ specified in [SPECS.md](SPECS.md); changes from ccsessions are listed in
36
+ [CHANGELOG.md](CHANGELOG.md).
37
+
38
+ ## Features
39
+
40
+ - **Project & session browser** — every pi project on your machine, newest
41
+ first, with recently-active indicators (●), fork markers (⑂), message
42
+ counts, token usage and cost
43
+ - **Conversation preview** — the tail of the active branch, rendered with
44
+ roles, Markdown for pi's replies, tool calls (⚙), `!` commands (⌘) and
45
+ compaction markers, without opening pi
46
+ - **One-key resume** — `r` replaces the TUI with `pi --session <file>` in the
47
+ session's working directory; `c` copies the command to the clipboard (OSC 52)
48
+ - **Archive & delete** — move sessions out of `pi --resume` (reversibly) or
49
+ delete them for good, per session or per project, with confirmation dialogs
50
+ - **Resizable panes** — drag the bars between panes with the mouse; sizes
51
+ are remembered per layout across runs (`~/.config/pi-sessions/settings.json`)
52
+ - **Export** — Markdown with YAML front matter (ready for Quarto/Pandoc) or the
53
+ raw JSONL, never overwriting an existing file
54
+ - **Live document** — `l` keeps `_session_<id>.md` in sync with a running
55
+ session, so a live-reloading renderer can show it with LaTeX rendered
56
+ - **Fast** — session metadata is cached per file (mtime + size), scanning runs
57
+ off the UI thread, previews read only the tail of large files
58
+
59
+ ## Requirements
60
+
61
+ - Python ≥ 3.10
62
+ - pi installed (`pi` on PATH — needed only for resuming)
63
+ - macOS or Linux
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pipx install pi-sessions-tui # or: uv tool install pi-sessions-tui
69
+ ```
70
+
71
+ Both install the `pisessions` command.
72
+
73
+ Or from a clone:
74
+
75
+ ```bash
76
+ git clone https://github.com/psychobarge/pi-sessions
77
+ pip install -e pi-sessions
78
+ ```
79
+
80
+ ## Usage
81
+
82
+ ```bash
83
+ pisessions
84
+ ```
85
+
86
+ | Key | Action |
87
+ | --- | --- |
88
+ | `j` / `k` / arrows | Move within the focused pane |
89
+ | `Tab` / `Shift+Tab` | Switch panes |
90
+ | `r` | Resume the selected session (in place) |
91
+ | `c` | Copy the resume command to the clipboard |
92
+ | `a` | Archive ↔ restore session · archive ↔ restore project |
93
+ | `d` | Delete session / project (with confirmation) |
94
+ | `n` | Rename project (set a display alias) |
95
+ | `e` | Export the session (Markdown or raw JSONL) |
96
+ | `l` | Follow the session in a live Markdown document |
97
+ | `/` | Filter the focused list (projects or sessions) |
98
+ | `p` | Command palette (change theme) |
99
+ | `Ctrl+R` | Rescan now (a rescan also runs automatically) |
100
+ | `q` | Quit |
101
+
102
+ `a` and `d` act on the **session** when the Sessions pane is focused and on
103
+ the whole **project** when the Projects pane is focused.
104
+
105
+ pi keeps no record of running sessions, so ● means *modified in the last
106
+ `PI_SESSIONS_LIVE_SECONDS` seconds* (default 120). Sessions marked this way
107
+ cannot be archived or deleted.
108
+
109
+ ## Configuration
110
+
111
+ | Variable | Default | Purpose |
112
+ | --- | --- | --- |
113
+ | `PI_SESSIONS_ROOT` | pi's own (`PI_CODING_AGENT_SESSION_DIR`, `$PI_CODING_AGENT_DIR/sessions`, `~/.pi/agent/sessions`) | Where to read sessions |
114
+ | `PI_SESSIONS_PI_BIN` | `pi` | Command used to resume |
115
+ | `PI_SESSIONS_RESUME_ROOT` | — | Rewrite the sessions root in resume commands, for a pi that sees it elsewhere (container) |
116
+ | `PI_SESSIONS_LIVE_SECONDS` | `120` | Recently-active threshold |
117
+ | `PI_SESSIONS_TRASH` | `0` | Delete through the `trash` command |
118
+ | `PI_SESSIONS_LIVE_DIR` | session cwd | Where live documents go (use a plain directory for Quarto projects) |
119
+ | `PI_SESSIONS_REFRESH_SECONDS` | `10` | Auto-refresh interval, `0` disables |
120
+ | `PI_SESSIONS_THEME` | saved choice, else `ansi-dark` | Textual theme |
121
+ | `PI_SESSIONS_CODE_THEME` | follows the theme | Pygments style for code blocks |
122
+ | `PI_SESSIONS_NERD_FONT`, `PI_SESSIONS_EYE`, `PI_SESSIONS_EYE_OFF` | — | Live-document glyphs |
123
+
124
+ Settings and project aliases live in `~/.config/pi-sessions/`, the cache in
125
+ `~/.cache/pi-sessions/`.
126
+
127
+ ### pi in a container
128
+
129
+ If pi runs in Docker with its agent directory in a named volume, the host
130
+ cannot see the sessions. Bind-mount a host directory over the container's
131
+ sessions directory (e.g. `-v ~/.pi/agent/sessions:/root/.pi/agent/sessions`),
132
+ then set `PI_SESSIONS_RESUME_ROOT=/root/.pi/agent/sessions` so resume
133
+ commands use the path pi sees.
134
+
135
+ ## How it works
136
+
137
+ pi stores each session as `<sessions root>/--<encoded cwd>--/<timestamp>_<id>.jsonl`:
138
+ a header line, then entries linked into a tree. pi-sessions reads those files
139
+ and never modifies them. Archiving a session moves it into an `archived/`
140
+ subdirectory, which pi does not list. Archiving a project moves its directory
141
+ to `sessions-archive/` next to the sessions root. Everything happens locally;
142
+ no network requests.
143
+
144
+ ## Development
145
+
146
+ ```bash
147
+ pip install -e . --group dev
148
+ pytest
149
+ ```
150
+
151
+ ## License
152
+
153
+ [MIT](LICENSE)
@@ -0,0 +1,126 @@
1
+ # pi-sessions
2
+
3
+ A fast terminal UI for browsing, previewing, resuming and managing
4
+ [pi](https://github.com/earendil-works/pi) coding agent sessions.
5
+
6
+ A fork of [ccsessions](https://github.com/miskiewiczm/ccsessions) by Marek
7
+ Miśkiewicz, which does the same for Claude Code. The full behaviour is
8
+ specified in [SPECS.md](SPECS.md); changes from ccsessions are listed in
9
+ [CHANGELOG.md](CHANGELOG.md).
10
+
11
+ ## Features
12
+
13
+ - **Project & session browser** — every pi project on your machine, newest
14
+ first, with recently-active indicators (●), fork markers (⑂), message
15
+ counts, token usage and cost
16
+ - **Conversation preview** — the tail of the active branch, rendered with
17
+ roles, Markdown for pi's replies, tool calls (⚙), `!` commands (⌘) and
18
+ compaction markers, without opening pi
19
+ - **One-key resume** — `r` replaces the TUI with `pi --session <file>` in the
20
+ session's working directory; `c` copies the command to the clipboard (OSC 52)
21
+ - **Archive & delete** — move sessions out of `pi --resume` (reversibly) or
22
+ delete them for good, per session or per project, with confirmation dialogs
23
+ - **Resizable panes** — drag the bars between panes with the mouse; sizes
24
+ are remembered per layout across runs (`~/.config/pi-sessions/settings.json`)
25
+ - **Export** — Markdown with YAML front matter (ready for Quarto/Pandoc) or the
26
+ raw JSONL, never overwriting an existing file
27
+ - **Live document** — `l` keeps `_session_<id>.md` in sync with a running
28
+ session, so a live-reloading renderer can show it with LaTeX rendered
29
+ - **Fast** — session metadata is cached per file (mtime + size), scanning runs
30
+ off the UI thread, previews read only the tail of large files
31
+
32
+ ## Requirements
33
+
34
+ - Python ≥ 3.10
35
+ - pi installed (`pi` on PATH — needed only for resuming)
36
+ - macOS or Linux
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pipx install pi-sessions-tui # or: uv tool install pi-sessions-tui
42
+ ```
43
+
44
+ Both install the `pisessions` command.
45
+
46
+ Or from a clone:
47
+
48
+ ```bash
49
+ git clone https://github.com/psychobarge/pi-sessions
50
+ pip install -e pi-sessions
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ```bash
56
+ pisessions
57
+ ```
58
+
59
+ | Key | Action |
60
+ | --- | --- |
61
+ | `j` / `k` / arrows | Move within the focused pane |
62
+ | `Tab` / `Shift+Tab` | Switch panes |
63
+ | `r` | Resume the selected session (in place) |
64
+ | `c` | Copy the resume command to the clipboard |
65
+ | `a` | Archive ↔ restore session · archive ↔ restore project |
66
+ | `d` | Delete session / project (with confirmation) |
67
+ | `n` | Rename project (set a display alias) |
68
+ | `e` | Export the session (Markdown or raw JSONL) |
69
+ | `l` | Follow the session in a live Markdown document |
70
+ | `/` | Filter the focused list (projects or sessions) |
71
+ | `p` | Command palette (change theme) |
72
+ | `Ctrl+R` | Rescan now (a rescan also runs automatically) |
73
+ | `q` | Quit |
74
+
75
+ `a` and `d` act on the **session** when the Sessions pane is focused and on
76
+ the whole **project** when the Projects pane is focused.
77
+
78
+ pi keeps no record of running sessions, so ● means *modified in the last
79
+ `PI_SESSIONS_LIVE_SECONDS` seconds* (default 120). Sessions marked this way
80
+ cannot be archived or deleted.
81
+
82
+ ## Configuration
83
+
84
+ | Variable | Default | Purpose |
85
+ | --- | --- | --- |
86
+ | `PI_SESSIONS_ROOT` | pi's own (`PI_CODING_AGENT_SESSION_DIR`, `$PI_CODING_AGENT_DIR/sessions`, `~/.pi/agent/sessions`) | Where to read sessions |
87
+ | `PI_SESSIONS_PI_BIN` | `pi` | Command used to resume |
88
+ | `PI_SESSIONS_RESUME_ROOT` | — | Rewrite the sessions root in resume commands, for a pi that sees it elsewhere (container) |
89
+ | `PI_SESSIONS_LIVE_SECONDS` | `120` | Recently-active threshold |
90
+ | `PI_SESSIONS_TRASH` | `0` | Delete through the `trash` command |
91
+ | `PI_SESSIONS_LIVE_DIR` | session cwd | Where live documents go (use a plain directory for Quarto projects) |
92
+ | `PI_SESSIONS_REFRESH_SECONDS` | `10` | Auto-refresh interval, `0` disables |
93
+ | `PI_SESSIONS_THEME` | saved choice, else `ansi-dark` | Textual theme |
94
+ | `PI_SESSIONS_CODE_THEME` | follows the theme | Pygments style for code blocks |
95
+ | `PI_SESSIONS_NERD_FONT`, `PI_SESSIONS_EYE`, `PI_SESSIONS_EYE_OFF` | — | Live-document glyphs |
96
+
97
+ Settings and project aliases live in `~/.config/pi-sessions/`, the cache in
98
+ `~/.cache/pi-sessions/`.
99
+
100
+ ### pi in a container
101
+
102
+ If pi runs in Docker with its agent directory in a named volume, the host
103
+ cannot see the sessions. Bind-mount a host directory over the container's
104
+ sessions directory (e.g. `-v ~/.pi/agent/sessions:/root/.pi/agent/sessions`),
105
+ then set `PI_SESSIONS_RESUME_ROOT=/root/.pi/agent/sessions` so resume
106
+ commands use the path pi sees.
107
+
108
+ ## How it works
109
+
110
+ pi stores each session as `<sessions root>/--<encoded cwd>--/<timestamp>_<id>.jsonl`:
111
+ a header line, then entries linked into a tree. pi-sessions reads those files
112
+ and never modifies them. Archiving a session moves it into an `archived/`
113
+ subdirectory, which pi does not list. Archiving a project moves its directory
114
+ to `sessions-archive/` next to the sessions root. Everything happens locally;
115
+ no network requests.
116
+
117
+ ## Development
118
+
119
+ ```bash
120
+ pip install -e . --group dev
121
+ pytest
122
+ ```
123
+
124
+ ## License
125
+
126
+ [MIT](LICENSE)