tabulynx 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.
- tabulynx-0.1.0/.github/workflows/publish-python-package.yml +190 -0
- tabulynx-0.1.0/.gitignore +13 -0
- tabulynx-0.1.0/.python-version +1 -0
- tabulynx-0.1.0/PKG-INFO +314 -0
- tabulynx-0.1.0/README.md +289 -0
- tabulynx-0.1.0/pyproject.toml +45 -0
- tabulynx-0.1.0/sample_data/filters_demo.csv +1001 -0
- tabulynx-0.1.0/sample_data/filters_demo.parquet +0 -0
- tabulynx-0.1.0/scripts/create_sample_data.py +56 -0
- tabulynx-0.1.0/src/tabulynx/__init__.py +15 -0
- tabulynx-0.1.0/src/tabulynx/__main__.py +5 -0
- tabulynx-0.1.0/src/tabulynx/cli.py +39 -0
- tabulynx-0.1.0/src/tabulynx/core.py +832 -0
- tabulynx-0.1.0/src/tabulynx/qt.py +2124 -0
- tabulynx-0.1.0/src/tabulynx/viewer.py +13 -0
- tabulynx-0.1.0/tests/test_core.py +231 -0
- tabulynx-0.1.0/uv.lock +218 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
name: Publish Python Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- development
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: publish-development
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
prepare:
|
|
18
|
+
name: Prepare Release
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
container:
|
|
21
|
+
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
|
22
|
+
outputs:
|
|
23
|
+
should_release: ${{ steps.version.outputs.should_release }}
|
|
24
|
+
version: ${{ steps.version.outputs.version }}
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@v5
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0
|
|
31
|
+
|
|
32
|
+
- name: Detect version bump
|
|
33
|
+
id: version
|
|
34
|
+
shell: bash
|
|
35
|
+
run: |
|
|
36
|
+
current_version="$(python -c 'import tomllib; from pathlib import Path; data = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8")); print(data["project"]["version"])')"
|
|
37
|
+
echo "version=$current_version" >> "$GITHUB_OUTPUT"
|
|
38
|
+
|
|
39
|
+
previous_ref="${{ github.event.before }}"
|
|
40
|
+
if [ -n "$previous_ref" ] && git cat-file -e "${previous_ref}:pyproject.toml" 2>/dev/null; then
|
|
41
|
+
previous_version="$(git show "${previous_ref}:pyproject.toml" | python -c 'import sys, tomllib; data = tomllib.loads(sys.stdin.read()); print(data["project"]["version"])')"
|
|
42
|
+
else
|
|
43
|
+
previous_version=""
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [ "$current_version" = "$previous_version" ]; then
|
|
47
|
+
echo "No version bump detected. Skipping release."
|
|
48
|
+
echo "should_release=false" >> "$GITHUB_OUTPUT"
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
if git rev-parse "refs/tags/v${current_version}" >/dev/null 2>&1; then
|
|
53
|
+
echo "Tag v${current_version} already exists." >&2
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo "should_release=true" >> "$GITHUB_OUTPUT"
|
|
58
|
+
|
|
59
|
+
test_build:
|
|
60
|
+
name: Test & Build
|
|
61
|
+
needs: prepare
|
|
62
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
container:
|
|
65
|
+
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- name: Checkout
|
|
69
|
+
uses: actions/checkout@v5
|
|
70
|
+
|
|
71
|
+
- name: Create venv
|
|
72
|
+
run: uv venv
|
|
73
|
+
|
|
74
|
+
- name: Install project + dev deps
|
|
75
|
+
run: uv sync --group dev
|
|
76
|
+
|
|
77
|
+
- name: Run tests
|
|
78
|
+
run: uv run pytest -q
|
|
79
|
+
|
|
80
|
+
- name: Build package
|
|
81
|
+
run: uv build
|
|
82
|
+
|
|
83
|
+
- name: Upload dist artifacts
|
|
84
|
+
uses: actions/upload-artifact@v4
|
|
85
|
+
with:
|
|
86
|
+
name: dist
|
|
87
|
+
path: dist/*
|
|
88
|
+
if-no-files-found: error
|
|
89
|
+
|
|
90
|
+
publish:
|
|
91
|
+
name: Publish to PyPI
|
|
92
|
+
needs:
|
|
93
|
+
- prepare
|
|
94
|
+
- test_build
|
|
95
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
container:
|
|
98
|
+
image: ghcr.io/astral-sh/uv:python3.12-bookworm
|
|
99
|
+
|
|
100
|
+
steps:
|
|
101
|
+
- name: Download dist artifacts
|
|
102
|
+
uses: actions/download-artifact@v4
|
|
103
|
+
with:
|
|
104
|
+
name: dist
|
|
105
|
+
path: dist
|
|
106
|
+
|
|
107
|
+
- name: Publish to PyPI
|
|
108
|
+
run: uv publish dist/* --token ${{ secrets.PYPI_API_TOKEN }}
|
|
109
|
+
|
|
110
|
+
tag_release:
|
|
111
|
+
name: Tag Release
|
|
112
|
+
needs:
|
|
113
|
+
- prepare
|
|
114
|
+
- publish
|
|
115
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
116
|
+
runs-on: ubuntu-latest
|
|
117
|
+
permissions:
|
|
118
|
+
contents: write
|
|
119
|
+
|
|
120
|
+
steps:
|
|
121
|
+
- name: Checkout
|
|
122
|
+
uses: actions/checkout@v5
|
|
123
|
+
with:
|
|
124
|
+
fetch-depth: 0
|
|
125
|
+
|
|
126
|
+
- name: Create release tag
|
|
127
|
+
shell: bash
|
|
128
|
+
run: |
|
|
129
|
+
version="${{ needs.prepare.outputs.version }}"
|
|
130
|
+
git config user.name "github-actions[bot]"
|
|
131
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
132
|
+
git tag "v${version}" "${GITHUB_SHA}"
|
|
133
|
+
git push origin "v${version}"
|
|
134
|
+
|
|
135
|
+
github_release:
|
|
136
|
+
name: Create GitHub Release
|
|
137
|
+
needs:
|
|
138
|
+
- prepare
|
|
139
|
+
- tag_release
|
|
140
|
+
if: needs.prepare.outputs.should_release == 'true'
|
|
141
|
+
runs-on: ubuntu-latest
|
|
142
|
+
permissions:
|
|
143
|
+
contents: write
|
|
144
|
+
|
|
145
|
+
steps:
|
|
146
|
+
- name: Checkout
|
|
147
|
+
uses: actions/checkout@v5
|
|
148
|
+
with:
|
|
149
|
+
fetch-depth: 0
|
|
150
|
+
|
|
151
|
+
- name: Build release notes
|
|
152
|
+
shell: bash
|
|
153
|
+
run: |
|
|
154
|
+
version="${{ needs.prepare.outputs.version }}"
|
|
155
|
+
previous_tag="$(git tag --sort=-version:refname | grep -v "^v${version}$" | head -n 1)"
|
|
156
|
+
version_notes="release-notes/v${version}.md"
|
|
157
|
+
|
|
158
|
+
if [ -f "$version_notes" ]; then
|
|
159
|
+
cp "$version_notes" release-notes.md
|
|
160
|
+
else
|
|
161
|
+
{
|
|
162
|
+
echo "## Release"
|
|
163
|
+
echo
|
|
164
|
+
echo "This release is published to PyPI."
|
|
165
|
+
echo
|
|
166
|
+
echo "Install with:"
|
|
167
|
+
echo
|
|
168
|
+
echo "\`\`\`bash"
|
|
169
|
+
echo "pip install -U tabulynx"
|
|
170
|
+
echo "\`\`\`"
|
|
171
|
+
} > release-notes.md
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
if [ -n "$previous_tag" ]; then
|
|
175
|
+
{
|
|
176
|
+
echo
|
|
177
|
+
echo "## Full Changelog"
|
|
178
|
+
echo
|
|
179
|
+
echo "https://github.com/${{ github.repository }}/compare/${previous_tag}...v${version}"
|
|
180
|
+
} >> release-notes.md
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
- name: Create GitHub Release
|
|
184
|
+
env:
|
|
185
|
+
GH_TOKEN: ${{ github.token }}
|
|
186
|
+
shell: bash
|
|
187
|
+
run: |
|
|
188
|
+
gh release create "v${{ needs.prepare.outputs.version }}" \
|
|
189
|
+
--notes-file release-notes.md \
|
|
190
|
+
--title "v${{ needs.prepare.outputs.version }}"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
tabulynx-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tabulynx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Desktop spreadsheet-style viewer for CSV, XLSX, and Parquet files
|
|
5
|
+
Project-URL: Homepage, https://github.com/Jeferson-Peter/tabulynx
|
|
6
|
+
Project-URL: Repository, https://github.com/Jeferson-Peter/tabulynx
|
|
7
|
+
Project-URL: Issues, https://github.com/Jeferson-Peter/tabulynx/issues
|
|
8
|
+
Keywords: csv,desktop,parquet,polars,qt,spreadsheet,xlsx
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
11
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Office/Business
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: fastexcel>=0.11.5
|
|
21
|
+
Requires-Dist: openpyxl>=3.1.5
|
|
22
|
+
Requires-Dist: polars>=1.12.0
|
|
23
|
+
Requires-Dist: pyside6>=6.8.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# TabuLynx
|
|
27
|
+
|
|
28
|
+
TabuLynx is a local desktop spreadsheet-style viewer for tabular files. It is meant for opening, exploring, filtering, sorting, querying, and exporting local datasets without starting a web server or using a full spreadsheet suite.
|
|
29
|
+
|
|
30
|
+
It supports:
|
|
31
|
+
|
|
32
|
+
- CSV
|
|
33
|
+
- XLSX
|
|
34
|
+
- Parquet
|
|
35
|
+
|
|
36
|
+
The core is built on `polars`, and the desktop interface is built with `PySide6`.
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- Native desktop table viewer for local tabular files
|
|
41
|
+
- Data-type aware filters for text, numbers, booleans, dates, and datetimes
|
|
42
|
+
- Multi-filter and multi-sort support
|
|
43
|
+
- Global search across columns
|
|
44
|
+
- Column visibility controls
|
|
45
|
+
- Explicit pagination with configurable page size
|
|
46
|
+
- Row details side panel
|
|
47
|
+
- Column statistics side panel
|
|
48
|
+
- Dataset summary side panel
|
|
49
|
+
- Export of the current view to CSV or Parquet
|
|
50
|
+
- SQL queries against the current view using Polars SQL
|
|
51
|
+
- Temporary SQL result tabs
|
|
52
|
+
- SQL examples, SQL clear action, and local SQL history
|
|
53
|
+
- Query presets
|
|
54
|
+
- Multiple files in tabs
|
|
55
|
+
- Recent files and pinned files
|
|
56
|
+
- Last-session restore
|
|
57
|
+
- Query history per tab with back/forward navigation
|
|
58
|
+
- Context menu actions on cells and headers
|
|
59
|
+
- Optimized XLSX browsing through cached Parquet conversion
|
|
60
|
+
- Keyboard shortcuts for common actions
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
Install dependencies:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv sync
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Run the desktop app:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uv run tabulynx
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Open a file directly:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv run tabulynx open ./your-file.csv
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You can also open:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv run tabulynx open ./your-file.xlsx
|
|
86
|
+
uv run tabulynx open ./your-file.parquet
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Basic Workflow
|
|
90
|
+
|
|
91
|
+
1. Open a `csv`, `xlsx`, or `parquet` file.
|
|
92
|
+
2. Use the global search box to quickly reduce the visible rows.
|
|
93
|
+
3. Add filters and sorts from the query area.
|
|
94
|
+
4. Use the `Columns` menu to show or hide columns.
|
|
95
|
+
5. Select a row to inspect full row values in the side panel.
|
|
96
|
+
6. Click a column header to view column statistics.
|
|
97
|
+
7. Use `Export` to save the current view as CSV or Parquet.
|
|
98
|
+
|
|
99
|
+
The current view means the result after applying search, filters, sorts, and visible columns.
|
|
100
|
+
|
|
101
|
+
## SQL Support
|
|
102
|
+
|
|
103
|
+
The SQL panel uses Polars SQL and runs against the current tab's current view. The available table name is always `current`.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
|
|
107
|
+
```sql
|
|
108
|
+
SELECT customer, revenue
|
|
109
|
+
FROM current
|
|
110
|
+
WHERE revenue > 100
|
|
111
|
+
ORDER BY revenue DESC
|
|
112
|
+
LIMIT 50
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Supported today:
|
|
116
|
+
|
|
117
|
+
- Querying the current tab as `current`
|
|
118
|
+
- `SELECT`, `WHERE`, `ORDER BY`, `LIMIT`, and common Polars SQL expressions supported by Polars
|
|
119
|
+
- Aggregations and grouping supported by Polars SQL
|
|
120
|
+
- SQL over the current view, so active search, filters, sorts, and visible columns are applied before the SQL query runs
|
|
121
|
+
- Opening SQL results as temporary result tabs
|
|
122
|
+
- Quick SQL examples
|
|
123
|
+
- Local SQL history
|
|
124
|
+
|
|
125
|
+
Not supported yet:
|
|
126
|
+
|
|
127
|
+
- Cross-tab SQL queries or joins between multiple open files
|
|
128
|
+
- Persistent SQL result tabs across app restarts
|
|
129
|
+
- SQL editing of source files
|
|
130
|
+
- Database features such as indexes, transactions, stored procedures, or user-defined SQL functions
|
|
131
|
+
- Full DuckDB/PostgreSQL-style SQL compatibility
|
|
132
|
+
|
|
133
|
+
## XLSX Handling
|
|
134
|
+
|
|
135
|
+
Excel files are handled differently from CSV and Parquet.
|
|
136
|
+
|
|
137
|
+
For `xlsx`, TabuLynx:
|
|
138
|
+
|
|
139
|
+
- Discovers sheet names up front
|
|
140
|
+
- Lets you switch sheets in the desktop UI
|
|
141
|
+
- Opens workbooks with a read-only ingestion path
|
|
142
|
+
- Converts the selected sheet into cached Parquet
|
|
143
|
+
- Uses the cached Parquet file for faster browsing, filtering, sorting, SQL, and pagination
|
|
144
|
+
|
|
145
|
+
This keeps the UI experience consistent while avoiding repeated direct Excel reads during exploration.
|
|
146
|
+
|
|
147
|
+
Important notes:
|
|
148
|
+
|
|
149
|
+
- The first open of a large sheet may take longer while the cache is created.
|
|
150
|
+
- The cache is invalidated when the source file metadata changes.
|
|
151
|
+
- Excel formulas are read as stored values when available.
|
|
152
|
+
- TabuLynx does not recalculate Excel formulas.
|
|
153
|
+
- TabuLynx does not preserve Excel formatting, formulas, merged cells, charts, or styles during export.
|
|
154
|
+
|
|
155
|
+
## Keyboard Shortcuts
|
|
156
|
+
|
|
157
|
+
- `Ctrl+O`: open file
|
|
158
|
+
- `Ctrl+F`: focus global search
|
|
159
|
+
- `Ctrl+Enter`: run SQL in the current tab
|
|
160
|
+
- `Esc`: clear filters in the current tab
|
|
161
|
+
- Double-click a column header divider: autosize the column
|
|
162
|
+
|
|
163
|
+
## Context Menus
|
|
164
|
+
|
|
165
|
+
Right-click a table cell for quick actions such as:
|
|
166
|
+
|
|
167
|
+
- Copy cell
|
|
168
|
+
- Copy row
|
|
169
|
+
- Filter by selected value
|
|
170
|
+
- Search/filter by selected text
|
|
171
|
+
- Hide the clicked column
|
|
172
|
+
|
|
173
|
+
Right-click a column header for quick column actions such as:
|
|
174
|
+
|
|
175
|
+
- Search in that column
|
|
176
|
+
- Clear filters for that column
|
|
177
|
+
- Sort ascending or descending
|
|
178
|
+
- Hide the column
|
|
179
|
+
|
|
180
|
+
## Presets, Recent Files, And Session State
|
|
181
|
+
|
|
182
|
+
TabuLynx stores local app state under `~/.tabulynx/`.
|
|
183
|
+
|
|
184
|
+
Current local state includes:
|
|
185
|
+
|
|
186
|
+
- Query presets
|
|
187
|
+
- SQL history
|
|
188
|
+
- Recent files
|
|
189
|
+
- Pinned files
|
|
190
|
+
- Last-session restore data
|
|
191
|
+
- XLSX Parquet cache
|
|
192
|
+
|
|
193
|
+
The app state is local to your machine and is not synced or uploaded by TabuLynx.
|
|
194
|
+
|
|
195
|
+
## Library Usage
|
|
196
|
+
|
|
197
|
+
You can also use the core library directly:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from tabulynx import open_dataset
|
|
201
|
+
|
|
202
|
+
dataset = open_dataset("your-file.xlsx", sheet="Sheet1")
|
|
203
|
+
|
|
204
|
+
print(dataset.columns())
|
|
205
|
+
print(dataset.row_count())
|
|
206
|
+
print(dataset.page(0, 100))
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Apply filters and sorts:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from tabulynx.core import ColumnFilter, SortRule, open_dataset
|
|
213
|
+
|
|
214
|
+
dataset = open_dataset("your-file.parquet")
|
|
215
|
+
dataset.add_filter(ColumnFilter(column="revenue", operator="gte", value="100"))
|
|
216
|
+
dataset.set_sorts([SortRule(column="revenue", descending=True)])
|
|
217
|
+
|
|
218
|
+
page = dataset.page(offset=0, limit=50)
|
|
219
|
+
print(page.rows)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Run SQL from Python:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
dataset = open_dataset("your-file.csv")
|
|
226
|
+
|
|
227
|
+
result = dataset.sql_query(
|
|
228
|
+
"""
|
|
229
|
+
SELECT customer, SUM(revenue) AS total_revenue
|
|
230
|
+
FROM current
|
|
231
|
+
GROUP BY customer
|
|
232
|
+
ORDER BY total_revenue DESC
|
|
233
|
+
"""
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
print(result)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Sample Data
|
|
240
|
+
|
|
241
|
+
Sample data for local testing lives in:
|
|
242
|
+
|
|
243
|
+
- `sample_data/filters_demo.csv`
|
|
244
|
+
- `sample_data/filters_demo.parquet`
|
|
245
|
+
|
|
246
|
+
Regenerate the sample files:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
uv run python scripts/create_sample_data.py
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Generate a larger sample:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
uv run python scripts/create_sample_data.py --rows 20000
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Run Tests
|
|
259
|
+
|
|
260
|
+
Install development dependencies:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
uv sync --group dev
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Run the test suite:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
uv run pytest -q
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Project Structure
|
|
273
|
+
|
|
274
|
+
```text
|
|
275
|
+
src/tabulynx/
|
|
276
|
+
__init__.py
|
|
277
|
+
__main__.py
|
|
278
|
+
cli.py
|
|
279
|
+
core.py
|
|
280
|
+
qt.py
|
|
281
|
+
viewer.py
|
|
282
|
+
|
|
283
|
+
sample_data/
|
|
284
|
+
filters_demo.csv
|
|
285
|
+
filters_demo.parquet
|
|
286
|
+
|
|
287
|
+
scripts/
|
|
288
|
+
create_sample_data.py
|
|
289
|
+
|
|
290
|
+
tests/
|
|
291
|
+
test_core.py
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Current Limitations
|
|
295
|
+
|
|
296
|
+
- TabuLynx is a viewer and exploration tool, not a full spreadsheet editor.
|
|
297
|
+
- It does not currently edit cells or save changes back into the original source file.
|
|
298
|
+
- XLSX support uses cached Parquet conversion per selected sheet; very large or irregular workbooks may take time on first open.
|
|
299
|
+
- Excel formulas are not recalculated by TabuLynx.
|
|
300
|
+
- Excel formatting, styles, merged cells, charts, and workbook-specific layout features are not preserved.
|
|
301
|
+
- SQL currently runs only against the current tab's current view as the table `current`.
|
|
302
|
+
- SQL result tabs are temporary and are not restored in the next session.
|
|
303
|
+
- Cross-tab SQL joins are not supported yet.
|
|
304
|
+
- Extremely large datasets may still depend on available memory and local disk cache.
|
|
305
|
+
- The UI is focused on desktop use and is not intended for browser or mobile workflows.
|
|
306
|
+
|
|
307
|
+
## Roadmap Ideas
|
|
308
|
+
|
|
309
|
+
- Cross-tab SQL queries
|
|
310
|
+
- Better SQL editor experience
|
|
311
|
+
- More test coverage for UI state and Excel edge cases
|
|
312
|
+
- More robust XLSX type inference for irregular workbooks
|
|
313
|
+
- Optional app packaging with PyInstaller or Nuitka
|
|
314
|
+
- Screenshots and release packaging documentation
|