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.
Files changed (39) hide show
  1. snakelit-0.1.0/.github/workflows/ci.yml +60 -0
  2. snakelit-0.1.0/.github/workflows/publish.yml +53 -0
  3. snakelit-0.1.0/CHANGELOG.md +30 -0
  4. snakelit-0.1.0/PKG-INFO +121 -0
  5. snakelit-0.1.0/README.md +109 -0
  6. snakelit-0.1.0/pixi.lock +1895 -0
  7. snakelit-0.1.0/pyproject.toml +49 -0
  8. snakelit-0.1.0/src/snakelit/__init__.py +0 -0
  9. snakelit-0.1.0/src/snakelit/edit.py +43 -0
  10. snakelit-0.1.0/src/snakelit/editor/__init__.py +0 -0
  11. snakelit-0.1.0/src/snakelit/editor/config.py +325 -0
  12. snakelit-0.1.0/src/snakelit/editor/table.py +332 -0
  13. snakelit-0.1.0/src/snakelit/editor/table_schema.py +157 -0
  14. snakelit-0.1.0/src/snakelit/editor/text.py +25 -0
  15. snakelit-0.1.0/src/snakelit/file_explorer.py +302 -0
  16. snakelit-0.1.0/src/snakelit/filetypes.py +37 -0
  17. snakelit-0.1.0/src/snakelit/merge.py +167 -0
  18. snakelit-0.1.0/src/snakelit/preview.py +58 -0
  19. snakelit-0.1.0/src/snakelit/types.py +106 -0
  20. snakelit-0.1.0/src/snakelit/utils/__init__.py +0 -0
  21. snakelit-0.1.0/src/snakelit/utils/format.py +15 -0
  22. snakelit-0.1.0/src/snakelit/utils/json.py +10 -0
  23. snakelit-0.1.0/src/snakelit/utils/schema.py +229 -0
  24. snakelit-0.1.0/src/snakelit/utils/st_layouts.py +23 -0
  25. snakelit-0.1.0/src/snakelit/utils/table.py +101 -0
  26. snakelit-0.1.0/src/snakelit/utils/ui_components.py +118 -0
  27. snakelit-0.1.0/src/snakelit/utils/yaml.py +56 -0
  28. snakelit-0.1.0/src/snakelit/utils/zip.py +60 -0
  29. snakelit-0.1.0/src/snakelit/version_picker.py +215 -0
  30. snakelit-0.1.0/tests/editor/__init__.py +0 -0
  31. snakelit-0.1.0/tests/editor/test_config.py +268 -0
  32. snakelit-0.1.0/tests/editor/test_table.py +261 -0
  33. snakelit-0.1.0/tests/editor/test_table_schema.py +116 -0
  34. snakelit-0.1.0/tests/test_file_explorer.py +371 -0
  35. snakelit-0.1.0/tests/test_json.py +12 -0
  36. snakelit-0.1.0/tests/test_merge.py +80 -0
  37. snakelit-0.1.0/tests/test_schema.py +117 -0
  38. snakelit-0.1.0/tests/test_version_picker.py +143 -0
  39. 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))
@@ -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
+ ```
@@ -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
+ ```