Beispiel #1
0
def test_audit__double_history_and_studio():
    student: Dict[str, Any] = {
        'areas': [
            AreaPointer(
                code='140',
                status=AreaStatus.Declared,
                kind=AreaType.Major,
                name='Studio Art',
                degree='B.A.',
                dept='ART',
                gpa=None,
                terms_since_declaration=None,
            ),
            AreaPointer(
                code='135',
                status=AreaStatus.Declared,
                kind=AreaType.Major,
                name='Art History',
                degree='B.A.',
                dept='ART',
                gpa=None,
                terms_since_declaration=None,
            ),
        ],
        'courses': [
            course_from_str('DEPT 123'),
        ],
    }

    c = Constants(matriculation_year=2000)

    area = AreaOfStudy.load(c=c,
                            student=Student.load(
                                dict(areas=student['areas'],
                                     courses=student['courses'])),
                            specification={
                                'name': 'Art History Test',
                                'type': 'major',
                                'code': '140',
                                'degree': 'B.A.',
                                'result': {
                                    'all': [{
                                        'course': 'DEPT 123'
                                    }],
                                }
                            })

    messages = list(
        audit(area=area,
              student=Student.load(
                  dict(areas=student['areas'], courses=student['courses']))))
    result = messages[-1].result

    assert result.result.items[-1].result.items[-1].result.assertions[
        0].expected == 18
Beispiel #2
0
def test_limit__at_most_1_course():
    test_data = io.StringIO("""
        limit:
          - at_most: 1
            where: {number: {$eq: 201}}

        result:
          from: courses
          where: {number: {$eq: 201}}
          assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data, Loader=yaml.SafeLoader), c=c)

    course_1 = course_from_str("BIO 201")
    course_2 = course_from_str("ABC 201")
    transcript = [course_1, course_2]

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    course_sets = set(frozenset(s.solution.output) for s in solutions)

    assert course_sets == set([
        frozenset((course_2,)),
        frozenset((course_1,)),
        frozenset(()),
    ])
Beispiel #3
0
def test_limit__at_most_1_credit():
    test_data = io.StringIO("""
        limit:
          - at_most: 1 credit
            where: {number: {$eq: 201}}

        result:
          from: courses
          assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data, Loader=yaml.SafeLoader), c=c)

    course_1 = course_from_str("ABC 201", credits='0.5')
    course_2 = course_from_str("BCD 201", credits='0.5')
    course_3 = course_from_str("CDE 201", credits='0.5')
    transcript = [course_1, course_2, course_3]

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    course_sets = set(frozenset(s.solution.output) for s in solutions)

    for i, s in enumerate(course_sets):
        print(i)
        for _c in s:
            print(_c.course())

    assert course_sets == set([
        frozenset((course_1, course_2)),
        frozenset((course_1, course_3)),
        frozenset((course_2, course_3)),
        frozenset((course_1,)),
        frozenset((course_2,)),
        frozenset((course_3,)),
        frozenset(()),
    ])
Beispiel #4
0
def test_from(caplog):
    caplog.set_level(logging.DEBUG)

    test_data = io.StringIO("""
        result:
            from: courses
            where: {gereqs: {$eq: SPM}}
            assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    transcript = [
        course_from_str("CSCI 111", gereqs=['SPM'], year=2008, term='1'),
        course_from_str("ASIAN 110"),
    ]

    s = next(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))
    a = s.audit().result

    assert len(a.successful_claims) == 1

    assert a.successful_claims[0].course.clbid == transcript[0].clbid
Beispiel #5
0
def test_solution_count_greaterthan_1(caplog):
    caplog.set_level(logging.DEBUG, logger='dp.rule.given.rule')
    area, transcript = __get_data("""
        result:
            from: courses
            where: {gereqs: {$eq: SPM}}
            assert: {count(courses): {$gt: 1}}
    """)

    solutions = area.solutions(student=Student.load(dict(courses=transcript)),
                               exceptions=[])

    sol = next(solutions)
    assert len(sol.solution.output) == 2

    sol = next(solutions)
    assert len(sol.solution.output) == 2

    sol = next(solutions)
    assert len(sol.solution.output) == 2

    sol = next(solutions)
    assert len(sol.solution.output) == 3

    with pytest.raises(StopIteration):
        next(solutions)
def test_limits_esth(caplog):
    spec = """
    result:
      from: courses
      limit:
        - at_most: 1
          where:
            $or:
              - course: {$in: ['STAT 110', 'STAT 212', 'STAT 214']}
              - ap: {$eq: AP Statistics}
      assert: {count(courses): {$gte: 2}}
    """

    area = AreaOfStudy.load(specification=yaml.load(stream=spec,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    psych_241 = course_from_str("PSYCH 241", clbid="0")
    stat_212 = course_from_str("STAT 212", clbid="1")
    ap_stat = course_from_str("STAT 0",
                              name="AP Statistics",
                              course_type="AP",
                              clbid="2")
    transcript = [psych_241, stat_212, ap_stat]

    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))
    course_sets = [list(s.solution.output) for s in solutions]

    assert course_sets == [
        [psych_241],
        [psych_241, stat_212],
        [psych_241, ap_stat],
    ]
Beispiel #7
0
def run_one(args: argparse.Namespace) -> None:
    stnum = args.stnum
    catalog = args.catalog
    code = args.code

    with sqlite_connect(args.db, readonly=True) as conn:
        results = conn.execute(
            '''
            SELECT input_data
            FROM server_data
            WHERE (stnum, catalog, code) = (:stnum, :catalog, :code)
        ''', {
                'stnum': stnum,
                'catalog': catalog,
                'code': code
            })

        record = results.fetchone()
        input_data: dict = json.loads(record['input_data'])

    areas = load_areas(args, [{'catalog': catalog, 'code': code}])
    result_msg = audit((stnum, catalog, code),
                       data=input_data,
                       db=args.db,
                       area_spec=areas[f"{catalog}/{code}"])
    assert result_msg

    student = Student.load(input_data)

    print(render_result(student, json.loads(result_msg['result'])))
def test_excluded_req_gpa():
    transcript = trns()

    area = AreaOfStudy.load(c=c, student=Student.load(dict(courses=transcript)), specification={
        'name': 'test',
        'type': 'concentration',
        'result': {
            'all': [
                {'requirement': 'compsci'},
                {'requirement': 'art'},
            ],
        },
        'requirements': {
            'compsci': {
                'result': {
                    'from': 'courses',
                    'where': {'subject': {'$eq': 'CSCI'}},
                    'assert': {'count(courses)': {'$gte': 2}},
                }
            },
            'art': {
                'in_gpa': False,
                'result': {
                    'from': 'courses',
                    'where': {'subject': {'$eq': 'ART'}},
                    'assert': {'count(courses)': {'$gte': 1}},
                },
            },
        },
    })

    solution = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))[0]
    result = solution.audit()

    assert area.result.items[1].in_gpa is False

    assert set(result.matched_for_gpa()) == set([transcript[0], transcript[1]])
    assert transcript[2] not in set(result.matched_for_gpa())

    assert result.gpa() == Decimal('2.5')
def test_global_limits(caplog):
    caplog.set_level(logging.DEBUG)

    test_data = io.StringIO("""
        limit:
          - at_most: 1
            where: {level: {$eq: 200}}
          - at_most: 1
            where: {level: {$eq: 300}}

        result:
          from: courses
          where: {subject: {$eq: BIO}}
          assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    bio_101 = course_from_str("BIO 101")
    bio_201 = course_from_str("BIO 201")
    bio_202 = course_from_str("BIO 202")
    bio_301 = course_from_str("BIO 301")
    bio_302 = course_from_str("BIO 302")
    transcript = [bio_101, bio_201, bio_202, bio_301, bio_302]

    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))
    course_sets = set([frozenset(s.solution.output) for s in solutions])

    assert course_sets == set([
        frozenset((bio_101, bio_201)),
        frozenset((bio_101, bio_201, bio_301)),
        frozenset((bio_101, bio_201, bio_302)),
        frozenset((bio_101, bio_202)),
        frozenset((bio_101, bio_202, bio_301)),
        frozenset((bio_101, bio_202, bio_301)),
        frozenset((bio_101, bio_202, bio_302)),
        frozenset((bio_101, bio_301)),
        frozenset((bio_101, bio_302)),
        frozenset((bio_101, )),
        frozenset((bio_201, bio_301)),
        frozenset((bio_201, bio_302)),
        frozenset((bio_201, )),
        frozenset((bio_202, bio_301)),
        frozenset((bio_202, bio_302)),
        frozenset((bio_202, )),
        frozenset((bio_301, )),
        frozenset((bio_302, )),
    ])
