class Donor: _f_name = js.String() _l_name = js.String() _donations = js.List() def __init__(self, f_name, l_name, donation=None): self._f_name = f_name self._l_name = l_name if donation is None: self._donations = [] else: self._donations = donation def f_name(self): return self._f_name def l_name(self): return self._l_name @property def full_name(self): return self._f_name + " " + self._l_name @property def get_donation_count(self): return len(self._donations) @property def get_donation_total(self): return sum(self._donations) @property def get_avg_donation(self): if len(self._donations) == 0: return 0 else: return round(sum(self._donations) / len(self._donations), 2) def add_donation(self, value): self._donations.append(value) def get_email_text(self, current_donation): """Prints a thank you email to a donator Donor name and amount is passed in as a parameter""" return "Dear {:s} {:s},\n\ Thank you for the generous donation of ${:,.2f}.\n\ Sincerely,\n\ Your Local Charity".format(*current_donation) def get_letter_text(self): """Returns a message of the donor name and donation total""" message = "Dear {:s},\n\ Thank you for donating ${:,.2f}.\n\ Sincerely,\n\ Your Local Charity" return message.format(self.full_name, self.get_donation_total)
class Donor: name = js.String() donations = js.List() def __init__(self, name, donations): self.name = name self.donations = donations @property def total_donations(self): return sum(self.donations) @property def num_of_gifts(self): return len(self.donations) def add_donation(self, donation): self.donations.append(donation) def save_data(self): data = self.to_json_compat() data = json.dumps(data) with open('{}.json'.format(self.name), 'w') as datafh: datafh.write(data) @classmethod def load_data(cls, donor_name): with open('{}'.format(donor_name), 'r') as ddatafh: ddata = ddatafh.read() ddata = json.loads(ddata) return cls.from_json_dict(ddata)
class DonorHistory: name = js.String() donations = js.List() def __init__(self, name, donations=None): self.name = name if donations is None: self.donations = [] else: self.donations = donations def add_donation(self, amount): try: self.donations.append(int(amount)) except ValueError: print("Please enter a donation amount.") def number_donations(self): return len(self.donations) def total_donation(self): try: return sum(self.donations) except TypeError: return self.donations def donation_avg(self): try: return self.total_donation() / self.number_donations() except TypeError: return self.donations
class Donor(): name = js.String() amount = js.Float() lst = js.List() def __init__(self, name, lst = []): self.name = name.capitalize() self.donation = lst def add_donations(self, amount): self.donation.append(amount) @property def total(self): return sum(self.donation) @property def times(self): return len(self.donation) @property def ave(self): return self.total/self.times @property def last(self): if len(self.donation) > 0: return self.donation[-1] else: return 0 def __str__(self): return f'{self.name}:{self.donation}'
class Donor(): _first = js.String() _last = js.String() _donations = js.List() def __init__(self, first_name, last_name, donations=None): self._first = first_name self._last = last_name if donations is None: self._donations = [] else: self._donations = donations @property def full_name(self): return '{} {}'.format(self._first, self._last) def thank_you_letter_template(self, donor): if self.num_of_donations > 1: return "Dear {},\nThank you for your {} generous donations of ${:.2f}. Your continued support helps our charity stay in business.\n\nSincerely,\n-The Team\n".format( donor.full_name, donor.num_of_donations, donor.total_donation) else: return "Dear {},\nThank you for your generous donation of ${:.2f}. Your support helps our charity stay in business.\n\nSincerely,\n-The Team\n".format( donor.full_name, donor.total_donation) def add_donation(self, amount): return self._donations.append(amount) @property def num_of_donations(self): return len(self._donations) @property def total_donation(self): return sum(self._donations) @property def avg_donation(self): return sum(self._donations / len(self._donations)) @property def donation_lis(self): return self._donations def __str__(self): return f"{self.full_name:20} ${self.total_donation:>17.2f} {self.num_of_donations:>6} ${self.avg_donation:>16.2f}"
class OtherSaveable: foo = js.String() bar = js.Int() def __init__(self, foo, bar): self.foo = foo self.bar = bar
class Donor: """ Instance of donor class for each donor. Takes a tuple of (name, [donations]) and has methods for finding total donations and average donation. Sorts on donor name or total donations. Implementing save as JSON feature """ name = js.String() _donations = js.List() def __init__(self, *args, **kwargs): """ Expected input format is a tuple containting a donor name and a list of donation values. """ self.name = str(args[0]) # Using protected _donations value because I don't want people # overwriting These values. I don't mind if they change the name. try: self._donations = [float(x) for x in args[1]] except IndexError: self._donations = [] def add_donation(self, val): """ Appends a positive numerical value to donations""" if val < 0: raise ValueError('Donation must be greater than 0') self._donations.append(float(val)) def sort_key(self): return self.name def sort_by_total(self): return self.total @property def donations(self): return self._donations @property def total(self): return sum(self._donations) @property def count(self): return len(self._donations) @property def average(self): try: return self.total / self.count except ZeroDivisionError: return 0
class Donor: """ Class to keep track of a donor with a donor name and list of donation amounts """ name = js.String() donationList = js.List() def __init__(self, name=''): self.name = name.strip() self.donationList = js.List() def addDonation(self, amount): """ Add a donation amount to the list """ self.donationList.append(amount) # CHANGE INTO A PROPERTY def getNumDonations(self): """ Get the number of donations the donor has made """ return len(self.donationList) def getAvgDonation(self): """ Get the average value of the donations the donor has made""" try: return self.getTotDonation() / self.getNumDonations() except ZeroDivisionError: return 0.0 def getTotDonation(self): """ Get the total value of the donations the donor has made """ return sum(self.donationList) def createThankYouEmail(self): """ Return donation thank you e-mail text based on the donor name and the donated amount """ result = ( "\nDear {:s},\n\n" "\tThank you so much for your generous donation of ${:,.2f}!\n\n" "\tIt will be put to very good use.\n\n" "\t\tSincerely,\n\t\t\t- The Team".format(self.name, self.getTotDonation())) return result def getDictRep(self): return {self.name: self.donationList}
class NoInit: """ A class with saveable attribute, but no __init__ """ x = js.Int() y = js.String()
class Donor: """ class to hold the information about a single donor """ name = js.String() donations = js.List() # reference to the DB its in -- this will be set in the instance # when added to the DonorDB _donor_db = None def __init__(self, name, donations=None): """ create a new Donor object :param name: the full name of the donor :param donations=None: iterable of past donations """ self.norm_name = self.normalize_name(name) self.name = name.strip() if donations is None: self.donations = [] else: self.donations = list(donations) def __str__(self): msg = (f"Donor: {self.name}, with {self.num_donations:d} " f"donations, totaling: ${self.total_donations:.2f}") return msg def mutating(method): """ Decorator that saves the DB when a change is made It should be applied to all mutating methods, so the data will be saved whenever it's been changed. NOTE: This requires that the donor object is in a DonorDB. """ # note that this is expecting to decorate a method # so self will be the first argument def wrapped(self, *args, **kwargs): print("wrapped method called") print(self) print(self._donor_db) res = method(self, *args, **kwargs) if self._donor_db is not None: self._donor_db.save() return res return wrapped @staticmethod def normalize_name(name): """ return a normalized version of a name to use as a comparison key simple enough to not be in a method now, but maybe you'd want to make it fancier later. """ return name.lower().strip() @property def last_donation(self): """ The most recent donation made """ try: return self.donations[-1] except IndexError: return None @property def total_donations(self): return sum(self.donations) @property def num_donations(self): return len(self.donations) @property def average_donation(self): return self.total_donations / self.num_donations @mutating def add_donation(self, amount): """ add a new donation """ print("add_donation called") amount = float(amount) if amount <= 0.0: raise ValueError("Donation must be greater than zero") self.donations.append(amount) def gen_letter(self): """ Generate a thank you letter for the donor :param: donor tuple :returns: string with letter note: This doesn't actually write to a file -- that's a separate function. This makes it more flexible and easier to test. """ return dedent('''Dear {0:s}, Thank you for your very kind donation of ${1:.2f}. It will be put to very good use. Sincerely, -The Team '''.format(self.name, self.last_donation))
class NoInit: x = js.Int() y = js.String()
class Donor(object): name = js.String() donations = js.List() def __init__(self, name, donations=None): if not name: raise ValueError("Donor name can not be empty") self.name = name if donations: self.donations = donations else: self.donations = [] @property def first_name(self): name_split = self.name.split() if len(name_split) >= 1: return name_split[0] @property def last_name(self): name_split = self.name.split() if len(name_split) == 1: return '' else: return ''.join(name_split[1:]) @property def donor_donations(self): """ Returns list of donor donations :return: list of donor donations """ return self.donations @property def donor_donations_sum(self): """ Returns sum of all donor donations :return: donor latest donation """ return sum(self.donations) @property def latest_donation(self): """ Returns donor latest donation :return: donor latest donation """ if self.donations: return self.donations[-1] def add_donation(self, amount): """ Adds donation to donor donations :return: """ if float(amount) <= 0: raise ValueError("donation amount can not be negative") self.donations.append(float(amount)) def generate_letter(self): """ Generate letter for donor """ return "Dear {},\n \nThank you for your generous donation {}.\n \n\n\t\tSincerely, \n\t\tLocal Charity". \ format(self.name, self.latest_donation)
class DonorsCollection(): _donors = js.Dict() rep = js.String() def __init__(self, val=None): self._donors = {} self.donors = val self.rep = "" @property def donors(self): return self._donors @donors.setter def donors(self, val): if val is not None: if isinstance(val, Donor): self._donors[val.name] = val else: raise ValueError("Must be instance od Donor class") return def add_donor(self): name = input("Type donor first and last name: ") donor_name = tuple(name.split()) if donor_name in self.donors: self.donors[donor_name].donations = float( input(" Donation in USD: ")) else: d = Donor(name) try: d.donations = float(input("Donation in USD: ")) except ValueError: print(""" Donation must be in USD... Donor not added """) del (d) return self.donors = d self.donors[donor_name].print_greetings def display_key(self, a): return a[-1] def display(self): for donor in sorted(self.donors, key=self.display_key): print("".join(["{} "] * len(donor)).format(*donor)) def custom_key(self, a): return (a[1].total) # 2nd arg => dict value => Donor instance def challenge(self, factor, min_donation=None, max_donation=None): for donor in self.donors: self.donors[donor] = \ self.donors[donor].multiply_donations(factor, min_donation, max_donation) @property def report(self): self.rep = "" self.rep += "{:<40}| {:<18}| {:<8}| {:<18}\n".format( 'Donor Name', 'Total Given', 'Num Gifts', 'Average Gift') self.rep += "{:-<90}\n".format('') for k, v in sorted(self.donors.items(), key=self.custom_key, reverse=True): name = " ".join(["{} "] * len(k)).format(*k) self.rep += "{:<40}{}{:>18.2f}{:>11}{}{:>17.2f}\n" \ .format(name, ' $', v.total, v.number, ' $', v.average) return (self.rep) def print_report(self): print(self.report) def write_letters(self): print("Sending letters to all donors...") for k, d in self.donors.items(): d.write_letter() def projections(self, factor, min_donation=None, max_donation=None): for donor in self.donors.values(): temp = cp.deepcopy(donor) # projection done on donor copy print("Donor: {} Current total of dination: {} \ Total after factor applied: {}".format( donor.name, donor.total, temp.multiply_donations(factor=factor, min_donation=min_donation, max_donation=max_donation).total)) del (temp) answer = None while answer not in ['Yes', 'No']: answer = input("Whould you like to multiply " + "(above min, below max) donations: [Yes, No]:") if answer == "Yes": self.challenge(factor, min_donation=min_donation, max_donation=max_donation) print("Changes applied...") else: print("No changes applied...") def save(self, backup_file=None): if not backup_file: backup_file = input( "Name of json backup file(without extension): ") bkp = self.to_json() name = "{}.json".format(backup_file) with open(name, 'w') as f: f.write(bkp) print("Database save in {}".format(name)) @classmethod def load(self, backup_file=None): if not backup_file: backup_file = input("Name of json backup file to load:\n") bkp_f = backup_file + ".json" with open(bkp_f, 'r') as f: bkp = json.load(f) return self.from_json_dict(bkp)
class DonorDonations(object): """ Class to hold the records of a donor and their donations. """ # Class attributes # It becomes apparent when looking at the constructor and the format we will be working with. # Need to work with the data in JSON format - here we will use: # string --> Donor name donor_name = js.String() # list --> Donations made by donor donations = js.List() # May not be needed but adding in case need it initial_state = False # Constructor - take in the name of the donor and donations def __init__(self, donor_name, donations=None): """Constructor for instantiating a donor.""" # Follow the example in example_dec.py # self.donor_name = donor_name # self.donations = [] self.donor_name = donor_name if donations is None: self.donations = [] else: self.donations = list(donations) @property def first_name(self): forename = self.donor_name.split() return forename[0] @property def last_name(self): surname = self.donor_name.split() return surname[1] @property def last_donation(self): """Grab the most recent donation from the list of donations.""" try: # We want the last donation so we want to use the negative index return self.donations[-1] except IndexError: return None @property def total_donations(self): """Total up all the donations that were made by a donor.""" return sum(self.donations) @property def average_donation(self): """Take the total_donations that were calculated and divide by the amount of donations made using len() on the donations list.""" return self.total_donations / len(self.donations) def letter_template(self): """Template for writing a letter to a donor, thanking them for their donation.""" return """Dear {}{},\n Thank you for your very kind donation of ${:.2f}.\n\n It will be put to very good use.\n\n \t\tSincerely,\n\t\t\t -The Team""".format(self.first_name, self.last_name, self.last_donation)
class Donor(object): name = js.String() donations = js.List() def __init__(self, name, donations=None): if not name: raise ValueError("Donor name cannot be empty.") self.name = name if not donations: self.donations = [] else: self.donations = donations @property def first(self): name_sp = self.name.split() if len(name_sp) == 1: return '' else: return name_sp[0] @property def last(self): name_sp = self.name.split() if len(name_sp) == 1: return self.name else: return ' '.join(name_sp[1:]) def add_donation(self, amount): if float(amount) <= 0: raise ValueError('Donation amount must be a positive number.') else: self.donations.append(amount) @property def last_donation(self): if not self.donations: return None else: return self.donations[-1] def generate_letter(self): """ Generates a Thank You letter to send to a donor. Uses the last value in their donations list to mention their last donation amount. :param donor: a donor dictionary entry :return: string containing the text of the Thank You letter. """ format_string = """ Dear {first_name} {last_name}, Thank you for your donation of ${last_donation:.2f}. Warmest Regards, Local Charity """ return format_string.format(last_donation=float(self.last_donation), first_name=self.first, last_name=self.last)
class Donor(): first_name = js.String() last_name = js.String() donations = js.List() def __init__(self, first, last, amount): self.first_name = first self.last_name = last if type(amount) is list: self.donations = amount else: self.donations = [amount] def add_donation(self, amount): if type(amount) is list: self.donations.extend(amount) else: self.donations.append(amount) def challenge(self, factor, min_donation=None, max_donation=None): if min_donation is not None: self.donations = list( filter(lambda x: x > min_donation, self.donations)) if max_donation is not None: self.donations = list( filter(lambda x: x < max_donation, self.donations)) self.donations = list(map(lambda x: x * factor, self.donations)) @property def total(self): return sum(self.donations) @property def count(self): return len(self.donations) @property def average(self): if self.count == 0: return 0 else: return self.total / self.count def __lt__(self, other): return self.total < other.total def __le__(self, other): return self.total <= other.total def __eq__(self, other): return self.total == other.total def __ge__(self, other): return self.total >= other.total def __gt__(self, other): return self.total > other.total def __ne__(self, other): return self.total != other.total