示例#1
0
def _patch_objects():
    """Things like Layout, Figure, and Data need to be included."""
    layout_attribute_paths = []
    for node, path in utils.node_generator(GRAPH_REFERENCE):
        if any([key in path for key in GRAPH_REFERENCE["defs"]["metaKeys"]]):
            continue  # objects don't exist under nested meta keys

        if path and path[-1] == "layoutAttributes":
            layout_attribute_paths.append(path)

    for trace_name in TRACE_NAMES:
        OBJECTS[trace_name] = {
            "meta_paths": [("traces", trace_name)],
            "attribute_paths": [("traces", trace_name, "attributes")],
            "additional_attributes": {},
        }

    OBJECTS["layout"] = {
        "meta_paths": [("layout",)],
        "attribute_paths": layout_attribute_paths,
        "additional_attributes": {},
    }

    figure_attributes = {
        "layout": {"role": "object"},
        "data": {"role": "object", "_isLinkedToArray": True},
        "frames": {"role": "object", "_isLinkedToArray": True},
    }
    OBJECTS["figure"] = {"meta_paths": [], "attribute_paths": [], "additional_attributes": figure_attributes}
示例#2
0
def _patch_objects():
    """Things like Layout, Figure, and Data need to be included."""
    layout_attribute_paths = []
    for node, path in utils.node_generator(GRAPH_REFERENCE):
        if any([key in path for key in GRAPH_REFERENCE['defs']['metaKeys']]):
            continue  # objects don't exist under nested meta keys

        if path and path[-1] == 'layoutAttributes':
            layout_attribute_paths.append(path)

    for trace_name in TRACE_NAMES:
        OBJECTS[trace_name] = {
            'meta_paths': [('traces', trace_name)],
            'attribute_paths': [('traces', trace_name, 'attributes')],
            'additional_attributes': {}
        }

    OBJECTS['layout'] = {'meta_paths': [('layout', )],
                         'attribute_paths': layout_attribute_paths,
                         'additional_attributes': {}}

    figure_attributes = {'layout': {'role': 'object'},
                         'data': {'role': 'object', '_isLinkedToArray': True}}
    OBJECTS['figure'] = {'meta_paths': [],
                         'attribute_paths': [],
                         'additional_attributes': figure_attributes}
示例#3
0
    def assert_dict_equal(self, d1, d2, msg=None):
        """
        Uses `np.allclose()` on number arrays.

        :raises: (AssertionError) Using TestCase's self.failureException

        """
        self.assertIsInstance(d1, dict, "First argument is not a dictionary")
        self.assertIsInstance(d2, dict, "Second argument is not a dictionary")

        for node, path in node_generator(d1):

            # first check that this sub-dict is contained in both dicts
            try:
                comp_node = get_by_path(d2, path)
            except (KeyError, IndexError):
                standard_msg = "Path {} exists in dict 1, but not dict 2.".format(
                    path)
                self.fail(self._formatMessage(msg, standard_msg))
            self.assertIsInstance(
                comp_node, dict,
                "Value at path {} is not a dict.".format(path))

            # check that each key in the first is contained in the second
            for key, val in node.items():
                if isinstance(val, dict):
                    continue  # this gets tested as its own node

                # check that the values at this key are equal
                val_path = path + (key, )
                try:
                    comp_val = comp_node[key]
                except KeyError:
                    standard_msg = "Path {} exists in dict 1, but not dict 2.".format(
                        self._format_path(val_path))
                    self.fail(self._formatMessage(msg, standard_msg))

                if isinstance(val, np.ndarray) or isinstance(
                        comp_val, np.ndarray):
                    if np.array_equal(val, comp_val):
                        continue
                elif val == comp_val:
                    continue

                if is_num_list(val) and is_num_list(comp_val):
                    if np.allclose(val, comp_val):
                        continue

                standard_msg = ("Value comparison failed at path {}.\n"
                                "{} != {}".format(self._format_path(val_path),
                                                  val, comp_val))
                self.fail(self._formatMessage(msg, standard_msg))

            # finally, check that keys in the second are in the first
            for key in comp_node:
                val_path = path + (key, )
                if key not in node:
                    standard_msg = "Path {} exists in dict 2, but not dict 1.".format(
                        self._format_path(val_path))
                    self.fail(self._formatMessage(msg, standard_msg))
