0

I have inherited a Python script that picks people to make cake for the office each week. In doing so, it maintains a list of people who want to make cake, as well as their email addresses, the last time they made cake and some other things. It stores all of them in a self appending object seen below:

import datetime as dt
import pickle

class Person():
    name_list=[]
    def __init__(self,name,email):
        self.name=name
        self.email=email
        self.lastCake=dt.datetime.strptime('01011990', '%d%m%Y').date()
        self.weight=0
        self.update_weight()
        Person.name_list.append(self)

    def __repr__(self):
        return "%s: %i"%(self.name,self.weight)

    def __str__(self):
        return "%s: %i"%(self.name,self.weight)

    def __lt__(self,other):
        return self.weight < other.weight

    def update_weight(self,now=dt.date.today()):
        days_since_cake=now-self.lastCake
        self.weight=int(days_since_cake.days)

def make_cake_list():
    Person('Alice','FAKE@FAKE.com')
    Person('Bob','FAKE@FAKE.com')
    Person('Cath','FAKE@FAKE.com')
    Person('Dave','FAKE@FAKE.com')

Because this script monitors and sends/receives emails, it runs constantly, and thus occasionally gets shut down when the system is rebooted/power outages/it crashes. This means that the Person object is written/read to/from a file, and Pickle is used to do this with the two functions:

def save_cake_list(people):
    with open("cake_list.dat",'w') as f:
        pickle.dump(people,f)

def read_cake_list():
    with open("cake_list.dat",'r') as f:
        return pickle.load(f)

All fairly standard. Except because of how its set up and how it maintains its lists, its a real pig to add new people and then keep track of who you have added (a few names are hard coded in, but I want to get rid of that feature. The less often I have to poke around in the guts of the script, the better!). And with Pickle, a human cant read/edit the file it creates.

So, is there a way to take the object Person (and its all-important, self-appending name_list) and pass it to a human readable file? XML files spring to mind, but methods I have looked at dont seem to handle the self-appending list system I have here and I dont have a lot of experience with them.

There is an addPerson function that isnt too bad, so I could always just store a list of people and emails, read that in and shove it in the function, but I would lose the weight (how long since a person last made cake).

Thoughts?

EDIT: I dont believe this is the same as the Dictionary to Serial to Dictionary question elsewhere, as I think converting my Class to Dictionary would lose a key piece of functionality required elsewhere in the code.

However, I am not familiar with Dictionaries, so if I am wrong, please do provide a MWS and explain why Dictionaries would work.

Alex Howard
  • 319
  • 3
  • 13
  • 1
    put that in a dictionary instead of in separate fields, and you'll be able to serialize the dict using json or str(), and read it back using json or ast.literal_eval. – Jean-François Fabre Jan 12 '17 at 20:55
  • Possible duplicate of [How do I serialize a Python dictionary into a string, and then back to a dictionary?](http://stackoverflow.com/questions/4342176/how-do-i-serialize-a-python-dictionary-into-a-string-and-then-back-to-a-diction) – Jean-François Fabre Jan 12 '17 at 20:56
  • My concern with dictionaries is I lose that self appending part of the code, and the neat nested feature of the object I currently have, which is sort of required for the email section of the code (not listed here). Essentially, the code sorts all the people in `Person` and pops off the one that has gone longest without making cake. It then pops off the name, emails them, waits for a reply, and if necessary, moves to the next person and so on. I couldnt do that with Dictionaries, could I? – Alex Howard Jan 12 '17 at 21:38

1 Answers1

0

I would go with json as a format to store data. Then you can take advantage of web solutions if required. You can go with json module but it will require a few hooks so I will pick the easiest option. I took the jsonpickle for serializing and deserializing complex python objects. Here is an example

import datetime as dt
import jsonpickle

class Person():
    name_list=[]
    def __init__(self,name,email):
        self.name=name
        self.email=email
        self.lastCake=dt.datetime.strptime('01011990', '%d%m%Y').date()
        self.weight=0
        self.update_weight()
        Person.name_list.append(self)

    def default(self):
        return self.__dict__

    def __repr__(self):
        return "%s: %i"%(self.name,self.weight)

    def __str__(self):
        return "%s: %i"%(self.name,self.weight)

    def __lt__(self,other):
        return self.weight < other.weight

    def update_weight(self,now=dt.date.today()):
        days_since_cake=now-self.lastCake
        self.weight=int(days_since_cake.days)

def make_cake_list():
    persons = list()
    persons.append(Person('Alice','FAKE@FAKE.com'))
    persons.append(Person('Bob','FAKE@FAKE.com'))
    persons.append(Person('Cath','FAKE@FAKE.com'))
    persons.append(Person('Dave','FAKE@FAKE.com'))
    return persons

persons = make_cake_list()
print jsonpickle.encode(persons, unpicklable=False)
taras
  • 3,579
  • 3
  • 26
  • 27
  • Would you mind giving a bit more of an expanded example? I am not sure how to convert my object into the sort of data string required for json. – Alex Howard Jan 13 '17 at 10:22
  • My apologies, Alex. It was not that easy. Updated the answer – taras Jan 13 '17 at 11:29