Skip to content

Refactor code#11

Merged
kaliv0 merged 5 commits into
mainfrom
refactor-code
Jan 12, 2026
Merged

Refactor code#11
kaliv0 merged 5 commits into
mainfrom
refactor-code

Conversation

@kaliv0

@kaliv0 kaliv0 commented Jan 12, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Chores

    • Bumped project version to 1.6.0 and tightened max line length.
  • Bug Fixes

    • Improved robustness of numeric operations (sum/average) with None/empty inputs.
    • Ensured file-handling cleans up resources on errors.
    • Made hashing errors for unhashable values clearer.
    • Fixed several stream behaviors (flatten, iterate, drop-while, take_last, none_match).
  • Documentation

    • Added docstrings across core stream and utility APIs.
  • Tests

    • Expanded tests for edge cases, error handling, and cleanup; removed an unused test fixture.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 12, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Bumps version and Ruff line length; adds docstrings; introduces iterator integration constants; changes flatten/iterate/drop_while semantics; tightens numeric validation and empty-stream handling; hardens FileStream initialization cleanup; improves DictItem hashing errors; removes a test fixture; and adds/expands tests for edge and error cases.

Changes

Cohort / File(s) Summary
Configuration & Version
pyproject.toml
Version bumped 1.5.0 → 1.6.0; Ruff max line length changed 110 → 100.
Decorators & Mapper docs
pyrio/decorators/handler.py, pyrio/decorators/mapper.py
Added docstrings for pre_call, handle_consumed, and map_dict_items; minor formatting and a coverage pragma.
Iterator Integration Constants
pyrio/iterators/itertools_mixin.py
Added class-level constants NO_SIGNATURE_FUNCTIONS, NO_KWARGS_FUNCTIONS and switched internal checks to use self.*.
Stream Generator behavior
pyrio/iterators/stream_generator.py
Added docstrings; changed flatten to recursive flattening, iterate to yield then update seed, drop_while to skip while predicate true then yield remainder; other methods documented.
Core Stream APIs
pyrio/streams/base_stream.py
iterable now caches Mapping as tuple of DictItem; added _validate_numeric_data used by sum and average (returns 0 if no valid numbers); reworked take_last (deque); inverted none_match logic; reduce handles empty iterables more robustly; formatting and error-message tweaks.
FileStream resource handling
pyrio/streams/file_stream.py
__new__ wraps file reading in try/except and ensures opened file handler is closed on exception; save and _write_mapping signatures reformatted (params unchanged).
DictItem hashing
pyrio/utils/dict_item.py
__hash__ now wraps hashing in try/except and raises a descriptive TypeError when value is unhashable.
Test fixtures
tests/conftest.py
Removed alias_dict pytest fixture.
DictItem tests
tests/test_dict_item.py
Added tests for hashing behavior, consistency, and unhashable-value errors; minor formatting adjustments.
FileStream tests
tests/test_file_stream.py
Added tests for file-handler cleanup on init exception, stale-temp cleanup on save, and atomic-write cleanup on serialization error; mostly formatting changes elsewhere.
Itertools mixin tests
tests/test_itertools_mixin.py
Reformatting and one test rename (rest_view_negative_steptest_view_negative_step).
Stream tests
tests/test_stream.py
Expanded coverage for reduce, sum, average, head, take_last, group_by, and various edge cases (empty streams, None values, single elements); updated some error expectations and formatting.

Sequence Diagram(s)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I hop through bytes with tidy cheer,
I flatten nests both far and near,
Seeds step forward, streams behave,
Files close safe — no open grave,
Hashes warn when types misappear.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Refactor code' is vague and generic, providing no meaningful insight into the specific changes made across multiple files and functional improvements. Consider using a more descriptive title that captures the main intent, such as 'Add docstrings and improve stream/iterator logic' or 'Enhance error handling and add documentation'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bda62b and 062222c.

📒 Files selected for processing (2)
  • pyrio/utils/dict_item.py
  • tests/test_dict_item.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • pyrio/utils/dict_item.py
  • tests/test_dict_item.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @pyrio/utils/dict_item.py:
- Around line 31-36: The current __hash__ implementation violates the
hash/equality contract for DictItem when values are unhashable; update
DictItem.__hash__ to attempt hashing (e.g., hash((self._key, self._value))) and
if that raises TypeError re-raise a TypeError so instances with unhashable
values become unhashable (do not fall back to id(self._value)); reference the
DictItem class and its __hash__ and __eq__ methods and ensure the error message
clearly states that DictItem is unhashable when its value is unhashable.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64d1255 and 2f0bf44.

