Skip to content

Commit ced57fe

Browse files
committed
fix: normalize line endings before parsing pyproject.toml
1 parent 52cbb9a commit ced57fe

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎src/client/pythonEnvironments/creation/provider/venvUtils.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export async function getPipRequirementsFiles(
5050

5151
function tomlParse(content: string): tomljs.JsonMap {
5252
try {
53-
return tomljs.parse(content);
53+
// Normalize CRLF to LF to prevent @iarna/toml from throwing control-character errors on comments
54+
return tomljs.parse(content.replace(/\r\n?/g, '\n'));
5455
} catch (err) {
5556
traceError('Failed to parse `pyproject.toml`:', err);
5657
}

‎src/test/pythonEnvironments/creation/provider/venvUtils.unit.test.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as workspaceApis from '../../../../client/common/vscodeApis/workspaceAp
1111
import {
1212
ExistingVenvAction,
1313
OPEN_REQUIREMENTS_BUTTON,
14+
isPipInstallableToml,
1415
pickExistingVenvAction,
1516
pickPackagesToInstall,
1617
} from '../../../../client/pythonEnvironments/creation/provider/venvUtils';
@@ -93,6 +94,29 @@ suite('Venv Utils test', () => {
9394
]);
9495
});
9596

97+
test('Toml with CRLF line endings and comments parses correctly', async () => {
98+
findFilesStub.resolves([]);
99+
pathExistsStub.resolves(true);
100+
readFileStub.resolves(
101+
'[project]\r\n# Project comment\r\nname = "spam"\r\nversion = "2020.0.0"\r\n[build-system]\r\n# Build system comment\r\nrequires = ["setuptools ~= 58.0"]\r\n',
102+
);
103+
104+
const actual = await pickPackagesToInstall(workspace1);
105+
assert.isTrue(showQuickPickWithBackStub.notCalled);
106+
assert.deepStrictEqual(actual, [
107+
{
108+
installType: 'toml',
109+
source: path.join(workspace1.uri.fsPath, 'pyproject.toml'),
110+
},
111+
]);
112+
});
113+
114+
test('isPipInstallableToml handles CRLF and comments correctly', () => {
115+
const crlfContent =
116+
'[project]\r\n# Comment\r\nname = "spam"\r\n[build-system]\r\n# Another comment\r\nrequires = ["setuptools"]\r\n';
117+
assert.isTrue(isPipInstallableToml(crlfContent));
118+
});
119+
96120
test('Toml found with deps, but user presses escape', async () => {
97121
findFilesStub.resolves([]);
98122
pathExistsStub.resolves(true);

0 commit comments

Comments
 (0)