Skip to content

Commit 33d30c9

Browse files
committed
Merge branch 'main' into environments-cache
2 parents 31abb9b + 6332b81 commit 33d30c9

File tree

25 files changed

+1358
-372
lines changed

25 files changed

+1358
-372
lines changed

.github/workflows/assignIssue.yml

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
name: Assign DS issue to someone
2+
on:
3+
issues:
4+
types: [opened]
5+
jobs:
6+
assignIssue:
7+
name: Assign Issue to Someone
8+
runs-on: ubuntu-latest
9+
if: github.repository == 'microsoft/vscode-python'
10+
steps:
11+
- name: Created internally
12+
id: internal
13+
env:
14+
ISSUE_OWNER: ${{github.event.issue.owner.login}}
15+
run: |
16+
echo ::set-output name=result::$(node -p -e "['rchiodo', 'greazer', 'joyceerhl', 'DavidKutu', 'claudiaregio', 'IanMatthewHuff', 'DonJayamanne'].filter(item => process.env.ISSUE_OWNER.toLowerCase() === item.toLowerCase()).length > 0 ? 1 : 0")
17+
shell: bash
18+
- name: Should we proceed
19+
id: proceed
20+
env:
21+
ISSUE_LABELS: ${{toJson(github.event.issue.labels)}}
22+
ISSUE_ASSIGNEES: ${{toJson(github.event.issue.assignees)}}
23+
ISSUE_IS_INTERNAL: ${{steps.internal.outputs.result}}
24+
run: |
25+
echo ::set-output name=result::$(node -p -e "process.env.ISSUE_IS_INTERNAL === '0' && JSON.parse(process.env.ISSUE_ASSIGNEES).length === 0 && JSON.parse(process.env.ISSUE_LABELS).filter(item => item.name.indexOf('data science') >= 0).length === 1 ? 1 : 0")
26+
shell: bash
27+
- uses: actions/checkout@v2
28+
if: steps.proceed.outputs.result == 1
29+
- name: Day of week
30+
if: steps.proceed.outputs.result == 1
31+
id: day
32+
run: |
33+
echo ::set-output name=number::$(node -p -e "new Date().getDay()")
34+
shell: bash
35+
- name: Hour of day
36+
if: steps.proceed.outputs.result == 1
37+
id: hour
38+
run: |
39+
echo ::set-output name=hour::$(node -p -e "(new Date().getUTCHours() - 7)%24")
40+
shell: bash
41+
- name: Week Number
42+
if: steps.proceed.outputs.result == 1
43+
id: week
44+
run: |
45+
echo ::set-output name=odd::$(node .github/workflows/week.js)
46+
shell: bash
47+
- name: Print day and week
48+
if: steps.proceed.outputs.result == 1
49+
run: |
50+
echo ${{steps.day.outputs.number}}
51+
echo ${{steps.week.outputs.odd}}
52+
echo ${{steps.hour.outputs.hour}}
53+
shell: bash
54+
- name: Even late friday (David)
55+
if: steps.proceed.outputs.result == 1 && steps.week.outputs.odd == 0 && steps.day.outputs.number == 5 && steps.hour.outputs.hour >= 16
56+
uses: actions/[email protected]
57+
env:
58+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59+
with:
60+
args: assign DavidKutu
61+
- name: Odd late friday (Joyce)
62+
if: steps.proceed.outputs.result == 1 && steps.week.outputs.odd == 1 && steps.day.outputs.number == 5 && steps.hour.outputs.hour >= 16
63+
uses: actions/[email protected]
64+
env:
65+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
66+
with:
67+
args: assign joyceerhl
68+
- name: Odd weekends (David)
69+
if: steps.proceed.outputs.result == 1 && steps.week.outputs.odd == 1 && (steps.day.outputs.number == 6 || steps.day.outputs.number == 0)
70+
uses: actions/[email protected]
71+
env:
72+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
73+
with:
74+
args: assign DavidKutu
75+
- name: Even weekends (Joyce)
76+
if: steps.proceed.outputs.result == 1 && steps.week.outputs.odd == 0 && (steps.day.outputs.number == 6 || steps.day.outputs.number == 0)
77+
uses: actions/[email protected]
78+
env:
79+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
80+
with:
81+
args: assign joyceerhl
82+
- name: Odd Monday (David)
83+
if: steps.proceed.outputs.result == 1 && steps.week.outputs.odd == 1 && steps.day.outputs.number == 1 && steps.hour.outputs.hour < 16
84+
uses: actions/[email protected]
85+
env:
86+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87+
with:
88+
args: assign DavidKutu
89+
- name: Even Monday (Joyce)
90+
if: steps.proceed.outputs.result == 1 && steps.week.outputs.odd == 0 && steps.day.outputs.number == 1 && steps.hour.outputs.hour < 16
91+
uses: actions/[email protected]
92+
env:
93+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
94+
with:
95+
args: assign joyceerhl
96+
- name: Tuesday (Ian)
97+
if: steps.proceed.outputs.result == 1 && (steps.day.outputs.number == 1 && steps.hour.outputs.hour >= 16) || (steps.day.outputs.number == 2 && steps.hour.outputs.hour < 16)
98+
uses: actions/[email protected]
99+
env:
100+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
101+
with:
102+
args: assign IanMatthewHuff
103+
- name: Wednesday (Rich)
104+
if: steps.proceed.outputs.result == 1 && (steps.day.outputs.number == 2 && steps.hour.outputs.hour >= 16) || (steps.day.outputs.number == 3 && steps.hour.outputs.hour < 16)
105+
uses: actions/[email protected]
106+
env:
107+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
108+
with:
109+
args: assign rchiodo
110+
- name: Thursday (Don)
111+
if: steps.proceed.outputs.result == 1 && (steps.day.outputs.number == 3 && steps.hour.outputs.hour >= 16) || (steps.day.outputs.number == 4 && steps.hour.outputs.hour < 16)
112+
uses: actions/[email protected]
113+
env:
114+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
115+
with:
116+
args: assign DonJayamanne
117+
- name: Friday (Claudia)
118+
if: steps.proceed.outputs.result == 1 && (steps.day.outputs.number == 4 && steps.hour.outputs.hour >= 16) || (steps.day.outputs.number == 5 && steps.hour.outputs.hour < 16)
119+
uses: actions/[email protected]
120+
env:
121+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
122+
with:
123+
args: assign claudiaregio

