Пример #1
0
def test_figures():
    ass = Assignment()

    with ass.add_figure() as f:
        f.caption = "A"
        f.caption += " figure"
        f.filename = "image.png"

    assert len(ass._figures) == 1
    assert ass._figures[0].filename == os.path.abspath("image.png")
    assert ass._figures[0].caption == "A figure"
    assert ass._figures[0].formatted_caption == "A figure"

    ass.NS.id = "1234"

    with ass.add_figure() as f:
        f.caption = "figure for question {id}"
        f.filename = "image.png"

    assert len(ass._figures) == 2
    assert ass._figures[0].filename == os.path.abspath("image.png")
    assert ass._figures[0].caption == "A figure"
    assert ass._figures[0].formatted_caption == "A figure"
    assert ass._figures[1].filename == os.path.abspath("image.png")
    assert ass._figures[1].caption == "figure for question {id}"
    assert ass._figures[1].formatted_caption == "figure for question 1234"
Пример #2
0
def test_simple_writer(tmpdir):
    with utils.TempDir(tmpdir):
        ass = Assignment()

        with ass.add_question() as q:
            q.text = "q1"
            with q.add_part() as p:
                p.text = "q1p1"
            with q.add_part() as p:
                p.text = "q1p2"

        with ass.add_question() as q:
            q.text = "q2"
            with q.add_part() as p:
                p.text = "q2p1"
            with q.add_part() as p:
                p.text = "q2p2"

        with pytest.raises(RuntimeError):
            w = Writers.Simple()
            w.dump(ass)

        fh = io.StringIO()
        writer = Writers.Simple(fh)
        writer.dump(ass)
Пример #3
0
def test_problem_set_builder(tmpdir):
    with utils.TempDir(tmpdir):
        ass = Assignment()
        with ass.add_question() as q:
            q.text += "Question 1"
            with q.add_question() as qq:
                qq.text += "What is the answer to Q1?"
                with qq.add_answer(Answer.Numerical) as a:
                    a.quantity = 1.23

        with ass.add_question() as q:
            q.text += "Question 2"
            with q.add_part() as p:
                p.text += "Question 2, Part 1"
                with p.add_question() as qq:
                    qq.text += "What is the answer to Q2P1?"
                    with qq.add_answer(Answer.Numerical) as a:
                        a.quantity = 2.34

        if os.path.exists("_test"): shutil.rmtree("_test")
        os.mkdir("_test")

        Actions.BuildProblemSetAndBlackboardQuiz(ass, "test")
        shutil.rmtree("_test")

        Actions.BuildProblemSetAndBlackboardQuiz(ass, "test", remove=True)

        assert os.path.isdir("_test")
        assert os.path.isfile("_test/test.tex")
        assert os.path.isfile("_test/test.pdf")
        assert os.path.isfile("_test/test.aux")
        assert os.path.isfile("_test/test-quiz.txt")
Пример #4
0
def test_blackboard_quiz_writer_output():
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = "q1.1"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.incorrect += "a1"
            a.incorrect += "a2"
            a.incorrect += "a3"
            a.correct += "a4"
    with ass.add_question() as q:
        q.text = "q1.2"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.incorrect += "a1"
            a.incorrect += "a2"
            a.incorrect += "a3"
            a.incorrect += "a4"

    with ass.add_question() as q:
        q.text = "q2.1"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = 1.23
    with ass.add_question() as q:
        q.text = "q2.2"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = u.Quantity(987654321, 'm/s')
    with ass.add_question() as q:
        q.text = "q2.3"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = u.Quantity(5432, '')
    with ass.add_question() as q:
        q.text = "q2.4"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = UQ_(Q_(10.234, 'm'), Q_(321, 'cm'))

    with ass.add_question() as q:
        q.text = "q3.1"
        with q.add_answer(Answer.Text) as a:
            a.text = "correct answer"
    with ass.add_question() as q:
        q.text = "q3.2"
        with q.add_answer(Answer.Text) as a:
            a.text = "first correct answer;second correct answer"
    writer.dump(ass)

    quiz_text = """\
MC\tq1.1\ta1\tincorrect\ta2\tincorrect\ta3\tincorrect\ta4\tcorrect\tNone of the above.\tincorrect
MC\tq1.2\ta1\tincorrect\ta2\tincorrect\ta3\tincorrect\ta4\tincorrect\tNone of the above.\tcorrect
NUM\tq2.1\t1.23E+00\t1.23E-02
NUM\tq2.2 Give your answer in meter / second.\t9.88E+08\t9.88E+06
NUM\tq2.3\t5.43E+03\t5.43E+01
NUM\tq2.4 Give your answer in meter.\t1.02E+01\t3.21E+00
FIB\tq3.1\tcorrect answer
FIB\tq3.2\tfirst correct answer\tsecond correct answer
"""

    assert fh.getvalue() == quiz_text
