sparkstagelapse 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.
@@ -0,0 +1,67 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch: {}
9
+
10
+ concurrency:
11
+ group: ci-${{ github.workflow }}-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ lint:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+ - run: pip install ".[dev]"
23
+ - run: ruff check .
24
+
25
+ test:
26
+ needs: lint
27
+ runs-on: ${{ matrix.os }}
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ os: [ubuntu-latest, macos-latest, windows-latest]
32
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+
36
+ - uses: actions/setup-python@v5
37
+ with:
38
+ python-version: ${{ matrix.python-version }}
39
+
40
+ - name: Install package with dev + tui extras
41
+ run: pip install ".[dev,tui]"
42
+
43
+ - name: Run test suite
44
+ run: pytest --cov=sparkstagelapse --cov-report=xml -v
45
+
46
+ - name: Upload coverage
47
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
48
+ uses: actions/upload-artifact@v4
49
+ with:
50
+ name: coverage-report
51
+ path: coverage.xml
52
+
53
+ build:
54
+ needs: test
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ - uses: actions/setup-python@v5
59
+ with:
60
+ python-version: "3.12"
61
+ - run: pip install build twine
62
+ - run: python -m build
63
+ - run: twine check dist/*
64
+ - uses: actions/upload-artifact@v4
65
+ with:
66
+ name: dist
67
+ path: dist/
@@ -0,0 +1,76 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ target:
9
+ description: "Where to publish"
10
+ required: true
11
+ default: testpypi
12
+ type: choice
13
+ options: [testpypi]
14
+
15
+ jobs:
16
+ build:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - name: Install package with dev extras
26
+ run: pip install ".[dev,tui]"
27
+
28
+ - name: Run test suite
29
+ run: pytest -v
30
+
31
+ - name: Build sdist and wheel
32
+ run: |
33
+ pip install build twine
34
+ python -m build
35
+ twine check dist/*
36
+
37
+ - uses: actions/upload-artifact@v4
38
+ with:
39
+ name: dist
40
+ path: dist/
41
+
42
+ publish-testpypi:
43
+ if: github.event_name == 'workflow_dispatch'
44
+ needs: build
45
+ runs-on: ubuntu-latest
46
+ environment:
47
+ name: testpypi
48
+ url: https://test.pypi.org/p/sparkstagelapse
49
+ permissions:
50
+ id-token: write # required for OIDC trusted publishing, no token/secret needed
51
+ steps:
52
+ - uses: actions/download-artifact@v4
53
+ with:
54
+ name: dist
55
+ path: dist/
56
+ - uses: pypa/gh-action-pypi-publish@release/v1
57
+ with:
58
+ repository-url: https://test.pypi.org/legacy/
59
+
60
+ publish-pypi:
61
+ # Only real PyPI releases are triggered by publishing a GitHub Release
62
+ # (tag a commit, then "Create a new release" from that tag in the UI).
63
+ if: github.event_name == 'release'
64
+ needs: build
65
+ runs-on: ubuntu-latest
66
+ environment:
67
+ name: pypi
68
+ url: https://pypi.org/p/sparkstagelapse
69
+ permissions:
70
+ id-token: write # required for OIDC trusted publishing, no token/secret needed
71
+ steps:
72
+ - uses: actions/download-artifact@v4
73
+ with:
74
+ name: dist
75
+ path: dist/
76
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,280 @@
1
+ # Created by https://www.toptal.com/developers/gitignore/api/python,spark
2
+ # Edit at https://www.toptal.com/developers/gitignore?templates=python,spark
3
+ ## Databricks toolbox ##
4
+ artifacts/
5
+
6
+ ### Python ###
7
+ # Byte-compiled / optimized / DLL files
8
+ __pycache__/
9
+ *.py[cod]
10
+ *$py.class
11
+
12
+ # C extensions
13
+ *.so
14
+
15
+ #VSCODE
16
+ .vscode/
17
+
18
+ # Distribution / packaging
19
+ .Python
20
+ build/
21
+ develop-eggs/
22
+ dist/
23
+ downloads/
24
+ eggs/
25
+ .eggs/
26
+ lib/
27
+ lib64/
28
+ parts/
29
+ sdist/
30
+ var/
31
+ wheels/
32
+ share/python-wheels/
33
+ *.egg-info/
34
+ .installed.cfg
35
+ *.egg
36
+ MANIFEST
37
+
38
+ # PyInstaller
39
+ # Usually these files are written by a python script from a template
40
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
41
+ *.manifest
42
+ *.spec
43
+
44
+ # Installer logs
45
+ pip-log.txt
46
+ pip-delete-this-directory.txt
47
+
48
+ # Unit test / coverage reports
49
+ htmlcov/
50
+ .tox/
51
+ .nox/
52
+ .coverage
53
+ .coverage.*
54
+ .cache
55
+ nosetests.xml
56
+ coverage.xml
57
+ *.cover
58
+ *.py,cover
59
+ .hypothesis/
60
+ .pytest_cache/
61
+ cover/
62
+
63
+ # Translations
64
+ *.mo
65
+ *.pot
66
+
67
+ # Django stuff:
68
+ *.log
69
+ local_settings.py
70
+ db.sqlite3
71
+ db.sqlite3-journal
72
+
73
+ # Flask stuff:
74
+ instance/
75
+ .webassets-cache
76
+
77
+ # Scrapy stuff:
78
+ .scrapy
79
+
80
+ # Sphinx documentation
81
+ docs/_build/
82
+
83
+ # PyBuilder
84
+ .pybuilder/
85
+ target/
86
+
87
+ # Jupyter Notebook
88
+ .ipynb_checkpoints
89
+
90
+ # IPython
91
+ profile_default/
92
+ ipython_config.py
93
+
94
+ # pyenv
95
+ # For a library or package, you might want to ignore these files since the code is
96
+ # intended to run in multiple environments; otherwise, check them in:
97
+ # .python-version
98
+
99
+ # pipenv
100
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
101
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
102
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
103
+ # install all needed dependencies.
104
+ #Pipfile.lock
105
+
106
+ # poetry
107
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
108
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
109
+ # commonly ignored for libraries.
110
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
111
+ #poetry.lock
112
+
113
+ # pdm
114
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
115
+ #pdm.lock
116
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
117
+ # in version control.
118
+ # https://pdm.fming.dev/#use-with-ide
119
+ .pdm.toml
120
+
121
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
122
+ __pypackages__/
123
+
124
+ # Celery stuff
125
+ celerybeat-schedule
126
+ celerybeat.pid
127
+
128
+ # SageMath parsed files
129
+ *.sage.py
130
+
131
+ # Environments
132
+ .env
133
+ .venv
134
+ env/
135
+ venv/
136
+ ENV/
137
+ env.bak/
138
+ venv.bak/
139
+
140
+ # Spyder project settings
141
+ .spyderproject
142
+ .spyproject
143
+
144
+ # Rope project settings
145
+ .ropeproject
146
+
147
+ # mkdocs documentation
148
+ /site
149
+
150
+ # mypy
151
+ .mypy_cache/
152
+ .dmypy.json
153
+ dmypy.json
154
+
155
+ # Pyre type checker
156
+ .pyre/
157
+
158
+ # pytype static type analyzer
159
+ .pytype/
160
+
161
+ # Cython debug symbols
162
+ cython_debug/
163
+
164
+ # PyCharm
165
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
166
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
167
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
168
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
169
+ #.idea/
170
+
171
+ ### Python Patch ###
172
+ # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
173
+ poetry.toml
174
+
175
+ # ruff
176
+ .ruff_cache/
177
+
178
+ # LSP config files
179
+ pyrightconfig.json
180
+
181
+ ### Spark ###
182
+ *#*#
183
+ *.#*
184
+ *.iml
185
+ *.ipr
186
+ *.iws
187
+ *.pyc
188
+ *.pyo
189
+ *.swp
190
+ *~
191
+ .DS_Store
192
+ .classpath
193
+ .ensime
194
+ .ensime_cache/
195
+ .ensime_lucene
196
+ .generated-mima*
197
+ .idea/
198
+ .idea_modules/
199
+ .project
200
+ .pydevproject
201
+ .scala_dependencies
202
+ .settings
203
+ /lib/
204
+ R-unit-tests.log
205
+ R/unit-tests.out
206
+ R/cran-check.out
207
+ R/pkg/vignettes/sparkr-vignettes.html
208
+ R/pkg/tests/fulltests/Rplots.pdf
209
+ build/*.jar
210
+ build/apache-maven*
211
+ build/scala*
212
+ build/zinc*
213
+ cache
214
+ checkpoint
215
+ conf/*.cmd
216
+ conf/*.conf
217
+ conf/*.properties
218
+ conf/*.sh
219
+ conf/*.xml
220
+ conf/java-opts
221
+ conf/slaves
222
+ dependency-reduced-pom.xml
223
+ derby.log
224
+ dev/create-release/*final
225
+ dev/create-release/*txt
226
+ dev/pr-deps/
227
+ docs/_site
228
+ docs/api
229
+ sql/docs
230
+ sql/site
231
+ lib_managed/
232
+ lint-r-report.log
233
+ log/
234
+ logs/
235
+ out/
236
+ project/boot/
237
+ project/build/target/
238
+ project/plugins/lib_managed/
239
+ project/plugins/project/build.properties
240
+ project/plugins/src_managed/
241
+ project/plugins/target/
242
+ python/lib/pyspark.zip
243
+ python/deps
244
+ python/test_coverage/coverage_data
245
+ python/test_coverage/htmlcov
246
+ python/pyspark/python
247
+ reports/
248
+ scalastyle-on-compile.generated.xml
249
+ scalastyle-output.xml
250
+ scalastyle.txt
251
+ spark-*-bin-*.tgz
252
+ spark-tests.log
253
+ src_managed/
254
+ streaming-tests.log
255
+ unit-tests.log
256
+ work/
257
+ docs/.jekyll-metadata
258
+
259
+ # For Hive
260
+ TempStatsStore/
261
+ metastore/
262
+ metastore_db/
263
+ sql/hive-thriftserver/test_warehouses
264
+ warehouse/
265
+ spark-warehouse/
266
+
267
+ # For R session data
268
+ .RData
269
+ .RHistory
270
+ .Rhistory
271
+ *.Rproj
272
+ *.Rproj.*
273
+
274
+ .Rproj.user
275
+
276
+ # For SBT
277
+ .jvmopts
278
+
279
+
280
+ # End of https://www.toptal.com/developers/gitignore/api/python,spark
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: sparkstagelapse
3
+ Version: 0.1.0
4
+ Summary: Affichage interactif de DataFrames (Spark/pandas) en notebook ou en script, via un dashboard web local persistant.
5
+ Project-URL: Homepage, https://github.com/OWNER/sparkstagelapse
6
+ Project-URL: Repository, https://github.com/OWNER/sparkstagelapse
7
+ Requires-Python: >=3.9
8
+ Requires-Dist: fastapi>=0.100
9
+ Requires-Dist: pandas>=1.5
10
+ Requires-Dist: requests>=2.28
11
+ Requires-Dist: rich>=13.0
12
+ Requires-Dist: uvicorn[standard]>=0.23
13
+ Provides-Extra: dev
14
+ Requires-Dist: build>=1.0; extra == 'dev'
15
+ Requires-Dist: httpx>=0.24; extra == 'dev'
16
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
17
+ Requires-Dist: pytest>=7.0; extra == 'dev'
18
+ Requires-Dist: ruff>=0.5; extra == 'dev'
19
+ Requires-Dist: twine>=5.0; extra == 'dev'
20
+ Provides-Extra: tui
21
+ Requires-Dist: textual>=0.40; extra == 'tui'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # sparkstagelapse
25
+
26
+ Interactive DataFrame display (Spark or pandas) — whether you're in a
27
+ notebook, a script, or a Databricks run — backed by a local web dashboard
28
+ that **stays open and up to date even after the script that launched it has
29
+ exited.**
30
+
31
+ ## Installation
32
+
33
+ From the root of this folder:
34
+
35
+ ```bash
36
+ pip install -e .
37
+ # or, if you also want the full-screen explorer (Textual):
38
+ pip install -e ".[tui]"
39
+ ```
40
+
41
+ ## Quick usage
42
+
43
+ ```python
44
+ from sparkstagelapse import display_spark
45
+
46
+ # df = spark.sql("select * from ...")
47
+ display_spark(df, title="Employees") # "auto" mode: notebook -> rich object, script -> web dashboard
48
+ display_spark(df, title="Employees", mode="web") # force the web dashboard
49
+ display_spark(df, title="Employees", mode="tui") # full-screen explorer (blocking)
50
+ display_spark(df, title="Employees", mode="rich") # plain ASCII output in the terminal
51
+ ```
52
+
53
+ Or directly on a pandas DataFrame:
54
+
55
+ ```python
56
+ from sparkstagelapse import SparkDisplay
57
+
58
+ SparkDisplay(pdf, title="Preview").show_web()
59
+ ```
60
+
61
+ ## The persistent dashboard
62
+
63
+ On the first `show_web()` call (or `mode="web"`), the client:
64
+
65
+ 1. Checks whether a server already responds on `127.0.0.1:8765` (`/health`).
66
+ 2. If yes: just pushes the new table to it over HTTP — no new process is
67
+ created.
68
+ 3. If no: **spawns the server as a detached process** (not a thread — a
69
+ daemon thread dies with its parent process, a separate process doesn't).
70
+ Your script keeps running normally, without blocking.
71
+
72
+ The server therefore stays alive after your script exits. The next run —
73
+ even tomorrow, even from a different script — will find the same dashboard
74
+ already open in your browser and update it live over WebSocket.
75
+
76
+ ### Managing the server manually
77
+
78
+ ```bash
79
+ python -m sparkstagelapse.dashboard status
80
+ python -m sparkstagelapse.dashboard stop
81
+ python -m sparkstagelapse.dashboard start # manual foreground start (blocking)
82
+ ```
83
+
84
+ Logs and pid files live in `~/.cache/sparkstagelapse/dashboard_<port>.log` / `.pid`.
85
+
86
+ ### Changing the port / host
87
+
88
+ ```python
89
+ from sparkstagelapse import DashboardClient, SparkDisplay
90
+
91
+ client = DashboardClient(host="127.0.0.1", port=9000)
92
+ SparkDisplay(pdf, title="Preview", _dashboard=client).show_web()
93
+ ```
94
+
95
+ ## Package structure
96
+
97
+ ```
98
+ sparkstagelapse/
99
+ ├── __init__.py # Public API: SparkDisplay, display_spark, DashboardClient
100
+ ├── display.py # SparkDisplay / display_spark — renders depending on context
101
+ └── dashboard/
102
+ ├── app.py # FastAPI app (HTTP + WebSocket routes), in-memory state
103
+ ├── server.py # Server bootstrap (foreground), pid/log files
104
+ ├── client.py # DashboardClient: health-check, detached spawn, HTTP push
105
+ ├── templates.py # HTML/JS template + table -> HTML rendering
106
+ └── __main__.py # CLI: start / stop / status
107
+ ```
108
+
109
+ ## Development
110
+
111
+ ```bash
112
+ pip install -e ".[dev,tui]"
113
+
114
+ ruff check . # lint
115
+ pytest -v # unit + integration tests
116
+ python -m build # build sdist + wheel
117
+ twine check dist/* # validate package metadata before upload
118
+ ```
119
+
120
+ ## CI/CD
121
+
122
+ See `.github/workflows/ci.yml` (lint + test matrix + build, on every push/PR)
123
+ and `.github/workflows/release.yml` (build + publish to PyPI/TestPyPI via
124
+ Trusted Publishing, on tagged GitHub Releases). Before the release workflow
125
+ can actually publish, you need to register this repo as a Trusted Publisher
126
+ on PyPI/TestPyPI — see the CI/CD explanation in this conversation for the
127
+ exact steps.
@@ -0,0 +1,104 @@
1
+ # sparkstagelapse
2
+
3
+ Interactive DataFrame display (Spark or pandas) — whether you're in a
4
+ notebook, a script, or a Databricks run — backed by a local web dashboard
5
+ that **stays open and up to date even after the script that launched it has
6
+ exited.**
7
+
8
+ ## Installation
9
+
10
+ From the root of this folder:
11
+
12
+ ```bash
13
+ pip install -e .
14
+ # or, if you also want the full-screen explorer (Textual):
15
+ pip install -e ".[tui]"
16
+ ```
17
+
18
+ ## Quick usage
19
+
20
+ ```python
21
+ from sparkstagelapse import display_spark
22
+
23
+ # df = spark.sql("select * from ...")
24
+ display_spark(df, title="Employees") # "auto" mode: notebook -> rich object, script -> web dashboard
25
+ display_spark(df, title="Employees", mode="web") # force the web dashboard
26
+ display_spark(df, title="Employees", mode="tui") # full-screen explorer (blocking)
27
+ display_spark(df, title="Employees", mode="rich") # plain ASCII output in the terminal
28
+ ```
29
+
30
+ Or directly on a pandas DataFrame:
31
+
32
+ ```python
33
+ from sparkstagelapse import SparkDisplay
34
+
35
+ SparkDisplay(pdf, title="Preview").show_web()
36
+ ```
37
+
38
+ ## The persistent dashboard
39
+
40
+ On the first `show_web()` call (or `mode="web"`), the client:
41
+
42
+ 1. Checks whether a server already responds on `127.0.0.1:8765` (`/health`).
43
+ 2. If yes: just pushes the new table to it over HTTP — no new process is
44
+ created.
45
+ 3. If no: **spawns the server as a detached process** (not a thread — a
46
+ daemon thread dies with its parent process, a separate process doesn't).
47
+ Your script keeps running normally, without blocking.
48
+
49
+ The server therefore stays alive after your script exits. The next run —
50
+ even tomorrow, even from a different script — will find the same dashboard
51
+ already open in your browser and update it live over WebSocket.
52
+
53
+ ### Managing the server manually
54
+
55
+ ```bash
56
+ python -m sparkstagelapse.dashboard status
57
+ python -m sparkstagelapse.dashboard stop
58
+ python -m sparkstagelapse.dashboard start # manual foreground start (blocking)
59
+ ```
60
+
61
+ Logs and pid files live in `~/.cache/sparkstagelapse/dashboard_<port>.log` / `.pid`.
62
+
63
+ ### Changing the port / host
64
+
65
+ ```python
66
+ from sparkstagelapse import DashboardClient, SparkDisplay
67
+
68
+ client = DashboardClient(host="127.0.0.1", port=9000)
69
+ SparkDisplay(pdf, title="Preview", _dashboard=client).show_web()
70
+ ```
71
+
72
+ ## Package structure
73
+
74
+ ```
75
+ sparkstagelapse/
76
+ ├── __init__.py # Public API: SparkDisplay, display_spark, DashboardClient
77
+ ├── display.py # SparkDisplay / display_spark — renders depending on context
78
+ └── dashboard/
79
+ ├── app.py # FastAPI app (HTTP + WebSocket routes), in-memory state
80
+ ├── server.py # Server bootstrap (foreground), pid/log files
81
+ ├── client.py # DashboardClient: health-check, detached spawn, HTTP push
82
+ ├── templates.py # HTML/JS template + table -> HTML rendering
83
+ └── __main__.py # CLI: start / stop / status
84
+ ```
85
+
86
+ ## Development
87
+
88
+ ```bash
89
+ pip install -e ".[dev,tui]"
90
+
91
+ ruff check . # lint
92
+ pytest -v # unit + integration tests
93
+ python -m build # build sdist + wheel
94
+ twine check dist/* # validate package metadata before upload
95
+ ```
96
+
97
+ ## CI/CD
98
+
99
+ See `.github/workflows/ci.yml` (lint + test matrix + build, on every push/PR)
100
+ and `.github/workflows/release.yml` (build + publish to PyPI/TestPyPI via
101
+ Trusted Publishing, on tagged GitHub Releases). Before the release workflow
102
+ can actually publish, you need to register this repo as a Trusted Publisher
103
+ on PyPI/TestPyPI — see the CI/CD explanation in this conversation for the
104
+ exact steps.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "sparkstagelapse"
7
+ version = "0.1.0"
8
+ description = "Affichage interactif de DataFrames (Spark/pandas) en notebook ou en script, via un dashboard web local persistant."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "pandas>=1.5",
13
+ "fastapi>=0.100",
14
+ "uvicorn[standard]>=0.23",
15
+ "requests>=2.28",
16
+ "rich>=13.0",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ tui = ["textual>=0.40"]
21
+ dev = ["pytest>=7.0", "pytest-cov>=4.0", "ruff>=0.5", "build>=1.0", "twine>=5.0", "httpx>=0.24"]
22
+
23
+ [project.urls]
24
+ Homepage = "https://github.com/OWNER/sparkstagelapse"
25
+ Repository = "https://github.com/OWNER/sparkstagelapse"
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = ["sparkstagelapse"]
29
+
30
+ [tool.pytest.ini_options]
31
+ addopts = "-ra -q"
32
+ testpaths = ["tests"]
33
+
34
+ [tool.ruff]
35
+ line-length = 100
36
+ target-version = "py39"
37
+
38
+ [tool.ruff.lint]
39
+ # Keep this to correctness + import hygiene. This is a small utility package;
40
+ # broad except/log-exception/security-linter opinions (BLE/S/RUF/SIM/C4) add
41
+ # noise without changing behavior, so they're intentionally not selected.
42
+ select = ["E", "F", "I"]
43
+ ignore = ["E501"] # long lines in HTML/CSS template strings aren't worth wrapping
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from .dashboard.client import DashboardClient
4
+ from .display import SparkDisplay, display
5
+
6
+ __all__ = ["SparkDisplay", "display", "DashboardClient"]
7
+
8
+ __version__ = "0.1.0"