📒 Files selected for processing (13)
  • pyproject.toml
  • pyrio/decorators/handler.py
  • pyrio/decorators/mapper.py
  • pyrio/iterators/itertools_mixin.py
  • pyrio/iterators/stream_generator.py
  • pyrio/streams/base_stream.py
  • pyrio/streams/file_stream.py
  • pyrio/utils/dict_item.py
  • tests/conftest.py
  • tests/test_dict_item.py
  • tests/test_file_stream.py
  • tests/test_itertools_mixin.py
  • tests/test_stream.py
💤 Files with no reviewable changes (1)
  • tests/conftest.py
🧰 Additional context used
🧬 Code graph analysis (8)
pyrio/decorators/handler.py (1)
pyrio/streams/base_stream.py (1)
  • BaseStream (10-389)
tests/test_file_stream.py (4)
pyrio/streams/file_stream.py (2)
  • FileStream (62-260)
  • process (92-94)
pyrio/iterators/stream_generator.py (3)
  • map (24-27)
  • filter (17-21)
  • flat_map (37-40)
pyrio/streams/base_stream.py (8)
  • map (48-51)
  • to_tuple (274-276)
  • filter (43-46)
  • flat_map (58-61)
  • BaseStream (10-389)
  • iterable (24-27)
  • iterable (30-31)
  • close (373-377)
pyrio/streams/stream.py (1)
  • Stream (7-54)
tests/test_dict_item.py (2)
pyrio/utils/dict_item.py (3)
  • value (13-14)
  • DictItem (1-36)
  • key (9-10)
tests/conftest.py (2)
  • json_dict (38-46)
  • nested_json (15-34)
tests/test_itertools_mixin.py (3)
pyrio/streams/stream.py (1)
  • Stream (7-54)
pyrio/iterators/itertools_mixin.py (1)
  • use (13-24)
pyrio/streams/base_stream.py (1)
  • to_list (270-272)
pyrio/streams/file_stream.py (1)
pyrio/streams/base_stream.py (3)
  • iterable (24-27)
  • iterable (30-31)
  • close (373-377)
pyrio/streams/base_stream.py (3)
pyrio/utils/dict_item.py (1)
  • DictItem (1-36)
pyrio/streams/stream.py (1)
  • of_nullable (16-20)
pyrio/exceptions/exception.py (1)
  • UnsupportedTypeError (13-14)
tests/test_stream.py (3)
pyrio/streams/stream.py (3)
  • Stream (7-54)
  • of (11-13)
  • empty (23-25)
pyrio/streams/base_stream.py (15)
  • filter_map (53-56)
  • to_list (270-272)
  • reduce (217-231)
  • head (112-117)
  • to_tuple (274-276)
  • sum (88-91)
  • average (93-96)
  • take_last (140-145)
  • sort (147-153)
  • map (48-51)
  • reverse (155-161)
  • to_dict (282-301)
  • none_match (192-194)
  • to_string (315-317)
  • collect (240-268)
pyrio/utils/dict_item.py (2)
  • value (13-14)
  • key (9-10)
pyrio/iterators/stream_generator.py (4)
pyrio/decorators/mapper.py (1)
  • map_dict_items (7-23)
pyrio/streams/base_stream.py (5)
  • concat (33-36)
  • iterable (24-27)
  • iterable (30-31)
  • map (48-51)
  • enumerate (209-215)
pyrio/streams/stream.py (1)
  • iterate (28-30)
pyrio/utils/dict_item.py (1)
  • key (9-10)
🔇 Additional comments (47)
pyproject.toml (1)

3-3: LGTM!

Version bump to 1.6.0 and line-length adjustment to 100 are appropriate for this refactoring release. The 100-character limit aligns well with common Python conventions.

Also applies to: 45-45

tests/test_itertools_mixin.py (2)

284-287: Good catch fixing the test name.

Renaming rest_view_negative_step to test_view_negative_step ensures pytest properly discovers and runs this test. The previous name would have been silently skipped during test runs.


10-12: LGTM!

Formatting adjustments align with the new 100-character line limit.

pyrio/decorators/handler.py (1)

35-56: LGTM!

The docstrings accurately describe the decorator behaviors:

  • pre_call: class-level decorator that wraps all callable methods
  • handle_consumed: prevents re-use of consumed streams and ensures cleanup after terminal operations

The # pragma: no cover on line 56 is appropriate for the defensive fallback branch.

pyrio/iterators/itertools_mixin.py (2)

