Adding to a date, checking if past expiration date - python

One part of my program requires that the user enters a date and this date is then checked against each product in the dictionary to see if the date the product arrived plus its shelf life causes the product to expire before or after the date entered by the user.
import sys
from string import *
import pickle
import datetime
cheeseDictionary = {}
userInput = ""
def loadProduct(fileName):
global cheeseDictionary
f = open(fileName,"r")
line = f.readline() # Reads line from file
while line:
line = line[:-1]
data = split(line,":") # Splits line when there is a colon
cheeseDictionary[data[0]] = {"date":data[1], "life":data[2], "name":data[3]} # Stores each split item
line = f.readline() # Next line
f.close()
def saveProduct(fileName,cheeseDictionary):
f = open(fileName, "w")
for i in sorted(cheeseDictionary.keys()):
v = cheeseDictionary[i]
f.write("%s:%s:%s:%s\n" % (i, v["date"], v["life"], v["name"]))
f.close()
def printProduct(cheeseDictionary):
print "ID"," ","Date"," ","Life(days)"," ","Name"
for cheese in cheeseDictionary:
print cheese," ",cheeseDictionary[cheese]["date"]," ",cheeseDictionary[cheese]["life"]," ",cheeseDictionary[cheese]["name"]
def addProduct():
global cheeseDicitonary
correct = 0
idInput = ""
dateInput = ""
lifeInput = ""
nameinput = ""
while correct != 1:
idInput = raw_input("Please enter the ID of the cheese to be added. ")
if cheeseDictionary.has_key(idInput):
print ("This ID already exists. Please try again.")
correct = 0
else:
newID = idInput
correct = 1
dateInput = raw_input("Please enter the date of the cheese to be added in the format dd/mm/yyyy. ")
lifeInput = raw_input("Please enter the life of the cheese to be added in days. ")
nameInput = raw_input("Please enter the name of the cheese to be added. ")
cheeseDictionary[idInput] = {"date":dateInput, "life":lifeInput, "name":nameInput}
def checkProduct(cheeseDictionary):
dateCheck = raw_input("Please enter the date in the format dd/mm/yyyy: ")
for cheese in cheeseDictionary:
I know I need to change the dates store din the dictionary into the date time format but I am unsure how to do this. Thanks for any advice given. :)

If I understand correctly, you need to transform strings representing dates in the format "dd/mm/yyyy" into datetime objects?
If so, you should use the datetime.strptime method. For example:
from datetime import datetime
d = datetime.strptime("28/03/2011", "%d/%m/%Y")
print repr(d)
This prints:
datetime.datetime(2011, 3, 28, 0, 0)

In order to parse a date string into a datetime object, you can use the strptime method:
http://www.tutorialspoint.com/python/time_strptime.htm
Almost everything you ever need to know about Python can be found in the documentation. Here is the documentation of datetime:
http://docs.python.org/library/datetime.html
As for date maths (addition and subtraction), they can be done by adding or subtracting a timedelta object to/from a datetime object. Here are the allowed operations:
datetime2 = datetime1 + timedelta
datetime2 = datetime1 - timedelta
timedelta = datetime1 - datetime2
datetime1 < datetime2
All the details can be found on the documentation page in the link above.
And here is another little tutorial on date maths:
http://phr0stbyte.blogspot.com/2008/08/python-datetime-math.html

