Skip to content

Commit

Permalink
Merge pull request #143 from toonarmycaptain/development
Browse files Browse the repository at this point in the history
  • Loading branch information
toonarmycaptain authored Feb 6, 2019
2 parents 1deabb9 + a26d3eb commit f4a45c6
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 31 deletions.
4 changes: 2 additions & 2 deletions .bettercodehub.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ languages:
- name: python
production:
exclude:
- /test_suite/.*
- .*/test_suite/.*

test:
include:
- /test_suite/.*
- .*/test_suite/.*

component_depth: 2
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [0.3.1-alpha]
### Added
- Improved test coverage.
- Add load_chart_data, load_json_from_file
- Add .bettercodehub.yml - prevent failed PR checks because of test code.
### Changed
- Fix bug in save_as_dialogue that failed with TypeError when called without filetypes parameter or with default filetypes=None.
- Fix circleci not storing test metadata.
- Refactor save_as_dialogue to prevent TypeError.
- Refactor load_class_data using load_from_json_file.

### Fixed
- Fix bug where avatar for student with score of 0 not added to student_scores.
- Fix bug in save_as_dialogue that failed with TypeError when called without filetypes parameter or with default filetypes=None.
- Fix circleci not storing test metadata.

## [0.3.0-alpha] - 2019-01-23
### Added
Expand Down
45 changes: 30 additions & 15 deletions dionysus_app/UI_menus/chart_generator/take_chart_data_UI.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,40 @@

# score entry:

from dionysus_app.class_functions import load_class_data, get_avatar_path
from dionysus_app.class_functions import get_avatar_path
from dionysus_app.data_folder import DataFolder
from dionysus_app.UI_menus.UI_functions import input_is_essentially_blank


CLASSLIST_DATA_PATH = DataFolder.generate_rel_path(DataFolder.CLASS_DATA.value)


def take_score_data(class_name: str):
def take_score_data(class_name: str, class_data_dict: dict):
"""
Prints score taking instructions, calls take_student_scores.
Prints a newline after completion for readability.
Returns dict with scores as keys, lists of Path objects as
values. eg student_scores = {33: [Path_obj1, Path_obj2, Path_obj3,
17: [Path_obj1, Path_obj2, Path_obj3]
}
:param class_name: str
:param class_data_dict: dict
:return: dict
"""
print(f"\nEnter student scores for {class_name}: \n"
f"Type score for each student, or '_' to exclude student, and press enter.")

student_scores = take_student_scores(class_name, class_data_dict)

# Newline between last score and 'Please enter a chart name/title: '
print('\n')

return student_scores


def take_student_scores(class_name: str, class_data_dict: dict):
"""
UI function presenting student names from supplied class one at a
time and taking a score for each.
Expand All @@ -27,31 +52,21 @@ def take_score_data(class_name: str):
17: [Path_obj1, Path_obj2, Path_obj3]
}
:param class_name: str
:param class_data_dict: dict
:return: dict
"""

class_data_dict = load_class_data(class_name)

student_scores = {}

print(f"\nEnter student scores for {class_name}: \n"
f"Type score for each student, or '_' to exclude student, and press enter.")

for student_name in list(class_data_dict.keys()):

student_avatar_filename = class_data_dict[student_name][0]
avatar_path = get_avatar_path(class_name, student_avatar_filename)

student_score = take_score_entry(student_name)
# add avatar to list of avatars for score
if student_score:
if student_score or student_score is 0:
student_scores[student_score] = student_scores.get(student_score, []) + [avatar_path]

# Newline between last score and 'Please enter a chart name/title: '
print('\n')

return student_scores


Expand All @@ -61,7 +76,7 @@ def take_score_entry(student_name: str, minimum: int=0, maximum: int=100):
:param student_name: str
:param minimum: int, default=0
:param maximum: int, default=100
:return: float
:return: float or None
"""
while True:
score = input(f'{student_name}: ')
Expand Down
8 changes: 6 additions & 2 deletions dionysus_app/chart_generator/create_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from dionysus_app.chart_generator.generate_image import generate_chart_image
from dionysus_app.chart_generator.process_chart_data import DEFAULT_CHART_PARAMS
from dionysus_app.class_functions import select_classlist
from dionysus_app.class_functions import select_classlist, load_class_data
from dionysus_app.data_folder import CHART_DATA_FILE_TYPE, DataFolder
from dionysus_app.file_functions import convert_to_json, copy_file
from dionysus_app.UI_menus.chart_generator.create_chart_UI import (display_image_save_as,
Expand Down Expand Up @@ -66,6 +66,8 @@ def assemble_chart_data():
"""
Collect data/user input for new chart.
Get classname from user, load class data, take chart data from user.
Return values for chart_data_dict assembly:
class_name: str
chart_name: str
Expand All @@ -78,7 +80,9 @@ def assemble_chart_data():

class_name = select_classlist() # TODO: warn for empty classlist

student_scores: dict = take_score_data(class_name)
class_data_dict = load_class_data(class_name)

