deepdiff icon indicating copy to clipboard operation
deepdiff copied to clipboard

8.1.0

Open seperman opened this issue 1 year ago • 1 comments

  • Removing deprecated lines from setup.py
  • Fixes __slots__ comparison when the attribute doesn't exist.
  • Relaxing orderly-set reqs

seperman avatar Sep 11 '24 05:09 seperman

Codecov Report

Attention: Patch coverage is 93.93939% with 2 lines in your changes missing coverage. Please review.

Project coverage is 96.52%. Comparing base (6d8a4c7) to head (32d60a9).

Files with missing lines Patch % Lines
deepdiff/deephash.py 66.66% 2 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #483      +/-   ##
==========================================
- Coverage   96.70%   96.52%   -0.19%     
==========================================
  Files          14       14              
  Lines        3946     3971      +25     
==========================================
+ Hits         3816     3833      +17     
- Misses        130      138       +8     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar Sep 12 '24 21:09 codecov[bot]

Hi @artemisart Thanks for reviewing! Sorry I was too busy. I'm going to make a release over the weekend.

seperman avatar Dec 06 '24 19:12 seperman

Hello!

I'm patching this branch in Debian to have deepdiff workin in python3.13. I have these tests failing. I'm didn't check in depth if is an error on my setup, or perhaps is something that can help you in something.

=================================== FAILURES ===================================
___________ TestDeltaCompareFunc.test_list_of_alphabet_and_its_delta ___________

self = <tests.test_delta.TestDeltaCompareFunc object at 0x7f83493da1e0>

    def test_list_of_alphabet_and_its_delta(self):
        l1 = "A B C D E F G D H".split()
        l2 = "B C X D H Y Z".split()
        diff = DeepDiff(l1, l2)
    
        # Problem: The index of values_changed should be either all for AFTER removals or BEFORE removals.
        # What we have here is that F & G transformation to Y and Z is not compatible with A and E removal
        # it is really meant for the removals to happen first, and then have indexes in L2 for values changing
        # rather than indexes in L1. Here what we need to have is:
        # A B C D E F G D H
        # A B C-X-E
        # B C D F G D H  # removal
    
        # What we really need is to report is as it is in difflib for delta specifically:
        # A B C D E F G D H
        # B C D E F G D H     delete    t1[0:1] --> t2[0:0]    ['A'] --> []
        # B C D E F G D H     equal     t1[1:3] --> t2[0:2] ['B', 'C'] --> ['B', 'C']
        # B C X D H           replace   t1[3:7] --> t2[2:3] ['D', 'E', 'F', 'G'] --> ['X']
        # B C X D H           equal     t1[7:9] --> t2[3:5] ['D', 'H'] --> ['D', 'H']
        # B C X D H Y Z       insert    t1[9:9] --> t2[5:7]       [] --> ['Y', 'Z']
    
        # So in this case, it needs to also include information about what stays equal in the delta
        # NOTE: the problem is that these operations need to be performed in a specific order.
        # DeepDiff removes that order and just buckets all insertions vs. replace vs. delete in their own buckets.
        # For times that we use Difflib, we may want to keep the information for the array_change key
        # just for the sake of delta, but not for reporting in deepdiff itself.
        # that way we can re-apply the changes as they were reported in delta.
    
        delta = Delta(diff)
        assert l2 == l1 + delta
        with pytest.raises(ValueError) as exc_info:
            l1 == l2 - delta
        assert "Please recreate the delta with bidirectional=True" == str(exc_info.value)
    
        delta2 = Delta(diff, bidirectional=True)
        assert l2 == l1 + delta2
        assert l1 == l2 - delta2
    
        dump = Delta(diff, bidirectional=True).dumps()
        delta3 = Delta(dump, bidirectional=True)
    
        assert l2 == l1 + delta3
        assert l1 == l2 - delta3
    
        dump4 = Delta(diff, bidirectional=True, serializer=json_dumps).dumps()
>       delta4 = Delta(dump4, bidirectional=True, deserializer=json_loads)

tests/test_delta.py:2440: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
deepdiff/delta.py:130: in __init__
    self.diff = _deserializer(diff, safe_to_import=safe_to_import)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = '{"values_changed": {"root[3]": {"new_value": "X", "old_value": "D", "new_path": "root[2]"}, "root[5]": {"new_value": ...3, 7, 2, 3, ["D", "E", "F", "G"], ["X"]], ["equal", 7, 9, 3, 5, null, null], ["insert", 9, 9, 5, 7, [], ["Y", "Z"]]]}}'
safe_to_import = None

    def _deserializer(obj, safe_to_import=None):
        result = deserializer(obj)
        if result.get('_iterable_opcodes'):
            _iterable_opcodes = {}
            for path, op_codes in result['_iterable_opcodes'].items():
                _iterable_opcodes[path] = []
                for op_code in op_codes:
                    _iterable_opcodes[path].append(
>                       Opcode(
                            **op_code
                        )
                    )
E                   TypeError: deepdiff.helper.Opcode() argument after ** must be a mapping, not list

