Skip to content

Commit 0413086

Browse files
authored
refactor(package): stable lakeflow_framework import namespace with bundled config/schemas (#87)
* feat(package): restructure src/ into pip-installable lakeflow_framework package - Introduce src/lakeflow_framework/ as a proper Python package with pyproject.toml (hatchling build); config/ and schemas/ bundled as package data - Implement Strategy B (Workspace Files-first) resolver in config_resolver: load_framework_default_json resolves via Workspace Files → importlib.resources → local/config/ overlay; load_framework_schema returns an importlib.resources traversable for bundled JSON schemas - Reduce src/*.py shims to thin re-exports from lakeflow_framework for backward compat - Add contrib/ extension point with README and __init__ stub - Add tests: test_package.py (import surface), test_strategy_b_resolver.py (resolver + schema) - Update all internal imports across dataflow/, dataflow_spec_builder/, and support modules - Add docs: ADR-0008 (package layout), ADR-0009 (Workspace Files-first resolver), deploy_wheel.rst, deploy_framework_overview.rst, contributor_contrib.rst; update all existing docs/ pages to reference lakeflow_framework imports - Align operational metadata, templates, logging, config, validator, and test docs with the packaged layout; extend the spelling wordlist; rephrase historized to history-tracked in samples README.
1 parent 3fd7580 commit 0413086

169 files changed

Lines changed: 4172 additions & 2182 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,41 @@ The framework supports centralized and domain-oriented operating models, and acc
2323
- Support for batch and streaming pipelines across Bronze/Silver/Gold, aligned to your chosen modelling pattern
2424
- Flexible for centralized and domain-oriented operating models
2525

26+
## Prerequisites
27+
28+
- Access to a Databricks workspace
29+
- Databricks CLI installed and authenticated (`databricks auth login` for your workspace, or a configured CLI profile)
30+
- Familiarity with Databricks Lakeflow Spark Declarative Pipelines concepts
31+
2632
## Quick start
2733

34+
Deploy the framework:
35+
2836
```bash
2937
git clone https://github.com/databricks-solutions/lakeflow_framework.git
3038
cd lakeflow_framework
31-
pip install -r requirements-dev.txt
39+
databricks bundle deploy -t dev
3240
```
3341

34-
Then:
35-
36-
1. Open the hosted docs: https://databricks-solutions.github.io/lakeflow_framework/
37-
2. Deploy the framework using the `Deploy Framework` guide
38-
3. Deploy samples from `samples/` using the documentation walkthroughs
39-
4. Build your first pipeline bundle using the `Build a Pipeline Bundle` guide
42+
Deploy samples (requires the framework above): see [samples/README.md](samples/README.md) for bundle descriptions and deploy scripts (`deploy.sh`, `deploy_feature_samples.sh`, `deploy_tpch.sh`, and others).
4043

41-
## Prerequisites
44+
```bash
45+
cd samples
46+
./deploy.sh
47+
```
4248

43-
- Access to a Databricks workspace
44-
- Databricks CLI installed and configured
45-
- Python environment with project dependencies installed
46-
- Familiarity with Databricks Lakeflow Spark Declarative Pipelines concepts
49+
Full deployment steps, configuration options, and walkthroughs are in the public docs [Getting Started](https://databricks-solutions.github.io/lakeflow_framework/current/getting_started.html) section.
4750

4851
## Repository structure
4952

50-
- `docs/` - Sphinx documentation and versioned docs build tooling
51-
- `samples/` - example framework and pipeline bundles
52-
- `src/` - framework source code and runtime components
53+
- `docs/` — Sphinx documentation and versioned docs build tooling
54+
- `samples/` — example framework and pipeline bundles
55+
- `src/` — framework bundle root deployed to the workspace (`framework.sourcePath` in DAB)
56+
- `lakeflow_framework/` — canonical Python package: runtime code, bundled default config (`config/default/`), and JSON schemas (`schemas/`). Prefer `from lakeflow_framework...` imports in new code.
57+
- `*.py` at `src/` root — backward-compatibility shims for legacy bare imports (e.g. `from constants import ...`); removed at v1.0.0
58+
- `local/` — customer-owned sparse config and extensions; never overwritten by upstream upgrades ([src/local/README.md](src/local/README.md))
59+
60+
See [Import conventions](https://databricks-solutions.github.io/lakeflow_framework/contributor_imports.html)
5361

5462
## Version compatibility
5563

@@ -69,10 +77,33 @@ The framework is actively maintained. Databricks support does not cover this rep
6977
Please refer to the [documentation](https://databricks-solutions.github.io/lakeflow_framework/) for further details and an explanation of the samples.
7078
The documentation needs to be deployed as HTML or Markdown within your org before it can be used.
7179

80+
### Local development quick start (contributors)
81+
82+
Clone the repository, then set up a Python 3.12 environment. This is a minimal local quick start — full contributor guidance (VS Code setup, lockfiles, deployment, and PR workflow) is in the documentation under **Framework Development & Contributors**.
83+
84+
```bash
85+
git clone https://github.com/databricks-solutions/lakeflow_framework.git
86+
cd lakeflow_framework
87+
python -m venv .venv
88+
source .venv/bin/activate # Windows: .venv\Scripts\activate
89+
pip install --require-hashes --no-deps -r requirements-dev.lock
90+
```
91+
92+
For editable installs and IDE auto-complete: `pip install -e ".[contrib]"` (see [Development Environment Setup](https://databricks-solutions.github.io/lakeflow_framework/contributor_dev_env.html)).
93+
94+
Run unit tests:
95+
96+
```bash
97+
pytest tests/ -m "not integration and not spark"
98+
```
99+
100+
See also `tests/README.md` and `docs/source/contributor_imports.rst` in the repository.
101+
72102
### Local docs development (optional)
73103

104+
Requires dev dependencies from `requirements-dev.lock`:
105+
74106
```bash
75-
pip install -r requirements-docs.txt
76107
make -C docs html
77108
```
78109

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.19.0
1+
v0.20.0
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# ADR-0008: `lakeflow_framework` pip-installable package
2+
3+
**Date:** 2026-05-23
4+
**Status:** Accepted
5+
**PR:** refactor/lakeflow-framework-package (v0.20.0)
6+
7+
---
8+
9+
## Context
10+
11+
The framework shipped as a flat collection of `.py` files directly under `src/`.
12+
Consumers cloned the repository and added `src/` to `sys.path` via
13+
`framework.sourcePath` — effectively a "copy the source" distribution model.
14+
15+
This had three structural problems:
16+
17+
1. **No stable import namespace.** All modules were importable as bare names
18+
(`from constants import ...`, `from bundle_loader import ...`). Any module
19+
name in a customer's pipeline bundle could shadow a framework module.
20+
21+
2. **No pip distribution path.** Teams that manage Python dependencies via PyPI,
22+
a UC Volume, or Artifactory had no clean way to consume the framework. Every
23+
consumer was forced to clone the repository and re-deploy it as a DAB bundle.
24+
25+
3. **Data files (config, schemas) lived outside any package.** `src/config/default/`
26+
and `src/schemas/` were loaded via hard-coded `os.path` joins relative to
27+
`framework.sourcePath`. There was no mechanism to bundle these files with a
28+
wheel and access them portably.
29+
30+
The project's `pyproject.toml` did not exist; `setup.py` or any standard packaging
31+
entry point was absent.
32+
33+
## Decision
34+
35+
Introduce a proper Python package under `src/lakeflow_framework/` and a
36+
`pyproject.toml` at the repository root.
37+
38+
### Package layout
39+
40+
```
41+
src/
42+
lakeflow_framework/
43+
__init__.py ← public API + __version__
44+
constants.py ← FrameworkPaths, enums
45+
config_resolver.py
46+
bundle_loader.py
47+
logger.py
48+
dlt_pipeline_builder.py
49+
...
50+
config/
51+
default/ ← bundled default config (package data)
52+
schemas/ ← bundled JSON schemas (package data)
53+
dataflow/
54+
flows/
55+
dataflow_spec_builder/
56+
contrib/
57+
__init__.py ← scaffold; empty until first module lands
58+
README.rst
59+
```
60+
61+
All imports inside the package use **absolute `lakeflow_framework.*` names**.
62+
No bare imports remain inside `src/lakeflow_framework/`.
63+
64+
### Compat shims
65+
66+
The old flat `src/*.py` locations (e.g. `src/constants.py`,
67+
`src/bundle_loader.py`) are replaced by thin re-export shims:
68+
69+
```python
70+
# src/constants.py — compat shim, remove at v1.0.0
71+
from lakeflow_framework.constants import * # noqa: F401,F403
72+
```
73+
74+
Existing pipeline notebooks and bundles that import bare names continue to work
75+
without change until `v1.0.0`.
76+
77+
### `pyproject.toml`
78+
79+
```toml
80+
[build-system]
81+
requires = ["setuptools>=68", "wheel"]
82+
build-backend = "setuptools.backends.legacy:build"
83+
84+
[project]
85+
name = "lakeflow-framework"
86+
dynamic = ["version"]
87+
...
88+
89+
[tool.setuptools.dynamic]
90+
version = { file = "VERSION" }
91+
92+
[tool.setuptools.packages.find]
93+
where = ["src"]
94+
95+
[tool.setuptools.package-data]
96+
lakeflow_framework = [
97+
"config/default/**/*",
98+
"schemas/**/*",
99+
]
100+
```
101+
102+
`VERSION` is the single source of truth for the release version; both
103+
`importlib.metadata` (wheel installs) and a direct file read (editable / flat
104+
deploy) converge on it.
105+
106+
### `contrib` subpackage
107+
108+
`src/lakeflow_framework/contrib/` is introduced as a scaffold with an empty
109+
`__init__.py` and a support-policy `README.rst`. No modules land in this PR.
110+
See `docs/decisions/0008-*` (this file) for the publish model and
111+
`docs/source/contributor_contrib.rst` for the contributor guide.
112+
113+
### Optional extras
114+
115+
```
116+
pip install lakeflow-framework # core only
117+
pip install "lakeflow-framework[contrib]" # + future contrib extras
118+
pip install "lakeflow-framework[all]" # everything
119+
```
120+
121+
The `contrib` extra is currently empty; installing it is a no-op until a contrib
122+
module is added.
123+
124+
### Deprecation timeline
125+
126+
| Version | Action |
127+
|---------|--------|
128+
| v0.20.0 | `src/lakeflow_framework/` package introduced; bare `src/` imports still work via shims |
129+
| v1.0.0 | Compat shims at old flat `src/*.py` paths removed |
130+
131+
## Consequences
132+
133+
- Teams can now `pip install lakeflow-framework` from PyPI, a UC Volume, or
134+
Artifactory. The wheel bundles default config and schemas; no separate file
135+
deployment is required.
136+
- The `lakeflow_framework.*` import namespace is globally unique; no shadow-import
137+
risk with customer code.
138+
- Existing flat-deploy customers are unaffected: the `src/` shims preserve
139+
backward compatibility, and `framework.sourcePath` + Workspace Files-first
140+
resolution (ADR-0009) means behaviour is identical to pre-v0.20.0.
141+
- Editable installs (`pip install -e ".[contrib]"`) are supported for local
142+
development; the `src/` layout ensures the installed package and the source
143+
tree are the same directory.
144+
- `docs/conf.py` reads `release` from the `VERSION` file at build time — the
145+
version shown in HTML headers is always current without manual edits.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# ADR-0009: Strategy B — Workspace Files-first config and schema resolution
2+
3+
**Date:** 2026-05-23
4+
**Status:** Accepted
5+
**PR:** refactor/lakeflow-framework-package (v0.20.0)
6+
7+
---
8+
9+
## Context
10+
11+
With the introduction of the `lakeflow_framework` Python package (ADR-0008),
12+
default config files (`config/default/`) and JSON schemas (`schemas/`) are
13+
bundled inside the wheel via `importlib.resources`. Previously they lived only
14+
in Workspace Files at `{framework_path}/lakeflow_framework/config/default/`.
15+
16+
Two deployments now co-exist:
17+
18+
| Deploy mode | Where defaults live |
19+
|-------------|---------------------|
20+
| Flat DAB deploy | On workspace files under `framework.sourcePath` |
21+
| Wheel install | Bundled inside the wheel (`importlib.resources`) |
22+
| Wheel + local overlay | Wheel bundled, plus `src/local/config/` fragments |
23+
24+
The resolver (`load_framework_default_json`) must decide which source to read
25+
first when both a Workspace Files path and the wheel package data are potentially available.
26+
27+
### Options considered
28+
29+
**Option A — Package-first (wheel-first)**
30+
- Always read from `importlib.resources`; treat Workspace Files as an optional
31+
override layer.
32+
- `+` Simple: the wheel is always the canonical source of defaults.
33+
- `` **Breaking for existing flat-deploy customers.** Their defaults live in
34+
Workspace Files; if the wheel shadow-contains a newer (or different) version of a default
35+
file, behaviour silently changes on upgrade.
36+
- `` Contradicts the "explicit wins" principle: a customer who set
37+
`framework.sourcePath` explicitly expects Workspace Files to be authoritative.
38+
39+
**Option B — Workspace Files-first (chosen)**
40+
- When `framework.sourcePath` is set and the file exists in Workspace Files, use it.
41+
- Fall back to `importlib.resources` only when no Workspace Files path is configured or
42+
the file is absent from Workspace Files.
43+
- Always deep-merge `src/local/config/` overlay on top (unchanged from
44+
ADR-0006).
45+
46+
**Option C — Explicit-only**
47+
- Require callers to pass either a Workspace Files path or `importlib.resources` traversable;
48+
no automatic fallback.
49+
- `` Forces every call site to be aware of the deploy mode; adds boilerplate
50+
at all 15+ call sites.
51+
52+
## Decision
53+
54+
Adopt **Strategy B (Workspace Files-first)** via `load_framework_default_json`:
55+
56+
```python
57+
def load_framework_default_json(
58+
name: str,
59+
framework_path: Optional[str] = None,
60+
) -> Dict:
61+
"""
62+
Resolution order:
63+
1. Workspace Files — {framework_path}/lakeflow_framework/config/default/{name}
64+
if framework_path is set and the file exists.
65+
2. Package data — importlib.resources (wheel or src/lakeflow_framework/ on sys.path).
66+
3. src/local/config/{name} overlay — deep-merged on top of (1) or (2)
67+
when framework_path is set and the fragment exists.
68+
"""
69+
```
70+
71+
### Resolution sequence in detail
72+
73+
1. **Workspace Files (explicit):** if `framework_path` is provided and
74+
`{framework_path}/lakeflow_framework/config/default/{name}` exists, load it.
75+
2. **Package data (fallback):** otherwise use
76+
`importlib.resources.files("lakeflow_framework") / "config" / "default" / name`.
77+
This works for both an installed wheel and an editable / flat-deploy install
78+
(the `src/lakeflow_framework/` directory is on `sys.path` in both cases).
79+
3. **Local overlay:** if `framework_path` is set and
80+
`{framework_path}/src/local/config/{name}` exists, deep-merge it on top of
81+
whichever base was loaded (dict keys merged recursively; overlay wins on
82+
conflict; non-dict values replaced wholesale). This preserves the ADR-0006
83+
sparse-overlay guarantee regardless of deploy mode.
84+
85+
The same logic applies to schema resolution via
86+
`load_framework_schema(name)` in `config_resolver`, which returns an
87+
`importlib.resources` traversable suitable for `jsonschema.RefResolver` and
88+
similar validators.
89+
90+
### Rationale for Workspace Files-first
91+
92+
- **Zero-change upgrade for flat-deploy customers.** Their `framework.sourcePath`
93+
points to the deployed `src/` directory in Workspace Files; those files are
94+
found at step 1 and the wheel is never consulted. Behaviour is identical to
95+
pre-v0.20.0.
96+
- **Explicit wins.** Setting `framework.sourcePath` is a deliberate act.
97+
Workspace Files-first honours that intent; package-first would silently override it.
98+
- **Wheel-install customers get clean defaults from the package.** They do not
99+
set `framework.sourcePath` (or set it only for local overlays), so step 1
100+
is skipped and `importlib.resources` is used — exactly as expected.
101+
- **Testability.** Workspace Files-first is trivially testable: point
102+
`framework_path` at a temp directory and place a fixture file there.
103+
Package-data fallback is also testable by omitting `framework_path`.
104+
105+
## Consequences
106+
107+
- **`load_framework_default_json`** is the single resolver for all default
108+
config and schema reads; call sites that previously used
109+
`os.path.join(framework_path, FrameworkPaths.CONFIG_PATH, name)` are
110+
migrated to it.
111+
- Flat-deploy customers see **no behaviour change** on upgrade to v0.20.0.
112+
- Wheel-install customers get defaults from the wheel with no `framework.sourcePath`
113+
required.
114+
- The `src/local/config/` sparse overlay (ADR-0006) continues to work in all
115+
three deploy modes — it is applied at step 3 independent of which base was
116+
used in steps 1–2.
117+
- If a future release ships an intentionally different default (e.g. a renamed
118+
key), flat-deploy customers picking up a new wheel without re-deploying their
119+
bundle will continue to use their Workspace Files defaults until they re-deploy.
120+
This is safe and predictable: Workspace Files-first ensures the Workspace Files always win.

docs/source/concepts.rst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,12 @@ The Framework Bundle contains:
7070
* - Component
7171
- Description
7272
* - **Framework Source Code**
73-
- The core framework source code under the ``src`` folder.
73+
- The core framework source code under the ``src/lakeflow_framework/`` package.
7474
* - **Global Framework Configuration**
75-
- The global framework configuration under the ``src/config`` folder.
76-
* - **Data Flow Spec Schema Definition**
77-
- The Data Flow Spec schema definition and validations under the ``src/schemas`` folder.
75+
- The framework default configuration under ``src/lakeflow_framework/config/default/``. Customer
76+
overrides go in ``src/local/config/`` as sparse files — only the keys to change are needed.
77+
* - **Data Flow Spec Schema Definitions**
78+
- The Data Flow Spec schema definitions and validations under ``src/lakeflow_framework/schemas/``.
7879
* - **Deployment YAML file**
7980
- The ``databricks.yml`` file which defines the bundle deployment settings.
8081

@@ -86,7 +87,7 @@ The Framework Bundle is deployed to a given workspace files location from where
8687
Framework Configuration
8788
~~~~~~~~~~~~~~~~~~~~~~~
8889

89-
The Framework and most of its features will have configuration settings that can be set in the Framework Bundle ``src/config`` folder. The configuration settings are explained in the section: :doc:`features`
90+
The Framework and most of its features will have configuration settings that can be set in the Framework Bundle ``src/lakeflow_framework/config/default/`` folder. Default values ship with the framework and are resolved automatically; individual keys can be overridden by placing sparse files in ``src/local/config/``. The configuration settings are explained in the section: :doc:`features`
9091

9192
.. admonition:: Setting Precedence
9293
:class: note

docs/source/contributor.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Framework Development & Contributors
66
:caption: Contents:
77

88
contributor_dev_env
9+
contributor_imports
910
contributor_dev_git
1011
contributor_dev_steps
1112
contributor_dev_docs
13+
contributor_contrib

0 commit comments

Comments
 (0)