Skip to content

Fix Pylance settings handling on Dev18 - #8587

Merged
Stella Huang (StellaHuang95) merged 4 commits into
microsoft:mainfrom
StellaHuang95:fix/8578-custom-rpc-binding
Jul 22, 2026
Merged

Fix Pylance settings handling on Dev18#8587
Stella Huang (StellaHuang95) merged 4 commits into
microsoft:mainfrom
StellaHuang95:fix/8578-custom-rpc-binding

Conversation

@StellaHuang95

Copy link
Copy Markdown
Contributor

Summary

Fixes #8578.

Checking Automatically add brackets to functions persisted correctly in Visual Studio, but Dev18 did not deliver the enabled setting to Pylance. As a result, Pylance continued returning plain completion text such as getcwd instead of a snippet such as getcwd($0).

Root cause

Dev18 uses System.Text.Json for eligible language clients, exposing three serialization and binding mismatches in the PTVS/Pylance configuration path:

  • Pylance sends workspace/configuration parameters as one object ({ "items": [...] }), but the custom StreamJsonRpc handler did not opt into whole-object parameter binding, so the request was rejected with -32602.
  • PTVS's outbound settings DTO used public fields. System.Text.Json does not serialize those fields by default, so the settings payload became {} even when the option was enabled.
  • The fallback workspace/didChangeConfiguration payload placed analysis settings directly under settings.analysis, while Pylance expects the section under settings.python.analysis.

Latest main also introduced a JToken signature-help middle layer. On Dev18, that type selects the Newtonsoft formatter for the whole language client, which conflicts with the STJ-compatible path needed for PTVS's initialize interception. The Dev18 implementation therefore uses JsonDocument, while the existing Dev17 JToken implementation remains unchanged.

Fix

  • Enable whole-object binding for object-shaped custom RPC messages, including workspace/configuration.
  • Deserialize custom payloads through a serializer-neutral helper that accepts both Newtonsoft and Dev18 STJ values.
  • Convert outbound Pylance settings fields to properties so both serializers emit the same JSON contract.
  • Send fallback configuration under the required python section.
  • Keep Dev18 signature-help interception on the System.Text.Json middle-layer contract while preserving the prior Dev17 path.
  • Align the custom Pylance progress notification handler signatures with their protocol shapes.

Risk

Risk is low because the changes are limited to the Pylance language-client serialization and custom RPC boundary:

  • Wire names and setting values are unchanged; the settings that were previously omitted are now serialized.
  • Whole-object binding is applied only to methods whose protocol parameters are object-shaped.
  • The fallback envelope now matches Pylance's documented section lookup.
  • Dev17 retains its existing signature-help implementation through conditional compilation.
  • Completion insertion behavior is not changed; this only allows Pylance to receive the existing option and return the intended snippet.

Validation

The fix was manually verified on Dev18: after enabling the option, function completions included parentheses as expected. No tests were added for this change.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b6a821e-0a88-49fa-807e-874551b5a398
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b6a821e-0a88-49fa-807e-874551b5a398
Copilot AI review requested due to automatic review settings July 22, 2026 22:06
@StellaHuang95
Stella Huang (StellaHuang95) requested a review from a team as a code owner July 22, 2026 22:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@StellaHuang95

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@heejaechang

Copy link
Copy Markdown

🔒 Automated review in progress — Heejae Chang (@heejaechang) is auto-reviewing this PR.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Dev18 (System.Text.Json-based) configuration/serialization mismatches in the PTVS ↔ Pylance boundary so Pylance actually receives persisted settings like “Automatically add brackets to functions” and can return snippet completions (e.g., getcwd($0)) as intended.

Changes:

  • Updates Dev18 signature-help interception to use JsonDocument instead of JToken to avoid forcing a Newtonsoft formatter.
  • Fixes custom StreamJsonRpc handling to support whole-object parameter binding and serializer-neutral deserialization for workspace/configuration and related messages.
  • Ensures Pylance settings serialize correctly under System.Text.Json by converting DTO fields to properties and nesting fallback config under settings.python.