Пример #5
0
def test_blackboard_quiz_writer_raises_on_no_answers():
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = "q1"

    with pytest.raises(RuntimeError):
        writer.dump(ass)
Пример #6
0
def test_question_tagging():

  ass = Assignment()
  with ass.add_question() as q:
    q.tags = "topic 1"
    q.tags += "topic 2"
    q.text = "q1"
    with q.add_answer(Answer.Text) as a:
      a.text = 'the answer'

  with ass.add_question() as q:
    q.tags = "topic 3"
    q.text = "q2"
    with q.add_part() as p:
      p.text = "q2p1"
      with p.add_answer(Answer.Text) as a:
        a.quantity = 2.34

  with ass.add_question() as q:
    q.text = "q3"
    q.tags = "topic 2"
    with q.add_part() as p:
      p.text = "q3p1"
      with p.add_answer(Answer.Text) as a:
        a.quantity = 3.10
    with q.add_part() as p:
      p.text = "q3p2"
      with p.add_answer(Answer.Text) as a:
        a.quantity = 3.2

  fass = Filters.filter( Filters.has_tag('topic 2'), ass )
  assert len(fass._questions) == 2
  assert fass._questions[0]._text == "q1"
  assert fass._questions[1]._text == "q3"

  fass = Filters.filter( Filters.has_tag('topic 3'), ass )
  assert len(fass._questions) == 1
  assert fass._questions[0]._text == "q2"


  fass = Filters.filter( Filters.has_tag("topic 2"), ass )
  assert len(fass._questions) == 2
  assert fass._questions[0]._text == "q1"
  assert fass._questions[1]._text == "q3"

  fass = Filters.filter( Filters.has_tag("topic 3"), ass )
  assert len(fass._questions) == 1
  assert fass._questions[0]._text == "q2"

  fass = Filters.filter( Filters.has_matching_tag("topic ."), ass )
  assert len(fass._questions) == 3
  assert fass._questions[0]._text == "q1"
  assert fass._questions[1]._text == "q2"
  assert fass._questions[2]._text == "q3"
Пример #7
0
def test_blackboard_quiz_writer_raises_on_unrecognized_answer_type():
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = "q1"
        with q.add_answer(Answer.AnswerBase) as a:
            pass

    with pytest.raises(RuntimeError):
        writer.dump(ass)
Пример #8
0
def test_blackboard_quiz_writer_removed_newlines_in_question_text():
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = '''A question
    with line breaks.'''
        with q.add_answer(Answer.MultipleChoice) as a:
            a.incorrect += "a1"
            a.correct += "a2"

    writer.dump(ass)

    assert fh.getvalue(
    ) == "MC\tA question with line breaks.\ta1\tincorrect\ta2\tcorrect\tNone of the above.\tincorrect\n"
Пример #9
0
def test_information():

    ass = Assignment()

    with ass.add_information() as info:
        info.text = "For each of the problems below..."

    with ass.add_question() as q:
        q.text = "Question 1"

    with ass.add_question() as q:
        q.text = "Question 2"

    with ass.add_information() as info:
        info.text = "For the next problem, assume..."

    with ass.add_question() as q:
        q.text = "Question 3"

    assert len(ass._questions) == 3
    assert len(ass._information) == 2
    assert 0 in ass._information
    assert 2 in ass._information
    assert ass._information[0].text == "For each of the problems below..."
    assert ass._information[2].text == "For the next problem, assume..."
