Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
99aea1a
build: use migrate-to-uv to move from Poetry to uv
deepyaman May 31, 2026
7bf0b49
docs: map existing codebase
deepyaman May 31, 2026
8d27ceb
docs: initialize project
deepyaman May 31, 2026
7a2ada4
chore: add project config
deepyaman May 31, 2026
ce3cc7f
docs: define v1 requirements
deepyaman May 31, 2026
14a0043
docs: create roadmap (4 phases)
deepyaman May 31, 2026
594dae0
docs: add project research
deepyaman May 31, 2026
f1762cf
docs(01): capture phase context
deepyaman May 31, 2026
c4d7057
docs(01): research phase Pure Foundation
deepyaman May 31, 2026
f89dfed
docs(01): create phase plan (4 plans, 3 waves)
deepyaman May 31, 2026
1600c9b
feat(01-01): register Execute JAX-RS resource in PyLegendSqlServer.java
deepyaman May 31, 2026
c566ec5
test(01-02): add failing tests for to_pure() on service and function …
deepyaman May 31, 2026
22de37c
feat(01-02): implement to_pure() on LegendServiceInputFrameAbstract a…
deepyaman May 31, 2026
557f13b
docs(01-01): complete plan summary - register Execute endpoint and bu…
deepyaman May 31, 2026
d49e9e7
docs(01-02): complete plan summary - implement to_pure() on abstract …
deepyaman May 31, 2026
2247fa7
merge(01-01): Register Execute JAX-RS resource in test server
deepyaman May 31, 2026
7847f0e
merge(01-02): Implement to_pure() on abstract input frames
deepyaman May 31, 2026
cc70e63
docs(phase-01): update tracking after wave 1 (plans 01-01, 01-02 comp…
deepyaman May 31, 2026
7482139
feat(01-03): add execute_pure_string, get_pure_string_schema, _build_…
deepyaman May 31, 2026
ada5720
test(01-03): add e2e tests for execute_pure_string and get_pure_strin…
deepyaman May 31, 2026
0d23482
docs(01-03): complete plan summary - Pure execution methods on Legend…
deepyaman May 31, 2026
14d0590
docs(phase-01): update tracking after wave 2 (plan 01-03 complete)
deepyaman May 31, 2026
8e9757a
feat(01-04): switch LegendQL frames to Pure schema/execution path (PU…
deepyaman May 31, 2026
6e135c3
test(01-04): add Pure-path tests for LegendQL service/function frames…
deepyaman May 31, 2026
434d61e
docs(01-04): complete plan summary - wire LegendQL API to Pure execut…
deepyaman May 31, 2026
50c1bcc
merge(01-04): Wire LegendQL API to Pure execution path end-to-end
deepyaman May 31, 2026
74ba2c1
docs(phase-01): update tracking after wave 3 (plan 01-04 complete)
deepyaman May 31, 2026
3d06cbc
docs(01): add code review report
deepyaman May 31, 2026
71d47de
test(01): add verification report — gaps found in PCT gate and xfail …
deepyaman May 31, 2026
e6dab13
docs(01): add gap-closure plan 01-05 for execute_frame guard and xfai…
deepyaman May 31, 2026
6f826dd
docs(01): revise plan 05 and roadmap based on PCT/SQL analysis
deepyaman Jun 1, 2026
105da90
fix(01-05): delete execute_frame override and _get_legendql_input_pro…
deepyaman Jun 1, 2026
e376879
fix(01-05): remove SQL fallback from LegendClient Pure methods and de…
deepyaman Jun 1, 2026
089d1ab
fix(01-05): remove stale xfail from Pure e2e tests and wire depot cas…
deepyaman Jun 1, 2026
7bb53a2
docs(01-05): complete gap-closure plan 01-05 execution summary
deepyaman Jun 1, 2026
9dddc00
merge(01-05): close verification gaps - delete execute_frame override…
deepyaman Jun 1, 2026
f6a874e
docs(phase-01): update tracking after wave 4 (plan 01-05 complete)
deepyaman Jun 1, 2026
4a023d0
docs(01): update code review report after plan 01-05 gap closure
deepyaman Jun 1, 2026
9995795
test(01): persist human verification items as UAT
deepyaman Jun 1, 2026
808e73d
fix(01): add Pure execute_frame to service/function frames; wire meta…
deepyaman Jun 1, 2026
b166be5
docs(02): research phase - remove legacy code and SQL layer
deepyaman Jun 1, 2026
5061396
docs(02): create phase plan for legacy/SQL removal
deepyaman Jun 1, 2026
69efc3a
docs(02): create phase plan
deepyaman Jun 1, 2026
b2f76c8
feat(02-01): re-home grammar_method decorator to pylegend/utils
deepyaman Jun 1, 2026
781b912
chore(02-01): delete legacy_api, pandas_api, sql, and database direct…
deepyaman Jun 1, 2026
b4e6189
docs(02-01): complete plan 02-01 - grammar_method re-homed and legacy…
deepyaman Jun 1, 2026
06675e7
merge(02-01): bring grammar_method re-home + Legacy/Pandas/SQL deleti…
deepyaman Jun 1, 2026
341cbd8
docs(phase-02): update tracking after wave 1
deepyaman Jun 1, 2026
85f212e
feat(02-02): remove SQL imports and to_sql_expression from primitives…
deepyaman Jun 1, 2026
40e5ce5
feat(02-02): remove SQL imports and methods from operations, expressi…
deepyaman Jun 1, 2026
4b2a623
docs(02-02): complete plan 02-02 - SQL metamodel removed from shared …
deepyaman Jun 1, 2026
37099bd
merge(02-02): bring SQL metamodel removal into main
deepyaman Jun 1, 2026
5b4b819
docs(phase-02): update tracking after wave 2
deepyaman Jun 1, 2026
f425d2f
feat(02-03): remove SQL/pandas from frame abstractions and LegendClient
deepyaman Jun 1, 2026
9ad5343
feat(02-03): remove SQL from extension bases, LegendQL frames, and 17…
deepyaman Jun 1, 2026
0d4a5ce
feat(02-03): clean public __init__.py files and smoke-test import pyl…
deepyaman Jun 1, 2026
2f179ed
docs(02-03): complete plan 02-03 - SQL/pandas surface removed, import…
deepyaman Jun 1, 2026
d15cac3
merge(02-03): bring SQL/pandas surface removal + __init__.py cleanup …
deepyaman Jun 1, 2026
eacb74d
docs(phase-02): update tracking after wave 3
deepyaman Jun 1, 2026
031c55c
refactor(02-04): clean SQL assertions from LegendQL function tests, c…
deepyaman Jun 1, 2026
4f5d5a9
refactor(02-04): clean SQL assertions from shared-language tests and …
deepyaman Jun 2, 2026
16fd5a3
docs(02-04): complete plan 02-04 - SQL assertions removed from retain…
deepyaman Jun 2, 2026
2d0d3d4
merge(02-04): bring test SQL assertion cleanup into main
deepyaman Jun 2, 2026
ba51ab8
docs(phase-02): update tracking after wave 4
deepyaman Jun 2, 2026
574c087
fix(02-04): remove lingering pandas_api lazy imports and clean pandas…
deepyaman Jun 2, 2026
15eb0df
chore(02-05): trim pyproject.toml to requests + ijson runtime deps
deepyaman Jun 2, 2026
f041179
fix(02-05): re-lock with trimmed deps; remove pandas/mockito from ret…
deepyaman Jun 2, 2026
a5f5d71
docs(02-05): complete plan 02-05 - dependency trim, uv re-lock, and t…
deepyaman Jun 2, 2026
92b8000
merge(02-05): bring dependency trim and uv re-lock into main
deepyaman Jun 2, 2026
b2069e3
docs(phase-02): update tracking after wave 5
deepyaman Jun 2, 2026
094d4c8
docs(phase-02): complete phase execution
deepyaman Jun 2, 2026
c57c98c
docs: commit leftover planning artifacts from phases 01-02
deepyaman Jun 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 2 additions & 11 deletions .github/workflows/actions/mypy_type_check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,8 @@ runs:
- name: MyPy Type Check
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Installing mypy"
pip install mypy
echo "Done with installing mypy"
echo "MyPy executable is:" $(which mypy)
echo "Running mypy ./.github/workflows/ --config-file=./.github/workflows/typing/config.cfg"
mypy ./.github/workflows/ --config-file=./.github/workflows/typing/config.cfg
uv run --with mypy mypy ./.github/workflows/ --config-file=./.github/workflows/typing/config.cfg
echo "Running mypy ./pylegend/ ./tests/ --config-file=./.github/workflows/typing/config.cfg"
mypy ./pylegend/ ./tests/ --config-file=./.github/workflows/typing/config.cfg
uv run --with mypy mypy ./pylegend/ ./tests/ --config-file=./.github/workflows/typing/config.cfg
echo "Done with typing check"
33 changes: 11 additions & 22 deletions .github/workflows/actions/poetry_build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

name: Poetry Build
name: Build

description: Poetry Build
description: Build

runs:
using: "composite"
Expand All @@ -24,30 +24,19 @@ runs:
with:
python-version: 3.12

- name: Poetry Install Dependencies
- name: Install Dependencies
uses: ./.github/workflows/actions/poetry_install_dependencies

- name: Poetry Version Bump
- name: Version Bump
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Poetry executable is:" $(which poetry)
poetry version $(poetry version --short).dev$GITHUB_RUN_NUMBER
echo "Updated version is:" $(poetry version --short)
current_version=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])")
uv version "${current_version}.dev${GITHUB_RUN_NUMBER}"
echo "Updated version is:" $(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])")

