treex-cli 0.1.6__tar.gz → 0.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: treex-cli
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: List directory contents as a tree with file and directory metadata
5
5
  Author: Corey Goldberg
6
6
  Maintainer: Corey Goldberg
@@ -100,7 +100,7 @@ Install `treex` from [PyPI][pypi-home] using either `pip` or `pipx`:
100
100
 
101
101
  ```
102
102
  $ treex --help
103
- usage: treex [-h] [-a] [-m] [-q] [-s] [directory]
103
+ usage: treex [-h] [-a] [-m] [-q] [-d] [-s] [directory]
104
104
 
105
105
  List directory contents as a tree with file and directory metadata.
106
106
 
@@ -109,9 +109,10 @@ positional arguments:
109
109
 
110
110
  options:
111
111
  -h, --help show this help message and exit
112
- -a, --all show all files (including those ignored by Git)
112
+ -a, --all show all files, including those ignored by Git
113
113
  -m, --modified show file modification times
114
114
  -q, --quiet don't show file metadata
115
+ -d, --dirs show directories only
115
116
  -s, --summary show summary only
116
117
  ```
117
118
 
@@ -75,7 +75,7 @@ Install `treex` from [PyPI][pypi-home] using either `pip` or `pipx`:
75
75
 
76
76
  ```
77
77
  $ treex --help
78
- usage: treex [-h] [-a] [-m] [-q] [-s] [directory]
78
+ usage: treex [-h] [-a] [-m] [-q] [-d] [-s] [directory]
79
79
 
80
80
  List directory contents as a tree with file and directory metadata.
81
81
 
@@ -84,9 +84,10 @@ positional arguments:
84
84
 
85
85
  options:
86
86
  -h, --help show this help message and exit
87
- -a, --all show all files (including those ignored by Git)
87
+ -a, --all show all files, including those ignored by Git
88
88
  -m, --modified show file modification times
89
89
  -q, --quiet don't show file metadata
90
+ -d, --dirs show directories only
90
91
  -s, --summary show summary only
91
92
  ```
92
93
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "treex-cli"
7
- version = "0.1.6"
7
+ version = "0.1.8"
8
8
  description="List directory contents as a tree with file and directory metadata"
9
9
  license = "MIT"
10
10
  license-files = ["LICENSE"]
@@ -53,6 +53,7 @@ py-modules = ["treex"]
53
53
  [tool.pytest]
54
54
  addopts = ["-v"]
55
55
  filterwarnings = ["default"]
56
+ tmp_path_retention_policy = "none"
56
57
 
57
58
  [tool.ruff]
58
59
  line-length = 88
@@ -62,7 +63,7 @@ target-version = "py310"
62
63
  [tool.ruff.lint]
63
64
  select = ["ALL"]
64
65
  ignore = [
65
- "ANN", "COM812", "D", "DTZ001", "DTZ006",
66
+ "ANN", "C901", "COM812", "D", "DTZ001", "DTZ006",
66
67
  "FBT", "PLR", "S603", "S607", "T201"
67
68
  ]
68
69
  fixable = ["ALL"]
@@ -14,6 +14,7 @@ filesystem is scanned normally without Git filtering.
14
14
 
15
15
  import argparse
16
16
  import subprocess
17
+ import sys
17
18
  from contextlib import suppress
18
19
  from datetime import datetime
19
20
  from pathlib import Path
@@ -151,6 +152,7 @@ def _collect_tree(
151
152
  rows,
152
153
  show_metadata,
153
154
  show_modified,
155
+ show_files,
154
156
  ):
155
157
  """Walk the tree once and collect the output rows."""
156
158
  entries = _get_tree_entries(path, gitignore)
