Skip to content

Commit

Permalink
add tests and some clean up (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
januschung authored Oct 18, 2020
1 parent 719ef7d commit 5d5190a
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 22 deletions.
41 changes: 30 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,31 @@ pip install -r requirements.txt
## How to Use
1. Generate the worksheet in pdf format with the following command:
```
python3 run.py --type [+|-|x|mix] --digits [1|2|3]
python3 run.py --type [+|-|x|mix] --digits [1|2|3] [-q|--question_count] [int] --output [custom-name.pdf]
```
For addition only worksheet, use the following command:
2. Print out the generated file `worksheet.pdf`

For addition only worksheet:
```
python3 run.py --type +
```
For calculation up to 3 digit range, use the following command:
For calculation up to 3 digits range:
```
python3 run.py --digits 3
```

2. Print out the generated file `worksheet.pdf`

For custom filename generated file, use the following command:
For generating different number of question, eg 100 (default is 80):
```
python3 run.py -q 100
```
or
```
python3 run.py --questino_count 100
```
For custom output filename (default is worksheet.pdf):
```
python3 run.py --output custom-name.pdf
```

3. You can generate more questions by editing the parameter `total_question` under `run.py`

## Sample
[sample worksheet](sample-worksheet.pdf)

Expand All @@ -65,8 +70,22 @@ I appreciate all suggestions or PRs which will help kids learn math better. Feel

## TODO
1. Add date/name/score section to the front page
2. Add support for Division
3. Pass in the number of questions with a flag (currently the default is 80)
2. Add support for division in long division format

## Special Thanks
My long time friend San for the inspiration of this project and lovely sons Tim and Hin. Thanks [thedanimal](https://github.com/thedanimal) for reviewing this README and adding new features.

Also, thank you for the love and support form the [Reddit Python community](https://www.reddit.com/r/Python/comments/ja5y2m/made_this_tool_with_python_and_my_son_now_hates_me/). You guys are amazing and are helping me to make this project better.

## Successful Story
Thanks [k1m0ch1](https://github.com/k1m0ch1) for sharing the heartwarming story:
>...I made this card for my kid, and then the teacher asks me if I can make some for the kids, well its generated anyway and very helpful, and the next day he asks me to make for a whole class, and next day he wants me to make for a whole school, and a weeks later other schools want me to help to make for a whole school.
more than 1000 generated file, with a custom filename for every kid and sent to the email
I'm doing it for free, while you made this free, love it <3

## Links
Thank you for your coverage.

[PyCoder's Weekly Issue #442](https://pycoders.com/issues/442)

[PyCoder's Weekly's tweet](https://twitter.com/pycoders/status/1316379986417381376)
20 changes: 9 additions & 11 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@

import argparse
import random
from typing import List, Tuple

from fpdf import FPDF
from typing import List, Tuple

QuestionInfo = Tuple[int, str, int, int]

Expand Down Expand Up @@ -62,10 +61,9 @@ def get_list_of_questions(self, question_count: int) -> List[QuestionInfo]:
allowing duplicates if needed (e.g. asking for 80 addition problems with max size 3 requires duplication)
:return: list of questions
"""
self.total_question = question_count
questions = []
duplicates = 0
while len(questions) < self.total_question:
while len(questions) < question_count:
new_question = self.generate_question()
if new_question not in questions or duplicates >= 10:
questions.append(new_question)
Expand All @@ -76,7 +74,7 @@ def get_list_of_questions(self, question_count: int) -> List[QuestionInfo]:
def make_question_page(self, data: List[QuestionInfo]):
"""Prepare a single page of questions"""
page_area = self.num_x_cell * self.num_y_cell
problems_per_page = self.split_arr(self.total_question, page_area)
problems_per_page = self.split_arr(self.question_count, page_area)
total_pages = len(problems_per_page)
for page in range(total_pages):
self.pdf.add_page(orientation='L')
Expand All @@ -87,7 +85,7 @@ def make_question_page(self, data: List[QuestionInfo]):
total_rows = len(problems_per_row)
self.print_question_row(data, page * page_area, problems_per_row[0])
for row in range(1, total_rows):
page_row = row * (self.num_x_cell)
page_row = row * self.num_x_cell
self.print_horizontal_separator()
self.print_question_row(data, page * page_area + page_row, problems_per_row[row])

Expand Down Expand Up @@ -145,7 +143,7 @@ def print_horizontal_separator(self):
self.pdf.ln()

def print_question_row(self, data, offset, num_problems):
# Print a single row of questions (total question in a row is set by num_x_cell)
"""Print a single row of questions (total question in a row is set by num_x_cell)"""
for x in range(0, num_problems):
self.print_top_row(str(x + 1 + offset))
self.print_edge_vertical_separator()
Expand Down Expand Up @@ -199,8 +197,8 @@ def main(type_, size, question_count, filename):
choices=['+', '-', 'x', 'mix'],
help='type of calculation: '
'+: Addition; '
'-: Substration; '
'x: Multipication; '
'-: Subtraction; '
'x: Multiplication; '
'mix: Mixed; '
'(default: +)',
)
Expand All @@ -214,7 +212,7 @@ def main(type_, size, question_count, filename):
'-q',
'--question_count',
type=int,
default='80', # Must be a multiple of 40
default='80', # Must be a multiple of 40
help='total number of questions' '(default: 80)',
)
parser.add_argument('--output', metavar='filename.pdf', default='worksheet.pdf',
Expand All @@ -229,5 +227,5 @@ def main(type_, size, question_count, filename):
size_ = 999
else:
size_ = 99

main(args.type, size_, args.question_count, args.output)
5 changes: 5 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[flake8]
exclude = venv/**,./.git
max-line-length = 150
max-complexity = 30
extend-ignore = W605, E722, F821
45 changes: 45 additions & 0 deletions tests/test_math_worksheet_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import math
import unittest

from run import MathWorksheetGenerator as Mg


class TestStringMethods(unittest.TestCase):

def test_generate_question_addition(self):
g = Mg(type_='+', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] + question[2], question[3])

def test_generate_question_subtraction(self):
g = Mg(type_='-', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] - question[2], question[3])
# answer should be greater than 0
self.assertGreaterEqual(question[3], 0)

def test_generate_question_multiplication(self):
g = Mg(type_='x', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] * question[2], question[3])

def test_generate_question_unsupport_type_(self):
g = Mg(type_='p', max_number=9, question_count=10)
with self.assertRaisesRegex(RuntimeError, expected_regex=r"Question main_type p not supported"):
g.generate_question()

def test_get_list_of_questions_correct_count(self):
g = Mg(type_='x', max_number=9, question_count=10)
question_list = g.get_list_of_questions(g.question_count)
self.assertEqual(len(question_list), g.question_count)

def test_make_question_page_page_count(self):
g = Mg(type_='x', max_number=9, question_count=2)
question_info = [[1, '+', 1, 2]] * g.question_count
g.make_question_page(question_info)
total_page = math.ceil(g.question_count / (g.num_x_cell * g.num_y_cell))
self.assertEqual(total_page, g.pdf.page)


if __name__ == '__main__':
unittest.main()

0 comments on commit 5d5190a

Please sign in to comment.