0

Description

I have been working on this solution for a couple of weeks now. I wrote the code to satisfy all requirements described in the problem set in about three hours. The rest of the time has been spent trying to get check50 to pass, which is a challenge because we do not know what is being tested.

Steps Taken

  1. I completed manual testing including with before.csv deleted down to one line in addition to the headers. All tests pass as expected.
  2. The "scourgify.py creates new CSV file" appears as a random failure, even with no code changes e.g. logging out for the night and logging in the next day.
  3. The "scourgify.py cleans short CSV file, scourgify.py does not produce CSV with specified format" test always fails. I have written code to both implicitly close the CSV files and to monitor sub-processes to confirm that exit code 0 is generated (not included in the code below).

Next steps

  1. It would be useful to know what check50 is expecting e.g. as acceptance criteria.
  2. I will try it on another computer in another location to see if that helps.
  3. I was provided with the suggestion that the issue is possibly a buffering/flushing issue or perhaps a check50 timing error; neither of which I would have expected on an "Introduction to..." course.
  4. If anyone can spot a glaring error in the code sample provided, that would be great! I am TRYING to learn.
  5. I cannot find nothing in the tutorial video for File I/O that relates to small file issues or for "with" failing to close files. I presume the idea is to have folk trawl through the documentation. I have not found anything that relates to this though.
  6. Are there other clean issues that we are supposed to be dealing with e.g. missing headers, other delimiters, non-utf data etc?
import sys
import csv


# scourgify.py to alter the sequence of strings in a .csv file
def main():
    new_format = []
    # Validate CLI input string
    if check_arguments_length(sys.argv):
        try:
            with open(sys.argv[1]) as before:
                reader = csv.DictReader(before)
                for row in reader:
                    last, first = row["name"].split(",")
                    new_format.append(
                        {
                            "first": first.strip(),
                            "last": last.strip(),
                            "house": row["house"].strip(),
                        }
                    )
        except FileNotFoundError:
            sys.exit("File does not exist")
        else:
            # Create and write to after.csv
            with open(sys.argv[2], "w") as after:
                writer = csv.DictWriter(after, fieldnames=["first", "last", "house"])
                # Add header names
                writer.writeheader()
                for row in sorted(
                    new_format, key=lambda new_format: new_format["first"]
                ):
                    writer.writerow(
                        {
                            "first": row["first"],
                            "last": row["last"],
                            "house": row["house"],
                        }
                    )


# Check that sys.argv is the right length
def check_arguments_length(args):
    if len(args) < 3:
        sys.exit("Too few command-line arguments")
    elif len(args) > 3:
        sys.exit("Too many command-line arguments")
    elif not args[1].endswith(".csv") or not args[2].endswith(".csv"):
        sys.exit("Not .csv files")
    else:
        return True


if __name__ == "__main__":
    main()
3
  • 1
    Don't sort the data before writing to output file. It's not in the spec. Follow the spec, nothing more, nothing less. Commented Dec 4, 2023 at 0:49
  • highly suggest avoiding try/except/else try/except it good but using the else there is a horrid practice especially in this case where it makes your code unnecessarily complex. suggest you reduce the nesting as a whole when possible, if chekarguments doesnt succeed you are already exiting, so do you even need an if? why not just throw an exception to catch and handle instead? beyond that what @DinoCoderSaurus said, follow the spec nothing more nothing less.
    – UpAndAdam
    Commented Dec 4, 2023 at 19:18
  • Thanks for the feedback. Much appreciated! Commented Dec 4, 2023 at 19:27

2 Answers 2

1

Success!

I managed to solve this in the end both by including the write loop inside of the read loop, also by including the delimiter and fieldnames parameters along with the if statement to check for fieldnames being recognised as data.

That way, there was no need to use an 'else:' clause.

Use of icecream for debugging was invaluable!

with open(sys.argv[1]) as before, open(sys.argv[2], "w") as after:
    reader = csv.DictReader(
        before, fieldnames=["name", "house"], delimiter=","
    )
    writer = csv.DictWriter(after, fieldnames=["first", "last", "house"])
    # This line writes the header row to the CSV file, based on the field names provided earlier
    writer.writeheader()
    for row in reader:
        # This 'if' statement checks for fieldnames being recognised as data
        if row == {"house": "house", "name": "name"}:
            continue
        last, first = row["name"].split(",")
        new_format = {
            first": first.lstrip(),
            "last": last,
            "house": row["house"],
        }
        # This line writes the content of the new_format dictionary as a row in the after CSV file
        writer.writerow(new_format)
0

This works for me! Turned out I need an lstrip()

def main():
try:
    if len(sys.argv) < 3:
        sys.exit("Too few command-line arguments")
    elif len(sys.argv) > 3:
        sys.exit("Too many command-line arguments")
    else:
        filename = sys.argv[1]
        file = read_file(filename)
        write_file(sys.argv[2], file)

except FileNotFoundError:
        sys.exit("Could not read invalid_file.csv")

def read_file(filename):
new_csv = []
with open(filename) as file:
    reader = csv.DictReader(file)
    for row in reader:
        last, first = row["name"].split(",")
        new_csv.append({"first": first.lstrip(), "last": last.lstrip(), "house": row["house"]})
return new_csv

def write_file(newfilename, data):
with open(newfilename, "w") as file:
    writer = csv.DictWriter(file, fieldnames = ["first","last", "house"])
    writer.writeheader()
    for row in data:
        writer.writerow(row)
return writer
1
  • This is an answer presumably to a different question and does not attempt to answer the current question. The OP already had an lstrip present. Please dont just post an answer because the title matches what you worked on and something worked for you, you have to make a proper connection to the actual question being asked.
    – UpAndAdam
    Commented Jan 2 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .