Error handling in python if file written with int instead of string - python-3.x

I have a code that works and have a simple question. If I were to change the text-file from strings to integer I want to error handle that. Is it possible? I only get error-warning when I change the integers to strings however I want it to work for changing strings to integer. For example if I change "Football" into a integer I want to get a error-warning. I then want to create an error-handling to print for example: "Something is wrong inside the textfile"
textfile:
Football # 8-9 # Pitch
Basketball # 9-10 # Gym
Lunch # 11-12 # Home
Reading # 13-14 # Library
from pprint import pprint
class Activity:
def __init__(self, name, start_time, end_time, location):
self.name = str(name)
self.start = int(start_time)
self.end = int(end_time)
self.location = str(location)
def read_file(filename):
activities = []
with open(filename, 'r') as f:
for line in f:
activity, time, location = line.strip().split(' # ')
start, end = time.split('-')
activities.append(Activity(activity, start, end, location))
return activities
activities = read_file('sample.txt')
pprint(activities)

You can check if a string is an integer by using isnumeric.
So let's change the input file to:
Football # 8-9 # Pitch
Basketball # 9-10 # Gym
Lunch # 11-12 # Home
3 # 13-14 # Library
Now we want to verify the name, for which we will write a validator:
class Activity:
def __init__(self, name, start_time, end_time, location):
self.name = self.validate_name(name)
self.start = int(start_time)
self.end = int(end_time)
self.location = location
def validate_name(self, name):
if name.isnumeric():
raise TypeError(f"The name: {name!r}, is not a string, please check your input file.")
return name
def __repr__(self):
return f"<{type(self).__name__}, (name={self.name}, start={self.start}, end={self.end}, loc={self.location})>"
Which results in a TypeError:
line 13, in validate_name
raise TypeError(f"The name: {name!r}, is not a string, please check your input file.")
TypeError: The name: '3', is not a string, please check your input file.
Note that your input is already a string, so there was no need to use str(name) and str(location).
Edit
The above solution only verifies if the entire name is an integer. For a solution that checks if the input is using valid characters we can use the re module in python and the method:
import re
def validate_input(self, name):
regex = re.compile('\d')
if regex.match(name):
raise TypeError(f"The name: {name!r}, contains an integer, please check your input file.")
return name
This will break whenever there is an integer in the input name. The previous solution would continue on inputs such as: Football 3, 3 Football. This solution would raise an error.
You can try out the regex expression for yourself on regex101

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 to make x variable change each time and read its value from txt file

I am working on my undergraduate project and this is my first time using Python to control a parrot bebop 2 drone. I have a variable x(an int) and I want to read its value from a file. In the mean time I want the program to read this file continuously; what I mean is that my text file input will be changed each time and I want the Python code to catch this change and change the value x.
For example:
if x is assigned 1 from the text file --> then the drone takes off.
in the mean time after x is assigned the value 1, I want it to be assigned 2 automatically and do the second command, for example: move to the left (but without disconnecting the drone "the first command")
here is my code, but I had a lot of problems with it, it checks the value, but no commands work after it knows the value of x:
bebop = Bebop()
print("connecting")
success = bebop.connect(10)
print(success)
f = open('EEGresults.txt')
lines = f.readlines()
list_of_elements = []
for line in lines:
list_of_elements += map(int, line.split())
f.close()
print (list_of_elements)
x = list_of_elements[1]
bebop.smart_sleep(5)
if x == 1:
print ("Yay! This number is = 1")
bebop.safe_takeoff(3)
else:
if x == 2:
print ("Yay! This number is = 2")
bebop.move_relative(0,0,0,1.6)
I expect that the code will read the value of x from text file directly and continuously and at the same time it will run the commands depending what the value of x that it receives.
I don´t know how to use Bebop but I whould use something like this...
First I would create an object to store the data from your file. So you need something like an onValueChanged callback. You have to define this object on your own:
class NotifierVariable():
def __init__(self):
self.__value = 0
self.__Listener = list()
#NotifierVariable.setter
def set(self, value):
if(value != self.__value):
self.__value = value
for callback in self.__Listener:
callback(self.__value)
#property
def get(self):
return self.__value
def addListener(self, callback):
self.__Listener.append(callback)
You can use it in the following way:
class NotifierVariable():
def __init__(self):
self.__value = 0
self.__Listener = list()
def set(self, value):
if(value != self.__value):
self.__value = value
for callback in self.__Listener:
callback(self.__value)
def get(self):
return self.__value
def addListener(self, callback):
self.__Listener.append(callback)
def Func(value):
print(value)
if __name__ == '__main__':
x = NotifierVariable()
x.addListener(Func)
x.set(10)
Now you have to read the file periodicly:
while(True):
with open('EEGresults.txt') as File:
lines = File.readlines()
list_of_elements = []
for line in lines:
list_of_elements += map(int, line.split())
print (list_of_elements)
x.set(list_of_elements[1])
time.sleep(10)
You use the callback to send the command to your drone. The file is periodicly read out every 10 seconds (you can change it) and update your x variable. A callback is triggered if the value got changed and then you can send a command, based on the input, to your drone.

