-
Notifications
You must be signed in to change notification settings - Fork 2
Mirror of 390 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
949f78b
95f3415
63ca183
2dc442d
2c580ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| node_modules | ||
| .venv |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import argparse | ||
| import sys | ||
|
|
||
|
|
||
| def parse_args(): | ||
| parser = argparse.ArgumentParser( | ||
| description="Reads file(s) and writes them to the standard output", | ||
| ) | ||
| parser.add_argument("paths", nargs="+", help="The file path(s) to process") | ||
| parser.add_argument( | ||
| "-n", | ||
| action="store_true", | ||
| dest="number_all", | ||
| help="Number the output lines, starting at 1.", | ||
| ) | ||
| parser.add_argument( | ||
| "-b", | ||
| action="store_true", | ||
| dest="number_nonblank", | ||
| help="Number only non-blank output lines, starting at 1.", | ||
| ) | ||
| return parser.parse_args() | ||
|
|
||
|
|
||
| def main(): | ||
| args = parse_args() | ||
|
|
||
| try: | ||
| for path in args.paths: | ||
| line_num = 1 | ||
|
|
||
| with open(path, "r", encoding="utf-8") as file: | ||
| for raw_line in file: | ||
| line = raw_line.rstrip("\n") | ||
| is_blank = line.strip() == "" | ||
| should_number = args.number_all or ( | ||
| args.number_nonblank and not is_blank) | ||
|
|
||
| if should_number: | ||
| print(f"{line_num} {line}") | ||
| line_num += 1 | ||
| else: | ||
| print(line) | ||
| except OSError as err: | ||
| print(err, file=sys.stderr) | ||
|
|
||
| return 0 | ||
|
|
||
|
|
||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import argparse | ||
| import os | ||
| import stat | ||
| import sys | ||
|
|
||
|
|
||
| def parse_args(): | ||
| parser = argparse.ArgumentParser( | ||
| description="List directory contents", | ||
| ) | ||
| parser.add_argument( | ||
| "paths", | ||
| nargs="*", | ||
| help="The file path to process (defaults to current directory)", | ||
| ) | ||
| parser.add_argument( | ||
| "-a", | ||
| action="store_true", | ||
| dest="include_hidden", | ||
| help="Include directory entries whose names begin with a dot ('.').", | ||
| ) | ||
| parser.add_argument( | ||
| "-1", | ||
| action="store_true", | ||
| dest="one_per_line", | ||
| help="Force output to be one entry per line.", | ||
| ) | ||
| return parser.parse_args() | ||
|
|
||
|
|
||
| def filter_hidden(files: list[str]) -> list[str]: | ||
| return [name for name in files if not name.startswith(".")] | ||
|
|
||
|
|
||
| def get_visible_entries(files: list[str], include_hidden: bool): | ||
| return files if include_hidden else filter_hidden(files) | ||
|
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function 'get_visible_entries' returns either all files or only non-hidden files, depending on the 'include_hidden' flag. The name 'get_visible_entries' might suggest it always returns only visible (non-hidden) files, but in fact, it sometimes returns all files including hidden ones. Could you think of a name that more clearly describes what this function does in both cases? |
||
|
|
||
|
|
||
| def format_entries(files: list[str], one_per_line: bool): | ||
| if len(files) == 0: | ||
| return | ||
| print(("\n" if one_per_line else "\t").join(files)) | ||
|
Comment on lines
+31
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The parameter 'files' in 'format_entries', 'filter_hidden', and 'get_visible_entries' is used for both files and directory entries, which could be files or directories. Do you think a more general name like 'entries' would make it clearer that these lists can contain both files and directories? |
||
|
|
||
|
Comment on lines
+39
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic for formatting and printing entries is used in multiple places (for files and for directories). If you find yourself repeating similar code, how might you extract it into a function to avoid duplication and make future changes easier? |
||
|
|
||
| def main(): | ||
| args = parse_args() | ||
|
|
||
| try: | ||
| file_paths = args.paths if args.paths else ["."] | ||
| include_hidden = bool(args.include_hidden) | ||
| one_per_line = bool(args.one_per_line) | ||
|
|
||
| result_files: list[str] = [] | ||
| result_dirs: dict[str, list[str]] = {} | ||
|
|
||
| for file_path in file_paths: | ||
| st = os.stat(file_path) | ||
| # Is a file? | ||
| if stat.S_ISREG(st.st_mode): | ||
|
Comment on lines
+58
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've noticed you added comments like '# Is a file?' and '# Is a directory?' right above the code that checks if a path is a file or directory. Since the code itself (using stat.S_ISREG and stat.S_ISDIR) is already quite clear about what it's doing, these comments don't add much extra information. When code is self-explanatory, it's often better to avoid comments like these, as they can clutter the code and make it harder to spot comments that actually explain something non-obvious. What do you think about relying on clear variable names and code structure to make your intent clear, and saving comments for places where the code might not be so obvious? |
||
| result_files.append(file_path) | ||
| # Is a directory? | ||
| if stat.S_ISDIR(st.st_mode): | ||
|
Comment on lines
+58
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've noticed that you have comments like '# Is a file?' and '# Is a directory?' right above the code that checks if a path is a file or directory. Since the code itself (using stat.S_ISREG and stat.S_ISDIR) is already quite clear about what it's doing, these comments don't add much value. When code is self-explanatory, extra comments can sometimes make the code harder to read by adding clutter. How might you decide when a comment is truly helpful versus when the code speaks for itself?
Comment on lines
+61
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, you have a comment '# Is a directory?' right before checking if a path is a directory. Since the function name and the code itself make it clear what's happening, this comment doesn't really add new information. Do you think the code would be just as understandable without this comment? Sometimes, removing obvious comments can make your code cleaner and easier to maintain.
Comment on lines
+58
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've noticed you added comments like '# Is a file?' and '# Is a directory?' right above the code that checks if a path is a file or directory. Since the code itself (using stat.S_ISREG and stat.S_ISDIR) is already quite clear about what it's doing, these comments don't add much extra information. When code is self-explanatory, do you think it's helpful to add comments like these, or could it make the code harder to read by adding clutter? How might you decide when a comment is truly needed? |
||
| result_dirs[file_path] = os.listdir(file_path) | ||
|
|
||
| result_files = get_visible_entries(result_files, include_hidden) | ||
|
|
||
| if len(file_paths) == 1: | ||
| entries = list(result_files) | ||
| for contents in result_dirs.values(): | ||
| filtered = get_visible_entries(contents, include_hidden) | ||
| entries.extend(filtered) | ||
| format_entries(entries, one_per_line) | ||
| else: | ||
| format_entries(result_files, one_per_line) | ||
|
|
||
| for directory, contents in result_dirs.items(): | ||
| print("\n" + directory + ":") | ||
| filtered = get_visible_entries(contents, include_hidden) | ||
| format_entries(filtered, one_per_line) | ||
|
Comment on lines
+76
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the section where you print directory contents for multiple directories, the logic for filtering and formatting entries is repeated. If you needed to change how entries are displayed, you'd have to update it in more than one place. How could you refactor this to avoid repeating yourself? |
||
| except OSError as err: | ||
| print(str(err), file=sys.stderr) | ||
|
|
||
| return 0 | ||
|
|
||
|
|
||
| main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| tabulate |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import argparse | ||
| import os | ||
| import sys | ||
|
|
||
| from tabulate import tabulate | ||
|
|
||
|
|
||
| def parse_args(): | ||
| parser = argparse.ArgumentParser( | ||
| description="word, line and byte count", | ||
| ) | ||
| parser.add_argument("paths", nargs="+", | ||
| help="The file path(s) to process.") | ||
| parser.add_argument( | ||
| "-l", | ||
| "--lines", | ||
| action="store_true", | ||
| help="The number of lines in each input file is written to the standard output.", | ||
| ) | ||
| parser.add_argument( | ||
| "-w", | ||
| "--words", | ||
| action="store_true", | ||
| help="The number of words in each input file is written to the standard output.", | ||
| ) | ||
| parser.add_argument( | ||
| "-c", | ||
| "--bytes", | ||
| action="store_true", | ||
| dest="bytes", | ||
| help="The number of bytes in each input file is written to the standard output.", | ||
| ) | ||
| return parser.parse_args() | ||
|
|
||
|
|
||
| def main(): | ||
| args = parse_args() | ||
|
|
||
| try: | ||
| file_paths: list[str] = args.paths | ||
| results: dict[str, dict[str, int]] = {} | ||
|
|
||
| for file_path in file_paths: | ||
| stats = os.stat(file_path) | ||
| count = {"lines": 0, "words": 0, "bytes": stats.st_size} | ||
|
|
||
| with open(file_path, "r", encoding="utf-8") as file: | ||
| for line in file: | ||
| count["lines"] += 1 | ||
| trimmed = line.strip() | ||
| if len(trimmed) > 0: | ||
| count["words"] += len(trimmed.split()) | ||
|
|
||
| results[file_path] = count | ||
|
|
||
| if len(file_paths) > 1: | ||
| total = {"lines": 0, "words": 0, "bytes": 0} | ||
| for file_count in results.values(): | ||
| total["lines"] += file_count["lines"] | ||
| total["words"] += file_count["words"] | ||
| total["bytes"] += file_count["bytes"] | ||
| results["total"] = total | ||
|
|
||
| no_options_provided = not (args.lines or args.words or args.bytes) | ||
| selected_option_keys: list[str] = [] | ||
|
|
||
| if args.lines: | ||
| selected_option_keys.append("lines") | ||
| if args.words: | ||
| selected_option_keys.append("words") | ||
| if args.bytes: | ||
| selected_option_keys.append("bytes") | ||
|
|
||
| output_columns = [ | ||
| "lines", "words", "bytes"] if no_options_provided else selected_option_keys | ||
| rows: list[list[str | int]] = [] | ||
| for name, values in results.items(): | ||
| rows.append([name] + [values[column] for column in output_columns]) | ||
|
|
||
| if no_options_provided: | ||
| print(tabulate(rows, headers=[ | ||
| "index"] + output_columns)) | ||
| else: | ||
| print(tabulate(rows, headers=[ | ||
| "index"] + output_columns)) | ||
|
Comment on lines
+81
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In your code, you have two branches (with and without options) that both print the table using 'tabulate', but the code is almost identical. If you ever wanted to change how you print the table, you'd have to remember to change it in both places. How could you avoid this duplication? |
||
| except OSError as err: | ||
| print(str(err), file=sys.stderr) | ||
|
|
||
| return 0 | ||
|
|
||
|
|
||
| main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function 'get_visible_entries' returns either all files or only non-hidden files, depending on the 'include_hidden' flag. The name 'get_visible_entries' might suggest it always returns only visible (non-hidden) entries, but it can also return hidden ones. Could you think of a name that more clearly describes what this function does based on its parameters?