示例#4
0
    def _make_all_nodes_and_paths(self):
        all_nodes = list(node_generator(self['layout']))

        # remove path 'second' as it's always an empty box
        all_paths = []
        for node in all_nodes:
            all_paths.append(node[1])
        path_second = ('second',)
        if path_second in all_paths:
            all_paths.remove(path_second)
        return all_nodes, all_paths
    def _make_all_nodes_and_paths(self):
        all_nodes = list(node_generator(self['layout']))

        # remove path 'second' as it's always an empty box
        all_paths = []
        for node in all_nodes:
            all_paths.append(node[1])
        path_second = ('second', )
        if path_second in all_paths:
            all_paths.remove(path_second)
        return all_nodes, all_paths
示例#6
0
    def _make_all_nodes_and_paths(self):
        from plotly.utils import node_generator

        all_nodes = list(node_generator(self["layout"]))
        all_nodes.sort(key=lambda x: x[1])

        # remove path 'second' as it's always an empty box
        all_paths = [node[1] for node in all_nodes]
        path_second = ("second", )
        if path_second in all_paths:
            all_paths.remove(path_second)
        return all_nodes, all_paths
示例#7
0
def _get_objects():
    """
    Create a reorganization of graph reference which organizes by object name.

    Each object can have *many* different definitions in the graph reference.
    These possibilities get narrowed down when we have contextual information
    about parent objects. For instance, Marker in Scatter has a different
    definition than Marker in Pie. However, we need Marker, Scatter, and Pie
    to exist on their own as well.

    Each value has the form:
    {
        'meta_paths': [],
        'attribute_paths': [],
        'additional_attributes': {}
    }

    * meta_paths describes the top-most path where this object is defined
    * attribute_paths describes all the locations where attributes exist
    * additional_attributes can be used to hard-code (patch) the plot schema

    :return: (dict)

    """
    objects = {}
    for node, path in utils.node_generator(GRAPH_REFERENCE):

        if any([key in path for key in GRAPH_REFERENCE['defs']['metaKeys']]):
            continue  # objects don't exist under nested meta keys
        if node.get('role') != 'object':
            continue
        if 'items' in node:
            continue

        object_name = path[-1]
        if object_name not in objects:
            objects[object_name] = {
                'meta_paths': [],
                'attribute_paths': [],
                'additional_attributes': {}
            }

        if node.get('attributes'):
            objects[object_name]['attribute_paths'].append(path +
                                                           ('attributes', ))
        else:
            objects[object_name]['attribute_paths'].append(path)

        objects[object_name]['meta_paths'].append(path)

    return objects
    def _compute_box_ids(self):
        box_ids_to_path = {}
        all_nodes = list(node_generator(self['layout']))

        for node in all_nodes:
            if (node[1] != () and node[0]['type'] == 'box'
                    and node[0]['boxType'] != 'empty'):
                try:
                    max_id = max(box_ids_to_path.keys())
                except ValueError:
                    max_id = 0
                box_ids_to_path[max_id + 1] = node[1]

        return box_ids_to_path
示例#9
0
    def _make_all_nodes_and_paths(self):
        from plotly.utils import node_generator

        all_nodes = list(node_generator(self['layout']))
        all_nodes.sort(key=lambda x: x[1])

        # remove path 'second' as it's always an empty box
        all_paths = []
        for node in all_nodes:
            all_paths.append(node[1])
        path_second = ('second',)
        if path_second in all_paths:
            all_paths.remove(path_second)
        return all_nodes, all_paths
示例#10
0
    def _compute_box_ids(self):
        box_ids_to_path = {}
        all_nodes = list(node_generator(self['layout']))
        all_nodes.sort(key=lambda x: x[1])
        for node in all_nodes:
            if (node[1] != () and node[0]['type'] == 'box'
                    and node[0]['boxType'] != 'empty'):
                try:
                    max_id = max(box_ids_to_path.keys())
                except ValueError:
                    max_id = 0
                box_ids_to_path[max_id + 1] = node[1]

        return box_ids_to_path
示例#11
0
def _get_objects():
    """
    Create a reorganization of graph reference which organizes by object name.

    Each object can have *many* different definitions in the graph reference.
    These possibilities get narrowed down when we have contextual information
    about parent objects. For instance, Marker in Scatter has a different
    definition than Marker in Pie. However, we need Marker, Scatter, and Pie
    to exist on their own as well.

    Each value has the form:
    {
        'meta_paths': [],
        'attribute_paths': [],
        'additional_attributes': {}
    }

    * meta_paths describes the top-most path where this object is defined
    * attribute_paths describes all the locations where attributes exist
    * additional_attributes can be used to hard-code (patch) the plot schema

    :return: (dict)

    """
    objects = {}
    for node, path in utils.node_generator(GRAPH_REFERENCE):

        if any([key in path for key in GRAPH_REFERENCE['defs']['metaKeys']]):
            continue  # objects don't exist under nested meta keys
        if node.get('role') != 'object':
            continue
        if 'items' in node:
            continue

        object_name = path[-1]
        if object_name not in objects:
            objects[object_name] = {'meta_paths': [], 'attribute_paths': [],
                                    'additional_attributes': {}}

        if node.get('attributes'):
            objects[object_name]['attribute_paths'].append(
                path + ('attributes', )
            )
        else:
            objects[object_name]['attribute_paths'].append(path)

        objects[object_name]['meta_paths'].append(path)

    return objects
示例#12
0
    def _compute_box_ids(self):
        from plotly.utils import node_generator

        box_ids_to_path = {}
        all_nodes = list(node_generator(self["layout"]))
        all_nodes.sort(key=lambda x: x[1])
        for node in all_nodes:
            if (node[1] != () and node[0]["type"] == "box"
                    and node[0]["boxType"] != "empty"):
                try:
                    max_id = max(box_ids_to_path.keys())
                except ValueError:
                    max_id = 0
                box_ids_to_path[max_id + 1] = node[1]

        return box_ids_to_path
示例#13
0
    def test_node_generator(self):

        # should generate a (node, path) pair for each dict in a dict

        node4 = {'h': 5}
        node3 = {'g': 7}
        node2 = {'e': node3}
        node1 = {'c': node2, 'd': ['blah']}
        node0 = {'a': node1, 'b': 8}

        expected_node_path_tuples = [(node0, ()), (node1, ('a', )),
                                     (node2, ('a', 'c')),
                                     (node3, ('a', 'c', 'e')),
                                     (node4, ('a', 'c', 'f'))]
        for i, item in enumerate(node_generator(node0)):
            self.assertEqual(item, expected_node_path_tuples[i])
示例#14
0
    def test_node_generator(self):

        # should generate a (node, path) pair for each dict in a dict

        node4 = {'h': 5}
        node3 = {'g': 7}
        node2 = {'e': node3}
        node1 = {'c': node2, 'd': ['blah']}
        node0 = {'a': node1, 'b': 8}

        expected_node_path_tuples = [
            (node0, ()),
            (node1, ('a',)),
            (node2, ('a', 'c')),
            (node3, ('a', 'c', 'e')),
            (node4, ('a', 'c', 'f'))
        ]
        for i, item in enumerate(node_generator(node0)):
            self.assertEqual(item, expected_node_path_tuples[i])
