@@ -10,6 +10,7 @@ import { IDynamicDebugConfigurationService } from '../types';
10
10
import { IFileSystem } from '../../../common/platform/types' ;
11
11
import { IPathUtils } from '../../../common/types' ;
12
12
import { DebuggerTypeName } from '../../constants' ;
13
+ import { asyncFilter } from '../../../common/utils/arrayUtils' ;
13
14
14
15
const workspaceFolderToken = '${workspaceFolder}' ;
15
16
@@ -31,19 +32,64 @@ export class DynamicPythonDebugConfigurationService implements IDynamicDebugConf
31
32
justMyCode : true ,
32
33
} ) ;
33
34
34
- const djangoManagePath = await this . fs . search ( path . join ( folder . uri . fsPath , '**/manage.py' ) ) ;
35
- if ( djangoManagePath . length ) {
36
- const managePath = path . relative ( folder . uri . fsPath , djangoManagePath [ 0 ] ) ;
35
+ const djangoManagePath = await this . getDjangoPath ( folder ) ;
36
+ if ( djangoManagePath ) {
37
37
providers . push ( {
38
38
name : 'Dynamic Python: Django' ,
39
39
type : DebuggerTypeName ,
40
40
request : 'launch' ,
41
- program : `${ workspaceFolderToken } ${ this . pathUtils . separator } ${ managePath } ` ,
41
+ program : `${ workspaceFolderToken } ${ this . pathUtils . separator } ${ djangoManagePath } ` ,
42
42
args : [ 'runserver' ] ,
43
43
django : true ,
44
44
justMyCode : true ,
45
45
} ) ;
46
46
}
47
+
48
+ let fastApiPath = await this . getFastApiPath ( folder ) ;
49
+ if ( fastApiPath ) {
50
+ fastApiPath = path
51
+ . relative ( folder . uri . fsPath , fastApiPath )
52
+ . replaceAll ( this . pathUtils . separator , '.' )
53
+ . replace ( '.py' , '' ) ;
54
+ providers . push ( {
55
+ name : 'Dynamic Python: FastAPI' ,
56
+ type : DebuggerTypeName ,
57
+ request : 'launch' ,
58
+ module : 'uvicorn' ,
59
+ args : [ `${ fastApiPath } :app` ] ,
60
+ jinja : true ,
61
+ justMyCode : true ,
62
+ } ) ;
63
+ }
64
+
47
65
return providers ;
48
66
}
67
+
68
+ private async getDjangoPath ( folder : WorkspaceFolder ) {
69
+ const possiblePaths = await this . getPossiblePaths ( folder , [ 'manage.py' , '*/manage.py' ] ) ;
70
+
71
+ return possiblePaths . length ? path . relative ( folder . uri . fsPath , possiblePaths [ 0 ] ) : null ;
72
+ }
73
+
74
+ private async getFastApiPath ( folder : WorkspaceFolder ) {
75
+ const possiblePaths = await this . getPossiblePaths ( folder , [ 'main.py' , 'app.py' , '*/main.py' , '*/app.py' ] ) ;
76
+ const regExpression = / a p p \s * = \s * F a s t A P I \( / ;
77
+ const flaskPaths = await asyncFilter ( possiblePaths , async ( possiblePath ) =>
78
+ regExpression . exec ( ( await this . fs . readFile ( possiblePath ) ) . toString ( ) ) ,
79
+ ) ;
80
+
81
+ return flaskPaths . length ? flaskPaths [ 0 ] : null ;
82
+ }
83
+
84
+ private async getPossiblePaths ( folder : WorkspaceFolder , globPatterns : string [ ] ) : Promise < string [ ] > {
85
+ const foundPathsPromises = ( await Promise . allSettled (
86
+ globPatterns . map (
87
+ async ( pattern ) : Promise < string [ ] > => this . fs . search ( path . join ( folder . uri . fsPath , pattern ) ) ,
88
+ ) ,
89
+ ) ) as { status : string ; value : [ ] } [ ] ;
90
+ const results : string [ ] = [ ] ;
91
+ foundPathsPromises . forEach ( ( result ) => results . push ( ...result . value ) ) ;
92
+
93
+ return results ;
94
+ }
49
95
}
0 commit comments