Add Python Adapter - #1654
Conversation
There was a problem hiding this comment.
Pull request overview
Adds first-class Python support to DSC by introducing a Python adapter (Microsoft.Adapter/Python), a Python discovery extension, and a bundled ms-dsc SDK (plus examples and tests) so Python resources can be authored, discovered, and invoked consistently across platforms.
Changes:
- Introduces the Python adapter implementation (
pyadapter/) and its manifests for Windows (python) and Unix (python3). - Adds the Python discovery extension (
python.discover.py) and extension manifests. - Adds the
ms-dscSDK package, unit tests/fixtures, and multiple Python resource examples; wires build to bundle the SDK and run pytest.
Reviewed changes
Copilot reviewed 84 out of 86 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| .gitignore | Adds Python-related ignores (bytecode, venvs, coverage, etc.). |
| adapters/python/.project.data.json | Adds build copy instructions for the Python adapter files. |
| adapters/python/README.md | Documents the adapter, SDK, discovery, and examples. |
| adapters/python/pyproject.toml | Defines Python adapter project metadata and pytest/coverage config. |
| adapters/python/pyadapter.py | Adds script entrypoint wrapper for adapter invocation. |
| adapters/python/pyadapter/init.py | Marks pyadapter as a package. |
| adapters/python/pyadapter/main.py | Enables python -m pyadapter invocation and sys.path normalization. |
| adapters/python/pyadapter/cache.py | Implements list cache keyed by installed distribution fingerprint. |
| adapters/python/pyadapter/cli.py | Defines adapter CLI argument parsing and dispatch. |
| adapters/python/pyadapter/discovery.py | Implements adapter-side list/discover/clear-cache operations. |
| adapters/python/pyadapter/logging.py | Adds structured stderr logging compatible with DSC trace format. |
| adapters/python/pyadapter/router.py | Dispatches get/set/test/delete/export to resource implementations. |
| adapters/python/pyadapter/schema.py | Generates JSON Schema for resources via SDK providers. |
| adapters/python/python.dsc.resource.json | Windows adapter manifest using python. |
| adapters/python/python3.dsc.resource.json | Linux/macOS adapter manifest using python3. |
| adapters/python/tests/conftest.py | Pytest setup (sys.path) + fixture manifest regeneration. |
| adapters/python/tests/fixture/pyproject.toml | Defines installable test resource package for adapter tests. |
| adapters/python/tests/fixture/dsc_test_resource/init.py | Fixture package init. |
| adapters/python/tests/fixture/dsc_test_resource/resources.py | Implements fixture resources for adapter tests. |
| adapters/python/tests/fixture/dsc_test_resource/dsc/DscTest.Export.dsc.adaptedResource.json | Prebuilt adapted manifest for export fixture. |
| adapters/python/tests/fixture/dsc_test_resource/dsc/DscTest.Get.dsc.adaptedResource.json | Prebuilt adapted manifest for get-only fixture. |
| adapters/python/tests/fixture/dsc_test_resource/dsc/DscTest.ReadWrite.dsc.adaptedResource.json | Prebuilt adapted manifest for read/write fixture. |
| adapters/python/tests/pytest.ini | Pytest + coverage configuration for adapter tests. |
| adapters/python/tests/unit/init.py | Unit test package init. |
| adapters/python/tests/unit/test_bundled_sdk.py | Tests bundled SDK importability and module invocation. |
| adapters/python/tests/unit/test_cache.py | Tests cache behavior and fingerprint stability. |
| adapters/python/tests/unit/test_cli.py | Tests dsc-gen manifest generation and adapter CLI handling. |
| adapters/python/tests/unit/test_example_resources.py | Tests example resource logic via direct imports. |
| adapters/python/tests/unit/test_logging.py | Tests adapter structured logging and level mapping. |
| adapters/python/tests/unit/test_main_module.py | Tests python -m pyadapter entrypoint behavior. |
| adapters/python/tests/unit/test_manifest.py | Validates adapter manifests structure/consistency. |
| adapters/python/tests/unit/test_metadata.py | Tests decorator metadata and enums. |
| adapters/python/tests/unit/test_protocols.py | Tests runtime-checkable Protocol capability detection. |
| adapters/python/tests/unit/test_pyadapter_schema.py | Tests schema generation fallback chain for resources. |
| adapters/python/tests/unit/test_results.py | Tests SetResult/TestResult containers. |
| adapters/python/tests/unit/test_schema.py | Tests dataclass schema type mapping and generation. |
| adapters/python/ms-dsc/README.md | Documents the ms-dsc SDK and authoring workflow. |
| adapters/python/ms-dsc/pyproject.toml | Defines the ms-dsc package and hatch build hook entry point. |
| adapters/python/ms-dsc/ms_dsc/init.py | SDK public API exports. |
| adapters/python/ms-dsc/ms_dsc/cli.py | Implements dsc-gen manifest CLI. |
| adapters/python/ms-dsc/ms_dsc/hooks/init.py | Hook package init. |
| adapters/python/ms-dsc/ms_dsc/hooks/hatchling.py | Implements Hatchling build hook for manifest generation. |
| adapters/python/ms-dsc/ms_dsc/logging.py | SDK-side logging helpers mirroring adapter behavior. |
| adapters/python/ms-dsc/ms_dsc/metadata.py | Defines decorator metadata and SetReturn/TestReturn enums. |
| adapters/python/ms-dsc/ms_dsc/protocols.py | Defines capability Protocols (Gettable/Settable/etc.). |
| adapters/python/ms-dsc/ms_dsc/py.typed | Marks package as typed for type checkers. |
| adapters/python/ms-dsc/ms_dsc/resource.py | Defines base DscResource[T] and schema access. |
| adapters/python/ms-dsc/ms_dsc/results.py | Defines SetResult and TestResult. |
| adapters/python/ms-dsc/ms_dsc/schema/init.py | Re-exports schema providers and protocol. |
| adapters/python/ms-dsc/ms_dsc/schema/_dataclass.py | Stdlib-only dataclass → JSON Schema implementation. |
| adapters/python/ms-dsc/ms_dsc/schema/_protocol.py | SchemaProvider Protocol definition. |
| adapters/python/ms-dsc/ms_dsc/schema/_pydantic.py | Optional Pydantic v2 schema provider. |
| adapters/python/examples/file-resource/README.md | Documents the file resource example package. |
| adapters/python/examples/file-resource/pyproject.toml | Example package metadata and entry points. |
| adapters/python/examples/file-resource/file_resource/init.py | Example package init. |
| adapters/python/examples/file-resource/file_resource/resource.py | Implements Example/File and Example/ManagedFile. |
| adapters/python/examples/file-resource/file_resource/dsc/Example.ManagedFile.dsc.adaptedResource.json | Prebuilt adapted manifest for Example/ManagedFile. |
| adapters/python/examples/file_presence/README.md | Documents the file presence example package. |
| adapters/python/examples/file_presence/pyproject.toml | Example package metadata and build hook usage. |
| adapters/python/examples/file_presence/file_presence/init.py | Example package init. |
| adapters/python/examples/file_presence/file_presence/resource.py | Implements Example/FilePresence. |
| adapters/python/examples/file_presence/file_presence/dsc/Example.FilePresence.dsc.adaptedResource.json | Prebuilt adapted manifest for Example/FilePresence. |
| adapters/python/examples/dsc-example-resource/README.md | Documents the multi-resource demo package. |
| adapters/python/examples/dsc-example-resource/pyproject.toml | Demo package metadata and entry points. |
| adapters/python/examples/dsc-example-resource/dsc_example_resource/init.py | Demo package init. |
| adapters/python/examples/dsc-example-resource/dsc_example_resource/resources.py | Implements Greeting/Counter/EnvVar demo resources. |
| adapters/python/examples/dsc-example-resource/dsc_example_resource/dsc/Example.Counter.dsc.adaptedResource.json | Prebuilt adapted manifest for Example/Counter. |
| adapters/python/examples/dsc-example-resource/dsc_example_resource/dsc/Example.EnvVar.dsc.adaptedResource.json | Prebuilt adapted manifest for Example/EnvVar. |
| adapters/python/examples/dsc-example-resource/dsc_example_resource/dsc/Example.Greeting.dsc.adaptedResource.json | Prebuilt adapted manifest for Example/Greeting. |
| adapters/python/examples/dsc-example-resource/examples/ensure-counters.dsc.yaml | Example config document for counters. |
| adapters/python/examples/dsc-example-resource/examples/ensure-envvars.dsc.yaml | Example config document for env vars. |
| adapters/python/examples/dsc-example-resource/examples/ensure-greeting.dsc.yaml | Example config document for greeting. |
| build.ps1 | Adds Python SDK bundling and pytest execution to build/test flow. |
| data.build.json | Adds Python adapter/SDK/extension artifacts to packaging lists. |
| examples/python-pydantic-resource/README.md | Adds a Pydantic-based example resource walkthrough. |
| examples/python-pydantic-resource/pyproject.toml | Defines dependencies/entry point for Pydantic example. |
| examples/python-pydantic-resource/my_package/init.py | Pydantic example package init. |
| examples/python-pydantic-resource/my_package/my_resource.py | Implements a Pydantic-schema DSC example resource. |
| extensions/python/.project.data.json | Adds build copy instructions for the Python discovery extension. |
| extensions/python/python.dsc.extension.json | Adds discovery extension manifest for python. |
| extensions/python/python3.dsc.extension.json | Adds discovery extension manifest for python3. |
| extensions/python/python.discover.py | Implements discovery by scanning installed distributions for manifests. |
| helpers.build.psm1 | Adds Python SDK bundling helper + pytest runner helper. |
Suppressed comments (2)
data.build.json:76
- macOS packaging only includes
python.dsc.extension.json(conditioned onpython), but this PR adds a separatepython3.dsc.extension.json. Without packaging the python3 extension manifest, discovery won’t run on systems where onlypython3exists.
data.build.json:183 - The build copy list for the python extension project only includes
python.dsc.extension.json, sopython3.dsc.extension.jsonwill never be copied into the build output. That makes Python discovery fail on platforms/environments where onlypython3is present.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 83 out of 85 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
helpers.build.psm1:3016
- This
returnis inside thebegin{}block, so it only ends the begin block — theprocess{}block still runs afterward. When Python is not found,$pythonCmdis$null, soprocess{}proceeds to& $pythonCmd.Source ..., which fails instead of skipping the tests as the warning implies. Add a guard at the start ofprocess{}so the function actually skips when Python is unavailable.
helpers.build.psm1:1847 - The exclusion filter here (and the docstring above referring to "the build hook (ms_dsc/build/)") is stale: the hatchling build hook now lives at
ms_dsc/hooks/hatchling.py, notms_dsc/build/. As a result,$rel -notlike 'build*'excludes nothing, and the build-onlyhooks/directory gets bundled into the runtime artifact. Update the exclusion (and docstring) to targethooks*so the build hook is excluded as intended.
| _exist: bool = Field( | ||
| default=True, | ||
| description="Whether the instance should exist.", | ||
| ) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 83 out of 85 changed files in this pull request and generated 1 comment.
Suppressed comments (5)
Previously missed (5) — in code that hasn't changed since the last review.
adapters/python/python.dsc.resource.json:114
- The adapter manifest defines a
validateoperation, but adapters must not implementvalidate— it is deprecated and input validation is handled by JSONSchema. Thepyadapter.cli validateverb and this manifest block should be removed so the adapter does not advertise a validation capability it shouldn't own.
adapters/python/python3.dsc.resource.json:114 - The adapter manifest defines a
validateoperation, but adapters must not implementvalidate— it is deprecated and input validation is handled by JSONSchema. Thepyadapter.cli validateverb and this manifest block should be removed so the adapter does not advertise a validation capability it shouldn't own.
helpers.build.psm1:3009 - This early skip does not work as intended. In an advanced function,
returninside thebeginblock only ends thebeginblock — theprocessblock still runs. So when Python is not on PATH,$pythonCmdis$null, the warning is emitted, andprocessstill executes& $pythonCmd.Source -m venv ...against a null command, producing a confusing failure instead of a clean skip. Move the availability check (and skip) into theprocessblock, or set a script-scoped flag inbeginand guard theprocessbody on it.
helpers.build.psm1:1847 - This exclusion no longer matches the build hook. The docstring above states it excludes the build hook at
ms_dsc/build/, but the hatchling hook now lives underms_dsc/hooks/(there is nobuild/directory), so$rel -notlike 'build*'excludes nothing and the build-time-only hook is bundled into the runtime SDK. Update the pattern to excludehooks*and fix the stale docstring reference toms_dsc/build/. Note the accompanying testtest_bundled_msdsc_excludes_build_hookchecks for abuild/directory that no longer exists, so it passes vacuously.
adapters/python/tests/unit/test_bundled_sdk.py:53 - This test no longer verifies the intended exclusion. The hatchling build hook was moved to
ms_dsc/hooks/, soms_dsc/build/never exists in the bundle and this assertion passes vacuously regardless of whether the hook is excluded. Assert against the actual hook location (e.g. that_BUNDLED_MSDSC / "hooks"is not present) so the test proves the build-time-only hook is excluded from the runtime SDK.
| "python.discover.py", | ||
| "python.dsc.extension.json" |
PR Summary
Implementation of Python RFC #1643
PR Context