How to use AppendSubstitution method in autotest

Best Python code snippet using autotest_python Github


Full Screen

...100 if formatter:101 return formatter102 else:103 raise BadFormatter('%r is not a valid formatter' % format_str)104 def AppendSubstitution(self, name, formatters):105 formatters = [self._GetFormatter(f) for f in formatters]106 self.current_block.Append((_DoSubstitute, (name, formatters)))107 def NewSection(self, repeated, section_name):108 """For sections or repeated sections."""109 new_block = _Section(section_name)110 if repeated:111 func = _DoRepeatedSection112 else:113 func = _DoSection114 self.current_block.Append((func, new_block))115 self.stack.append(new_block)116 self.current_block = new_block117 def NewClause(self, name):118 # TODO: Raise errors if the clause isn't appropriate for the current block119 # isn't a 'repeated section' (e.g. alternates with in a non-repeated120 # section)121 self.current_block.NewClause(name)122 def EndSection(self):123 self.stack.pop()124 self.current_block = self.stack[-1]125 def Root(self):126 # It's assumed that we call this at the end of the program127 return self.current_block128class _Section(object):129 """Represents a (repeated) section."""130 def __init__(self, section_name=None):131 """132 Args:133 section_name: name given as an argument to the section134 """135 self.section_name = section_name136 # Pairs of func, args, or a literal string137 self.current_clause = []138 self.statements = {'default': self.current_clause}139 def __repr__(self):140 return '<Block %s>' % self.section_name141 def Statements(self, clause='default'):142 return self.statements.get(clause, [])143 def NewClause(self, clause_name):144 new_clause = []145 self.statements[clause_name] = new_clause146 self.current_clause = new_clause147 def Append(self, statement):148 """Append a statement to this block."""149 self.current_clause.append(statement)150class _ScopedContext(object):151 """Allows scoped lookup of variables.152 If the variable isn't in the current context, then we search up the stack.153 """154 def __init__(self, context):155 self.stack = [context]156 def PushSection(self, name):157 new_context = self.stack[-1].get(name)158 self.stack.append(new_context)159 return new_context160 def Pop(self):161 self.stack.pop()162 def CursorValue(self):163 return self.stack[-1]164 def __iter__(self):165 """Assumes that the top of the stack is a list."""166 # The top of the stack is always the current context.167 self.stack.append(None)168 for item in self.stack[-2]:169 self.stack[-1] = item170 yield item171 self.stack.pop()172 def Lookup(self, name):173 """174 Get the value associated with a name in the current context. The current175 context could be an dictionary in a list, or a dictionary outside a list.176 """177 i = len(self.stack) - 1178 while 1:179 context = self.stack[i]180 if not isinstance(context, dict): # Can't look up names in a list or atom181 i -= 1182 else:183 value = context.get(name)184 if value is None: # A key of None or a missing key are treated the same185 i -= 1186 else:187 return value188 if i <= -1: # Couldn't find it anywhere189 raise UndefinedVariable('%r is not defined' % name)190def _ToString(x):191 if type(x) in (str, unicode):192 return x193 else:194 return pprint.pformat(x)195def _HtmlAttrValue(x):196 return cgi.escape(x, quote=True)197# See for more198# escape types.199#200# Also, we might want to take a look at Django filters.201#202# This is a *public* constant, so that callers can use it construct their own203# formatter lookup dictionaries, and pass them in to Template.204_DEFAULT_FORMATTERS = {205 'html': cgi.escape,206 # The 'htmltag' name is deprecated. The html-attr-value name is preferred207 # because it can be read with "as":208 # {url|html-attr-value} means:209 # "substitute 'url' as an HTML attribute value"210 'html-attr-value': _HtmlAttrValue,211 'htmltag': _HtmlAttrValue,212 'raw': lambda x: x,213 # Used for the length of a list. Can be used for the size of a dictionary214 # too, though I haven't run into that use case.215 'size': lambda value: str(len(value)),216 # The argument is a dictionary, and we get a a=1&b=2 string back.217 'url-params': urllib.urlencode, 218 # The argument is an atom, and it takes 'Search query?' -> 'Search+query%3F'219 'url-param-value': urllib.quote_plus, # param is an atom220 # The default formatter, when no other default is specifier. For debugging,221 # this could be lambda x: json.dumps(x, indent=2), but here we want to be222 # compatible to Python 2.4.223 'str': _ToString,224 # Just show a plain URL on an HTML page (without anchor text).225 'plain-url': lambda x: '<a href="%s">%s</a>' % (226 cgi.escape(x, quote=True), cgi.escape(x)),227 # Placeholders for "standard names". We're not including them by default228 # since they require additional dependencies. We can provide a part of the229 # "lookup chain" in for people people want the dependency.230 231 # 'json' formats arbitrary data dictionary nodes as JSON strings. 'json'232 # and 'js-string' are identical (since a JavaScript string *is* JSON). The233 # latter is meant to be serve as extra documentation when you want a string234 # argument only, which is a common case. 235 'json': None,236 'js-string': None,237 }238def SplitMeta(meta):239 """Split and validate metacharacters.240 Example: '{}' -> ('{', '}')241 This is public so the syntax highlighter and other tools can use it.242 """243 n = len(meta)244 if n % 2 == 1:245 raise ConfigurationError(246 '%r has an odd number of metacharacters' % meta)247 return meta[:n/2], meta[n/2:]248_token_re_cache = {}249def MakeTokenRegex(meta_left, meta_right):250 """Return a (compiled) regular expression for tokenization.251 Args:252 meta_left, meta_right: e.g. '{' and '}'253 - The regular expressions are memoized.254 - This function is public so the syntax highlighter can use it.255 """256 key = meta_left, meta_right257 if key not in _token_re_cache:258 # Need () for re.split259 _token_re_cache[key] = re.compile(260 r'(' +261 re.escape(meta_left) +262 # For simplicity, we allow all characters except newlines inside263 # metacharacters ({} / [])264 r'.+?' +265 re.escape(meta_right) +266 # Some declarations also include the newline at the end -- that is, we267 # don't expand the newline in that case268 r'\n?)')269 return _token_re_cache[key]270def CompileTemplate(271 template_str, builder=None, meta='{}', format_char='|',272 more_formatters=lambda x: None, default_formatter='str'):273 """Compile the template string, calling methods on the 'program builder'.274 Args:275 template_str: The template string. It should not have any compilation276 options in the header -- those are parsed by FromString/FromFile277 builder: Something with the interface of _ProgramBuilder278 meta: The metacharacters to use279 more_formatters: A function which maps format strings to280 *other functions*. The resulting functions should take a data281 dictionary value (a JSON atom, or a dictionary itself), and return a282 string to be shown on the page. These are often used for HTML escaping,283 etc. There is a default set of formatters available if more_formatters284 is not passed.285 default_formatter: The formatter to use for substitutions that are missing a286 formatter. The 'str' formatter the "default default" -- it just tries287 to convert the context value to a string in some unspecified manner.288 Returns:289 The compiled program (obtained from the builder)290 Raises:291 The various subclasses of CompilationError. For example, if292 default_formatter=None, and a variable is missing a formatter, then293 MissingFormatter is raised.294 This function is public so it can be used by other tools, e.g. a syntax295 checking tool run before submitting a template to source control.296 """297 builder = builder or _ProgramBuilder(more_formatters)298 meta_left, meta_right = SplitMeta(meta)299 # : is meant to look like Python 3000 formatting {foo:.3f}. According to300 # PEP 3101, that's also what .NET uses.301 # | is more readable, but, more importantly, reminiscent of pipes, which is302 # useful for multiple formatters, e.g. {name|js-string|html}303 if format_char not in (':', '|'):304 raise ConfigurationError(305 'Only format characters : and | are accepted (got %r)' % format_char)306 # Need () for re.split307 token_re = MakeTokenRegex(meta_left, meta_right)308 tokens = token_re.split(template_str)309 # If we go to -1, then we got too many {end}. If end at 1, then we're missing310 # an {end}.311 balance_counter = 0312 for i, token in enumerate(tokens):313 # By the definition of re.split, even tokens are literal strings, and odd314 # tokens are directives.315 if i % 2 == 0:316 # A literal string317 if token:318 builder.Append(token)319 else:320 had_newline = False321 if token.endswith('\n'):322 token = token[:-1]323 had_newline = True324 assert token.startswith(meta_left), token325 assert token.endswith(meta_right), token326 token = token[len(meta_left) : -len(meta_right)]327 # It's a comment328 if token.startswith('#'):329 continue330 # It's a "keyword" directive331 if token.startswith('.'):332 token = token[1:]333 literal = {334 'meta-left': meta_left,335 'meta-right': meta_right,336 'space': ' ',337 }.get(token)338 if literal is not None:339 builder.Append(literal)340 continue341 match = _SECTION_RE.match(token)342 if match:343 repeated, _, section_name = match.groups()344 builder.NewSection(repeated, section_name)345 balance_counter += 1346 continue347 if token in ('or', 'alternates with'):348 builder.NewClause(token)349 continue350 if token == 'end':351 balance_counter -= 1352 if balance_counter < 0:353 # TODO: Show some context for errors354 raise TemplateSyntaxError(355 'Got too many %send%s statements. You may have mistyped an '356 "earlier 'section' or 'repeated section' directive."357 % (meta_left, meta_right))358 builder.EndSection()359 continue360 # Now we know the directive is a substitution.361 parts = token.split(format_char)362 if len(parts) == 1:363 if default_formatter is None:364 raise MissingFormatter('This template requires explicit formatters.')365 # If no formatter is specified, the default is the 'str' formatter,366 # which the user can define however they desire.367 name = token368 formatters = [default_formatter]369 else:370 name = parts[0]371 formatters = parts[1:]372 builder.AppendSubstitution(name, formatters)373 if had_newline:374 builder.Append('\n')375 if balance_counter != 0:376 raise TemplateSyntaxError('Got too few %send%s statements' %377 (meta_left, meta_right))378 return builder.Root()379_OPTION_RE = re.compile(r'^([a-zA-Z\-]+):\s*(.*)')380# TODO: whitespace mode, etc.381_OPTION_NAMES = ['meta', 'format-char', 'default-formatter']382def FromString(s, more_formatters=lambda x: None, _constructor=None):383 """Like FromFile, but takes a string."""384 f = cStringIO.StringIO(s)385 return FromFile(f, more_formatters=more_formatters, _constructor=_constructor)386def FromFile(f, more_formatters=lambda x: None, _constructor=None):...

