From 4d2d3de38b4c651349c63eae81ab1b80353869a2 Mon Sep 17 00:00:00 2001 From: hakarrr Date: Sat, 24 Oct 2026 17:44:36 +0530 Subject: [PATCH 1/2] Fix home path handling in pathname conversion --- humanfriendly/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/humanfriendly/__init__.py b/humanfriendly/__init__.py index 4c0a333..ecc9acc 100644 --- a/humanfriendly/__init__.py +++ b/humanfriendly/__init__.py @@ -618,7 +618,7 @@ def format_path(pathname): home = os.environ.get('HOME') if home: home = os.path.abspath(home) - if pathname.startswith(home): + if pathname == home or pathname.startswith(os.path.join(home, '')): pathname = os.path.join('~', os.path.relpath(pathname, home)) return pathname From 5ab9ee511386ba738358a398d63d52a864d9737e Mon Sep 17 00:00:00 2001 From: hakarrr Date: Sat, 24 Oct 2026 17:44:49 +0530 Subject: [PATCH 2/2] Cover sibling path prefixes and home normalization --- humanfriendly/tests.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/humanfriendly/tests.py b/humanfriendly/tests.py index 72dad99..432d2e3 100644 --- a/humanfriendly/tests.py +++ b/humanfriendly/tests.py @@ -591,6 +591,37 @@ def test_format_path(self): absolute_path = os.path.join(os.environ['HOME'], '.vimrc') self.assertEqual(friendly_path, format_path(absolute_path)) + def test_format_path_home_boundaries(self): + """Only abbreviate complete home directory components.""" + home = os.path.abspath(os.path.join(os.sep, 'home', 'user')) + cases = [ + (home, os.path.join('~', '.')), + (os.path.join(home, 'file'), os.path.join('~', 'file')), + (os.path.join(home, 'nested', 'file'), os.path.join('~', 'nested', 'file')), + (home + 'name', home + 'name'), + (os.path.join(home + '-backup', 'file'), os.path.join(home + '-backup', 'file')), + (os.path.join(home + '.old', 'file'), os.path.join(home + '.old', 'file')), + (os.path.dirname(home), os.path.dirname(home)), + (os.path.join(home, '..', 'other'), os.path.join(os.path.dirname(home), 'other')), + ] + for configured_home in (home, home + os.sep): + with PatchedItem(os.environ, 'HOME', configured_home): + for pathname, expected in cases: + self.assertEqual(expected, format_path(pathname)) + + def test_format_path_root_home(self): + """A filesystem root home still contains its descendants.""" + home = os.path.abspath(os.sep) + with PatchedItem(os.environ, 'HOME', home): + self.assertEqual(os.path.join('~', '.'), format_path(home)) + self.assertEqual(os.path.join('~', 'file'), format_path(os.path.join(home, 'file'))) + + def test_format_path_without_home(self): + """An empty home does not abbreviate an absolute pathname.""" + pathname = os.path.abspath(os.path.join(os.sep, 'home', 'user', 'file')) + with PatchedItem(os.environ, 'HOME', ''): + self.assertEqual(pathname, format_path(pathname)) + def test_parse_path(self): """Test :func:`humanfriendly.parse_path()`.""" friendly_path = os.path.join('~', '.vimrc')