How can I replace h5py.AttributeManager with a custom class?

I want to store an astropy Quantity in an hdf5 attribute.
What I'm doing at the moment is this:
from astropy import units
import h5py
length_1 = 5.3 * units.meter
# -- Write attribute ----------
with h5py.File("./temp.hdf5", "w") as data:
# write value
data.attrs.create("length", length_1.value)
# write unit
data.attrs.create("lengthUnit", length_1.unit.to_string())
# -- Read attribute -----------
with h5py.File("./temp.hdf5", "r") as data:
# read value
lengthValue = data.attrs["length"]
# read unit
lengthUnit = data.attrs["lengthUnit"]
# recreate length as Quantity
length_2 = lengthValue * units.Unit(lengthUnit)
However, it would be helpful if I could modify the getter/setter process of the AttributeManager to handle any Quantity as I do here.
E.g.
class QuantityAttributeManager(h5py.AttributeManager):
def __init__(self, parent):
super().__init__(parent)
# __setitem__ uses create
def create(self, name, data, shape=None, dtype=None):
if isinstance(data, units.Quantity):
super().create(
name,
data.value
)
super().create(
"{:s}Unit".format(name),
data.unit.to_string().encode("utf-8")
)
else:
super().create(name, data, shape, dtype)
# def __getitem__
# [...]
with h5py.File("./temp.hdf5", "w") as data:
# really this should be:
# data.attrs["length"] = length
# and this is where the problem lies
attr = QuantityAttributeManager(data["/"])
attr["length"] = length_1
print(list(attr.keys())) # ['length', 'lengthUnit']
The .attrs attribute is defined as ([source])
#property
def attrs(self):
""" Attributes attached to this object """
from . import attrs
with phil:
return attrs.AttributeManager(self)
in HLObject, which Dataset and Group inherit. File inherits Group but overrides .attrs.
The best option I can see is to redirect the from . import attrs line to use QuantityAttributeManager instead, but I'm not sure how.
(Preferably without being too hacky.)
A possible solution could be to monkey patch, but then the new attribute manager would always be used.
h5py._hl.attrs.AttributeManager = QuantityAttributeManager
with h5py.File("./temp.hdf5", "w") as data:
data.attrs["length"] = length
print(list(data.attrs.keys())) # ['length', 'lengthUnit']

How to print all the highest value places