student_scores: dict = take_score_data(class_name, class_data_dict)

chart_name = take_chart_name()

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
matplotlib==3.0.2
Pillow==5.4.1
setuptools==40.6.3
setuptools==40.7.2
2 changes: 1 addition & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pexpect==4.6.0
pytest==4.1.0
pytest==4.2.0

# Running tests on Travis
codacy-coverage==1.3.11
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages

setup(name='dionysus_app',
version='0.3.0-alpha',
version='0.3.1-alpha',
description='Avatar chart generator',
author='David Antonini',
author_email='toonarmycaptain@hotmail.com',
Expand Down
81 changes: 76 additions & 5 deletions test_suite/UI_menus_tests/test_take_chart_data_UI.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,79 @@
# import signal
# from unittest import TestCase
#
# from dionysus_app.chart_generator.take_graph_data import take_score_entry
# import pexpect.run
from unittest import TestCase, mock
from unittest.mock import patch

from dionysus_app.UI_menus.chart_generator.take_chart_data_UI import (take_score_data,
take_student_scores,
)
from test_suite.testing_class_data import testing_class_data_set as test_class_data


class TestTakeScoreData(TestCase):
def setUp(self):
self.test_classname = 'the knights who say ni'
self.test_class_data_dict = test_class_data['loaded_dict']

self.score_entry_instruction = (f"\nEnter student scores for {self.test_classname}: \n"
f"Type score for each student, or '_' to exclude student, and press enter.")
self.newline_after_entry = '\n'
self.print_calls = [self.score_entry_instruction, self.newline_after_entry]

self.mock_score_avatar_dict = {'scores': 'list of avatars'}

@patch('dionysus_app.UI_menus.chart_generator.take_chart_data_UI.take_student_scores')
@patch('dionysus_app.UI_menus.chart_generator.take_chart_data_UI.print')
def test_take_score_data(self, mocked_print, mocked_take_student_scores):
mocked_take_student_scores.return_value = self.mock_score_avatar_dict

assert take_score_data(self.test_classname,
self.test_class_data_dict) == self.mock_score_avatar_dict

assert mocked_print.call_args_list == [mock.call(print_call) for print_call in self.print_calls]
mocked_take_student_scores.called_once_with(self.test_classname, self.test_class_data_dict)


class TestTakeStudentScores(TestCase):
mock_DEFAULT_AVATAR_PATH = 'mocked_default_avatar_path'

def setUp(self):
self.mock_DEFAULT_AVATAR_PATH = 'mocked_default_avatar_path'

self.test_classname = 'the knights who say ni'
self.test_class_data_dict = test_class_data['loaded_dict']

# NB If data other than avatar in dict values, this test implementation may need to change.
self.mocked_get_avatar_path_return_values = [f'path to {avatar[0]}' if avatar[0] is not None
else self.mock_DEFAULT_AVATAR_PATH
for avatar in test_class_data['loaded_dict'].values()]

# Gives no score to one student with and without an avatar.
self.mocked_take_score_entry_return_values = [0, 1, 3, None, 50, 99, 100, 1, 2, 3, 4, None, 6, 7, 8]
self.test_take_student_scores_return_value = {0: ['path to Cali_avatar.png'],
1: [self.mock_DEFAULT_AVATAR_PATH, self.mock_DEFAULT_AVATAR_PATH],
3: [self.mock_DEFAULT_AVATAR_PATH, self.mock_DEFAULT_AVATAR_PATH],
# None: ['Zach_avatar.png', None], # No score not returned.
50: [self.mock_DEFAULT_AVATAR_PATH],
99: [self.mock_DEFAULT_AVATAR_PATH],
100: [self.mock_DEFAULT_AVATAR_PATH],
2: ['path to Ashley_avatar.png'],
4: [self.mock_DEFAULT_AVATAR_PATH],
6: ['path to Danielle.png'],
7: [self.mock_DEFAULT_AVATAR_PATH],
8: [self.mock_DEFAULT_AVATAR_PATH]
}

@patch('dionysus_app.UI_menus.chart_generator.take_chart_data_UI.get_avatar_path')
@patch('dionysus_app.UI_menus.chart_generator.take_chart_data_UI.take_score_entry')
def test_take_student_scores(self, mocked_take_score_entry, mocked_get_avatar_path):
mocked_take_score_entry.side_effect = self.mocked_take_score_entry_return_values
mocked_get_avatar_path.side_effect = self.mocked_get_avatar_path_return_values

assert take_student_scores(self.test_classname,
self.test_class_data_dict) == self.test_take_student_scores_return_value

mocked_take_score_entry.call_args_list = [mock.call(student_name) for student_name in self.test_class_data_dict]
mocked_get_avatar_path.call_args_list = [mock.call(self.test_classname,
self.test_class_data_dict[student_name][0])
for student_name in self.test_class_data_dict]


def test_take_score_entry():
Expand Down

0 comments on commit f4a45c6

Please sign in to comment.