Skip to content

Check Functions do not display datetime comparisons helpfully #98

Open

Description

@pazzarpj

Comparing datetime functions in a chk_* will show .3g instead of the repr for the datetime object. This could overflow into other object time comparisons that are not float or integer based.

Activity

  1. christopherwallis commented on Apr 2, 2019

    @christopherwallis
    Contributor

    Had a go at replicating this issue but without any luck. Ended up writing some tests for chk_smaller.
    They're in my fix-time-checks fork in Fixate/test/core/test_checks.py if it helps.

  2. clint-lawrence commented on Apr 3, 2019

    @clint-lawrence
    Collaborator

    @pazzarpj, have you got a script that shows the error? or can you write a failing test?

  3. pazzarpj commented on Apr 5, 2019

    @pazzarpj
    ContributorAuthor
    from datetime import datetime, timedelta
    from fixate.core.checks import CheckClass, _in_range
    from fixate.ui_cmdline.cmd_line import _print_comparisons
    chk1 = CheckClass(_min=2, _max=3, test_val=2.5, target=_in_range)
    date_thing = datetime(2019, 1, 1, 0, 0)
    chk2 = CheckClass(_min=date_thing - timedelta(seconds=2), _max=datetime.now() + timedelta(seconds=2), test_val=date_thing, target=_in_range)
    
    _print_comparisons(True, chk1, 1, None)
    _print_comparisons(True, chk2, 2, None)

    Expected output

    Check 1: PASS when comparing 2.5 in range 2 - 3 :
    Check 2: PASS when comparing 2019-01-01 00:00:00 in range 2018-12-31 23:59:58 - 2019-01-01 00:00:02 :

    Actual

    Check 1: PASS when comparing 2.5 in range 2 - 3 :
    Check 2: PASS when comparing .3g in range .3g - .3g :
  4. christopherwallis commented on Apr 5, 2019

    @christopherwallis
    Contributor

    There seems to be an issue with timestruct objects as well in that script. They're displayed with their data but always pass:

    t = time.localtime(time.time())
    chk3 = CheckClass(_min=time.localtime(1545925760), _max=time.localtime(1545925777), test_val=t, target=_in_range)
    
    _print_comparisons(True, chk3, 3, None)
    
    Check 3: PASS when comparing time.struct_time(tm_year=2019, tm_mon=4,
    tm_mday=5, tm_hour=19, tm_min=50, tm_sec=33, tm_wday=4, tm_yday=95,
    tm_isdst=1) in range time.struct_time(tm_year=2018, tm_mon=12, tm_mday=28,
    tm_hour=2, tm_min=49, tm_sec=20, tm_wday=4, tm_yday=362, tm_isdst=1) -
    time.struct_time(tm_year=2018, tm_mon=12, tm_mday=28, tm_hour=2, tm_min=49,
    tm_sec=37, tm_wday=4, tm_yday=362, tm_isdst=1)
    

    However the issue doesn't seem to occur when using chk_in_range for either timestruct or datetime objects as the following tests pass:

    def test_time_struct_check_true():
        t = time.localtime(1545925765)
        chk = chk_in_range(t, time.localtime(1545925760), time.localtime(1545925777), "Time is in range")
        assert chk
    
    
    def test_time_struct_check_false():
        with pytest.raises(CheckFail):
            t = time.localtime(1554452763)
            chk = chk_in_range(t, time.localtime(1545925760), time.localtime(1545925777), "Time is NOT in range")
    
    
    def test_datetime_struct_check_true():
        t_min = datetime.now()
        time.sleep(1)
        t = datetime.now()
        time.sleep(1)
        t_max = datetime.now()
        chk = chk_in_range(t, t_min, t_max, "DateTime is in range")
        assert chk
    
    
    def test_datetime_struct_check_false():
        with pytest.raises(CheckFail):
            t_min = datetime.now()
            time.sleep(1)
            t_max = datetime.now()
            time.sleep(1)
            t = datetime.now()
            chk = chk_in_range(t, t_min, t_max, "DateTime is not in range")
            assert chk
    
  5. pazzarpj commented on Apr 5, 2019

    @pazzarpj
    ContributorAuthor

    The script I provided was to demonstrate the display issue, the CheckClass doesn't actually run the check.

    _print_comparisons first parameter determines if it displays as pass/fail.

    The issue is that the _print_comparisons function assumes a number with the {:.3g} string formatter.

  6. christopherwallis commented on Apr 5, 2019

    @christopherwallis
    Contributor

    Riiight, i finally get it now. I'll stop barking up the wrong tree. Will look into it when i get a chance. Thanks for slow walking me there.

  7. christopherwallis commented on Apr 8, 2019

    @christopherwallis
    Contributor

    Issue found in ui_cmdline\cmd_line.py line 304:

    def round_to_3_sig_figures(chk):
        """
        Tries to round elements to 3 significant figures for formatting
        :param chk:
        :return:
        """
        ret_dict = {}
        for element in ["_min", "_max", "test_val", "nominal", "tol"]:
            ret_dict[element] = getattr(chk, element, None)
            try:
                ret_dict[element] = "{:.3g}".format(ret_dict[element])
            except:
                pass
        return ret_dict
    

    format with decimal places does not produce the desired output but does not raise an error when datetime object is used.

    Adding an assert math.isclose within the try: rejects the change of format, allowing the original formatting (standard datetime object output) to be shown:

    Check 1: PASS when comparing 2.5 in range 2 - 3 :
    
    Check 2: PASS when comparing 2019-01-01 00:00:00 in range 2018-12-31
    23:59:58 - 2019-04-08 21:52:25.021197 :
    

    Will run a few more tests and upload the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions