11use crate :: model:: { Argument , Class , Function , Module , VariableLengthArgument } ;
2- use std:: collections:: HashMap ;
2+ use std:: collections:: { BTreeSet , HashMap } ;
33use std:: path:: { Path , PathBuf } ;
44
55/// Generates the [type stubs](https://typing.readthedocs.io/en/latest/source/stubs.html) of a given module.
@@ -32,51 +32,70 @@ fn add_module_stub_files(
3232
3333/// Generates the module stubs to a String, not including submodules
3434fn module_stubs ( module : & Module ) -> String {
35+ let mut modules_to_import = BTreeSet :: new ( ) ;
3536 let mut elements = Vec :: new ( ) ;
3637 for class in & module. classes {
3738 elements. push ( class_stubs ( class) ) ;
3839 }
3940 for function in & module. functions {
40- elements. push ( function_stubs ( function) ) ;
41+ elements. push ( function_stubs ( function, & mut modules_to_import ) ) ;
4142 }
4243 elements. push ( String :: new ( ) ) ; // last line jump
43- elements. join ( "\n " )
44+
45+ let mut final_elements = Vec :: new ( ) ;
46+ for module_to_import in & modules_to_import {
47+ final_elements. push ( format ! ( "import {module_to_import}" ) ) ;
48+ }
49+ final_elements. extend ( elements) ;
50+ final_elements. join ( "\n " )
4451}
4552
4653fn class_stubs ( class : & Class ) -> String {
4754 format ! ( "class {}: ..." , class. name)
4855}
4956
50- fn function_stubs ( function : & Function ) -> String {
57+ fn function_stubs ( function : & Function , modules_to_import : & mut BTreeSet < String > ) -> String {
5158 // Signature
5259 let mut parameters = Vec :: new ( ) ;
5360 for argument in & function. arguments . positional_only_arguments {
54- parameters. push ( argument_stub ( argument) ) ;
61+ parameters. push ( argument_stub ( argument, modules_to_import ) ) ;
5562 }
5663 if !function. arguments . positional_only_arguments . is_empty ( ) {
5764 parameters. push ( "/" . into ( ) ) ;
5865 }
5966 for argument in & function. arguments . arguments {
60- parameters. push ( argument_stub ( argument) ) ;
67+ parameters. push ( argument_stub ( argument, modules_to_import ) ) ;
6168 }
6269 if let Some ( argument) = & function. arguments . vararg {
6370 parameters. push ( format ! ( "*{}" , variable_length_argument_stub( argument) ) ) ;
6471 } else if !function. arguments . keyword_only_arguments . is_empty ( ) {
6572 parameters. push ( "*" . into ( ) ) ;
6673 }
6774 for argument in & function. arguments . keyword_only_arguments {
68- parameters. push ( argument_stub ( argument) ) ;
75+ parameters. push ( argument_stub ( argument, modules_to_import ) ) ;
6976 }
7077 if let Some ( argument) = & function. arguments . kwarg {
7178 parameters. push ( format ! ( "**{}" , variable_length_argument_stub( argument) ) ) ;
7279 }
7380 format ! ( "def {}({}): ..." , function. name, parameters. join( ", " ) )
7481}
7582
76- fn argument_stub ( argument : & Argument ) -> String {
83+ fn argument_stub ( argument : & Argument , modules_to_import : & mut BTreeSet < String > ) -> String {
7784 let mut output = argument. name . clone ( ) ;
85+ if let Some ( annotation) = & argument. annotation {
86+ output. push_str ( ": " ) ;
87+ output. push_str ( annotation) ;
88+ if let Some ( ( module, _) ) = annotation. rsplit_once ( '.' ) {
89+ // TODO: this is very naive
90+ modules_to_import. insert ( module. into ( ) ) ;
91+ }
92+ }
7893 if let Some ( default_value) = & argument. default_value {
79- output. push ( '=' ) ;
94+ output. push_str ( if argument. annotation . is_some ( ) {
95+ " = "
96+ } else {
97+ "="
98+ } ) ;
8099 output. push_str ( default_value) ;
81100 }
82101 output
@@ -99,26 +118,29 @@ mod tests {
99118 positional_only_arguments : vec ! [ Argument {
100119 name: "posonly" . into( ) ,
101120 default_value: None ,
121+ annotation: None ,
102122 } ] ,
103123 arguments : vec ! [ Argument {
104124 name: "arg" . into( ) ,
105125 default_value: None ,
126+ annotation: None ,
106127 } ] ,
107128 vararg : Some ( VariableLengthArgument {
108129 name : "varargs" . into ( ) ,
109130 } ) ,
110131 keyword_only_arguments : vec ! [ Argument {
111132 name: "karg" . into( ) ,
112133 default_value: None ,
134+ annotation: Some ( "str" . into( ) ) ,
113135 } ] ,
114136 kwarg : Some ( VariableLengthArgument {
115137 name : "kwarg" . into ( ) ,
116138 } ) ,
117139 } ,
118140 } ;
119141 assert_eq ! (
120- "def func(posonly, /, arg, *varargs, karg, **kwarg): ..." ,
121- function_stubs( & function)
142+ "def func(posonly, /, arg, *varargs, karg: str , **kwarg): ..." ,
143+ function_stubs( & function, & mut BTreeSet :: new ( ) )
122144 )
123145 }
124146
@@ -130,22 +152,25 @@ mod tests {
130152 positional_only_arguments : vec ! [ Argument {
131153 name: "posonly" . into( ) ,
132154 default_value: Some ( "1" . into( ) ) ,
155+ annotation: None ,
133156 } ] ,
134157 arguments : vec ! [ Argument {
135158 name: "arg" . into( ) ,
136159 default_value: Some ( "True" . into( ) ) ,
160+ annotation: None ,
137161 } ] ,
138162 vararg : None ,
139163 keyword_only_arguments : vec ! [ Argument {
140164 name: "karg" . into( ) ,
141165 default_value: Some ( "\" foo\" " . into( ) ) ,
166+ annotation: Some ( "str" . into( ) ) ,
142167 } ] ,
143168 kwarg : None ,
144169 } ,
145170 } ;
146171 assert_eq ! (
147- "def afunc(posonly=1, /, arg=True, *, karg= \" foo\" ): ..." ,
148- function_stubs( & function)
172+ "def afunc(posonly=1, /, arg=True, *, karg: str = \" foo\" ): ..." ,
173+ function_stubs( & function, & mut BTreeSet :: new ( ) )
149174 )
150175 }
151176}
0 commit comments