Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

python 3.6 Background Classes allow us to define new types for Python. We can fi

ID: 3858031 • Letter: P

Question

python 3.6

Background Classes allow us to define new types for Python. We can first think of a class as defining a new container - instead of a list, tuple, set, or dictionary, we can have our own collection of values, each with a chosen name. We can then read out a value or update a value, much like reading or replacing the values in a list or dictionary. But we can also put methods in a class definition, giving us a way to specify the exact ways we should interact with values of this new type. Once we have created a class definition, we can create as many objects of the new type as we want and use them in our programs. We can create entirely new types during the design phase of writing a program. This enables us to think in terms of types (and instances of types) that better model what we see in the real world, instead of endlessly relying on lists or dictionaries (and having to remember exactly how we intended to use those things as proxies for the values we actually had in mind) Exceptions allow us to recover from unusual events - some unavoidable (user types in bad file name or bad input in general), some unexpected (such as IndexErrors when stepping through a list). Without exceptions, we tend to program in an "ask permission, then attempt" style of calculation. But using exceptions, we can instead program iin a "try it first, beg for forgiveness" approach by writing code that specifies how to recover from exceptions that we allowed to occur

Explanation / Answer

Event.py
---------------------------
from TimeSpan import *
from Moment import *


class Event:

    def __init__(self, title, location, timespan):
        """
        Constructor
        :param title:
        :param location:
        :param timespan:
        :return:
        """
        self.title = title
        self.location = location
        self.timespan = timespan

    def __str__(self):
        return "Event: {0}. Location: {1}. {2}, {3} ".format(self.title, self.location, self.timespan.start, self.timespan.stop)

    def __repr__(self):
        return "Event ("{0}", "{1}", {2})".format(self.title, self.location, repr(self.timespan))


if __name__ == '__main__':
    start = Moment(2014, 12, 4, 14, 1)
    stop = Moment(2014, 12, 4, 14, 30)
    span = TimeSpan(start, stop)
    e = Event("Lunch With Mum", "Home", span)
    print(e)
print(repr(e))
-----------------------------------------------------------------
EventPlanner.py
-------------------------------
from ScheduleConflictError import *


class EventPlanner:

    def __init__(self, owner, events=None):
        """
        Constructor
        :param owner:
        :param events:
        :return:
        """
        self.owner = owner
        if events is None:
            self.events = []
        else:
            self.events = events

    def __str__(self):
        return "EventPlanner ("{0}", {1})".format(self.owner, self.events)

    def __repr__(self):
        return str(self)

    def add_event(self, event):
        """
        Add the given event
        :param event:
        :return:
        """
        # check whether there is any events so the list

        if len(self.events) == 0:
            self.events.append(event)
            return None
        else:
            for ev in self.events:
                if ev.timespan.overlaps(event.timespan):
                    raise ScheduleConflictError("The event {0}, overlaps with event {1}".format(event, ev))

            # if we get here then that means there is no overlap so we add the event
            self.events.append(event)
            return None

    def add_events(self, events):
        """
        Adds events in the given list
        :param events:
        :return:
        """
        events_not_added = 0
        length = len(events)

        if length == 0:
            return 0
        else:
            for i in range(0, length):
                ev = events.pop()
                try:
                    self.add_event(ev)
                except ScheduleConflictError as ex:
                    events_not_added += 1
            return events_not_added

    def available_at(self, moment):
        """
        Checks if the owner is available at the given mat
        :param moment:
        :return:
        """
        if len(self.events) == 0:
            return True
        else:
            for ev in self.events:
                if ev.timespan.during_moment(moment):
                    return False
            return True

    def available_during(self, timespan):
        """
        Checks if the owner is available at the given timespan
        :param timespan:
        :return:
        """
        if len(self.events) == 0:
            return True
        else:
            for ev in self.events:
                if ev.timespan.overlaps(timespan):
                    return False
            return True

    def can_attend(self, event):
        """
        Checks if the owner can attend the event
        :param event:
        :return:
        """
        if len(self.events) == 0:
            return True
        else:
            # make sure the User is not available during that event

           return not self.available_during(event.timespan)

----------------------------------------------------------------------------
Moment.py
--------------------------------
from TimeError import *