- name: Poetry Build
- name: Build
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Poetry executable is:" $(which poetry)
echo "Running poetry build"
poetry build
echo "Done with poetry build"
echo "Running uv build"
uv build
echo "Done with build"
16 changes: 5 additions & 11 deletions .github/workflows/actions/poetry_install_dependencies/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.

name: Poetry Install Dependencies
name: Install Dependencies

description: Poetry Install Dependencies
description: Install Dependencies

runs:
using: "composite"
steps:
- name: Poetry Install Dependencies
- name: Install Dependencies
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Poetry executable is:" $(which poetry)
echo "Running poetry install"
poetry install --with dev
echo "Running uv sync"
uv sync
echo "Done with installing dependencies"
19 changes: 5 additions & 14 deletions .github/workflows/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,16 @@ runs:
with:
python-version: ${{ inputs.python-version }}

- name: Install Poetry
- name: Install uv
run: |
echo "Install poetry"
pip install poetry
echo "Install uv"
pip install uv
shell: bash

- name: Setup Virtual Environment
run: |
echo "Python version is:" $(python --version)
echo "Creating and activating virtual environment"
python -m venv .venv
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Done with activating virtual environment"
echo "Python executable is:" $(which python)
echo "Update pip and setuptools"
python -m pip install --upgrade pip setuptools
echo "Creating virtual environment"
uv venv .venv
echo "Setup complete"
shell: bash
2 changes: 1 addition & 1 deletion .github/workflows/cve-scanning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ jobs:
- name: Scan CVEs
run: |
source .venv/bin/activate
poetry install --with dev
uv sync
which safety
safety check --full-report
4 changes: 2 additions & 2 deletions .github/workflows/license-scanning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ jobs:
- name: Scan Licenses
run: |
source .venv/bin/activate
poetry install --with dev
pip-licenses --format=markdown --order=license --allow-only="MIT License;Apache Software License;BSD License;Mozilla Public License 2.0 (MPL 2.0);MIT No Attribution License (MIT-0);Python Software Foundation License;Apache-2.0;BSD-2-Clause;BSD-3-Clause;BSD-3-Clause AND ISC;MIT;PSF-2.0;Apache-2.0 OR BSD-3-Clause;MIT AND Python-2.0;Apache-2.0 OR BSD-2-Clause;BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0;MIT AND PSF-2.0;"
uv sync
pip-licenses --format=markdown --order=license --allow-only="MIT License;Apache Software License;BSD License;Mozilla Public License 2.0 (MPL 2.0);MIT No Attribution License (MIT-0);Python Software Foundation License;Apache-2.0;BSD-2-Clause;BSD-3-Clause;BSD-3-Clause AND ISC;MIT;PSF-2.0;Apache-2.0 OR BSD-3-Clause;MIT AND Python-2.0;Apache-2.0 OR BSD-2-Clause;BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0;MIT AND PSF-2.0;MIT OR Apache-2.0;"
18 changes: 4 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,7 @@ jobs:
id: validate_and_set_image_tag
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Poetry executable is:" $(which poetry)
project_version=$(poetry version --short)
project_version=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])")
release_version=${GITHUB_REF#refs/*/pylegend-}
if [ ${project_version} == ${release_version} ]; then
echo "Version matches"
Expand Down Expand Up @@ -111,13 +105,9 @@ jobs:
PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }}
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
source .venv/Scripts/activate
else
source .venv/bin/activate
fi
echo "Poetry executable is:" $(which poetry)
poetry publish --build --username "$PYPI_USERNAME" --password "$PYPI_PASSWORD"
echo "Building and publishing to PyPI"
uv build
uv publish --username "$PYPI_USERNAME" --password "$PYPI_PASSWORD"

