Write a CSV file asynchronously in Python - python

I am writing a CSV file with the following function:
import csv
import os
import aiofiles
async def write_extract_file(output_filename: str, csv_list: list):
"""
Write the extracted content into the file
"""
try:
async with aiofiles.open(output_filename, "w+") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=columns.keys())
writer.writeheader()
writer.writerows(csv_list)
except FileNotFoundError:
print("Output file not present", output_filename)
print("Current dir: ", os.getcwd())
raise FileNotFoundError
However, as there is no await allowed over writerows method, there are no rows being written into the CSV file.
How to resolve this issue? Is there any workaround available?
Thank you.
Entire code can be found here.

You can use aiocsv. Here is a quick example of writing a row to a CSV file asynchronously:
import asyncio
import aiofiles
from aiocsv import AsyncWriter
async def main():
async with aiofiles.open('your-path.csv', 'w') as f:
writer = AsyncWriter(f)
await writer.writerow(['name', 'age'])
await writer.writerow(['John', 25])
asyncio.run(main())
For more examples follow: https://pypi.org/project/aiocsv/

In my opinion it’s better not to try to use the aiofiles with the csv module and run the synchronous code using loop.run_in_executor and wait it asynchronously like below:
def write_extract_file(output_filename: str, csv_list: list):
"""
Write the extracted content into the file
"""
try:
with open(output_filename, "w+") as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=columns.keys())
writer.writeheader()
writer.writerows(csv_list)
except FileNotFoundError:
print("Output file not present", output_filename)
print("Current dir: ", os.getcwd())
raise FileNotFoundError
async def main():
loop = asyncio.get_running_loop()
await loop.run_in_executor(None, write_extract_file, 'test.csv', csv_list)

You can use aiofiles, you just gotta convert the dict to a row :)
import aiofiles
async def write_extract_file(
output_filename: str, csv_list: list
):
cols = columns.keys()
async with aiofiles.open(output_filename, mode='w+') as f_out:
await f_out.write(','.join(cols)+'\n')
for data in csv_list:
line = []
for c in cols:
line.append(str(data[c]) if c in data else '')
line = ','.join(line) + '\n'
await f_out.write(line)

Related

Using with open from other file

I have a Python file were I want to add functions that I don't want to have in my main code like open csv files which is this case. The problem is when I want to invoke the function where I have the method "open with" the error:
"ValueError: I/O operation on closed file."
appears and for what I found this happens because indentation.
main.py:
from external_tools import read_csv
import unittest
class ClassTest(unittest.TestCase):
def test_a(self):
csv_file = "file.csv"
csv_reader = read_csv(csv_file)
for line in csv_reader:
print(line[0])
if __name__ == '__main__':
unittest.main()
external_tools.py
import datetime
import csv
def epoch_converter():
epoch_time = 40246871
date_time = datetime.datetime.fromtimestamp(epoch_time)
print("Given epoch time: ", epoch_time)
print("Converted Datetime: ", date_time)
def read_csv(csv_file):
with open(csv_file, 'r') as csv_file:
csv_reader = csv.reader(csv_file)
print(csv_reader)
return csv_reader
Is there any way to do it in this way or do I have to use open with in my main?
Here's how to do what I suggested in my comment, which was to turn read_csv into a context manager itself using contextlib.contextmanager as a function decorator.
main.py
from external_tools import read_csv
import unittest
class ClassTest(unittest.TestCase):
def test_a(self):
csv_file = "testfile.csv"
with read_csv(csv_file) as csv_reader:
for row in csv_reader:
print(row)
if __name__ == '__main__':
unittest.main()
external_tools.py
import datetime
from contextlib import contextmanager
import csv
def epoch_converter():
epoch_time = 40246871
date_time = datetime.datetime.fromtimestamp(epoch_time)
print("Given epoch time: ", epoch_time)
print("Converted Datetime: ", date_time)
#contextmanager
def read_csv(csv_file):
with open(csv_file, 'r', newline='') as csv_file:
csv_reader = csv.reader(csv_file)
yield csv_reader
print('csv file closed')

How to save user id only once in json file discord.py

The code I have saves the same user in the json file again:
#client.command()
async def Shibaku1(ctx, coin1, coin2, coin3, coin4, coin5, coin6):
with open('Shibaku1.json', 'r') as f:
coins_data = json.load(f)
coins_data[ctx.author.id] = (coin1, coin2, coin3, coin4, coin5, coin6)
with open('Shibaku1.json', 'w') as f:
json.dump(coins_data, f)
I tried making an if statement in order to not happen, but it didn't seem to work
Python automatically updates keys in dictionary if they exist.
You should convert ctx.author.id to str using str(ctx.author.id):
#client.command()
async def Shibaku1(ctx, coin1, coin2, coin3, coin4, coin5, coin6):
with open('Shibaku1.json', 'r') as f:
coins_data = json.load(f)
coins_data[str(ctx.author.id)] = (coin1, coin2, coin3, coin4, coin5, coin6)
with open('Shibaku1.json', 'w') as f:
json.dump(coins_data, f)

Command SetPrefix and Json? Discord py

