Best Python code snippet using localstack_python
error_analysis.py
Source:error_analysis.py  
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__':...avalens.py
Source:avalens.py  
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...index.py
Source:index.py  
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__":...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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