class Moment():

    def __init__(self, year=0, month=0, day=0, hour=0, minute=0):
        """
        Constructor
        :param year:
        :param month:
        :param day:
        :param hour:
        :param minute:
        :return:
        """
        try:
            if Moment.is_int("Year", year) and Moment.is_int("Month", month) and Moment.is_int("Day", day)
                    and Moment.is_int("Hour", hour) and Moment.is_int("Minute", minute):
                if Moment.is_year_valid(year):
                    self.year = year
                if Moment.is_month_valid(month):
                    self.month = month
                if Moment.is_day_valid(year, month, day):
                    self.day = day
                if Moment.is_hour_valid(hour):
                    self.hour = hour
                if Moment.is_minute_valid(minute):
                    self.minute = minute

        except Exception as e:
            print(e)

    def __str__(self):
        fmonth = self.month
        fday = self.day
        fhour = self.hour
        fminute = self.minute
        if self.month < 10:
            fmonth = "0{0}".format(self.month)
        if self.day < 10:
            fday = "0{0}".format(self.day)
        if self.hour < 10:
            fhour = "0{0}".format(self.hour)
        if self.minute < 10:
            fminute = "0{0}".format(self.minute)

        return "{0}/{1}/{2}-{3}:{4}".format(self.year, fmonth, fday, fhour, fminute)

    def __repr__(self):
        return "Moment({0}, {1}, {2}, {3}, {4})".format(self.year, self.month, self.day, self.hour, self.minute)

    def before(self, other):
        """
        Checks if the Moment is before other
        :param other:
        :return:
        """

        if self.year < other.year:

            return True
        else:
            if self.month < other.month and self.year < other.year:

                return True
            else:
                if self.day < other.day and (self.month < other.month and self.year < other.year):

                    return True
                else:
                    if self.hour < other.hour and (self.day < other.day and self.month < other.month and self.year < other.year):
                        return True
                    else:
                        if self.minute < other.minute and (self.hour < other.hour and self.day < other.day and self.month < other.month and self.year < other.year):

                            return True
                        else:
                            return False

    def equal(self, other):
        """
        Checks if the two moments are equal
        :param other:
        :return:
        """
        is_equal = False
        if self.year == other.year:
            is_equal = True
            if self.month == other.month:
                is_equal = True
                if self.day == other.day:
                    is_equal = True
                    if self.hour == other.hour:
                        is_equal = True
                        if self.minute == other.minute:
                            is_equal = True
                        else:
                            is_equal = False
                    else:
                        is_equal = False
                else:
                    is_equal = False
            else:
                is_equal = False
        else:
            is_equal = False

        return is_equal

    def after(self, other):
        """
        Checks is the moment is after the other
        :param other:
        :return:
        """
        is_early = False
        if self.year > other.year:
            is_early = True
        else:
            if self.month > other.month and self.year > other.year:
                is_early = True
            else:
                if self.day > other.day and (self.month > other.month and self.year > other.year):
                    is_early = True
                else:
                    if self.hour > other.hour and (self.day > other.day and self.month > other.month and self.year > other.year):
                        is_early = True
                    else:
                        if self.minute > other.minute and (self.hour > other.hour and self.day > other.day and self.month > other.month and self.year > other.year):
                            is_early = True
                        else:
                            is_early = False
        return is_early

    def delta(self, year=0, month=0, day=0, hour=0, minute=0):
        """
        Transforms the current moment in a positive or negative way
        :param year:
        :param month:
        :param day:
        :param hour:
        :param minute:
        :return:
        """

        # first check if the deal with the minutes
        carry_over_hours = int((self.minute + minute) / 60)
        new_minutes = (self.minute + minute) % 60

        #then deal with the hours
        carry_over_days = int((self.hour + hour + carry_over_hours) / 24)
        new_hours = (self.hour + hour + carry_over_hours) % 24

        #deal with days

        remaining_days_to_end_of_the_current_month = Moment.get_number_of_days_in_a_month(self.year, self.month)- (self.day + carry_over_days)

        #check if the days we have overflow

        overflow_days = day - remaining_days_to_end_of_the_current_month
        #if the overflow_days are 0 or negative then we good we end there else we loop through the days until they are done

        new_month = 0
        carry_over_months = 0
        new_day = 0
        new_year = 0
        if overflow_days <= 0:
            new_day = self.day + day + carry_over_days
            new_month = self.month
            carry_over_months = 0
            overflow_days = 0
        else:
            carry_over_months += 1
            new_month = self.month + 1
            new_year = self.year
            while overflow_days > 0:
                if new_month == 13:
                    new_month = 1
                    new_year += 1
                month_length = Moment.get_number_of_days_in_a_month(new_year, new_month)
                overflow = overflow_days - month_length
                if overflow < 0:
                    #here we remain in the same month
                    new_day = overflow_days
                    overflow_days = 0
                elif overflow == 0:
                    #here we remain in the same month and set the day to the last day of the month
                    new_day = month_length
                    overflow_days = 0
                elif overflow > 0:
                    carry_over_months += 1
                    new_month += 1
                    overflow_days = overflow

        #now we deal with the months

        carry_over_years = 0
        if (self.month + month + carry_over_months) % 12 == 0:
            new_month = 12
        else:
            new_month = (self.month + month + carry_over_months) % 12
            carry_over_years = int((self.month + month + carry_over_months) / 12)

        # dealing with years

        new_year = self.year + carry_over_years + year

        #bringing everything together

        self.year = round(new_year)
        self.month = round(new_month)
        self.day = round(new_day)
        self.hour = round(new_hours)
        self.minute = round(new_minutes)

    def is_leap_year(year):
        """
        Checks if the year is leap year
        :param year:
        :return: Boolean either true or false
        """
        if year % 400 == 0:
            return True
        elif year % 100 == 0:
            return False
        elif year % 4 == 0:
            return True
        else:
            return False

    def is_int(name, value):
        """
        Checks if the value provided is int
        :param name:
        :param value:
        :return:
        """
        if isinstance(value, int):
            return True
        else:
            raise TimeError("The value provided for %s is not an integer" % name)

    def is_year_valid(year):
        if year >= 0:
            return True
        else:
            raise TimeError("The value {0} provided for year is not valid".format(year))

    def is_month_valid(month):
        """
        Checks if the month is valid
        :param month:
        :return:
        """
        if month >= 1 and month <= 12:
            return True
        else:
            raise TimeError("The value {0} provided for month is not valid".format(month))

    def is_day_valid(year, month, day):
        """
        Checks if the day passed is valid
        :param year:
        :param month:
        :param day:
        :return:
        """
        start_day = 1
        last_day = 0

        #first we determine the last day of the month

        if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12:
            last_day = 31
        elif month == 4 or month == 6 or month == 9 or month == 11:
            last_day = 30
        else:
            if Moment.is_leap_year(year):
                last_day = 29
            else:
                last_day = 28

        #then we check if they day of the month is valid
        if day >= start_day and day <= last_day:
            return True
        else:
            raise TimeError("The value {0} for day of {1} month and {2} year is not valid".format(
                day, month, year))


    def is_hour_valid(hour):
        if hour >=0 and hour <=23:
            return True
        else:
            raise TimeError("The value {0} provided for hour is not valid".format(hour))

    def is_minute_valid(minute):
        if minute >= 0 and minute <= 59:
            return True
        else:
            raise TimeError("The value {0} provided for minute is not valid".format(minute))

    def get_number_of_days_in_a_month(year, month):
        days_in_a_month = 0
        if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12:
            days_in_a_month = 31
        elif month == 4 or month == 6 or month == 9 or month == 11:
            days_in_a_month = 30
        else:
            if Moment.is_leap_year(year):
                days_in_a_month = 29
            else:
                days_in_a_month = 28

        return days_in_a_month
