How to use _compile_rule method in Gherkin-python

Best Python code snippet using gherkin-python

parser_v2.py

Source:parser_v2.py Github

copy

Full Screen

...227 self.prefixes = {}228 for key in self.grammar:229 self.prefixes[key] = self.get_prefixes(key)230 def compile_repeat(self, rule):231 rule_parser = self._compile_rule(rule['repeat'])232 @self.parser('repeat',rule=rule, emit=False)233 def repeat_parser(state, context):234 cnt=0235 current_state = state236 while True:237 try:238 current_state = rule_parser(current_state, context)239 cnt+=1240 except ParserError:241 break242 if cnt == 0:243 raise ParserError244 return current_state245 return repeat_parser246 def compile_optional(self, rule):247 rule_parser = self._compile_rule(rule['optional'])248 @self.parser('optional',rule=rule, emit=False)249 def optional_parser(state, context):250 try:251 return rule_parser(state, context)252 except ParserError as me:253 return state254 return optional_parser255 def compile_or(self, rule):256 alternative_parsers = []257 alternatives = rule['or']258 for i,alternative in enumerate(alternatives):259 alternative_parsers.append((alternative,self._compile_rule(alternative)))260 @self.parser('or',rule=rule, emit=False)261 def or_parser(state, context):262 """263 Pass in context object that contains information about the following things:264 * Which rule has called this one?265 *266 """267 found = False268 for alternative,alternative_parser in alternative_parsers:269 try:270 return alternative_parser(state, context)271 except ParserError as pe:272 continue273 else:274 raise ParserError("No alternative matched!")275 return or_parser276 def compile_not(self, rule):277 rule_parser = self._compile_rule(rule['not'])278 @self.parser('not',rule=rule, emit=False)279 def not_parser(state, context):280 try:281 rule_parser(state, context)282 except ParserError:283 return state284 raise ParserError("not condition did match!")285 return not_parser286 def compile_and(self, rule):287 rule_parser = self._compile_rule(rule['and'])288 @self.parser('and',rule=rule, emit=False)289 def and_parser(state, context):290 try:291 rule_parser(state, context)292 return state293 except ParserError:294 raise ParserError("and condition did not match!")295 return and_parser296 def compile_sequence(self, rules):297 """298 Increase the level by one for each element in the sequence299 """300 parsers = []301 for i,rule in enumerate(rules):302 ps = self._compile_rule(rule)303 if ps is None:304 raise AttributeError305 parsers.append((rule,ps))306 @self.parser('sequence', rule=rules,emit=False)307 def sequence_parser(state, context):308 """309 * Execute the first parser on the state310 * For each returned state, execute the second parser311 * For each returned state, execute the third parser...312 """313 current_state = state.copy()314 for rule,parser in parsers:315 current_state = parser(current_state, context)316 return current_state317 return sequence_parser318 def compile(self, debug=True):319 self.parsers = {}320 return self._compile_rule('start')321 def resolve_rule(self,name):322 func = getattr(self,'compile_{}'.format(name.replace('-','_')))323 return func324 def rule_prefix(self,rule_name):325 return set([])326 def can_proceed(self, rule, state):327 return True328 def get_prefixes(self,rule,visited_rules = None):329 if visited_rules is None:330 visited_rules = set()331 prefixes = set()332 get_prefixes = lambda rule: self.get_prefixes(rule,visited_rules=visited_rules)333 if isinstance(rule, (str,unicode)):334 if rule in visited_rules:335 return set([])336 visited_rules|=set([rule])337 if rule in self.grammar:338 return get_prefixes(self.grammar[rule])339 else:340 return self.rule_prefix(rule)341 elif isinstance(rule,(tuple,list)):342 for i,subrule in enumerate(rule):343 subrule_prefixes = get_prefixes(subrule)344 if (not subrule_prefixes and not prefixes) or (None in subrule_prefixes):345 prefixes |= subrule_prefixes - set([None])346 else:347 prefixes |= subrule_prefixes348 break349 elif isinstance(rule,dict) and len(rule) == 1:350 key,value = rule.items()[0]351 if key == 'or':352 for subrule in value:353 prefixes |= get_prefixes(subrule)354 elif key in ('and','repeat'):355 prefixes |= get_prefixes(value)356 elif key == 'not':357 #not sure if this is the right way to handle not358 return set([None])359# prefixes |= {('not',prefix) for prefix in get_prefixes(value)}360 elif key == 'optional':361 prefixes |= set([None])362 prefixes |= get_prefixes(value)363 else:364 return self.rule_prefix(rule)365 else:366 raise ValueError("Invalid rule!")367 def _compile_rule(self, name_or_rule):368 name = None369 if isinstance(name_or_rule,(str,unicode)):370 name = name_or_rule371 if name in self.parsers:372 return self.parsers[name]373 try:374 rule = self.grammar[name]375 except KeyError:376 try:377 func = self.resolve_rule(name)378 return func()379 except AttributeError:380 raise ParserError("Unknown rule: {}".format(name))381 else:382 rule = name_or_rule383 def parse_subrule(rule, name=None):384 rule_name = rule.keys()[0]385 try:386 func = self.resolve_rule(rule_name)387 except AttributeError:388 raise ParserError("Unknown rule: {}".format(rule_name))389 subparser = func(rule)390 if name:391 @self.parser(name,rule=name,emit=True)392 def name_parser(state, context):393 return subparser(state, context)394 self.parsers[name] = name_parser395 return name_parser396 return subparser397 #this allows definition of recursive parsing rules via a simple function call398 if name:399 #this will lead to infinite recursion if the parser is not replaced!400 def subrule_parser(state, context):401 return self.parsers[name](state, context)402 self.parsers[name] = subrule_parser403 if isinstance(rule,(list,tuple)):404 sequence_parser = self.compile_sequence(rule)405 if name:406 @self.parser(name,rule=name,emit=True)407 def subrule_parser(state, context):408 return sequence_parser(state, context)409 self.parsers[name] = subrule_parser410 return subrule_parser411 return sequence_parser412 elif isinstance(rule,dict) and len(rule) == 1:413 return parse_subrule(rule, name=name)414 elif isinstance(rule,(str,unicode)):415 ps = self._compile_rule(rule)416 @self.parser(name,rule=rule,emit=True)417 def subrule_parser(state, context):418 return ps(state, context)419 self.parsers[name] = subrule_parser420 return subrule_parser421 raise ParserError("Unknown rule: {}".format(name or name_or_rule or '(no name given)'))422class StringParserGenerator(BaseParserGenerator):423 """424 Generating an abstract syntax tree is done implictly by each rule425 """426 def parser(self,name,rule=None, emit=True):427 def dec(f):428 def decorated_function(state, context, *args, **kwargs):429 new_context = Context(context.level+1,name,context)430 #print("{}{} {}:{}".format(" "*new_context.level,new_context.name,state.line,state.col))431 i = len(state.tokens)432 result = f(state, new_context, *args, **kwargs)433 if emit:434 #this rule was successful, we can create a node in the parse tree for it435 children = result.tokens[i:]436 result.tokens = result.tokens[:i]437 new_token = state.create_token(name,state.value[:result.pos-state.pos],push=False)438 result.tokens.append(new_token)439 if children:440 new_token['c'] = children441 return result442 return decorated_function443 return dec444 def rule_prefix(self,rule):445 if isinstance(rule,(str,unicode)):446 return set([rule])447 elif isinstance(rule,dict) and len(rule) == 1:448 key,value = rule.items()[0]449 if key == 'literal':450 return set([value])451 elif key == 'regex':452 return set([('regex',value)])453 else:454 raise ValueError455 def compile_eof(self):456 @self.parser('eof',rule='eof', emit=True)457 def eof_parser(state, context):458 if state.value != '':459 raise ParserError("Expected EOF")460 return state461 return eof_parser462 def compile_indent(self):463 @self.parser('indent',rule='indent', emit=False)464 def indent_parser(state, context):465 """466 * Match the indentation467 * Compare the matched indentation to the current one.468 * If it is longer, emit a CURRENT_INDENT INDENT token sequence469 * If it is shorter, emit a DEDENT+ CURRENT_INDENT token sequence470 """471 indent_str = re.match(r'^[ \t]*',state.value).group(0)472 new_state = state.copy()473 indents = new_state.store.get('indent',[''])474 current_indent = indents[-1]475 if indent_str == current_indent:476 #yield a CURRENT_INDENT token477 new_state.create_token('current_indent',indent_str,ignore=True)478 new_state.advance(len(indent_str))479 return new_state480 elif len(indent_str) > len(current_indent) and indent_str[:len(current_indent)] == current_indent:481 #this is an indentation482 new_state.create_token('current_indent',current_indent,ignore=True)483 new_state.advance(len(current_indent))484 new_indent = indent_str[len(current_indent):]485 new_state.create_token('indent',new_indent)486 new_state.advance(len(new_indent))487 indents.append(indent_str)488 new_state.store['indent'] = indents489 return new_state490 else:491 #this should be a dedentation492 possible_indents = indents[:-1]493 cnt = 0494 while True:495 if not possible_indents:496 raise ParserError("Dedentation does not match!")497 cnt+=1498 possible_indent = possible_indents.pop(-1)499 if possible_indent == indent_str:500 for i in range(cnt):501 new_state.create_token('dedent','')502 new_state.create_token('current_indent',possible_indent,ignore=True)503 new_state.store['indent'] = possible_indents+[possible_indent]504 new_state.advance(len(indent_str))505 return new_state506 return indent_parser507 def compile_regex(self, rule):508 regex = rule['regex']509 #DOTALL is necessary to match newlines510 compiled_regex = re.compile('^{}'.format(regex),re.DOTALL)511 @self.parser('regex', rule=rule)512 def regex_parser(state, context):513 match = compiled_regex.match(state.value)514 if match:515 s = match.group(0)516 context.debug("match!")517 new_state = state.copy()518 new_state.result = s519 new_state.advance(len(s))520 return new_state521 else:522 raise ParserError("Regex not matched: {}".format(regex))523 return regex_parser524 def compile_literal(self, rule):525 value = rule['literal']526 if isinstance(value, dict):527 value = self._compile_rule(value)528 @self.parser('literal',rule=rule)529 def literal_parser(state, context):530 if callable(value):531 v = value(state, context)532 else:533 v = value534 found_value = state.value[:len(v)]535 if found_value != v:536 raise ParserError("Expected {}, but found '{}'".format(value, found_value))537 context.debug(v)538 new_state = state.copy()539 new_state.advance(len(v))540 new_state.result = v541 return new_state...

