-
-
Notifications
You must be signed in to change notification settings - Fork 27
LONDON SDC | Anna Fedyna | Module-Tools | Week 4 | Implement Shell Tools in Python #51
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
a44e356
eff137f
fa3122d
670c026
1763633
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 |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import argparse | ||
|
||
parser = argparse.ArgumentParser( | ||
prog='Cat Command', | ||
description='Display and concatenate files contents') | ||
|
||
parser.add_argument("-n", help="Number the output lines, starting at 1.", default = None, action="store_true") | ||
parser.add_argument("-b", help="Number the non-blank output lines, starting at 1.", default = None, action="store_true") | ||
parser.add_argument("paths", nargs="+", help="The file to search") | ||
|
||
args = parser.parse_args() | ||
|
||
for path in args.paths: | ||
try: | ||
with open(path, "r") as f: | ||
content = f.read() | ||
if args.n or args.b : | ||
counter = 1 | ||
arr = content.split('\n')[:-1] | ||
for line in arr: | ||
if args.b and not line: | ||
print(line) | ||
continue | ||
print(counter, line) | ||
counter += 1 | ||
except FileNotFoundError: | ||
print(f"Error: File '{path}' not found.") | ||
Comment on lines
+26
to
+27
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. Very good catching of the error cases, this really improves the user's experience. Congrats! |
||
except Exception as e: | ||
print(f"An error occurred: {e}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import argparse | ||
import os | ||
|
||
parser = argparse.ArgumentParser( | ||
prog='ls command', | ||
description='list directory contents') | ||
|
||
parser.add_argument("-1", "--one", help="Force output to be one entry per line.", default = None, action="store_true") | ||
parser.add_argument("-a", help="Include directory entries whose names begin with a dot (.).", default = None, action="store_true") | ||
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. When I run the $ ls -a sample-files
. .. .hidden.txt 1.txt 2.txt 3.txt dir How could you change your solution to make sure they are printed? |
||
parser.add_argument("paths", nargs="*", help="The file to search") | ||
|
||
args = parser.parse_args() | ||
cwd = os.getcwd() | ||
|
||
def list_docs(dir_to_procccess): | ||
try: | ||
documents = [document for document in os.listdir(dir_to_procccess)] | ||
doc_to_output = [] | ||
for doc in documents: | ||
if not args.a and doc.startswith("."): | ||
continue | ||
else: | ||
doc_to_output.append(doc) | ||
doc_to_output.sort() | ||
if args.one: | ||
for doc in doc_to_output: | ||
print(doc) | ||
else: | ||
print(' '.join(doc_to_output)) | ||
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 ls, files are printed with a certain amount of padding, so that if we have many files, they appear to be in a table:
This is not part of the assignment brief but, as a streacth goal, would you like to consider how to pad the outputs like that? |
||
except FileNotFoundError: | ||
print(f"Error: Directory '{dir_to_procccess}' not found.") | ||
except NotADirectoryError: | ||
print(f"Error: '{dir_to_procccess}' is not a directory.") | ||
except Exception as e: | ||
print(f"An unexpected error occurred: {e}") | ||
|
||
if args.paths: | ||
for directory in args.paths: | ||
try: | ||
dir_to_procccess = os.path.join(cwd, directory) | ||
list_docs(dir_to_procccess) | ||
except Exception as e: | ||
print(f"An unexpected error occurred: {e}") | ||
else: | ||
list_docs(cwd) | ||
Comment on lines
+44
to
+45
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. Good catch on the behaviour of |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,72 @@ | ||||||
import argparse | ||||||
import os | ||||||
import re | ||||||
|
||||||
parser = argparse.ArgumentParser( | ||||||
prog='wc command', | ||||||
description='word, line, character, and byte count') | ||||||
|
||||||
parser.add_argument("-c", "--bytes", help="The number of bytes in each input file is written to the standard output.", default = None, action="store_true") | ||||||
parser.add_argument("-l", "--lines", help="The number of lines in each input file is written to the standard output.", default = None, action="store_true") | ||||||
parser.add_argument("-w", "--words", help="The number of words in each input file is written to the standard output.", default = None, action="store_true") | ||||||
parser.add_argument("paths", nargs="+", help="The file to search") | ||||||
|
||||||
args = parser.parse_args() | ||||||
cwd = os.getcwd() | ||||||
|
||||||
|
||||||
def count_lines(content): | ||||||
return len(content.splitlines()) | ||||||
|
||||||
def count_words(content): | ||||||
return len(re.findall("[a-zA-Z\-\.'/]+", content)) | ||||||
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. Whenever I run this solution, I see the following warning:
While the code seems to work even with the warning, could you elaborate on what could be the reason for the warning? |
||||||
|
||||||
def count_bytes(content): | ||||||
return len(content.encode('utf-8')) | ||||||
|
||||||
def process_file_content(content, path): | ||||||
if not args.lines and not args.words and not args.bytes: | ||||||
global no_options | ||||||
no_options = True | ||||||
lines_in_file = count_lines(content) | ||||||
words_in_file = count_words(content) | ||||||
bytes_in_file = count_bytes(content) | ||||||
print(lines_in_file, words_in_file, bytes_in_file, path) | ||||||
return {'lines': lines_in_file, 'words':words_in_file, 'bytes':bytes_in_file} | ||||||
output = {} | ||||||
if args.lines: | ||||||
output['lines'] = count_lines(content) | ||||||
if args.words: | ||||||
output['words'] = count_words(content) | ||||||
if args.bytes: | ||||||
output['bytes'] = count_bytes(content) | ||||||
print(' '.join([ str(val) for val in output.values()]), path) | ||||||
return output | ||||||
|
||||||
total_lines, total_words, total_bytes = 0, 0, 0 | ||||||
for path in args.paths: | ||||||
try: | ||||||
file_path_to_procccess = os.path.join(cwd, path) | ||||||
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.
Suggested change
Typo: There was an extra c :D This is not relevant for the code working, but in a real code review it's likely to get pointed out, so I do it here as well. If you decide to change it, note that you'll have to change every place where that variable is used. |
||||||
if os.path.isfile(file_path_to_procccess) : | ||||||
with open(file_path_to_procccess, 'r') as f: | ||||||
file_content = f.read() | ||||||
dict_output = process_file_content(file_content, path) | ||||||
total_lines += dict_output['lines'] if args.lines or no_options else 0 | ||||||
total_words += dict_output['words'] if args.words or no_options else 0 | ||||||
total_bytes += dict_output['bytes'] if args.bytes or no_options else 0 | ||||||
elif os.path.isdir(file_path_to_procccess): | ||||||
print(f"{path}: Is a directory") | ||||||
except FileNotFoundError: | ||||||
print(f"Error: File '{file_path_to_procccess}' not found.") | ||||||
Comment on lines
+59
to
+60
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. What happens if I pass three files, but the second one is missing? How will that affect the output? |
||||||
except Exception as e: | ||||||
print(f"An unexpected error occurred: {e}") | ||||||
|
||||||
if len(args.paths) > 1: | ||||||
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. When I pass more than one line and any flag, I get the following error: For instance, with this invocation:
What could be the cause of this? |
||||||
if no_options: | ||||||
print(total_lines, total_words, total_bytes, 'total') | ||||||
else: | ||||||
total_output_line = [] | ||||||
if args.lines: total_output_line.append(str(total_lines)) | ||||||
if args.words: total_output_line.append(str(total_words)) | ||||||
if args.bytes: total_output_line.append(str(total_bytes)) | ||||||
print(' '.join(total_output_line), 'total') |
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.
What happens if neither
-n
nor-b
are used?For instance, what will your solution print if we invoke it like this:
python3 cat.py sample-files/1.txt
?