For the heck of it I've done a pretty comprehensive object-oriented rewrite:
import datetime
class Date(object):
def __init__(self, s):
if isinstance(s, Date):
self.date = s.date
elif isinstance(s, datetime.date):
self.date = s
else:
self.date = datetime.datetime.strptime(s, "%d/%m/%Y")
def __add__(self, val):
if isinstance(val, Life):
val = val.life
elif not isinstance(val, datetime.timedelta):
val = datetime.timedelta(val)
return self.__class__(self.date + val)
def __cmp__(self, val):
return (self.date - val.date).days
def __str__(self):
return self.date.strftime("%d/%m/%Y")
class Life(object):
def __init__(self, s):
if isinstance(s, Life):
self.life = s.life
elif isinstance(s, datetime.timedelta):
self.life = s
else:
self.life = datetime.timedelta(days=int(s))
def __str__(self):
return str(self.life.days)
class Product(object):
FMT = "{0:10} {1:10} {2:24}".format
def __init__(self, date, life, name):
super(Product,self).__init__()
self.date = Date(date)
self.life = Life(life)
self.name = str(name).strip()
def __str__(self):
return Product.FMT(self.date, self.life, self.name)
def expires(self):
return Date(self.date + self.life)
#classmethod
def get(cls):
date = getClass(Date, "Please enter the date (DD/MM/YYYY): ")
life = getClass(Life, "Please enter the life (in days): ")
name = raw_input("Please enter the name of the cheese: ")
return cls(date, life, name)
def vals(self):
return self.date, self.life, self.name
class FileOf(object):
def __init__(self, cls):
self.data = {}
self.cls = cls
def loadFile(self, fname, mode='r', sep=':'):
_data = self.data
_cls = self.cls
with open(fname, mode) as inf:
for line in inf:
try:
items = line.strip().split(sep)
id = items.pop(0)
_data[id] = _cls(*items)
except ValueError, e:
print(e)
return self
def saveFile(self, fname, mode='w', sep=':', eol='\n', key=None):
_data = self.data
keys = _data.keys()
keys.sort(key=key)
with open(fname, mode) as outf:
for id in keys:
outf.write(str(id)+sep)
outf.write(sep.join(str(v) for v in _data[id].vals()))
outf.write(eol)
return self
def addNew(self):
id = getNewKey(self.data, "Please enter the new ID: ")
obj = getClass(self.cls)
self.data[id] = obj
return self
def printAll(self, key=None):
_data = self.data
_cls = self.cls
ID = "{0:4} ".format
print ID("id") + _cls.FMT("Date", "Life", "Name")
keys = _data.keys()
keys.sort(key=key)
for id in keys:
print ID(id) + _cls.FMT(*(_data[id].vals()))
return self
def filter(self, filterFn):
newFile = FileOf(self.cls)
newFile.data = {id:item for id,item in self.data.iteritems() if filterFn(id, item)}
return newFile
def getNewKey(keys, msg='', keytype=str):
"Prompt for a key not already in keys"
while True:
key = keytype(raw_input(msg))
if key in keys:
print("This key already exists. Please try again.")
else:
return key
def getClass(cls, *args, **kwargs):
"Return a new instance of given class; prompt for required values"
if hasattr(cls, 'get'):
# if the class knows how to 'get' itself, let it
return cls.get(*args, **kwargs)
else:
# otherwise we assume the class knows how to init itself from a string
while True:
s = raw_input(*args)
try:
return cls(s, **kwargs)
except ValueError, e:
print(e)
def getExpired(cheeses, asOf=None):
asOf = Date(asOf) if asOf else getClass(Date, "Please enter expiration test date (DD/MM/YYYY): ")
return cheeses.filter(lambda id,obj: obj.expires() <= asOf)
def main():
cheeses = FileOf(Product).loadFile('cheesefile.txt')
cheeses.printAll()
cheeses.addNew()
expiredA = getExpired(cheeses) # prompt for expiration date
expiredB = getExpired(cheeses, "12/3/2011") # use given date
print("The expired items are:")
expiredB.printAll()
cheeses.saveFile('cheesefile.txt')
if __name__=="__main__":
main()
and a sample cheesefile.txt file:
ab:03/01/2011:10:brie
ac:03/01/2001:20:camembert
de:01/03/2011:30:brie
fg:01/03/2011:1:blink and it's gone
hi:01/05/2011:200:hard white cheddar
jkl:01/04/2011:60:jarlsberg

Related

How can I print each item in an unknown length list that is a class attribute as a string in python?