Full Screen

Full Screen

parser_old.py

Source:parser_old.py Github

copy

Full Screen

...132 yield new_state133 return ref_parser134 def compile_ast_list(self, props, url):135 name = props.get('name')136 rule_parser = self._compile_rule(props['value'], url+'.ast-list')137 @parser('ast-list', url)138 def ast_list_parser(state, context):139 l = []140 current_node = state.current_node141 state.current_node = l142 try:143 for new_state in rule_parser(state, context):144 if isinstance(current_node,dict) and name:145 new_current_node = new_state.current_node146 new_state.current_node = current_node.copy()147 new_state.current_node[name] = new_current_node148 yield new_state149 finally:150 state.current_node = current_node151 return ast_list_parser152 def compile_ast_prop(self, props, url):153 name = props.get('name')154 value_parser = self._compile_rule(props['value'], url+'.ast-prop')155 @parser('ast-prop', url)156 def ast_prop_parser(state, context):157 for new_state in value_parser(state, context):158 current_node = new_state.current_node159 if isinstance(current_node,dict):160 current_node[name] = new_state.result161 yield new_state162 return ast_prop_parser163 def compile_ast_node(self, props, url):164 """165 Create a new AST node.166 * If the current node is a list, appends the new node to it167 * If the current node is a dict, puts the new node in the key given by name (if provided)168 * If none of these things match, does nothing169 """170 rule_parser = self._compile_rule(props['value'], url+'.ast-node')171 name = props.get('name')172 @parser('ast-node', url)173 def ast_node_parser(state, context):174 d = {}175 d.update(props.get('props',{}))176 current_node = state.current_node177 state.current_node = d178 try:179 for new_state in rule_parser(state, context):180 new_current_node = new_state.current_node181 if isinstance(current_node,list):182 new_state.current_node = current_node[:]183 new_state.current_node.append(new_current_node)184 elif isinstance(current_node,dict):185 new_state.current_node = current_node.copy()186 if name:187 new_state.current_node[name] = new_current_node188 else:189 new_state.current_node.update(new_current_node)190 yield new_state191 finally:192 state.current_node = current_node193 return ast_node_parser194 def compile_repeat(self, rule, url):195 rule_parser = self._compile_rule(rule, url+'.repeat')196 @parser('repeat', url)197 def repeat_parser(state, context):198 cnt=0199 current_state = state200 states_to_repeat=[state]201 states_to_yield = []202 productions = []203 while states_to_repeat or states_to_yield or productions:204 if states_to_repeat:205 current_state=states_to_repeat.pop()206 states_to_yield.append(current_state)207 try:208 production=rule_parser(current_state, context)209 new_state = next(production)210 #if the production does not advance the state, we reject it...211 if new_state.pos == current_state.pos:212 continue213 productions.append(production)214 states_to_repeat.append(new_state)215 except (ParserError, StopIteration) as e :216 continue217 elif states_to_yield:218 state_to_yield = states_to_yield.pop()219 cnt +=1220 if state_to_yield != state:221 yield state_to_yield222 elif productions:223 production = productions[-1]224 try:225 new_state = next(production)226 states_to_yield.append(new_state)227 except (ParserError,StopIteration):228 productions.pop()229 if cnt==0:230 raise ParserError("Not matched!")231 return repeat_parser232 def compile_optional(self, rule, url):233 rule_parser = self._compile_rule(rule, url+'.optional')234 @parser('optional', url)235 def optional_parser(state, context):236 try:237 for new_state in rule_parser(state, context):238 yield new_state239 except ParserError as me:240 pass241 yield state242 return optional_parser243 def compile_store(self, args, url):244 name = args['name']245 value = args['value']246 value_parser = self._compile_rule(value, url+'.store')247 @parser('store', url)248 def store_parser(state, context):249 for ns in value_parser(state, context):250 new_state = state.copy()251 new_state.result = ns.result252 yield new_state253 return store_parser254 def compile_literal(self, value, url):255 if isinstance(value, dict):256 value = self._compile_rule(value, url+'.literal')257 @parser('literal', url)258 def literal_parser(state, context):259 context.debug(value)260 if callable(value):261 v = value(state, context)262 else:263 v = value264 found_value = state.value[:len(v)]265 if found_value != v:266 raise ParserError("Expected {}, but found '{}'".format(value, found_value))267 context.debug(v)268 new_state = state.copy()269 new_state.advance(len(v))270 new_state.result = v271 yield new_state272 return literal_parser273 def compile_python_code(self, code, url):274 gv = globals().copy()275 gv['url'] = url276 exec(code,gv,gv)277 return gv['parser']278 def compile_or(self, alternatives, url):279 alternative_parsers = []280 for i,alternative in enumerate(alternatives):281 alternative_parsers.append((alternative,self._compile_rule(alternative, url+'.or.{}'.format(i))))282 @parser('or', url)283 def or_parser(state, context):284 """285 Pass in context object that contains information about the following things:286 * Which rule has called this one?287 *288 """289 found = False290 alternative_productions = []291 for params,alternative_parser in alternative_parsers:292 try:293 alternative_productions.append(alternative_parser(state, context))294 except ParserError as me:295 continue296 i = 0297 while alternative_productions:298 production = alternative_productions[i%len(alternative_productions)]299 try:300 new_state = next(production)301 found = True302 yield new_state303 i+=1304 except (ParserError,StopIteration):305 alternative_productions.remove(production)306 if not found:307 raise ParserError("No alternative matched!")308 return or_parser309 def compile_sequence(self, rules, url):310 """311 Increase the level by one for each element in the sequence312 """313 parsers = []314 for i,rule in enumerate(rules):315 ps = self._compile_rule(rule, url+'.seq.{}'.format(i))316 if ps is None:317 raise AttributeError318 parsers.append(ps)319 @parser('sequence', url)320 def sequence_parser(state, context):321 """322 * Execute the first parser on the state323 * For each returned state, execute the second parser324 * For each returned state, execute the third parser...325 """326 def parse_sequence(state, parsers):327 parser = parsers.pop(0)328 for new_state in parser(state, context):329 if parsers:330 try:331 for new_new_state in parse_sequence(new_state, parsers[:]):332 yield new_new_state333 except ParserError:334 continue335 else:336 yield new_state337 for new_state in parse_sequence(state, parsers[:]):338 yield new_state339 return sequence_parser340 def compile(self, debug=True):341 self.parsers = {}342 return self._compile_rule('start', '')343 def _compile_rule(self, name_or_rule, url):344 """345 Takes a YAML grammar as input and returns a Python parser function that can be346 called with a Stream instance and a state as arguments.347 """348 name = None349 if isinstance(name_or_rule,(str,unicode)):350 name = name_or_rule351 if name in self.parsers:352 return self.parsers[name]353 rule = self.grammar[name]354 else:355 rule = name_or_rule356 if name:357 new_url = url+'.'+name358 else:359 new_url = url360 def parse_subrule(rule, name=None):361 rule_name = rule.keys()[0]362 args = rule.values()[0]363 if rule_name == '$python':364 result = self.compile_python_code(args, url+'.{}'.format(name))365 if name:366 self.parsers[name] = result367 return result368 try:369 func = getattr(self,'compile_{}'.format(rule_name.replace('-','_')))370 except AttributeError:371 raise ParserError("Unknown rule: {}".format(rule_name))372 subparser = func(args, new_url)373 @parser(rule_name, None)374 def subrule_parser(state, context):375 for result in subparser(state, context):376 yield result377 if name:378 @parser(name, None)379 def name_parser(state, context):380 for result in subrule_parser(state, context):381 yield result382 self.parsers[name] = name_parser383 return name_parser384 return subrule_parser385 #this allows definition of recursive parsing rules via a simple function call386 if name:387 #this will lead to infinite recursion if the parser is not replaced!388 @parser(name, url)389 def subrule_parser(state, context):390 for result in self.parsers[name](state, context):391 yield result392 self.parsers[name] = subrule_parser393 if isinstance(rule,(list,tuple)):394 sequence_parser = self.compile_sequence(rule, new_url)395 if name:396 @parser(name, None)397 def subrule_parser(state, context):398 for result in sequence_parser(state, context):399 yield result400 self.parsers[name] = subrule_parser401 return subrule_parser402 return sequence_parser403 elif isinstance(rule,dict) and len(rule) == 1:404 return parse_subrule(rule, name=name)405 elif isinstance(rule,(str,unicode)):406 new_new_url = new_url+'.'+rule407 ps = self._compile_rule(rule, new_new_url)408 @parser(name, None)409 def subrule_parser(state, context):410 for result in ps(state, context):411 yield result412 self.parsers[name] = subrule_parser413 return subrule_parser414 raise ParserError("Unknown rule: {}".format(name or name_or_rule or '(no name given)'))415if __name__ == '__main__':416 import sys417 sys.setrecursionlimit(100000)418 if len(sys.argv) < 3:419 sys.stderr.write("Usage: {} [grammar filename] [code filename]\n".format(os.path.basename(__file__)))420 exit(-1)421 grammar_filename = sys.argv[1]...

