791 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			791 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								from collections import OrderedDict
							 | 
						||
| 
								 | 
							
								import copy
							 | 
						||
| 
								 | 
							
								import numbers
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import typing
							 | 
						||
| 
								 | 
							
								from textwrap import fill, dedent
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from typing_extensions import TypedDict, NotRequired, Literal
							 | 
						||
| 
								 | 
							
								from dash.development.base_component import _explicitize_args
							 | 
						||
| 
								 | 
							
								from dash.exceptions import NonExistentEventException
							 | 
						||
| 
								 | 
							
								from ._all_keywords import python_keywords
							 | 
						||
| 
								 | 
							
								from ._collect_nodes import collect_nodes, filter_base_nodes
							 | 
						||
| 
								 | 
							
								from ._py_prop_typing import (
							 | 
						||
| 
								 | 
							
								    get_custom_ignore,
							 | 
						||
| 
								 | 
							
								    get_custom_props,
							 | 
						||
| 
								 | 
							
								    get_prop_typing,
							 | 
						||
| 
								 | 
							
								    shapes,
							 | 
						||
| 
								 | 
							
								    get_custom_imports,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								from .base_component import Component, ComponentType
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import_string = """# AUTO GENERATED FILE - DO NOT EDIT
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import typing  # noqa: F401
							 | 
						||
| 
								 | 
							
								from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
							 | 
						||
| 
								 | 
							
								from dash.development.base_component import Component, _explicitize_args
							 | 
						||
| 
								 | 
							
								{custom_imports}
							 | 
						||
| 
								 | 
							
								ComponentType = typing.Union[
							 | 
						||
| 
								 | 
							
								    str,
							 | 
						||
| 
								 | 
							
								    int,
							 | 
						||
| 
								 | 
							
								    float,
							 | 
						||
| 
								 | 
							
								    Component,
							 | 
						||
| 
								 | 
							
								    None,
							 | 
						||
| 
								 | 
							
								    typing.Sequence[typing.Union[str, int, float, Component, None]],
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NumberType = typing.Union[
							 | 
						||
| 
								 | 
							
								    typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# pylint: disable=unused-argument,too-many-locals,too-many-branches
							 | 
						||
| 
								 | 
							
								def generate_class_string(
							 | 
						||
| 
								 | 
							
								    typename,
							 | 
						||
| 
								 | 
							
								    props,
							 | 
						||
| 
								 | 
							
								    description,
							 | 
						||
| 
								 | 
							
								    namespace,
							 | 
						||
| 
								 | 
							
								    prop_reorder_exceptions=None,
							 | 
						||
| 
								 | 
							
								    max_props=None,
							 | 
						||
| 
								 | 
							
								    custom_typing_module=None,
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """Dynamically generate class strings to have nicely formatted docstrings,
							 | 
						||
| 
								 | 
							
								    keyword arguments, and repr.
							 | 
						||
| 
								 | 
							
								    Inspired by http://jameso.be/2013/08/06/namedtuple.html
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    typename
							 | 
						||
| 
								 | 
							
								    props
							 | 
						||
| 
								 | 
							
								    description
							 | 
						||
| 
								 | 
							
								    namespace
							 | 
						||
| 
								 | 
							
								    prop_reorder_exceptions
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    string
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    # TODO _prop_names, _type, _namespace, and available_properties
							 | 
						||
| 
								 | 
							
								    # can be modified by a Dash JS developer via setattr
							 | 
						||
| 
								 | 
							
								    # TODO - Tab out the repr for the repr of these components to make it
							 | 
						||
| 
								 | 
							
								    # look more like a hierarchical tree
							 | 
						||
| 
								 | 
							
								    # TODO - Include "description" "defaultValue" in the repr and docstring
							 | 
						||
| 
								 | 
							
								    #
							 | 
						||
| 
								 | 
							
								    # TODO - Handle "required"
							 | 
						||
| 
								 | 
							
								    #
							 | 
						||
| 
								 | 
							
								    # TODO - How to handle user-given `null` values? I want to include
							 | 
						||
| 
								 | 
							
								    # an expanded docstring like Dropdown(value=None, id=None)
							 | 
						||
| 
								 | 
							
								    # but by templating in those None values, I have no way of knowing
							 | 
						||
| 
								 | 
							
								    # whether a property is None because the user explicitly wanted
							 | 
						||
| 
								 | 
							
								    # it to be `null` or whether that was just the default value.
							 | 
						||
| 
								 | 
							
								    # The solution might be to deal with default values better although
							 | 
						||
| 
								 | 
							
								    # not all component authors will supply those.
							 | 
						||
| 
								 | 
							
								    c = '''class {typename}(Component):
							 | 
						||
| 
								 | 
							
								    """{docstring}"""
							 | 
						||
| 
								 | 
							
								    _children_props = {children_props}
							 | 
						||
| 
								 | 
							
								    _base_nodes = {base_nodes}
							 | 
						||
| 
								 | 
							
								    _namespace = '{namespace}'
							 | 
						||
| 
								 | 
							
								    _type = '{typename}'
							 | 
						||
| 
								 | 
							
								{shapes}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(
							 | 
						||
| 
								 | 
							
								        self,
							 | 
						||
| 
								 | 
							
								        {default_argtext}
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        self._prop_names = {list_of_valid_keys}
							 | 
						||
| 
								 | 
							
								        self._valid_wildcard_attributes =\
							 | 
						||
| 
								 | 
							
								            {list_of_valid_wildcard_attr_prefixes}
							 | 
						||
| 
								 | 
							
								        self.available_properties = {list_of_valid_keys}
							 | 
						||
| 
								 | 
							
								        self.available_wildcard_properties =\
							 | 
						||
| 
								 | 
							
								            {list_of_valid_wildcard_attr_prefixes}
							 | 
						||
| 
								 | 
							
								        _explicit_args = kwargs.pop('_explicit_args')
							 | 
						||
| 
								 | 
							
								        _locals = locals()
							 | 
						||
| 
								 | 
							
								        _locals.update(kwargs)  # For wildcard attrs and excess named props
							 | 
						||
| 
								 | 
							
								        args = {args}
							 | 
						||
| 
								 | 
							
								        {required_validation}
							 | 
						||
| 
								 | 
							
								        super({typename}, self).__init__({argtext})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								setattr({typename}, "__init__", _explicitize_args({typename}.__init__))
							 | 
						||
| 
								 | 
							
								'''
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    filtered_props = (
							 | 
						||
| 
								 | 
							
								        filter_props(props)
							 | 
						||
| 
								 | 
							
								        if (prop_reorder_exceptions is not None and typename in prop_reorder_exceptions)
							 | 
						||
| 
								 | 
							
								        or (prop_reorder_exceptions is not None and "ALL" in prop_reorder_exceptions)
							 | 
						||
| 
								 | 
							
								        else reorder_props(filter_props(props))
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    wildcard_prefixes = repr(parse_wildcards(props))
							 | 
						||
| 
								 | 
							
								    list_of_valid_keys = repr(list(map(str, filtered_props.keys())))
							 | 
						||
| 
								 | 
							
								    custom_ignore = get_custom_ignore(custom_typing_module)
							 | 
						||
| 
								 | 
							
								    docstring = create_docstring(
							 | 
						||
| 
								 | 
							
								        component_name=typename,
							 | 
						||
| 
								 | 
							
								        props=filtered_props,
							 | 
						||
| 
								 | 
							
								        description=description,
							 | 
						||
| 
								 | 
							
								        prop_reorder_exceptions=prop_reorder_exceptions,
							 | 
						||
| 
								 | 
							
								        ignored_props=custom_ignore,
							 | 
						||
| 
								 | 
							
								    ).replace("\r\n", "\n")
							 | 
						||
| 
								 | 
							
								    required_args = required_props(filtered_props)
							 | 
						||
| 
								 | 
							
								    is_children_required = "children" in required_args
							 | 
						||
| 
								 | 
							
								    required_args = [arg for arg in required_args if arg != "children"]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    prohibit_events(props)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # pylint: disable=unused-variable
							 | 
						||
| 
								 | 
							
								    prop_keys = list(props.keys())
							 | 
						||
| 
								 | 
							
								    if "children" in props and "children" in list_of_valid_keys:
							 | 
						||
| 
								 | 
							
								        prop_keys.remove("children")
							 | 
						||
| 
								 | 
							
								        # TODO For dash 3.0, remove the Optional and = None for proper typing.
							 | 
						||
| 
								 | 
							
								        #  Also add the other required props after children.
							 | 
						||
| 
								 | 
							
								        default_argtext = f"children: typing.Optional[{get_prop_typing('node', '', '', {})}] = None,\n        "
							 | 
						||
| 
								 | 
							
								        args = "{k: _locals[k] for k in _explicit_args if k != 'children'}"
							 | 
						||
| 
								 | 
							
								        argtext = "children=children, **args"
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        default_argtext = ""
							 | 
						||
| 
								 | 
							
								        args = "{k: _locals[k] for k in _explicit_args}"
							 | 
						||
| 
								 | 
							
								        argtext = "**args"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if len(required_args) == 0:
							 | 
						||
| 
								 | 
							
								        required_validation = ""
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        required_validation = f"""
							 | 
						||
| 
								 | 
							
								        for k in {required_args}:
							 | 
						||
| 
								 | 
							
								            if k not in args:
							 | 
						||
| 
								 | 
							
								                raise TypeError(
							 | 
						||
| 
								 | 
							
								                    'Required argument `' + k + '` was not specified.')
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if is_children_required:
							 | 
						||
| 
								 | 
							
								        required_validation += """
							 | 
						||
| 
								 | 
							
								        if 'children' not in _explicit_args:
							 | 
						||
| 
								 | 
							
								            raise TypeError('Required argument children was not specified.')
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    default_arglist = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for prop_key in prop_keys:
							 | 
						||
| 
								 | 
							
								        prop = props[prop_key]
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            prop_key.endswith("-*")
							 | 
						||
| 
								 | 
							
								            or prop_key in python_keywords
							 | 
						||
| 
								 | 
							
								            or prop_key == "setProps"
							 | 
						||
| 
								 | 
							
								        ):
							 | 
						||
| 
								 | 
							
								            continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        type_info = prop.get("type")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if not type_info:
							 | 
						||
| 
								 | 
							
								            print(f"Invalid prop type for typing: {prop_key}")
							 | 
						||
| 
								 | 
							
								            default_arglist.append(f"{prop_key} = None")
							 | 
						||
| 
								 | 
							
								            continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        type_name = type_info.get("name")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        custom_props = get_custom_props(custom_typing_module)
							 | 
						||
| 
								 | 
							
								        typed = get_prop_typing(
							 | 
						||
| 
								 | 
							
								            type_name,
							 | 
						||
| 
								 | 
							
								            typename,
							 | 
						||
| 
								 | 
							
								            prop_key,
							 | 
						||
| 
								 | 
							
								            type_info,
							 | 
						||
| 
								 | 
							
								            custom_props=custom_props,
							 | 
						||
| 
								 | 
							
								            custom_ignore=custom_ignore,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        arg_value = f"{prop_key}: typing.Optional[{typed}] = None"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        default_arglist.append(arg_value)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if max_props:
							 | 
						||
| 
								 | 
							
								        final_max_props = max_props - (1 if "children" in props else 0)
							 | 
						||
| 
								 | 
							
								        if len(default_arglist) > final_max_props:
							 | 
						||
| 
								 | 
							
								            default_arglist = default_arglist[:final_max_props]
							 | 
						||
| 
								 | 
							
								            docstring += (
							 | 
						||
| 
								 | 
							
								                "\n\n"
							 | 
						||
| 
								 | 
							
								                "Note: due to the large number of props for this component,\n"
							 | 
						||
| 
								 | 
							
								                "not all of them appear in the constructor signature, but\n"
							 | 
						||
| 
								 | 
							
								                "they may still be used as keyword arguments."
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    default_argtext += ",\n        ".join(default_arglist + ["**kwargs"])
							 | 
						||
| 
								 | 
							
								    nodes = collect_nodes({k: v for k, v in props.items() if k != "children"})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return dedent(
							 | 
						||
| 
								 | 
							
								        c.format(
							 | 
						||
| 
								 | 
							
								            typename=typename,
							 | 
						||
| 
								 | 
							
								            namespace=namespace,
							 | 
						||
| 
								 | 
							
								            filtered_props=filtered_props,
							 | 
						||
| 
								 | 
							
								            list_of_valid_wildcard_attr_prefixes=wildcard_prefixes,
							 | 
						||
| 
								 | 
							
								            list_of_valid_keys=list_of_valid_keys,
							 | 
						||
| 
								 | 
							
								            docstring=docstring,
							 | 
						||
| 
								 | 
							
								            default_argtext=default_argtext,
							 | 
						||
| 
								 | 
							
								            args=args,
							 | 
						||
| 
								 | 
							
								            argtext=argtext,
							 | 
						||
| 
								 | 
							
								            required_validation=required_validation,
							 | 
						||
| 
								 | 
							
								            children_props=nodes,
							 | 
						||
| 
								 | 
							
								            base_nodes=filter_base_nodes(nodes) + ["children"],
							 | 
						||
| 
								 | 
							
								            shapes="\n".join(shapes.get(typename, {}).values()),
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def generate_class_file(
							 | 
						||
| 
								 | 
							
								    typename,
							 | 
						||
| 
								 | 
							
								    props,
							 | 
						||
| 
								 | 
							
								    description,
							 | 
						||
| 
								 | 
							
								    namespace,
							 | 
						||
| 
								 | 
							
								    prop_reorder_exceptions=None,
							 | 
						||
| 
								 | 
							
								    max_props=None,
							 | 
						||
| 
								 | 
							
								    custom_typing_module="dash_prop_typing",
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """Generate a Python class file (.py) given a class string.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    typename
							 | 
						||
| 
								 | 
							
								    props
							 | 
						||
| 
								 | 
							
								    description
							 | 
						||
| 
								 | 
							
								    namespace
							 | 
						||
| 
								 | 
							
								    prop_reorder_exceptions
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    class_string = generate_class_string(
							 | 
						||
| 
								 | 
							
								        typename,
							 | 
						||
| 
								 | 
							
								        props,
							 | 
						||
| 
								 | 
							
								        description,
							 | 
						||
| 
								 | 
							
								        namespace,
							 | 
						||
| 
								 | 
							
								        prop_reorder_exceptions,
							 | 
						||
| 
								 | 
							
								        max_props,
							 | 
						||
| 
								 | 
							
								        custom_typing_module,
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    custom_imp = get_custom_imports(custom_typing_module)
							 | 
						||
| 
								 | 
							
								    custom_imp = custom_imp.get(typename) or custom_imp.get("*")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if custom_imp:
							 | 
						||
| 
								 | 
							
								        imports = import_string.format(
							 | 
						||
| 
								 | 
							
								            custom_imports="\n" + "\n".join(custom_imp) + "\n\n"
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        imports = import_string.format(custom_imports="")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    file_name = f"{typename:s}.py"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    file_path = os.path.join(namespace, file_name)
							 | 
						||
| 
								 | 
							
								    with open(file_path, "w", encoding="utf-8") as f:
							 | 
						||
| 
								 | 
							
								        f.write(imports)
							 | 
						||
| 
								 | 
							
								        f.write(class_string)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    print(f"Generated {file_name}")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def generate_imports(project_shortname, components):
							 | 
						||
| 
								 | 
							
								    with open(
							 | 
						||
| 
								 | 
							
								        os.path.join(project_shortname, "_imports_.py"), "w", encoding="utf-8"
							 | 
						||
| 
								 | 
							
								    ) as f:
							 | 
						||
| 
								 | 
							
								        component_imports = "\n".join(f"from .{x} import {x}" for x in components)
							 | 
						||
| 
								 | 
							
								        all_list = ",\n".join(f'    "{x}"' for x in components)
							 | 
						||
| 
								 | 
							
								        imports_string = f"{component_imports}\n\n__all__ = [\n{all_list}\n]"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        f.write(imports_string)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def generate_classes_files(project_shortname, metadata, *component_generators):
							 | 
						||
| 
								 | 
							
								    components = []
							 | 
						||
| 
								 | 
							
								    for component_path, component_data in metadata.items():
							 | 
						||
| 
								 | 
							
								        component_name = component_path.split("/")[-1].split(".")[0]
							 | 
						||
| 
								 | 
							
								        components.append(component_name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for generator in component_generators:
							 | 
						||
| 
								 | 
							
								            generator(
							 | 
						||
| 
								 | 
							
								                component_name,
							 | 
						||
| 
								 | 
							
								                component_data["props"],
							 | 
						||
| 
								 | 
							
								                component_data["description"],
							 | 
						||
| 
								 | 
							
								                project_shortname,
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return components
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def generate_class(
							 | 
						||
| 
								 | 
							
								    typename, props, description, namespace, prop_reorder_exceptions=None
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """Generate a Python class object given a class string.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    typename
							 | 
						||
| 
								 | 
							
								    props
							 | 
						||
| 
								 | 
							
								    description
							 | 
						||
| 
								 | 
							
								    namespace
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    string = generate_class_string(
							 | 
						||
| 
								 | 
							
								        typename, props, description, namespace, prop_reorder_exceptions
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    scope = {
							 | 
						||
| 
								 | 
							
								        "Component": Component,
							 | 
						||
| 
								 | 
							
								        "ComponentType": ComponentType,
							 | 
						||
| 
								 | 
							
								        "_explicitize_args": _explicitize_args,
							 | 
						||
| 
								 | 
							
								        "typing": typing,
							 | 
						||
| 
								 | 
							
								        "numbers": numbers,
							 | 
						||
| 
								 | 
							
								        "TypedDict": TypedDict,
							 | 
						||
| 
								 | 
							
								        "NotRequired": NotRequired,
							 | 
						||
| 
								 | 
							
								        "Literal": Literal,
							 | 
						||
| 
								 | 
							
								        "NumberType": typing.Union[
							 | 
						||
| 
								 | 
							
								            typing.SupportsFloat, typing.SupportsComplex, typing.SupportsInt
							 | 
						||
| 
								 | 
							
								        ],
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    # pylint: disable=exec-used
							 | 
						||
| 
								 | 
							
								    exec(string, scope)
							 | 
						||
| 
								 | 
							
								    result = scope[typename]
							 | 
						||
| 
								 | 
							
								    return result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def required_props(props):
							 | 
						||
| 
								 | 
							
								    """Pull names of required props from the props object.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    props: dict
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    list
							 | 
						||
| 
								 | 
							
								        List of prop names (str) that are required for the Component
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    return [prop_name for prop_name, prop in list(props.items()) if prop["required"]]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def create_docstring(
							 | 
						||
| 
								 | 
							
								    component_name,
							 | 
						||
| 
								 | 
							
								    props,
							 | 
						||
| 
								 | 
							
								    description,
							 | 
						||
| 
								 | 
							
								    prop_reorder_exceptions=None,
							 | 
						||
| 
								 | 
							
								    ignored_props=tuple(),
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """Create the Dash component docstring.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    component_name: str
							 | 
						||
| 
								 | 
							
								        Component name
							 | 
						||
| 
								 | 
							
								    props: dict
							 | 
						||
| 
								 | 
							
								        Dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    description: str
							 | 
						||
| 
								 | 
							
								        Component description
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    str
							 | 
						||
| 
								 | 
							
								        Dash component docstring
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    # Ensure props are ordered with children first
							 | 
						||
| 
								 | 
							
								    props = (
							 | 
						||
| 
								 | 
							
								        props
							 | 
						||
| 
								 | 
							
								        if (
							 | 
						||
| 
								 | 
							
								            prop_reorder_exceptions is not None
							 | 
						||
| 
								 | 
							
								            and component_name in prop_reorder_exceptions
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								        or (prop_reorder_exceptions is not None and "ALL" in prop_reorder_exceptions)
							 | 
						||
| 
								 | 
							
								        else reorder_props(props)
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    n = "n" if component_name[0].lower() in "aeiou" else ""
							 | 
						||
| 
								 | 
							
								    args = "\n".join(
							 | 
						||
| 
								 | 
							
								        create_prop_docstring(
							 | 
						||
| 
								 | 
							
								            prop_name=p,
							 | 
						||
| 
								 | 
							
								            type_object=prop["type"] if "type" in prop else prop["flowType"],
							 | 
						||
| 
								 | 
							
								            required=prop["required"],
							 | 
						||
| 
								 | 
							
								            description=prop["description"],
							 | 
						||
| 
								 | 
							
								            default=prop.get("defaultValue"),
							 | 
						||
| 
								 | 
							
								            indent_num=0,
							 | 
						||
| 
								 | 
							
								            is_flow_type="flowType" in prop and "type" not in prop,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								        for p, prop in filter_props(props, ignored_props).items()
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return (
							 | 
						||
| 
								 | 
							
								        f"A{n} {component_name} component.\n{description}\n\nKeyword arguments:\n{args}"
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def prohibit_events(props):
							 | 
						||
| 
								 | 
							
								    """Events have been removed. Raise an error if we see dashEvents or
							 | 
						||
| 
								 | 
							
								    fireEvents.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    props: dict
							 | 
						||
| 
								 | 
							
								        Dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    Raises
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    ?
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if "dashEvents" in props or "fireEvents" in props:
							 | 
						||
| 
								 | 
							
								        raise NonExistentEventException(
							 | 
						||
| 
								 | 
							
								            "Events are no longer supported by dash. Use properties instead, "
							 | 
						||
| 
								 | 
							
								            "eg `n_clicks` instead of a `click` event."
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def parse_wildcards(props):
							 | 
						||
| 
								 | 
							
								    """Pull out the wildcard attributes from the Component props.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    props: dict
							 | 
						||
| 
								 | 
							
								        Dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    list
							 | 
						||
| 
								 | 
							
								        List of Dash valid wildcard prefixes
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    list_of_valid_wildcard_attr_prefixes = []
							 | 
						||
| 
								 | 
							
								    for wildcard_attr in ["data-*", "aria-*"]:
							 | 
						||
| 
								 | 
							
								        if wildcard_attr in props:
							 | 
						||
| 
								 | 
							
								            list_of_valid_wildcard_attr_prefixes.append(wildcard_attr[:-1])
							 | 
						||
| 
								 | 
							
								    return list_of_valid_wildcard_attr_prefixes
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def reorder_props(props):
							 | 
						||
| 
								 | 
							
								    """If "children" is in props, then move it to the front to respect dash
							 | 
						||
| 
								 | 
							
								    convention, then 'id', then the remaining props sorted by prop name
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    props: dict
							 | 
						||
| 
								 | 
							
								        Dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    dict
							 | 
						||
| 
								 | 
							
								        Dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Constructing an OrderedDict with duplicate keys, you get the order
							 | 
						||
| 
								 | 
							
								    # from the first one but the value from the last.
							 | 
						||
| 
								 | 
							
								    # Doing this to avoid mutating props, which can cause confusion.
							 | 
						||
| 
								 | 
							
								    props1 = [("children", "")] if "children" in props else []
							 | 
						||
| 
								 | 
							
								    props2 = [("id", "")] if "id" in props else []
							 | 
						||
| 
								 | 
							
								    return OrderedDict(props1 + props2 + sorted(list(props.items())))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def filter_props(props, ignored_props=tuple()):
							 | 
						||
| 
								 | 
							
								    """Filter props from the Component arguments to exclude:
							 | 
						||
| 
								 | 
							
								        - Those without a "type" or a "flowType" field
							 | 
						||
| 
								 | 
							
								        - Those with arg.type.name in {'func', 'symbol', 'instanceOf'}
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    props: dict
							 | 
						||
| 
								 | 
							
								        Dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    dict
							 | 
						||
| 
								 | 
							
								        Filtered dictionary with {propName: propMetadata} structure
							 | 
						||
| 
								 | 
							
								    Examples
							 | 
						||
| 
								 | 
							
								    --------
							 | 
						||
| 
								 | 
							
								    ```python
							 | 
						||
| 
								 | 
							
								    prop_args = {
							 | 
						||
| 
								 | 
							
								        'prop1': {
							 | 
						||
| 
								 | 
							
								            'type': {'name': 'bool'},
							 | 
						||
| 
								 | 
							
								            'required': False,
							 | 
						||
| 
								 | 
							
								            'description': 'A description',
							 | 
						||
| 
								 | 
							
								            'flowType': {},
							 | 
						||
| 
								 | 
							
								            'defaultValue': {'value': 'false', 'computed': False},
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        'prop2': {'description': 'A prop without a type'},
							 | 
						||
| 
								 | 
							
								        'prop3': {
							 | 
						||
| 
								 | 
							
								            'type': {'name': 'func'},
							 | 
						||
| 
								 | 
							
								            'description': 'A function prop',
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    # filtered_prop_args is now
							 | 
						||
| 
								 | 
							
								    # {
							 | 
						||
| 
								 | 
							
								    #    'prop1': {
							 | 
						||
| 
								 | 
							
								    #        'type': {'name': 'bool'},
							 | 
						||
| 
								 | 
							
								    #        'required': False,
							 | 
						||
| 
								 | 
							
								    #        'description': 'A description',
							 | 
						||
| 
								 | 
							
								    #        'flowType': {},
							 | 
						||
| 
								 | 
							
								    #        'defaultValue': {'value': 'false', 'computed': False},
							 | 
						||
| 
								 | 
							
								    #    },
							 | 
						||
| 
								 | 
							
								    # }
							 | 
						||
| 
								 | 
							
								    filtered_prop_args = filter_props(prop_args)
							 | 
						||
| 
								 | 
							
								    ```
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    filtered_props = copy.deepcopy(props)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for arg_name, arg in list(filtered_props.items()):
							 | 
						||
| 
								 | 
							
								        if arg_name in ignored_props or ("type" not in arg and "flowType" not in arg):
							 | 
						||
| 
								 | 
							
								            filtered_props.pop(arg_name)
							 | 
						||
| 
								 | 
							
								            continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Filter out functions and instances --
							 | 
						||
| 
								 | 
							
								        # these cannot be passed from Python
							 | 
						||
| 
								 | 
							
								        if "type" in arg:  # These come from PropTypes
							 | 
						||
| 
								 | 
							
								            arg_type = arg["type"]["name"]
							 | 
						||
| 
								 | 
							
								            if arg_type in {"func", "symbol", "instanceOf"}:
							 | 
						||
| 
								 | 
							
								                filtered_props.pop(arg_name)
							 | 
						||
| 
								 | 
							
								        elif "flowType" in arg:  # These come from Flow & handled differently
							 | 
						||
| 
								 | 
							
								            arg_type_name = arg["flowType"]["name"]
							 | 
						||
| 
								 | 
							
								            if arg_type_name == "signature":
							 | 
						||
| 
								 | 
							
								                # This does the same as the PropTypes filter above, but "func"
							 | 
						||
| 
								 | 
							
								                # is under "type" if "name" is "signature" vs just in "name"
							 | 
						||
| 
								 | 
							
								                if "type" not in arg["flowType"] or arg["flowType"]["type"] != "object":
							 | 
						||
| 
								 | 
							
								                    filtered_props.pop(arg_name)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            raise ValueError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return filtered_props
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def fix_keywords(txt):
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    replaces javascript keywords true, false, null with Python keywords
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    fix_word = {"true": "True", "false": "False", "null": "None"}
							 | 
						||
| 
								 | 
							
								    for js_keyword, python_keyword in fix_word.items():
							 | 
						||
| 
								 | 
							
								        txt = txt.replace(js_keyword, python_keyword)
							 | 
						||
| 
								 | 
							
								    return txt
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# pylint: disable=too-many-arguments
							 | 
						||
| 
								 | 
							
								# pylint: disable=too-many-locals
							 | 
						||
| 
								 | 
							
								def create_prop_docstring(
							 | 
						||
| 
								 | 
							
								    prop_name,
							 | 
						||
| 
								 | 
							
								    type_object,
							 | 
						||
| 
								 | 
							
								    required,
							 | 
						||
| 
								 | 
							
								    description,
							 | 
						||
| 
								 | 
							
								    default,
							 | 
						||
| 
								 | 
							
								    indent_num,
							 | 
						||
| 
								 | 
							
								    is_flow_type=False,
							 | 
						||
| 
								 | 
							
								):
							 | 
						||
| 
								 | 
							
								    """Create the Dash component prop docstring.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    prop_name: str
							 | 
						||
| 
								 | 
							
								        Name of the Dash component prop
							 | 
						||
| 
								 | 
							
								    type_object: dict
							 | 
						||
| 
								 | 
							
								        react-docgen-generated prop type dictionary
							 | 
						||
| 
								 | 
							
								    required: bool
							 | 
						||
| 
								 | 
							
								        Component is required?
							 | 
						||
| 
								 | 
							
								    description: str
							 | 
						||
| 
								 | 
							
								        Dash component description
							 | 
						||
| 
								 | 
							
								    default: dict
							 | 
						||
| 
								 | 
							
								        Either None if a default value is not defined, or
							 | 
						||
| 
								 | 
							
								        dict containing the key 'value' that defines a
							 | 
						||
| 
								 | 
							
								        default value for the prop
							 | 
						||
| 
								 | 
							
								    indent_num: int
							 | 
						||
| 
								 | 
							
								        Number of indents to use for the context block
							 | 
						||
| 
								 | 
							
								        (creates 2 spaces for every indent)
							 | 
						||
| 
								 | 
							
								    is_flow_type: bool
							 | 
						||
| 
								 | 
							
								        Does the prop use Flow types? Otherwise, uses PropTypes
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    str
							 | 
						||
| 
								 | 
							
								        Dash component prop docstring
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    py_type_name = js_to_py_type(
							 | 
						||
| 
								 | 
							
								        type_object=type_object, is_flow_type=is_flow_type, indent_num=indent_num
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    indent_spacing = "  " * indent_num
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    default = default["value"] if default else ""
							 | 
						||
| 
								 | 
							
								    default = fix_keywords(default)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_required = "optional"
							 | 
						||
| 
								 | 
							
								    if required:
							 | 
						||
| 
								 | 
							
								        is_required = "required"
							 | 
						||
| 
								 | 
							
								    elif default and default not in ["None", "{}", "[]"]:
							 | 
						||
| 
								 | 
							
								        is_required = "default " + default.replace("\n", "")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # formats description
							 | 
						||
| 
								 | 
							
								    period = "." if description else ""
							 | 
						||
| 
								 | 
							
								    description = description.strip().strip(".").replace('"', r"\"") + period
							 | 
						||
| 
								 | 
							
								    desc_indent = indent_spacing + "    "
							 | 
						||
| 
								 | 
							
								    description = fill(
							 | 
						||
| 
								 | 
							
								        description,
							 | 
						||
| 
								 | 
							
								        initial_indent=desc_indent,
							 | 
						||
| 
								 | 
							
								        subsequent_indent=desc_indent,
							 | 
						||
| 
								 | 
							
								        break_long_words=False,
							 | 
						||
| 
								 | 
							
								        break_on_hyphens=False,
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    description = f"\n{description}" if description else ""
							 | 
						||
| 
								 | 
							
								    colon = ":" if description else ""
							 | 
						||
| 
								 | 
							
								    description = fix_keywords(description)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if "\n" in py_type_name:
							 | 
						||
| 
								 | 
							
								        # corrects the type
							 | 
						||
| 
								 | 
							
								        dict_or_list = "list of dicts" if py_type_name.startswith("list") else "dict"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # format and rewrite the intro to the nested dicts
							 | 
						||
| 
								 | 
							
								        intro1, intro2, dict_descr = py_type_name.partition("with keys:")
							 | 
						||
| 
								 | 
							
								        intro = f"`{prop_name}` is a {intro1}{intro2}"
							 | 
						||
| 
								 | 
							
								        intro = fill(
							 | 
						||
| 
								 | 
							
								            intro,
							 | 
						||
| 
								 | 
							
								            initial_indent=desc_indent,
							 | 
						||
| 
								 | 
							
								            subsequent_indent=desc_indent,
							 | 
						||
| 
								 | 
							
								            break_long_words=False,
							 | 
						||
| 
								 | 
							
								            break_on_hyphens=False,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # captures optional nested dict description and puts the "or" condition on a new line
							 | 
						||
| 
								 | 
							
								        if "| dict with keys:" in dict_descr:
							 | 
						||
| 
								 | 
							
								            dict_part1, dict_part2 = dict_descr.split(" |", 1)
							 | 
						||
| 
								 | 
							
								            dict_part2 = "".join([desc_indent, "Or", dict_part2])
							 | 
						||
| 
								 | 
							
								            dict_descr = f"{dict_part1}\n\n  {dict_part2}"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # ensures indent is correct if there is a second nested list of dicts
							 | 
						||
| 
								 | 
							
								        current_indent = dict_descr.lstrip("\n").find("-")
							 | 
						||
| 
								 | 
							
								        if current_indent == len(indent_spacing):
							 | 
						||
| 
								 | 
							
								            dict_descr = "".join(
							 | 
						||
| 
								 | 
							
								                "\n\n    " + line for line in dict_descr.splitlines() if line != ""
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            f"\n{indent_spacing}- {prop_name} ({dict_or_list}; {is_required}){colon}"
							 | 
						||
| 
								 | 
							
								            f"{description}"
							 | 
						||
| 
								 | 
							
								            f"\n\n{intro}{dict_descr}"
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    tn = f"{py_type_name}; " if py_type_name else ""
							 | 
						||
| 
								 | 
							
								    return f"\n{indent_spacing}- {prop_name} ({tn}{is_required}){colon}{description}"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def map_js_to_py_types_prop_types(type_object, indent_num):
							 | 
						||
| 
								 | 
							
								    """Mapping from the PropTypes js type object to the Python type."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def shape_or_exact():
							 | 
						||
| 
								 | 
							
								        return "dict with keys:\n" + "\n".join(
							 | 
						||
| 
								 | 
							
								            create_prop_docstring(
							 | 
						||
| 
								 | 
							
								                prop_name=prop_name,
							 | 
						||
| 
								 | 
							
								                type_object=prop,
							 | 
						||
| 
								 | 
							
								                required=prop["required"],
							 | 
						||
| 
								 | 
							
								                description=prop.get("description", ""),
							 | 
						||
| 
								 | 
							
								                default=prop.get("defaultValue"),
							 | 
						||
| 
								 | 
							
								                indent_num=indent_num + 2,
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            for prop_name, prop in type_object["value"].items()
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def array_of():
							 | 
						||
| 
								 | 
							
								        inner = js_to_py_type(type_object["value"])
							 | 
						||
| 
								 | 
							
								        if inner:
							 | 
						||
| 
								 | 
							
								            return "list of " + (
							 | 
						||
| 
								 | 
							
								                inner + "s"
							 | 
						||
| 
								 | 
							
								                if inner.split(" ")[0] != "dict"
							 | 
						||
| 
								 | 
							
								                else inner.replace("dict", "dicts", 1)
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        return "list"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def tuple_of():
							 | 
						||
| 
								 | 
							
								        elements = [js_to_py_type(element) for element in type_object["elements"]]
							 | 
						||
| 
								 | 
							
								        return f"list of {len(elements)} elements: [{', '.join(elements)}]"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return dict(
							 | 
						||
| 
								 | 
							
								        array=lambda: "list",
							 | 
						||
| 
								 | 
							
								        bool=lambda: "boolean",
							 | 
						||
| 
								 | 
							
								        number=lambda: "number",
							 | 
						||
| 
								 | 
							
								        string=lambda: "string",
							 | 
						||
| 
								 | 
							
								        object=lambda: "dict",
							 | 
						||
| 
								 | 
							
								        any=lambda: "boolean | number | string | dict | list",
							 | 
						||
| 
								 | 
							
								        element=lambda: "dash component",
							 | 
						||
| 
								 | 
							
								        node=lambda: "a list of or a singular dash component, string or number",
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.oneOf
							 | 
						||
| 
								 | 
							
								        enum=lambda: (
							 | 
						||
| 
								 | 
							
								            "a value equal to: "
							 | 
						||
| 
								 | 
							
								            + ", ".join(str(t["value"]) for t in type_object["value"])
							 | 
						||
| 
								 | 
							
								        ),
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.oneOfType
							 | 
						||
| 
								 | 
							
								        union=lambda: " | ".join(
							 | 
						||
| 
								 | 
							
								            js_to_py_type(subType)
							 | 
						||
| 
								 | 
							
								            for subType in type_object["value"]
							 | 
						||
| 
								 | 
							
								            if js_to_py_type(subType) != ""
							 | 
						||
| 
								 | 
							
								        ),
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.arrayOf
							 | 
						||
| 
								 | 
							
								        arrayOf=array_of,
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.objectOf
							 | 
						||
| 
								 | 
							
								        objectOf=lambda: (
							 | 
						||
| 
								 | 
							
								            "dict with strings as keys and values of type "
							 | 
						||
| 
								 | 
							
								            + js_to_py_type(type_object["value"])
							 | 
						||
| 
								 | 
							
								        ),
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.shape
							 | 
						||
| 
								 | 
							
								        shape=shape_or_exact,
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.exact
							 | 
						||
| 
								 | 
							
								        exact=shape_or_exact,
							 | 
						||
| 
								 | 
							
								        tuple=tuple_of,
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def map_js_to_py_types_flow_types(type_object):
							 | 
						||
| 
								 | 
							
								    """Mapping from the Flow js types to the Python type."""
							 | 
						||
| 
								 | 
							
								    return dict(
							 | 
						||
| 
								 | 
							
								        array=lambda: "list",
							 | 
						||
| 
								 | 
							
								        boolean=lambda: "boolean",
							 | 
						||
| 
								 | 
							
								        number=lambda: "number",
							 | 
						||
| 
								 | 
							
								        string=lambda: "string",
							 | 
						||
| 
								 | 
							
								        Object=lambda: "dict",
							 | 
						||
| 
								 | 
							
								        any=lambda: "bool | number | str | dict | list",
							 | 
						||
| 
								 | 
							
								        Element=lambda: "dash component",
							 | 
						||
| 
								 | 
							
								        Node=lambda: "a list of or a singular dash component, string or number",
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.oneOfType
							 | 
						||
| 
								 | 
							
								        union=lambda: " | ".join(
							 | 
						||
| 
								 | 
							
								            js_to_py_type(subType)
							 | 
						||
| 
								 | 
							
								            for subType in type_object["elements"]
							 | 
						||
| 
								 | 
							
								            if js_to_py_type(subType) != ""
							 | 
						||
| 
								 | 
							
								        ),
							 | 
						||
| 
								 | 
							
								        # Flow's Array type
							 | 
						||
| 
								 | 
							
								        Array=lambda: "list"
							 | 
						||
| 
								 | 
							
								        + (
							 | 
						||
| 
								 | 
							
								            f' of {js_to_py_type(type_object["elements"][0])}s'
							 | 
						||
| 
								 | 
							
								            if js_to_py_type(type_object["elements"][0]) != ""
							 | 
						||
| 
								 | 
							
								            else ""
							 | 
						||
| 
								 | 
							
								        ),
							 | 
						||
| 
								 | 
							
								        # React's PropTypes.shape
							 | 
						||
| 
								 | 
							
								        signature=lambda indent_num: (
							 | 
						||
| 
								 | 
							
								            "dict with keys:\n"
							 | 
						||
| 
								 | 
							
								            + "\n".join(
							 | 
						||
| 
								 | 
							
								                create_prop_docstring(
							 | 
						||
| 
								 | 
							
								                    prop_name=prop["key"],
							 | 
						||
| 
								 | 
							
								                    type_object=prop["value"],
							 | 
						||
| 
								 | 
							
								                    required=prop["value"]["required"],
							 | 
						||
| 
								 | 
							
								                    description=prop["value"].get("description", ""),
							 | 
						||
| 
								 | 
							
								                    default=prop.get("defaultValue"),
							 | 
						||
| 
								 | 
							
								                    indent_num=indent_num + 2,
							 | 
						||
| 
								 | 
							
								                    is_flow_type=True,
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								                for prop in type_object["signature"]["properties"]
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        ),
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def js_to_py_type(type_object, is_flow_type=False, indent_num=0):
							 | 
						||
| 
								 | 
							
								    """Convert JS types to Python types for the component definition.
							 | 
						||
| 
								 | 
							
								    Parameters
							 | 
						||
| 
								 | 
							
								    ----------
							 | 
						||
| 
								 | 
							
								    type_object: dict
							 | 
						||
| 
								 | 
							
								        react-docgen-generated prop type dictionary
							 | 
						||
| 
								 | 
							
								    is_flow_type: bool
							 | 
						||
| 
								 | 
							
								        Does the prop use Flow types? Otherwise, uses PropTypes
							 | 
						||
| 
								 | 
							
								    indent_num: int
							 | 
						||
| 
								 | 
							
								        Number of indents to use for the docstring for the prop
							 | 
						||
| 
								 | 
							
								    Returns
							 | 
						||
| 
								 | 
							
								    -------
							 | 
						||
| 
								 | 
							
								    str
							 | 
						||
| 
								 | 
							
								        Python type string
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    js_type_name = type_object["name"]
							 | 
						||
| 
								 | 
							
								    js_to_py_types = (
							 | 
						||
| 
								 | 
							
								        map_js_to_py_types_flow_types(type_object=type_object)
							 | 
						||
| 
								 | 
							
								        if is_flow_type
							 | 
						||
| 
								 | 
							
								        else map_js_to_py_types_prop_types(
							 | 
						||
| 
								 | 
							
								            type_object=type_object, indent_num=indent_num
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (
							 | 
						||
| 
								 | 
							
								        "computed" in type_object
							 | 
						||
| 
								 | 
							
								        and type_object["computed"]
							 | 
						||
| 
								 | 
							
								        or type_object.get("type", "") == "function"
							 | 
						||
| 
								 | 
							
								    ):
							 | 
						||
| 
								 | 
							
								        return ""
							 | 
						||
| 
								 | 
							
								    if js_type_name in js_to_py_types:
							 | 
						||
| 
								 | 
							
								        if js_type_name == "signature":  # This is a Flow object w/ signature
							 | 
						||
| 
								 | 
							
								            return js_to_py_types[js_type_name](indent_num)  # type: ignore[reportCallIssue]
							 | 
						||
| 
								 | 
							
								        # All other types
							 | 
						||
| 
								 | 
							
								        return js_to_py_types[js_type_name]()  # type: ignore[reportCallIssue]
							 | 
						||
| 
								 | 
							
								    return ""
							 |