I have a class (Student) with different attributes, such as studentId, address, and courses. My str method for the class returns all the information that the user put in. However, for the attributes that are lists, such as courses, the location of the information is printed out instead of the actual information. Here is the code (sorry it's a little long, there's a bunch of classes):
class Person:
__name = None
__age = None
__address = None
def __init__(self, name, age=0, address=None):
self.set_name(name)
self.set_age(age)
self.set_address(address)
def __str__(self):
return 'Name: ' + self.__name + '\n' + \
'Age: ' + str(self.__age) + '\n' + \
'Address: ' + str(self.__address)
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_age(self, age):
self.__age = age
def get_age(self):
return self.__age
def set_address(self, address):
self.__address = address
def get_address(self):
return self.__address
class Student(Person):
def __init__(self, name, studentID= None, age= 0, address= None):
super(Student, self).__init__(name, age, address)
self.set_studentID(studentID)
self.__courses =[]
def __str__(self):
result = Person.__str__(self)
result += '\nStudent ID:' + self.get_studentID()
for item in self.__courses:
result += '\n ' + str(item)
return result
def set_studentID(self, studentID):
if isinstance(studentID, str) and len(studentID.strip()) > 0:
self.__studentID = studentID.strip()
else:
self.__studentID = 'NA'
def get_studentID(self):
return self.__studentID
def add_course(self, course):
print('in add_course')
self.__courses.append(course)
def get_courses(self):
for i in range(len(self.__courses)):
return self.__courses[i]
class Course:
__courseName = None
__dept = None
__credits = None
def __init__(self, courseName, dept= 'GE', credits= None):
self.set_courseName(courseName)
self.set_dept(dept)
self.set_credits(credits)
def __str__(self):
return self.get_courseName() + '/' + self.get_dept() + '/' + str(self.get_credits())
def set_courseName(self, courseName):
if isinstance(courseName, str) and len(courseName.strip()) > 0:
self.__courseName = courseName.strip()
else:
print('ERROR: Name must be a non-empty string')
raise TypeError('Name must be a non-empty string')
def get_courseName(self):
return self.__courseName
def set_dept(self, dept):
if isinstance(dept, str) and len(dept.strip()) > 0:
self.__dept = dept.strip()
else:
self.__dept = "GE"
def get_dept(self):
return self.__dept
def set_credits(self, credits):
if isinstance(credits, int) and credits > 0:
self.__credits = credits
else:
self.__credits = 3
def get_credits(self):
return self.__credits
students = []
def recordStudentEntry():
name = input('What is your name? ')
age = input('How old are you? ')
studentID= input('What is your student ID? ')
address = input('What is your address? ')
s1 = Student(name, studentID, int(age), address)
students.append(s1)
s1.add_course(recordCourseEntry())
print('\ndisplaying students...')
displayStudents()
print()
def recordCourseEntry():
courses = []
for i in range(2):
courseName = input('What is the name of one course you are taking? ')
dept = input('What department is your course in? ')
credits = input('How many credits is this course? ')
c1 = Course(courseName, dept, credits)
print(c1)
courses.append(c1)
displayCourses(courses)
return courses
def displayCourses(courses):
print('\ndisplaying courses of student... ')
for c in range(len(courses)):
print(courses[c])
def displayStudents():
for s in range(len(students)):
print()
print(students[s])
recordStudentEntry()
This is how the code above prints out the 'displaying students...' part:
displaying students...
Name: sam
Age: 33
Address: 123 st
Student ID:123abc
[<__main__.Course object at 0x000002BE36E0F7F0>, <__main__.Course object at
0x000002BE36E0F040>]
I know that it is printing out the location because I need to index into the list. However, the length of the list will be different every time. Normally if I wanted to index into a list, for example, to print a list of names, I would do:
listOfNames = ['sam', 'john', 'sara']
for i in range(len(listOfNames)):
print(listOfNames[i])
or
listOfNames = ['sam', 'john', 'sara']
for i in listOfNames:
print(i)
(not sure what if any difference there is between the 2 ways since they both print out the same way:)
sam
john
sara
How can I write something like the indexing into a list technique shown here in my str method for my class so that it prints the information and not the location?
It would be good to keep to the standard conventions for Python, such as naming
private attributes for objects with single underscores, not double underscores.
The latter are reserved for Python "internal" attributes and methods.
Also, it is convention to use object attributes for objects with get/set methods,
not class attributes. This will make it easier to inspect your objects, while
still maintaining data hiding. Example:
class Course:
def __init__(self, courseName, dept= 'GE', credits= None):
self._courseName = None
self._dept = None
self._credits = None
self.set_courseName(courseName)
...
Your question about why the courses don't print out the way you expected
is rooted in a programming error with the way you programmed the recording
of courses. In recordCourseEntry(), you record two courses and put them
in a list. However, you pass that to your Student object using a method
intended for one course at a time. My suggested fix would be:
...
# s1.add_course(recordCourseEntry())
courses = recordCourseEntry()
for course in courses:
s1.add_course(course)
...
This will probably be enough to get you going. An example output I got was:
Name: Virtual Scooter
Age: 33
Address: 101 University St.
Student ID:2021
ff/GE/3
gg/GE/3