Full Screen

Full Screen Github


Full Screen

1import typing2import pathlib3import re4from bzd.parser.element import Element, Sequence5from bzd.parser.visitor import Visitor as VisitorBase6from bzd.parser.error import Error, ExceptionParser7# Needed by the include method8import bzd.template.template9from bzd.template.substitution import SubstitutionsAccessor, SubstitutionWrapper10ResultType = typing.List[str]11class Loop:12 def __init__(self, parent: typing.Optional["Loop"]) -> None:13 self.parent = parent14 self.index: int = 015 @property16 def first(self) -> bool:17 return self.index == 018 def _inc(self) -> None:19 self.index += 120class Visitor(VisitorBase[ResultType, ResultType]):21 nestedKind = None22 def __init__(self,23 substitutions: typing.Union[SubstitutionsAccessor, SubstitutionWrapper],24 includeDirs: typing.Sequence[pathlib.Path] = [pathlib.Path(__file__).parent.parent.parent.parent],25 indent: bool = False) -> None:26 # Re-use directly substitution wrapper if provided.27 # This is needed by the include control block, as we want macros (for example) to be executed28 # with the current substition object and not a copy at a given time.29 self.substitutions = substitutions if isinstance(substitutions,30 SubstitutionWrapper) else SubstitutionWrapper(substitutions)31 self.includeDirs = includeDirs32 # Indent multiline substitution blocks to mmaatch the start of the block.33 self.indent = indent34 self.indentRegexpr = re.compile(r"(?:^|\n)([ \t]*)$")35 # Used to trigger the else condition, this works as any un-resolved if must be followed by the else (if any).36 self.followElse = False37 def visitBegin(self, result: ResultType) -> ResultType:38 return []39 def resolveExpressions(self, sequence: Sequence) -> typing.List[typing.Any]:40 """Resolve expressions into their values.41 Expression is a nested sequence that might correspond to callable arguments, pipeable expression or more42 simply a single expression.43 """44 values: typing.List[typing.Any] = []45 operator = None46 operatorUnary = None47 def substitute(value: typing.Any, key: typing.Any) -> typing.Any:48 if isinstance(key, str) and hasattr(value, key):49 return getattr(value, key)50 try:51 return value[key]52 except:53 raise Exception(54 f"Substitution value for the key '{key}' does not exists. Value is: '{Error.valueExtract(value)}'")55 operators: typing.Dict[str, typing.Callable[[typing.Any, typing.Any], typing.Any]] = {56 "|": (lambda l, r: r(l)),57 "==": (lambda l, r: l == r),58 "!=": (lambda l, r: l != r),59 ">": (lambda l, r: l > r),60 ">=": (lambda l, r: l >= r),61 "<": (lambda l, r: l < r),62 "<=": (lambda l, r: l <= r),63 "in": (lambda l, r: l in r),64 }65 operatorsUnary: typing.Dict[str, typing.Callable[[typing.Any], typing.Any]] = {"not": (lambda r: not r)}66 for element in sequence:67 try:68 elementType = element.getAttr("type").value69 if elementType in operators:70 assert operator is None, f"Detected 2 consecutive operators '{operator}' and '{elementType}'."71 operator = elementType72 elif elementType in operatorsUnary:73 assert operatorUnary is None, f"Detected 2 consecutive unary operators '{operatorUnary}' and '{elementType}'."74 operatorUnary = elementType75 else:76 value: typing.Any77 if elementType == "symbol":78 value = self.substitutions79 for symbol in element.getNestedSequenceAssert(kind="symbol"):80 symbolType = symbol.getAttr("type").value if symbol.isAttr("type") else "symbol"81 if symbolType == "symbol":82 key = symbol.getAttr("value").value83 value = substitute(value, key)84 elif symbolType == "callable":85 assert callable(value), f"The value is not callable."86 args = self.resolveExpressions(symbol.getNestedSequenceAssert("callable"))87 value = value(*args)88 elif symbolType == "array":89 key = self.resolveExpression(symbol.getNestedSequenceAssert("array"))90 value = substitute(value, key)91 else:92 assert False, f"Unknwon symbol type '{symbolType}'."93 elif elementType == "string":94 value = element.getAttr("value").value95 elif elementType == "number":96 value = float(element.getAttr("value").value)97 elif elementType == "true":98 value = True99 elif elementType == "false":100 value = False101 else:102 assert False, f"Unsupported element type '{elementType}'."103 if operator is not None:104 assert len(values) > 0, "There is no value to apply this {operator} operator."105 values[-1] = operators[operator](values[-1], value)106 operator = None107 elif operatorUnary is not None:108 value = operatorsUnary[operatorUnary](value)109 values.append(value)110 operatorUnary = None111 else:112 values.append(value)113 except Exception as e:114 Error.handleFromElement(element=element, message=str(e))115 assert operator is None and operatorUnary is None, "Unterminated expression."116 return values117 def resolveExpression(self, sequence: Sequence) -> typing.Any:118 """Resolve a single expression and ensure it is unique."""119 values = self.resolveExpressions(sequence)120 assert len(values) == 1, f"There are more than a single value: {[type(v) for v in values]}."121 return values[0]122 def visitSubstitution(self, element: Element, result: ResultType) -> None:123 """124 Handle substitution.125 """126 value = self.resolveExpression(element.getNestedSequenceAssert("value"))127 # Save the output128 assert isinstance(value,129 (int, float, str, pathlib.Path130 )), f"The resulting substitued value must be a number, a string or a path, instead received {type(value)}."131 self.appendSubstitution(element=element, result=result, string=str(value))132 def appendSubstitution(self, element: Element, result: ResultType, string: str) -> ResultType:133 # Apply indentation if enabled134 if self.indent and result:135 m =[-1])136 if m:137 string = string.replace("\n", "\n" + result.append(string)139 return result140 def appendBlock(self, element: Element, result: ResultType, block: ResultType) -> ResultType:141 result += block142 return result143 def visitForBlock(self, element: Element) -> ResultType:144 """145 Handle for loop block.146 """147 Error.assertHasAttr(element=element, attr="value1")148 Error.assertHasSequence(element=element, sequence="iterable")149 Error.assertHasSequence(element=element, sequence="nested")150 value1 = element.getAttr("value1").value151 value2 = element.getAttrValue("value2")152 sequence = element.getNestedSequence(kind="nested")153 assert sequence154 block: ResultType = []155 # Loop through the elements156 iterable = self.resolveExpression(sequence=element.getNestedSequenceAssert("iterable"))157 loop = Loop(self.substitutions["loop"] if "loop" in self.substitutions else None)158 self.substitutions.register(element=element, key="loop", value=loop)159 if value2 is None:160 for value in iterable:161 self.substitutions.register(element=element, key=value1, value=value)162 block += self._visit(sequence=sequence)163 self.substitutions.unregister(value1)164 loop._inc()165 else:166 iterablePair = iterable.items() if isinstance(iterable, dict) else enumerate(iterable)167 for key, value in iterablePair:168 self.substitutions.register(element=element, key=value1, value=key)169 self.substitutions.register(element=element, key=value2, value=value)170 block += self._visit(sequence=sequence)171 self.substitutions.unregister(value2)172 self.substitutions.unregister(value1)173 loop._inc()174 self.substitutions.unregister("loop")175 return block176 def visitIfBlock(self, element: Element, optionalCondition: bool) -> ResultType:177 """178 Handle if block.179 """180 sequence = element.getNestedSequenceAssert(kind="nested")181 maybeCondition = element.getNestedSequence(kind="condition")182 if maybeCondition is None:183 assert optionalCondition, "Missing condition."184 condition = True185 else:186 condition = bool(self.resolveExpression(sequence=maybeCondition))187 self.followElse = not condition188 if condition:189 return self._visit(sequence=sequence)190 return []191 def processMacro(self, element: Element, *args: typing.Any) -> str:192 """193 Process a macro already defined.194 """195 sequence = element.getNestedSequence("nested")196 assert sequence197 # Build the argument list198 argList = []199 argument = element.getNestedSequence("argument")200 assert argument is not None201 for arg in argument:202 Error.assertHasAttr(element=arg, attr="name")203 argList.append(arg.getAttr("name").value)204 # Sanity check205 Error.assertTrue(element=element,206 condition=len(argList) == len(args),207 message="Wrong number of argument(s), expected {}: {}".format(len(argList), ", ".join(argList)))208 for i, name in enumerate(argList):209 self.substitutions.register(element=element, key=name, value=args[i])210 # Process the template211 result = self._visit(sequence=sequence)212 for name in argList:213 self.substitutions.unregister(name)214 return "".join(result)215 def visitMacro(self, element: Element) -> None:216 """217 Handle macro definition block.218 """219 Error.assertHasSequence(element=element, sequence="argument")220 Error.assertHasSequence(element=element, sequence="nested")221 Error.assertHasAttr(element=element, attr="name")222 name = element.getAttr("name").value223 Error.assertTrue(element=element,224 attr="name",225 condition=(name not in self.substitutions),226 message="Name conflict with macro and an already existing name: '{}'.".format(name))227 # Register the macro228 self.substitutions.register(element=element, key=name, value=lambda *args: self.processMacro(element, *args))229 def visitInclude(self, element: Element) -> ResultType:230 """231 Handle include.232 """233 Error.assertHasAttr(element=element, attr="value")234 includePathStr = element.getAttr("value").value235 Error.assertTrue(element=element,236 condition=isinstance(includePathStr, str),237 message="The include path must resolve into a string, instead: '{}'.".format(includePathStr))238 path = pathlib.Path(includePathStr)239 paths = [(base / path) for base in self.includeDirs if (base / path).is_file()]240 Error.assertTrue(element=element,241 condition=len(paths) > 0,242 message="No valid file '{}' within {}".format(includePathStr,243 str([f.as_posix() for f in self.includeDirs])))244 template = bzd.template.template.Template(template=paths[0].read_text(),245 includeDirs=self.includeDirs,246 indent=self.indent)247 result, substitutions = template._render(substitutions=self.substitutions)248 # Update the current substitution object249 self.substitutions.update(substitutions)250 return result251 def visitElement(self, element: Element, result: ResultType) -> ResultType:252 """253 Go through all elements and dispatch the action.254 """255 Error.assertHasAttr(element=element, attr="category")256 category = element.getAttr("category").value257 try:258 # Raw content259 if category == "content":260 Error.assertHasAttr(element=element, attr="content")261 string = element.getAttr("content").value262 result.append(string)263 # Substitution264 elif category == "substitution":265 self.visitSubstitution(element=element, result=result)266 # Comments267 elif category == "comment":268 pass269 # End statement270 elif category == "end":271 # Reset the else flag here to make sure nested if without else do not trigger.272 self.followElse = False273 # For loop block274 elif category == "for":275 block = self.visitForBlock(element=element)276 self.appendBlock(element=element, result=result, block=block)277 # If block278 elif category == "if":279 block = self.visitIfBlock(element=element, optionalCondition=False)280 self.appendBlock(element=element, result=result, block=block)281 # Else block282 elif category == "else":283 block = []284 if self.followElse:285 block = self.visitIfBlock(element=element, optionalCondition=True)286 self.appendBlock(element=element, result=result, block=block)287 # Macro block288 elif category == "macro":289 self.visitMacro(element=element)290 # Include block291 elif category == "include":292 block = self.visitInclude(element=element)293 self.appendBlock(element=element, result=result, block=block)294 else:295 raise Exception("Unsupported category: '{}'.".format(category))296 # Propagate processed exception to the top layer297 except ExceptionParser as e:298 raise e299 except Exception as e:300 Error.handleFromElement(element=element, message=str(e))...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:


You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run autotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?