Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/prompts/newNotebookCell.stest.ts
13389 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import assert from 'assert';
6
import { newNotebookCodeCell } from '../../src/extension/intents/node/newNotebookIntent';
7
import { IChatMLFetcher } from '../../src/platform/chat/common/chatMLFetcher';
8
import { IEndpointProvider } from '../../src/platform/endpoint/common/endpointProvider';
9
import { ITestingServicesAccessor } from '../../src/platform/test/node/services';
10
import { INotebookSection } from '../../src/util/common/notebooks';
11
import { CancellationToken } from '../../src/util/vs/base/common/cancellation';
12
import { URI } from '../../src/util/vs/base/common/uri';
13
import { IInstantiationService } from '../../src/util/vs/platform/instantiation/common/instantiation';
14
import { ssuite, stest } from '../base/stest';
15
import { fetchConversationOptions } from '../e2e/scenarioTest';
16
import { isValidPythonFile } from '../simulation/diagnosticProviders/python';
17
18
ssuite({ title: 'newNotebook', subtitle: 'prompt', location: 'panel' }, () => {
19
stest({ description: 'generate code cell', language: 'python' }, async (testingServiceCollection) => {
20
const accessor = testingServiceCollection.createTestingAccessor();
21
const endpoint = await accessor.get(IEndpointProvider).getChatEndpoint('copilot-base');
22
const topic = 'Creating Random Arrays with Numpy';
23
const sections: INotebookSection[] = [
24
{
25
'title': 'Import Required Libraries',
26
'content': 'Import the necessary libraries, including NumPy.'
27
},
28
{
29
'title': 'Create Random Arrays',
30
'content': 'Use NumPy to create random arrays of various shapes and sizes, including 1D, 2D, and 3D arrays.'
31
},
32
{
33
'title': 'Seed the Random Number Generator',
34
'content': 'Use the seed() function to seed the random number generator for reproducibility.'
35
},
36
{
37
'title': 'Generate Random Integers',
38
'content': 'Use the randint() function to generate random integers within a specified range.'
39
}
40
];
41
42
const cells: string[] = [];
43
const firstCell = await newNotebookCodeCell(accessor.get(IInstantiationService), accessor.get(IChatMLFetcher), endpoint, fetchConversationOptions(), undefined, topic, sections[0], '', 'python', URI.file('sample.ipynb'), CancellationToken.None);
44
assert.ok(firstCell !== undefined, 'code should not be empty');
45
assert.ok(firstCell.includes('import numpy as np'), 'code should include import numpy as np');
46
47
const firstCellIsValid = await validatePythonCode(accessor, firstCell!);
48
assert.ok(firstCellIsValid, 'first cell code should be valid python code');
49
cells.push(firstCell!);
50
51
const secondCell = await newNotebookCodeCell(accessor.get(IInstantiationService), accessor.get(IChatMLFetcher), endpoint, fetchConversationOptions(), undefined, topic, sections[1], cells.join('\n'), 'python', URI.file('sample.ipynb'), CancellationToken.None);
52
assert.ok(secondCell !== undefined, 'code should not be empty');
53
assert.ok(!secondCell.includes('import numpy'), 'code should not include import numpy again');
54
// const secondCellIsValid = await validatePythonCode(accessor, secondCell!);
55
// assert.ok(secondCellIsValid, 'second cell code should be valid python code');
56
});
57
58
stest({ description: 'Generate code cell (numpy)', language: 'python' }, async (testingServiceCollection) => {
59
const accessor = testingServiceCollection.createTestingAccessor();
60
const endpoint = await accessor.get(IEndpointProvider).getChatEndpoint('copilot-base');
61
const topic = 'A Jupyter notebook that creates a structured array with NumPy.';
62
const sections: INotebookSection[] = [
63
{
64
title: 'Import Required Libraries', content: 'Import the necessary libraries, including NumPy.'
65
},
66
{
67
title: 'Create Structured Array', content: 'Use NumPy to create a structured array with named fields and data types.'
68
},
69
{
70
title: 'Accessing Structured Array Elements', content: 'Access individual elements of the structured array using the field names.'
71
},
72
{
73
title: 'Iterating over Structured Arrays', content: 'Iterate over the structured array using a fo…nd access the field values for each element.'
74
}
75
];
76
77
const cells: string[] = [];
78
const firstCell = await newNotebookCodeCell(accessor.get(IInstantiationService), accessor.get(IChatMLFetcher), endpoint, fetchConversationOptions(), undefined, topic, sections[0], '', 'python', URI.file('sample.ipynb'), CancellationToken.None);
79
assert.ok(firstCell !== undefined, 'code should not be empty');
80
assert.ok(firstCell.includes('import numpy as np'), 'code should include import numpy as np');
81
82
const firstCellIsValid = await validatePythonCode(accessor, firstCell!);
83
assert.ok(firstCellIsValid, 'code should be valid python code');
84
cells.push(firstCell!);
85
86
for (let i = 1; i < sections.length; i++) {
87
const cell = await newNotebookCodeCell(accessor.get(IInstantiationService), accessor.get(IChatMLFetcher), endpoint, fetchConversationOptions(), undefined, topic, sections[i], cells.join('\n'), 'python', URI.file('sample.ipynb'), CancellationToken.None);
88
assert.ok(cell !== undefined, 'code should not be empty');
89
assert.ok(!cell.includes('import numpy'), 'code should not include import numpy again');
90
const cellIsValid = await validatePythonCode(accessor, cell!);
91
assert.ok(cellIsValid, 'code should be valid python code');
92
cells.push(cell!);
93
}
94
});
95
96
stest({ description: 'Generate code cell (seaborn + pandas)', language: 'python' }, async (testingServiceCollection) => {
97
const accessor = testingServiceCollection.createTestingAccessor();
98
const endpoint = await accessor.get(IEndpointProvider).getChatEndpoint('copilot-base');
99
const topic = 'A Jupyter notebook that loads planets data from Seaborn and performs aggregation in Pandas.';
100
const sections: INotebookSection[] = [
101
{ title: 'Import Required Libraries', content: 'Import the necessary libraries, including Pandas and Seaborn.' },
102
103
{ title: 'Load Planets Data', content: 'Load the planets data from Seaborn into a Pandas DataFrame.' },
104
105
{ title: 'Data Cleaning', content: 'Clean the data by removing missing values and converting data types if necessary.' },
106
107
{ title: 'Aggregation with GroupBy', content: 'Use the groupby() function to group the data…erform aggregation operations on the groups.' },
108
109
{ title: 'Aggregation with Pivot Tables', content: 'Use the pivot_table() function to create a p… summarizes the data by one or more columns.' },
110
];
111
112
const cells: string[] = [];
113
const firstCell = await newNotebookCodeCell(accessor.get(IInstantiationService), accessor.get(IChatMLFetcher), endpoint, fetchConversationOptions(), undefined, topic, sections[0], '', 'python', URI.file('sample.ipynb'), CancellationToken.None);
114
assert.ok(firstCell !== undefined, 'code should not be empty');
115
assert.ok(firstCell.includes('import seaborn'), 'code should include import seaborn');
116
assert.ok(firstCell.includes('import pandas'), 'code should include import pandas');
117
118
const firstCellIsValid = await validatePythonCode(accessor, firstCell!);
119
assert.ok(firstCellIsValid, 'code should be valid python code');
120
cells.push(firstCell!);
121
122
for (let i = 1; i < sections.length; i++) {
123
const cell = await newNotebookCodeCell(accessor.get(IInstantiationService), accessor.get(IChatMLFetcher), endpoint, fetchConversationOptions(), undefined, topic, sections[i], cells.join('\n'), 'python', URI.file('sample.ipynb'), CancellationToken.None);
124
assert.ok(cell !== undefined, 'code should not be empty');
125
assert.ok(!cell.includes('import seaborn'), 'code should not include import seaborn again');
126
assert.ok(!cell.includes('import pandas'), 'code should not include import pandas again');
127
const cellIsValid = await validatePythonCode(accessor, cell!);
128
assert.ok(cellIsValid, 'code should be valid python code');
129
cells.push(cell!);
130
}
131
});
132
});
133
134
// async function validatePythonCode(pythonCode: string): Promise<boolean> {
135
// const validateCode = `
136
// import codeop
137
// import re
138
139
// def validate_python_code(code):
140
// # Split the code into separate statements
141
// statements = re.split(r"\\n(?=\\w)", code)
142
// for statement in statements:
143
// codeop.compile_command(statement)
144
145
// validate_python_code("""${pythonCode}""")
146
// `;
147
// if (pythonCode.startsWith('```')) {
148
// return false;
149
// }
150
151
// return new Promise((resolve) => {
152
// exec(`python3 -c "${validateCode.replace(/["\\]/g, '\\$&')}"`, (error, stdout, stderr) => {
153
// if (error) {
154
// return resolve(false);
155
// } else if (stderr && stderr.length > 0) {
156
// return resolve(false);
157
// }
158
159
// resolve(true);
160
// });
161
// });
162
// }
163
164
async function validatePythonCode(accessor: ITestingServicesAccessor, pythonCode: string): Promise<boolean> {
165
const escapedPythonCode = pythonCode.replace(/`/g, 'BACKTICK_PLACEHOLDER');
166
const validateCode = `
167
import codeop
168
import re
169
170
def validate_python_code(code):
171
# Replace placeholder string with actual backtick
172
code = code.replace('BACKTICK_PLACEHOLDER', chr(96))
173
# Split the code into separate statements
174
statements = re.split(r"\\n(?=\\w)", code)
175
for statement in statements:
176
codeop.compile_command(statement)
177
178
validate_python_code("""${escapedPythonCode}""")
179
`;
180
return isValidPythonFile(accessor, validateCode);
181
}
182
183