Best Python code snippet using localstack_python
__init__.py
Source:__init__.py  
1import collections2import configargparse3from flask import Flask, Response, send_from_directory4from flask_cors import CORS5import jinja26import json7import os8import pandas as pd9import pkg_resources10import pkgutil11import re12import requests13import shutil14import sys15from flipbook.utils import get_relative_directory_to_data_files_list, get_relative_directory_to_metadata, \16    is_excel_table, get_data_page_url, METADATA_JSON_FILE_TYPE, CONTENT_HTML_FILE_TYPE17PATH_COLUMN = 'Path'18WEBSITE_DIR = "flipbook_html"19MAIN_PAGE_HEADER_FILENAME = "flipbook_main_page_header.html"20DATA_PAGE_HEADER_FILENAME = "flipbook_data_page_header.html"21p = configargparse.ArgumentParser(22    formatter_class=configargparse.DefaultsFormatter,23    add_config_file_help=True,24    add_env_var_help=True,25    config_file_parser_class=configargparse.YAMLConfigFileParser,26    default_config_files=["~/.flipbook_config"],27    args_for_writing_out_config_file=["--save-current-options-to-config-file"],28)29p.add_argument("-i", "--include", action="append", help="Only include files whose path contains this keyword")30p.add_argument("-x", "--exclude", action="append", help="Skip files whose path contains this keyword. If both "31               " --include and --exclude are specified, --exclude takes precedence over --include", default=[WEBSITE_DIR])32p.add_argument("-t", "--form-responses-table", default="flipbook_form_responses.tsv",33               help="The .tsv or .xls path where form responses are saved. If the file already exists,"34                    "it will be parsed for previous form responses and then updated as the user fills in the form(s)."35                    "If the file doesn't exist, it will be created after the 1st form response.")36p.add_argument("-m", "--metadata-table", default="flipbook_metadata.tsv",37               help="The .tsv or .xls path containing metadata to show on data pages. There are two optional ways "38                    "to add metadata to the data pages. The 1st way is to put a 'flipbook_metadata.json' file "39                    "inside a directory that contains images or data files (in which case any key-value pairs from "40                    "the json file will be shown at the top of the data page that displays those images). "41                    "The other way is to specify this table, which needs to have a 'Path' column with relative "42                    "directory paths that contain images and data files. The data page corresponding to those "43                    "directory paths will then display values from the other columns in this table. If both this table "44                    "and 'flipbook_metadata.json' files are found, the values from this table will override values in "45                    "the 'flipbook_metadata.json' files.")46p.add_argument("-j", "--form-schema-json", help="Path of .json file containing a custom form schema. For the expected format "47               "see https://github.com/broadinstitute/flipbook/tree/main/form_schema_examples")48p.add_argument("-s", "--sort-by", action="append", help="Order pages by metadata column(s)")49p.add_argument("-r", "--reverse-sort", action="store_true", help="Reverses the sort order")50p.add_argument("--hide-metadata-on-home-page", action="store_true", help="Don't show metadata columns in the "51               "home page table")52p.add_argument("--add-metadata-to-form-responses-table", action="store_true", help="Also write metadata columns to the "53               "form responses table when saving users' form responses")54p.add_argument("--generate-static-website", action="store_true", help="Instead of starting a web server, this option "55               "causes FlipBook to write out a set of static html pages for all the images it finds and then exit. "56               "The generated pages can then be viewed in a browser, uploaded to some other web server (such as "57               "GitHub Pages, embedded in another existing website, etc. The generated web pages are identical to "58               "the standard FlipBook user interface except they don't contain the forms for entering responses about "59               "each image - and so just allow flipping through the images.")60#p.add_argument("-c", "--config-file", help="Path of yaml config file", env_var="FLIPBOOK_CONFIG_FILE")61p.add_argument("-v", "--verbose", action='count', default=0, help="Print more info")62p.add_argument("--host", default="127.0.0.1", env_var="HOST", help="Listen for connections on this hostname or IP")63p.add_argument("-p", "--port", default="8080", env_var="PORT", type=int, help="Listen for connections on this port")64p.add_argument("--dev-mode", action="store_true", env_var="DEV", help="Run server in developer mode so it reloads "65               "html templates and source code if they're changed")66p.add_argument("directory", default=".", nargs="?", help="Top-level directory to search for images and data files")67args = p.parse_args()68if args.verbose > 1:69    p.print_values()70if not os.path.isdir(args.directory):71    p.error(f"{args.directory} directory not found")72args.directory = os.path.realpath(args.directory)73def parse_table(path):74    if not os.path.isfile(path):75        raise ValueError(f"{path} not found")76    try:77        if is_excel_table(path):78            df = pd.read_excel(path, engine="openpyxl")79        else:80            df = pd.read_table(path)81    except Exception as e:82        raise ValueError(f"Unable to parse {path}: {e}")83        # validate table contents84    if PATH_COLUMN not in df.columns:85        raise ValueError(f"{path} must have a column named '{PATH_COLUMN}'")86    df.set_index(PATH_COLUMN, inplace=True, drop=False)87    df = df.fillna('')88    print(f"Parsed {len(df)} rows from {path}")89    return df90# search directory for images and data files91RELATIVE_DIRECTORY_TO_DATA_FILES_LIST = get_relative_directory_to_data_files_list(92    args.directory,93    args.include,94    args.exclude,95    verbose=args.verbose)96if not RELATIVE_DIRECTORY_TO_DATA_FILES_LIST:97    p.error(f"No images or data files found in {args.directory}")98# parse metadata from flipbook_metadata.json files99METADATA_COLUMNS, RELATIVE_DIRECTORY_TO_METADATA = get_relative_directory_to_metadata(100    args.directory,101    RELATIVE_DIRECTORY_TO_DATA_FILES_LIST,102    verbose=args.verbose)103# parse metadata from the metadata_table if specified104if args.metadata_table and os.path.isfile(args.metadata_table):105    #args.metadata_table = os.path.join(args.directory, args.metadata_table)106    try:107        df = parse_table(args.metadata_table)108    except ValueError as e:109        p.error(str(e))110    for relative_directory, row in df.iterrows():111        metadata_dict = {k: v for k, v in row.to_dict().items() if k != PATH_COLUMN}112        if relative_directory not in RELATIVE_DIRECTORY_TO_METADATA:113            RELATIVE_DIRECTORY_TO_METADATA[relative_directory] = {}114            if args.verbose:115                print(f"Setting new metadata row for {relative_directory} to {metadata_dict}")116        else:117            if args.verbose:118                print(f"Updating existing metadata row for {relative_directory} to {metadata_dict}")119        RELATIVE_DIRECTORY_TO_METADATA[relative_directory].update(metadata_dict)120        for key in metadata_dict:121            if key not in METADATA_COLUMNS:122                METADATA_COLUMNS.append(key)123# define input form fields to show on each data page124FORM_SCHEMA = [125    {126        "type": "radio",127        "columnName": "Verdict",128        "choices": [129            {"value": "normal", "label": "Normal"},130            {"value": "intermediate", "label": "Intermediate"},131            {"value": "full-expansion", "label": "Full Expansion"},132            {"value": "double-expansion", "label": "Double Expansion"},133        ]134    },135    {136        "type": "radio",137        "columnName": "Confidence",138        "inputLabel": "Confidence",139        "choices": [140            {"value": "borderline", "label": "Borderline"},141            {"value": "confident", "label": "Confident"},142        ]143    },144    {145        "type": "text",146        "columnName": "Notes",147        "size": 60148    }149]150if args.generate_static_website:151    FORM_SCHEMA = {}152if args.form_schema_json:153    print(f"Loading form schema from {args.form_schema_json}")154    try:155        if os.path.isfile(args.form_schema_json):156            with open(args.form_schema_json, "rt") as f:157                FORM_SCHEMA = json.load(f)158        elif args.form_schema_json.startswith("http"):159            # Convert https://github.com/broadinstitute/flipbook/blob/main/flipbook/__init__.py to the raw url:160            # https://raw.githubusercontent.com/broadinstitute/flipbook/main/flipbook/__init__.py161            github_match = re.search("//github.com/(.*)/blob/(.*)", args.form_schema_json)162            if github_match:163                part1 = github_match.group(1)164                part2 = github_match.group(2)165                github_raw_file_url = f"https://raw.githubusercontent.com/{part1}/{part2}"166                if args.verbose:167                    print(f"Converting form schema url {args.form_schema_json} to {github_raw_file_url}")168                args.form_schema_json = github_raw_file_url169            r = requests.get(url=args.form_schema_json)170            FORM_SCHEMA = r.json()171    except Exception as e:172        p.error(f"Couldn't parse {args.form_schema_json}: {e}")173FORM_SCHEMA_COLUMNS = [r['columnName'] for r in FORM_SCHEMA]174# validate FORM_SCHEMA and determine keyboard shortcuts175FORM_RADIO_BUTTON_KEYBOARD_SHORTCUTS = {}176for i, form_schema_row in enumerate(FORM_SCHEMA):177    if not isinstance(form_schema_row, dict):178        raise ValueError(f"FORM_SCHEMA row {i} must be a dictionary")179    missing_keys = {'type', 'columnName'} - set(form_schema_row.keys())180    if missing_keys:181        raise ValueError(f"FORM_SCHEMA row {i} is missing values for these keys: {', '.join(missing_keys)}")182    if form_schema_row['type'] not in ('text', 'radio'):183        raise ValueError(f"FORM_SCHEMA row {i} has unexpected 'type' value: {form_schema_row['type']}")184    if 'name' not in form_schema_row:185        form_schema_row['name'] = form_schema_row['columnName'].lower()186    form_schema_row['name'] = re.sub("[^a-zA-Z0-9_]", "_", form_schema_row['name'])187    if 'inputLabel' not in form_schema_row:188        form_schema_row['inputLabel'] = form_schema_row['columnName']189    if form_schema_row['type'] == 'radio':190        if 'choices' not in form_schema_row or not isinstance(form_schema_row['choices'], list):191            raise ValueError(f"FORM_SCHEMA row {i} is missing a 'choices' list")192        for choice in form_schema_row['choices']:193            if not isinstance(choice, dict):194                raise ValueError(f"FORM_SCHEMA row {i} must 'choices' list must contain dictionaries")195            missing_keys = {'value', 'label'} - set(choice.keys())196            if missing_keys:197                raise ValueError(f"FORM_SCHEMA row {i} 'choices' list has entries where these keys are missing: {', '.join(missing_keys)}")198            label_without_html = re.sub("<[^<]+?>", "", choice['label']).strip()199            first_letter = (label_without_html or choice["value"])[0]200            FORM_RADIO_BUTTON_KEYBOARD_SHORTCUTS[first_letter] = choice['value']201            print(f"Form Keyboard Shortcut: {first_letter} => {choice['label']}")202# parse or create FORM_RESPONSES dict for storing user responses203FORM_RESPONSES = {}204# if a form_responses_table is provided with additional columns which are not in the current FORM_SCHEMA (eg. if the205# form schema changes, save this info here so it's not lost when the table is updated after new form responses.206EXTRA_COLUMNS_IN_FORM_RESPONSES_TABLE = []207EXTRA_DATA_IN_FORM_RESPONSES_TABLE = {}208if FORM_SCHEMA:209    args.form_responses_table = os.path.join(args.directory, args.form_responses_table)210    args.form_responses_table_is_excel = is_excel_table(args.form_responses_table)211    if os.path.isfile(args.form_responses_table):212        try:213            df = parse_table(args.form_responses_table)214        except ValueError as e:215            p.error(str(e))216        EXTRA_COLUMNS_IN_FORM_RESPONSES_TABLE = [c for c in df.columns if c not in FORM_SCHEMA_COLUMNS and c not in METADATA_COLUMNS and c != PATH_COLUMN]217    else:218        # make sure the table can be written out later219        if not os.access(os.path.dirname(args.form_responses_table), os.W_OK):220            p.error(f"Unable to create {args.form_responses_table}")221        # create empty table in memory222        df = pd.DataFrame(columns=[PATH_COLUMN] + FORM_SCHEMA_COLUMNS)223        df.set_index(PATH_COLUMN, inplace=True, drop=False)224    # store form responses in memory.225    # NOTE: This is not thread-safe and assumes a single-threaded server. For multi-threaded226    # or multi-process servers like gunicorn, this will need to be replaced with a sqlite or redis backend.227    FORM_RESPONSES = collections.OrderedDict()228    for relative_directory, row in df.iterrows():229        row_as_dict = row.to_dict()230        FORM_RESPONSES[relative_directory] = {k: v for k, v in row_as_dict.items() if k in FORM_SCHEMA_COLUMNS}231        EXTRA_DATA_IN_FORM_RESPONSES_TABLE[relative_directory] = {k: v for k, v in row_as_dict.items() if k not in FORM_SCHEMA_COLUMNS and k != PATH_COLUMN}232    print(f"Will save form responses to {args.form_responses_table}  (columns: {', '.join(FORM_SCHEMA_COLUMNS + EXTRA_COLUMNS_IN_FORM_RESPONSES_TABLE)})")233if args.sort_by:234    valid_columns = set([PATH_COLUMN])235    valid_columns.update(FORM_SCHEMA_COLUMNS)236    if METADATA_COLUMNS:237        valid_columns.update(METADATA_COLUMNS)238    invalid_values = ", ".join([f"'{s}'" for s in args.sort_by if s not in valid_columns])239    if invalid_values:240        p.error(f"{invalid_values} column(s) not found in metadata. --sort-by value should be one of: " +241                ", ".join(valid_columns))242    print(f"Sorting {len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)} pages by {', '.join(args.sort_by)}")243    def get_sort_key(i):244        relative_dir = i[0]245        sort_key = []246        for s in args.sort_by:247            if s == PATH_COLUMN:248                sort_key.append(relative_dir)249                continue250            form_value = FORM_RESPONSES.get(relative_dir, {}).get(s)251            if form_value is not None:252                sort_key.append(str(form_value))253                continue254            metadata_value = RELATIVE_DIRECTORY_TO_METADATA.get(relative_dir, {}).get(s)255            if metadata_value is not None:256                sort_key.append(str(metadata_value))257                continue258        return tuple(sort_key)259    RELATIVE_DIRECTORY_TO_DATA_FILES_LIST = sorted(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST, key=get_sort_key, reverse=args.reverse_sort)260def send_file(path):261    print(f"Sending {args.directory} {path}")262    if path.startswith("favicon"):263        return Response(pkg_resources.resource_stream('flipbook', 'icons/favicon.png'), mimetype='image/png')264    return send_from_directory(args.directory, path, as_attachment=True)265def get_static_data_page_url(page_number, last):266    i = page_number - 1267    if i < 0 or i >= len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST):268        raise ValueError(f"page_number arg is out of bounds. It must be between 1 and {len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)}")269    relative_dir, _ = RELATIVE_DIRECTORY_TO_DATA_FILES_LIST[i]270    name = relative_dir.replace("/", "__")271    return f"page_{name}.html"272def main():273    # add a ctime(..) function to allow the last-changed-time of a path to be computed within a jinja template274    jinja2.environment.DEFAULT_FILTERS['ctime'] = lambda path: int(os.path.getctime(path)) if os.path.isfile(path) else 0275    from flipbook.main_list import main_list_handler276    from flipbook.data_page import data_page_handler277    from flipbook.save import save_form_handler278    app = Flask(__name__)279    if args.generate_static_website:280        os.makedirs(WEBSITE_DIR, exist_ok=True)281        with open(os.path.join(WEBSITE_DIR, "index.html"), "wt") as f:282            f.write(main_list_handler(is_static_website=True).get_data(as_text=True))283        with open(os.path.join(WEBSITE_DIR, "favicon.png"), "wb") as f:284            f.write(pkgutil.get_data('flipbook', 'icons/favicon.png'))285        last_page_number = len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)286        for i, (relative_directory, data_file_types_and_paths) in enumerate(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST):287            page_number = i + 1288            with app.test_request_context(get_data_page_url(page_number, last_page_number)):289                page_dir = os.path.join(WEBSITE_DIR, relative_directory)290                os.makedirs(page_dir, exist_ok=True)291                for data_file_type, data_file in data_file_types_and_paths:292                    if data_file_type in (METADATA_JSON_FILE_TYPE, CONTENT_HTML_FILE_TYPE):293                        continue294                    print("Copying", data_file_type, data_file, "to", page_dir)295                    shutil.copy(data_file, page_dir)296                with open(os.path.join(WEBSITE_DIR, get_static_data_page_url(page_number, last_page_number)), "wt") as f:297                    f.write(data_page_handler(is_static_website=True).get_data(as_text=True))298        print("Done")299        print(f"Generated static website in the ./{WEBSITE_DIR} directory")300        sys.exit(0)301    # start web server302    CORS(app)303    app.url_map.strict_slashes = False304    app.add_url_rule('/', view_func=main_list_handler, methods=['GET'])305    app.add_url_rule('/page', view_func=data_page_handler, methods=['POST', 'GET'])306    app.add_url_rule('/save', view_func=save_form_handler, methods=['POST'])307    app.add_url_rule('/<path:path>', view_func=send_file, methods=['GET'])308    os.environ["WERKZEUG_RUN_MAIN"] = "true"309    host = os.environ.get('HOST', args.host)310    port = int(os.environ.get('PORT', args.port))311    if args.verbose:312        print(f"Connecting to {host}:{port}")313    try:314        app.run(315            debug=args.dev_mode,316            host=host,317            port=port)318    except OSError as e:319        if "already in use" in str(e):320            p.error(f"Port {port} is already in use by another process. Use -p to specify a different port.")321        else:...data_page.py
Source:data_page.py  
1import os2from flask import request, Response3from pprint import pprint, pformat4from flipbook import args, RELATIVE_DIRECTORY_TO_DATA_FILES_LIST, FORM_SCHEMA, FORM_RESPONSES, \5    RELATIVE_DIRECTORY_TO_METADATA, FORM_RADIO_BUTTON_KEYBOARD_SHORTCUTS, EXTRA_DATA_IN_FORM_RESPONSES_TABLE, \6    get_static_data_page_url, DATA_PAGE_HEADER_FILENAME7from flipbook.utils import load_jinja_template, get_data_page_url, CONTENT_HTML_FILE_TYPE, \8    IMAGE_FILE_TYPE9DATA_PAGE_TEMPLATE = None10def data_page_handler(is_static_website=False):11    global DATA_PAGE_TEMPLATE12    if DATA_PAGE_TEMPLATE is None or args.dev_mode:13        DATA_PAGE_TEMPLATE = load_jinja_template("data_page")14    if args.verbose:15        print(f"data_page_handler received {request.url}")16    params = {}17    if dict(request.args):18        params.update(dict(request.args))19    if dict(request.values):20        params.update(dict(request.values))21    json_args = request.get_json(force=True, silent=True)22    if 'i' not in params:23        params.update(json_args or {})24    if args.verbose > 1:25        print(f"data_page_handler request.data: {pformat(request.data)}")26        print(f"data_page_handler request.form: {bool(request.form)} {pformat(request.form)}")27        print(f"data_page_handler request.args: {bool(request.args)} {pformat(request.args)}")28        print(f"data_page_handler request.values: {bool(request.values)} {pformat(request.values)}")29        print(f"data_page_handler request.get_json(..): {bool(json_args)} {pformat(json_args)}")30        print(f"data_page_handler request.__dict__: {pformat(request.__dict__)}")31        print(f"data_page_handler params: {params}")32    i = None33    relative_dir = params.get("path")34    if relative_dir:35        # override i36        for idx, (known_relative_dir, _) in enumerate(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST):37            if relative_dir == known_relative_dir:38                i = idx + 139                break40        else:41            print(f"ERROR: path param '{relative_dir}' not recognized. Falling back on using i param.")42    if i is None:43        i = params.get("i")44    try:45        if isinstance(i, list):46            i = int(i[0])47        else:48            i = int(i)49    except (ValueError, TypeError) as e:50        print(f"ERROR: unable to parse parameter i: '{i}': {type(e).__name__} {e}. Setting i = 1.")51        i = 152    last = params.get("last", i)53    try:54        if isinstance(i, list):55            last = int(last[0])56        else:57            last = int(last)58    except (ValueError, TypeError) as e:59        print(f"ERROR: unable to parse parameter 'last': '{last}': {type(e).__name__} {e}. Setting last = {i}.")60        last = i61    if last < 1:62        print(f"ERROR: parameter 'last' (= {last}) is less than 1. Resetting it to 1.")63        last = 164    if i < 1:65        print(f"ERROR: parameter i (= {i}) is less than 1. Resetting it to 1.")66        i = 167    if i > len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST):68        print(f"ERROR: parameter i (= {i}) is greater than the # of pages "69              f"(= {len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)}). "70              f"Resetting it to {len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)}.")71        i = len(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)72    relative_dir, data_file_types_and_paths = RELATIVE_DIRECTORY_TO_DATA_FILES_LIST[i - 1]73    image_file_paths = []74    for data_file_type, data_file_path in data_file_types_and_paths:75        if data_file_type == IMAGE_FILE_TYPE:76            image_file_paths.append(data_file_path)77    metadata_json_dict = RELATIVE_DIRECTORY_TO_METADATA.get(relative_dir, {})78    metadata_json_dict.update(EXTRA_DATA_IN_FORM_RESPONSES_TABLE.get(relative_dir, {}))79    content_html_strings = []80    for data_file_type, data_file_path in data_file_types_and_paths:81        if data_file_type != CONTENT_HTML_FILE_TYPE:82            continue83        with open(os.path.join(args.directory, data_file_path), "rt") as f:84            content_string = f.read()85            content_html_strings.append((data_file_path, content_string))86    if args.verbose:87        print(f"data_page_handler returning i={i}, last={last}, relative_directory={relative_dir}, "88              f"{len(image_file_paths)} image_file_paths, {len(metadata_json_dict)} records in metadata_json_dict, "89              f"{len(content_html_strings)} content_html_strings")90    data_page_header_html = ""91    if os.path.isfile(os.path.join(args.directory, DATA_PAGE_HEADER_FILENAME)):92        with open(os.path.join(args.directory, DATA_PAGE_HEADER_FILENAME), "rt") as f:93            data_page_header_html = f.read()94    html = DATA_PAGE_TEMPLATE.render(95        i=i,96        last=last,97        header_html=data_page_header_html,98        relative_directory=relative_dir,99        image_file_paths=image_file_paths,100        metadata_json_dict=metadata_json_dict,101        content_html_strings=content_html_strings,102        get_data_page_url=get_data_page_url if not is_static_website else get_static_data_page_url,103        form_schema=FORM_SCHEMA,104        form_radio_button_keyboard_shortcuts=FORM_RADIO_BUTTON_KEYBOARD_SHORTCUTS,105        form_responses=FORM_RESPONSES.get(relative_dir, {}),106        is_static_website=is_static_website,107    )...main_list.py
Source:main_list.py  
1import os2from flask import request, Response3from flipbook import args, RELATIVE_DIRECTORY_TO_DATA_FILES_LIST, FORM_RESPONSES, FORM_SCHEMA_COLUMNS, \4    RELATIVE_DIRECTORY_TO_METADATA, METADATA_COLUMNS, EXTRA_DATA_IN_FORM_RESPONSES_TABLE, \5    EXTRA_COLUMNS_IN_FORM_RESPONSES_TABLE, get_static_data_page_url, MAIN_PAGE_HEADER_FILENAME6from flipbook.utils import load_jinja_template, get_data_page_url7MAIN_LIST_TEMPLATE = None8def main_list_handler(is_static_website=False):9    global MAIN_LIST_TEMPLATE10    if MAIN_LIST_TEMPLATE is None or args.dev_mode:11        MAIN_LIST_TEMPLATE = load_jinja_template("main_list")12    if args.verbose:13        print(f"main_list_handler received {request.url}")14    data_files_list = [15        (page_number + 1, relative_directory, data_file_types_and_paths)16        for page_number, (relative_directory, data_file_types_and_paths) in enumerate(RELATIVE_DIRECTORY_TO_DATA_FILES_LIST)17    ]18    # combine metadata from 2 potential sources: RELATIVE_DIRECTORY_TO_METADATA and EXTRA_DATA_IN_FORM_RESPONSES_TABLE19    metadata_columns = []20    metadata_dict = {}21    if not args.hide_metadata_on_home_page:22        metadata_columns = METADATA_COLUMNS23        if not is_static_website:24            metadata_columns += EXTRA_COLUMNS_IN_FORM_RESPONSES_TABLE25        for relative_dir in list(RELATIVE_DIRECTORY_TO_METADATA.keys()) + list(EXTRA_DATA_IN_FORM_RESPONSES_TABLE.keys()):26            metadata_dict[relative_dir] = dict(RELATIVE_DIRECTORY_TO_METADATA.get(relative_dir, {}))27            metadata_dict[relative_dir].update(dict(EXTRA_DATA_IN_FORM_RESPONSES_TABLE.get(relative_dir, {})))28    main_page_header_html = ""29    if os.path.isfile(os.path.join(args.directory, MAIN_PAGE_HEADER_FILENAME)):30        with open(os.path.join(args.directory, MAIN_PAGE_HEADER_FILENAME), "rt") as f:31            main_page_header_html = f.read()32    html = MAIN_LIST_TEMPLATE.render(33        header_html=main_page_header_html,34        data_files_list=data_files_list,35        get_data_page_url=get_data_page_url if not is_static_website else get_static_data_page_url,36        form_column_names=FORM_SCHEMA_COLUMNS,37        form_responses_dict=FORM_RESPONSES,38        metadata_column_names=metadata_columns,39        metadata_dict=metadata_dict,40        form_responses_table_path=args.form_responses_table,41        is_static_website=is_static_website,42    )...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!!
