Skip to content

Commit 6a628c5

Browse files
committed
Update documentation and dependencies for Excel file handling
- Enhanced `CHANGELOG.md` to include notable libraries in the documentation. - Updated `README.md` to reference the new libraries documentation. - Added `fastavro`, `fastexcel`, and `XlsxWriter` to `requirements.txt` to support Excel and Avro file operations. - Modified `data_loader.py` to improve Excel file reading functionality, ensuring files open correctly on the first sheet unless specified otherwise.
1 parent 41bbb1d commit 6a628c5

7 files changed

Lines changed: 104 additions & 7 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
1313
live preview on the first 200 rows. Results open as a view like AI results (`/api/transform/*`).
1414
- Open-source project files: license, contributing guide, code of conduct, security policy, issue and pull
1515
request templates, and CI.
16-
- Documentation under `docs/`.
16+
- Documentation under `docs/`, including [a list of notable libraries](docs/libraries.md) linked from the README.
1717
- Sidebar badges: loaded datasets show icons for whether they are indexed for searching and optimized for
1818
browsing (`GET /api/datasets/features`).
1919
- **Optimize for browsing**: for large files whose deep pages load slowly (Parquet written as huge row groups,
@@ -24,6 +24,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
2424
### Fixed
2525

2626
- `.gitignore` no longer excludes `package.json`, `package-lock.json` and `tsconfig*.json`.
27+
- Excel and Avro files could not be opened, and Excel export failed: `requirements.txt` now includes fastexcel,
28+
XlsxWriter and fastavro, and Excel files open on the first sheet unless a sheet is chosen.
2729
- Column details showed an empty distribution for list, array and struct columns. List items are now counted
2830
(number lists get a histogram of their items), struct values are shown as JSON, and the counts are computed
2931
lazily.

‎README.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ Full instructions: [docs/getting-started.md](docs/getting-started.md).
112112
| [Architecture](docs/architecture.md) | Components and data flow |
113113
| [API reference](docs/api-reference.md) | REST endpoints |
114114
| [Development](docs/development.md) | Setup, tests, conventions |
115+
| [Libraries](docs/libraries.md) | Notable libraries and what they are used for |
115116
| [Troubleshooting](docs/troubleshooting.md) | Common problems |
116117

117118
## Tech stack
@@ -123,6 +124,8 @@ Full instructions: [docs/getting-started.md](docs/getting-started.md).
123124
| NumPy (search index) | zustand, TanStack Query/Table |
124125
| httpx (OpenAI-compatible LLM APIs) | Recharts, CodeMirror 6 |
125126

127+
See [docs/libraries.md](docs/libraries.md) for every notable library, its version, what it does here and its license.
128+
126129
## Project structure
127130

128131
```

‎backend/app/services/data_loader.py‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,7 @@ def _read_orc_lazy(self, path: str, **options) -> pl.LazyFrame:
226226

227227
def _read_excel_lazy(self, path: str, format: DataFormat, **options) -> pl.LazyFrame:
228228
"""Read Excel file."""
229-
sheet_name = options.get("sheet_name", 0)
230-
df = pl.read_excel(path, sheet_name=sheet_name, **options)
231-
return df.lazy()
229+
return self._read_excel_eager(path, format, **options).lazy()
232230

233231
def load_eager(self, path: str, format: Optional[DataFormat] = None, **options) -> pl.DataFrame:
234232
"""Load data eagerly as DataFrame."""
@@ -295,9 +293,15 @@ def _read_orc_eager(self, path: str, **options) -> pl.DataFrame:
295293
return pl.from_arrow(table)
296294

297295
def _read_excel_eager(self, path: str, format: DataFormat, **options) -> pl.DataFrame:
298-
"""Read Excel file eagerly."""
299-
sheet_name = options.get("sheet_name", 0)
300-
return pl.read_excel(path, sheet_name=sheet_name, **options)
296+
"""Read Excel file eagerly (the first sheet unless sheet_name or sheet_id is given)."""
297+
options = dict(options)
298+
sheet = options.pop("sheet_name", None)
299+
if isinstance(sheet, int):
300+
options["sheet_id"] = sheet + 1
301+
elif sheet:
302+
options["sheet_name"] = sheet
303+
options.setdefault("sheet_id", None if "sheet_name" in options else 1)
304+
return pl.read_excel(path, **options)
301305

302306
def get_schema(self, lf: pl.LazyFrame) -> List[ColumnSchema]:
303307
"""Extract schema from LazyFrame."""

‎backend/requirements.txt‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ colorama==0.4.6
99
cramjam==2.13.0
1010
et_xmlfile==2.0.0
1111
fastapi==0.142.4
12+
fastavro==1.13.1
13+
fastexcel==0.21.0
1214
fastparquet==2026.9.0
1315
fsspec==2026.9.0
1416
h11==0.16.0
@@ -55,5 +57,6 @@ typing_extensions==4.16.0
5557
tzdata==2026.5
5658
uvicorn==0.54.0
5759
xlrd==2.0.2
60+
XlsxWriter==3.2.9
5861
xxhash==4.0.1
5962
zstandard==0.25.0

‎backend/tests/test_formats.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Formats that need optional packages (fastexcel, XlsxWriter, fastavro) read and write with requirements.txt."""
2+
import fastavro
3+
import polars as pl
4+
import pytest
5+
6+
from app.models.schemas import DataFormat
7+
from app.services.data_loader import DataLoader
8+
9+
DF = pl.DataFrame({"text": ["a", "b"], "n": [1, 2]})
10+
11+
12+
@pytest.mark.parametrize("sheet", [{}, {"sheet_name": "Sheet1"}, {"sheet_name": 0}, {"sheet_id": 1}])
13+
def test_excel_round_trip(tmp_path, sheet):
14+
path = str(tmp_path / "data.xlsx")
15+
loader = DataLoader()
16+
loader.write(DF, path, DataFormat.XLSX)
17+
assert loader.load_lazy(path, **sheet).collect().equals(DF)
18+
19+
20+
def test_avro_read(tmp_path):
21+
path = tmp_path / "data.avro"
22+
schema = {"type": "record", "name": "r", "fields": [
23+
{"name": "text", "type": "string"}, {"name": "n", "type": "long"}]}
24+
with open(path, "wb") as f:
25+
fastavro.writer(f, schema, DF.to_dicts())
26+
assert DataLoader().load_lazy(str(path)).collect().equals(DF)

‎docs/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Polars and a React frontend shows them in the browser.
2525
| [API reference](api-reference.md) | Every REST endpoint |
2626
| [Frontend guide](frontend.md) | Structure, state, component rules |
2727
| [Development](development.md) | Local setup, tests, code style, adding features |
28+
| [Libraries](libraries.md) | Notable libraries, versions, licenses and what each is used for |
2829

2930
## Project
3031

‎docs/libraries.md‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Libraries
2+
3+
Data Expert is built on open-source libraries. This page lists the notable ones, what each does in the app, and
4+
where to learn more. Exact versions are pinned in [`backend/requirements.txt`](../backend/requirements.txt) and
5+
[`frontend/package.json`](../frontend/package.json) (resolved in `package-lock.json`).
6+
7+
## Backend (Python 3.14)
8+
9+
| Library | Version | Used for | License |
10+
|---------|---------|----------|---------|
11+
| [FastAPI](https://fastapi.tiangolo.com/) | 0.142 | REST API: routes, request validation, OpenAPI docs at `/docs` | MIT |
12+
| [Starlette](https://www.starlette.io/) | 1.7 | ASGI toolkit under FastAPI; streamed downloads | BSD-3-Clause |
13+
| [Uvicorn](https://www.uvicorn.org/) | 0.54 | ASGI server that runs the backend (`python -m app.main`) | BSD-3-Clause |
14+
| [sse-starlette](https://github.com/sysid/sse-starlette) | 3.5 | Server-sent events for streamed AI responses | BSD-3-Clause |
15+
| [Pydantic](https://docs.pydantic.dev/) v2 | 2.14 | Request and response models, AI plan validation | MIT |
16+
| [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) | 2.15 | Settings from `config.yaml` and environment variables | MIT |
17+
| [PyYAML](https://pyyaml.org/) | 6.0 | Reads `config.yaml` | MIT |
18+
| [Polars](https://pola.rs/) | 2.0 | The data engine: lazy reading of every format, paging, search scans, edits, transforms, statistics, export | MIT |
19+
| [PyArrow](https://arrow.apache.org/docs/python/) | 25 | Parquet metadata (instant file open), streaming row readers, Arrow IPC browse copies, ORC | Apache-2.0 |
20+
| [NumPy](https://numpy.org/) | 2.5 | Search index fingerprints and vectorized statistics | BSD-3-Clause |
21+
| [HTTPX](https://www.python-httpx.org/) | 0.28 | Calls to OpenAI-compatible, Anthropic and Gemini model APIs | BSD-3-Clause |
22+
| [fastexcel](https://github.com/ToucanToco/fastexcel) | 0.21 | Reading Excel files (`.xlsx`, `.xls`) through Polars | MIT |
23+
| [XlsxWriter](https://xlsxwriter.readthedocs.io/) | 3.2 | Exporting to Excel through Polars | BSD-2-Clause |
24+
| [fastavro](https://fastavro.readthedocs.io/) | 1.13 | Reading Avro files | MIT |
25+
26+
## Frontend (React + TypeScript)
27+
28+
| Library | Version | Used for | License |
29+
|---------|---------|----------|---------|
30+
| [React](https://react.dev/) | 18 | UI components | MIT |
31+
| [TypeScript](https://www.typescriptlang.org/) | 5 | Static types for the whole frontend | Apache-2.0 |
32+
| [Vite](https://vite.dev/) | 8 | Dev server and production build | MIT |
33+
| [Tailwind CSS](https://tailwindcss.com/) | 3 | Styling | MIT |
34+
| [Radix UI](https://www.radix-ui.com/primitives) | 1–2 | Accessible primitives behind `src/components/ui/` (select, tabs, dropdown, checkbox, scroll area) | MIT |
35+
| [TanStack Table](https://tanstack.com/table) | 8 | The Browse data table: columns, sizing, row selection | MIT |
36+
| [TanStack Query](https://tanstack.com/query) | 5 | Server-state caching and request deduplication | MIT |
37+
| [zustand](https://zustand.docs.pmnd.rs/) | 4 | Global state stores (`src/stores/`) | MIT |
38+
| [axios](https://axios-http.com/) | 1 | HTTP client behind every `src/lib/*Api.ts` module | MIT |
39+
| [Recharts](https://recharts.org/) | 2.12 | Charts in Stats and column details | MIT |
40+
| [CodeMirror 6](https://codemirror.net/) via [@uiw/react-codemirror](https://uiwjs.github.io/react-codemirror/) | 6 / 4.25 | JSON row editor and code views | MIT |
41+
| [lucide-react](https://lucide.dev/) | 0.303 | Icons | ISC |
42+
| [react-hot-toast](https://react-hot-toast.com/) | 2 | Notifications | MIT |
43+
| [clsx](https://github.com/lukeed/clsx) + [tailwind-merge](https://github.com/dcastil/tailwind-merge) | 2 / 3 | Combining class names (`cn()` helper) | MIT |
44+
45+
## Development and testing
46+
47+
| Library | Used for | License |
48+
|---------|----------|---------|
49+
| [pytest](https://pytest.org/) and [pytest-asyncio](https://pytest-asyncio.readthedocs.io/) | Backend test suite (`cd backend && pytest`) | MIT / Apache-2.0 |
50+
| [mypy](https://mypy-lang.org/) | Optional static type checks for the backend | MIT |
51+
| [ESLint](https://eslint.org/) 9 with [typescript-eslint](https://typescript-eslint.io/), react-hooks and react-refresh plugins | Frontend linting (`npm run lint`) | MIT |
52+
| [PostCSS](https://postcss.org/) and [Autoprefixer](https://github.com/postcss/autoprefixer) | Tailwind build pipeline | MIT |
53+
54+
## AI model servers
55+
56+
Data Expert does not bundle a model. It talks to any OpenAI-compatible server (for example
57+
[llama.cpp](https://github.com/ggml-org/llama.cpp), [Ollama](https://ollama.com/), [LM Studio](https://lmstudio.ai/)
58+
or [vLLM](https://docs.vllm.ai/)) and to hosted providers. See [AI assistant](ai-assistant.md).

0 commit comments

Comments
 (0)