add a node alphabetically ordered to a doubly linked list in python

I am doing a project for university. I have a doubly-linked list to define a health center class. Also, I have the patient class:
import os.path
class Patient:
# Class to represent a Patient
def __init__(self, name, year, covid, vaccine):
self.name = name
self.year = year
self.covid = covid
self.vaccine = vaccine
def __str__(self):
return self.name + '\t' + str(self.year) + '\t' + str(self.covid) + '\t' + str(self.vaccine)
class HealthCenter(DList):
# Class to represent a Health Center
def __init__(self, filetsv = None):
super(HealthCenter, self).__init__()
if filetsv is None or not os.path.isfile(filetsv):
self.name = ''
else:
print('Loading the data for the health center from the file', filetsv)
self.name = filetsv.replace('.tsv', '')
tsv_file = open(filetsv)
read_tsv = csv.reader(tsv_file, delimiter = "\t")
for row in read_tsv:
name = row[0]
year = int(row[1])
covid = False
if int(row[2]) == 1:
covid = True
vaccine = int(row[3])
self.addLast(Patient(name, year, covid, vaccine))
My problem is I have to add the patients in alphabetical order, as nodes, inside the list that the health center is.
Here is my code:
def addPatient(self, patient):
new_node = DNode(None)
new_node.elem = patient
new_node.elem.name = patient.name
new_node.elem.year = patient.year
new_node.elem.covid = patient.covid
new_node.elem.vaccine = patient.vaccine
current = self._head
current.elem = self._head.elem
# if empty
if self.isEmpty() == True:
self._head = new_node
self._tail = new_node
self.size = 1
else:
i = 0
while current.elem.name != patient.name and current.elem.name < patient.name:
current = current.next
i += 1
if current.elem.name == patient.name:
if current.elem == patient:
return print("This patient already exists")
else:
self.insertAt(i, new_node)
return print("WARNING \n A patient with the same name already exists: \n",
str(current.elem),"Added patient: \n", patient)
elif current.elem.name > patient.name:
return self.insertAt(i-1, new_node)
It gives me the following error
File "C:.../phase 1 spyder.py", line 73, in addPatient
while (current.elem.name != patient.name) and (current.elem.name < patient.name):
AttributeError: 'NoneType' object has no attribute 'elem'
I don't understand why, I have defined in other functions the variable current and use it as current.elem and current.elem.name or another attribute like covid, year or vaccine, and I donĀ“t get this error.
Help pls

How to get rid of eval in subclass appending to superclass instance list?

