tfbpshiny 1.0.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.
- tfbpshiny-1.0.0/LICENSE +14 -0
- tfbpshiny-1.0.0/PKG-INFO +159 -0
- tfbpshiny-1.0.0/README.md +133 -0
- tfbpshiny-1.0.0/pyproject.toml +66 -0
- tfbpshiny-1.0.0/tfbpshiny/__init__.py +0 -0
- tfbpshiny-1.0.0/tfbpshiny/__main__.py +215 -0
- tfbpshiny-1.0.0/tfbpshiny/app.css +344 -0
- tfbpshiny-1.0.0/tfbpshiny/app.py +233 -0
- tfbpshiny-1.0.0/tfbpshiny/brentlab_yeast_collection.yaml +456 -0
- tfbpshiny-1.0.0/tfbpshiny/components.py +481 -0
- tfbpshiny-1.0.0/tfbpshiny/configure_logger.py +134 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/__init__.py +0 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/binding/__init__.py +13 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/binding/queries.py +549 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/binding/server/__init__.py +39 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/binding/server/workspace.py +1233 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/binding/ui.py +104 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/comparison/__init__.py +0 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/comparison/queries.py +769 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/comparison/server/__init__.py +38 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/comparison/server/workspace.py +1738 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/comparison/ui.py +188 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/home/__init__.py +0 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/home/ui.py +109 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/__init__.py +15 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/queries.py +389 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/server/__init__.py +41 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/server/workspace.py +1208 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/ui.py +102 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/__init__.py +0 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/queries.py +330 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/__init__.py +68 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/dataset_row.py +314 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/sidebar.py +867 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/workspace.py +489 -0
- tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/ui.py +607 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/correlation_matrix.py +125 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/perf.py +109 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/plot_formatter.py +41 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/ratelimit.py +114 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/sample_conditions.py +97 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/topn_matrix.py +150 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/vdb_init.py +397 -0
- tfbpshiny-1.0.0/tfbpshiny/utils/vdb_materialize.py +179 -0
- tfbpshiny-1.0.0/tfbpshiny/www/binding.png +0 -0
- tfbpshiny-1.0.0/tfbpshiny/www/perturbation.png +0 -0
tfbpshiny-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Copyright (c) 2024, Chase Mateusiak
|
|
2
|
+
|
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
|
4
|
+
it under the terms of the GNU General Public License as published by
|
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
(at your option) any later version.
|
|
7
|
+
|
|
8
|
+
This program is distributed in the hope that it will be useful,
|
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
GNU General Public License for more details.
|
|
12
|
+
|
|
13
|
+
You should have received a copy of the GNU General Public License
|
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
tfbpshiny-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tfbpshiny
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A shiny app which provides a dashboard to https://huggingface.co/collections/BrentLab/yeastresources
|
|
5
|
+
License: GPL-3.0
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Author: chasem
|
|
8
|
+
Author-email: chasem@wustl.edu
|
|
9
|
+
Requires-Python: >=3.11,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Dist: faicons (>=0.2.2,<0.3.0)
|
|
17
|
+
Requires-Dist: labretriever (>=1.1.2,<2.0.0)
|
|
18
|
+
Requires-Dist: plotly (>=6.0.1,<7.0.0)
|
|
19
|
+
Requires-Dist: python-dotenv (>=1.1.0,<2.0.0)
|
|
20
|
+
Requires-Dist: scikit-learn (>=1.6.1,<2.0.0)
|
|
21
|
+
Requires-Dist: shiny (>=1.4.0,<2.0.0)
|
|
22
|
+
Requires-Dist: shinywidgets (>=0.7.1,<0.8.0)
|
|
23
|
+
Requires-Dist: upsetjs-jupyter-widget (>=1.9.0,<2.0.0)
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# TFBPShiny
|
|
27
|
+
|
|
28
|
+
A Shiny web application for exploring transcription factor binding and perturbation
|
|
29
|
+
data from the [Brent Lab yeast collection](https://huggingface.co/collections/BrentLab/yeastresources).
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Resource Requirements
|
|
34
|
+
|
|
35
|
+
This app requires the following minimum resources to run:
|
|
36
|
+
|
|
37
|
+
- 4GB storage on disk
|
|
38
|
+
- 8GB RAM (10GB or more is recommended for better performance)
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
If you wish to keep the app separated from your local environment, you should first
|
|
43
|
+
create a virtual environment. You can do this with `venv`. `cd` to the directory
|
|
44
|
+
where you want the virtual environment to be created, and run:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m venv tfbpshiny_env
|
|
48
|
+
source tfbpshiny_env/bin/activate
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python -m pip install tfbpshiny
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Run the app:
|
|
58
|
+
|
|
59
|
+
This will download the necessary datasets from huggingface into a cache directory
|
|
60
|
+
that is created in your current working directory. By default, it is called
|
|
61
|
+
`./tfbpshiny_hf_cache`. When you run the app again, if you launch it from the same
|
|
62
|
+
location it will verify that the cache is up to date, and use it, without
|
|
63
|
+
re-downloading. You can also specify a custom cache directory with `--cache-dir`.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python -m tfbpshiny launch
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
To install the latest development version from GitHub, use:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python -m pip install git+https://github.com/BrentLab/tfbpshiny@dev
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For production deployment (EC2/Docker) and shinyapps.io deployment instructions,
|
|
76
|
+
see [docs/development.md](docs/development.md).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Contributing
|
|
81
|
+
|
|
82
|
+
### Setup
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/BrentLab/tfbpshiny.git
|
|
86
|
+
cd tfbpshiny
|
|
87
|
+
poetry install
|
|
88
|
+
pre-commit install
|
|
89
|
+
# First-time Playwright setup (required for E2E tests)
|
|
90
|
+
poetry run playwright install chromium
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Plotly JS bundle
|
|
94
|
+
|
|
95
|
+
The app loads Plotly from a local bundle (`tfbpshiny/www/plotly-3.5.0.min.js`)
|
|
96
|
+
rather than a CDN to avoid race conditions when multiple outputs initialize
|
|
97
|
+
simultaneously. This file is gitignored due to its size (~4.8 MB). After
|
|
98
|
+
cloning, download it once:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
curl -fsSL https://cdn.plot.ly/plotly-3.5.0.min.js \
|
|
102
|
+
-o tfbpshiny/www/plotly-3.5.0.min.js
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
If the `plotly` Python package is upgraded, check the new JS version it expects:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python -c "
|
|
109
|
+
import re, plotly.graph_objects as go
|
|
110
|
+
from plotly.io import to_html
|
|
111
|
+
m = re.search(r'plotly-([\d.]+)\.min\.js', to_html(go.Figure(), include_plotlyjs='cdn'))
|
|
112
|
+
print(m.group(0))
|
|
113
|
+
"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Then download the matching version and update the `src` in `tfbpshiny/app.py`.
|
|
117
|
+
|
|
118
|
+
### Environment variables
|
|
119
|
+
|
|
120
|
+
Create a `.env` file in the repo root to override defaults:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Optional — only needed for private HuggingFace datasets
|
|
124
|
+
HF_TOKEN=<your_huggingface_token>
|
|
125
|
+
|
|
126
|
+
# Optional — override the VirtualDB config path
|
|
127
|
+
VIRTUALDB_CONFIG=/path/to/custom_config.yaml
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Running the app
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
poetry run python -m tfbpshiny --log-level DEBUG launch \
|
|
134
|
+
--port 8010 --host 127.0.0.1 --debug
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Running tests
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
poetry run pytest tests/unit/ # unit tests
|
|
141
|
+
poetry run pytest tests/e2e/ # end-to-end
|
|
142
|
+
poetry run pytest # all tests
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Code quality
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
pre-commit run --all-files
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Branching
|
|
152
|
+
|
|
153
|
+
1. Switch to `dev`: `git switch dev`
|
|
154
|
+
1. Branch from `dev` — **not** `main`: `git switch -c my-feature`
|
|
155
|
+
1. Keep branches small and focused to make review easier
|
|
156
|
+
1. Rebase onto `dev` periodically: `git rebase dev`
|
|
157
|
+
1. When ready, open a pull request targeting the BrentLab `dev`
|
|
158
|
+
branch — **not** `main`
|
|
159
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# TFBPShiny
|
|
2
|
+
|
|
3
|
+
A Shiny web application for exploring transcription factor binding and perturbation
|
|
4
|
+
data from the [Brent Lab yeast collection](https://huggingface.co/collections/BrentLab/yeastresources).
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Resource Requirements
|
|
9
|
+
|
|
10
|
+
This app requires the following minimum resources to run:
|
|
11
|
+
|
|
12
|
+
- 4GB storage on disk
|
|
13
|
+
- 8GB RAM (10GB or more is recommended for better performance)
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
If you wish to keep the app separated from your local environment, you should first
|
|
18
|
+
create a virtual environment. You can do this with `venv`. `cd` to the directory
|
|
19
|
+
where you want the virtual environment to be created, and run:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m venv tfbpshiny_env
|
|
23
|
+
source tfbpshiny_env/bin/activate
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python -m pip install tfbpshiny
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Run the app:
|
|
33
|
+
|
|
34
|
+
This will download the necessary datasets from huggingface into a cache directory
|
|
35
|
+
that is created in your current working directory. By default, it is called
|
|
36
|
+
`./tfbpshiny_hf_cache`. When you run the app again, if you launch it from the same
|
|
37
|
+
location it will verify that the cache is up to date, and use it, without
|
|
38
|
+
re-downloading. You can also specify a custom cache directory with `--cache-dir`.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python -m tfbpshiny launch
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
To install the latest development version from GitHub, use:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pip install git+https://github.com/BrentLab/tfbpshiny@dev
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For production deployment (EC2/Docker) and shinyapps.io deployment instructions,
|
|
51
|
+
see [docs/development.md](docs/development.md).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Contributing
|
|
56
|
+
|
|
57
|
+
### Setup
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/BrentLab/tfbpshiny.git
|
|
61
|
+
cd tfbpshiny
|
|
62
|
+
poetry install
|
|
63
|
+
pre-commit install
|
|
64
|
+
# First-time Playwright setup (required for E2E tests)
|
|
65
|
+
poetry run playwright install chromium
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Plotly JS bundle
|
|
69
|
+
|
|
70
|
+
The app loads Plotly from a local bundle (`tfbpshiny/www/plotly-3.5.0.min.js`)
|
|
71
|
+
rather than a CDN to avoid race conditions when multiple outputs initialize
|
|
72
|
+
simultaneously. This file is gitignored due to its size (~4.8 MB). After
|
|
73
|
+
cloning, download it once:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
curl -fsSL https://cdn.plot.ly/plotly-3.5.0.min.js \
|
|
77
|
+
-o tfbpshiny/www/plotly-3.5.0.min.js
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If the `plotly` Python package is upgraded, check the new JS version it expects:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python -c "
|
|
84
|
+
import re, plotly.graph_objects as go
|
|
85
|
+
from plotly.io import to_html
|
|
86
|
+
m = re.search(r'plotly-([\d.]+)\.min\.js', to_html(go.Figure(), include_plotlyjs='cdn'))
|
|
87
|
+
print(m.group(0))
|
|
88
|
+
"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then download the matching version and update the `src` in `tfbpshiny/app.py`.
|
|
92
|
+
|
|
93
|
+
### Environment variables
|
|
94
|
+
|
|
95
|
+
Create a `.env` file in the repo root to override defaults:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Optional — only needed for private HuggingFace datasets
|
|
99
|
+
HF_TOKEN=<your_huggingface_token>
|
|
100
|
+
|
|
101
|
+
# Optional — override the VirtualDB config path
|
|
102
|
+
VIRTUALDB_CONFIG=/path/to/custom_config.yaml
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Running the app
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
poetry run python -m tfbpshiny --log-level DEBUG launch \
|
|
109
|
+
--port 8010 --host 127.0.0.1 --debug
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Running tests
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
poetry run pytest tests/unit/ # unit tests
|
|
116
|
+
poetry run pytest tests/e2e/ # end-to-end
|
|
117
|
+
poetry run pytest # all tests
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Code quality
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pre-commit run --all-files
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Branching
|
|
127
|
+
|
|
128
|
+
1. Switch to `dev`: `git switch dev`
|
|
129
|
+
1. Branch from `dev` — **not** `main`: `git switch -c my-feature`
|
|
130
|
+
1. Keep branches small and focused to make review easier
|
|
131
|
+
1. Rebase onto `dev` periodically: `git rebase dev`
|
|
132
|
+
1. When ready, open a pull request targeting the BrentLab `dev`
|
|
133
|
+
branch — **not** `main`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "tfbpshiny"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "A shiny app which provides a dashboard to https://huggingface.co/collections/BrentLab/yeastresources"
|
|
5
|
+
authors = ["chasem <chasem@wustl.edu>"]
|
|
6
|
+
license = "GPL-3.0"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
|
|
9
|
+
[tool.poetry.dependencies]
|
|
10
|
+
python = "^3.11"
|
|
11
|
+
labretriever = "^1.1.2"
|
|
12
|
+
shiny = "^1.4.0"
|
|
13
|
+
shinywidgets = "^0.7.1"
|
|
14
|
+
upsetjs-jupyter-widget = "^1.9.0"
|
|
15
|
+
scikit-learn = "^1.6.1"
|
|
16
|
+
plotly = "^6.0.1"
|
|
17
|
+
python-dotenv = "^1.1.0"
|
|
18
|
+
faicons = "^0.2.2"
|
|
19
|
+
|
|
20
|
+
[tool.poetry.group.dev.dependencies]
|
|
21
|
+
ipykernel = "^7.2.0"
|
|
22
|
+
pytest = "^9.0.2"
|
|
23
|
+
nbformat = "^5.10.4"
|
|
24
|
+
playwright = "^1.58.0"
|
|
25
|
+
pytest-playwright = "^0.7.2"
|
|
26
|
+
|
|
27
|
+
[tool.pytest.ini_options]
|
|
28
|
+
minversion = "6.0"
|
|
29
|
+
python_files = [
|
|
30
|
+
"tests.py",
|
|
31
|
+
"test_*.py",
|
|
32
|
+
]
|
|
33
|
+
pythonpath = ['.']
|
|
34
|
+
addopts = "--ignore=tmp"
|
|
35
|
+
|
|
36
|
+
[tool.coverage.run]
|
|
37
|
+
include = ["tfbpshiny/**"]
|
|
38
|
+
omit = ["*/tests/*"]
|
|
39
|
+
|
|
40
|
+
[tool.black]
|
|
41
|
+
line-length = 88
|
|
42
|
+
target-version = ['py311']
|
|
43
|
+
include = '\.py$'
|
|
44
|
+
|
|
45
|
+
[tool.isort]
|
|
46
|
+
profile = "black"
|
|
47
|
+
line_length = 88
|
|
48
|
+
known_first_party = [
|
|
49
|
+
"tfbpshiny",
|
|
50
|
+
]
|
|
51
|
+
skip = ["venv/"]
|
|
52
|
+
|
|
53
|
+
[tool.mypy]
|
|
54
|
+
python_version = "3.11"
|
|
55
|
+
check_untyped_defs = true
|
|
56
|
+
ignore_missing_imports = true
|
|
57
|
+
warn_unused_ignores = false
|
|
58
|
+
warn_redundant_casts = true
|
|
59
|
+
warn_unused_configs = true
|
|
60
|
+
|
|
61
|
+
[tool.pylint.FORMAT]
|
|
62
|
+
max-line-length = 88
|
|
63
|
+
|
|
64
|
+
[build-system]
|
|
65
|
+
requires = ["poetry-core"]
|
|
66
|
+
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import pathlib
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Literal, cast
|
|
9
|
+
|
|
10
|
+
from shiny import run_app
|
|
11
|
+
|
|
12
|
+
from tfbpshiny.configure_logger import LogLevel, configure_logger
|
|
13
|
+
|
|
14
|
+
_DEFAULT_VIRTUALDB_CONFIG = str(
|
|
15
|
+
__import__("pathlib").Path(__file__).parent / "brentlab_yeast_collection.yaml"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
_DEFAULT_CACHE_DIR = "./tfbpshiny_hf_cache"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _apply_cache_dir(cache_dir: str) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Set ``HF_CACHE_DIR`` to the resolved absolute path before any HF imports.
|
|
24
|
+
|
|
25
|
+
Must be called before importing labretriever or huggingface_hub so that
|
|
26
|
+
``snapshot_download`` and ``VirtualDB`` see the overridden path.
|
|
27
|
+
|
|
28
|
+
:param cache_dir: Path to the HuggingFace cache directory.
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
os.environ["HF_CACHE_DIR"] = str(pathlib.Path(cache_dir).resolve())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _run_initialize(
|
|
35
|
+
virtualdb_config: str,
|
|
36
|
+
hf_token: str | None,
|
|
37
|
+
log_level: int,
|
|
38
|
+
log_handler: Literal["console", "file"],
|
|
39
|
+
) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Download all dataset files into the local HuggingFace cache and verify views.
|
|
42
|
+
|
|
43
|
+
Exits the process with code 1 if any download or view-verification step fails.
|
|
44
|
+
|
|
45
|
+
:param virtualdb_config: Path to the VirtualDB YAML config file.
|
|
46
|
+
:param hf_token: Optional HuggingFace token for private repo access.
|
|
47
|
+
:param log_level: Numeric logging level (e.g. ``logging.INFO``).
|
|
48
|
+
:param log_handler: Handler type passed to :func:`configure_logger`.
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
from tfbpshiny.utils.vdb_init import initialize_data
|
|
52
|
+
|
|
53
|
+
configure_logger("shiny", level=log_level, handler_type=log_handler)
|
|
54
|
+
logger = logging.getLogger("shiny")
|
|
55
|
+
|
|
56
|
+
cache_msg = os.environ.get("HF_CACHE_DIR", "(huggingface default)")
|
|
57
|
+
logger.info("Downloading all datasets into HuggingFace cache: %s", cache_msg)
|
|
58
|
+
try:
|
|
59
|
+
vdb, _ = initialize_data(virtualdb_config, hf_token, local_files_only=False)
|
|
60
|
+
except Exception:
|
|
61
|
+
logger.exception("Cache initialization failed.")
|
|
62
|
+
sys.exit(1)
|
|
63
|
+
|
|
64
|
+
logger.info("Verifying all dataset views are readable...")
|
|
65
|
+
views_df = vdb.query(
|
|
66
|
+
"SELECT view_name FROM duckdb_views()"
|
|
67
|
+
" WHERE schema_name = 'main'"
|
|
68
|
+
" AND view_name NOT LIKE 'duckdb_%'"
|
|
69
|
+
" AND view_name NOT LIKE 'sqlite_%'"
|
|
70
|
+
" AND view_name NOT LIKE 'pragma_%'"
|
|
71
|
+
" ORDER BY view_name"
|
|
72
|
+
)
|
|
73
|
+
view_names = views_df["view_name"].tolist()
|
|
74
|
+
failed: list[str] = []
|
|
75
|
+
for view_name in view_names:
|
|
76
|
+
try:
|
|
77
|
+
df = vdb.query(f'SELECT * FROM "{view_name}" LIMIT 1')
|
|
78
|
+
logger.info(" OK %-30s (%d col(s))", view_name, len(df.columns))
|
|
79
|
+
except Exception:
|
|
80
|
+
logger.exception(" FAIL %s", view_name)
|
|
81
|
+
failed.append(view_name)
|
|
82
|
+
|
|
83
|
+
if failed:
|
|
84
|
+
logger.error("Verification failed for: %s", ", ".join(failed))
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
|
|
87
|
+
logger.info("Cache initialization complete.")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def run_launch(args: argparse.Namespace) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Download the dataset cache (unless ``--skip-initialize`` is set), then start the
|
|
93
|
+
app.
|
|
94
|
+
|
|
95
|
+
By default uses ``./tfbpshiny_hf_cache`` as the HuggingFace cache directory so
|
|
96
|
+
a plain ``python -m tfbpshiny launch`` is self-contained: it downloads data on
|
|
97
|
+
first run and serves it on subsequent runs from the same local directory.
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
cache_dir: str = args.cache_dir
|
|
101
|
+
_apply_cache_dir(cache_dir)
|
|
102
|
+
|
|
103
|
+
log_level = LogLevel.from_string(args.log_level)
|
|
104
|
+
hf_token: str | None = os.getenv("HF_TOKEN")
|
|
105
|
+
|
|
106
|
+
if not args.skip_initialize:
|
|
107
|
+
_run_initialize(
|
|
108
|
+
virtualdb_config=args.virtualdb_config,
|
|
109
|
+
hf_token=hf_token,
|
|
110
|
+
log_level=log_level.value,
|
|
111
|
+
log_handler=cast(Literal["console", "file"], args.log_handler),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Env vars are the only reliable way to pass config to uvicorn reload workers,
|
|
115
|
+
# which re-import app.py in a subprocess and cannot see in-process mutations.
|
|
116
|
+
os.environ["TFBPSHINY_LOG_LEVEL"] = str(log_level.value)
|
|
117
|
+
os.environ["TFBPSHINY_LOG_HANDLER"] = args.log_handler
|
|
118
|
+
os.environ["VIRTUALDB_CONFIG"] = args.virtualdb_config
|
|
119
|
+
os.environ["TFBPSHINY_MATERIALIZE"] = "0" if args.no_materialize else "1"
|
|
120
|
+
|
|
121
|
+
kwargs: dict[str, object] = {"port": args.port, "host": args.host}
|
|
122
|
+
if args.debug:
|
|
123
|
+
kwargs.update({"reload": True, "reload_dirs": ["tfbpshiny/shiny_app"]})
|
|
124
|
+
run_app("tfbpshiny.app:app", **kwargs) # type: ignore
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def make_parser() -> argparse.ArgumentParser:
|
|
128
|
+
parser = argparse.ArgumentParser(
|
|
129
|
+
prog="tfbpshiny",
|
|
130
|
+
description=(
|
|
131
|
+
"tfbpshiny — TF Binding and Perturbation Explorer."
|
|
132
|
+
" Use --help after any command."
|
|
133
|
+
),
|
|
134
|
+
epilog="Use 'tfbpshiny <command> --help' for more info on each command.",
|
|
135
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
136
|
+
)
|
|
137
|
+
parser.add_argument(
|
|
138
|
+
"--log-level",
|
|
139
|
+
type=str,
|
|
140
|
+
default="WARNING",
|
|
141
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
142
|
+
help="Set logging level.",
|
|
143
|
+
)
|
|
144
|
+
parser.add_argument(
|
|
145
|
+
"--log-handler",
|
|
146
|
+
type=str,
|
|
147
|
+
default="console",
|
|
148
|
+
choices=["console", "file"],
|
|
149
|
+
help="Set log handler type.",
|
|
150
|
+
)
|
|
151
|
+
parser.add_argument(
|
|
152
|
+
"--virtualdb-config",
|
|
153
|
+
type=str,
|
|
154
|
+
default=_DEFAULT_VIRTUALDB_CONFIG,
|
|
155
|
+
help="Path to the VirtualDB YAML configuration file.",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
159
|
+
|
|
160
|
+
launch_parser = subparsers.add_parser(
|
|
161
|
+
"launch",
|
|
162
|
+
help="Download the dataset cache (first run) and start the Shiny app.",
|
|
163
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
164
|
+
)
|
|
165
|
+
launch_parser.add_argument(
|
|
166
|
+
"--cache-dir",
|
|
167
|
+
type=str,
|
|
168
|
+
default=_DEFAULT_CACHE_DIR,
|
|
169
|
+
help=(
|
|
170
|
+
"HuggingFace cache directory. Datasets are downloaded here on first run "
|
|
171
|
+
"and read from here on subsequent runs. "
|
|
172
|
+
"Equivalent to setting HF_CACHE_DIR."
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
launch_parser.add_argument(
|
|
176
|
+
"--skip-initialize",
|
|
177
|
+
action="store_true",
|
|
178
|
+
default=False,
|
|
179
|
+
help=(
|
|
180
|
+
"Skip the dataset download and verification step. "
|
|
181
|
+
"Use when the cache is already populated and you want a faster startup."
|
|
182
|
+
),
|
|
183
|
+
)
|
|
184
|
+
launch_parser.add_argument(
|
|
185
|
+
"--no-materialize",
|
|
186
|
+
action="store_true",
|
|
187
|
+
default=False,
|
|
188
|
+
help=(
|
|
189
|
+
"Disable in-memory materialization of dataset views at startup. "
|
|
190
|
+
"Reduces startup memory at the cost of slower query performance. "
|
|
191
|
+
"Equivalent to setting TFBPSHINY_MATERIALIZE=0."
|
|
192
|
+
),
|
|
193
|
+
)
|
|
194
|
+
launch_parser.add_argument(
|
|
195
|
+
"--port", type=int, default=8000, help="Port to serve the Shiny app on."
|
|
196
|
+
)
|
|
197
|
+
launch_parser.add_argument(
|
|
198
|
+
"--host", type=str, default="127.0.0.1", help="Host to bind the Shiny app."
|
|
199
|
+
)
|
|
200
|
+
launch_parser.add_argument(
|
|
201
|
+
"--debug", action="store_true", help="Enable debug mode with auto-reload."
|
|
202
|
+
)
|
|
203
|
+
launch_parser.set_defaults(func=run_launch)
|
|
204
|
+
|
|
205
|
+
return parser
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def main() -> None:
|
|
209
|
+
parser = make_parser()
|
|
210
|
+
args = parser.parse_args()
|
|
211
|
+
args.func(args)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if __name__ == "__main__":
|
|
215
|
+
main()
|