Пример #10
0
def test_latex_writer_header_and_footers():
    ass = Assignment()
    ass.meta.title = "The Title"
    ass.meta.header = {
        'R': "right header",
        'L': "left header",
        'C': "center header"
    }
    ass.meta.footer = {
        'R': "right footer",
        'L': "left footer",
        'C': "center footer"
    }
    ass.meta.config = {
        'answers': {
            'numerical/spacing': '2in',
            'multiple_choice/symbol': r'\alph*)',
            'text/spacing': r'3in'
        }
    }

    with ass.add_question() as q:
        q.text = "q1"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.incorrect += "a1"
            a.correct += "a2"

    fh = io.StringIO()
    writer = Writers.Latex(fh)
    writer.make_key = True

    writer.dump(ass)

    print(fh.getvalue())
    assert re.search("header", fh.getvalue())
    assert re.search("footer", fh.getvalue())
    assert re.search("left header", fh.getvalue())
    assert re.search("center header", fh.getvalue())
    assert re.search("right header", fh.getvalue())
    assert re.search("left footer", fh.getvalue())
    assert re.search("center footer", fh.getvalue())
    assert re.search("right footer", fh.getvalue())
    assert re.search(r"\\title\{The Title\}", fh.getvalue())
Пример #11
0
def test_blackboard_quiz_writer_output_with_macros():
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = r"q1.1 \shell[strip]{pwd}"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.incorrect += "a1"
            a.incorrect += "a2"
            a.incorrect += "a3"
            a.correct += "a4"
    writer.dump(ass)

    quiz_text = """\
MC\tq1.1 {CWD}\ta1\tincorrect\ta2\tincorrect\ta3\tincorrect\ta4\tcorrect\tNone of the above.\tincorrect
""".format(CWD=os.path.abspath(os.getcwd()))

    assert fh.getvalue() == quiz_text
Пример #12
0
def test_demo():
    ass = Assignment()

    with ass.add_question() as q:
        q.text = '''
    Compute the gravitational force exerted on a {Mass1} object by:
    '''
        q.NS.Mass1 = 1.2

        with q.add_part() as p:
            p.text = '''
      Earth.
      '''

        with q.add_part() as p:
            p.text = '''
      A {Mass2} object placed {Distance} away.
      '''

            p.NS.Mass2 = 2.3
Пример #13
0
def test_latex_writer_raises_with_no_fh():
    ass = Assignment()

    with ass.add_question() as q:
        q.text = "q1"
        with q.add_part() as p:
            p.text = "q1p1"
        with q.add_part() as p:
            p.text = "q1p2"

    with ass.add_question() as q:
        q.text = "q2"
        with q.add_part() as p:
            p.text = "q2p1"
        with q.add_part() as p:
            p.text = "q2p2"

    with pytest.raises(RuntimeError):
        w = Writers.Latex()
        w.dump(ass)
Пример #14
0
def test_latex_writer(tmpdir):
    with utils.TempDir(tmpdir):
        fh = io.StringIO()
        writer = Writers.Latex(fh)
        writer.make_key = True

        ass = Assignment()
        ass.meta.title = "Homework Assignment"
        ass.meta.header = {'R': r"powered by \LaTeX"}
        ass.meta.config = {
            'answers': {
                'numerical/spacing': '2in',
                'multiple_choice/symbol': r'\alph*)',
                'text/spacing': r'3in'
            }
        }

        with ass.add_information() as info:
            info.text = "This is some information for the assignment."

        with ass.add_question() as q:
            q.text = "q1"
            with q.add_answer(Answer.MultipleChoice) as a:
                a.incorrect += "a1"
                a.incorrect += "a2"
                a.incorrect += "a3"
                a.correct += "a4"
        with ass.add_information() as info:
            info.text = "This information should appear between the first and second question."
        with ass.add_question() as q:
            q.text = "q2"
            with q.add_answer(Answer.Numerical) as a:
                a.quantity = 1.23
        with ass.add_question() as q:
            q.text = "q3"
            with q.add_part() as p:
                p.text = "q3p1"
            with q.add_part() as p:
                p.text = "q3p2"
        with ass.add_question() as q:
            q.text = "q1"
            with q.add_answer(Answer.MultipleChoice) as a:
                a.correct += "a1"
                a.incorrect += "a2"
                a.incorrect += "a3"
                a.correct += "a4"

        writer.dump(ass)

        with open('test.tex', 'w') as f:
            f.write(fh.getvalue())