deepdiff/delta.py:102: TypeError
___ TestDeepDiffText.test_exclude_path_when_prefix_of_exclude_path_matches1 ____

self = <tests.test_diff_text.TestDeepDiffText object at 0x7f834934f440>

    def test_exclude_path_when_prefix_of_exclude_path_matches1(self):
        diff = DeepDiff({}, {'foo': '', 'bar': ''}, exclude_paths=['foo', 'bar'])
>       assert not diff
E       AssertionError: assert not {'values_changed': {'root': {'new_value': {'foo': '', 'bar': ''}, 'old_value': {}}}}

tests/test_diff_text.py:1555: AssertionError
_____________________ TestDeepDiffText.test_bad_attribute ______________________

self = <tests.test_diff_text.TestDeepDiffText object at 0x7f8349355c70>

    def test_bad_attribute(self):
        class Bad:
            __slots__ = ['x', 'y']
    
            def __getattr__(self, key):
                raise AttributeError("Bad item")
    
            def __str__(self):
                return "Bad Object"
    
        t1 = Bad()
        t2 = Bad()
    
        ddiff = DeepDiff(t1, t2)
        result = {'unprocessed': ['root: Bad Object and Bad Object']}
>       assert result == ddiff
E       AssertionError: assert {'unprocessed... Bad Object']} == {}
E         
E         Left contains 1 more item:
E         {'unprocessed': ['root: Bad Object and Bad Object']}
E         Use -v to get more diff

tests/test_diff_text.py:1791: AssertionError
_________ TestDeepDiffText.test_group_by_with_none_key_and_ignore_case _________

self = <tests.test_diff_text.TestDeepDiffText object at 0x7f8349356570>

    def test_group_by_with_none_key_and_ignore_case(self):
        """Test that group_by works with None keys when ignore_string_case is True"""
        dict1 = [{'txt_field': 'FULL_NONE', 'group_id': None}, {'txt_field': 'FULL', 'group_id': 'a'}]
        dict2 = [{'txt_field': 'PARTIAL_NONE', 'group_id': None}, {'txt_field': 'PARTIAL', 'group_id': 'a'}]
    
>       diff = DeepDiff(
            dict1,
            dict2,
            ignore_order=True,
            group_by='group_id',
            ignore_string_case=True
        )

tests/test_diff_text.py:2230: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
deepdiff/diff.py:332: in __init__
    self._diff(root, parents_ids=frozenset({id(t1)}), _original_type=_original_type)
deepdiff/diff.py:1669: in _diff
    self._diff_dict(level, parents_ids, local_tree=local_tree)
deepdiff/diff.py:605: in _diff_dict
    t1_clean_to_keys = self._get_clean_to_keys_mapping(keys=t1_keys, level=level)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {}, keys = [None, 'a']