示例#15
0
    def test_node_generator(self):

        # should generate a (node, path) pair for each dict in a dict

        node4 = {"h": 5}
        node3 = {"g": 7}
        node2 = {"e": node3}
        node1 = {"c": node2, "d": ["blah"]}
        node0 = {"a": node1, "b": 8}

        expected_node_path_tuples = [
            (node0, ()),
            (node1, ("a",)),
            (node2, ("a", "c")),
            (node3, ("a", "c", "e")),
            (node4, ("a", "c", "f")),
        ]
        for i, item in enumerate(node_generator(node0)):
            self.assertEqual(item, expected_node_path_tuples[i])
示例#16
0
def _get_arrays():
    """Very few arrays, but this dict is the complement of OBJECTS."""
    arrays = {}
    for node, path in utils.node_generator(GRAPH_REFERENCE):

        if any([key in path for key in GRAPH_REFERENCE['defs']['metaKeys']]):
            continue  # objects don't exist under nested meta keys
        if node.get('role') != 'object':
            continue
        if 'items' not in node:
            continue

        object_name = path[-1]
        if object_name not in arrays:
            items = node['items']

            # If items is a dict, it's anyOf them.
            if isinstance(items, dict):
                item_names = list(items.keys())
            else:
                item_names = [object_name[:-1]]
            arrays[object_name] = {'meta_paths': [path], 'items': item_names}

    return arrays
示例#17
0
def _get_arrays():
    """Very few arrays, but this dict is the complement of OBJECTS."""
    arrays = {}
    for node, path in utils.node_generator(GRAPH_REFERENCE):

        if any([key in path for key in GRAPH_REFERENCE['defs']['metaKeys']]):
            continue  # objects don't exist under nested meta keys
        if node.get('role') != 'object':
            continue
        if 'items' not in node:
            continue

        object_name = path[-1]
        if object_name not in arrays:
            items = node['items']

            # If items is a dict, it's anyOf them.
            if isinstance(items, dict):
                item_names = list(items.keys())
            else:
                item_names = [object_name[:-1]]
            arrays[object_name] = {'meta_paths': [path], 'items': item_names}

    return arrays
示例#18
0
    def assert_dict_equal(self, d1, d2, msg=None):
        """
        Uses `np.allclose()` on number arrays.

        :raises: (AssertionError) Using TestCase's self.failureException

        """
        self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
        self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')

        for node, path in node_generator(d1):

            # first check that this sub-dict is contained in both dicts
            try:
                comp_node = get_by_path(d2, path)
            except (KeyError, IndexError):
                standard_msg = (
                    'Path {} exists in dict 1, but not dict 2.'
                    .format(path)
                )
                self.fail(self._formatMessage(msg, standard_msg))
            self.assertIsInstance(
                comp_node, dict, 'Value at path {} is not a dict.'.format(path)
            )

            # check that each key in the first is contained in the second
            for key, val in node.items():
                if isinstance(val, dict):
                    continue  # this gets tested as its own node

                # check that the values at this key are equal
                val_path = path + (key, )
                try:
                    comp_val = comp_node[key]
                except KeyError:
                    standard_msg = (
                        'Path {} exists in dict 1, but not dict 2.'
                        .format(self._format_path(val_path))
                    )
                    self.fail(self._formatMessage(msg, standard_msg))

                if (isinstance(val, np.ndarray) or
                        isinstance(comp_val, np.ndarray)):
                    if np.array_equal(val, comp_val):
                        continue
                elif val == comp_val:
                    continue

                if is_num_list(val) and is_num_list(comp_val):
                    if np.allclose(val, comp_val):
                        continue

                standard_msg = (
                    'Value comparison failed at path {}.\n'
                    '{} != {}'
                    .format(self._format_path(val_path), val, comp_val)
                )
                self.fail(self._formatMessage(msg, standard_msg))

            # finally, check that keys in the second are in the first
            for key in comp_node:
                val_path = path + (key, )
                if key not in node:
                    standard_msg = (
                        'Path {} exists in dict 2, but not dict 1.'
                        .format(self._format_path(val_path))
                    )
                    self.fail(self._formatMessage(msg, standard_msg))