Python creating object from .txt not working - object

Trying to read a .txt file then turn its information into an object:
class HeaderReader:
#staticmethod
def headerFromFile(filePath):
with open(filePath, 'r') as file:
headerList = HeaderList()
headerFile = ''
for element in range(7):
headerFile += file.readline()
tempList= headerFile.rstrip().split('\n')
#tempList= ['Company:', 'Things', 'Day:', '07:11:1987', 'Time:', '15:55', 'Transfers:']
for splittedEls in tempList:
header = Header(
splittedEls[0],
splittedEls[1],
splittedEls[2],
splittedEls[3],
splittedEls[4],
splittedEls[5],
splittedEls[6]
)
headerList.append(header)
return headerList
Works fine until it reachs splittedEls[4] which is 'Time:' returning IndexError: string index out of range which makes no sense for me. Header class is just a standard 7 paramenters class, will post if needed. Any idea on what's the problem?

I'm dumb, i think the second loop was just wrong, think this works:
class HeaderReader:
#staticmethod
def headerFromFile(filePath):
with open(filePath, 'r') as file:
headerList = HeaderList()
headerFile = ''
for element in range(7):
headerFile += file.readline()
tempList = headerFile.rstrip().split('\n')
header = Header(
tempList[0],
tempList[1],
tempList[2],
tempList[3],
tempList[4],
tempList[5],
tempList[6]
)
return header

Related

Duplicate a string in Tkinter when redirecting output to a text field

I redirect all my output to the program text field in Tkinter and I wanted to add a date and time to the message:
class StdRedirector(object):
def __init__(self, text_field):
self.text_field = text_field
def write(self, string):
msg_time = datetime.now().strftime('%m-%d %H:%M:%S')
self.text_field.configure(state='normal')
self.text_field.insert('end', f'{msg_time} >> {string}')
self.text_field.see('end')
self.text_field.configure(state='disabled')
class App:
def __init__(self):
self.builder = pygubu.Builder()
self.__init_ui()
self.__init_callbacks()
self.mainwindow.mainloop()
def __init_ui(self):
self.builder.add_from_file(path.join(base_dir, 'assets', 'app.ui'))
self.mainwindow = self.builder.get_object('mainwindow')
self.output_text_field = self.builder.get_object('output_text_field')
sys.stdout = StdRedirector(self.output_text_field)
sys.stderr = StdRedirector(self.output_text_field)
def __init_callbacks(self):
callbacks = {
'update_balance_function': self.__update_balance
}
self.builder.connect_callbacks(callbacks)
def __update_balance(self):
print(True)
But the date line I added is duplicated:
As I understand it, the line is separated by the line separator \n and each substring is sent separately, including line break. Can I fix it somehow?
You can simply check whether the string argument in write() contains any meaningful content, e.g. using ìf string.strip():
class StdRedirector(object):
def __init__(self, text_field):
self.text_field = text_field
def write(self, string):
self.text_field.configure(state='normal')
if string.strip(): # add date before message
msg_time = datetime.now().strftime('%m-%d %H:%M:%S')
self.text_field.insert('end', f'{msg_time} >> {string}')
else: # simply insert string
self.text_field.insert('end', string)
self.text_field.see('end')
self.text_field.configure(state='disabled')

How can i catch any error caused by unset module variable?

