How to use tag_policy method in localstack

Best Python code snippet using localstack_python

error_analysis.py

Source:error_analysis.py Github

copy

Full Screen

1from typing import Dict, List2import pandas as pd3import seaborn as sns4from matplotlib import pyplot as plt5from pandas import DataFrame6from sklearn.metrics import confusion_matrix7import numpy as np8from nlu.error_structure import MentionTypeError, MergeSplitError, FalseError, SimpleSpanError, NERCorrect, NERErrorComposite, \9 ComplicatedError10from nlu.ext_utils.confusion_matrix_pretty_print import pretty_plot_confusion_matrix11from nlu.parser import ConllParser12from nlu.utils import groupby, two_level_groupby, sort_two_level_group, add_total_column_row, fprint, make_autopct13cmap = sns.cubehelix_palette(as_cmap=True, light=.9)14def is_error(ems_pair):15 return isinstance(ems_pair.result, NERErrorComposite)16def is_correct(ems_pair):17 return isinstance(ems_pair.result, NERCorrect)18def is_span_error(ems_pair):19 return is_error(ems_pair) and isinstance(ems_pair.result.span_error, SimpleSpanError)20def is_only_span_error(ems_pair):21 return is_span_error(ems_pair) and not is_type_error(ems_pair) and not is_complicate_error(ems_pair)22def is_false_error(ems_pair):23 return is_error(ems_pair) and isinstance(ems_pair.result.false_error, FalseError)24def is_only_type_error(ems_pair):25 return is_type_error(ems_pair) and not is_span_error(ems_pair) and not is_complicate_error(ems_pair)26def is_fn(ems_pair):27 return is_false_error(ems_pair) and ems_pair.result.false_error.false_type == 'False Negative'28def is_fp(ems_pair):29 return is_false_error(ems_pair) and ems_pair.result.false_error.false_type == 'False Positive'30def is_ex(ems_pair):31 return is_span_error(ems_pair) and ems_pair.result.span_error.span_type == 'Expansion'32def is_re(ems_pair):33 return is_ex(ems_pair) and ems_pair.result.span_error.direction == 'Right'34def is_le(ems_pair):35 return is_ex(ems_pair) and ems_pair.result.span_error.direction == 'Left'36def is_rle(ems_pair):37 return is_ex(ems_pair) and ems_pair.result.span_error.direction == 'Right Left'38def is_dim(ems_pair):39 return is_span_error(ems_pair) and ems_pair.result.span_error.span_type == 'Diminished'40def is_rd(ems_pair):41 return is_dim(ems_pair) and ems_pair.result.span_error.direction == 'Right'42def is_ld(ems_pair):43 return is_dim(ems_pair) and ems_pair.result.span_error.direction == 'Left'44def is_rld(ems_pair):45 return is_dim(ems_pair) and ems_pair.result.span_error.direction == 'Right Left'46def is_cross(ems_pair):47 return is_span_error(ems_pair) and 'Crossed' in ems_pair.result.span_error.type48def is_rc(ems_pair):49 return is_cross(ems_pair) and ems_pair.result.span_error.direction == 'Right'50def is_lc(ems_pair):51 return is_cross(ems_pair) and ems_pair.result.span_error.direction == 'Left'52def is_merge_split(ems_pair):53 return is_error(ems_pair) and isinstance(ems_pair.result.span_error, MergeSplitError)54def is_merge(ems_pair):55 return is_merge_split(ems_pair) and ems_pair.result.span_error.type == 'Spans Merged'56def is_split(ems_pair):57 return is_merge_split(ems_pair) and ems_pair.result.span_error.type == 'Span Split'58def is_type_error(ems_pair):59 return is_error(ems_pair) and isinstance(ems_pair.result.type_error, MentionTypeError)60def is_complicate_error(ems_pair):61 return is_error(ems_pair) and isinstance(ems_pair.result.span_error, ComplicatedError)62def filtered_results(parser, is_funcs, boolean=all) -> List[NERErrorComposite]:63 """64 :param parser: `ConllParser` class65 :param is_funcs: filter functions that return boolean value66 :param boolean: `any` or `all`67 :return: List of `NERErrorComposite`68 """69 errors = []70 for doc in parser.docs:71 for sent in doc:72 if sent.ems_pairs:73 for ems_pair in sent.ems_pairs:74 # overloading75 try: # funcs as a list76 if boolean([is_func(ems_pair) for is_func in is_funcs]):77 errors.append(ems_pair.result)78 except TypeError: # funcs as only a function79 if is_funcs(ems_pair):80 errors.append(ems_pair.result)81 except NameError:82 raise NameError('is_funcs is not one of the predefined result types')83 return errors84def get_false_errors_category(parser):85 _is_types = {'False Positive': is_fp, 'False Negative': is_fn, 'All False Errors': is_false_error}86 return {name: filtered_results(parser, is_func) for name, is_func in _is_types.items()}87def get_all_false_errors(parser):88 return filtered_results(parser, is_false_error)89def get_false_positives(parser):90 return filtered_results(parser, is_fp)91def get_false_negatives(parser):92 return filtered_results(parser, is_fn)93def get_span_errors_category(parser):94 _is_types = {'Right Expansion': is_re, 'Left Expansion': is_le, 'Right Left Expansion': is_rle,95 'Right Diminished': is_rd, 'Left Diminished': is_ld, 'Right Left Diminished': is_rld,96 'Right Crossed': is_rc, 'Left Crossed': is_lc,97 'Spans Merged': is_merge, 'Span Split': is_split,98 'Complicate': is_complicate_error,99 'All Span Errors': is_span_error}100 return {name: filtered_results(parser, is_func) for name, is_func in _is_types.items()}101def get_all_span_errors(parser):102 return filtered_results(parser, is_span_error)103def get_only_span_errors(parser):104 return filtered_results(parser, is_only_span_error)105def get_all_type_errors(parser):106 return filtered_results(parser, is_type_error)107def get_only_type_errors(parser):108 return filtered_results(parser, is_only_type_error)109def get_span_and_type_composite_errors(parser):110 return filtered_results(parser, [is_type_error, is_span_error])111def get_only_span_and_type_composite_errors(parser):112 return filtered_results(parser, [is_type_error, is_span_error, lambda e: not is_complicate_error(e)])113def get_complicate_errors(parser):114 return filtered_results(parser, is_complicate_error)115def print_type_errors(parser):116 all_type_errors = get_all_type_errors(parser)117 error_table = {}118 for error in all_type_errors:119 type = str(error.type_error)120 if type not in error_table.keys():121 error_table[type] = 1122 else:123 error_table[type] += 1124 for key in sorted(error_table.keys()):125 print(key + ": " + str(error_table[key]))126def print_list_len_in_dict(dict_: Dict):127 for name, list_ in dict_.items():128 print('{}: {}'.format(name, len(list_)))129class NERErrorAnalyzer:130 """131 input: DocumentsWithErrorAnn132 """133 @classmethod134 def print_report(cls):135 pass136 @classmethod137 def save_report(cls, parser, tag_policy='conll'):138 fprint('Error Analysis')139 # print140 fnames = ['error_pie.png', 'false_error_heatmap.png', 'span_error_heatmap.png', 'confusion_matrix.png']141 cls.print_error_pie(parser, fnames[0])142 cls.print_false_error_heatmap(parser, tag_policy=tag_policy, save_file=fnames[1])143 cls.print_span_error_heatmap(parser, tag_policy=tag_policy, save_file=fnames[2])144 cls.pprint_ner_confusion_matrix(parser, tag_policy=tag_policy, save_file=fnames[3])145 @staticmethod146 def get_span_error_category_df(parser, transpose=True, tag_policy='conll'):147 errs = get_only_span_errors(parser)148 key1 = lambda err: err.span_error.type149 key2 = lambda err: err.ptypes[0]150 g = two_level_groupby(errs, key1, key2, count=True)151 df = DataFrame(g)152 if transpose:153 df = df.T154 span_etype_order = ['Right Expansion', 'Left Expansion', 'Right Left Expansion',155 'Right Diminished', 'Left Diminished', 'Right Left Diminished',156 'Right Crossed', 'Left Crossed',157 'Spans Merged', 'Span Split',158 'Complicate']159 if tag_policy == 'wnut':160 etypes = ['person', 'location', 'corporation', 'group', 'creative-work', 'product']161 elif tag_policy == 'conll':162 etypes = ['PER', 'LOC', 'ORG', 'MISC']163 df = sort_two_level_group(df, span_etype_order, etypes)164 add_total_column_row(df)165 return df166 @staticmethod167 def get_false_error_category_df(parser, transpose=True, tag_policy='conll'):168 errs = filtered_results(parser, is_false_error)169 key1 = lambda e: e.false_error.false_type170 key2 = lambda err: err.false_error.em_type171 g = two_level_groupby(errs, key1, key2, count=True)172 df = DataFrame(g)173 if transpose:174 df = df.T175 if tag_policy == 'wnut':176 etypes = ['person', 'location', 'corporation', 'group', 'creative-work', 'product']177 elif tag_policy == 'conll':178 etypes = ['PER', 'LOC', 'ORG', 'MISC']179 df = sort_two_level_group(df, ['False Positive', 'False Negative'], etypes)180 add_total_column_row(df)181 return df182 @staticmethod183 def print_error_pie(parser, save_file=None):184 only_span_errors = get_only_span_errors(parser)185 only_type_errors = get_only_type_errors(parser)186 only_span_and_type_composite_errors = get_only_span_and_type_composite_errors(parser)187 false_negatives = get_false_negatives(parser)188 false_positives = get_false_positives(parser)189 complicate_erorrs = get_complicate_errors(parser)190 # Pie chart191 labels = ['Only Span', 'Only Type', 'Span and Type', 'Complicate Errors', 'False Positive', 'False Negative']192 sizes = [len(only_span_errors), len(only_type_errors), len(only_span_and_type_composite_errors),193 len(complicate_erorrs),194 len(false_positives), len(false_negatives)]195 # colors196 # colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']197 fig1, ax1 = plt.subplots()198 ax1.pie(sizes, labels=labels, autopct=make_autopct(sizes), startangle=90)199 # draw circle200 centre_circle = plt.Circle((0, 0), 0.70, fc='white')201 fig = plt.gcf()202 fig.gca().add_artist(centre_circle)203 # Equal aspect ratio ensures that pie is drawn as a circle204 ax1.axis('equal')205 plt.tight_layout()206 if save_file is not None:207 plt.savefig(save_file)208 else:209 plt.show()210 @staticmethod211 def print_span_error_pie(): #TODO212 pass213 @staticmethod214 def print_composite_errors(parser):215 # get complicated error216 com_err_array = get_complicate_errors(parser)217 print(com_err_array)218 @staticmethod219 def print_false_errors(parser, tag_policy='conll'): #TODO: duplicated?220 if tag_policy == 'wnut':221 etypes = ['person', 'location', 'corporation', 'group', 'creative-work', 'product']222 elif tag_policy == 'conll':223 etypes = ['PER', 'LOC', 'ORG', 'MISC']224 # group fp/fn by entity type225 fns = get_false_negatives(parser)226 fps = get_false_positives(parser)227 key = lambda err: err.false_error.em_type228 fn_groups = groupby(fns, key)229 fp_groups = groupby(fps, key)230 order = {key: i for i, key in enumerate(etypes)}231 for fp_type, fps in sorted(fp_groups.items(), key=lambda x: order[x[0]]):232 print('{} - {}'.format(fp_type, len(fps)))233 for fn_type, fns in sorted(fn_groups.items(), key=lambda x: order[x[0]]):234 print('{} - {}'.format(fn_type, len(fns)))235 @staticmethod236 def print_span_error_heatmap(parser, tag_policy='conll', save_file=None, **kwargs):237 err_df = NERErrorAnalyzer.get_span_error_category_df(parser, tag_policy=tag_policy)238 plt.figure()239 hm = sns.heatmap(err_df, annot=True, linewidth=1, fmt='.0f', cmap=cmap, **kwargs)240 hm.set_facecolor(np.append(cmap.colors[0][:-1], 0.5))241 hm.set_xticklabels(hm.get_xticklabels(), rotation=45)242 if save_file is not None:243 plt.savefig(save_file, bbox_inches='tight')244 else:245 plt.show()246 @staticmethod247 def print_false_error_heatmap(parser, save_file=None, tag_policy='conll', **kwargs):248 err_df = NERErrorAnalyzer.get_false_error_category_df(parser, tag_policy=tag_policy)249 plt.figure()250 hm = sns.heatmap(err_df, annot=True, linewidth=1, fmt='.0f', cmap=cmap, **kwargs)251 hm.set_facecolor(np.append(cmap.colors[0][:-1], 0.5))252 hm.set_xticklabels(hm.get_xticklabels(), rotation=45)253 hm.set_yticklabels(hm.get_yticklabels(), rotation=0)254 if save_file is not None:255 plt.savefig(save_file, bbox_inches='tight')256 else:257 plt.show()258 @classmethod259 def get_confusion_matrix_df(cls, parser: ConllParser, tag_policy='conll') -> DataFrame:260 wnut_types = ["person", "location", "corporation", "group", "creative-work", "product"]261 conll_types = ["PER", "LOC", "ORG", "MISC"]262 labels = wnut_types if tag_policy == 'wnut' else conll_types263 cm = cls.get_confusion_matrix(parser, tag_policy)264 return pd.DataFrame(cm, index=labels, columns=labels)265 @staticmethod266 def get_confusion_matrix(parser: ConllParser, tag_policy='conll') -> List[List[int]]:267 y_true = []268 y_pred = []269 for doc in parser.docs:270 for sentence in doc:271 if sentence.ems_pairs:272 for ems_pair in sentence.ems_pairs:273 if len(ems_pair.result.gtypes) == 1 and len(ems_pair.result.ptypes) == 1:274 y_true.append(ems_pair.result.gtypes[0])275 y_pred.append(ems_pair.result.ptypes[0])276 wnut_types = ["person", "location", "corporation", "group", "creative-work", "product"]277 conll_types = ["PER", "LOC", "ORG", "MISC"]278 labels = wnut_types if tag_policy == 'wnut' else conll_types279 return confusion_matrix(y_true, y_pred, labels=labels)280 @classmethod281 def print_ner_confusion_matrix(cls, parser, tag_policy='conll', **kwargs):282 cm = cls.get_confusion_matrix(parser, tag_policy=tag_policy)283 cls.print_confusion_matrix(cm, tag_policy=tag_policy, **kwargs)284 @classmethod285 def pprint_ner_confusion_matrix(cls, parser, tag_policy='conll', **kwargs):286 cm = cls.get_confusion_matrix(parser, tag_policy=tag_policy)287 cls.pprint_confusion_matrix(cm, tag_policy=tag_policy, **kwargs)288 @staticmethod289 def print_confusion_matrix(cm: List[List[int]], tag_policy='conll'):290 fig = plt.figure()291 ax = fig.add_subplot(111)292 cax = ax.matshow(cm)293 wnut_types = ["person", "location", "corporation", "group", "creative-work", "product"]294 conll_types = ["PER", "LOC", "ORG", "MISC"]295 labels = wnut_types if tag_policy == 'wnut' else conll_types296 plt.title('Confusion matrix of the classifier')297 fig.colorbar(cax)298 ax.set_xticklabels([''] + labels)299 ax.set_yticklabels([''] + labels)300 ax.xaxis.tick_bottom()301 plt.xticks(rotation=45, ha='right', rotation_mode='anchor')302 plt.xlabel('Predicted')303 plt.ylabel('True')304 # Loop over data dimensions and create text annotations.305 for i in range(len(labels)):306 for j in range(len(labels)):307 ax.text(j, i, cm[i, j], ha="center", va="center", color="w")308 plt.show()309 @staticmethod310 def pprint_confusion_matrix(cm: List[List[int]], tag_policy='conll', **kwargs):311 wnut_types = ["person", "location", "corporation", "group", "creative-work", "product"]312 conll_types = ["PER", "LOC", "ORG", "MISC"]313 labels = wnut_types if tag_policy == 'wnut' else conll_types314 df_cm = pd.DataFrame(cm, index=labels, columns=labels)315 pretty_plot_confusion_matrix(df_cm, pred_val_axis='x', show_null_values=0, **kwargs)316if __name__ == '__main__':...

Full Screen

Full Screen

avalens.py

Source:avalens.py Github

copy

Full Screen

1import os2import numpy as np3import pandas as pd4from datetime import datetime5from avatarpy import Avatar6class AvaLens:7 def __init__(self, id_policy='filepath', tag_policy='provide'):8 r"""Lens for group analysis of avatars9 :param id_policy: {'filepath'(default))|'incremental'|'provide'|'basename'}10 :param tag_policy: {'provide'(default))|'dirname'}11 """12 assert id_policy in ['filepath','incremental','provide','basename'], 'wrong argument for id_policy'13 assert tag_policy in ['provide','dirname'], 'wrong argument for id_policy'14 self._avatars = []15 self.id_policy = id_policy16 self.tag_policy = tag_policy17 def __repr__(self):18 return f'AvaLens instance containing avatars: {self.avatars}'19 @property20 def avatars(self):21 """User Added avatars"""22 return self._avatars23 def add_file(self, csv_path, ID=None, tags={}, verbose=1):24 if self.id_policy == 'filepath':25 ID = csv_path26 elif self.id_policy == 'incremental':27 ID = len(self.avatars)28 elif self.id_policy == 'provide':29 assert ID is not None, 'User should provide ID or select id_policy among ["filpath", "incremental", "basname"]'30 ID = ID31 elif self.id_policy == 'basename':32 ID = os.path.splitext(os.path.basename(csv_path))[0]33 if self.tag_policy == 'dirname':34 tags = dict(tag=os.path.basename(os.path.dirname(csv_path)))35 elif self.tag_policy == 'provide':36 tags = tags37 avatar = Avatar(csv_path=csv_path, ID=ID, tags=tags)38 self.avatars.append(avatar)39 if verbose==1:40 print(f'[{datetime.now()}] Added new Avatar(csv_path={csv_path}, ID={ID}, tags={tags})', end='\r')41 if verbose==2:42 print(f'[{datetime.now()}] Added new Avatar(csv_path={csv_path}, ID={ID}, tags={tags})')43 return self44 def add_folder(self, root, ID=None, tags={}, verbose=1):45 for path, subdirs, files in os.walk(root):46 for name in files:47 if name.lower().endswith('.csv'):48 csv_path = os.path.join(path, name)49 self.add_file(csv_path, ID, tags, verbose=verbose)50 return self51 def describe(self, include=['corr', 'stat'], func_kws={}, indices=None, assign_ID=True, assign_tags=True):52 describes = []53 for avatar in self.avatars:54 if func_kws:55 for name, func in func_kws.items():56 avatar.annotation.add(by=func, name=name)57 indices = avatar.annotation.get_indices(name)58 desc = avatar.describe(indices=indices, include=include, assign_ID=assign_ID, assign_tags=assign_tags).assign(event=name)59 describes.append(desc)60 else:61 desc = avatar.describe(indices=indices, include=include, assign_ID=assign_ID, assign_tags=assign_tags)62 describes.append(desc)63 return pd.concat(describes).reset_index(drop=True)64 @property65 def search_event(self):66 return SearchEvent(parent=self)67class SearchEvent:68 def __init__(self, parent=None):69 self.__parent = parent70 self.__events = []71 self.__event_name = ''72 def __call__(self, func, name, length=20, verbos=1):73 """Search event by given function.74 """75 assert callable(func), 'func should be callable'76 self.__events = []77 self.__event_name = name78 for avatar in self.__parent.avatars:79 boolean_series = func(avatar)80 assert isinstance(boolean_series, pd.Series), 'func should return pd.Series of boolean with index'81 assert boolean_series.dtype == bool, 'dtype of boolean_series should be bool'82 events = self.split_boolean_series(boolean_series)83 filtered_events = []84 for arr in events:85 if len(arr)<length:86 continue87 else:88 while len(arr)>=length:89 filtered_events.append(arr[:length])90 arr = arr[length:]91 if verbos==1:92 print(f'Total {len(filtered_events)} event was detected', end='\r')93 if verbos==2:94 print(f'Total {len(filtered_events)} event was detected')95 self.__events.append(filtered_events)96 return self97 @staticmethod98 def split_boolean_series(boolean_series):99 indices, boolean = boolean_series.index, boolean_series.values100 pos = np.nonzero(boolean[1:] != boolean[:-1])[0] + 1101 arrs = np.split(indices, pos)102 arrs = arrs[0::2] if boolean[0] else arrs[1::2]103 return arrs104 def describe(self, include=['corr', 'stat'], assign_ID=True, assign_tags=True, assign_event_name=True):105 describes = []106 for avatar, events in zip(self.__parent.avatars, self.__events) :107 for indices in events:108 desc = avatar.describe(indices=indices, include=include, assign_ID=assign_ID, assign_tags=assign_tags)109 describes.append(desc)110 df = pd.concat(describes).reset_index(drop=True)111 if assign_event_name:112 df = df.assign(event=self.__event_name)113 return df114 #TODO...