Show a summary per file
File Description
Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonSignatureHelpMiddleLayer.cs Switches Dev18 middle-layer contract to JsonDocument while preserving Dev17 JToken behavior.
Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClientCustomTarget.cs Adjusts custom RPC handlers to use whole-object parameter binding and adds serializer-neutral payload deserialization.
Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClient.cs Nests fallback didChangeConfiguration payload under settings.python to match Pylance expectations.
Python/Product/PythonTools/PythonTools/LanguageServerClient/LanguageServerSettings.cs Converts outbound settings DTO members from fields to properties so STJ emits the expected JSON.
Python/Product/PythonTools/PythonTools.csproj Adds a Dev18-conditional reference to System.Text.Json.
Build/18.0/packages.config Adds System.Text.Json NuGet package for Dev18 build inputs.

Review details

Comments suppressed due to low confidence (1)

Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClientCustomTarget.cs:179

  • OnWorkspaceConfiguration no longer guards against deserialization failures. If Deserialize throws (malformed payload / unexpected formatter value), the RPC request will fail with an exception rather than safely returning null like the previous implementation.
        public async Task<object> OnWorkspaceConfiguration(object arg) {
            var reqParams = Deserialize<WorkspaceConfiguration.ConfigurationParams>(arg);
            if (this.WorkspaceConfiguration != null && reqParams != null) {
                var eventArgs = new ConfigurationArgs { requestParams = reqParams, requestResult = null };
                await this.WorkspaceConfiguration.InvokeAsync(this, eventArgs);
                return eventArgs.requestResult;
            }
            return null;
        }
  • Files reviewed: 6/6 changed files
  • Comments generated: 3
  • Review effort level: Low

// Special case language_server/analysis_complete. We need this for testing so we
// know when it's okay to try to bring up intellisense
if (telemetry.EventName == "language_server/analysis_complete") {
AnalysisComplete?.Invoke(this, EventArgs.Empty);
Comment on lines +152 to 168
public void OnRegisterCapability(object arg) {
var regParams = Deserialize<VisualStudio.LanguageServer.Protocol.RegistrationParams>(arg);
if (regParams?.Registrations == null) {
return;
}

if (regParams.Registrations.Any(p => p.Method == "workspace/didChangeWorkspaceFolders")) {
_joinableTaskContext.Factory.RunAsync(async () => this.WorkspaceFolderChangeRegistered.Invoke(this, EventArgs.Empty));
}
var watchedFilesReg = regParams.Registrations.FirstOrDefault(p => p.Method == "workspace/didChangeWatchedFiles");
if (watchedFilesReg != null) {
var optionsObj = watchedFilesReg.RegisterOptions as JObject;
if (watchedFilesReg?.RegisterOptions is JObject optionsObj) {
var options = optionsObj.ToObject<DidChangeWatchedFilesRegistrationOptions>();
if (options != null) {
_joinableTaskContext.Factory.RunAsync(async () => this.WatchedFilesRegistered.Invoke(this, options));
}
}
}
Comment thread Python/Product/PythonTools/PythonTools.csproj
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 22:13
@StellaHuang95

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (1)

Python/Product/PythonTools/PythonTools/LanguageServerClient/PythonLanguageClientCustomTarget.cs:123

  • The AnalysisComplete invocation is missing indentation, which makes the block harder to read and looks like a formatting slip.
            if (telemetry.EventName == "language_server/analysis_complete") {
AnalysisComplete?.Invoke(this, EventArgs.Empty);
            }
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment on lines +181 to 190
private static T Deserialize<T>(object arg) where T : class {
if (arg == null) {
return null;
}

// Dev18 supplies System.Text.Json values; older formatters supply JToken.
return arg is JToken token
? token.ToObject<T>()
: JsonConvert.DeserializeObject<T>(arg.ToString());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

@StellaHuang95
Stella Huang (StellaHuang95) merged commit c485730 into microsoft:main Jul 22, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Checking "Automatically add brackets to functions" has no effect.

3 participants