First:
I wanted to add more functions to my bot so that I created a new folder where I would try new things!
Second:
I wanted to add a command to set a prefix!
Third:
I added a prefix.json file and a start.bat to start the bot next to the bot.py
Fourth:
TROUBLE!
When writing the script with more than 1280 likes, the bat and the python file did not load, they both closed
Fifth:
The script!
import discord
import json
from discord.ext import commands
def get_prefix(bot, message):
with open('prefix.json', 'r') as f:
prefixes = json.load(f)
return prefixes[str(guild.id)] = '.'
token = 'Private (-:'
bot = commands.Bot(command_prefix='c:', help_command=None)
#bot.event
async def on_ready():
print('Ya estoy')
#bot.event
async def on_guild_join(guild):
with open('prefix.json', 'r') as f:
prefixes = json.load(f)
prefixes[str(guild.id)] = '.'
with open('prefix.json', 'w') as f:
json.dump(prefixes, f, indent=4)
#bot.event
async def on_guild_remove(guild):
with open('prefix.json', 'r') as f:
prefixes = json.load(f)
prefixes.pop(str(guild.id))
with open('prefix.json', 'w') as f:
json.dump(prefixes, f, indent=4)
#bot.command()
async def setprefix(ctx, prefix):
with open('prefix.json', 'r') as f:
prefixes = json.load(f)
prefixes[str(ctx.guild.id)] = prefix
with open('prefix.json', 'w') as f:
json.dump(prefixes, f, indent=4)
bot.run(token)
First: What's the problem there?
Second: your get_prefix function needs to be passed into the command_prefix of Bot
code:
def get_prefix(bot, message):
with open('prefix.json', 'r') as f:
prefixes = json.load(f)
return prefixes[str(message.guild.id)]
bot = commands.Bot(command_prefix=get_prefix, help_command=None)
Third: what's the issue with your bat file?
fourth: I'm not sure what your bat is doing and what you're doing with it.

Url's from CSV not passing to function

I'm trying to pass Urls from a .csv to a function that will send requests to SMMRY api. The .csv has a column labeled 'url', and the API summarizes websites using SMMRY (https://smmry.com/) and asyncio. The smmrpy module creates an "article" object and while it can print the properties, I'm trying to past a list of URLs to the function and have it loop and print summarizations until complete
The problem is, the urls aren't being passed to the function. Below is my code
import time
import csv
import asyncio
import smmrpy
s = smmrpy.SMMRPY("ABCDEFGHI")
with open('Dec1.csv') as csvFile:
reader = csv.DictReader(csvFile)
for row in reader:
URL = (row['url'])
async def main():
article = await s.get_smmry(URL)
global contents
contents = article.content
#print(contents)
print(article.keywords)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
print(contents)
I can't test this, but try:
import time
import csv
import asyncio
import smmrpy
async def main():
s = smmrpy.SMMRPY("ABCDEFGHI")
with open('Dec1.csv') as csvFile:
reader = csv.DictReader(csvFile)
for row in reader:
URL = (row['url'])
article = await s.get_smmry(URL)
contents = article.content
print(contents)
print(article.keywords)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Write a result of a function in a csv

I'm trying to write the result of a function in a csv. Unfortunately, no pandas.
csv file input:
Hello all well?
today is cold!
I have not had lunch yet
He does not have many brothers or sisters.
We are sick
Script:
import re
import csv
import string
with open('teste_csv.csv', 'r') as f:
file = csv.reader(f)
for line in file:
message = ''.join(line)
def toto(message):
message = message.lower()
p = re.compile('|'.join(map(re.escape, string.punctuation)))
no_punct = p.sub(' ', message)
writer = csv.writer(open('result.csv', 'w'))
for row in no_punct:
writer.writerow(row)
return writer
print(toto(message))
At my terminal, I have <_csv.writer object at 0x7fee60e57c50> and in my result.csv I have only one line written 'w'. I would like each line to be in my result.csv
You keep erasing the file since everytime you call toto it opens result.csv for writing, hence you are left only with a single write. You need to open the file once ,and create the wirter once. You also only need to define the function once for that matter:
import re
import csv
import string
def toto(message,writer):
message = message.lower()
p = re.compile('|'.join(map(re.escape, string.punctuation)))
no_punct = p.sub(' ', message)
for row in no_punct:
writer.writerow(row)
with open('teste_csv.csv', 'r') as f:
writer = csv.writer(open('result.csv','w'))
file = csv.reader(f)
for line in file:
message = ''.join(line)
toto(message,writer)
You need to put the writer outside of your first loop. each time you are looping throw it's opening and rewriting the file
another issue you are defining and calling the toto inside the loop so it's getting called with last message value.
import re
import csv
import string
with open('test.csv', 'r') as f:
file = csv.reader(f)
writer = csv.writer(open('result.csv', 'w'))
def toto(message):
message = message.lower()
p = re.compile('|'.join(map(re.escape, string.punctuation)))
no_punct = p.sub(' ', message)
for row in no_punct:
writer.writerow(row)
return writer
for line in file:
print line
message=''.join(line)
print(toto(message))

Categories