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.
Files changed (46) hide show
  1. tfbpshiny-1.0.0/LICENSE +14 -0
  2. tfbpshiny-1.0.0/PKG-INFO +159 -0
  3. tfbpshiny-1.0.0/README.md +133 -0
  4. tfbpshiny-1.0.0/pyproject.toml +66 -0
  5. tfbpshiny-1.0.0/tfbpshiny/__init__.py +0 -0
  6. tfbpshiny-1.0.0/tfbpshiny/__main__.py +215 -0
  7. tfbpshiny-1.0.0/tfbpshiny/app.css +344 -0
  8. tfbpshiny-1.0.0/tfbpshiny/app.py +233 -0
  9. tfbpshiny-1.0.0/tfbpshiny/brentlab_yeast_collection.yaml +456 -0
  10. tfbpshiny-1.0.0/tfbpshiny/components.py +481 -0
  11. tfbpshiny-1.0.0/tfbpshiny/configure_logger.py +134 -0
  12. tfbpshiny-1.0.0/tfbpshiny/modules/__init__.py +0 -0
  13. tfbpshiny-1.0.0/tfbpshiny/modules/binding/__init__.py +13 -0
  14. tfbpshiny-1.0.0/tfbpshiny/modules/binding/queries.py +549 -0
  15. tfbpshiny-1.0.0/tfbpshiny/modules/binding/server/__init__.py +39 -0
  16. tfbpshiny-1.0.0/tfbpshiny/modules/binding/server/workspace.py +1233 -0
  17. tfbpshiny-1.0.0/tfbpshiny/modules/binding/ui.py +104 -0
  18. tfbpshiny-1.0.0/tfbpshiny/modules/comparison/__init__.py +0 -0
  19. tfbpshiny-1.0.0/tfbpshiny/modules/comparison/queries.py +769 -0
  20. tfbpshiny-1.0.0/tfbpshiny/modules/comparison/server/__init__.py +38 -0
  21. tfbpshiny-1.0.0/tfbpshiny/modules/comparison/server/workspace.py +1738 -0
  22. tfbpshiny-1.0.0/tfbpshiny/modules/comparison/ui.py +188 -0
  23. tfbpshiny-1.0.0/tfbpshiny/modules/home/__init__.py +0 -0
  24. tfbpshiny-1.0.0/tfbpshiny/modules/home/ui.py +109 -0
  25. tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/__init__.py +15 -0
  26. tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/queries.py +389 -0
  27. tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/server/__init__.py +41 -0
  28. tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/server/workspace.py +1208 -0
  29. tfbpshiny-1.0.0/tfbpshiny/modules/perturbation/ui.py +102 -0
  30. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/__init__.py +0 -0
  31. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/queries.py +330 -0
  32. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/__init__.py +68 -0
  33. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/dataset_row.py +314 -0
  34. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/sidebar.py +867 -0
  35. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/server/workspace.py +489 -0
  36. tfbpshiny-1.0.0/tfbpshiny/modules/select_datasets/ui.py +607 -0
  37. tfbpshiny-1.0.0/tfbpshiny/utils/correlation_matrix.py +125 -0
  38. tfbpshiny-1.0.0/tfbpshiny/utils/perf.py +109 -0
  39. tfbpshiny-1.0.0/tfbpshiny/utils/plot_formatter.py +41 -0
  40. tfbpshiny-1.0.0/tfbpshiny/utils/ratelimit.py +114 -0
  41. tfbpshiny-1.0.0/tfbpshiny/utils/sample_conditions.py +97 -0
  42. tfbpshiny-1.0.0/tfbpshiny/utils/topn_matrix.py +150 -0
  43. tfbpshiny-1.0.0/tfbpshiny/utils/vdb_init.py +397 -0
  44. tfbpshiny-1.0.0/tfbpshiny/utils/vdb_materialize.py +179 -0
  45. tfbpshiny-1.0.0/tfbpshiny/www/binding.png +0 -0
  46. tfbpshiny-1.0.0/tfbpshiny/www/perturbation.png +0 -0
@@ -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/>.
@@ -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()