feat: add Python IntelliSense for generated APIs - #2676
Conversation
AB#1984585 ## Summary Generate and package PEP 561 type stubs for SynapseML Python wrappers, with precise constructor, Param, setter, getter, estimator, and package export types across all components. Add namespace-safe typing markers, a manual UDFTransformer stub, deterministic packaging cleanup, regression tests, and installation guidance. ## Prompting Intent Implement reliable IDE and notebook IntelliSense for SynapseML OpenAI and other generated Python APIs in an isolated worktree, including parameters such as concurrency. Preserve runtime behavior and JVM compatibility, rebase on current master, validate published-wheel behavior, and review repeatedly for correctness and performance regressions. ## Linked Sources - Requirements issue: microsoft#1013 ## Rationale Use adjacent .pyi files rather than runtime annotations so Python execution and imports remain unchanged while Pylance, Pyright, and Jedi receive precise signatures. Keep stub-only metadata separate from ParamInfo to preserve its JVM constructor shape, retain fluent public-wrapper subtypes with a bound TypeVar, place py.typed markers in component-owned namespace subpackages to avoid wheel ownership conflicts, and clean aggregate merge output so removed generated files cannot leak into later wheels. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7dc287c1-b6cf-42f8-a26e-bf673be9f3d3
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Hey Rana Singh (@ranadeepsingh) 👋! We use semantic commit messages to streamline the release process. Examples of commit messages with semantic prefixes:
To test your commit locally, please follow our guild on building from source. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Adds PEP 561 typing support for SynapseML’s generated Python wrappers by emitting .pyi stubs and py.typed markers during codegen and ensuring both component and aggregate wheels package these typing artifacts, improving editor IntelliSense for constructors, params, setters/getters, and estimator model returns.
Changes:
- Generate per-wrapper
.pyistub files (including inferred types forServiceParam) alongside existing runtime.pywrappers. - Generate
__init__.pyistub exports andpy.typedmarkers for typed subpackages; include*.pyi/py.typedin wheelpackage_data. - Add targeted Scala tests for stub/type inference behavior and clean the aggregate merged Python directory before packaging.
Show a summary per file
| File | Description |
|---|---|
| docs/Get Started/Install SynapseML.md | Documents that wheels ship PEP 561 typing metadata and how editors pick it up. |
| core/src/test/scala/com/microsoft/azure/synapse/ml/codegen/VerifyDefaultParamInfo.scala | Adds tests validating pyi type strings and ServiceParam stub-type inference. |
| core/src/test/scala/com/microsoft/azure/synapse/ml/codegen/PyCodegenSuite.scala | Adds end-to-end tests asserting generated .pyi, __init__.pyi, and wheel packaging behavior. |
| core/src/main/scala/com/microsoft/azure/synapse/ml/codegen/Wrappable.scala | Emits .pyi stubs for generated wrappers (typed __init__, setParams, param accessors, and extra methods). |
| core/src/main/scala/com/microsoft/azure/synapse/ml/codegen/PyCodegen.scala | Generates __init__.pyi exports, creates py.typed markers, and packages typing artifacts. |
| core/src/main/scala/com/microsoft/azure/synapse/ml/codegen/DefaultParamInfo.scala | Introduces PythonTypeInfo + reflection-based type inference for more precise stub types. |
| core/src/main/python/synapse/ml/stages/UDFTransformer.pyi | Adds a manual stub for the exceptional UDFTransformer wrapper. |
| build.sbt | Ensures aggregate wheel includes typing artifacts and cleans merged Python sources before packaging. |
Review details
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 7/8 changed files
- Comments generated: 2
- Review effort level: Lite
## Summary Nest typed codegen test fixtures so FuzzingTest ignores them while retaining generated class names for stub assertions. This prevents test-only stages from being interpreted as production pipeline stages. ## Prompting Intent The engineer requested fully validated SynapseML IntelliSense support with repeated review and no regressions. Azure CI exposed a core discovery failure after the initial PR, so this change fixes the root cause and validates the exact failing suite. ## Linked Sources - GitHub PR: microsoft#2676 - GitHub issue: microsoft#1013 - Azure CI build: https://msdata.visualstudio.com/A365/_build/results?buildId=232483047 ## Rationale Production-stage fuzzing intentionally ignores nested classes. Nesting the fixtures confines the fix to tests and preserves runtime and wheel behavior; explicit fixture class-name overrides keep generated stub expectations deterministic. Adding a fuzzing exemption instead would weaken coverage for real stages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7dc287c1-b6cf-42f8-a26e-bf673be9f3d3
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Review details
Suppressed comments (1)
core/src/main/scala/com/microsoft/azure/synapse/ml/codegen/PyCodegen.scala:141
packageFolderbecomes values like "/services" in the recursion (packageFolder + "/" + f.getName). Passing that directly intoFileUtilities.join(conf.pySrcDir, ..., packageFolder)can causedirto resolve to an absolute filesystem path (because the last segment starts with "/"), which would make init/stub generation read/write outsideconf.pySrcDir. NormalizepackageFolder(strip the leading slash) for filesystem paths, while keeping the originalpackageFolderfor the special-case comparisons ("/services", "/cognitive").
}
}
makeInitStub(conf, dir, packageFolder, packageString)
dir.listFiles().filter(_.isDirectory).foreach(f =>
makeInitFiles(conf, packageFolder + "/" + f.getName)
- Files reviewed: 7/8 changed files
- Comments generated: 1
- Review effort level: Lite
57c799b
into
microsoft:master
Related Issues/PRs
Closes #1013.
What changes are proposed in this pull request?
SynapseML's generated Python wrappers expose runtime keyword names, but they do
not currently ship PEP 561 typing metadata. Editors therefore infer many
setters and optional parameters as
Unknown, and package-level class discoveryis inconsistent.
This PR:
.pyifiles for generated transformers, estimators, andmodels, including typed constructors,
setParams, Params, setters, getters,estimator model returns, and Python-only generated methods;
ServiceParamvalues such asconcurrency,temperature, anddeploymentName, without changing runtime converters or the publicParamInfoJVM shape;component-owned namespace subpackages, and packages them in both component
and aggregate wheels;
UDFTransformerwrapper, which doesnot inherit its generated base class;
generated files cannot survive into later wheels; and
The generated runtime
.pyexecution structure remains unchanged; onlydocumentation type labels become more precise.
How is this patch tested?
Validation on the final rebased commit:
com.microsoft.azure.synapse.ml.core.**selector passed, includingthe production-stage discovery suite that caught test-only fixture leakage.
compile,Test / compile,scalastyle, andTest / scalastylepassed across all six modules.black==22.3.0 --checkandgit diff --checkpassed.and OpenCV.
packageSynapseMLproduced an installable aggregate wheel containing 221.pyifiles and 17 namespace-safepy.typedmarkers.stub, and 140 package-level exports; the same stubs also passed with a
Python 3.8 target.
the expected types.
OpenAIPromptconstructor parameters includingconcurrency..pyifile was loaded bythe Python runtime.
PythonWrappabletrait has no new abstract JVM members comparedwith the target-branch binary surface.
all 310 generated runtime
.pyfiles.(typed median 1.495s vs. baseline 1.521s). Comparable dirty-worktree codegen
was within local noise (60.06s vs. 58.89s).
232486498
passed 76 checks, including
UnitTests core. Its only failed job is theunrelated Fabric E2E cleanup, which aborted before running tests because
GET https://api.fabric.microsoft.com/v1/workspacesreturned HTTP 500 onboth the initial run and a failed-job-only retry.
Does this PR change any dependencies?
Does this PR add a new feature? If so, have you added samples on website?