I cannot figure out how to get python to print all the highest values as it only prints the first one it encounters.
It takes standard input from a file that has on a few lines the following:
89 Michael Dunne (grade name)
I know I can use the zip function but I cannot figure out how only print the name from it
If I add "highstudents = sorted(zip(grade,name),reverse=True)" it sorts from high to low but I do not know how to filter the name out as it prints as "(89, 'Pepe')"
The code below is the following attempt so far.
import sys
def topgrade(x):
s = max(x)
return s
def main():
s = sys.argv[1]
grade=[]
name = []
try:
with open(s,'r') as studata:
for line in studata:
try:
line = line.strip()
grade.append(int(line[0:2]))
name.append(line[3::])
except ValueError:
print("Invalid mark",line[0:2],"encountered. Skipping.")
top = topgrade(grade)
a = grade.index(top)
print("Best students:",name[a])
print("Best mark:",top)
except FileNotFoundError:
print("File not found:",s)
if __name__ == '__main__':
main()
Rather than trying to keep the students and marks in 2 separate lists (with the risk that they get out of step) it is better to use a dictionary - where the key is the mark and the value is a list of the student(s) who obtained that mark.
Then it is a simple task of just printing out the highest key, and the associated list of students. I'm using defaultdict as an easier option than having to create or append to the list for each value.
from collections import defaultdict
import sys
def main():
s = sys.argv[1]
grades = defaultdict(list)
try:
with open(s,'r') as studata:
for line in studata:
try:
line = line.strip()
grades[int(line[0:2])].append(line[3::])
except ValueError:
print("Invalid mark",line[0:2],"encountered. Skipping.")
top_mark = max(grades.keys())
print("Best students:{}".format(','.join(grades[top_mark])))
print("Best mark: {}".format(top_mark))
except FileNotFoundError:
print("File not found:",s)
if __name__ == '__main__':
main()

Problems removing case sensitivity while searching strings

I'm learning python using open courseware from MIT and one of the problem sets is to learn how to use classes to search RSS feeds for subjects of interest. I am not sure why I am getting the error displayed below. I am trying to convert both the search word string and the string from the news story object to all lowercase before trying to find the word - that way there if the search word is 'soft', then the trigger should fire on a string such as 'Koalas are soft and cuddly' and also 'Soft sandpaper is not effective'.
import string
class NewsStory(object):
#news story is defined by 5 strings: guid, title, subject, summary, and link
def __init__(self, guid, title, subject, summary, link):
self.guid = guid
self.title = title
self.subject = subject
self.summary = summary
self.link = link
def get_guid(self):
return self.guid
def get_title(self):
return self.title
def get_subject(self):
return self.subject
def get_summary(self):
return self.summary
def get_link(self):
return self.link
class Trigger(object):
#abstract class
def evaluate(self, story):
"""
Returns True if an alert should be generated
for the given news item, or False otherwise.
"""
raise NotImplementedError
# Whole Word Triggers
# Problems 2-5
# TODO: WordTrigger
class WordTrigger(Trigger):
def __init__(self, word):
#make search word all lowercase to remove case sensitivity
self.word = string.lower(word)
def is_word_in(self, text):
#make text string from news story all lowercase to remove case sensitivity
self.text = string.lower(text)
#use the find method of the string class
#it returns the lowest index where substring s is found in string; returns -1 if substring not found
return string.find(self.text, self.word) > -1
# TODO: TitleTrigger, this subclass of WordTrigger will trigger on search term that is found in the title string of the news story object
class TitleTrigger(WordTrigger):
def __init__(self, word):
self.word = string.lower(word)
def evaluate(self, story):
#story is an instance of the NewsStory class
title = story.get_title
return super(TitleTrigger, self).is_word_in(title)
#make news story object
news1 = NewsStory('1234','it is raining dogs and cats','animals falling from sky','3 dogs and 2 cats fell from sky','www.cat.com')
#make TitleTrigger object
testTrig = TitleTrigger('cats')
testTrig.evaluate(news1)
The error that I am scratching my head over is displayed below:
>>>
Traceback (most recent call last):
File "C:/Users/David/Documents/Python2_7/Unit 2/postonline.py", line 61, in <module>
testTrig.evaluate(news1)
File "C:/Users/David/Documents/Python2_7/Unit 2/postonline.py", line 55, in evaluate
return super(TitleTrigger, self).is_word_in(title)
File "C:/Users/David/Documents/Python2_7/Unit 2/postonline.py", line 42, in is_word_in
self.text = string.lower(text)
File "C:\WinPython-64bit-2.7.10.3\python-2.7.10.amd64\lib\string.py", line 228, in lower
return s.lower()
AttributeError: 'function' object has no attribute 'lower'

Resources