Full Screen

Full Screen

index.py

Source:index.py Github

copy

Full Screen

1import json2import os3TAG_POLICY_DIR = "tag-policies"4SCP_DIR = "service-control-policies"5RESOURCE_TO_ACTION_MAP = "resource-syntax-map.json"6def valid_statement(statement):7 if "Condition" not in statement:8 return False9 elif "Action" not in statement or len(statement["Action"]) == 0:10 return False11 elif "Resource" not in statement or len(statement["Resource"]) == 0:12 return False13 return True14def validate_and_optimize_statement(s):15 if not valid_statement(s):16 return False17 for attr in ["Action", "Resource"]:18 if isinstance(s[attr], list) and len(s[attr]) == 1:19 s[attr] = s[attr][0]20 elif isinstance(s[attr], list):21 s[attr] = s[attr] = list(dict.fromkeys(s[attr]))22 return s23def inject_tag_to_condition_template(tag, condition):24 new_condition = {}25 for operator in condition:26 new_condition[operator] = {}27 for key, val in condition[operator].items():28 new_key = key.replace("<tag>", tag)29 new_condition[operator][new_key] = val.replace("<tag>", tag)30 return new_condition31def tag_and_resource_to_statement(sid, tag_name, resource_name, resource):32 print(f"--- Generating SCP statement for {tag_name} / {resource_name}")33 statement = {34 "Sid": sid,35 "Effect": "Deny",36 }37 if "Condition" in resource and len(resource["Condition"].keys()) > 0:38 statement["Condition"] = inject_tag_to_condition_template(tag_name, resource["Condition"])39 else:40 statement["Condition"] = {41 "StringNotLike": {42 f"aws:RequestTag/{tag_name}": "?*",43 }44 }45 for attr in ["Action", "Resource"]:46 if attr in resource:47 statement[attr] = resource[attr]48 print(49 f"||| Optimizing generated statement for {tag_name} / {resource_name}")50 return validate_and_optimize_statement(statement)51def convert_tag_policy_to_scp_statements(tag_policy):52 print(f"--- Reading IAM / Tag Policy Resource Map")53 try:54 with open(os.path.join(".", RESOURCE_TO_ACTION_MAP)) as json_file:55 resource_map = json.load(json_file)56 except Exception as e:57 print(58 f"!!! Error reading IAM Action to Resources map: {RESOURCE_TO_ACTION_MAP}")59 print(e)60 quit()61 print(f"--- Reading enforced resources")62 statements = []63 inheritance_operators = ["@@assign", "@@append"]64 itr = 065 for tag_name in tag_policy["tags"]:66 if "enforced_for" in tag_policy["tags"][tag_name]:67 print(f"||| Enforced resources for {tag_name}:")68 for io in inheritance_operators:69 if io in tag_policy["tags"][tag_name]["enforced_for"]:70 for resource_name in tag_policy["tags"][tag_name]["enforced_for"][io]:71 # Tag / Resource match for enforcement72 if resource_name in resource_map.keys():73 itr += 174 s = tag_and_resource_to_statement(75 f"tag{itr}", tag_name, resource_name, resource_map[resource_name])76 if s:77 statements.append(s)78 # Handle wildcard resources in resource map79 elif resource_name.endswith(':*'):80 wildcard_resources = [r for r in resource_map.keys(81 ) if r.startswith(resource_name.split(':')[0])]82 for wildcard_resource_name in wildcard_resources:83 s = tag_and_resource_to_statement(84 f"tag{itr}", tag_name, wildcard_resource_name, resource_map[wildcard_resource_name])85 if s:86 statements.append(s)87 return statements88def create_statements_for_tag(tag_name, tag_statement, resource_map):89 statements = []90 return statements91def convert_tag_policy_to_scp(filename, tag_policy):92 statements = convert_tag_policy_to_scp_statements(tag_policy)93 print(f"--- Converted {filename} to SCP")94 return {"Version": "2012-10-17", "Statement": statements}95def write_scp_to_disk(filename, scp):96 print(f"--- Writing SCP: {filename}")97 with open(os.path.join(SCP_DIR, filename), "w") as scp_file:98 json.dump(scp, scp_file, indent=2)99def main():100 print("--- Reading tag policies")101 tag_policy_files = [f for f in os.listdir(102 TAG_POLICY_DIR) if f.endswith(".json")]103 for filename in tag_policy_files:104 print(f"||| Reading tag policy: {filename}")105 with open(os.path.join(TAG_POLICY_DIR, filename)) as json_file:106 tag_policy = json.load(json_file)107 scp = convert_tag_policy_to_scp(filename, tag_policy)108 write_scp_to_disk(filename, scp)109if __name__ == "__main__":...

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 localstack 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