Example #1
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))
Example #2
0
    def test_get_by_path(self):

        # should be able to traverse into a nested dict/list with key array

        figure = {'data': [{}, {'marker': {'color': ['red', 'blue']}}]}
        path = ('data', 1, 'marker', 'color')
        value = get_by_path(figure, path)
        expected_value = ['red', 'blue']
        self.assertEqual(value, expected_value)
Example #3
0
    def test_get_by_path(self):

        # should be able to traverse into a nested dict/list with key array

        figure = {"data": [{}, {"marker": {"color": ["red", "blue"]}}]}
        path = ("data", 1, "marker", "color")
        value = get_by_path(figure, path)
        expected_value = ["red", "blue"]
        self.assertEqual(value, expected_value)
Example #4
0
    def test_get_by_path(self):

        # should be able to traverse into a nested dict/list with key array

        figure = {'data': [{}, {'marker': {'color': ['red', 'blue']}}]}
        path = ('data', 1, 'marker', 'color')
        value = get_by_path(figure, path)
        expected_value = ['red', 'blue']
        self.assertEqual(value, expected_value)
Example #5
0
def get_attributes_dicts(object_name, parent_object_names=()):
    """
    Returns *all* attribute information given the context of parents.

    The response has the form:
    {
      ('some', 'path'): {},
      ('some', 'other', 'path'): {},
      ...
      'additional_attributes': {}
    }

    There may be any number of paths mapping to attribute dicts. There will be
    one attribute dict under 'additional_attributes' which will usually be
    empty.

    :param (str|unicode) object_name: The object name whose attributes we want.
    :param (list[str|unicode]) parent_object_names: Names of parent objects.
    :return: (dict)

    """
    object_dict = OBJECTS[object_name]

    # If we patched this object, we may have added hard-coded attrs.
    additional_attributes = object_dict['additional_attributes']

    # We should also one or more paths where attributes are defined.
    attribute_paths = list(object_dict['attribute_paths'])  # shallow copy

    # If we have parent_names, some of these attribute paths may be invalid.
    for parent_object_name in reversed(parent_object_names):
        if parent_object_name in ARRAYS:
            continue
        parent_object_dict = OBJECTS[parent_object_name]
        parent_attribute_paths = parent_object_dict['attribute_paths']
        for path in list(attribute_paths):
            if not _is_valid_sub_path(path, parent_attribute_paths):
                attribute_paths.remove(path)

    # We return a dict mapping paths to attributes. We also add in additional
    # attributes if defined.
    attributes_dicts = {
        path: utils.get_by_path(GRAPH_REFERENCE, path)
        for path in attribute_paths
    }
    attributes_dicts['additional_attributes'] = additional_attributes

    return attributes_dicts
Example #6
0
def get_attributes_dicts(object_name, parent_object_names=()):
    """
    Returns *all* attribute information given the context of parents.

    The response has the form:
    {
      ('some', 'path'): {},
      ('some', 'other', 'path'): {},
      ...
      'additional_attributes': {}
    }

    There may be any number of paths mapping to attribute dicts. There will be
    one attribute dict under 'additional_attributes' which will usually be
    empty.

    :param (str|unicode) object_name: The object name whose attributes we want.
    :param (list[str|unicode]) parent_object_names: Names of parent objects.
    :return: (dict)

    """
    object_dict = OBJECTS[object_name]

    # If we patched this object, we may have added hard-coded attrs.
    additional_attributes = object_dict['additional_attributes']

    # We should also one or more paths where attributes are defined.
    attribute_paths = list(object_dict['attribute_paths'])  # shallow copy

    # If we have parent_names, some of these attribute paths may be invalid.
    for parent_object_name in reversed(parent_object_names):
        if parent_object_name in ARRAYS:
            continue
        parent_object_dict = OBJECTS[parent_object_name]
        parent_attribute_paths = parent_object_dict['attribute_paths']
        for path in list(attribute_paths):
            if not _is_valid_sub_path(path, parent_attribute_paths):
                attribute_paths.remove(path)

    # We return a dict mapping paths to attributes. We also add in additional
    # attributes if defined.
    attributes_dicts = {path: utils.get_by_path(GRAPH_REFERENCE, path)
                  for path in attribute_paths}
    attributes_dicts['additional_attributes'] = additional_attributes

    return attributes_dicts
Example #7
0
    def test_numpy_integer_import(self):
        # should generate a figure with subplots of array and not throw a ValueError
        import numpy as np
        import plotly.graph_objects as go
        from plotly.subplots import make_subplots

        indices_rows = np.array([1], dtype=np.int)
        indices_cols = np.array([1], dtype=np.int)
        fig = make_subplots(rows=1, cols=1)
        fig.add_trace(go.Scatter(y=[1]),
                      row=indices_rows[0],
                      col=indices_cols[0])

        data_path = ("data", 0, "y")
        value = get_by_path(fig, data_path)
        expected_value = (1, )
        self.assertEqual(value, expected_value)