--------------------------------------------------------------------
ScheduleConflictError(Exception).py
---------------------------------
class ScheduleConflictError(Exception):

    def __init__(self, msg):

        self.msg = msg

    def __str__(self):

        return self.msg

    def __repr__(self):

        return self.msg
--------------------------------------------------------------------
TimeError.py
--------------------------------
class TimeError(Exception):

    def __init__(self, msg):

        self.msg = msg

    def __str__(self):

        return self.msg

    def __repr__(self):

        return self.msg

-------------------------------------------------------------------
TimeSpan.py
-------------------------------------
from Moment import *
from TimeError import *


class TimeSpan:

    def __init__(self, start, stop):
        """
        Constructor
        :param start:
        :param stop:
        :return:
        """
        if stop.before(start):
            raise TimeError("The stop moment {0} cannot be before start moment {1}".format(stop, start))
        else:
            self.start = start
            self.stop = stop

    def __str__(self):
        return "Timespan({0}, {1})".format(self.start, self.stop)

    def __repr__(self):
        return "Timespan({0}, {1})".format(repr(self.start), repr(self.stop))

    def during_moment(self, moment):
        """
        Checks if the moment is during the timespan
        :param moment:
        :return:
        """

        if self.start.before(moment) and self.stop.after(moment):
            return True
        elif self.start.equal(moment) or self.stop.equal(moment):
            return True
        else:
            return False

    def overlaps(self, other):
        """
        Checks if the Time spans overlaps
        :param other:
        :return:
        """

        if self.start.equal(other.start) or self.stop.equal(other.stop):
            return True
        elif self.start.before(other.start) and self.stop.after(other.start):
            return True
        elif other.stop.after(self.start) and other.stop.before(self.stop):
            return True
        else:
            return False

    def set_duration(self, year=0, month=0, day=0, hour=0, minute=0):
        """
        Resets ths values of the stop moment
        :param year:
        :param month:
        :param day:
        :param hour:
        :param minute:
        :return:
        """
        self.stop.delta(year, month, day, hour, minute)
        if self.stop.before(self.start):
            raise TimeError("The stop Moment is before the start Moment")
        else:
            return True