@@ -20,16 +20,18 @@ import {
2020 GetEnvironmentScope ,
2121 PythonEnvironment ,
2222 PythonEnvironmentId ,
23+ PythonProject ,
2324} from '../../api' ;
2425import * as extensionApis from '../../common/extension.apis' ;
2526import { PythonEnvironmentManagers } from '../../features/envManagers' ;
2627import * as settingHelpers from '../../features/settings/settingHelpers' ;
27- import { PythonProjectManager } from '../../internal.api' ;
28+ import { InternalPackageManager , PythonProjectManager } from '../../internal.api' ;
2829import { setupNonThenable } from '../mocks/helper' ;
2930
3031suite ( 'PythonEnvironmentManagers getLastKnownEnvironment' , ( ) => {
3132 let envManagers : PythonEnvironmentManagers ;
3233 let projectManager : typeMoq . IMock < PythonProjectManager > ;
34+ let projectsByUri : Map < string , PythonProject > ;
3335
3436 function makeEnv ( id : string ) : PythonEnvironment {
3537 const envId : PythonEnvironmentId = { id, managerId : 'test-manager' } ;
@@ -58,8 +60,10 @@ suite('PythonEnvironmentManagers getLastKnownEnvironment', () => {
5860
5961 projectManager = typeMoq . Mock . ofType < PythonProjectManager > ( ) ;
6062 setupNonThenable ( projectManager ) ;
61- // No project for a scope -> refreshEnvironment/getLastKnownEnvironment use the 'global' key.
62- projectManager . setup ( ( pm ) => pm . get ( typeMoq . It . isAny ( ) ) ) . returns ( ( ) => undefined ) ;
63+ projectsByUri = new Map ( ) ;
64+ projectManager
65+ . setup ( ( pm ) => pm . get ( typeMoq . It . isAny ( ) ) )
66+ . returns ( ( uri ) => projectsByUri . get ( uri . toString ( ) ) ) ;
6367
6468 envManagers = new PythonEnvironmentManagers ( projectManager . object ) ;
6569 } ) ;
@@ -96,6 +100,13 @@ suite('PythonEnvironmentManagers getLastKnownEnvironment', () => {
96100 return id ;
97101 }
98102
103+ function stubPackageManager ( id = 'ms-python.python:pip' ) : void {
104+ const packageManager = typeMoq . Mock . ofType < InternalPackageManager > ( ) ;
105+ setupNonThenable ( packageManager ) ;
106+ packageManager . setup ( ( manager ) => manager . id ) . returns ( ( ) => id ) ;
107+ sinon . stub ( envManagers , 'getPackageManager' ) . returns ( packageManager . object ) ;
108+ }
109+
99110 test ( 'returns undefined before any environment has been resolved' , ( ) => {
100111 registerManager ( async ( ) => makeEnv ( 'env1' ) ) ;
101112 assert . strictEqual ( envManagers . getLastKnownEnvironment ( undefined ) , undefined ) ;
@@ -127,7 +138,7 @@ suite('PythonEnvironmentManagers getLastKnownEnvironment', () => {
127138 test ( 'does not update selection, settings, or events when a registered manager rejects a selection' , async ( ) => {
128139 const scope = Uri . file ( '/workspace/script.py' ) ;
129140 const project = { name : 'script.py' , uri : scope } ;
130- projectManager . setup ( ( pm ) => pm . get ( scope ) ) . returns ( ( ) => project ) ;
141+ projectsByUri . set ( scope . toString ( ) , project ) ;
131142 const managerSet = sinon . stub ( ) . rejects ( new Error ( 'Inline-script environment is not an owned cache entry.' ) ) ;
132143 const managerId = registerManager ( async ( ) => undefined , managerSet ) ;
133144 const rejected = {
@@ -239,6 +250,65 @@ suite('PythonEnvironmentManagers getLastKnownEnvironment', () => {
239250 assert . strictEqual ( envManagers . getLastKnownEnvironment ( secondUri ) , second ) ;
240251 } ) ;
241252
253+ test ( 'does not persist an inline-script manager for the containing project' , async ( ) => {
254+ const script = Uri . file ( '/workspace/project/script.py' ) ;
255+ const containingProject = { name : 'project' , uri : Uri . file ( '/workspace/project' ) } ;
256+ projectsByUri . set ( script . toString ( ) , containingProject ) ;
257+ const managerId = registerManager ( async ( ) => undefined , async ( ) => undefined , 'inline-script' ) ;
258+ const environment = { ...makeEnv ( 'inline' ) , envId : { id : 'inline' , managerId } } ;
259+ stubPackageManager ( ) ;
260+ const settings = sinon . stub ( settingHelpers , 'setAllManagerSettings' ) . resolves ( ) ;
261+
262+ await envManagers . setEnvironment ( script , environment ) ;
263+
264+ assert . strictEqual ( settings . callCount , 0 ) ;
265+ } ) ;
266+
267+ test ( 'persists an inline-script manager when the script is its own project' , async ( ) => {
268+ const script = Uri . file ( '/workspace/script.py' ) ;
269+ const scriptProject = { name : 'script.py' , uri : script } ;
270+ projectsByUri . set ( script . toString ( ) , scriptProject ) ;
271+ const managerId = registerManager ( async ( ) => undefined , async ( ) => undefined , 'inline-script' ) ;
272+ const environment = { ...makeEnv ( 'inline' ) , envId : { id : 'inline' , managerId } } ;
273+ stubPackageManager ( ) ;
274+ const settings = sinon . stub ( settingHelpers , 'setAllManagerSettings' ) . resolves ( ) ;
275+
276+ await envManagers . setEnvironment ( script , environment ) ;
277+
278+ sinon . assert . calledOnce ( settings ) ;
279+ assert . deepStrictEqual ( settings . firstCall . args [ 0 ] , [
280+ {
281+ project : scriptProject ,
282+ envManager : managerId ,
283+ packageManager : 'ms-python.python:pip' ,
284+ } ,
285+ ] ) ;
286+ } ) ;
287+
288+ test ( 'persists batch inline settings only for scripts registered as exact projects' , async ( ) => {
289+ const exactScript = Uri . file ( '/workspace/exact.py' ) ;
290+ const nestedScript = Uri . file ( '/workspace/project/nested.py' ) ;
291+ const looseScript = Uri . file ( '/outside/loose.py' ) ;
292+ const exactProject = { name : 'exact.py' , uri : exactScript } ;
293+ const containingProject = { name : 'project' , uri : Uri . file ( '/workspace/project' ) } ;
294+ projectsByUri . set ( exactScript . toString ( ) , exactProject ) ;
295+ projectsByUri . set ( nestedScript . toString ( ) , containingProject ) ;
296+ const managerId = registerManager ( async ( ) => undefined , async ( ) => undefined , 'inline-script' ) ;
297+ const environment = { ...makeEnv ( 'inline' ) , envId : { id : 'inline' , managerId } } ;
298+ const settings = sinon . stub ( settingHelpers , 'setAllManagerSettings' ) . resolves ( ) ;
299+
300+ await envManagers . setEnvironments ( [ exactScript , nestedScript , looseScript ] , environment ) ;
301+
302+ sinon . assert . calledOnce ( settings ) ;
303+ assert . deepStrictEqual ( settings . firstCall . args [ 0 ] , [
304+ {
305+ project : exactProject ,
306+ envManager : managerId ,
307+ packageManager : 'ms-python.python:pip' ,
308+ } ,
309+ ] ) ;
310+ } ) ;
311+
242312 test ( 'retains an earlier successful refresh when a later refresh fails' , async ( ) => {
243313 const refreshed = makeEnv ( 'refreshed' ) ;
244314 let resolveFirst : ( ( environment : PythonEnvironment ) => void ) | undefined ;
0 commit comments