Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong diff in case of dictionary has dotted keys in ignore in dictdiffer. #107

Closed
jyoti-arora1991 opened this issue May 30, 2018 · 2 comments

Comments

@jyoti-arora1991
Copy link

jyoti-arora1991 commented May 30, 2018

Issue occurring on dictdiffer-0.7.1.

Lets take two dictionaries:

config_dict = OrderedDict([('address', 'devops011-slv-01.gvs.ggn'),('nifi.zookeeper.session.timeout', '3 secs')])

ref_dict = OrderedDict([('address', 'devops011-slv-01.gvs.ggn'),('nifi.zookeeper.session.timeout', '4 secs')])

list(diff(config_dict, ref_dict,ignore=set(['nifi.zookeeper.session.timeout'])))

Output for above is:

[('change', ['nifi.zookeeper.session.timeout'], ('3 secs', '4 secs'))]

seems like ignore functionality is not working when we pass dotted key in ignore set.

@yoyonel
Copy link
Contributor

yoyonel commented Feb 23, 2019

I write a fix/patch to workaround this problem: feature/Issue#107

My solution is to provide a function to generate raw ignored keys.

I define a RAW_IGNORE_KEY_TOKEN to generate (prefix) raw ignored keys (in utils.py).
I use this functionnality in diff function for updating elements in ignore list keys:

if isinstance(ignore, Iterable):
        def _unmake_raw_ignore_key(key):
            return key[len(RAW_IGNORE_KEY_TOKEN):]

        def _is_raw_ignore_key(key):
            return key.startswith(RAW_IGNORE_KEY_TOKEN)

        def _process_ignore_value(value):
            if isinstance(value, int):
                return value,
            elif isinstance(value, list):
                return tuple(value)
            elif isinstance(value, string_types) and _is_raw_ignore_key(value):
                return _unmake_raw_ignore_key(value),
            return value

        ignore = type(ignore)(_process_ignore_value(value) for value in ignore)

Usage in unittest:

def test_ignore_dotted_key_disable(self):
        key_to_ignore = u'nifi.zookeeper.session.timeout'
        config_dict = OrderedDict(
            [('address', 'devops011-slv-01.gvs.ggn'),
             (key_to_ignore, '3 secs')])

        ref_dict = OrderedDict(
            [('address', 'devops011-slv-01.gvs.ggn'),
             (key_to_ignore, '4 secs')])

        assert len(
            list(diff(config_dict, ref_dict,
                      ignore=[make_raw_ignore_key(key_to_ignore)]))) == 0

@jirikuncar Sound good for you ? (if yes, i can PR my branch)

@yoyonel
Copy link
Contributor

yoyonel commented Feb 23, 2019

A simpler (better) approach with simple custom type to indicate dotted ignore key: feature/Issue#107_oo

Custom type in utils.py:

class DottedIgnoreKey(str):
    """Custom type to specify dotted ignore key.

    This custom type help to desactivate dotted interpretation.
    """

    pass

Using in diff function in init.py:

def _process_ignore_value(value):
            if isinstance(value, int):
                return value,
            elif isinstance(value, list):
                return tuple(value)
            elif isinstance(value, DottedIgnoreKey):
                return str(value),
            return value

and finally in unit test test_dictdiffer.py:

def test_ignore_dotted_ignore_key(self):
        key_to_ignore = u'nifi.zookeeper.session.timeout'
        config_dict = OrderedDict(
            [('address', 'devops011-slv-01.gvs.ggn'),
             (key_to_ignore, '3 secs')])

        ref_dict = OrderedDict(
            [('address', 'devops011-slv-01.gvs.ggn'),
             (key_to_ignore, '4 secs')])

        assert len(
            list(diff(config_dict, ref_dict,
                      ignore=[DottedIgnoreKey(key_to_ignore)]))) == 0

Work fine with minimal modifications impact in code base :-D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants