def test_040_registered_attribute_simple_class(self, clean_Date): Date.register_new_calendar('test_1', ExampleTestCalendar) # Date attribute type and metaclass are correct assert Date.test_1.__name__ == 'ExampleTestCalendarInDate' assert type(Date.test_1).__name__ == 'ModifiedClass' assert issubclass(Date.test_1, ExampleTestCalendar) # constructed date type and value are is correct d1a = Date.test_1(100, 4) assert type(d1a) == Date assert d1a.day_count == 697 # new attribute on date instance, type and value are correct d1b = Date(1000) assert isinstance(d1b.test_1, ExampleTestCalendar) assert type(d1b.test_1).__name__ == 'ExampleTestCalendarInDate' assert type(d1b.test_1.__class__).__name__ == 'ModifiedClass' assert d1b.test_1.week == 143 assert d1b.test_1.day == 6 # new attribute on date instance build by another calendar, type and value are correct d1c = Date.gregorian(100, 2, 3) assert isinstance(d1c.test_1, ExampleTestCalendar) assert type(d1c.test_1).__name__ == 'ExampleTestCalendarInDate' assert type(d1c.test_1.__class__).__name__ == 'ModifiedClass' assert d1c.test_1.week == 5171 assert d1c.test_1.day == 3
def test_040_registered_attribute_simple_class(self, clean_Date): Date.register_new_calendar("test_1", ExampleTestCalendar) # Date attribute type and metaclass are correct assert Date.test_1.__name__ == "ExampleTestCalendarInDate" assert type(Date.test_1).__name__ == "ModifiedClass" assert issubclass(Date.test_1, ExampleTestCalendar) # constructed date type and value are is correct d1a = Date.test_1(100, 4) assert type(d1a) == Date assert d1a.day_count == 697 # new attribute on date instance, type and value are correct d1b = Date(1000) assert isinstance(d1b.test_1, ExampleTestCalendar) assert type(d1b.test_1).__name__ == "ExampleTestCalendarInDate" assert type(d1b.test_1.__class__).__name__ == "ModifiedClass" assert d1b.test_1.week == 143 assert d1b.test_1.day == 6 # new attribute on date instance build by another calendar, type and value are correct d1c = Date.gregorian(100, 2, 3) assert isinstance(d1c.test_1, ExampleTestCalendar) assert type(d1c.test_1).__name__ == "ExampleTestCalendarInDate" assert type(d1c.test_1.__class__).__name__ == "ModifiedClass" assert d1c.test_1.week == 5171 assert d1c.test_1.day == 3
def test_000_register_new_calendar(self, clean_Date): assert not hasattr(Date, "test_1") with pytest.raises(AttributeError): Date.test_1 Date.register_new_calendar("test_1", ExampleTestCalendar) assert hasattr(Date, "test_1") Date.test_1
def test_000_register_new_calendar(self, clean_Date): assert not hasattr(Date, 'test_1') with pytest.raises(AttributeError): Date.test_1 Date.register_new_calendar('test_1', ExampleTestCalendar) assert hasattr(Date, 'test_1') Date.test_1
def test_310_disallowed_operations(self): a = Date(42) b = Date(24) # These operations are invalid because TimeDelta is not integer. for value in (42.25, 41.75, -42.25, -41.75): with pytest.raises(ValueError): a + TimeDelta(value) with pytest.raises(ValueError): a - TimeDelta(value) # Add/sub int, float, string, complex, specials and containers should be illegal for obj in (10, 34.5, "abc", 1 + 2j, INF, NAN, {}, [], ()): with pytest.raises(TypeError): a + obj with pytest.raises(TypeError): a - obj with pytest.raises(TypeError): obj + a with pytest.raises(TypeError): obj - a # Reverse operations with pytest.raises(TypeError): TimeDelta(2) - a for obj in (1, 1.1, b): with pytest.raises(TypeError): a * obj with pytest.raises(TypeError): obj * a with pytest.raises(TypeError): a / obj with pytest.raises(TypeError): obj / a with pytest.raises(TypeError): a // obj with pytest.raises(TypeError): obj // a with pytest.raises(TypeError): pow(a, obj) with pytest.raises(TypeError): pow(obj, a) with pytest.raises(TypeError): a ^ obj with pytest.raises(TypeError): obj ^ a with pytest.raises(TypeError): a >> obj with pytest.raises(TypeError): obj >> a with pytest.raises(TypeError): a << obj with pytest.raises(TypeError): obj << a
def test_010_invalid_parameter_types(self): """The argument is required and must be an integer.""" # exception with no or two parameters with pytest.raises(TypeError): Date() with pytest.raises(TypeError): Date(1, 2) # exception with non-numeric types for par in ("1", (1,), [1], {1: 1}, (), [], {}, None): with pytest.raises(TypeError): Date(par) # exception with invalid numeric types for par in (1.0, Fraction(1, 1), Decimal(1), 1j): with pytest.raises(TypeError): Date(par)
def test_900_pickling(self): for day_count in date_test_data: d = Date(day_count) for protocol in range(pickle.HIGHEST_PROTOCOL + 1): pickled = pickle.dumps(d, protocol) derived = pickle.loads(pickled) assert d == derived
def test_330_comparison_with_invalid_types(self): class SomeClass: pass d = Date(1) # exception with non-numeric types for par in ("1", (1,), [1], {1: 1}, (), [], {}, None, SomeClass()): assert not (d == par) assert d != par with pytest.raises(TypeError): d < par with pytest.raises(TypeError): d > par with pytest.raises(TypeError): d <= par with pytest.raises(TypeError): d >= par # exception with numeric types (all invalid) for par in (1, 1.0, Fraction(1, 1), Decimal(1), 1j, 1 + 1j, INF, NAN): assert not (d == par) assert d != par with pytest.raises(TypeError): d < par with pytest.raises(TypeError): d > par with pytest.raises(TypeError): d <= par with pytest.raises(TypeError): d >= par
def test_900_avoid_date_override(self): d = Date.gregorian(1, 1, 1) # I do not want an instance of Date created through a Gregorian to have its static methods # One of the implementation I used had this error and I want to avoid it with pytest.raises(AttributeError): getattr(d, 'is_leap_year') with pytest.raises(AttributeError): d.is_leap_year
def test_900_avoid_date_override(self): d = Date.gregorian(1, 1, 1) # I do not want an instance of Date created through a Gregorian to have its static methods # One of the implementation I used had this error and I want to avoid it with pytest.raises(AttributeError): getattr(d, "is_leap_year") with pytest.raises(AttributeError): d.is_leap_year
def test_340_hash_equality(self): """Date instances are immutable.""" d1 = Date(42) d2 = Date(42) assert hash(d1) == hash(d2) dic = {d1: 1} dic[d2] = 2 assert len(dic) == 1 assert dic[d1] == 2 assert dic[d2] == 2 d3 = Date(32) + TimeDelta(10) assert hash(d1) == hash(d3) dic[d3] = 2 assert len(dic) == 1 assert dic[d3] == 2
def test_110_get_unknown_attribute(self): """Date instances have one attribute.""" # I want to do this, because Date will have attributes added at runtime # let's tests this both on class and instance with pytest.raises(AttributeError): Date.unknown d = Date(1) with pytest.raises(AttributeError): d.unknown
def test_046_registered_attribute_class_with_static_methods( self, clean_Date): class ExampleTestCalendar3(ExampleTestCalendar): @staticmethod def is_odd(number): return (number % 2) == 1 Date.register_new_calendar("test_3", ExampleTestCalendar3) # Date attribute type and metaclass are correct assert Date.test_3.__name__ == "ExampleTestCalendar3InDate" assert type(Date.test_3).__name__ == "ModifiedClass" assert issubclass(Date.test_3, ExampleTestCalendar) # constructed date type and value are is correct d3a = Date.test_3(100, 4) assert type(d3a) == Date assert d3a.day_count == 697 # new attribute on date instance, type and value are correct d3b = Date(1000) assert isinstance(d3b.test_3, ExampleTestCalendar3) assert type(d3b.test_3).__name__ == "ExampleTestCalendar3InDate" assert type(d3b.test_3.__class__).__name__ == "ModifiedClass" assert d3b.test_3.week == 143 assert d3b.test_3.day == 6 # new attribute on date instance build by another calendar, type and value are correct d3c = Date.gregorian(100, 2, 3) assert isinstance(d3c.test_3, ExampleTestCalendar3) assert type(d3c.test_3).__name__ == "ExampleTestCalendar3InDate" assert type(d3c.test_3.__class__).__name__ == "ModifiedClass" assert d3c.test_3.week == 5171 assert d3c.test_3.day == 3 # static method can be reached on the class and on all types of instance assert Date.test_3.is_odd(3) assert not Date.test_3.is_odd(4) assert d3a.test_3.is_odd(3) assert not d3a.test_3.is_odd(4) assert d3b.test_3.is_odd(3) assert not d3b.test_3.is_odd(4) assert d3c.test_3.is_odd(3) assert not d3c.test_3.is_odd(4)
def test_046_registered_attribute_class_with_static_methods(self, clean_Date): class ExampleTestCalendar3(ExampleTestCalendar): @staticmethod def is_odd(number): return (number % 2) == 1 Date.register_new_calendar('test_3', ExampleTestCalendar3) # Date attribute type and metaclass are correct assert Date.test_3.__name__ == 'ExampleTestCalendar3InDate' assert type(Date.test_3).__name__ == 'ModifiedClass' assert issubclass(Date.test_3, ExampleTestCalendar) # constructed date type and value are is correct d3a = Date.test_3(100, 4) assert type(d3a) == Date assert d3a.day_count == 697 # new attribute on date instance, type and value are correct d3b = Date(1000) assert isinstance(d3b.test_3, ExampleTestCalendar3) assert type(d3b.test_3).__name__ == 'ExampleTestCalendar3InDate' assert type(d3b.test_3.__class__).__name__ == 'ModifiedClass' assert d3b.test_3.week == 143 assert d3b.test_3.day == 6 # new attribute on date instance build by another calendar, type and value are correct d3c = Date.gregorian(100, 2, 3) assert isinstance(d3c.test_3, ExampleTestCalendar3) assert type(d3c.test_3).__name__ == 'ExampleTestCalendar3InDate' assert type(d3c.test_3.__class__).__name__ == 'ModifiedClass' assert d3c.test_3.week == 5171 assert d3c.test_3.day == 3 # static method can be reached on the class and on all types of instance assert Date.test_3.is_odd(3) assert not Date.test_3.is_odd(4) assert d3a.test_3.is_odd(3) assert not d3a.test_3.is_odd(4) assert d3b.test_3.is_odd(3) assert not d3b.test_3.is_odd(4) assert d3c.test_3.is_odd(3) assert not d3c.test_3.is_odd(4)
def test_500_repr(self): import datetime2 for day_count in date_test_data: d = Date(day_count) date_repr = repr(d) names, args = date_repr.split("(") assert names.split(".") == ["datetime2", "Date"] args = args[:-1] # drop ')' assert int(args) == day_count assert d == eval(repr(d))
def test_100_date_has_attributes_but_instance_not(self): # the date class aways has a registered attribute assert hasattr(Date, 'gregorian') assert Date.gregorian # an instance created with another calendar or by Date does not have # the attribute; it is instead is reachable via the Date class d1 = Date(4) with pytest.raises(KeyError): d1.__dict__['gregorian'] assert hasattr(d1, 'gregorian') d1.gregorian d2 = Date.iso(3, 4, 5) with pytest.raises(KeyError): d2.__dict__['gregorian'] assert hasattr(d2, 'gregorian') d2.gregorian # a Date instance created via the calendar does have the same attribute d3 = Date.gregorian(3, 4, 5) assert hasattr(d3, 'gregorian') d3.gregorian
def test_100_date_has_attributes_but_instance_not(self): # the date class aways has a registered attribute assert hasattr(Date, "gregorian") assert Date.gregorian # an instance created with another calendar or by Date does not have # the attribute; it is instead is reachable via the Date class d1 = Date(4) with pytest.raises(KeyError): d1.__dict__["gregorian"] assert hasattr(d1, "gregorian") d1.gregorian d2 = Date.iso(3, 4, 5) with pytest.raises(KeyError): d2.__dict__["gregorian"] assert hasattr(d2, "gregorian") d2.gregorian # a Date instance created via the calendar does have the same attribute d3 = Date.gregorian(3, 4, 5) assert hasattr(d3, "gregorian") d3.gregorian
def test_020_register_new_calendar_invalid_attribute_name(self): with pytest.raises(ValueError): Date.register_new_calendar("", ExampleTestCalendar) with pytest.raises(ValueError): Date.register_new_calendar("123new", ExampleTestCalendar) with pytest.raises(ValueError): Date.register_new_calendar(123, ExampleTestCalendar)
def test_020_register_new_calendar_invalid_attribute_name(self): with pytest.raises(ValueError): Date.register_new_calendar('', ExampleTestCalendar) with pytest.raises(ValueError): Date.register_new_calendar('123new', ExampleTestCalendar) with pytest.raises(ValueError): Date.register_new_calendar(123, ExampleTestCalendar)
def test_020_today(self): """Return a Date object that represents the current local date.""" # for the time being, let's use the good old datetime module :-) import datetime # we need to ensure that we are not testing across date change for dummy in range(3): today_before = datetime.date.today() date_today = Date.today() today_after = datetime.date.today() if today_before == today_after: break assert date_today.day_count == today_before.toordinal()
def test_020_today(self): "Return a Date object that represents the current local date." # for the time being, let's use the good old datetime module :-) import datetime # we need to ensure that we are not testing across date change for dummy in range(3): today_before = datetime.date.today() date_today = Date.today() today_after = datetime.date.today() if today_before == today_after: break assert date_today.day_count == today_before.toordinal()
def test_030_register_new_calendar_invalid_calendar_class(self): class NoFromCalendar: # without from_rata_die def __init__(self, week, day): self.week = week self.day = day def to_rata_die(self): return 7 * (self.week - 1) + self.day with pytest.raises(TypeError): Date.register_new_calendar("test_1", NoFromCalendar) class NoToCalendar: # without to_rata_die def __init__(self, week, day): self.week = week self.day = day @classmethod def from_rata_die(cls, rata_die): return cls((rata_die - 1) // 7 + 1, (rata_die - 1) % 7 + 1) with pytest.raises(TypeError): Date.register_new_calendar("test_1", NoToCalendar)
def test_030_register_new_calendar_invalid_calendar_class(self): class NoFromCalendar: # without from_rata_die def __init__(self, week, day): self.week = week self.day = day def to_rata_die(self): return 7 * (self.week - 1) + self.day with pytest.raises(TypeError): Date.register_new_calendar('test_1', NoFromCalendar) class NoToCalendar: # without to_rata_die def __init__(self, week, day): self.week = week self.day = day @classmethod def from_rata_die(cls, rata_die): return cls((rata_die - 1) // 7 + 1, (rata_die - 1) % 7 + 1) with pytest.raises(TypeError): Date.register_new_calendar('test_1', NoToCalendar)
def test_043_registered_attribute_class_with_other_constructors( self, clean_Date): class ExampleTestCalendar2(ExampleTestCalendar): @classmethod def with_thousands(cls, thousands, week, day): return cls(1000 * thousands + week, day) Date.register_new_calendar("test_2", ExampleTestCalendar2) # Date attribute type and metaclass are correct assert Date.test_2.__name__ == "ExampleTestCalendar2InDate" assert type(Date.test_2).__name__ == "ModifiedClass" assert issubclass(Date.test_2, ExampleTestCalendar) # constructed date type and value are is correct d2a = Date.test_2(100, 4) assert type(d2a) == Date assert d2a.day_count == 697 d2d = Date.test_2.with_thousands(2, 3, 4) assert type(d2d) == Date assert d2d.day_count == 14018 # new attribute on date instance, type and value are correct d2b = Date(1000) assert isinstance(d2b.test_2, ExampleTestCalendar2) assert type(d2b.test_2).__name__ == "ExampleTestCalendar2InDate" assert type(d2b.test_2.__class__).__name__ == "ModifiedClass" assert d2b.test_2.week == 143 assert d2b.test_2.day == 6 # new attribute on date instance build by another calendar, type and value are correct d2c = Date.gregorian(100, 2, 3) assert isinstance(d2c.test_2, ExampleTestCalendar2) assert type(d2c.test_2).__name__ == "ExampleTestCalendar2InDate" assert type(d2c.test_2.__class__).__name__ == "ModifiedClass" assert d2c.test_2.week == 5171 assert d2c.test_2.day == 3
def test_043_registered_attribute_class_with_other_constructors(self, clean_Date): class ExampleTestCalendar2(ExampleTestCalendar): @classmethod def with_thousands(cls, thousands, week, day): return cls(1000 * thousands + week, day) Date.register_new_calendar('test_2', ExampleTestCalendar2) # Date attribute type and metaclass are correct assert Date.test_2.__name__ == 'ExampleTestCalendar2InDate' assert type(Date.test_2).__name__ == 'ModifiedClass' assert issubclass(Date.test_2, ExampleTestCalendar) # constructed date type and value are is correct d2a = Date.test_2(100, 4) assert type(d2a) == Date assert d2a.day_count == 697 d2d = Date.test_2.with_thousands(2, 3, 4) assert type(d2d) == Date assert d2d.day_count == 14018 # new attribute on date instance, type and value are correct d2b = Date(1000) assert isinstance(d2b.test_2, ExampleTestCalendar2) assert type(d2b.test_2).__name__ == 'ExampleTestCalendar2InDate' assert type(d2b.test_2.__class__).__name__ == 'ModifiedClass' assert d2b.test_2.week == 143 assert d2b.test_2.day == 6 # new attribute on date instance build by another calendar, type and value are correct d2c = Date.gregorian(100, 2, 3) assert isinstance(d2c.test_2, ExampleTestCalendar2) assert type(d2c.test_2).__name__ == 'ExampleTestCalendar2InDate' assert type(d2c.test_2.__class__).__name__ == 'ModifiedClass' assert d2c.test_2.week == 5171 assert d2c.test_2.day == 3
def test_920_subclass1(self): # check that there is no interference from the interface mechanism and from possible additional arguments class D(Date): theAnswer = 42 def __init__(self, *args, **kws): temp = kws.copy() self.extra = temp.pop("extra") Date.__init__(self, *args, **temp) def newmeth(self, start): return start + (self.day_count * 3) // 2 d1 = Date(102013) d2 = D(102013, extra=7) assert d2.theAnswer == 42 assert d2.extra == 7 assert d1.day_count == d2.day_count assert d2.newmeth(-7) == (d1.day_count * 3) // 2 - 7
def test_100_write_attribute(self): "This attribute is read-only." d = Date(1) with pytest.raises(AttributeError): d.day_count = 3
def test_320_comparisons(self): d1 = Date(42) d2 = Date(42) assert d1 == d2 assert d1 <= d2 assert d1 >= d2 assert not (d1 != d2) assert not (d1 < d2) assert not (d1 > d2) d3 = Date(4242) # this is larger than d1 assert d1 < d3 assert d3 > d1 assert d1 <= d3 assert d3 >= d1 assert d1 != d3 assert d3 != d1 assert not (d1 == d3) assert not (d3 == d1) assert not (d1 > d3) assert not (d3 < d1) assert not (d1 >= d3) assert not (d3 <= d1) # Reverse comparison mechanism class DateLike: def __init__(self): self.day_count = 42 def __eq__(self, other): return self.day_count == other.day_count def __ne__(self, other): return self.day_count != other.day_count def __lt__(self, other): return self.day_count < other.day_count def __le__(self, other): return self.day_count <= other.day_count def __gt__(self, other): return self.day_count > other.day_count def __ge__(self, other): return self.day_count >= other.day_count dl = DateLike() d4 = Date(4) d42 = Date(42) d55 = Date(55) assert not (d4 == dl) assert d42 == dl assert not (d55 == dl) assert d4 != dl assert not (d42 != dl) assert d55 != dl assert d4 < dl assert not (d42 < dl) assert not (d55 < dl) assert d4 <= dl assert d42 <= dl assert not (d55 <= dl) assert not (d4 > dl) assert not (d42 > dl) assert d55 > dl assert not (d4 >= dl) assert d42 >= dl assert d55 >= dl
def test_010_register_new_calendar_existing_calendar_or_attribute(self): with pytest.raises(AttributeError): Date.register_new_calendar("gregorian", ExampleTestCalendar) with pytest.raises(AttributeError): Date.register_new_calendar("day_count", ExampleTestCalendar)
def test_350_bool(self): """In boolean contexts, all Date instances are considered to be true.""" for day_count in date_test_data: assert Date(day_count)
def test_520_str(self): for day_count in date_test_data: d = Date(day_count) assert int(str(d)[5:]) == day_count
def __init__(self, *args, **kws): temp = kws.copy() self.extra = temp.pop("extra") Date.__init__(self, *args, **temp)
def test_000_valid_parameter_types(self): """The argument is required and must be an integer.""" for day_count in date_test_data: assert Date(day_count).day_count == day_count
def test_100_write_attribute(self): """This attribute is read-only.""" d = Date(1) with pytest.raises(AttributeError): d.day_count = 3
def test_010_register_new_calendar_existing_calendar_or_attribute(self): with pytest.raises(AttributeError): Date.register_new_calendar('gregorian', ExampleTestCalendar) with pytest.raises(AttributeError): Date.register_new_calendar('day_count', ExampleTestCalendar)
def __init__(self, *args, **kws): temp = kws.copy() self.extra = temp.pop('extra') Date.__init__(self, *args, **temp)
def test_300_valid_operations(self): a = Date(0) b = Date(-3) c = Date(5) zero = TimeDelta(0) one = TimeDelta(1) minusone = TimeDelta(-1) # Addition between Date and TimeDelta # test with zero, negative and positive dates assert a + zero == Date(0) assert a + one == Date(1) assert a + minusone == Date(-1) assert b + zero == Date(-3) assert b + one == Date(-2) assert b + minusone == Date(-4) assert c + zero == Date(5) assert c + one == Date(6) assert c + minusone == Date(4) # Reverse addition between TimeDelta and Date # test with zero, negative and positive dates assert zero + a == Date(0) assert one + a == Date(1) assert minusone + a == Date(-1) assert zero + b == Date(-3) assert one + b == Date(-2) assert minusone + b == Date(-4) assert zero + c == Date(5) assert one + c == Date(6) assert minusone + c == Date(4) # subtraction between Date and TimeDelta, reverse is not defined # test with zero, negative and positive dates assert a - zero == Date(0) assert a - one == Date(-1) assert a - minusone == Date(1) assert b - zero == Date(-3) assert b - one == Date(-4) assert b - minusone == Date(-2) assert c - zero == Date(5) assert c - one == Date(4) assert c - minusone == Date(6) # subtraction between two Date's, reverse is not defined # test with zero, negative and positive dates assert a - a == TimeDelta(0) assert a - b == TimeDelta(3) assert a - c == TimeDelta(-5) assert b - a == TimeDelta(-3) assert b - b == TimeDelta(0) assert b - c == TimeDelta(-8) assert c - a == TimeDelta(5) assert c - b == TimeDelta(8) assert c - c == TimeDelta(0)