@@ -26,14 +26,20 @@ class FileSystemStats:
26
26
class FileSystemNode (Source ): # pylint: disable=too-many-instance-attributes
27
27
"""Base class for filesystem nodes (files, directories, symlinks)."""
28
28
29
- name : str = ""
30
- path_str : str = ""
31
- path : Path | None = None
29
+ # Required fields - no default values to prevent missing data initialization
30
+ name : str
31
+ path_str : str
32
+ path : "Path"
33
+
34
+ # Optional fields with sensible defaults
32
35
size : int = 0
33
36
file_count : int = 0
34
37
dir_count : int = 0
35
38
depth : int = 0
36
39
children : list [FileSystemNode ] = field (default_factory = list )
40
+
41
+ # Class attribute for display type name (instead of fragile string manipulation)
42
+ _display_type : str = "NODE"
37
43
38
44
@property
39
45
def tree (self ) -> str :
@@ -75,7 +81,8 @@ def content_string(self) -> str:
75
81
A string representation of the node's content.
76
82
77
83
"""
78
- type_name = self .__class__ .__name__ .upper ().replace ("FILESYSTEM" , "" )
84
+ # Use class attribute instead of fragile string manipulation
85
+ type_name = self ._display_type
79
86
80
87
parts = [
81
88
SEPARATOR ,
@@ -87,14 +94,44 @@ def content_string(self) -> str:
87
94
return "\n " .join (parts ) + "\n \n "
88
95
89
96
def get_content (self ) -> str :
90
- """Return file content. Override in subclasses for specific behavior."""
91
- if self .path is None :
92
- return "Error: No path specified"
97
+ """Return file content with proper encoding detection."""
98
+ from gitingest .utils .file_utils import _decodes , _get_preferred_encodings , _read_chunk
99
+ from gitingest .utils .notebook import process_notebook
100
+
101
+ # Handle notebook files specially
102
+ if self .path .suffix == ".ipynb" :
103
+ try :
104
+ return process_notebook (self .path )
105
+ except Exception as exc :
106
+ return f"Error processing notebook: { exc } "
107
+
108
+ # Read a chunk to check if it's binary or text
109
+ chunk = _read_chunk (self .path )
110
+
111
+ if chunk is None :
112
+ return "Error reading file"
113
+
114
+ if chunk == b"" :
115
+ return "[Empty file]"
116
+
117
+ # Check if it's binary
118
+ if not _decodes (chunk , "utf-8" ):
119
+ return "[Binary file]"
120
+
121
+ # Find the first encoding that decodes the sample
122
+ good_enc : str | None = next (
123
+ (enc for enc in _get_preferred_encodings () if _decodes (chunk , encoding = enc )),
124
+ None ,
125
+ )
126
+
127
+ if good_enc is None :
128
+ return "Error: Unable to decode file with available encodings"
93
129
94
130
try :
95
- return self .path .read_text (encoding = "utf-8" )
96
- except Exception as e :
97
- return f"Error reading content of { self .name } : { e } "
131
+ with self .path .open (encoding = good_enc ) as fp :
132
+ return fp .read ()
133
+ except (OSError , UnicodeDecodeError ) as exc :
134
+ return f"Error reading file with { good_enc !r} : { exc } "
98
135
99
136
def get_summary_info (self ) -> str :
100
137
"""Return summary information. Override in subclasses."""
@@ -112,10 +149,6 @@ def get_display_name(self) -> str:
112
149
"""Get display name for tree view. Override in subclasses."""
113
150
return self .name
114
151
115
- def has_children (self ) -> bool :
116
- """Return whether this node has children to display."""
117
- return False
118
-
119
152
@property
120
153
def content (self ) -> str :
121
154
"""Return file content (simplified version for backward compatibility)."""
@@ -125,6 +158,8 @@ def content(self) -> str:
125
158
@dataclass
126
159
class FileSystemFile (FileSystemNode ):
127
160
"""Represents a file in the filesystem."""
161
+
162
+ _display_type : str = "FILE"
128
163
129
164
def get_sort_priority (self ) -> int :
130
165
"""Files have priority 0 for sorting."""
@@ -149,6 +184,7 @@ class FileSystemDirectory(FileSystemNode):
149
184
"""Represents a directory in the filesystem."""
150
185
151
186
file_count_total : int = 0
187
+ _display_type : str = "DIRECTORY"
152
188
153
189
def get_content (self ) -> str :
154
190
"""Directories cannot have content."""
@@ -167,10 +203,6 @@ def get_display_name(self) -> str:
167
203
"""Directories get a trailing slash."""
168
204
return self .name + "/"
169
205
170
- def has_children (self ) -> bool :
171
- """Directories have children if the list is not empty."""
172
- return bool (self .children )
173
-
174
206
def render_tree (self , prefix : str = "" , * , is_last : bool = True ) -> list [str ]:
175
207
"""Render the tree representation of this directory."""
176
208
lines = []
@@ -195,6 +227,7 @@ class GitRepository(FileSystemDirectory):
195
227
"""A directory that contains a .git folder, representing a Git repository."""
196
228
197
229
git_info : dict = field (default_factory = dict ) # Store git metadata like branch, commit, etc.
230
+ _display_type : str = "GIT_REPOSITORY"
198
231
199
232
def render_tree (self , prefix : str = "" , * , is_last : bool = True ) -> list [str ]:
200
233
"""Render the tree representation of this git repository."""
@@ -216,7 +249,7 @@ class FileSystemSymlink(FileSystemNode):
216
249
"""Represents a symbolic link in the filesystem."""
217
250
218
251
target : str = ""
219
- # Add symlink-specific fields if needed
252
+ _display_type : str = "SYMLINK"
220
253
221
254
def get_content (self ) -> str :
222
255
"""Symlinks content is what they point to."""
0 commit comments