7-11: LGTM!

Extracting the function lists to class-level constants (NO_SIGNATURE_FUNCTIONS, NO_KWARGS_FUNCTIONS) improves maintainability and allows subclasses to extend or override these lists if needed.


27-27: LGTM!

Using self.NO_SIGNATURE_FUNCTIONS and self.NO_KWARGS_FUNCTIONS instead of inline literals centralizes the configuration and maintains consistency with the new class-level constants.

Also applies to: 48-48

pyrio/iterators/stream_generator.py (4)

6-8: LGTM!

Clear class-level docstring explaining the lazy evaluation pattern.


42-49: LGTM!

The flatten implementation correctly handles recursive flattening of nested iterables while preserving strings as atomic elements. The docstring accurately describes the behavior.


58-65: LGTM!

The iterate generator correctly yields the seed first, then repeatedly applies the operation to produce subsequent values. The optional condition parameter allows for bounded iteration.


122-132: LGTM!

The drop_while implementation correctly handles the two-phase iteration: first skipping elements while the predicate is true, then yielding all remaining elements (including the first non-matching element that triggered the break).

pyrio/streams/file_stream.py (2)

74-89: Excellent resource safety improvement.

The try/except pattern ensures the file handle is properly closed if any exception occurs during file reading or stream initialization. Key points:

  • file_handler = None before the try block prevents UnboundLocalError in the except block
  • The check file_handler is not None and not file_handler.closed is defensive and correct
  • Re-raising the exception preserves the original error context

147-155: LGTM!

Method signature reformatting aligns with the 100-character line limit without changing functionality.

Also applies to: 192-194

pyrio/decorators/mapper.py (1)

7-9: LGTM!

The docstring concisely describes the decorator's purpose. The implementation correctly transforms only Mapping arguments while preserving other argument types.

tests/test_dict_item.py (3)

42-46: LGTM!

Formatting adjustment aligns with the updated line length configuration. No logic changes.


69-71: LGTM!

Reformatted assertion for better readability.


81-89: LGTM!

Good test coverage for the new __hash__ fallback behavior. The tests verify that:

  1. hash() returns an int for both hashable and unhashable values (lists, dicts)
  2. Hash is consistent across multiple calls on the same object

Note that the consistency test (hash(item) == hash(item)) will always pass for the same object within a single process run, which is the expected behavior being verified here.

tests/test_file_stream.py (10)

70-75: LGTM!

Formatting adjustment for lambda expression line wrapping.


103-108: LGTM!

Improved readability with multiline chaining for the nested stream operations.


223-225: LGTM!

Minor formatting adjustment.


336-338: LGTM!

Formatting change for lambda expression.


405-407: LGTM!

Assertion reformatted for readability.


437-439: LGTM!

Formatting change for method chaining.


503-508: LGTM!

Formatting adjustment for the save call with multiple options.


511-542: Good test for resource cleanup on initialization failure.

The test properly verifies that the file handler is closed when an exception occurs during FileStream initialization. The monkeypatch approach is appropriate for simulating the failure scenario.

One minor observation: the test tracks close calls via close_called.append(True) but asserts len(close_called) > 0. This is sufficient for the test's purpose.


545-556: Good test for stale temporary file cleanup.

The test verifies that pre-existing .tmp files are properly cleaned up during the save operation, which is important for robustness in case of previous interrupted writes.


559-579: Good test for atomic write failure recovery.

The test properly verifies that:

  1. The temporary file is cleaned up when serialization fails
  2. The source file remains unchanged after the failure

This ensures the atomic write pattern is working correctly - either the write succeeds completely or the original file is preserved.

tests/test_stream.py (14)

106-111: LGTM!

Formatting adjustment for line wrapping.


126-145: Excellent test coverage for reduce on iterators.

Good addition of tests covering:

  • Basic reduce on iterator
  • Reduce with identity on iterator
  • Empty iterator (with and without identity)
  • Single element iterator

These tests verify that reduce works correctly with non-rewindable iterators.


219-222: Good test for negative head count validation.

Matches the implementation in base_stream.py that raises ValueError for negative counts.


391-410: Good test coverage for sum edge cases.

Tests cover:

  • Sum on iterators
  • Sum with floats
  • Sum with None values (filtered out)
  • Sum with mixed types (raises)
  • Sum when all values are None

425-447: Good test coverage for average edge cases.

Tests mirror the sum tests and verify:

  • Error message updated to reference "average" instead of "sum"
  • Average on iterators
  • Average with floats
  • Average with None values
  • Average with mixed types
  • Average when all None

