1616import json
1717import re
1818from ast import literal_eval
19- from typing import List , Optional
19+ from typing import Any , Dict , List , Optional
2020
2121import yaml
2222
@@ -126,7 +126,7 @@ def __init__(
126126 self .current_params_indentation = 1
127127
128128 # The current element i.e. user, bot, event, if ...
129- self .current_element = None
129+ self .current_element : Optional [ Dict [ str , Any ]] = None
130130
131131 # The flows that have been parsed
132132 self .flows = {}
@@ -264,7 +264,7 @@ def _normalize_line_text(self):
264264
265265 flow_hash = string_hash (flow_text )
266266
267- self .text += " anonymous-" + flow_hash
267+ self .text += " anonymous-" + str ( flow_hash )
268268
269269 # Below are some more advanced normalizations
270270
@@ -313,8 +313,9 @@ def _create_namespace(self, namespace):
313313 # Now, append the new one
314314 self .current_namespaces .append (namespace )
315315 self .current_namespace = "." .join (self .current_namespaces )
316- self .current_indentation = self .next_line ["indentation" ]
317- self .current_indentations .append (self .next_line ["indentation" ])
316+ next_indentation = self .next_line ["indentation" ] if self .next_line else 0
317+ self .current_indentation = next_indentation
318+ self .current_indentations .append (next_indentation )
318319
319320 # Reset the branches and the ifs on a new flow
320321 self .branches = []
@@ -335,7 +336,11 @@ def _ignore_block_body(self):
335336 def _include_source_mappings (self ):
336337 # Include the source mapping information if required
337338 if self .include_source_mapping :
338- if self .current_element and "_source_mapping" not in self .current_element :
339+ if (
340+ self .current_element is not None
341+ and isinstance (self .current_element , dict )
342+ and "_source_mapping" not in self .current_element
343+ ):
339344 self .current_element ["_source_mapping" ] = {
340345 "filename" : self .filename ,
341346 "line_number" : self .current_line ["number" ],
@@ -790,7 +795,7 @@ def _process_define(self):
790795
791796 # If we're dealing with a topic, then we expand the flow definition
792797 if define_token == "topic" :
793- self . _insert_topic_flow_definition ()
798+ # TODO: Implement topic flow definition insertion
794799 return
795800
796801 # Compute the symbol type
@@ -957,14 +962,18 @@ def _extract_params(self, param_lines: Optional[List] = None):
957962 if isinstance (yaml_value , str ):
958963 yaml_value = {"$0" : yaml_value }
959964
960- # self.current_element.update(yaml_value)
961- for k in yaml_value .keys ():
962- # if the key tarts with $, we remove it
963- param_name = k
964- if param_name [0 ] == "$" :
965- param_name = param_name [1 :]
965+ if (
966+ self .current_element is not None
967+ and isinstance (self .current_element , dict )
968+ and yaml_value is not None
969+ ):
970+ for k in yaml_value .keys ():
971+ # if the key tarts with $, we remove it
972+ param_name = k
973+ if param_name [0 ] == "$" :
974+ param_name = param_name [1 :]
966975
967- self .current_element [param_name ] = yaml_value [k ]
976+ self .current_element [param_name ] = yaml_value [k ]
968977
969978 def _is_test_flow (self ):
970979 """Returns true if the current flow is a test one.
@@ -1005,11 +1014,13 @@ def _is_sample_flow(self):
10051014 def _parse_when (self ):
10061015 # TODO: deal with "when" after "else when"
10071016 assert (
1008- self .next_line ["indentation" ] > self .current_line ["indentation" ]
1017+ self .next_line is not None
1018+ and self .next_line ["indentation" ] > self .current_line ["indentation" ]
10091019 ), "Expected indented block after 'when' statement."
10101020
10111021 # Create the new branch
1012- new_branch = {"elements" : [], "indentation" : self .next_line ["indentation" ]}
1022+ next_indentation = self .next_line ["indentation" ] if self .next_line else 0
1023+ new_branch = {"elements" : [], "indentation" : next_indentation }
10131024
10141025 # # on else, we need to pop the previous branch
10151026 # if self.main_token == "else when":
@@ -1040,13 +1051,16 @@ def _parse_when(self):
10401051 # continue
10411052 # else
10421053 # ...
1054+ next_indentation = (
1055+ self .next_line ["indentation" ] if self .next_line else 0
1056+ )
10431057 self .lines .insert (
10441058 self .current_line_idx + 1 ,
10451059 {
10461060 "text" : f"continue" ,
10471061 # We keep the line mapping the same
10481062 "number" : self .current_line ["number" ],
1049- "indentation" : self . next_line [ "indentation" ] ,
1063+ "indentation" : next_indentation ,
10501064 },
10511065 )
10521066 self .lines .insert (
@@ -1320,9 +1334,11 @@ def _parse_bot(self):
13201334 "text" : f"{ utterance_text } " ,
13211335 # We keep the line mapping the same
13221336 "number" : self .current_line ["number" ],
1323- "indentation" : self .current_indentation + 2
1324- if i == len (indented_lines )
1325- else indented_lines [i ]["indentation" ],
1337+ "indentation" : (
1338+ self .current_indentation + 2
1339+ if i == len (indented_lines )
1340+ else indented_lines [i ]["indentation" ]
1341+ ),
13261342 },
13271343 )
13281344
@@ -1343,7 +1359,9 @@ def _parse_bot(self):
13431359 if utterance_id is None :
13441360 self .current_element ["bot" ] = {
13451361 "_type" : "element" ,
1346- "text" : utterance_text [1 :- 1 ],
1362+ "text" : (
1363+ utterance_text [1 :- 1 ] if utterance_text is not None else ""
1364+ ),
13471365 }
13481366
13491367 # if we have quick_replies, we move them in the element
@@ -1361,7 +1379,13 @@ def _parse_bot(self):
13611379 # If there was a bot message with a snippet, we also add an expect
13621380 # TODO: can this be handled better?
13631381 try :
1364- if "snippet" in self .current_element ["bot" ]:
1382+ if (
1383+ self .current_element is not None
1384+ and isinstance (self .current_element , dict )
1385+ and "bot" in self .current_element
1386+ and isinstance (self .current_element ["bot" ], dict )
1387+ and "snippet" in self .current_element ["bot" ]
1388+ ):
13651389 self .branches [- 1 ]["elements" ].append (
13661390 {
13671391 "expect" : "snippet" ,
@@ -1425,7 +1449,8 @@ def _parse_do(self):
14251449
14261450 # if we need to save the return values, we store the info
14271451 if "=" in flow_name :
1428- return_vars , flow_name = get_stripped_tokens (split_max (flow_name , "=" , 1 ))
1452+ stripped_tokens = get_stripped_tokens (split_max (flow_name , "=" , 1 ))
1453+ return_vars , flow_name = stripped_tokens [0 ], stripped_tokens [1 ]
14291454 else :
14301455 return_vars = None
14311456
@@ -1475,8 +1500,9 @@ def _parse_meta(self):
14751500 branch_elements .insert (0 , {"meta" : {}})
14761501
14771502 # Update the elements coming from the parameters
1478- for k in self .current_element .keys ():
1479- branch_elements [0 ]["meta" ][k ] = self .current_element [k ]
1503+ if self .current_element is not None :
1504+ for k in self .current_element .keys ():
1505+ branch_elements [0 ]["meta" ][k ] = self .current_element [k ]
14801506
14811507 def _parse_generic (self ):
14821508 value = split_max (self .text , " " , 1 )[1 ].strip ()
@@ -1545,7 +1571,9 @@ def _parse_if_branch(self, if_condition):
15451571 self .ifs .append (
15461572 {
15471573 "element" : self .current_element ,
1548- "indentation" : self .next_line ["indentation" ],
1574+ "indentation" : (
1575+ self .next_line ["indentation" ] if self .next_line is not None else 0
1576+ ),
15491577 # We also record this to match it with the else
15501578 "keyword_indentation" : self .current_indentation ,
15511579 }
@@ -1588,7 +1616,9 @@ def _parse_while(self):
15881616 self .branches .append (
15891617 {
15901618 "elements" : self .current_element ["do" ],
1591- "indentation" : self .next_line ["indentation" ],
1619+ "indentation" : (
1620+ self .next_line ["indentation" ] if self .next_line is not None else 0
1621+ ),
15921622 }
15931623 )
15941624
@@ -1602,7 +1632,9 @@ def _parse_any(self):
16021632 self .branches .append (
16031633 {
16041634 "elements" : self .current_element ["any" ],
1605- "indentation" : self .next_line ["indentation" ],
1635+ "indentation" : (
1636+ self .next_line ["indentation" ] if self .next_line is not None else 0
1637+ ),
16061638 }
16071639 )
16081640
@@ -1631,7 +1663,9 @@ def _parse_infer(self):
16311663 self .branches .append (
16321664 {
16331665 "elements" : self .current_element ["infer" ],
1634- "indentation" : self .next_line ["indentation" ],
1666+ "indentation" : (
1667+ self .next_line ["indentation" ] if self .next_line is not None else 0
1668+ ),
16351669 }
16361670 )
16371671
@@ -1767,15 +1801,15 @@ def parse(self):
17671801 exception = Exception (error )
17681802
17691803 # Decorate the exception with where the parsing failed
1770- exception . filename = self .filename
1771- exception . line = self .current_line ["number" ]
1772- exception . error = str (ex )
1804+ setattr ( exception , " filename" , self .filename )
1805+ setattr ( exception , " line" , self .current_line ["number" ])
1806+ setattr ( exception , " error" , str (ex ) )
17731807
17741808 raise exception
17751809
17761810 self .current_line_idx += 1
17771811
1778- result = {"flows" : self .flows }
1812+ result : Dict [ str , Any ] = {"flows" : self .flows }
17791813
17801814 if self .imports :
17811815 result ["imports" ] = self .imports
@@ -1818,7 +1852,7 @@ def parse_snippets_and_imports(self):
18181852 """
18191853 snippets = {}
18201854 imports = []
1821- snippet = None
1855+ snippet : Optional [ Dict [ str , Any ]] = None
18221856
18231857 while self .current_line_idx < len (self .lines ):
18241858 self ._fetch_current_line ()
@@ -1833,6 +1867,7 @@ def parse_snippets_and_imports(self):
18331867 for k in self .current_line .keys ():
18341868 d [k ] = self .current_line [k ]
18351869 d ["filename" ] = self .filename
1870+ assert snippet is not None # Type checker hint
18361871 snippet ["lines" ].append (d )
18371872
18381873 self .current_line_idx += 1
0 commit comments