LatvianPython/pyoracle_forms

View on GitHub
forms_api/api_scraper.py

Summary

Maintainability
A
0 mins
Test Coverage
import json
import re
from collections import deque, defaultdict
from itertools import repeat, chain


def file_lines(filepath):
    with open(filepath, mode="r", encoding="utf-8") as file:
        return file.readlines()


def scrape_constants(filepath, prefix):
    constant_re = re.compile(r"#define (\w+?) +(\d+)")

    def parse_line(line):
        constant, value = constant_re.match(line).groups()
        return constant, int(value)

    return dict(
        parse_line(line)
        for line in file_lines(filepath)
        if line.startswith(f"#define {prefix}")
    )


def collect_macros(lines):
    deq = deque(lines)
    deq.rotate(-1)
    return (
        "".join((convenience, signature)).replace("\n", "")
        for convenience, signature in zip(lines, deq)
        if convenience.startswith("#define d2f")
    )


def all_macros(filepath):
    return collect_macros(file_lines(filepath))


ABBREVIATIONS = {
    "ob": "D2FFO_ANY",
    "alt": "D2FFO_ALERT",
    "alb": "D2FFO_ATT_LIB",
    "blk": "D2FFO_BLOCK",
    "cnv": "D2FFO_CANVAS",
    "crd": "D2FFO_COORD",
    "dsa": "D2FFO_DAT_SRC_ARG",
    "dsc": "D2FFO_DAT_SRC_COL",
    "edt": "D2FFO_EDITOR",
    "evt": "D2FFO_EVENT",
    "fnt": "D2FFO_FONT",
    "fmd": "D2FFO_FORM_MODULE",
    "fpm": "D2FFO_FORM_PARAM",
    "gra": "D2FFO_GRAPHIC",
    "itm": "D2FFO_ITEM",
    "lpu": "D2FFO_LIB_PROG_UNIT",
    "lib": "D2FFO_LIBRARY_MODULE",
    "lov": "D2FFO_LOV",
    "lcm": "D2FFO_LV_COLMAP",
    "mnu": "D2FFO_MENU",
    "mni": "D2FFO_MENU_ITEM",
    "mmd": "D2FFO_MENU_MODULE",
    "mpm": "D2FFO_MENU_PARAM",
    "obg": "D2FFO_OBJ_GROUP",
    "ogc": "D2FFO_OBG_CHILD",
    "olb": "D2FFO_OBJ_LIB",
    "olt": "D2FFO_OBJ_LIB_TAB",
    "pgu": "D2FFO_PROG_UNIT",
    "pnt": "D2FFO_POINT",
    "ppc": "D2FFO_PROP_CLASS",
    "rdb": "D2FFO_RADIO_BUTTON",
    "rcg": "D2FFO_REC_GROUP",
    "rcs": "D2FFO_RG_COLSPEC",
    "rel": "D2FFO_RELATION",
    "rpt": "D2FFO_REPORT",
    "tbp": "D2FFO_TAB_PAGE",
    "trg": "D2FFO_TRIGGER",
    "vat": "D2FFO_VIS_ATTR",
    "win": "D2FFO_WINDOW",
}


def forms_objects(api_version):
    objects = scrape_constants(f"./{api_version}/d2fdef.h", "D2FFO_")
    return {
        abbreviation: (object_type, objects[object_type])
        for abbreviation, object_type in ABBREVIATIONS.items()
        if object_type in objects.keys()
    }


def macros(api_version):
    return chain.from_iterable(
        zip(all_macros(f"./{api_version}/d2f{abbreviation}.h"), repeat(object_type))
        for abbreviation, object_type in forms_objects(api_version).items()
    )


def forms_object_properties(api_version):
    properties = scrape_constants(f"./{api_version}/d2fdef.h", "D2FP_")
    macro_regex = re.compile(
        r"#define d2f\w+?[gs]_(\w+?)\(.+(?:(?:Get)|(?:Set))(.+?)Prop.+,(\w+),val\)"
    )

    object_properties = defaultdict(set)
    for macro, object_type in macros(api_version):
        match = macro_regex.match(macro)
        if match:
            prop_name, prop_type, prop = match.groups()
            object_properties[object_type].add(
                (prop_name, prop_type.lower(), prop, properties[prop])
            )
    return object_properties


def parse_headers(api_version):
    return {
        obj_name: {
            "object_number": obj_type,
            "properties": sorted(
                [
                    {
                        "short_name": short_name,
                        "data_type": data_type,
                        "macro_name": macro_name,
                        "property_number": property_name,
                    }
                    for (short_name, data_type, macro_name, property_name) in properties
                ],
                key=lambda x: x["property_number"],
            ),
        }
        for (obj_name, obj_type), properties in forms_object_properties(
            api_version
        ).items()
    }


def parse_all():
    versions = ["6i", "10g", "12c"]

    for version in versions:
        with open(
            f"../pyoracle_forms/forms_api/parsed_{version}.json",
            mode="w",
            encoding="utf-8",
        ) as file:
            json.dump(parse_headers(version), file, indent=2)


def main():
    parse_all()


if __name__ == "__main__":
    main()