Skip to content

Commit 8a77683

Browse files
feat: Detect name & version from pyproject.toml
1 parent 029e3d8 commit 8a77683

File tree

5 files changed

+155
-17
lines changed

5 files changed

+155
-17
lines changed

packages/pyright-scip/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/pyright-scip/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"webpack-cli": "^4.9.1"
4444
},
4545
"dependencies": {
46-
"@iarna/toml": "2.2.5",
46+
"@iarna/toml": "^2.2.5",
4747
"command-exists": "^1.2.9",
4848
"commander": "^9.2.0",
4949
"diff": "^5.0.0",

packages/pyright-scip/src/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export class ScipPyrightConfig {
110110
pyprojectFilePath = this._findPyprojectTomlFile(projectRoot);
111111

112112
if (!pyprojectFilePath && !commandLineOptions.fromVsCodeExtension) {
113-
pyprojectFilePath = this._findPyprojectTomlFileHereOrUp(projectRoot);
113+
pyprojectFilePath = this.findPyprojectTomlFileHereOrUp(projectRoot);
114114
}
115115

116116
if (pyprojectFilePath) {
@@ -364,7 +364,7 @@ export class ScipPyrightConfig {
364364
return undefined;
365365
}
366366

367-
private _findPyprojectTomlFileHereOrUp(searchPath: string): string | undefined {
367+
public findPyprojectTomlFileHereOrUp(searchPath: string): string | undefined {
368368
return forEachAncestorDirectory(searchPath, (ancestor) => this._findPyprojectTomlFile(ancestor));
369369
}
370370

packages/pyright-scip/src/indexer.ts

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as child_process from 'child_process';
22
import * as path from 'path';
3+
import * as TOML from '@iarna/toml';
34
import { Event } from 'vscode-languageserver/lib/common/api';
45

56
import { Program } from 'pyright-internal/analyzer/program';
@@ -28,6 +29,43 @@ export class Indexer {
2829
pyrightConfig: ConfigOptions;
2930
projectFiles: Set<string>;
3031

32+
public static inferProjectInfo(
33+
inferProjectVersionFromCommit: boolean,
34+
getPyprojectTomlContents: () => string | undefined
35+
): { name: string | undefined; version: string | undefined } {
36+
let name = undefined;
37+
let version = undefined;
38+
try {
39+
const pyprojectTomlContents = getPyprojectTomlContents();
40+
if (pyprojectTomlContents) {
41+
const tomlMap = TOML.parse(pyprojectTomlContents);
42+
let project = tomlMap['project'] as TOML.JsonMap | undefined;
43+
if (project) {
44+
name = project['name'];
45+
version = project['version'];
46+
}
47+
if (!name || !version) {
48+
let tool = tomlMap['tool'] as TOML.JsonMap | undefined;
49+
if (tool) {
50+
let toolPoetry = tool['poetry'] as TOML.JsonMap | undefined;
51+
if (toolPoetry) {
52+
name = name ?? toolPoetry['name'];
53+
version = version ?? toolPoetry['version'];
54+
}
55+
}
56+
}
57+
}
58+
} catch (_) {}
59+
name = typeof name === 'string' ? name : undefined;
60+
version = typeof version === 'string' ? version : undefined;
61+
if (!version && inferProjectVersionFromCommit) {
62+
try {
63+
version = child_process.execSync('git rev-parse HEAD').toString().trim();
64+
} catch (_) {}
65+
}
66+
return { name, version };
67+
}
68+
3169
constructor(public scipConfig: ScipConfig) {
3270
this.counter = new Counter();
3371

@@ -40,23 +78,29 @@ export class Indexer {
4078
//
4179
// private _getConfigOptions(host: Host, commandLineOptions: CommandLineOptions): ConfigOptions {
4280
let fs = new PyrightFileSystem(createFromRealFileSystem());
81+
let config = new ScipPyrightConfig(scipConfig, fs);
82+
this.pyrightConfig = config.getConfigOptions();
4383

44-
if (
45-
scipConfig.infer.projectVersionFromCommit &&
46-
(!scipConfig.projectVersion || scipConfig.projectVersion === '')
47-
) {
48-
try {
49-
scipConfig.projectVersion = child_process.execSync('git rev-parse HEAD').toString().trim();
50-
} catch (e) {
51-
scipConfig.projectVersion = '';
84+
if (!scipConfig.projectName || !scipConfig.projectVersion) {
85+
const { name, version } = Indexer.inferProjectInfo(
86+
scipConfig.infer.projectVersionFromCommit,
87+
(): string | undefined => {
88+
const tomlPath = config.findPyprojectTomlFileHereOrUp(scipConfig.projectRoot);
89+
if (tomlPath) {
90+
return fs.readFileSync(tomlPath, 'utf8');
91+
}
92+
return undefined;
93+
}
94+
);
95+
if (!scipConfig.projectName && name) {
96+
scipConfig.projectName = name;
97+
}
98+
if (!scipConfig.projectVersion && version) {
99+
scipConfig.projectVersion = version;
52100
}
53101
}
54102

55-
let config = new ScipPyrightConfig(scipConfig, fs);
56-
this.pyrightConfig = config.getConfigOptions();
57-
58103
const matcher = new FileMatcher(this.pyrightConfig, fs);
59-
60104
this.projectFiles = new Set(matcher.matchFiles(this.pyrightConfig.include, this.pyrightConfig.exclude));
61105
if (scipConfig.targetOnly) {
62106
scipConfig.targetOnly = path.resolve(scipConfig.targetOnly);

packages/pyright-scip/test/test-main.ts

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,97 @@
11
import { main } from '../src/main-impl';
22
import * as path from 'path';
33
import * as fs from 'fs';
4+
import { Indexer } from '../src/indexer';
45

5-
function testMain(mode: 'check' | 'update'): void {
6+
function testPyprojectParsing() {
7+
const testCases = [
8+
{
9+
expected: { name: undefined, version: undefined },
10+
tomlContents: [
11+
``,
12+
`[project]`,
13+
`[tool.poetry]`,
14+
`[tool]
15+
poetry = {}`,
16+
`[tool.poetry]
17+
name = false
18+
version = {}`,
19+
],
20+
},
21+
{
22+
expected: { name: 'abc', version: undefined },
23+
tomlContents: [
24+
`[project]
25+
name = "abc"`,
26+
`[tool.poetry]
27+
name = "abc"`,
28+
`[tool]
29+
poetry = { name = "abc" }`,
30+
`[project]
31+
name = "abc"
32+
[tool.poetry]
33+
name = "ignored"`,
34+
],
35+
},
36+
{
37+
expected: { name: undefined, version: '16.05' },
38+
tomlContents: [
39+
`[project]
40+
version = "16.05"`,
41+
`[tool.poetry]
42+
version = "16.05"`,
43+
`[tool]
44+
poetry = { version = "16.05" }`,
45+
`[project]
46+
version = "16.05"
47+
[tool.poetry]
48+
version = "ignored"`,
49+
],
50+
},
51+
{
52+
expected: { name: 'abc', version: '16.05' },
53+
tomlContents: [
54+
`[project]
55+
name = "abc"
56+
version = "16.05"`,
57+
`[tool.poetry]
58+
name = "abc"
59+
version = "16.05"`,
60+
`[project]
61+
name = "abc"
62+
[tool.poetry]
63+
version = "16.05"`,
64+
`[project]
65+
version = "16.05"
66+
[tool.poetry]
67+
name = "abc"`,
68+
`[project]
69+
[tool.poetry]
70+
name = "abc"
71+
version = "16.05"`,
72+
],
73+
},
74+
];
75+
76+
for (const testCase of testCases) {
77+
for (const content of testCase.tomlContents) {
78+
const got = Indexer.inferProjectInfo(false, () => content);
79+
const want = testCase.expected;
80+
if (got.name !== want.name) {
81+
throw `name mismatch (got: ${got.name}, expected: ${want.name}) for ${content}`;
82+
}
83+
if (got.version !== want.version) {
84+
throw `version mismatch (got: ${got.version}, expected: ${want.version}) for ${content}`;
85+
}
86+
}
87+
}
88+
}
89+
90+
function unitTests(): void {
91+
testPyprojectParsing();
92+
}
93+
94+
function snapshotTests(mode: 'check' | 'update'): void {
695
const nodePath = process.argv[0];
796
const startCwd = process.cwd();
897
// Returns list of subdir names, not absolute paths.
@@ -40,6 +129,11 @@ function testMain(mode: 'check' | 'update'): void {
40129
}
41130
}
42131

132+
function testMain(mode: 'check' | 'update'): void {
133+
unitTests();
134+
snapshotTests(mode);
135+
}
136+
43137
if (process.argv.indexOf('--check') !== -1) {
44138
testMain('check');
45139
} else {

0 commit comments

Comments
 (0)