I am using eval to run a generated string to append the newly created EggOrder instance to the list of the correct instance of the DailyOrders class. The day provided by EggOrder is used to used to append to the correct instance. This relies on eval and the variable name of the DailyOrders instance and so it would be great to get this removed. I know there must be a better way.
class DailyOrders:
PRICE_PER_DOZEN = 6.5
def __init__(self, day):
self.orders = []
self.day = day
def total_eggs(self):
total_eggs = 0
for order in self.orders:
total_eggs += order.eggs
return total_eggs
def show_report(self):
if self.total_eggs() < 0:
print("No Orders")
else:
print(f"Summary:\nTotal Eggs Ordered: {self.total_eggs()}")
print(f"Average Eggs Per Customer: {self.total_eggs() / len(self.orders):.0f}\n*********")
class EggOrder():
def __init__(self, eggs=0, name="", day=""):
if not name:
self.new_order()
else:
self.name = name
self.eggs = eggs
self.day = day
eval(f"{self.day.lower()}.orders.append(self)")
def new_order(self):
self.name = string_checker("Name: ")
self.eggs = num_checker("Number of Eggs: ")
self.day = string_checker("Date: ")
def get_dozens(self):
if self.eggs % 12 != 0:
dozens = int(math.ceil(self.eggs / 12))
else:
dozens = self.eggs / 12
return dozens
def show_order(self):
print(f"{self.name} ordered {self.eggs} eggs. The price is ${self.get_dozens() * DailyOrders.PRICE_PER_DOZEN}.")
if __name__ == "__main__":
friday = DailyOrders("Friday")
friday_order = EggOrder(12, "Someone", "Friday")
friday_order.show_order()
friday.show_report()
saturday = DailyOrders("Saturday")
saturday_order = EggOrder(19, "Something", "Saturday")
saturday_order = EggOrder(27, "Alex Stiles", "Saturday")
saturday.show_report()
DailyOrders isn't actually a superclass (it was in a earlier version), it acts like one and I suspect the answer might have some inheritance.

Python - Remove specific object in list by condition

I have a class "PushInfo"
And generate 300 PushInfo object in list
I want remove duplicate userid and ip in the list
Here is my code:
from faker import Faker
import random
def RemovePustListDuplicateData(PushList):
return list(set([(x.userid, x.ip) for x in PushList]))
def FakeData(number):
PushList = []
fake = Faker()
accountList = [('john','127.0.0.1'),('john','127.0.0.1'),('amy','127.0.0.1'),
('lia','140.112.1.9'),('julia','140.112.1.9'),
('asuka','140.112.1.9'),('roy','140.112.1.9'),('stacie','140.112.1.9'),('ben','123.964.123.41'),
('yich','127.0.0.1'),('beef','127.0.0.1'),('aloha','235.151.123.1'),('yamaha','235.151.123.1')]
for i in range(0,number):
user = random.choice(accountList)
PushList.append(PushInfo(fake.name(),
user[0],
fake.text(max_nb_chars=10),
fake.date(pattern="%Y-%m-%d"),
user[1]
))
return PushList
class PushInfo:
def __init__(self, name, userid, content, time,ip=''):
self.name = name
self.userid = userid
self.content = content
self.time = time
self.ip = ip
PushList = FakeData(300)
print("top 10 push in list:")
for push in PushList[:10]:
print("name:"+push.name+" id:"+push.userid+" content:"+push.content+" time:"+push.time+" ip:"+push.ip)
print("\nremove duplicate userid and ip data")
print(RemovePustListDuplicateData(PushList))
https://repl.it/#YichLin/Remove-object-in-list/
The example code is return tuple list
[(userid,ip),(userid,ip)....]
But the result I want is
[PushInfo(some data),PushInfo(some data),.....]
How to achieve this result?
Try this:
from faker import Faker
import random
def RemovePustListDuplicateData(PushList):
return list(set(PushList))
def FakeData(number):
PushList = []
fake = Faker()
accountList = [('john','127.0.0.1'),('john','127.0.0.1'),('amy','127.0.0.1'),
('lia','140.112.1.9'),('julia','140.112.1.9'),
('asuka','140.112.1.9'),('roy','140.112.1.9'),('stacie','140.112.1.9'),('ben','123.964.123.41'),
('yich','127.0.0.1'),('beef','127.0.0.1'),('aloha','235.151.123.1'),('yamaha','235.151.123.1')]
for i in range(0,number):
user = random.choice(accountList)
PushList.append(PushInfo(fake.name(),
user[0],
fake.text(max_nb_chars=10),
fake.date(pattern="%Y-%m-%d"),
user[1]
))
return PushList
class PushInfo:
def __init__(self, name, userid, content, time,ip=''):
self.name = name
self.userid = userid
self.content = content
self.time = time
self.ip = ip
def __eq__(self, other):
return self.userid==other.userid and self.ip==other.ip
def __hash__(self):
return hash(('userid', self.userid, 'ip', self.ip))
def __repr__(self):
return str(self.userid) + ' ' + str(self.ip)
PushList = FakeData(300)
print("top 10 push in list:")
for push in PushList[:10]:
print("name:"+push.name+" id:"+push.userid+" content:"+push.content+" time:"+push.time+" ip:"+push.ip)
print("\nremove duplicate userid and ip data")
print(RemovePustListDuplicateData(PushList))
You need to implement eq and hash methods in order to check whether two objects are same.
Change the RemovePustListDuplicateData(PushList) function as follows:-
def RemovePustListDuplicateData(PushList):
object_memo = set()
final_list = []
for object in PushList:
if (object.userid, object.ip) in object_memo:
continue
else:
final_list.append(object)
object_memo.add((object.userid, object.ip))
return final_list
I hope it helps!

