Esempio n. 1
0
def perform_codegen():
    # Set root codegen output directory
    # ---------------------------------
    # (relative to project root)
    abs_file_path = opath.realpath(__file__)
    packages_py = opath.dirname(opath.dirname(opath.dirname(abs_file_path)))
    outdir = opath.join(packages_py, "plotly", "plotly")

    # Delete prior codegen output
    # ---------------------------
    validators_pkgdir = opath.join(outdir, "validators")
    if opath.exists(validators_pkgdir):
        shutil.rmtree(validators_pkgdir)

    graph_objs_pkgdir = opath.join(outdir, "graph_objs")
    if opath.exists(graph_objs_pkgdir):
        shutil.rmtree(graph_objs_pkgdir)

    # plotly/datatypes is not used anymore, but was at one point so we'll
    # still delete it if we find it in case a developer is upgrading from an
    # older version
    datatypes_pkgdir = opath.join(outdir, "datatypes")
    if opath.exists(datatypes_pkgdir):
        shutil.rmtree(datatypes_pkgdir)

    # Load plotly schema
    # ------------------
    plot_schema_path = opath.join(
        packages_py, "plotly", "codegen", "resources", "plot-schema.json"
    )

    with open(plot_schema_path, "r") as f:
        plotly_schema = json.load(f)

    # Preprocess Schema
    # -----------------
    preprocess_schema(plotly_schema)

    # Build node lists
    # ----------------
    # ### TraceNode ###
    base_traces_node = TraceNode(plotly_schema)
    compound_trace_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, TraceNode
    )
    all_trace_nodes = PlotlyNode.get_all_datatype_nodes(plotly_schema, TraceNode)

    # ### LayoutNode ###
    compound_layout_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, LayoutNode
    )
    layout_node = compound_layout_nodes[0]
    all_layout_nodes = PlotlyNode.get_all_datatype_nodes(plotly_schema, LayoutNode)

    subplot_nodes = [
        node
        for node in layout_node.child_compound_datatypes
        if node.node_data.get("_isSubplotObj", False)
    ]

    # ### FrameNode ###
    compound_frame_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, FrameNode
    )
    frame_node = compound_frame_nodes[0]
    all_frame_nodes = PlotlyNode.get_all_datatype_nodes(plotly_schema, FrameNode)

    # ### All nodes ###
    all_datatype_nodes = all_trace_nodes + all_layout_nodes + all_frame_nodes

    all_compound_nodes = [
        node
        for node in all_datatype_nodes
        if node.is_compound and not isinstance(node, ElementDefaultsNode)
    ]

    # Write out validators
    # --------------------
    # # ### Layout ###
    for node in all_layout_nodes:
        write_validator_py(outdir, node)

    # ### Trace ###
    for node in all_trace_nodes:
        write_validator_py(outdir, node)

    # ### Frames ###
    for node in all_frame_nodes:
        write_validator_py(outdir, node)

    # ### Data (traces) validator ###
    write_data_validator_py(outdir, base_traces_node)

    # Alls
    # ----
    alls = {}

    # Write out datatypes
    # -------------------
    for node in all_compound_nodes:
        write_datatype_py(outdir, node)
        alls.setdefault(node.path_parts, [])
        alls[node.path_parts].extend(
            c.name_datatype_class for c in node.child_compound_datatypes
        )
        if node.parent_path_parts == ():
            # Add top-level classes to alls
            alls.setdefault((), [])
            alls[node.parent_path_parts].append(node.name_datatype_class)

    # ### Deprecated ###
    # These are deprecated legacy datatypes like graph_objs.Marker
    write_deprecated_datatypes(outdir)

    # Write figure class to graph_objs
    # --------------------------------
    data_validator = get_data_validator_instance(base_traces_node)
    layout_validator = layout_node.get_validator_instance()
    frame_validator = frame_node.get_validator_instance()

    write_figure_classes(
        outdir,
        base_traces_node,
        data_validator,
        layout_validator,
        frame_validator,
        subplot_nodes,
    )

    # Write datatype __init__.py files
    # --------------------------------
    # ### Build mapping from parent package to datatype class ###
    path_to_datatype_import_info = {}
    for node in all_compound_nodes:
        key = node.parent_path_parts

        # submodule import
        if node.child_compound_datatypes:

            path_to_datatype_import_info.setdefault(key, []).append(
                (f"plotly.graph_objs{node.parent_dotpath_str}", node.name_undercase)
            )
            alls[node.parent_path_parts].append(node.name_undercase)

    # ### Write plotly/graph_objs/graph_objs.py ###
    # This if for backward compatibility. It just imports everything from
    # graph_objs/__init__.py
    write_graph_objs_graph_objs(outdir)

    # ### Add Figure and FigureWidget ###
    root_datatype_imports = path_to_datatype_import_info[()]
    root_datatype_imports.append(("._figure", "Figure"))
    alls[()].append("Figure")

    # ### Add deprecations ###
    root_datatype_imports.append(("._deprecations", DEPRECATED_DATATYPES.keys()))
    alls[()].extend(DEPRECATED_DATATYPES.keys())

    # Sort alls
    for k, v in alls.items():
        alls[k] = list(sorted(v))

    optional_figure_widget_import = f"""
__all__ = {alls[()]}
try:
    import ipywidgets
    from distutils.version import LooseVersion
    if LooseVersion(ipywidgets.__version__) >= LooseVersion('7.0.0'):
        from ._figurewidget import FigureWidget
    del LooseVersion
    del ipywidgets
    __all__.append("FigureWidget")
except ImportError:
    pass
"""
    root_datatype_imports.append(optional_figure_widget_import)

    # ### __all__ ###
    for path_parts, class_names in alls.items():
        if path_parts and class_names:
            filepath = opath.join(outdir, "graph_objs", *path_parts, "__init__.py")
            with open(filepath, "at") as f:
                f.write(f"\n__all__ = {class_names}")

    # ### Output datatype __init__.py files ###
    graph_objs_pkg = opath.join(outdir, "graph_objs")
    for path_parts, import_pairs in path_to_datatype_import_info.items():
        write_init_py(graph_objs_pkg, path_parts, import_pairs)

    # ### Output graph_objects.py alias
    graph_objects_path = opath.join(outdir, "graph_objects.py")
    with open(graph_objects_path, "wt") as f:
        f.write(
            f"""\
from __future__ import absolute_import
from plotly.graph_objs import *
__all__ = {alls[()]}"""
        )

    # ### Run black code formatter on output directories ###
    subprocess.call(["black", "--target-version=py27", validators_pkgdir])
    subprocess.call(["black", "--target-version=py27", graph_objs_pkgdir])
    subprocess.call(["black", "--target-version=py27", graph_objects_path])