Пример #15
0
def test_extract_quiz():

  ass = Assignment()

  with ass.add_question() as q:
    q.text = "q1"

    with q.add_question() as qq:
      qq.text = "q1:qq"

      with qq.add_answer(Answer.Text) as a:
        a.text = 'the answer'

  with ass.add_question() as q:
    q.text = "q2"

    with q.add_part() as p:
      p.text = "q2p1"

      with q.add_question() as qq:
        qq.text = "q2p1:qq"

  with ass.add_question() as q:
    q.text = "q3"

    with q.add_part() as p:
      p.text = "q3p1"

      with q.add_question() as qq:
        qq.text = "q3p1:qq"

    with q.add_part() as p:
      p.text = "q3p2"

  filt = Filters.QuizExtractor()

  quiz = filt.filter(ass)

  fh = io.StringIO()
  writer = Writers.Simple(fh)
  writer.dump(quiz)
Пример #16
0
def test_blackboard_quiz_writer_raises_on_multiple_choice_with_no_correct_answer(
):
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)
    writer.config.add_none_of_the_above_choice = False

    ass = Assignment()
    with ass.add_question() as q:
        q.text = "q1"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.incorrect += "a1"
            a.incorrect += "a2"
            a.incorrect += "a3"

    with pytest.raises(RuntimeError):
        writer.dump(ass)

    writer.config.add_none_of_the_above_choice = True
    writer.dump(ass)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = "q1"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.meta.add_none_of_the_above_choice = False
            a.incorrect += "a1"
            a.incorrect += "a2"
            a.incorrect += "a3"

    with pytest.raises(RuntimeError):
        writer.dump(ass)
Пример #17
0
def test_question_text():
    ass = Assignment()

    with ass.add_question() as q:
        q.text = "question 1 text"
        q.NS.x = 10

        # with q.add_answer( Numerical ) as a:
        # def calc(x):
        # return 2*x
        # a.NS.calc = calc

        with q.add_part() as p:
            p.text = "question 1, part 1 text"
        with q.add_part() as p:
            p.text = "question 1, part 2 text"

    with ass.add_question() as q:
        q.text = "question 2 text"

        with q.add_part() as p:
            p.text = "question 2, part 1 text"

        with q.add_part() as p:
            p.text = "question 2, part 2 text"
            # with q.add_answer( MultipleChoice ) as a:
            # a.choices  = '''
            # incorrect
            # ^correct"
            # also not correct
            # incorrect 4
            # '''

    assert ass._questions[0]._text == "question 1 text"
    assert ass._questions[0]._parts[0]._text == "question 1, part 1 text"
    assert ass._questions[0]._parts[1]._text == "question 1, part 2 text"
    assert ass._questions[1]._text == "question 2 text"
    assert ass._questions[1]._parts[0]._text == "question 2, part 1 text"
    assert ass._questions[1]._parts[1]._text == "question 2, part 2 text"
