1
1
import json
2
2
import os
3
3
import re
4
- from typing import Sequence
4
+ from typing import Dict , Sequence
5
5
from urllib .parse import urlparse
6
6
7
7
import requests
12
12
13
13
from sphinx_needs .api import add_need
14
14
from sphinx_needs .config import NEEDS_CONFIG , NeedsSphinxConfig
15
+ from sphinx_needs .data import NeedsInfoType
15
16
from sphinx_needs .debug import measure_time
16
17
from sphinx_needs .filter_common import filter_single_need
17
18
from sphinx_needs .needsfile import check_needs_file
@@ -105,12 +106,11 @@ def run(self) -> Sequence[nodes.Node]:
105
106
for error in errors .schema :
106
107
logger .info (f' { error .message } -> { "." .join (error .path )} ' )
107
108
108
- with open (correct_need_import_path ) as needs_file :
109
- needs_file_content = needs_file .read ()
110
109
try :
111
- needs_import_list = json .loads (needs_file_content )
110
+ with open (correct_need_import_path ) as needs_file :
111
+ needs_import_list = json .load (needs_file )
112
112
except json .JSONDecodeError as e :
113
- # ToDo : Add exception handling
113
+ # TODO : Add exception handling
114
114
raise e
115
115
116
116
if version is None :
@@ -123,8 +123,8 @@ def run(self) -> Sequence[nodes.Node]:
123
123
if version not in needs_import_list ["versions" ].keys ():
124
124
raise VersionNotFound (f"Version { version } not found in needs import file { correct_need_import_path } " )
125
125
126
- # TODO type this (it uncovers lots of bugs)
127
- needs_list = needs_import_list ["versions" ][version ]["needs" ]
126
+ # TODO this is not exactly NeedsInfoType, because the export removes/adds some keys
127
+ needs_list : Dict [ str , NeedsInfoType ] = needs_import_list ["versions" ][version ]["needs" ]
128
128
129
129
# Filter imported needs
130
130
needs_list_filtered = {}
@@ -136,7 +136,7 @@ def run(self) -> Sequence[nodes.Node]:
136
136
137
137
# Support both ways of addressing the description, as "description" is used in json file, but
138
138
# "content" is the sphinx internal name for this kind of information
139
- filter_context ["content" ] = need ["description" ]
139
+ filter_context ["content" ] = need ["description" ] # type: ignore[typeddict-item]
140
140
try :
141
141
if filter_single_need (self .env .app , filter_context , filter_string ):
142
142
needs_list_filtered [key ] = need
@@ -158,70 +158,67 @@ def run(self) -> Sequence[nodes.Node]:
158
158
for id in needs_list :
159
159
# Manipulate links in all link types
160
160
for extra_link in extra_links :
161
- if extra_link ["option" ] in need and id in need [extra_link ["option" ]]:
162
- for n , link in enumerate (need [extra_link ["option" ]]):
161
+ if extra_link ["option" ] in need and id in need [extra_link ["option" ]]: # type: ignore[literal-required]
162
+ for n , link in enumerate (need [extra_link ["option" ]]): # type: ignore[literal-required]
163
163
if id == link :
164
- need [extra_link ["option" ]][n ] = "" .join ([id_prefix , id ])
164
+ need [extra_link ["option" ]][n ] = "" .join ([id_prefix , id ]) # type: ignore[literal-required]
165
165
# Manipulate descriptions
166
166
# ToDo: Use regex for better matches.
167
- need ["description" ] = need ["description" ].replace (id , "" .join ([id_prefix , id ]))
167
+ need ["description" ] = need ["description" ].replace (id , "" .join ([id_prefix , id ])) # type: ignore[typeddict-item]
168
168
169
169
# tags update
170
170
for need in needs_list .values ():
171
171
need ["tags" ] = need ["tags" ] + tags
172
172
173
+ known_options = (
174
+ "title" ,
175
+ "status" ,
176
+ "content" ,
177
+ "id" ,
178
+ "tags" ,
179
+ "hide" ,
180
+ "template" ,
181
+ "pre_template" ,
182
+ "post_template" ,
183
+ "collapse" ,
184
+ "style" ,
185
+ "layout" ,
186
+ "need_type" ,
187
+ * [x ["option" ] for x in extra_links ],
188
+ * NEEDS_CONFIG .extra_options ,
189
+ )
173
190
need_nodes = []
174
191
for need in needs_list .values ():
175
192
# Set some values based on given option or value from imported need.
176
- need ["template" ] = self .options .get ("template" , getattr ( need , "template" , None ))
177
- need ["pre_template" ] = self .options .get ("pre_template" , getattr ( need , "pre_template" , None ))
178
- need ["post_template" ] = self .options .get ("post_template" , getattr ( need , "post_template" , None ))
179
- need ["layout" ] = self .options .get ("layout" , getattr ( need , "layout" , None ))
180
- need ["style" ] = self .options .get ("style" , getattr ( need , "style" , None ))
181
- need [ "style" ] = self . options . get ( "style" , getattr ( need , "style" , None ))
193
+ need ["template" ] = self .options .get ("template" , need . get ( "template" ))
194
+ need ["pre_template" ] = self .options .get ("pre_template" , need . get ( "pre_template" ))
195
+ need ["post_template" ] = self .options .get ("post_template" , need . get ( "post_template" ))
196
+ need ["layout" ] = self .options .get ("layout" , need . get ( "layout" ))
197
+ need ["style" ] = self .options .get ("style" , need . get ( "style" ))
198
+
182
199
if "hide" in self .options :
183
200
need ["hide" ] = True
184
201
else :
185
- need ["hide" ] = getattr ( need , "hide" , None )
186
- need ["collapse" ] = self .options .get ("collapse" , getattr ( need , "collapse" , None ))
202
+ need ["hide" ] = need . get ( "hide" , False )
203
+ need ["collapse" ] = self .options .get ("collapse" , need . get ( "collapse" ))
187
204
188
205
# The key needs to be different for add_need() api call.
189
- need ["need_type" ] = need ["type" ]
206
+ need ["need_type" ] = need ["type" ] # type: ignore[typeddict-unknown-key]
190
207
191
208
# Replace id, to get unique ids
192
209
need ["id" ] = id_prefix + need ["id" ]
193
210
194
- need ["content" ] = need ["description" ]
211
+ need ["content" ] = need ["description" ] # type: ignore[typeddict-item]
212
+
195
213
# Remove unknown options, as they may be defined in source system, but not in this sphinx project
196
- extra_link_keys = [x ["option" ] for x in extra_links ]
197
- extra_option_keys = list (NEEDS_CONFIG .extra_options )
198
- default_options = [
199
- "title" ,
200
- "status" ,
201
- "content" ,
202
- "id" ,
203
- "tags" ,
204
- "hide" ,
205
- "template" ,
206
- "pre_template" ,
207
- "post_template" ,
208
- "collapse" ,
209
- "style" ,
210
- "layout" ,
211
- "need_type" ,
212
- ]
213
- delete_options = []
214
- for option in need .keys ():
215
- if option not in default_options + extra_link_keys + extra_option_keys :
216
- delete_options .append (option )
217
-
218
- for option in delete_options :
219
- del need [option ]
214
+ for option in list (need ):
215
+ if option not in known_options :
216
+ del need [option ] # type: ignore
220
217
221
218
need ["docname" ] = self .docname
222
219
need ["lineno" ] = self .lineno
223
220
224
- nodes = add_need (self .env .app , self .state , ** need )
221
+ nodes = add_need (self .env .app , self .state , ** need ) # type: ignore[call-arg]
225
222
need_nodes .extend (nodes )
226
223
227
224
add_doc (self .env , self .env .docname )
0 commit comments