Esempio n. 2
0
def perform_codegen():
    # Set root codegen output directory
    # ---------------------------------
    # (relative to project root)
    abs_file_path = opath.realpath(__file__)
    packages_py = opath.dirname(opath.dirname(opath.dirname(abs_file_path)))
    outdir = opath.join(packages_py, "plotly", "plotly")

    # Delete prior codegen output
    # ---------------------------
    validators_pkgdir = opath.join(outdir, "validators")
    if opath.exists(validators_pkgdir):
        shutil.rmtree(validators_pkgdir)

    graph_objs_pkgdir = opath.join(outdir, "graph_objs")
    if opath.exists(graph_objs_pkgdir):
        shutil.rmtree(graph_objs_pkgdir)

    # plotly/datatypes is not used anymore, but was at one point so we'll
    # still delete it if we find it in case a developer is upgrading from an
    # older version
    datatypes_pkgdir = opath.join(outdir, "datatypes")
    if opath.exists(datatypes_pkgdir):
        shutil.rmtree(datatypes_pkgdir)

    # Load plotly schema
    # ------------------
    plot_schema_path = opath.join(packages_py, "plotly", "codegen",
                                  "resources", "plot-schema.json")

    with open(plot_schema_path, "r") as f:
        plotly_schema = json.load(f)

    # Preprocess Schema
    # -----------------
    preprocess_schema(plotly_schema)

    # Build node lists
    # ----------------
    # ### TraceNode ###
    base_traces_node = TraceNode(plotly_schema)
    compound_trace_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, TraceNode)
    all_trace_nodes = PlotlyNode.get_all_datatype_nodes(
        plotly_schema, TraceNode)

    # ### LayoutNode ###
    compound_layout_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, LayoutNode)
    layout_node = compound_layout_nodes[0]
    all_layout_nodes = PlotlyNode.get_all_datatype_nodes(
        plotly_schema, LayoutNode)

    subplot_nodes = [
        node for node in layout_node.child_compound_datatypes
        if node.node_data.get("_isSubplotObj", False)
    ]

    layout_array_nodes = [
        node for node in layout_node.child_compound_datatypes
        if node.is_array_element and node.has_child("xref")
        and node.has_child("yref")
    ]

    # ### FrameNode ###
    compound_frame_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, FrameNode)
    frame_node = compound_frame_nodes[0]
    all_frame_nodes = PlotlyNode.get_all_datatype_nodes(
        plotly_schema, FrameNode)

    # ### All nodes ###
    all_datatype_nodes = all_trace_nodes + all_layout_nodes + all_frame_nodes

    all_compound_nodes = [
        node for node in all_datatype_nodes
        if node.is_compound and not isinstance(node, ElementDefaultsNode)
    ]

    # Write out validators
    # --------------------
    # # ### Layout ###
    for node in all_layout_nodes:
        write_validator_py(outdir, node)

    # ### Trace ###
    for node in all_trace_nodes:
        write_validator_py(outdir, node)

    # ### Frames ###
    for node in all_frame_nodes:
        write_validator_py(outdir, node)

    # ### Data (traces) validator ###
    write_data_validator_py(outdir, base_traces_node)

    # Alls
    # ----
    alls = {}

    # Write out datatypes
    # -------------------
    for node in all_compound_nodes:
        write_datatype_py(outdir, node)

    # ### Deprecated ###
    # These are deprecated legacy datatypes like graph_objs.Marker
    write_deprecated_datatypes(outdir)

    # Write figure class to graph_objs
    # --------------------------------
    data_validator = get_data_validator_instance(base_traces_node)
    layout_validator = layout_node.get_validator_instance()
    frame_validator = frame_node.get_validator_instance()

    write_figure_classes(
        outdir,
        base_traces_node,
        data_validator,
        layout_validator,
        frame_validator,
        subplot_nodes,
        layout_array_nodes,
    )

    # Write validator __init__.py files
    # ---------------------------------
    # ### Write __init__.py files for each validator package ###
    validator_rel_class_imports = {}
    for node in all_datatype_nodes:
        if node.is_mapped:
            continue
        key = node.parent_path_parts
        validator_rel_class_imports.setdefault(
            key,
            []).append(f"._{node.name_property}.{node.name_validator_class}")

    # Add Data validator
    root_validator_pairs = validator_rel_class_imports[()]
    root_validator_pairs.append("._data.DataValidator")

    # Output validator __init__.py files
    validators_pkg = opath.join(outdir, "validators")
    for path_parts, rel_classes in validator_rel_class_imports.items():
        write_init_py(validators_pkg, path_parts, [], rel_classes)

    # Write datatype __init__.py files
    # --------------------------------
    datatype_rel_class_imports = {}
    datatype_rel_module_imports = {}

    for node in all_compound_nodes:
        key = node.parent_path_parts

        # class import
        datatype_rel_class_imports.setdefault(
            key,
            []).append(f"._{node.name_undercase}.{node.name_datatype_class}")

        # submodule import
        if node.child_compound_datatypes:
            datatype_rel_module_imports.setdefault(
                key, []).append(f".{node.name_undercase}")

    # ### Write plotly/graph_objs/graph_objs.py ###
    # This if for backward compatibility. It just imports everything from
    # graph_objs/__init__.py
    write_graph_objs_graph_objs(outdir)

    # ### Add Figure and FigureWidget ###
    root_datatype_imports = datatype_rel_class_imports[()]
    root_datatype_imports.append("._figure.Figure")

    # ### Add deprecations ###
    for dep_clas in DEPRECATED_DATATYPES:
        root_datatype_imports.append(f"._deprecations.{dep_clas}")

    optional_figure_widget_import = f"""
if sys.version_info < (3, 7) or TYPE_CHECKING:
    try:
        import ipywidgets as _ipywidgets
        from distutils.version import LooseVersion as _LooseVersion
        if _LooseVersion(_ipywidgets.__version__) >= _LooseVersion("7.0.0"):
            from ..graph_objs._figurewidget import FigureWidget
        else:
            raise ImportError()
    except Exception:
        from ..missing_ipywidgets import FigureWidget
else:
    __all__.append("FigureWidget")
    orig_getattr = __getattr__
    def __getattr__(import_name):
        if import_name == "FigureWidget":
            try:
                import ipywidgets
                from distutils.version import LooseVersion

                if LooseVersion(ipywidgets.__version__) >= LooseVersion("7.0.0"):
                    from ..graph_objs._figurewidget import FigureWidget

                    return FigureWidget
                else:
                    raise ImportError()
            except Exception:
                from ..missing_ipywidgets import FigureWidget
                return FigureWidget

        return orig_getattr(import_name)
"""
    # ### __all__ ###
    for path_parts, class_names in alls.items():
        if path_parts and class_names:
            filepath = opath.join(outdir, "graph_objs", *path_parts,
                                  "__init__.py")
            with open(filepath, "at") as f:
                f.write(f"\n__all__ = {class_names}")

    # ### Output datatype __init__.py files ###
    graph_objs_pkg = opath.join(outdir, "graph_objs")
    for path_parts in datatype_rel_class_imports:
        rel_classes = sorted(datatype_rel_class_imports[path_parts])
        rel_modules = sorted(datatype_rel_module_imports.get(path_parts, []))
        if path_parts == ():
            init_extra = optional_figure_widget_import
        else:
            init_extra = ""
        write_init_py(graph_objs_pkg, path_parts, rel_modules, rel_classes,
                      init_extra)

    # ### Output graph_objects.py alias
    graph_objects_rel_classes = [
        "..graph_objs." + rel_path.split(".")[-1]
        for rel_path in datatype_rel_class_imports[()]
    ]
    graph_objects_rel_modules = [
        "..graph_objs." + rel_module.split(".")[-1]
        for rel_module in datatype_rel_module_imports[()]
    ]

    graph_objects_init_source = build_from_imports_py(
        graph_objects_rel_modules,
        graph_objects_rel_classes,
        init_extra=optional_figure_widget_import,
    )
    graph_objects_path = opath.join(outdir, "graph_objects", "__init__.py")
    os.makedirs(opath.join(outdir, "graph_objects"), exist_ok=True)
    with open(graph_objects_path, "wt") as f:
        f.write(graph_objects_init_source)

    # ### Run black code formatter on output directories ###
    subprocess.call(["black", "--target-version=py36", validators_pkgdir])
    subprocess.call(["black", "--target-version=py36", graph_objs_pkgdir])
    subprocess.call(["black", "--target-version=py36", graph_objects_path])