Full Screen

Full Screen

project.py

Source:project.py Github

copy

Full Screen

...93 Assert that there's no legacy filter.py code hooked up.94 '''95 assert self.filter_py is None96 for rule in rules:97 self.rules.extend(self._compile_rule(rule))98 def add_child(self, child):99 self.children.append(child)100 def set_locales(self, locales, deep=False):101 self.locales = locales102 for child in self.children:103 if not child.locales or deep:104 child.set_locales(locales, deep=deep)105 else:106 locs = [loc for loc in locales if loc in child.locales]107 child.set_locales(locs)108 @property109 def configs(self):110 'Recursively get all configs in this project and its children'111 yield self112 for child in self.children:113 for config in child.configs:114 yield config115 def filter(self, l10n_file, entity=None):116 '''Filter a localization file or entities within, according to117 this configuration file.'''118 if self.filter_py is not None:119 return self.filter_py(l10n_file.module, l10n_file.file,120 entity=entity)121 rv = self._filter(l10n_file, entity=entity)122 if rv is None:123 return 'ignore'124 return rv125 class FilterCache(object):126 def __init__(self, locale):127 self.locale = locale128 self.rules = []129 self.l10n_paths = []130 def cache(self, locale):131 if self._cache and self._cache.locale == locale:132 return self._cache133 self._cache = self.FilterCache(locale)134 for paths in self.paths:135 self._cache.l10n_paths.append(paths['l10n'].with_env({136 "locale": locale137 }))138 for rule in self.rules:139 cached_rule = rule.copy()140 cached_rule['path'] = rule['path'].with_env({141 "locale": locale142 })143 self._cache.rules.append(cached_rule)144 return self._cache145 def _filter(self, l10n_file, entity=None):146 actions = set(147 child._filter(l10n_file, entity=entity)148 for child in self.children)149 if 'error' in actions:150 # return early if we know we'll error151 return 'error'152 cached = self.cache(l10n_file.locale)153 if any(p.match(l10n_file.fullpath) for p in cached.l10n_paths):154 action = 'error'155 for rule in reversed(cached.rules):156 if not rule['path'].match(l10n_file.fullpath):157 continue158 if ('key' in rule) ^ (entity is not None):159 # key/file mismatch, not a matching rule160 continue161 if 'key' in rule and not rule['key'].match(entity):162 continue163 action = rule['action']164 break165 actions.add(action)166 if 'error' in actions:167 return 'error'168 if 'warning' in actions:169 return 'warning'170 if 'ignore' in actions:171 return 'ignore'172 def _compile_rule(self, rule):173 assert 'path' in rule174 if isinstance(rule['path'], list):175 for path in rule['path']:176 _rule = rule.copy()177 _rule['path'] = Matcher(path, env=self.environ, root=self.root)178 for __rule in self._compile_rule(_rule):179 yield __rule180 return181 if isinstance(rule['path'], six.string_types):182 rule['path'] = Matcher(183 rule['path'], env=self.environ, root=self.root184 )185 if 'key' not in rule:186 yield rule187 return188 if not isinstance(rule['key'], six.string_types):189 for key in rule['key']:190 _rule = rule.copy()191 _rule['key'] = key192 for __rule in self._compile_rule(_rule):193 yield __rule194 return195 rule = rule.copy()196 key = rule['key']197 if key.startswith('re:'):198 key = key[3:]199 else:200 key = re.escape(key) + '$'201 rule['key'] = re.compile(key)...