.github/workflows/week.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* For a given date, get the ISO week number
2+
*
3+
* Based on information at:
4+
*
5+
* http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
6+
*
7+
* Algorithm is to find nearest thursday, it's year
8+
* is the year of the week number. Then get weeks
9+
* between that date and the first day of that year.
10+
*
11+
* Note that dates in one year can be weeks of previous
12+
* or next year, overlap is up to 3 days.
13+
*
14+
* e.g. 2014/12/29 is Monday in week 1 of 2015
15+
* 2012/1/1 is Sunday in week 52 of 2011
16+
*/
17+
function getWeekNumber(d) {
18+
// Copy date so don't modify original
19+
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
20+
// Set to nearest Thursday: current date + 4 - current day number
21+
// Make Sunday's day number 7
22+
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
23+
// Get first day of year
24+
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
25+
// Calculate full weeks to nearest Thursday
26+
return Math.ceil(((d - yearStart) / 86400000 + 1) / 7);
27+
}
28+
// Whether it is an odd or event week.
29+
console.log(getWeekNumber(new Date()) % 2);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
"onCommand:python.datascience.selectJupyterInterpreter",
101101
"onCommand:python.datascience.selectjupytercommandline",
102102
"onCommand:python.enableSourceMapSupport",
103-
"onNotebookEditor:jupyter-notebook",
103+
"onNotebook:jupyter-notebook",
104104
"workspaceContains:mspythonconfig.json",
105105
"workspaceContains:pyproject.toml",
106106
"onCustomEditor:ms-python.python.notebook.ipynb"