So I have this function list and showlist but i need to catch any error caused by an unset module variable. can someone help me whats the first thing i should do?
this is my code at the moment
import csv
filep #filepath
menulist = []
def list():
"""Function to read the csv file, create a nested list
and return the list that is sorted based on calories
in the ascending order."""
global menulist
menulist = [] #store items
with open(filep) as csv_file: #read file
reader = csv.reader (csv_file, delimiter=',')
next(reader, None)
for row in reader:
row[2] = int(row[2].strip())
row[1] = float(row[1].strip())
if row[2]> 100 and row[2] <200:
menulist.append(row)
menulist.sort(key=lambda x: x[-1])
def show_list():#Function to display menu
global menulist
for i in range(len(menulist)):
print ('%-4d%-20s%-15s%-15s' %(i + 1, menulist[i][0], menulist[i][2], menulist[i][1]))
list()
show_list()
for example, if the variable file is not set before the list() is called, the function needs to catch an error and prints an appropriate comment
You are using a built-in function name as your function name. Which is not considered as a good practice in Python. It replaces the built-in function list() which is used to create a list. And you need to define a variable before you can use it.
Here's how you can catch the error and print an appropriate comment, with the variable defined:
import csv
filep = str(input("Enter the file name with path : ")) # filepath
menulist = []
def calorieList():
"""Function to read the csv file, create a nested list
and return the list that is sorted based on calories
in the ascending order."""
global menulist
menulist = [] # store items
with open(filep) as csv_file: # read file
reader = csv.reader(csv_file, delimiter=",")
next(reader, None)
for row in reader:
row[2] = int(row[2].strip())
row[1] = float(row[1].strip())
if row[2] > 100 and row[2] < 200:
menulist.append(row)
menulist.sort(key=lambda x: x[-1])
def show_list(): # Function to display menu
global menulist
for i in range(len(menulist)):
print("%-4d%-20s%-15s%-15s" % (i + 1, menulist[i][0], menulist[i][2], menulist[i][1]))
try:
calorieList()
except FileNotFoundError:
print("Enter a valid file path.")
show_list()
I assume you meant filep by the file variable.
If you try to access filep before it is set, your program should raise NameError: name 'filep' is not defined.
But if you want to raise a custom error message, you can just use a try-except block as follows:
import csv
filep #filepath
menulist = []
def list():
"""Function to read the csv file, create a nested list
and return the list that is sorted based on calories
in the ascending order."""
global menulist
menulist = [] #store items
try:
with open(filep) as csv_file: #read file
reader = csv.reader (csv_file, delimiter=',')
next(reader, None)
for row in reader:
row[2] = int(row[2].strip())
row[1] = float(row[1].strip())
if row[2]> 100 and row[2] <200:
menulist.append(row)
except NameError:
raise ValueError("Your custom message here")
menulist.sort(key=lambda x: x[-1])
def show_list():#Function to display menu
global menulist
for i in range(len(menulist)):
print ('%-4d%-20s%-15s%-15s' %(i + 1, menulist[i][0], menulist[i][2], menulist[i][]))
list()
show_list()

How to determine the number of columns per row variably in a CSV File with Python?