@@ -158,15 +160,26 @@ def _collect_tree(
158
160
  rows.append((prefix + "└── [permission denied]", None))
159
161
  return 0
160
162
  total_size = 0
161
- for index, entry in enumerate(entries):
162
- is_last = index == len(entries) - 1
163
- connector = "└── " if is_last else "├── "
164
- tree_name = prefix + connector + entry.name
163
+ # When files are hidden, only directories determine which visible
164
+ # entry is last. Files are still processed for stats and sizes.
165
+ visible_entries = entries
166
+ if not show_files:
167
+ visible_entries = [entry for entry in entries if entry.is_dir()]
168
+ visible_index = 0
169
+ for entry in entries:
170
+ is_visible = show_files or entry.is_dir()
171
+ if is_visible:
172
+ is_last = visible_index == len(visible_entries) - 1
173
+ visible_index += 1
174
+ connector = "└── " if is_last else "├── "
175
+ tree_name = prefix + connector + entry.name
176
+ else:
177
+ tree_name = None
165
178
  if entry.is_dir():
166
179
  stats["directories"] += 1
167
180
  row_index = len(rows)
168
181
  rows.append((tree_name, None))
169
- # Indent nested entries, preserving the tree's vertical branch
182
+ # Indent nested entries, preserving the tree's vertical branch.
170
183
  extension = " " if is_last else "│ "
171
184
  dir_size = _collect_tree(
172
185
  entry,
@@ -176,6 +189,7 @@ def _collect_tree(
176
189
  rows,
177
190
  show_metadata,
178
191
  show_modified,
192
+ show_files,
179
193
  )
180
194
  total_size += dir_size
181
195
  if show_metadata:
@@ -186,25 +200,17 @@ def _collect_tree(
186
200
  stats["files"] += 1
187
201
  stats["total_size"] += size
188
202
  total_size += size
189
- timestamp = modified if show_modified else None
190
- rows.append((tree_name, (size_text, info, timestamp)))
203
+ if show_files:
204
+ timestamp = modified if show_modified else None
205
+ rows.append((tree_name, (size_text, info, timestamp)))
191
206
  else:
192
207
  stats["files"] += 1
193
208
  stats["total_size"] = None
194
- rows.append((tree_name, None))
209
+ if show_files:
210
+ rows.append((tree_name, None))
195
211
  return total_size
196
212
 
197
213
 
198
- def print_summary(stats):
199
- directories = stats["directories"]
200
- files = stats["files"]
201
- total_size = stats["total_size"]
202
- summary = f"{directories:,} directories • {files:,} files"
203
- if total_size:
204
- summary += f" • {_format_size(total_size)}"
205
- print(summary)
206
-
207
-
208
214
  def print_tree(
209
215
  directory,
210
216
  prefix="",
@@ -213,8 +219,9 @@ def print_tree(
213
219
  show_metadata=True,
214
220
  show_modified=False,
215
221
  show_tree=True,
222
+ show_files=True,
216
223
  ):
217
- """Print the directory tree with aligned file metadata."""
224
+ """Print the directory tree with aligned metadata."""
218
225
  if stats is None:
219
226
  stats = {"directories": 0, "files": 0, "total_size": 0}
220
227
  rows = []
@@ -227,18 +234,16 @@ def print_tree(
227
234
  rows,
228
235
  show_metadata,
229
236
  show_modified,
237
+ show_files,
230
238
  )
231
239
  if show_tree:
232
- # Align file metadata with the longest tree/name
233
- max_tree_name_width = max(
234
- (len(tree_name) for tree_name, _ in rows),
235
- default=0,
236
- )
237
- for tree_name, file_info_data in rows:
238
- if file_info_data is None:
240
+ # Align metadata with the longest tree/name
241
+ max_tree_name_width = max((len(tree_name) for tree_name, _ in rows), default=0)
242
+ for tree_name, metadata in rows:
243
+ if metadata is None:
239
244
  print(tree_name)
240
245
  continue
241
- size_text, info, modified = file_info_data
246
+ size_text, info, modified = metadata
242
247
  output = f"{tree_name:<{max_tree_name_width}}{size_text:>10}"
243
248
  if info is not None:
244
249
  output += f" {info:<10}"
@@ -248,11 +253,24 @@ def print_tree(
248
253
  return stats
249
254
 
250
255
 
256
+ def print_summary(stats):
257
+ """Print a summary of directory/file counts and total size."""
258
+ directories = stats["directories"]
259
+ files = stats["files"]
260
+ total_size = stats["total_size"]
261
+ directory_label = "directory" if directories == 1 else "directories"
262
+ file_label = "file" if files == 1 else "files"
263
+ summary = f"{directories:,} {directory_label} • {files:,} {file_label}"
264
+ if total_size is not None:
265
+ summary += f" • {_format_size(total_size)}"
266
+ print(summary)
267
+
268
+
251
269
  def parse_args(argv=None):
252
270
  """Parse command-line arguments."""
253
271
  parser = argparse.ArgumentParser(
254
- description="List directory contents as a tree with "
255
- "file and directory metadata.",
272
+ description="List directory contents as a tree "
273
+ "with file and directory metadata.",
256
274
  )
257
275
  parser.add_argument(
258
276
  "directory",
@@ -265,7 +283,7 @@ def parse_args(argv=None):
265
283
  "-a",
266
284
  "--all",
267
285
  action="store_true",
268
- help="show all files (including those ignored by Git)",
286
+ help="show all files, including those ignored by Git",
269
287
  )
270
288
  parser.add_argument(
271
289
  "-m",
@@ -279,6 +297,12 @@ def parse_args(argv=None):
279
297
  action="store_true",
280
298
  help="don't show file metadata",
281
299
  )
300
+ parser.add_argument(
301
+ "-d",
302
+ "--dirs",
303
+ action="store_true",
304
+ help="show directories only",
305
+ )
282
306
  parser.add_argument(
283
307
  "-s",
284
308
  "--summary",
@@ -289,28 +313,35 @@ def parse_args(argv=None):
289
313
 
290
314
 
291
315
  def main():
292
- args = parse_args()
293
- path = args.directory
294
- if not path.is_dir():
295
- print(f"Not a directory: {path}")
296
- return 1
297
- # Only initialize Git support if it will be used
298
- gitignore = None if args.all else GitIgnore(path)
299
- show_tree = not args.summary
300
- show_metadata = not args.quiet
301
- if show_tree:
302
- print(path)
303
- stats = print_tree(
304
- path,
305
- gitignore=gitignore,
306
- show_metadata=show_metadata,
307
- show_modified=args.modified,
308
- show_tree=show_tree,
309
- )
310
- if show_tree:
311
- print()
312
- print_summary(stats)
313
- return 0
316
+ try:
317
+ args = parse_args()
318
+ path = args.directory
319
+ if not path.is_dir():
320
+ print(f"Not a directory: {path}", file=sys.stderr)
321
+ return 1
322
+ # Only initialize Git support if it will be used
323
+ gitignore = None if args.all else GitIgnore(path)
324
+ show_tree = not args.summary
325
+ show_metadata = not args.quiet
326
+ show_files = not args.dirs
327
+ if show_tree:
328
+ print(path)
329
+ stats = print_tree(
330
+ path,
331
+ gitignore=gitignore,
332
+ show_metadata=show_metadata,
333
+ show_modified=args.modified,
334
+ show_tree=show_tree,
335
+ show_files=show_files,
336
+ )
337
+ if show_tree:
338
+ print()
339
+ print_summary(stats)
340
+ except KeyboardInterrupt:
341
+ print("\nInterrupted", file=sys.stderr)
342
+ return 130
343
+ else:
344
+ return 0
314
345
 
315
346
 
316
347
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: treex-cli
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: List directory contents as a tree with file and directory metadata
5
5
  Author: Corey Goldberg
6
6
  Maintainer: Corey Goldberg
@@ -100,7 +100,7 @@ Install `treex` from [PyPI][pypi-home] using either `pip` or `pipx`:
100
100
 
101
101
  ```
102
102
  $ treex --help
103
- usage: treex [-h] [-a] [-m] [-q] [-s] [directory]
103
+ usage: treex [-h] [-a] [-m] [-q] [-d] [-s] [directory]
104
104
 
105
105
  List directory contents as a tree with file and directory metadata.
106
106
 
@@ -109,9 +109,10 @@ positional arguments:
109
109
 
110
110
  options:
111
111
  -h, --help show this help message and exit
112
- -a, --all show all files (including those ignored by Git)
112
+ -a, --all show all files, including those ignored by Git
113
113
  -m, --modified show file modification times
114
114
  -q, --quiet don't show file metadata
115
+ -d, --dirs show directories only
115
116
  -s, --summary show summary only
116
117
  ```
117
118
 
File without changes
File without changes