Esempio n. 3
0
def perform_codegen():
    # Set root codegen output directory
    # ---------------------------------
    # (relative to project root)
    outdir = 'plotly'

    # Delete prior codegen output
    # ---------------------------
    validators_pkgdir = opath.join(outdir, 'validators')
    if opath.exists(validators_pkgdir):
        shutil.rmtree(validators_pkgdir)

    graph_objs_pkgdir = opath.join(outdir, 'graph_objs')
    if opath.exists(graph_objs_pkgdir):
        shutil.rmtree(graph_objs_pkgdir)

    # plotly/datatypes is not used anymore, but was at one point so we'll
    # still delete it if we find it in case a developer is upgrading from an
    # older version
    datatypes_pkgdir = opath.join(outdir, 'datatypes')
    if opath.exists(datatypes_pkgdir):
        shutil.rmtree(datatypes_pkgdir)

    # Load plotly schema
    # ------------------
    with open('plotly/package_data/plot-schema.json', 'r') as f:
        plotly_schema = json.load(f)

    # Preprocess Schema
    # -----------------
    preprocess_schema(plotly_schema)

    # Build node lists
    # ----------------
    # ### TraceNode ###
    base_traces_node = TraceNode(plotly_schema)
    compound_trace_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, TraceNode)
    all_trace_nodes = PlotlyNode.get_all_datatype_nodes(
        plotly_schema, TraceNode)

    # ### LayoutNode ###
    compound_layout_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, LayoutNode)
    layout_node = compound_layout_nodes[0]
    all_layout_nodes = PlotlyNode.get_all_datatype_nodes(
        plotly_schema, LayoutNode)

    # ### FrameNode ###
    compound_frame_nodes = PlotlyNode.get_all_compound_datatype_nodes(
        plotly_schema, FrameNode)
    frame_node = compound_frame_nodes[0]
    all_frame_nodes = PlotlyNode.get_all_datatype_nodes(
        plotly_schema, FrameNode)

    # ### All nodes ###
    all_datatype_nodes = (all_trace_nodes +
                          all_layout_nodes +
                          all_frame_nodes)

    all_compound_nodes = [node for node in all_datatype_nodes
                          if node.is_compound and
                          not isinstance(node, ElementDefaultsNode)]

    # Write out validators
    # --------------------
    # # ### Layout ###
    for node in all_layout_nodes:
        write_validator_py(outdir, node)

    # ### Trace ###
    for node in all_trace_nodes:
        write_validator_py(outdir, node)

    # ### Frames ###
    for node in all_frame_nodes:
        write_validator_py(outdir, node)

    # ### Data (traces) validator ###
    write_data_validator_py(outdir, base_traces_node)

    # Write out datatypes
    # -------------------
    # ### Layout ###
    for node in compound_layout_nodes:
        write_datatype_py(outdir, node)

    # ### Trace ###
    for node in compound_trace_nodes:
        write_datatype_py(outdir, node)

    # ### Frames ###
    for node in compound_frame_nodes:
        write_datatype_py(outdir, node)

    # ### Deprecated ###
    # These are deprecated legacy datatypes like graph_objs.Marker
    write_deprecated_datatypes(outdir)

    # Write figure class to graph_objs
    # --------------------------------
    data_validator = get_data_validator_instance(base_traces_node)
    layout_validator = layout_node.get_validator_instance()
    frame_validator = frame_node.get_validator_instance()

    write_figure_classes(outdir,
                         base_traces_node,
                         data_validator,
                         layout_validator,
                         frame_validator)

    # Write validator __init__.py files
    # ---------------------------------
    # ### Write __init__.py files for each validator package ###
    path_to_validator_import_info = {}
    for node in all_datatype_nodes:
        if node.is_mapped:
            continue
        key = node.parent_path_parts
        path_to_validator_import_info.setdefault(key, []).append(
            (f"._{node.name_property}", node.name_validator_class)
        )

    # Add Data validator
    root_validator_pairs = path_to_validator_import_info[()]
    root_validator_pairs.append(('._data', 'DataValidator'))

    # Output validator __init__.py files
    validators_pkg = opath.join(outdir, 'validators')
    for path_parts, import_pairs in path_to_validator_import_info.items():
        write_init_py(validators_pkg, path_parts, import_pairs)

    # Write datatype __init__.py files
    # --------------------------------
    # ### Build mapping from parent package to datatype class ###
    path_to_datatype_import_info = {}
    for node in all_compound_nodes:
        key = node.parent_path_parts

        # class import
        path_to_datatype_import_info.setdefault(key, []).append(
            (f"._{node.name_undercase}", node.name_datatype_class)
        )

        # submodule import
        if node.child_compound_datatypes:

            path_to_datatype_import_info.setdefault(key, []).append(
                (f"plotly.graph_objs{node.parent_dotpath_str}",
                 node.name_undercase)
            )

    # ### Write plotly/graph_objs/graph_objs.py ###
    # This if for backward compatibility. It just imports everything from
    # graph_objs/__init__.py
    write_graph_objs_graph_objs(outdir)

    # ### Add Figure and FigureWidget ###
    root_datatype_imports = path_to_datatype_import_info[()]
    root_datatype_imports.append(('._figure', 'Figure'))

    optional_figure_widget_import = """
try:
    import ipywidgets
    from distutils.version import LooseVersion
    if LooseVersion(ipywidgets.__version__) >= LooseVersion('7.0.0'):
        from ._figurewidget import FigureWidget
    del LooseVersion
    del ipywidgets
except ImportError:
    pass
"""
    root_datatype_imports.append(optional_figure_widget_import)

    # ### Add deprecations ###
    root_datatype_imports.append(('._deprecations', DEPRECATED_DATATYPES.keys()))

    # ### Output datatype __init__.py files ###
    graph_objs_pkg = opath.join(outdir, 'graph_objs')
    for path_parts, import_pairs in path_to_datatype_import_info.items():
        write_init_py(graph_objs_pkg, path_parts, import_pairs)