Full Screen

Full Screen

language.py

Source:language.py Github

copy

Full Screen

1import os2import string3class CompileRule(object):4 def __init__(self, compile_rule, exec_rule=None, time_limits=8):5 self._compile_rule = compile_rule6 self._exec_rule = './exec' if exec_rule is None else exec_rule7 self.time_limits = time_limits8 def compile(self, source):9 workspace = source.parent10 print('Compiling ...')11 print(source)12 com = string.Template(self._compile_rule).substitute(13 source=source.name)14 print('$', com)15 result = os.system('cd {} && {}'.format(workspace, com))16 return result17 def execute(self, source, testcase, output):18 workspace = source.parent19 com = string.Template(self._exec_rule).substitute(name=source.stem)20 result = os.system('cd {} && timeout -s 9 {} {} < {} > {}'.format(21 workspace, self.time_limits, com, testcase, output.name))22 return result23class CompileRuleP(CompileRule):24 def __init__(self, compiler, flags, time_limits=8):25 self._compile_rule = '{} -o exec ${source} {}'.format(26 compiler, flags, source='{source}')27 self._exec_rule = './exec'28 self.time_limits = time_limits29class ScriptRule(CompileRule):30 def __init__(self, exec_rule, time_limits=40):31 self._exec_rule = exec_rule32 self.time_limits = time_limits33 def compile(self, source):34 return 035rule_from_language = {36 'c': CompileRuleP(37 os.getenv('CC', 'gcc'),38 os.getenv('CCFLAGS', '-O2 -Wall')),39 'cpp': CompileRuleP(40 os.getenv('CXX', 'g++'),41 os.getenv('CXXFLAGS', '-O2 --std=c++14 -Wall')),42 'cs': CompileRule(43 'mcs -warn:0 -o+ -r:System.Numerics ${source}',44 'mono ${name}.exe', 16),45 'd': CompileRule(46 'dmd -m64 -w -O -release -inline ${source}',47 './${name}', 12),48 'go': ScriptRule(49 'go run ${name}.go', 20),50 'hs': CompileRuleP(51 os.getenv('GHC', 'ghc'),52 os.getenv('GHCFLAGS', '-O2'), 12),53 'java': CompileRule(54 'javac ${source}',55 'java -Xms512m ${name}', 16),56 'ml': CompileRuleP(57 os.getenv('OCAMLOPT', 'ocamlfind ocamlopt'),58 os.getenv('OCAMLOPTFLAGS',59 '-linkpkg -thread -package str,num,threads,batteries'), 12),60 'rs': CompileRuleP('rustc', '-O'),61 'py': ScriptRule('/usr/bin/env python ${name}.py'),62 'rb': ScriptRule('ruby ${name}.rb'),...

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:

YouTube

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

Run Gherkin-python 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?

Helpful

NotHelpful