Skip to content

8.7.0#579

Open
seperman wants to merge 42 commits intomasterfrom
dev
Open

8.7.0#579
seperman wants to merge 42 commits intomasterfrom
dev

Conversation

@seperman
Copy link
Member

  • Adding support for python 3.14

vitalis89 and others added 21 commits September 12, 2025 23:06
If `key` is not in result, then there's no point in trying to delete it anyway
Fix logarithmic_similarity return type hint
When comparing two lists where all items are removed (t2 becomes an empty list),
the colored view would display an empty list [] instead of showing the removed
items in red.

The bug occurred because `_colorize_json()` returned '[]' immediately if the
list was empty, without checking for items that were removed and should be
displayed.

Fix: Check for removed items before returning empty list representation.

Added tests:
- test_colored_view_list_all_items_removed
- test_colored_compact_view_list_all_items_removed
Update lambda function to check for attribute existence in __slots__.
Add tests for DeepHash with classes using __slots__
…e when serializing integers

  larger than 9223372036854775807 (2^63-1) or smaller than -9223372036854775808 (-2^63). This is an
  orjson limitation since it only supports signed 64-bit integers natively.

  Fix in deepdiff/serialization.py:
  1. Added _convert_oversized_ints() helper (line ~739) that recursively walks a data structure and
  converts any integer outside the signed 64-bit range to a string.
  2. Wrapped the orjson.dumps() call in a try/except — on the specific "Integer exceeds 64-bit range"
   TypeError, the data is pre-processed through _convert_oversized_ints() and retried.

  Tests added in tests/test_serialization.py:
  - test_json_dumps_large_int_exceeding_64bit — basic case with a large positive int
  - test_json_dumps_large_int_in_nested_structure — large int nested inside dicts
  - test_json_dumps_large_negative_int — large negative int
… calling

  type(obj)(converted_list) to reconstruct them. This fails because NamedTuple constructors require
  positional arguments matching their field definitions, not a single list.

  Solution: Before reconstructing a tuple subclass, check for the _fields attribute (the NamedTuple
  marker). If present, reconstruct via type(obj)(**dict(zip(obj._fields, converted))) so each field
  is passed by keyword. Plain tuples and lists continue to use the original path.
… it returned a

  dict containing opaque DiffLevel objects rather than a readable Python dictionary. The
  workaround was to_dict(view_override='text'), but that was locked to whatever verbose_level was
   set at init time (default 1), meaning you couldn't get the full detail that the tree view had
  access to.

  Change: Replaced the view_override parameter with verbose_level on both to_dict() and
  to_json(). These methods now always produce a text-view dictionary — an actual usable Python
  dict. The default verbosity is context-aware:

  - If the original view is 'text': uses the verbose_level from initialization (preserving
  existing behavior).
  - If the original view is 'tree': defaults to verbose_level=2 (the most detailed output), since
   tree-view users chose that view for its richness.

  In both cases, you can override the verbosity explicitly: to_dict(verbose_level=0),
  to_dict(verbose_level=1), etc.
  - pyproject.toml: requires-python changed to >=3.10, removed 3.9 classifier, cleaned up all
  python_version < '3.10' / python_version >= '3.10' conditional dependencies (coverage, click,
  numpy, orjson, polars, pytest, pytest-cov, python-dotenv)
  - .github/workflows/main.yaml: Removed 3.9 from matrix, added 3.14, changed DEFAULT_PYTHON and
  all conditional checks from 3.12 to 3.14
  - noxfile.py: Removed 3.9, added 3.14 to pytest session
  - README.md: Updated to "Python 3.10+" and added "Dropping support for Python 3.9" to What is
  New
  - CLAUDE.md: Updated to "3.10+"
  - .github/ISSUE_TEMPLATE/bug_report.md: Updated example version from 3.9.12 to 3.10.12

  Changelog/docs updates:
  - CHANGELOG.md: Added "Dropping support for Python 3.9" to v8-7-0
  - docs/changelog.rst: Added "Dropping support for Python 3.9" to v8-7-0
  - docs/index.rst: Added new 8-7-0 section with all its entries (matching the pattern of
  existing version sections)
@codecov
Copy link

codecov bot commented Mar 11, 2026

Codecov Report

❌ Patch coverage is 97.29730% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 96.06%. Comparing base (0d07ec2) to head (b1e3c11).

Files with missing lines Patch % Lines
deepdiff/serialization.py 96.87% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #579      +/-   ##
==========================================
- Coverage   96.10%   96.06%   -0.04%     
==========================================
  Files          16       16              
  Lines        4488     4474      -14     
==========================================
- Hits         4313     4298      -15     
- Misses        175      176       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

seperman and others added 13 commits March 25, 2026 09:54
Fix ignore_keys issue in detailed__dict__
Add support for callable group_by
…t-display

Fix: Colored view displays empty list [] when all items are removed
…w's fields, with path and

  action required and the rest optional.
  2. Changed the return type of to_flat_dicts from List[FlatDeltaRow] to List[FlatDeltaDict].
  3. Used cast to tell pyright the _asdict() output conforms to FlatDeltaDict.
  4. Fixed the parameter bug — the original code was hardcoding include_action_in_path=False,
  report_type_changes=True instead of passing through the actual arguments.
…anges:

  1. Hash cache collision (deephash.py): The shared self.hashes dict used raw objects as keys.
  Since Python treats 1 == 1.0 and hash(1) == hash(1.0), looking up 1.0 returned the cached hash
  for 1, silently hiding the type difference.
  2. Distance over-counting (distance.py): _get_item_length counted both old_type and old_value in
  type_changes entries, double-counting a single operation. This inflated distances, causing the
  pairing algorithm to reject items that should have been matched.

  Fixes:

  - deepdiff/deephash.py: Added _make_hash_key() / _make_hash_key_for_lookup() that wrap numeric
  objects as (type(obj), obj) tuples when ignore_numeric_type_changes=False. Applied at cache
  lookup, cache store, and all public accessor methods (__getitem__, __contains__, get, get_key).
  Added _unwrap_hash_key() for iteration methods so the public API still shows raw objects.
  - deepdiff/distance.py: Skip old_type and old_value keys in _get_item_length — they're metadata
  about prior state, not additional operations. Also added ignore_numeric_type_changes to
  DistanceProtocol and threaded it through get_key calls.
  - Test updates: Updated expected distance values in test_distance.py to reflect the corrected
  distance formula.
Ensure that delta replays apply changes to correct t1/t2 based on usage of iterable_compare_func
…ersion mechanism in model.py

   DiffLevel.path so future developers understand why the keys are swapped.
  2. Added test_moved_and_type_changed — covers the type_changes code path where items both move
  and change type (str -> int), which the original tests didn't exercise.
Fix bug in DeepHash for classes with uninitialised slots
…tr() swallows all

  AttributeErrors — including those from __getattr__. This made objects with a broken __getattr__
  (like the Bad test class) appear to have zero accessible slots rather than failing the strategy.

  The fix uses object.__getattribute__() to check each slot directly, which bypasses __getattr__
  entirely. For classes that do define __getattr__, if a slot isn't initialized via the descriptor,
   we fall back to the normal getattr() — letting __getattr__ either provide a value or raise
  (propagating the failure). This correctly handles:

  - Uninitialized slots (no __getattr__): skipped gracefully, empty dict is valid
  - Partially initialized slots: only initialized ones included
  - Broken __getattr__: error propagates, object becomes unprocessed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants