5

I have an endpoint that takes a csv file.

Now, I want to write a test that makes a post request with this file.

I am trying to generate this csv file on the fly (rather than manually create and store it)

I tried this:

def csv_fixture(rows, type):
    headers = None
    if type == "merchant_upload":
        headers = MerchantCSV.ordered_columns()
    elif type == "invoice_upload":
        headers = InvoiceCSV.ordered_columns()
    assert headers is not None
    rows = [headers] + rows
    with open("file.csv", "w+") as f:
        writer = csv.writer(f)
        writer.writerows(rows)
        yield f

my_file = csv_fixture(merchants, type="merchant_upload")
request = rf.post("/invoice_admin/upload_organisations/",
                      {"onboarding_file": my_file})

My endpoint does something like this:

    if filename not in request.FILES:
        raise Exception("Upload Failed: No file submitted.")
    file = TextIOWrapper(
        request.FILES[filename].file, encoding=request.encoding)

    headers = peek_first_row(file)
    missing = required_cols - set(headers)
    if missing:
        raise Exception(f"Columns missing in csv: {str(missing)})")

    return csv.DictReader(file)

My endpoint works if I manually upload the file. However, if I try doing it programatically with the first snipper, I get an error:


    def peek_first_row(file):
        rows = csv.reader(file)
>       headers = next(rows)
E       StopIteration

app/invoice_admin/csv_parser.py:11: StopIteration

Please could someone guide me? I have looked at lots of tutorials, but I'm lost at this point.

1 Answer 1

2

This might help.

Ex:

def csv_fixture(rows, type):
    headers = None
    if type == "merchant_upload":
        headers = MerchantCSV.ordered_columns()
    elif type == "invoice_upload":
        headers = InvoiceCSV.ordered_columns()
    assert headers is not None
    rows = [headers] + rows
    with open("file.csv", "w+") as f:
        writer = csv.writer(f)
        writer.writerows(rows)
    return open("file.csv", "rb")

my_file = csv_fixture(merchants, type="merchant_upload")
request = rf.post("/invoice_admin/upload_organisations/",
                      files={"onboarding_file": my_file})
Sign up to request clarification or add additional context in comments.

3 Comments

thank you! This worked! Do you know of a more pythonic way of writing the above code?
the receiver would have to manually close the file though, right? I think a combination of with() and yield would be better?
also I don't want to store the file, the current code stores it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.