snakelit 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.
- snakelit-0.1.0/.github/workflows/ci.yml +60 -0
- snakelit-0.1.0/.github/workflows/publish.yml +53 -0
- snakelit-0.1.0/CHANGELOG.md +30 -0
- snakelit-0.1.0/PKG-INFO +121 -0
- snakelit-0.1.0/README.md +109 -0
- snakelit-0.1.0/pixi.lock +1895 -0
- snakelit-0.1.0/pyproject.toml +49 -0
- snakelit-0.1.0/src/snakelit/__init__.py +0 -0
- snakelit-0.1.0/src/snakelit/edit.py +43 -0
- snakelit-0.1.0/src/snakelit/editor/__init__.py +0 -0
- snakelit-0.1.0/src/snakelit/editor/config.py +325 -0
- snakelit-0.1.0/src/snakelit/editor/table.py +332 -0
- snakelit-0.1.0/src/snakelit/editor/table_schema.py +157 -0
- snakelit-0.1.0/src/snakelit/editor/text.py +25 -0
- snakelit-0.1.0/src/snakelit/file_explorer.py +302 -0
- snakelit-0.1.0/src/snakelit/filetypes.py +37 -0
- snakelit-0.1.0/src/snakelit/merge.py +167 -0
- snakelit-0.1.0/src/snakelit/preview.py +58 -0
- snakelit-0.1.0/src/snakelit/types.py +106 -0
- snakelit-0.1.0/src/snakelit/utils/__init__.py +0 -0
- snakelit-0.1.0/src/snakelit/utils/format.py +15 -0
- snakelit-0.1.0/src/snakelit/utils/json.py +10 -0
- snakelit-0.1.0/src/snakelit/utils/schema.py +229 -0
- snakelit-0.1.0/src/snakelit/utils/st_layouts.py +23 -0
- snakelit-0.1.0/src/snakelit/utils/table.py +101 -0
- snakelit-0.1.0/src/snakelit/utils/ui_components.py +118 -0
- snakelit-0.1.0/src/snakelit/utils/yaml.py +56 -0
- snakelit-0.1.0/src/snakelit/utils/zip.py +60 -0
- snakelit-0.1.0/src/snakelit/version_picker.py +215 -0
- snakelit-0.1.0/tests/editor/__init__.py +0 -0
- snakelit-0.1.0/tests/editor/test_config.py +268 -0
- snakelit-0.1.0/tests/editor/test_table.py +261 -0
- snakelit-0.1.0/tests/editor/test_table_schema.py +116 -0
- snakelit-0.1.0/tests/test_file_explorer.py +371 -0
- snakelit-0.1.0/tests/test_json.py +12 -0
- snakelit-0.1.0/tests/test_merge.py +80 -0
- snakelit-0.1.0/tests/test_schema.py +117 -0
- snakelit-0.1.0/tests/test_version_picker.py +143 -0
- snakelit-0.1.0/tests/test_yaml.py +43 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
lint:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Install Pixi
|
|
25
|
+
uses: prefix-dev/setup-pixi@v0.10.0
|
|
26
|
+
with:
|
|
27
|
+
environments: test
|
|
28
|
+
|
|
29
|
+
- name: Check formatting
|
|
30
|
+
run: pixi run -e test ruff format --check src tests
|
|
31
|
+
|
|
32
|
+
- name: Lint
|
|
33
|
+
run: pixi run -e test ruff check src tests
|
|
34
|
+
|
|
35
|
+
- name: Typecheck
|
|
36
|
+
run: pixi run -e test pyright src tests
|
|
37
|
+
|
|
38
|
+
test:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- name: Install Pixi
|
|
43
|
+
uses: prefix-dev/setup-pixi@v0.10.0
|
|
44
|
+
with:
|
|
45
|
+
environments: test
|
|
46
|
+
- name: Run tests
|
|
47
|
+
run: pixi run -e test pytest -q
|
|
48
|
+
|
|
49
|
+
build:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v4
|
|
53
|
+
|
|
54
|
+
- name: Install Pixi
|
|
55
|
+
uses: prefix-dev/setup-pixi@v0.10.0
|
|
56
|
+
with:
|
|
57
|
+
environments: publish
|
|
58
|
+
|
|
59
|
+
- name: Build and check package
|
|
60
|
+
run: pixi run --environment publish check
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release-please:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
outputs:
|
|
16
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
17
|
+
steps:
|
|
18
|
+
- uses: googleapis/release-please-action@v5
|
|
19
|
+
id: release
|
|
20
|
+
with:
|
|
21
|
+
# release-type: python updates the version in pyproject.toml,
|
|
22
|
+
# generates CHANGELOG.md, creates the release PR and the tag.
|
|
23
|
+
# Use a dedicated PAT instead of GITHUB_TOKEN if the release PR
|
|
24
|
+
# should itself trigger CI on `main`.
|
|
25
|
+
release-type: python
|
|
26
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
|
|
28
|
+
publish:
|
|
29
|
+
needs: release-please
|
|
30
|
+
if: ${{ needs.release-please.outputs.release_created }}
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
environment:
|
|
33
|
+
name: pypi
|
|
34
|
+
url: https://pypi.org/project/snakelit/
|
|
35
|
+
permissions:
|
|
36
|
+
id-token: write
|
|
37
|
+
contents: read
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Install Pixi
|
|
42
|
+
uses: prefix-dev/setup-pixi@v0.10.0
|
|
43
|
+
with:
|
|
44
|
+
environments: publish
|
|
45
|
+
|
|
46
|
+
- name: Build and check package
|
|
47
|
+
run: pixi run --environment publish check
|
|
48
|
+
|
|
49
|
+
# Trusted Publishing (OIDC): no username/password; the PyPI side must
|
|
50
|
+
# have this repo + workflow (publish.yml) + environment "pypi"
|
|
51
|
+
# registered as a trusted publisher.
|
|
52
|
+
- name: Publish to PyPI
|
|
53
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-11-11)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* class FileExplorer ([ab1ea6c](https://github.com/Hocnonsense/snakelit/commit/ab1ea6c68954300488aed9df93fde9ca67caa151))
|
|
9
|
+
* download and delete popup ([63b075f](https://github.com/Hocnonsense/snakelit/commit/63b075f7f46ba40a9a0e47e24632061a89abb8ec))
|
|
10
|
+
* editors[suffix](path, data, key) ([f8a98ff](https://github.com/Hocnonsense/snakelit/commit/f8a98ff8b606b95c5758254e755df06386a097df))
|
|
11
|
+
* file_explorer ([33f4211](https://github.com/Hocnonsense/snakelit/commit/33f421141fcf250ac50ebb1f8e9c7e01fe17db6b))
|
|
12
|
+
* merge from user ([b5b8191](https://github.com/Hocnonsense/snakelit/commit/b5b8191c5b2190812be4932501f31c63ecc35834))
|
|
13
|
+
* preview file ([12aede5](https://github.com/Hocnonsense/snakelit/commit/12aede5dc0d27f1d278e779f9e2d89914ba765ad))
|
|
14
|
+
* table ([5feb10a](https://github.com/Hocnonsense/snakelit/commit/5feb10afe7a755ed74c7d465726e21f55d622d78))
|
|
15
|
+
* upload ([ea412c9](https://github.com/Hocnonsense/snakelit/commit/ea412c9e27d8ba013822e5a597482f505e138996))
|
|
16
|
+
* upload ([f530031](https://github.com/Hocnonsense/snakelit/commit/f53003130bf6b8b57189f885936c50976af22a0b))
|
|
17
|
+
* version_picker ([7dce8be](https://github.com/Hocnonsense/snakelit/commit/7dce8be04203a42e17850ccb0fa73721ec616401))
|
|
18
|
+
* yaml editor support ([005d754](https://github.com/Hocnonsense/snakelit/commit/005d754c9a3f675e55b66e76aae03612449134c1))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* compatibility ([682a9dc](https://github.com/Hocnonsense/snakelit/commit/682a9dccffa30ec3fcb19d129203b6923ae00038))
|
|
24
|
+
* edit table ([38884d3](https://github.com/Hocnonsense/snakelit/commit/38884d3c6d7fccfef792495960f37fa21b9207af))
|
|
25
|
+
* edit_for(path: str, store: FileStore... ([16a3db9](https://github.com/Hocnonsense/snakelit/commit/16a3db92e3014649bd1fd4156dddaa582b619244))
|
|
26
|
+
* load table ([8605e2e](https://github.com/Hocnonsense/snakelit/commit/8605e2e39430f3e952f3183e5cb3f36cd4b6ee05))
|
|
27
|
+
* merge ([7b7745b](https://github.com/Hocnonsense/snakelit/commit/7b7745bc885f0bf25482d0c603da4854fe87042a))
|
|
28
|
+
* rerun only if success ([9ded74e](https://github.com/Hocnonsense/snakelit/commit/9ded74ee7bbb48ae55f655e078794f9e171cb002))
|
|
29
|
+
* sys.platform != "emscripten ([5bb47e3](https://github.com/Hocnonsense/snakelit/commit/5bb47e324030d330b133d6ee8ef0ee6bbd7e0308))
|
|
30
|
+
* table with schema ([ceebdc9](https://github.com/Hocnonsense/snakelit/commit/ceebdc963f741bf2723961eff18baca521e1561e))
|
snakelit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: snakelit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reusable Streamlit widgets for Snakemake workflows
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: jsonschema<5,>=4
|
|
7
|
+
Requires-Dist: pyyaml<7,>=6
|
|
8
|
+
Requires-Dist: streamlit<2,>=1.55
|
|
9
|
+
Provides-Extra: tables
|
|
10
|
+
Requires-Dist: polars<3,>=1.30; extra == 'tables'
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# snakelit
|
|
14
|
+
|
|
15
|
+
Reusable Streamlit widgets for Snakemake workflows.
|
|
16
|
+
|
|
17
|
+
`snakelit` collects the UI pieces that otherwise get copied between the Snakemake workflow catalog's browser app and SRPtn.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
### File explorer
|
|
21
|
+
|
|
22
|
+
`FileExplorer` knows nothing about the filesystem. Implement `FileStore` and
|
|
23
|
+
hand it over:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import streamlit as st
|
|
27
|
+
|
|
28
|
+
from snakelit.file_explorer import FileExplorer
|
|
29
|
+
from snakelit.types import FileStore, Stat
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MemoryStore(FileStore): ...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if "explorer" not in st.session_state:
|
|
36
|
+
st.session_state["explorer"] = FileExplorer(
|
|
37
|
+
"files", MemoryStore({"notes.txt": b"hello\n"})
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
st.session_state["explorer"].render()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Click the folder and files to preview and edit, supports uploads and downloads.
|
|
44
|
+
`FileExplorer(..., on_zip=callback)` adds an "Unzip and trigger merge" action for a single uploaded `.zip`; the callback receives `(name, bytes)` and returns whether the page should rerun.
|
|
45
|
+
|
|
46
|
+
### Schema-driven editors
|
|
47
|
+
|
|
48
|
+
`snakelit` enables edit configfiles and tables with optional schema.
|
|
49
|
+
Schemas are read-only and used to choose widgets, coerce values and report errors.
|
|
50
|
+
|
|
51
|
+
#### Configuration
|
|
52
|
+
|
|
53
|
+
`schema_config` renders a config document as a form and falls back to a raw YAML/JSON editor.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from snakelit.editor.config import schema_config
|
|
57
|
+
|
|
58
|
+
errors: list[str] = []
|
|
59
|
+
updated = schema_config(
|
|
60
|
+
data,
|
|
61
|
+
errors,
|
|
62
|
+
schema,
|
|
63
|
+
header="Workflow configuration",
|
|
64
|
+
key="config",
|
|
65
|
+
format="yaml",
|
|
66
|
+
)
|
|
67
|
+
if updated is not None:
|
|
68
|
+
store.write("config/config.yaml", updated)
|
|
69
|
+
for message in errors:
|
|
70
|
+
st.error(message)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Passing `edit_file=callback` adds a button next to string values that look like paths; the host decides whether to open or create the file.
|
|
74
|
+
|
|
75
|
+
#### Tables
|
|
76
|
+
|
|
77
|
+
`schema_table` does the same for tables and uses the declared row schema to cast columns before editing and validate every row afterwards. It needs the `tables` extra and accepts `csv`, `tsv`, `parquet` and `xlsx`:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from snakelit.editor.table import schema_table
|
|
81
|
+
|
|
82
|
+
errors: list[str] = []
|
|
83
|
+
updated = schema_table(
|
|
84
|
+
data,
|
|
85
|
+
errors,
|
|
86
|
+
schema,
|
|
87
|
+
key="samples",
|
|
88
|
+
format="tsv",
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Merge view
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from snakelit.merge import diff_files, render_merge
|
|
96
|
+
|
|
97
|
+
render_merge(
|
|
98
|
+
store,
|
|
99
|
+
"Merge me/wf@main (abc1234)",
|
|
100
|
+
diff_files(store, incoming),
|
|
101
|
+
base=original_files,
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Rows can be applied, finished or deleted; an empty dict means the merge is complete.
|
|
106
|
+
|
|
107
|
+
## Install
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install snakelit
|
|
111
|
+
pip install "snakelit[tables]" # table editor and table preview
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Python 3.11+ and Streamlit 1.55+.
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pixi run -e test pytest -q
|
|
120
|
+
pixi run -e publish check
|
|
121
|
+
```
|
snakelit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# snakelit
|
|
2
|
+
|
|
3
|
+
Reusable Streamlit widgets for Snakemake workflows.
|
|
4
|
+
|
|
5
|
+
`snakelit` collects the UI pieces that otherwise get copied between the Snakemake workflow catalog's browser app and SRPtn.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
### File explorer
|
|
9
|
+
|
|
10
|
+
`FileExplorer` knows nothing about the filesystem. Implement `FileStore` and
|
|
11
|
+
hand it over:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import streamlit as st
|
|
15
|
+
|
|
16
|
+
from snakelit.file_explorer import FileExplorer
|
|
17
|
+
from snakelit.types import FileStore, Stat
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MemoryStore(FileStore): ...
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if "explorer" not in st.session_state:
|
|
24
|
+
st.session_state["explorer"] = FileExplorer(
|
|
25
|
+
"files", MemoryStore({"notes.txt": b"hello\n"})
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
st.session_state["explorer"].render()
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Click the folder and files to preview and edit, supports uploads and downloads.
|
|
32
|
+
`FileExplorer(..., on_zip=callback)` adds an "Unzip and trigger merge" action for a single uploaded `.zip`; the callback receives `(name, bytes)` and returns whether the page should rerun.
|
|
33
|
+
|
|
34
|
+
### Schema-driven editors
|
|
35
|
+
|
|
36
|
+
`snakelit` enables edit configfiles and tables with optional schema.
|
|
37
|
+
Schemas are read-only and used to choose widgets, coerce values and report errors.
|
|
38
|
+
|
|
39
|
+
#### Configuration
|
|
40
|
+
|
|
41
|
+
`schema_config` renders a config document as a form and falls back to a raw YAML/JSON editor.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from snakelit.editor.config import schema_config
|
|
45
|
+
|
|
46
|
+
errors: list[str] = []
|
|
47
|
+
updated = schema_config(
|
|
48
|
+
data,
|
|
49
|
+
errors,
|
|
50
|
+
schema,
|
|
51
|
+
header="Workflow configuration",
|
|
52
|
+
key="config",
|
|
53
|
+
format="yaml",
|
|
54
|
+
)
|
|
55
|
+
if updated is not None:
|
|
56
|
+
store.write("config/config.yaml", updated)
|
|
57
|
+
for message in errors:
|
|
58
|
+
st.error(message)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Passing `edit_file=callback` adds a button next to string values that look like paths; the host decides whether to open or create the file.
|
|
62
|
+
|
|
63
|
+
#### Tables
|
|
64
|
+
|
|
65
|
+
`schema_table` does the same for tables and uses the declared row schema to cast columns before editing and validate every row afterwards. It needs the `tables` extra and accepts `csv`, `tsv`, `parquet` and `xlsx`:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from snakelit.editor.table import schema_table
|
|
69
|
+
|
|
70
|
+
errors: list[str] = []
|
|
71
|
+
updated = schema_table(
|
|
72
|
+
data,
|
|
73
|
+
errors,
|
|
74
|
+
schema,
|
|
75
|
+
key="samples",
|
|
76
|
+
format="tsv",
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Merge view
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from snakelit.merge import diff_files, render_merge
|
|
84
|
+
|
|
85
|
+
render_merge(
|
|
86
|
+
store,
|
|
87
|
+
"Merge me/wf@main (abc1234)",
|
|
88
|
+
diff_files(store, incoming),
|
|
89
|
+
base=original_files,
|
|
90
|
+
)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Rows can be applied, finished or deleted; an empty dict means the merge is complete.
|
|
94
|
+
|
|
95
|
+
## Install
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install snakelit
|
|
99
|
+
pip install "snakelit[tables]" # table editor and table preview
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Python 3.11+ and Streamlit 1.55+.
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pixi run -e test pytest -q
|
|
108
|
+
pixi run -e publish check
|
|
109
|
+
```
|