level = <root t1:{None: {'txt...}, t2:{None: {'txt...}>

    def _get_clean_to_keys_mapping(self, keys, level):
        """
        Get a dictionary of cleaned value of keys to the keys themselves.
        This is mainly used to transform the keys when the type changes of keys should be ignored.
    
        TODO: needs also some key conversion for groups of types other than the built-in strings and numbers.
        """
        result = dict_()
        for key in keys:
            if self.ignore_string_type_changes and isinstance(key, bytes):
                clean_key = key.decode('utf-8')
            elif self.use_enum_value and isinstance(key, Enum):
                clean_key = key.value
            elif isinstance(key, numbers):
                type_ = "number" if self.ignore_numeric_type_changes else key.__class__.__name__
                clean_key = self.number_to_string(key, significant_digits=self.significant_digits,
                                                  number_format_notation=self.number_format_notation)
                clean_key = KEY_TO_VAL_STR.format(type_, clean_key)
            else:
                clean_key = key
            if self.ignore_string_case:
>               clean_key = clean_key.lower()
E               AttributeError: 'NoneType' object has no attribute 'lower'

deepdiff/diff.py:560: AttributeError
___________ TestDeepDiffText.test_affected_root_keys_when_dict_empty ___________

self = <tests.test_diff_text.TestDeepDiffText object at 0x7f8349356750>

    def test_affected_root_keys_when_dict_empty(self):
        diff = DeepDiff({}, {1:1, 2:2}, threshold_to_diff_deeper=0)
        assert [1, 2] == diff.affected_root_keys
    
        diff2 = DeepDiff({}, {1:1, 2:2})
>       assert [] == diff2.affected_root_keys
E       assert [] == [not present]
E         
E         Right contains one more item: not present
E         Use -v to get more diff

tests/test_diff_text.py:2251: AssertionError
_________________________ TestDeepHashPrep.test_polars _________________________

self = <tests.test_hash.TestDeepHashPrep object at 0x7f8349367530>

    def test_polars(self):
>       import polars as pl
E       ModuleNotFoundError: No module named 'polars'

tests/test_hash.py:795: ModuleNotFoundError
_________ TestSerialization.test_serialization_text_force_builtin_json _________

self = <tests.test_serialization.TestSerialization object at 0x7f83489e9d90>

    def test_serialization_text_force_builtin_json(self):
        ddiff = DeepDiff(t1, t2)
>       with pytest.raises(TypeError) as excinfo:
E       Failed: DID NOT RAISE <class 'TypeError'>

tests/test_serialization.py:52: Failed
_______________ TestDeepDiffPretty.test_namedtuple_seriazliation _______________

self = <tests.test_serialization.TestDeepDiffPretty object at 0x7f8348a291c0>

    def test_namedtuple_seriazliation(self):
        op_code = Opcode(tag="replace", t1_from_index=0, t1_to_index=1, t2_from_index=10, t2_to_index=20)
        serialized = json_dumps(op_code)
        expected = '{"tag":"replace","t1_from_index":0,"t1_to_index":1,"t2_from_index":10,"t2_to_index":20,"old_values":null,"new_values":null}'
>       assert serialized == expected
E       assert '["replace", ..., null, null]' == '{"tag":"repl...values":null}'
E         
E         - {"tag":"replace","t1_from_index":0,"t1_to_index":1,"t2_from_index":10,"t2_to_index":20,"old_values":null,"new_values":null}
E         + ["replace", 0, 1, 10, 20, null, null]

tests/test_serialization.py:412: AssertionError
____________________ TestDeepDiffPretty.test_reversed_list _____________________

self = <tests.test_serialization.TestDeepDiffPretty object at 0x7f8348a28530>

    def test_reversed_list(self):
        items = reversed([1, 2, 3])
    
        serialized = json_dumps(items)
        serialized2 = json_dumps(items)
    
>       assert '[3,2,1]' == serialized
E       AssertionError: assert '[3,2,1]' == '[3, 2, 1]'
E         
E         - [3, 2, 1]
E         ?    -  -
E         + [3,2,1]

tests/test_serialization.py:420: AssertionError
=============================== warnings summary ===============================
tests/test_serialization.py:391
  /build/reproducible-path/deepdiff-8.0.1/.pybuild/cpython3_3.12_deepdiff/build/tests/test_serialization.py:391: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
    (7, datetime.datetime.utcnow(), datetime.datetime.fromisoformat),

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

------------------------------------------------------------------------------------------------ benchmark: 3 tests ------------------------------------------------------------------------------------------------
Name (time in us)                                  Min                 Max               Mean            StdDev             Median               IQR            Outliers  OPS (Kops/s)            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_lfu[items0-3-expected_results0-1.333]     14.6970 (1.0)      313.0990 (2.98)     16.1242 (1.0)      6.5514 (1.27)     15.5090 (1.0)      0.5010 (1.0)        92;334       62.0184 (1.0)        7977           1
test_lfu[items1-3-expected_results1-1.666]     17.5230 (1.19)     105.0680 (1.0)      19.5968 (1.22)     5.1401 (1.0)      18.8250 (1.21)     1.3930 (2.78)      287;366       51.0287 (0.82)      25482           1
test_lfu[items2-3-expected_results2-3.333]     23.6950 (1.61)     161.3240 (1.54)     25.4352 (1.58)     5.6073 (1.09)     24.8160 (1.60)     0.5810 (1.16)      247;987       39.3155 (0.63)      23376           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
=========================== short test summary info ============================
FAILED tests/test_delta.py::TestDeltaCompareFunc::test_list_of_alphabet_and_its_delta
FAILED tests/test_diff_text.py::TestDeepDiffText::test_exclude_path_when_prefix_of_exclude_path_matches1
FAILED tests/test_diff_text.py::TestDeepDiffText::test_bad_attribute - Assert...
FAILED tests/test_diff_text.py::TestDeepDiffText::test_group_by_with_none_key_and_ignore_case
FAILED tests/test_diff_text.py::TestDeepDiffText::test_affected_root_keys_when_dict_empty
FAILED tests/test_hash.py::TestDeepHashPrep::test_polars - ModuleNotFoundErro...
FAILED tests/test_serialization.py::TestSerialization::test_serialization_text_force_builtin_json
FAILED tests/test_serialization.py::TestDeepDiffPretty::test_namedtuple_seriazliation
FAILED tests/test_serialization.py::TestDeepDiffPretty::test_reversed_list - ...
============= 9 failed, 937 passed, 10 skipped, 1 warning in 4.74s =============

Please ignore the polars package error. Any help or clue is welcome :)

eamanu avatar Dec 16 '24 20:12 eamanu

Hi @eamanu All these tests pass for me on Ubuntu 24.04.1 and Python 3.13. What version of Debian are you using?

seperman avatar Dec 16 '24 22:12 seperman

Hi @seperman

Thanks for your response. I'm in Debian sid. Now, as you merged I will wait the release to package it.

I suspect that I missed something while patching the PR.

eamanu avatar Dec 16 '24 23:12 eamanu

Hi @seperman,

The issue was because orjson is a dependency. In despite that deepdiff has a import error manage, the tests need it, if not they fail.

eamanu avatar Dec 18 '24 21:12 eamanu

Hi @eamanu Yeah, you need to install the requirements-dev.txt before running the tests. You can take a look at the github actions that run the tests.

seperman avatar Dec 20 '24 00:12 seperman