Example #8
0
def get_attributes_dicts(object_name, parent_object_names=()):
    """
    Returns *all* attribute information given the context of parents.

    The response has the form:
    {
      ('some', 'path'): {},
      ('some', 'other', 'path'): {},
      ...
      'additional_attributes': {}
    }

    There may be any number of paths mapping to attribute dicts. There will be
    one attribute dict under 'additional_attributes' which will usually be
    empty.

    :param (str|unicode) object_name: The object name whose attributes we want.
    :param (list[str|unicode]) parent_object_names: Names of parent objects.
    :return: (dict)

    """
    object_dict = OBJECTS[object_name]

    # If we patched this object, we may have added hard-coded attrs.
    additional_attributes = object_dict['additional_attributes']

    # We should also one or more paths where attributes are defined.
    attribute_paths = list(object_dict['attribute_paths'])  # shallow copy

    # Map frame 'data' and 'layout' to previously-defined figure attributes.
    # Examples of parent_object_names changes:
    #   ['figure', 'frames'] --> ['figure', 'frames']
    #   ['figure', 'frames', FRAME_NAME] --> ['figure']
    #   ['figure', 'frames', FRAME_NAME, 'data'] --> ['figure', 'data']
    #   ['figure', 'frames', FRAME_NAME, 'layout'] --> ['figure', 'layout']
    #   ['figure', 'frames', FRAME_NAME, 'foo'] -->
    #     ['figure', 'frames', FRAME_NAME, 'foo']
    #   [FRAME_NAME, 'layout'] --> ['figure', 'layout']
    if FRAME_NAME in parent_object_names:
        len_parent_object_names = len(parent_object_names)
        index = parent_object_names.index(FRAME_NAME)
        if len_parent_object_names == index + 1:
            if object_name in ('data', 'layout'):
                parent_object_names = ['figure', object_name]
        elif len_parent_object_names > index + 1:
            if parent_object_names[index + 1] in ('data', 'layout'):
                parent_object_names = (['figure'] +
                                       list(parent_object_names)[index + 1:])

    # If we have parent_names, some of these attribute paths may be invalid.
    for parent_object_name in reversed(parent_object_names):
        if parent_object_name in ARRAYS:
            continue
        parent_object_dict = OBJECTS[parent_object_name]
        parent_attribute_paths = parent_object_dict['attribute_paths']
        for path in list(attribute_paths):
            if not _is_valid_sub_path(path, parent_attribute_paths):
                attribute_paths.remove(path)

    # We return a dict mapping paths to attributes. We also add in additional
    # attributes if defined.
    attributes_dicts = {
        path: utils.get_by_path(GRAPH_REFERENCE, path)
        for path in attribute_paths
    }
    attributes_dicts['additional_attributes'] = additional_attributes

    return attributes_dicts
Example #9
0
def get_attributes_dicts(object_name, parent_object_names=()):
    """
    Returns *all* attribute information given the context of parents.

    The response has the form:
    {
      ('some', 'path'): {},
      ('some', 'other', 'path'): {},
      ...
      'additional_attributes': {}
    }

    There may be any number of paths mapping to attribute dicts. There will be
    one attribute dict under 'additional_attributes' which will usually be
    empty.

    :param (str|unicode) object_name: The object name whose attributes we want.
    :param (list[str|unicode]) parent_object_names: Names of parent objects.
    :return: (dict)

    """
    object_dict = OBJECTS[object_name]

    # If we patched this object, we may have added hard-coded attrs.
    additional_attributes = object_dict["additional_attributes"]

    # We should also one or more paths where attributes are defined.
    attribute_paths = list(object_dict["attribute_paths"])  # shallow copy

    # Map frame 'data' and 'layout' to previously-defined figure attributes.
    # Examples of parent_object_names changes:
    #   ['figure', 'frames'] --> ['figure', 'frames']
    #   ['figure', 'frames', FRAME_NAME] --> ['figure']
    #   ['figure', 'frames', FRAME_NAME, 'data'] --> ['figure', 'data']
    #   ['figure', 'frames', FRAME_NAME, 'layout'] --> ['figure', 'layout']
    #   ['figure', 'frames', FRAME_NAME, 'foo'] -->
    #     ['figure', 'frames', FRAME_NAME, 'foo']
    #   [FRAME_NAME, 'layout'] --> ['figure', 'layout']
    if FRAME_NAME in parent_object_names:
        len_parent_object_names = len(parent_object_names)
        index = parent_object_names.index(FRAME_NAME)
        if len_parent_object_names == index + 1:
            if object_name in ("data", "layout"):
                parent_object_names = ["figure", object_name]
        elif len_parent_object_names > index + 1:
            if parent_object_names[index + 1] in ("data", "layout"):
                parent_object_names = ["figure"] + list(parent_object_names)[index + 1 :]

    # If we have parent_names, some of these attribute paths may be invalid.
    for parent_object_name in reversed(parent_object_names):
        if parent_object_name in ARRAYS:
            continue
        parent_object_dict = OBJECTS[parent_object_name]
        parent_attribute_paths = parent_object_dict["attribute_paths"]
        for path in list(attribute_paths):
            if not _is_valid_sub_path(path, parent_attribute_paths):
                attribute_paths.remove(path)

    # We return a dict mapping paths to attributes. We also add in additional
    # attributes if defined.
    attributes_dicts = {path: utils.get_by_path(GRAPH_REFERENCE, path) for path in attribute_paths}
    attributes_dicts["additional_attributes"] = additional_attributes

    return attributes_dicts
Example #10
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))