497-510: Good test coverage for take_last on iterators.

Tests verify take_last works correctly with:

  • Regular iterators
  • Empty iterators
  • Empty iterators with default value
  • Single element iterators

537-545: LGTM!

Formatting adjustment for multi-key sort test.


569-577: LGTM!

Formatting adjustment for reverse with comparator test.


582-584: LGTM!

Formatting adjustment for complex pipeline test.


720-733: Good test coverage for none_match edge cases.

Tests verify:

  • none_match on empty stream returns True (correct behavior - vacuously true)
  • Partial match, all match, and single match scenarios all return False

833-838: LGTM!

Formatting adjustment for to_dict_merger test.


941-949: Good test coverage for group_by edge cases.

Tests verify:

  • Empty stream returns empty dict
  • Unconsumed groups can still yield keys correctly

959-961: LGTM!

Formatting adjustment for to_string test.


1031-1034: LGTM!

Formatting adjustment for parametrize decorator.

pyrio/streams/base_stream.py (7)

23-27: Good optimization for Mapping handling.

Caching the tuple of DictItem instances avoids recreating them on each property access. This is more efficient and ensures consistent object identity across multiple accesses.


82-96: Good refactor: Extracted numeric validation into helper.

The _validate_numeric_data helper cleanly handles:

  • Type validation (int/float/None)
  • Filtering out None values
  • Dynamic error message with operation name

Both sum and average now share this validation logic, reducing duplication.


140-145: Good optimization for take_last.

Using deque(maxlen=1) is an efficient O(n) single-pass approach that works with any iterable, including generators that can't be indexed. This is preferable to converting to a list just to get the last element.


192-194: LGTM!

The simplified none_match implementation using not any(...) is semantically clearer and equivalent to the previous logic.


217-231: Good improvement to reduce for empty iterators.

The try/except pattern for handling empty iterators is cleaner than checking length (which wouldn't work for generators). The behavior correctly:

  • Returns Optional.of_nullable(identity) when the stream is empty with an identity provided
  • Returns Optional.of_nullable(None) when empty without identity (via StopIteration)

233-237: LGTM!

Formatting adjustment for readability.


303-313: LGTM!

Error message reformatted to multiline for consistency with line length configuration.

Comment thread pyrio/utils/dict_item.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pyrio/utils/dict_item.py (1)

31-37: Consider exception chaining for better debugging.

The new error handling provides a clearer message, which is good. However, the original exception context is lost. Using from to chain exceptions preserves the traceback, which can help with debugging.

♻️ Suggested improvement
     def __hash__(self):
         try:
             return hash((self._key, self._value))
-        except TypeError:
+        except TypeError as e:
             raise TypeError(
                 f"unhashable type: 'DictItem' (value of type '{type(self._value).__name__}' is unhashable)"
-            )
+            ) from e
tests/test_dict_item.py (1)

86-89: Consider strengthening the hash consistency test.

The current test hash(item) == hash(item) is trivially true since it compares the same call. A more meaningful test would verify the hash contract: equal objects must have equal hashes.

♻️ Suggested improvement
 @pytest.mark.parametrize("value", ["John", 42, (1, 2, 3)])
 def test_dict_item_hash_consistency(value):
     item = DictItem(key="k", value=value)
-    assert hash(item) == hash(item)
+    item2 = DictItem(key="k", value=value)
+    # Equal items must have equal hashes (hash contract)
+    assert item == item2
+    assert hash(item) == hash(item2)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f0bf44 and 0bda62b.

📒 Files selected for processing (2)
  • pyrio/utils/dict_item.py
  • tests/test_dict_item.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/test_dict_item.py (2)
pyrio/utils/dict_item.py (3)
  • value (13-14)
  • DictItem (1-37)
  • key (9-10)
tests/conftest.py (2)
  • json_dict (38-46)
  • nested_json (15-34)
🔇 Additional comments (3)
tests/test_dict_item.py (3)

42-45: LGTM!

Formatting change for better readability. No functional impact.


69-71: LGTM!

Formatting change for better readability.


92-102: LGTM!

Good test coverage for the new error handling in __hash__. The parameterized test covers lists, dicts, and nested structures, and correctly validates the error message format.

@kaliv0 kaliv0 merged commit 1aa5b95 into main Jan 12, 2026
5 checks passed
@kaliv0 kaliv0 deleted the refactor-code branch January 12, 2026 17:41
@coderabbitai coderabbitai Bot mentioned this pull request Jan 26, 2026
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.

1 participant