def test_normal_gpa():
    transcript = trns()

    area = AreaOfStudy.load(c=c, student=Student.load(dict(courses=transcript)), specification={
        'name': 'test',
        'type': 'concentration',
        'result': {
            'all': [
                {'requirement': 'compsci'},
                {'requirement': 'art'},
            ],
        },
        'requirements': {
            'compsci': {
                'result': {
                    'from': 'courses',
                    'where': {'subject': {'$eq': 'CSCI'}},
                    'assert': {'count(courses)': {'$gte': 2}},
                }
            },
            'art': {
                'result': {
                    'from': 'courses',
                    'where': {'subject': {'$eq': 'ART'}},
                    'assert': {'count(courses)': {'$gte': 1}},
                },
            },
        },
    })

    solution = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))[0]

    result = solution.audit()

    assert set(result.matched()) == set(transcript)

    assert result.gpa() == Decimal('2.0')
Beispiel #11
0
def test_mc__none_2(caplog):
    caplog.set_level(logging.DEBUG, logger='dp.context')

    test_data = io.StringIO("""
        result:
            either:
                - requirement: Root
                - requirement: Alt

        requirements:
            Root:
                result:
                    course: DEPT 123

            Alt:
                result:
                    course: DEPT 123

        multicountable:
            DEPT 123:
                - [Root]
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    course = course_from_str('DEPT 123')

    solutions = area.solutions(student=Student.load(dict(courses=[course])),
                               exceptions=[])

    results = [s.audit() for s in solutions]
    assert len(results) == 3

    result_a, result_b, result_c = results
    assert result_a.is_ok() is True
    assert result_b.is_ok() is True
    assert result_c.is_ok() is True

    assert list(c.course.course() for c in result_c.claims()
                if c.failed is False) == [course.course()]

    assert result_c.result.items[0].result.claim_attempt.failed is False
    assert result_c.result.items[1].result.claim_attempt.failed is True
Beispiel #12
0
def test_overlaps(caplog: Any) -> None:
    # caplog.set_level(logging.DEBUG)
    global c

    area = AreaOfStudy.load(c=c, specification={
        "result": {"all": [
            {"requirement": "Core"},
            {"requirement": "Electives"},
        ]},
        "requirements": {
            "Core": {
                "result": {"all": [
                    {"course": "MUSIC 212"},
                    {"course": "MUSIC 214"},
                ]},
            },
            "Electives": {
                "result": {
                    "from": "courses",
                    "where": {
                        "$and": [
                            {"subject": {"$eq": "MUSIC"}},
                            {"level": {"$eq": [300]}},
                        ],
                    },
                    "all": [
                        {"assert": {"count(courses)": {"$gte": 2}}},
                    ],
                },
            },
        },
    })

    transcript = [course_from_str(c) for c in ["MUSIC 212", "MUSIC 214", "MUSIC 301", "MUSIC 302"]]
    ctx = RequirementContext().with_transcript(transcript)

    area.result.find_independent_children(items=area.result.items, ctx=ctx)

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.is_ok() is True
Beispiel #13
0
def test_mc__only_query_references(caplog):
    caplog.set_level(logging.DEBUG, logger='dp.context')

    test_data = io.StringIO("""
        result:
            all:
                - requirement: Root
                - requirement: Alt

        requirements:
            Root:
                result:
                    from: courses
                    assert: {count(courses): {$gte: 1}}

            Alt:
                result:
                    from: courses
                    assert: {count(courses): {$gte: 1}}

        multicountable:
            DEPT 123:
                - [Root]
                - [Alt]
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    course = course_from_str('DEPT 123')

    solutions = area.solutions(student=Student.load(dict(courses=[course])),
                               exceptions=[])

    results = [s.audit() for s in solutions]
    assert len(results) == 1

    result_a = results[0]
    assert result_a.is_ok() is True

    assert list(c.course.course() for c in result_a.claims()
                if c.failed is False) == [course.course(),
                                          course.course()]
Beispiel #14
0
def test_pruning_on_count_rule(caplog):
    caplog.set_level(logging.DEBUG)

    area = AreaOfStudy.load(specification={
        "result": {
            "any": [
                {
                    "course": "DEPT 123"
                },
                {
                    "course": "DEPT 234"
                },
                {
                    "course": "DEPT 345"
                },
            ],
        },
    },
                            c=c)

    course_a = course_from_str("DEPT 123", clbid="0")
    course_b = course_from_str("DEPT 234", clbid="1")
    transcript = [course_a, course_b]

    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))

    assert [[
        x.course for x in s.solution.items if isinstance(x, CourseResult)
    ] for s in solutions] == [['DEPT 123', 'DEPT 234']]
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.result.count == 1
    assert result.is_ok() is True
    assert result.is_waived() is False
    assert result.claims()[0].course.clbid == course_a.clbid