Пример #18
0
def test_blackboard_writer_figures(tmpdir):
    with utils.TempDir(tmpdir):
        image_text = r"""<?xml version="1.0" encoding="UTF-8" ?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="125" cy="125" r="75" fill="orange" />
</svg>
"""
        with open("file.svg", "w") as f:
            f.write(image_text)

        fh = io.StringIO()
        writer = Writers.BlackboardQuiz(fh)

        ass = Assignment()
        with ass.add_question() as q:
            q.text = "See image above."
            with q.add_figure() as f:
                f.filename = "file.svg"
            with q.add_answer(Answer.MultipleChoice) as a:
                a.incorrect += "a"
                a.correct += "b"
        with ass.add_question() as q:
            q.text = "no image here."
            with q.add_answer(Answer.MultipleChoice) as a:
                a.correct += "a"
                a.incorrect += "b"

        writer.dump(ass)

        quiz_text = """\
MC\t{IMAGE_TEXT}</br>Consider the figure above. See image above.\ta\tincorrect\tb\tcorrect\tNone of the above.\tincorrect
MC\tno image here.\ta\tcorrect\tb\tincorrect\tNone of the above.\tincorrect
""".format(IMAGE_TEXT=image_text.replace("\n", " "))

        assert fh.getvalue() == quiz_text

        with open("Bb-quiz-with-figure.txt", "w") as f:
            writer.dump(ass, f)
Пример #19
0
def test_blackboard_quiz_writer_with_numerical_answer_tolerance():
    fh = io.StringIO()
    writer = Writers.BlackboardQuiz(fh)

    ass = Assignment()
    with ass.add_question() as q:
        q.text = "q1"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = UQ_(Q_(10, 'm'), Q_(1, 'm'))
    with ass.add_question() as q:
        q.text = "q2"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = UQ_(Q_('10', 'm'), Q_('1', 'cm'))
    with ass.add_question() as q:
        q.text = "q3"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = Q_(10, 'm')
    with ass.add_question() as q:
        q.text = "q4"
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = Q_('10', 'm')

    writer.dump(ass)
Пример #20
0
def test_test_question_bank():
    bank = Assignment()

    def CalcAnswer(Mass):
        return (Mass * Q_(9.8, 'm/s^2')).to("N")

    with bank.add_question() as q:
        q.text = r'''How much does a {Mass:} weigh?'''
        q.tags += "M1"
        q.tags += "L1"
        q.NS.Mass = Q_(10, 'kg')
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = CalcAnswer

    with bank.add_question(copy.deepcopy(q)) as q:
        q.NS.Mass = Q_(20, 'kg')
        q.answer.NS.__dict__.update(q.NS.__dict__)

    with bank.add_question(copy.deepcopy(q)) as q:
        q.NS.Mass = Q_(30, 'kg')
        q.answer.NS.__dict__.update(q.NS.__dict__)

    def CalcAnswer(Mass1, Mass2, Distance):
        # a_r = v^2 / r = G m1 / r^2
        # v^2 = G m1 / r
        # v = sqrt( G m1 / r )
        G = Q_(6.674e-11, 'N kg^-2 m^2')
        return ((G * Mass1 / Distance)**0.5).to('m/s')

    with bank.add_question() as q:
        q.text = r'''How fast will a {Mass1} mass in a {Distance} orbit around a {Mass2} mass be traveling?'''
        q.tags += "M1"
        q.tags += "L2"
        q.NS.Mass1 = Q_(10, 'kg')
        q.NS.Mass2 = Q_(300, 'kg')
        q.NS.Distance = Q_(10, 'm')
        with q.add_answer(Answer.Numerical) as a:
            a.quantity = CalcAnswer

    with bank.add_question(copy.deepcopy(q)) as q:
        q.NS.Mass1 = Q_(35, 'kg')
        q.answer.NS.__dict__.update(q.NS.__dict__)

    with bank.add_question(copy.deepcopy(q)) as q:
        q.NS.Mass1 = Q_(500, 'kg')
        q.answer.NS.__dict__.update(q.NS.__dict__)

    test1 = Assignment()
    test2 = Assignment()
    test3 = Assignment()
    test4 = Assignment()

    for q in PullRandomQuestions(bank,
                                 predicate=(has_tag("M1") & has_tag("L1"))):
        with test1.add_question(q):
            pass

    for q in PullRandomQuestions(bank,
                                 predicate=(has_tag("M1") | has_tag("L1"))):
        with test2.add_question(q):
            pass

    for q in PullRandomQuestions(bank,
                                 num=2,
                                 predicate=(has_tag("M1") & has_tag("L1"))):
        with test3.add_question(q):
            pass

    for q in PullRandomQuestions(bank,
                                 num=2,
                                 predicate=(has_tag("M1") | has_tag("L1"))):
        with test4.add_question(q):
            pass

    assert len(test1._questions) == 3
    assert len(test2._questions) == 6
    assert len(test3._questions) == 2
    assert len(test4._questions) == 2

    with pytest.raises(RuntimeError):
        PullRandomQuestions(bank, num=2, predicate=has_tag("Missing"))

    assert CheckQuestionBank(bank, Checks.has_a_tag)
    assert CheckQuestionBank(bank, has_tag("M1"))
    assert not CheckQuestionBank(bank, has_tag("M2"))

    assert CheckQuestionBank(bank, Checks.has_answer)

    with bank.add_question() as q:
        q.text = "None"

    assert not CheckQuestionBank(bank, Checks.has_answer)

    del bank._questions[-1]
    assert CheckQuestionBank(bank, Checks.has_answer)

    with bank.add_question() as q:
        q.text = "None"
        with q.add_answer(Answer.MultipleChoice) as a:
            pass

    assert not CheckQuestionBank(bank, Checks.has_answer)

    del bank._questions[-1]
    assert CheckQuestionBank(bank, Checks.has_answer)

    with bank.add_question() as q:
        q.text = "None"
        with q.add_answer(Answer.MultipleChoice) as a:
            a.correct += "A"

    assert CheckQuestionBank(bank, Checks.has_answer)