I am analyzing xml-structured Textfiles about insider dealings. I wrote some code to parse through the XML-structure and write my output in a CSV file. The results of the files are written per line and the analyzed information is written in individual columns. But in some files information is present in multiple times and my code override the information in the cells, in the end only one date is in the cell of my CSV-File.
import csv
import glob
import re
import string
import time
import bs4 as bs
# User defined directory for files to be parsed
TARGET_FILES = r'D:\files\'
# User defined file pointer to LM dictionary
# User defined output file
OUTPUT_FILE = r'D:\ouput\Parser.csv'
# Setup output
OUTPUT_FIELDS = [r'Datei', 'transactionDate', r'transactionsCode', r'Director', r'Officer', r'Titel', r'10-% Eigner', r'sonstiges', r'SignatureDate']
def main():
f_out = open(OUTPUT_FILE, 'w')
wr = csv.writer(f_out, lineterminator='\n', delimiter=';')
wr.writerow(OUTPUT_FIELDS)
file_list = glob.glob(TARGET_FILES)
for file in file_list:
print(file)
with open(file, 'r', encoding='UTF-8', errors='ignore') as f_in:
soup = bs.BeautifulSoup(f_in, 'xml')
output_data = get_data(soup)
output_data[0] = file
wr.writerow(output_data)
def get_data(soup):
# overrides the transactionDate if more than one transactions disclosed on the current form
# the number determine the column for the output
_odata = [0] * 9
try:
for item in soup.find_all('transactionDate'):
_odata[1] = item.find('value').text
except AttributeError:
_odata[1] = ('keine Angabe')
try:
for item in soup.find_all('transactionAcquiredDisposedCode'):
_odata[2] = item.find('value').text
except AttributeError:
_odata[2] = 'ka'
for item in soup.find_all('reportingOwnerRelationship'):
try:
_odata[3] = item.find('isDirector').text
except AttributeError:
_odata[3] = ('ka')
try:
_odata[4] = item.find('isOfficer').text
except AttributeError:
_odata[4] = ('ka')
try:
_odata[5] = item.find('officerTitle').text
except AttributeError:
_odata[5] = 'ka'
try:
_odata[6] = item.find('isTenPercentOwner').text
except AttributeError:
_odata[6] = ('ka')
try:
_odata[7] = item.find('isOther').text
except AttributeError:
_odata[7] = ('ka')
try:
for item in soup.find_all('ownerSignature'):
_odata[8] = item.find('signatureDate').text
except AttributeError:
_odata[8] = ('ka')
return _odata
if __name__ == '__main__':
print('\n' + time.strftime('%c') + '\nGeneric_Parser.py\n')
main()
print('\n' + time.strftime('%c') + '\nNormal termination.')
Actually the code works, but overwrites columns if, for e.g. more than one transacion date is given in the file. So I need a code that automatically uses the next column for each transaction date. How could this work?
I would be glad if someone have a solution for my problem. Thanks a lot!
Your issue is that you are iterating over the result of
soup.find_all()
and every time you are writing to the same value. You need to do something with
_odata in each iteration, otherwise you will only end up with whatever is written to it the last time.
If you can show us what the data you're trying to parse actually looks like, perhaps we could give a more specific answer.

Exporting Python to Excel is only showing one row of data [duplicate]

I have data which is being accessed via http request and is sent back by the server in a comma separated format, I have the following code :
site= 'www.example.com'
hdr = {'User-Agent': 'Mozilla/5.0'}
req = urllib2.Request(site,headers=hdr)
page = urllib2.urlopen(req)
soup = BeautifulSoup(page)
soup = soup.get_text()
text=str(soup)
The content of text is as follows:
april,2,5,7
may,3,5,8
june,4,7,3
july,5,6,9
How can I save this data into a CSV file.
I know I can do something along the lines of the following to iterate line by line:
import StringIO
s = StringIO.StringIO(text)
for line in s:
But i'm unsure how to now properly write each line to CSV
EDIT---> Thanks for the feedback as suggested the solution was rather simple and can be seen below.
Solution:
import StringIO
s = StringIO.StringIO(text)
with open('fileName.csv', 'w') as f:
for line in s:
f.write(line)
General way:
##text=List of strings to be written to file
with open('csvfile.csv','wb') as file:
for line in text:
file.write(line)
file.write('\n')
OR
Using CSV writer :
import csv
with open(<path to output_csv>, "wb") as csv_file:
writer = csv.writer(csv_file, delimiter=',')
for line in data:
writer.writerow(line)
OR
Simplest way:
f = open('csvfile.csv','w')
f.write('hi there\n') #Give your csv text here.
## Python will convert \n to os.linesep
f.close()
You could just write to the file as you would write any normal file.
with open('csvfile.csv','wb') as file:
for l in text:
file.write(l)
file.write('\n')
If just in case, it is a list of lists, you could directly use built-in csv module
import csv
with open("csvfile.csv", "wb") as file:
writer = csv.writer(file)
writer.writerows(text)
I would simply write each line to a file, since it's already in a CSV format:
write_file = "output.csv"
with open(write_file, "wt", encoding="utf-8") as output:
for line in text:
output.write(line + '\n')
I can't recall how to write lines with line-breaks at the moment, though :p
Also, you might like to take a look at this answer about write(), writelines(), and '\n'.
To complement the previous answers, I whipped up a quick class to write to CSV files. It makes it easier to manage and close open files and achieve consistency and cleaner code if you have to deal with multiple files.
class CSVWriter():
filename = None
fp = None
writer = None
def __init__(self, filename):
self.filename = filename
self.fp = open(self.filename, 'w', encoding='utf8')
self.writer = csv.writer(self.fp, delimiter=';', quotechar='"', quoting=csv.QUOTE_ALL, lineterminator='\n')
def close(self):
self.fp.close()
def write(self, elems):
self.writer.writerow(elems)
def size(self):
return os.path.getsize(self.filename)
def fname(self):
return self.filename
Example usage:
mycsv = CSVWriter('/tmp/test.csv')
mycsv.write((12,'green','apples'))
mycsv.write((7,'yellow','bananas'))
mycsv.close()
print("Written %d bytes to %s" % (mycsv.size(), mycsv.fname()))
Have fun
What about this:
with open("your_csv_file.csv", "w") as f:
f.write("\n".join(text))
str.join() Return a string which is the concatenation of the strings in iterable.
The separator between elements is
the string providing this method.
In my situation...
with open('UPRN.csv', 'w', newline='') as out_file:
writer = csv.writer(out_file)
writer.writerow(('Name', 'UPRN','ADMIN_AREA','TOWN','STREET','NAME_NUMBER'))
writer.writerows(lines)
you need to include the newline option in the open attribute and it will work
https://www.programiz.com/python-programming/writing-csv-files