AttributeError: AS Instance has no attribute 'toString'

Writing code in Python for an Astar program to find the shortest path between cities. Getting the above error, and I'm at a complete loss. Pulling between a few .py files, here are the relevant sections:
from asdriver.py - added full asdriver
import adata # Map data
import astar # A* class
import sys
# Default start, goal cities
defaultcities = ('Yakima, WA', 'Tampa, FL')
def printnode(n):
print n.toString()
adata.input()
startcity = raw_input("Start city [{0}]: ".format(defaultcities[0])).strip()
if startcity == '': startcity = defaultcities[0]
if startcity not in adata.cities:
print "City not recognized"
sys.exit(0)
goalcity = raw_input("Goal city [{0}]: ".format(defaultcities[1])).strip()
if goalcity == '': goalcity = defaultcities[1]
if goalcity not in adata.cities:
print "City not recognized"
sys.exit(0)
dbg = raw_input("Debug Options: [none]").strip()
findpath = astar.AS(startcity, goalcity, printnode)
ans = findpath.astar_run(printnode, dbg)
if not ans:
print "No answer"
else:
print "Final Path:"
print ans.toString()
From astar.py
import adata
class AS:
def __init__(self, startcity, goalcity, tracefunc):
self.startcity = startcity
self.goalcity = goalcity
self.tracefunc = tracefunc
self.openlist = [Node([startcity])]
self.closedlist = []
def heuristic(self, printnode, start, end):
raise NotImplementedError
def astar_run(self, startcity, endcity, dbg = ""):
while self.openlist:
citystep = min(self.openlist, key = lambda o:o.g + o.h)
if citystep == self.goalcity:
path = []
while citystep.parent:
path.append(citystep)
citystep = citystep.parent
path.append(citystep)
return path[::-1]
self.openlist.remove(citystep)
self.closedlist.append(citystep)
for printnode in self.openlist: #was self.tracefunc
if printnode in self.closedset:
continue
elif printnode in self.openset:
newG = citystep.g + citystep.cost(printnode)
if printnode.g > newG:
printnode.g = newG
printnode.parent = citystep
else:
printnode.g = citystep.g + citystep.cost(printnode)
printnode.h = self.heuristic(printnode, start, end)
printnode.parent = citystep
self.openset.add(printnode)
return self
class Node:
def __init__(self, path=[], f=0, g=0, h=0):
self.path = path[:]
self.f = f
self.g = g
self.h = h
self.parent = None
def toString(self):
s = 'f=%d g=%d h=%d ' % (self.f, self.g, self.h)
for city in self.path:
s = s + ' ' + city
return s
def cost(self):
raise NotImplementedError
'
Complete beginner, so any help would be appreciated.
Thanks in advance!!!
Your def astar_run() method returns self (see last line of your method), or it returns a list by slicing the path[::-1], neither has a toString() method so you are getting this exception. If you want to print the representation of your class then it is normal to declare this method __repr__() and then you can just print ans. If you want to be able to convert to a string then the method is usually called __str__().
What do you expect to be return from astar_run()? It is usually poor practice to return two different types from the same function.

Categories

Resources