src/client/common/utils/misc.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,53 @@ export function isUri(resource?: Uri | any): resource is Uri {
130130
return typeof uri.path === 'string' && typeof uri.scheme === 'string';
131131
}
132132

133+
/**
134+
* Create a filter func that determine if the given URI and candidate match.
135+
*
136+
* The scheme must match, as well as path.
137+
*
138+
* @param checkParent - if `true`, match if the candidate is rooted under `uri`
139+
* @param checkChild - if `true`, match if `uri` is rooted under the candidate
140+
* @param checkExact - if `true`, match if the candidate matches `uri` exactly
141+
*/
142+
export function getURIFilter(
143+
uri: Uri,
144+
opts: {
145+
checkParent?: boolean;
146+
checkChild?: boolean;
147+
checkExact?: boolean;
148+
} = { checkExact: true }
149+
): (u: Uri) => boolean {
150+
let uriPath = uri.path;
151+
while (uri.path.endsWith('/')) {
152+
uriPath = uriPath.slice(0, -1);
153+
}
154+
const uriRoot = `${uriPath}/`;
155+
function filter(candidate: Uri): boolean {
156+
if (candidate.scheme !== uri.scheme) {
157+
return false;
158+
}
159+
let candidatePath = candidate.path;
160+
while (candidate.path.endsWith('/')) {
161+
candidatePath = candidatePath.slice(0, -1);
162+
}
163+
if (opts.checkExact && candidatePath === uriPath) {
164+
return true;
165+
}
166+
if (opts.checkParent && candidatePath.startsWith(uriRoot)) {
167+
return true;
168+
}
169+
if (opts.checkChild) {
170+
const candidateRoot = `{candidatePath}/`;
171+
if (uriPath.startsWith(candidateRoot)) {
172+
return true;
173+
}
174+
}
175+
return false;
176+
}
177+
return filter;
178+
}
179+
133180
export function isNotebookCell(documentOrUri: TextDocument | Uri): boolean {
134181
const uri = isUri(documentOrUri) ? documentOrUri : documentOrUri.uri;
135182
return uri.scheme.includes(NotebookCellScheme);

src/client/datascience/jupyter/jupyterDebugger.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
'use strict';
44
import type { nbformat } from '@jupyterlab/coreutils';
55
import { inject, injectable, named } from 'inversify';
6+
// tslint:disable-next-line: no-require-imports
7+
import unescape = require('lodash/unescape');
68
import * as path from 'path';
79
import * as uuid from 'uuid/v4';
810
import { DebugConfiguration, Disposable } from 'vscode';
@@ -473,8 +475,10 @@ export class JupyterDebugger implements IJupyterDebugger, ICellHashListener {
473475
if (outputs.length > 0) {
474476
const data = outputs[0].data;
475477
if (data && data.hasOwnProperty('text/plain')) {
478+
// Plain text should be escaped by our execution engine. Unescape it so
479+
// we can parse it.
476480
// tslint:disable-next-line:no-any
477-
return (data as any)['text/plain'];
481+
return unescape((data as any)['text/plain']);
478482
}
479483
if (outputs[0].output_type === 'stream') {
480484
const stream = outputs[0] as nbformat.IStream;

src/client/datascience/jupyter/kernels/cellExecution.ts

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import { nbformat } from '@jupyterlab/coreutils';
77
import type { KernelMessage } from '@jupyterlab/services/lib/kernel/messages';
8-
import { CancellationToken, CellOutputKind, CellStreamOutput, NotebookCell, NotebookCellRunState } from 'vscode';
9-
import type { NotebookEditor as VSCNotebookEditor } from '../../../../../types/vscode-proposed';
8+
import { CancellationToken, CellOutputKind, NotebookCell, NotebookCellRunState } from 'vscode';
9+
import type { CellDisplayOutput, NotebookEditor as VSCNotebookEditor } from '../../../../../types/vscode-proposed';
1010
import { concatMultilineString, formatStreamText } from '../../../../datascience-ui/common';
1111
import { IApplicationShell, IVSCodeNotebook } from '../../../common/application/types';
1212
import { traceInfo, traceWarning } from '../../../common/logger';
@@ -38,8 +38,6 @@ import {
3838
import { IKernel } from './types';
3939
// tslint:disable-next-line: no-var-requires no-require-imports
4040
const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed');
41-
// tslint:disable-next-line: no-require-imports
42-
import escape = require('lodash/escape');
4341

4442
export class CellExecutionFactory {
4543
constructor(
@@ -471,11 +469,6 @@ export class CellExecution {
471469
// See this for docs on the messages:
472470
// https://jupyter-client.readthedocs.io/en/latest/messaging.html#messaging-in-jupyter
473471
private async handleExecuteResult(msg: KernelMessage.IExecuteResultMsg, clearState: RefBool) {
474-
// Escape text output
475-
if (msg.content.data && msg.content.data.hasOwnProperty('text/plain')) {
476-
msg.content.data['text/plain'] = escape(msg.content.data['text/plain'] as string);
477-
}
478-
479472
await this.addToCellData(
480473
{
481474
output_type: 'execute_result',
@@ -500,7 +493,7 @@ export class CellExecution {
500493
// Mark as stream output so the text is formatted because it likely has ansi codes in it.
501494
output_type: 'stream',
502495
// tslint:disable-next-line: no-any
503-
text: escape((o.data as any)['text/plain'].toString()),
496+
text: (o.data as any)['text/plain'].toString(),
504497
metadata: {},
505498
execution_count: reply.execution_count
506499
},
@@ -531,16 +524,20 @@ export class CellExecution {
531524
}
532525

533526
// Might already have a stream message. If so, just add on to it.
527+
// We use Rich output for text streams (not CellStreamOutput, known VSC Issues).
528+
// https://github.com/microsoft/vscode-python/issues/14156
534529
const lastOutput =
535530
exitingCellOutput.length > 0 ? exitingCellOutput[exitingCellOutput.length - 1] : undefined;
536-
const existing: CellStreamOutput | undefined =
537-
lastOutput && lastOutput.outputKind === CellOutputKind.Text ? lastOutput : undefined;
538-
if (existing) {
531+
const existing: CellDisplayOutput | undefined =
532+
lastOutput && lastOutput.outputKind === CellOutputKind.Rich ? lastOutput : undefined;
533+
if (existing && 'text/plain' in existing.data) {
539534
// tslint:disable-next-line:restrict-plus-operands
540-
existing.text = formatStreamText(concatMultilineString(existing.text + escape(msg.content.text)));
535+
existing.data['text/plain'] = formatStreamText(
536+
concatMultilineString(`${existing.data['text/plain']}${escape(msg.content.text)}`)
537+
);
541538
edit.replaceCellOutput(this.cellIndex, [...exitingCellOutput]); // This is necessary to get VS code to update (for now)
542539
} else {
543-
const originalText = formatStreamText(concatMultilineString(escape(msg.content.text)));
540+
const originalText = formatStreamText(concatMultilineString(msg.content.text));
544541
// Create a new stream entry
545542
const output: nbformat.IStream = {
546543
output_type: 'stream',
@@ -553,11 +550,6 @@ export class CellExecution {
553550
}
554551

555552
private async handleDisplayData(msg: KernelMessage.IDisplayDataMsg, clearState: RefBool) {
556-
// Escape text output
557-
if (msg.content.data && msg.content.data.hasOwnProperty('text/plain')) {
558-
msg.content.data['text/plain'] = escape(msg.content.data['text/plain'] as string);
559-
}
560-
561553
const output: nbformat.IDisplayData = {
562554
output_type: 'display_data',
563555
data: msg.content.data,

0 commit comments

Comments
 (0)