@@ -1567,6 +1567,79 @@ def modified(self, path):
15671567 """Return the modified timestamp of a file as a datetime.datetime"""
15681568 raise NotImplementedError
15691569
1570+ def tree (
1571+ self ,
1572+ path : str = '/' ,
1573+ recursion_limit : int = 2 ,
1574+ max_display : int = 25 ,
1575+ display_size : bool = False ,
1576+ prefix : str = "" ,
1577+ is_last : bool = True ,
1578+ first : bool = True
1579+ ):
1580+ """
1581+ Display a tree-like structure of the filesystem starting from the given path.
1582+
1583+ Parameters
1584+ ----------
1585+ path: Root path to start traversal from
1586+ recursion_limit: Maximum depth of directory traversal
1587+ max_display: Maximum number of items to display per directory
1588+ display_size: Whether to display file sizes
1589+ prefix: Current line prefix for visual tree structure
1590+ is_last: Whether current item is last in its level
1591+ first: Whether this is the first call (displays root path)
1592+
1593+ Example
1594+ -------
1595+ >>> fs.tree(path='/start/folder', display_size=True)
1596+
1597+ /start/folder
1598+ ├── folder1
1599+ │ ├── file1.txt (1.234MB)
1600+ │ └── file2.txt (0.567MB)
1601+ └── folder2
1602+ └── file3.txt (2.345MB)
1603+ """
1604+ if first :
1605+ print (path )
1606+ if recursion_limit :
1607+ try :
1608+ contents = self .ls (path , detail = True )
1609+ contents .sort (key = lambda x : (not x .get ('type' ) == 'directory' , x .get ('name' , '' )))
1610+
1611+ if max_display is not None and len (contents ) > max_display :
1612+ displayed_contents = contents [:max_display ]
1613+ remaining_count = len (contents ) - max_display
1614+ else :
1615+ displayed_contents = contents
1616+ remaining_count = 0
1617+
1618+ for i , item in enumerate (displayed_contents ):
1619+ is_last_item = (i == len (displayed_contents ) - 1 ) and (remaining_count == 0 )
1620+
1621+ branch = "└── " if is_last_item else "├── "
1622+ new_prefix = prefix + (" " if is_last_item else "│ " )
1623+
1624+ name = os .path .basename (item .get ('name' , '' ))
1625+ size = f" ({ item .get ('size' , 0 ) / 2 ** 20 :.3f} Mb)" if display_size and item .get ('type' ) == 'file' else ""
1626+
1627+ print (f"{ prefix } { branch } { name } { size } " )
1628+
1629+ if item .get ('type' ) == 'directory' and recursion_limit > 0 :
1630+ self .tree (item .get ('name' , '' ), recursion_limit - 1 , max_display , new_prefix , is_last_item , display_size = display_size , first = False )
1631+
1632+ if remaining_count > 0 :
1633+ more_message = f"{ remaining_count } more item(s) not displayed."
1634+ print (f"{ prefix } { '└── ' if is_last else '├── ' } { more_message } " )
1635+
1636+ except FileNotFoundError :
1637+ print (f"{ prefix } Error: Path not found - { path } " )
1638+ except PermissionError :
1639+ print (f"{ prefix } Error: Permission denied - { path } " )
1640+ except Exception as e :
1641+ print (f"{ prefix } Unexpected error: { str (e )} " )
1642+
15701643 # ------------------------------------------------------------------------
15711644 # Aliases
15721645
0 commit comments