Пример #21
0
def test_update():
    ass1 = Assignment()
    ass2 = Assignment()

    with ass1.add_question() as q:
        q.text = "A1Q1"

    with ass1.add_question() as q:
        q.text = "A1Q2"

    with ass2.add_question() as q:
        q.text = "A2Q1"

    assert len(ass1._questions) == 2
    assert len(ass2._questions) == 1

    assert ass1._questions[0]._text == "A1Q1"
    assert ass1._questions[1]._text == "A1Q2"
    assert ass2._questions[0]._text == "A2Q1"

    ass1.update(ass2)

    assert len(ass1._questions) == 3
    assert len(ass2._questions) == 1

    assert ass1._questions[0]._text == "A1Q1"
    assert ass1._questions[1]._text == "A1Q2"
    assert ass1._questions[2]._text == "A2Q1"
    assert ass2._questions[0]._text == "A2Q1"

    ass2.update(ass1)

    assert len(ass1._questions) == 3
    assert len(ass2._questions) == 4

    assert ass1._questions[0]._text == "A1Q1"
    assert ass1._questions[1]._text == "A1Q2"
    assert ass1._questions[2]._text == "A2Q1"

    assert ass2._questions[0]._text == "A2Q1"
    assert ass2._questions[1]._text == "A1Q1"
    assert ass2._questions[2]._text == "A1Q2"
    assert ass2._questions[3]._text == "A2Q1"
Пример #22
0
import os, sys
from pyAssignment.Assignment import Assignment
import pyAssignment.Assignment.Answers as Answer
from pyAssignment.Actions import BuildProblemSetAndBlackboardQuiz
import pint

units = pint.UnitRegistry()
Q_ = units.Quantity

ass = Assignment()
ass.meta.title = r'Simple Assignment'

with ass.add_question() as q:
    q.text = r'''Calculate the weight of a 20 kg mass.'''

    with q.add_question() as qq:
        qq.text = r'''What is the mass?'''
        with qq.add_answer(Answer.Numerical) as a:
            a.quantity = (Q_(20, 'kg') * Q_(9.8, 'm/s^2')).to('N')

basename = os.path.basename(__file__).replace(".py", "")
BuildProblemSetAndBlackboardQuiz(ass, basename)