18 from robot.utils import file_writer, is_pathlike, is_string
20 from .statements
import Comment, EmptyLine
21 from .visitor
import ModelVisitor
22 from ..lexer
import Token
33 _attributes = (
'lineno',
'col_offset',
'end_lineno',
'end_col_offset',
'errors')
40 statement = FirstStatementFinder.find_from(self)
41 return statement.lineno
if statement
else -1
47 statement = FirstStatementFinder.find_from(self)
48 return statement.col_offset
if statement
else -1
54 statement = LastStatementFinder.find_from(self)
55 return statement.end_lineno
if statement
else -1
58 end_col_offset = property
61 statement = LastStatementFinder.find_from(self)
62 return statement.end_col_offset
if statement
else -1
71 for node
in self.body:
72 if not isinstance(node, (EmptyLine, Comment)):
81 _fields = (
'header',
'body')
83 def __init__(self, header, body=None, errors=()):
93 _fields = (
'sections',)
97 _attributes = (
'source',
'languages') + Block._attributes
99 def __init__(self, sections=None, source=None, languages=()):
111 output = output
or self.
sourcesource
113 raise TypeError(
'Saving model requires explicit output '
114 'when original source is not path.')
122 _fields = (
'header',
'body')
133 class VariableSection(Section):
144 return self.
headerheader.type == Token.TASK_HEADER
151 class CommentSection(Section):
159 _fields = (
'header',
'body')
169 return self.
headerheader.name
176 _fields = (
'header',
'body')
186 return self.
headerheader.name
198 _fields = (
'header',
'body',
'orelse',
'end')
200 def __init__(self, header, body=None, orelse=None, end=None, errors=()):
211 return self.
headerheader.type
217 return self.
headerheader.condition
223 return self.
headerheader.assign
230 if self.
typetypetype == Token.INLINE_IF:
237 self.
errorserrorserrors += (f
'{type} branch cannot be empty.',)
240 orelse = self.
orelseorelse
244 if orelse.type == Token.ELSE:
245 error =
'Only one ELSE allowed.'
247 error =
'ELSE IF not allowed after ELSE.'
250 else_seen = else_seen
or orelse.type == Token.ELSE
251 orelse = orelse.orelse
255 self.
errorserrorserrors += (
'IF must have closing END.',)
259 assign = branch.assign
262 item = branch.body[0]
263 if assign
and item.type != Token.KEYWORD:
264 self.
errorserrorserrors += (
'Inline IF with assignment can only contain '
266 if getattr(item,
'assign',
None):
267 self.
errorserrorserrors += (
'Inline IF branches cannot contain assignments.',)
268 if item.type == Token.INLINE_IF:
269 self.
errorserrorserrors += (
'Inline IF cannot be nested.',)
270 branch = branch.orelse
277 _fields = (
'header',
'body',
'end')
279 def __init__(self, header, body=None, end=None, errors=()):
289 return self.
headerheader.variables
295 return self.
headerheader.values
301 return self.
headerheader.flavor
305 self.
errorserrorserrors += (
'FOR loop cannot be empty.',)
307 self.
errorserrorserrors += (
'FOR loop must have closing END.',)
314 _fields = (
'header',
'body',
'next',
'end')
316 def __init__(self, header, body=None, next=None, end=None, errors=()):
327 return self.
headerheader.type
333 return getattr(self.
headerheader,
'patterns', ())
336 pattern_type = property
339 return getattr(self.
headerheader,
'pattern_type',
None)
345 return getattr(self.
headerheader,
'variable',
None)
355 self.
errorserrorserrors += (f
'{self.type} branch cannot be empty.',)
361 empty_except_count = 0
362 branch = self.
nextnext
364 if branch.type == Token.EXCEPT:
366 self.
errorserrorserrors += (
'EXCEPT not allowed after ELSE.',)
368 self.
errorserrorserrors += (
'EXCEPT not allowed after FINALLY.',)
369 if branch.patterns
and empty_except_count:
370 self.
errorserrorserrors += (
'EXCEPT without patterns must be last.',)
371 if not branch.patterns:
372 empty_except_count += 1
374 if branch.type == Token.ELSE:
376 self.
errorserrorserrors += (
'ELSE not allowed after FINALLY.',)
378 if branch.type == Token.FINALLY:
381 if finally_count > 1:
382 self.
errorserrorserrors += (
'Only one FINALLY allowed.',)
385 if empty_except_count > 1:
386 self.
errorserrorserrors += (
'Only one EXCEPT without patterns allowed.',)
387 if not (except_count
or finally_count):
388 self.
errorserrorserrors += (
'TRY structure must have EXCEPT or FINALLY branch.',)
392 self.
errorserrorserrors += (
'TRY must have closing END.',)
399 _fields = (
'header',
'body',
'end')
401 def __init__(self, header, body=None, end=None, errors=()):
411 return self.
headerheader.condition
417 return self.
headerheader.limit
421 self.
errorserrorserrors += (
'WHILE loop cannot be empty.',)
423 self.
errorserrorserrors += (
'WHILE loop must have closing END.',)
433 self.
writerwriter = output
438 self.
visitvisit(model)
444 for token
in statement.tokens:
454 self.
_context_context.start_block(node)
455 node.validate(self.
_context_context)
456 ModelVisitor.generic_visit(self, node)
460 if node.header.type == Token.FINALLY:
461 self.
_context_context.in_finally =
True
463 self.
_context_context.in_finally =
False
466 node.validate(self.
_context_context)
467 ModelVisitor.generic_visit(self, node)
477 self.
rootsroots.append(node)
480 self.
rootsroots.pop()
483 in_keyword = property
486 return Keyword
in [
type(r)
for r
in self.
rootsroots]
492 return For
in [
type(r)
for r
in self.
rootsroots]
498 return While
in [
type(r)
for r
in self.
rootsroots]
510 return finder.statement
518 ModelVisitor.generic_visit(self, node)
530 return finder.statement
def validate(self, context)
def save(self, output=None)
Save model to the given output or to the original source file.
def __init__(self, sections=None, source=None, languages=())
def generic_visit(self, node)
def find_from(cls, model)
def visit_Statement(self, statement)
def validate(self, context)
def __init__(self, header, body=None, end=None, errors=())
def __init__(self, header, body=None, errors=())
Represents IF structures in the model.
def _validate_structure(self)
def validate(self, context)
def __init__(self, header, body=None, orelse=None, end=None, errors=())
def _validate_inline_if(self)
def __init__(self, header, body=None)
def find_from(cls, model)
def visit_Statement(self, statement)
def visit_Statement(self, node)
def visit_Block(self, node)
def visit_Try(self, node)
def __init__(self, output)
def visit_Statement(self, statement)
def __init__(self, header=None, body=None)
def __init__(self, header, body=None)
def _validate_structure(self)
def __init__(self, header, body=None, next=None, end=None, errors=())
def validate(self, context)
def start_block(self, node)
def validate(self, context)
def __init__(self, header, body=None, end=None, errors=())
NodeVisitor that supports matching nodes based on their base classes.
def write(msg, level='INFO', html=False)
Writes the message to the log file using the given level.
def file_writer(path=None, encoding='UTF-8', newline=None, usage=None)