docker_build_push:
name: Build-Push Docker Image
Expand Down
85 changes: 85 additions & 0 deletions .planning/PROJECT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# PyLegend 2.0

## What This Is

PyLegend is a Python client library for the [FINOS Legend](https://legend.finos.org/) platform that enables users to build tabular dataset queries using a Python API, compile them to Pure (the Legend functional query language), and execute them against a Legend engine. Version 2.0 replaces the multi-API architecture with a single Ibis backend (`ibis.legend`), while preserving the LegendQL API as a backwards-compatible wrapper for existing users.

## Core Value

Internal library teams and Legend PCT tests can build and execute TDS queries against a Legend engine using familiar Python APIs without maintaining knowledge of the underlying Pure or engine protocol.

## Requirements

### Validated

- ✓ LegendQL API (`LegendQLApiTdsClient`) with TdsFrame operations (filter, restrict, extend, rename, groupBy, aggregate, join, and all current dataframe operations) — existing
- ✓ Pure expression generation via `to_pure_expression()` — existing
- ✓ Legend service and function frame inputs — existing
- ✓ HTTP client with auth schemes (`HeaderTokenAuthScheme`) — existing
- ✓ Streaming result handlers (CSV, Pandas DataFrame, string) — existing
- ✓ CI matrix across Python 3.9–3.14 on Ubuntu and Windows — existing

### Active

- [ ] Ibis backend registered and importable as `ibis.legend`
- [ ] Ibis backend compiles Ibis table expressions to Pure strings
- [ ] Ibis backend connects to Legend services (for organizations with internal instances)
- [ ] All TdsFrame operations currently in the LegendQL API continue to work via the Ibis backend
- [ ] LegendQL API reimplemented as a thin wrapper over the Ibis backend
- [ ] Legacy API removed
- [ ] Pandas API removed
- [ ] SQL compilation layer removed (not needed; Pure generation is the target output)
- [ ] Legend PCT matrix remains green after rewrite

### Out of Scope

- SQL generation — Pure generation is the only compilation target in 2.0
- Legacy API maintenance — being removed in this milestone
- Pandas API maintenance — being removed in this milestone
- Full `ibis-backends` test suite compliance — Pure/Legend is more limited than typical SQL backends; existing PyLegend operations must work, full suite compliance is deferred
- Pure output formatting options — keep generation simple, no pretty-print/indent config
- Expansion of supported operations beyond what currently works in PyLegend 1.x

## Context

- **Codebase:** See `.planning/codebase/` for full analysis. Current architecture has three parallel API layers (LegendQL, Legacy, Pandas) that all compile to a SQL metamodel, then to vendor SQL. The SQL layer is significant complexity with only the PostgreSQL vendor implemented.
- **Ibis reference:** `https://github.com/deepyaman/ibis-pandas` shows the pattern for registering a custom Ibis backend. The new backend should follow this registration pattern so it's available as `ibis.legend`.
- **PCT tests:** PyLegend appears in the Legend PCT (Protocol Conformance Test) matrix. The exact wiring is unclear but must be preserved. Investigate as part of Phase 1.
- **Pure language:** Capitalized as "Pure" (not PURE) — it is the Legend platform's functional query language, not an acronym. Verify against official Legend documentation during implementation.
- **Internal library users:** Organizations use an internal library that extends PyLegend's TdsFrame. Those users never interact with PyLegend directly — they call methods on TdsFrame subclasses. The method signatures and behavior of TdsFrame operations are the primary backwards-compatibility surface.

## Constraints

- **Backwards compatibility:** LegendQL API public interface must remain stable (method names, signatures, return types on TdsFrame and its operations). Internal implementation can change freely.
- **Python support:** Maintain Python 3.9–3.14 compatibility (existing CI matrix).
- **Ibis:** Must implement as a proper Ibis backend following Ibis's backend registration protocol.
- **Simplicity:** Prefer fewer abstractions over the current three-layer architecture. Removing the SQL metamodel layer is a desired simplification.

## Key Decisions

| Decision | Rationale | Outcome |
|----------|-----------|---------|
| Remove Legacy and Pandas APIs first | Reduces scope; fewer API layers to reconcile during Ibis backend design | — Pending |
| Ibis backend as primary implementation | Industry-standard Python dataframe API; future-proofs PyLegend for ecosystem interop | — Pending |
| LegendQL API wraps Ibis backend | Avoids maintaining two separate query-building layers | — Pending |
| Pure generation only (drop SQL) | SQL compilation was unused complexity; Legend engine accepts Pure natively | — Pending |

## Evolution

This document evolves at phase transitions and milestone boundaries.

**After each phase transition** (via `/gsd-transition`):
1. Requirements invalidated? → Move to Out of Scope with reason
2. Requirements validated? → Move to Validated with phase reference
3. New requirements emerged? → Add to Active
4. Decisions to log? → Add to Key Decisions
5. "What This Is" still accurate? → Update if drifted

**After each milestone** (via `/gsd-complete-milestone`):
1. Full review of all sections
2. Core Value check — still the right priority?
3. Audit Out of Scope — reasons still valid?
4. Update Context with current state

---
*Last updated: 2026-05-31 after initialization*
Loading
Loading