Add public API regression guard for databricks.bundles.core - #6439
Add public API regression guard for databricks.bundles.core#6439Sankalp-Mittal wants to merge 2 commits into
Conversation
Waiting for approvalCould not determine reviewers from git history. Eligible reviewers: Suggestions based on git history. See OWNERS for ownership rules. |
_bases() filtered out `object` but not underscore-prefixed private bases, so a generated private base (e.g. _GeneratedResources introduced by the wiring refactor) would surface in the golden as a false positive even though the public contract is intact. Mirror _members()'s underscore filter. No-op for the current golden on this branch, where Resources has no private base. Co-authored-by: Isaac <no-reply@databricks.com>
| # alongside this test and copied into the run dir). | ||
| # --python 3.11 is pinned deliberately: the snapshot must stay reproducible independent of the | ||
| # repo-wide UV_PYTHON minimum, and the dump uses typing.get_overloads (Python 3.11+). | ||
| uv run --python 3.11 -q $UV_ARGS python dump_public_api.py |
There was a problem hiding this comment.
- I feel like this should live in python/databricks_tests/ instead of acceptance/ ?
- why pin python version?
There was a problem hiding this comment.
- Sure that can be done, but I'm not sure what the advantage of that would be?
- to get the overloads present we need
typing.get_overloadsthis requirespython >= 3.11and the default used is3.10, pinning also ensures that the golden remains stable (although I'm not sure how it could change across versions still good to have this)
| out.append("]") | ||
| out.append("") | ||
|
|
||
| for name in sorted(core.__all__): |
There was a problem hiding this comment.
why do we have __all__? seems we are maintaining a list of exports of the module, when we can just use e.g. all = dir(core)?
There was a problem hiding this comment.
__all__ is defined in python/databricks/bundles/core/__init__.py and it is the list of stuff we want to publicly expose (it also acts as a guide for users on what they can use), on the other hand if we use dir(core) it just list everything that exists in the object, so it would also include submodules and other private attributes, so I don't think it makes sense to list them down
There was a problem hiding this comment.
it also acts as a guide for users on what they can use
__all__ should not be for users to consume - dunder variables are internal-only
it just list everything that exists in the object, so it would also include submodules and other private attributes
You can skip those from the snapshot, they aren't part of the stable public API in python by convention. Note:
>>> set(core.__all__) == set(x for x in dir(core) if not x.startswith('_'))
True
There was a problem hiding this comment.
__all__should not be for users to consume - dunder variables are internal-only
Yes but __all__ does control what gets imported on from core import * so it makes sense to only keep these as the ones listed, if both the lists are same then, that's fine but I still don't know why we should prefer using dir(core)
Summary
A regression guard has been added to the public facing API's on PyDABs, this is done to test that auto generating the code does not change any public API's.
Why
The upcoming PyDABs codegen/wiring refactor (#6397) converts the hand-written
databricks.bundles.corewiring —Resources, the*_mutatorfunctions, the_ResourceTyperegistry,__all__— into generated code. Nothing today guards the typed public surface customers import and type-check against, so that refactor (or a future one) could silently drop a type hint, move a*keyword marker, rename a method, or change the export set.This lands a golden snapshot of that surface on main first, freezing the known-good pre-refactor API. #6397 then merges main in and must reproduce the identical golden — that passing test is the proof the refactor preserved the public API.
generate-checkcannot do this: after the refactor regenerates the wiring it trivially passes ("checked-in == regenerated"); only a golden captured here, before the refactor, can show the new generated wiring equals the old hand-written surface.What
An acceptance test at
acceptance/bundle/python/public-api/whosescriptruns a checked-indump_public_api.pyunderuv, snapshottingdatabricks.bundles.core's__all__, everyResources.add_*signature and property, the*_mutatoroverloads,Variable/VariableOr*, the support types, and the_ResourceType.all()registry.Notable design decisions
Variable[str], notdatabricks.bundles.core._variable.Variable). The refactor moves internal_-prefixed modules; a golden keyed on internal paths would false-fail even when the public API is unchanged. Public imports go through thecore.__init__re-exports, which is exactly what the golden pins.inspect.Signatureso/,*,*args,**kwargsmarkers render explicitly and stably.--python 3.11is pinned so the golden is reproducible independent of the repo-wideUV_PYTHONminimum, andtyping.get_overloads(3.11+) is available. Output verified identical on 3.11 and 3.12.This pull request and its description were written by Isaac.