Beispiel #15
0
def x_test_overlaps(caplog: Any) -> None:
    # caplog.set_level(logging.DEBUG)

    area = AreaOfStudy.load(c=c, specification={
        "result": {"all": [
            {"requirement": "Core"},
            {"requirement": "Electives"},
            {"requirement": "Lessons"},
        ]},
        "requirements": {
            "Core": {
                "result": {"all": [
                    {"course": "MUSIC 212"},
                    {"course": "MUSIC 214"},
                    {"course": "MUSIC 237"},
                    {"course": "MUSIC 251"},
                    {"course": "MUSIC 261"},
                    {"course": "MUSIC 298"},
                ]},
            },
            "Electives": {
                "result": {
                    "from": "courses",
                    "where": {
                        "$and": [
                            {"subject": {"$eq": "MUSIC"}},
                            {"level": {"$in": [200, 300]}},
                        ],
                    },
                    "all": [
                        {"assert": {"count(courses)": {"$gte": 8}}},
                        {
                            "where": {"level": {"$eq": 300}},
                            "assert": {"count(courses)": {"$gte": 2}},
                        },
                    ],
                },
            },
            "Lessons": {
                "result": {
                    "from": "courses",
                    "where": {"subject": {"$eq": "MUSPF"}},
                    "all": [
                        {"assert": {"count(terms)": {"$gte": 6}}},
                        {"assert": {"sum(credits)": {"$gte": 2.5}}},
                        {
                            "where": {"credits": {"$eq": 0.5}},
                            "assert": {"count(terms)": {"$gte": 4}},
                        },
                    ],
                },
            },
        },
    })

    transcript = [course_from_str(c) for c in [
        "MUSIC 212", "MUSIC 214", "MUSIC 237", "MUSIC 251", "MUSIC 252", "MUSIC 298",
        "MUSIC 222", "MUSIC 224", "MUSIC 247", "MUSIC 261", "MUSIC 262", "MUSIC 299", "MUSIC 301", "MUSIC 302",
        "MUSPF 101", "MUSPF 102", "MUSPF 103", "MUSPF 104", "MUSPF 105", "MUSPF 106",
    ]]

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.is_ok() is True
Beispiel #16
0
def render(args: argparse.Namespace) -> None:
    stnum = args.stnum
    catalog = args.catalog
    code = args.code
    branch = args.branch
    base = args.base

    input_data: Optional[Dict]
    baseline_result: Optional[Dict]
    branch_result: Optional[Dict] = None

    with sqlite_connect(args.db, readonly=True) as conn:
        if branch == 'server':
            results = conn.execute(
                '''
                SELECT d.input_data, d.result as output
                FROM server_data d
                WHERE d.stnum = :stnum
                    AND d.catalog = :catalog
                    AND d.code = :code
            ''', {
                    'catalog': catalog,
                    'code': code,
                    'stnum': stnum
                })

            record = results.fetchone()
            assert record, {'catalog': catalog, 'code': code, 'stnum': stnum}

            input_data = json.loads(record['input_data'])
            baseline_result = json.loads(record['output'])

        elif branch == 'baseline':
            results = conn.execute(
                '''
                SELECT d.input_data, b1.result as output
                FROM server_data d
                LEFT JOIN baseline b1 ON (b1.stnum, b1.catalog, b1.code) = (d.stnum, d.catalog, d.code)
                WHERE d.stnum = :stnum
                    AND d.catalog = :catalog
                    AND d.code = :code
            ''', {
                    'catalog': catalog,
                    'code': code,
                    'stnum': stnum
                })

            record = results.fetchone()
            assert record, {'catalog': catalog, 'code': code, 'stnum': stnum}

            input_data = json.loads(record['input_data'])
            baseline_result = json.loads(record['output'])

        else:
            if base == 'baseline':
                results = conn.execute(
                    '''
                    SELECT d.input_data, b1.result as baseline, b2.result as branch
                    FROM server_data d
                    LEFT JOIN baseline b1 ON (b1.stnum, b1.catalog, b1.code) = (d.stnum, d.catalog, d.code)
                    LEFT JOIN branch b2 ON (b2.stnum, b2.catalog, b2.code) = (d.stnum, d.catalog, d.code)
                    WHERE d.stnum = :stnum
                        AND d.catalog = :catalog
                        AND d.code = :code
                        AND b2.branch = :branch
                ''', {
                        'catalog': catalog,
                        'code': code,
                        'stnum': stnum,
                        'branch': branch
                    })
            else:
                results = conn.execute(
                    '''
                    SELECT d.input_data, b1.result as baseline, b2.result as branch
                    FROM server_data d
                    LEFT JOIN branch b1 ON (b1.stnum, b1.catalog, b1.code) = (d.stnum, d.catalog, d.code)
                    LEFT JOIN branch b2 ON (b2.stnum, b2.catalog, b2.code) = (d.stnum, d.catalog, d.code)
                    WHERE d.stnum = :stnum
                        AND d.catalog = :catalog
                        AND d.code = :code
                        AND b1.branch = :base
                        AND b2.branch = :branch
                ''', {
                        'catalog': catalog,
                        'code': code,
                        'stnum': stnum,
                        'branch': branch,
                        'base': base
                    })

            record = results.fetchone()
            assert record, f"could not find record matching catalog={catalog}, code={code}, stnum={stnum}, branch={branch}"

            input_data = json.loads(record['input_data'])
            baseline_result = json.loads(record['baseline'])
            branch_result = json.loads(record['branch'])

        assert input_data
        assert baseline_result

        student = Student.load(input_data)

        if not branch_result:
            print(render_result(student, baseline_result))
            return

        if args.diff:
            baseline_result_lines = render_result(student,
                                                  baseline_result).split('\n')
            branch_result_lines = render_result(student,
                                                branch_result).split('\n')

            if baseline_result_lines == branch_result_lines:
                print('no changes')
                return
            else:
                d = difflib.Differ()
                print('\n'.join(
                    d.compare(baseline_result_lines, branch_result_lines)))
                return

        print('Baseline')
        print('========')
        print()
        print(render_result(student, baseline_result))
        print()
        print()
        label = f'Branch: {branch}'
        print(label)
        print('=' * len(label))
        print()
        print(render_result(student, branch_result))