can't set attribute in class instance in Python

I'm trying to create a instance of a class to test that the module I created is working properly.
Here is the module (fileWriter.py), the error appears to be in the init method:
class File(object):
'''process the data from a file'''
#fields
#fileName = name of file
#textData = data read from/written to file
#Constructor
def __init__(self, fileName = 'saved_data.txt', textData = ''):
#Attributes
self.fileName = fileName
self.textData = textData
#Properties
#property #getter
def fileName(self):
return self.__fileName
#fileName.setter #setter
def fileName(self, value):
self.__fileName = value
#property #getter
def textData(self, value):
self.__textData = value
#Methods
def saveData(self):
'''appends data to file'''
try:
fileObj = open(self.fileName, 'a')
fileObj.write(self.textData)
fileObj.close()
except Exception as e:
print('You have the following error: ' + str(e))
return('Data successfully saved to file.')
def toString(self):
'''returns text data explicitly'''
return self.fileName + ':' + self.textData
def __str__(self):
'''returns text data implicitly'''
return self.toString()
To test the class, I wrote the following test harness:
import fileWriter
import fileWriter
#test harness
processorObj = fileWriter.File()
processorObj.fileName = 'test.txt'
processorObj.textData = 'testing, 1, 2, 3...'
strMessage = processorObj.saveData()
print(strMessage)
if __name__ == '__main__':
raise Exception('Don\'t run a module by itself!')
When I run the test file, I get the error:
File "testFileWriter.py", line 4, in
processorObj = fileWriter.File()
File "/Users/Haruka/Documents/python_class/Employees/fileWriter.py", line 19, in init
self.textData = textData
AttributeError: can't set attribute
I can't figure out what's wrong with self.textData = textData. Can anybody help?
I'm not sure if you formatted your code after pasting, but there are a few typos:
def __init__(self, file_name = 'saved_data.txt', text_data = ''):
#Attributes
self.__file_name = file_name
self.__text_data = text_data
and
#property #getter
def text_data(self):
return self.__text_data
Later in test, you're also trying to set the text_data property without a setter in your example. You can add to your class:
#textData.setter
def text_data(self, value):
self.__text_data = value
The more pythonic way to do some of the file io stuff is with a context.
def save_data(self):
'''appends data to file'''
with open(self.file_name, 'a') as f:
f.write(self.text_data)
return('Data successfully saved to file.')

Resources