From d9e4f62af871f396edaa9dec7b144140fc2d2905 Mon Sep 17 00:00:00 2001 From: NabeelShar Date: Sat, 13 Dec 2025 13:00:02 +0500 Subject: [PATCH] Fix inspect() not respecting sort=False for instance attributes - Modified _render() in rich/_inspect.py to preserve insertion order when sort=False - When sort=False and object has __dict__, use vars() to get instance attributes in insertion order - Added test_inspect_sort_parameter to verify the fix - Updated CHANGELOG.md and CONTRIBUTORS.md Fixes #3432 --- CHANGELOG.md | 6 ++++++ CONTRIBUTORS.md | 1 + rich/_inspect.py | 10 ++++++++++ tests/test_inspect.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5320566..d2ca3cbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Fixed `inspect()` not respecting `sort=False` parameter for instance attributes https://github.com/Textualize/rich/issues/3432 + ## [14.2.0] - 2025-10-09 ### Changed diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4b04786b..ea01c1be 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -93,4 +93,5 @@ The following people have contributed to the development of Rich: - [chthollyphile](https://github.com/chthollyphile) - [Jonathan Helmus](https://github.com/jjhelmus) - [Brandon Capener](https://github.com/bcapener) +- [Nab](https://github.com/Nabeelshar) - [Alex Zheng](https://github.com/alexzheng111) diff --git a/rich/_inspect.py b/rich/_inspect.py index 27d65cec..a74f5061 100644 --- a/rich/_inspect.py +++ b/rich/_inspect.py @@ -135,6 +135,16 @@ class Inspect(JupyterMixin): obj = self.obj keys = dir(obj) total_items = len(keys) + + # When sort=False, prefer __dict__ order for instance attributes + if not self.sort and hasattr(obj, "__dict__"): + # Get instance attributes in insertion order + instance_keys = list(vars(obj).keys()) + # Get remaining attributes from dir() that aren't in __dict__ + class_keys = [key for key in keys if key not in instance_keys] + # Combine: instance attributes first (in order), then class attributes + keys = instance_keys + class_keys + if not self.dunder: keys = [key for key in keys if not key.startswith("__")] if not self.private: diff --git a/tests/test_inspect.py b/tests/test_inspect.py index 3f6e5b9f..a138f526 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -501,3 +501,37 @@ def test_object_is_one_of_types( obj: object, types: Sequence[str], expected_result: bool ): assert is_object_one_of_types(obj, types) is expected_result + + +def test_inspect_sort_parameter(): + """Test that sort=False preserves insertion order of instance attributes.""" + + class Test: + def __init__(self): + self.c = 1 + self.b = 2 + self.a = 3 + + test = Test() + + # Test sort=False preserves insertion order (c, b, a) + console = Console(width=50, file=io.StringIO(), legacy_windows=False) + inspect(test, console=console, sort=False, value=False, docs=False) + result_unsorted = console.file.getvalue() + + # Check that 'c' appears before 'b' and 'b' appears before 'a' + pos_c = result_unsorted.find("c = 1") + pos_b = result_unsorted.find("b = 2") + pos_a = result_unsorted.find("a = 3") + assert pos_c < pos_b < pos_a, "sort=False should preserve insertion order" + + # Test sort=True sorts alphabetically (a, b, c) + console = Console(width=50, file=io.StringIO(), legacy_windows=False) + inspect(test, console=console, sort=True, value=False, docs=False) + result_sorted = console.file.getvalue() + + # Check that 'a' appears before 'b' and 'b' appears before 'c' + pos_a = result_sorted.find("a = 3") + pos_b = result_sorted.find("b = 2") + pos_c = result_sorted.find("c = 1") + assert pos_a < pos_b < pos_c, "sort=True should sort alphabetically"