Esempio n. 1
0
    def test_select_student(self, monkeypatch, selected_student_name,
                            selected_student_students_index):
        test_class_students = [
            Student(name='one'),
            Student(name='two'),
            Student(name='three')
        ]
        test_class = Class(name='some_class', students=test_class_students)
        test_student_options = {1: 'one', 2: 'two', 3: 'three'}

        def mocked_display_student_selection_menu(class_options):
            if class_options != test_student_options:
                raise ValueError  # Ensure called with correct arg.
            return None

        def mocked_take_student_selection(class_options):
            if class_options != test_student_options:
                raise ValueError  # Ensure called with correct arg.
            return selected_student_name

        monkeypatch.setattr(class_functions, 'display_student_selection_menu',
                            mocked_display_student_selection_menu)
        monkeypatch.setattr(class_functions, 'take_student_selection',
                            mocked_take_student_selection)

        assert select_student(
            test_class) == test_class_students[selected_student_students_index]
Esempio n. 2
0
    def test_create_chart(self, request, database_backend):
        """
        Verify API works.

        NB No verification in API test, as API for verifying does not exist.
        TODO: Verify saved chart contents when load/edit features added.
        """
        test_database = request.getfixturevalue(database_backend)
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                              ])
        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1]],
                100: [test_class.students[2]],
            }
        }

        assert test_database.create_chart(test_chart_data_dict) is None
Esempio n. 3
0
class TestClassStr:
    @pytest.mark.parametrize(
        'class_object,'
        'expected_str', [
            (Class(name='name_only_class'),
             f"Class {'name_only_class'}, with id=None, containing 0 students."
             ),
            (Class(class_id='some class id', name='name_only_class with id'),
             f"Class {'name_only_class with id'}, with id={'some class id'}, containing 0 students."
             ),
            (Class.from_dict(test_full_class_data_set['json_dict_rep']),
             f"Class {Class.from_dict(test_full_class_data_set['json_dict_rep']).name}, "
             f"with id={Class.from_dict(test_full_class_data_set['json_dict_rep']).id}, "
             f"containing {len(Class.from_dict(test_full_class_data_set['json_dict_rep']).students)} students, "
             f"with names: {', '.join([student.name for student in Class.from_dict(test_full_class_data_set['json_dict_rep']).students])}."
             ),
            (Class(class_id='some class id',
                   name='small_class with id',
                   students=[Student(name='one'),
                             Student(name='two')
                             ]), f"Class {'small_class with id'}, "
             f"with id={'some class id'}, "
             f"containing 2 students, "
             f"with names: one, two."),
        ])
    def test_str(self, class_object, expected_str):
        assert str(class_object) == expected_str
Esempio n. 4
0
class TestStudentRepr:
    @pytest.mark.parametrize('student_object',
                             [Student(name='I have no avatar!'),
                              Student(name='I have an avatar', avatar_id='my_avatar_id.png'),
                              ])
    def test_repr(self, student_object):
        assert repr(student_object) == (f'{student_object.__class__.__module__}'
                                        f'.{student_object.__class__.__name__}('
                                        f'id={student_object.id if student_object.id else None !r}, '
                                        f'name={student_object._name!r}, '
                                        f'avatar_id={student_object._avatar_id!r})')
Esempio n. 5
0
class TestStudentStr:
    @pytest.mark.parametrize(
        'student_object,'
        'expected_str',
        [(Student(name='I have no avatar!'),
          f"Student {'I have no avatar!'}, with no avatar, and id=None."),
         (Student(name='I have an avatar', avatar_id='path_to_my_avatar'),
          f"Student {'I have an avatar'}, with avatar {'path_to_my_avatar'}, and id=None."),
         (Student(student_id='some id', name='I have an id and avatar', avatar_id='path_to_my_avatar'),
          f"Student {'I have an id and avatar'}, with avatar {'path_to_my_avatar'}, and id=some id.")
         ])
    def test_str(self, student_object, expected_str, test_student_name_only, test_student_with_avatar):
        assert str(student_object) == expected_str
Esempio n. 6
0
class TestStudentJsonDict:
    @pytest.mark.parametrize(
        'student_object,output_json',
        [(Student('Sir Galahad'), {'name': 'Sir Galahad'}),  # name only
         (Student('Sir Lancelot: the Brave', avatar_id=None), {'name': 'Sir Lancelot: the Brave'}),
         (Student('Arther, King of the Britons', avatar_id='Holy_Grail.jpg'),
          {'name': 'Arther, King of the Britons', 'avatar_id': 'Holy_Grail.jpg'}
          ),
         (Student('Brian', avatar_id='a_naughty_boy.png'),
          {'name': 'Brian', 'avatar_id': 'a_naughty_boy.png'}),
         ])
    def test_json_dict(self, student_object, output_json):
        assert student_object.json_dict() == output_json
Esempio n. 7
0
    def test_score_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50.0: [test_class.students[1], test_class.students[3]],
                100: [test_class.students[2]],
            }
        }
        test_database.create_chart(test_chart_data_dict)

        scores_data = []
        score_id = 1  # initiate score id
        for score, students in test_chart_data_dict[
                'score-students_dict'].items():
            # NB One chart in db -> chart.id = 1]
            for student in students:
                scores_data += [(score_id, test_chart_data_dict['chart_id'],
                                 student.id, score)]
                score_id += 1

        # Verify reprs of scores in db:
        score_strings = [
            (
                f"<Score("
                f"id={score[0]}, "
                f"chart_id={score[1]}, "
                f"student_id={score[2]}, "
                f"value={float(score[3])}"  # Value is stored as a float.
                f")>") for score in scores_data
        ]
        with test_database.session_scope() as test_session:
            assert repr(test_session.query(
                test_database.Score).all()) == f"[{', '.join(score_strings)}]"
Esempio n. 8
0
    def test_create_chart(self, empty_sqlite_sqlalchemy_database):
        """
        Verify API works.

        NB No verification in API test, as API for verifying does not exist.
        TODO: Verify saved chart contents when load/edit features added.
        """
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])
        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1], test_class.students[3]],
                100: [test_class.students[2]],
            }
        }

        assert test_database.create_chart(test_chart_data_dict) is None

        # Verify chart data in db:
        # A load_chart method might go here.
        with test_database.session_scope() as test_session:
            assert test_session.execute(
                """SELECT chart.name FROM chart""").fetchone(
                )[0] == test_chart_data_dict['chart_name']

            scores_data = []
            for score, students in test_chart_data_dict[
                    'score-students_dict'].items():
                # NB One chart in db -> chart.id = 1
                scores_data += [(1, student.id, score) for student in students]
            assert test_session.execute(
                """SELECT chart_id, student_id, value FROM score""").fetchall(
                ) == scores_data
            # Ensure chart id added to chart_data_dict:
            assert test_chart_data_dict['chart_id'] == 1
Esempio n. 9
0
class TestStudentStr:
    @pytest.mark.parametrize(
        'student_object,'
        'expected_str', [
            (Student(name='I have no avatar!'),
             f"Student {'I have no avatar!'}, with no avatar."),
            (Student(name='I have an avatar',
                     avatar_filename='path_to_my_avatar'),
             f"Student {'I have an avatar'}, with avatar {'path_to_my_avatar'}."
             ),
        ])
    def test_str(self, student_object, expected_str, test_student_name_only,
                 test_student_with_avatar):
        assert str(student_object) == expected_str
Esempio n. 10
0
class TestStudentName:
    """
    Test Student name and path_safe_name properties.
    """

    def test_name_getter(self):
        test_name = 'Arthur, King of the Britons'
        assert Student(name='Arthur, King of the Britons').name == test_name

    def test_name_setter_unmocked(self, test_student_name_only):
        test_changed_name = 'Sir Lancelot: the not-so-brave'
        assert test_student_name_only.name != test_changed_name

        # Change name
        test_student_name_only.name = test_changed_name

        assert test_student_name_only.name == test_changed_name

    @pytest.mark.parametrize(
        'name_arg',
        [{'passing a dict': 'Some value'},  # dict
         ['passing', 'a', 'list'],  # list
         Student('Student object for name'),  # Student object
         ('passed', 'tuple',),  # tuple
         ])
    def test_non_str_name_raises_error(self, name_arg):
        """Test error is raised for each bad type, error msg contains type."""
        with pytest.raises(TypeError, match=str(type(name_arg))):
            Student(name=name_arg)
Esempio n. 11
0
    def test_instantiate_with_avatar_id(self):
        test_instantiate_student_with_avatar = Student(self.test_name,
                                                       avatar_id=self.test_avatar_id)

        assert test_instantiate_student_with_avatar.avatar_id == self.test_avatar_id

        assert isinstance(test_instantiate_student_with_avatar.avatar_id, str)
Esempio n. 12
0
    def load_class(self, class_id: Any) -> Class:
        """
        Load class from database using primary key class.id.

        :param class_id:
        :return: Class
        """
        with self.session_scope() as session:
            class_data = session.query(self.Class, self.Student).filter(
                self.Class.id == self.Student.class_id).filter(
                    self.Student.class_id == class_id).all()

            if class_data:
                class_id, class_name = class_data[0][0].id, class_data[0][
                    0].name
                students_list = [
                    Student(
                        student_id=student.id,
                        name=student.name,
                        class_id=class_data.id,
                        avatar_id=student.avatar_id,
                    ) for class_data, student in class_data
                ]
            else:  # Empty class
                empty_class = session.query(
                    self.Class).filter(self.Class.id == class_id).one()
                students_list = []
                class_id, class_name = empty_class.id, empty_class.name

            return Class(class_id=class_id,
                         name=class_name,
                         students=students_list)
Esempio n. 13
0
    def test_update_class(self, empty_json_database, test_full_class):
        test_json_database = empty_json_database
        test_class = Class(test_full_class.name, test_full_class.students)
        # create_class takes a NewClass object due to avatar moving machinery.
        test_class_new_class = NewClass(test_full_class.name,
                                        test_full_class.students)
        assert test_class.json_dict() == test_class_new_class.json_dict(
        )  # Ensure classes are the same.

        # Create class in database.
        test_json_database.create_class(
            NewClass(test_full_class.name, test_full_class.students))
        # Ensure test_class in database
        test_class.id = test_class.name

        # Loaded class will have ids:
        test_loaded_class = test_full_class.json_dict()
        for student in test_loaded_class['students']:
            student['id'] = student['name']
        assert test_json_database.load_class(
            test_class.name).json_dict() == test_loaded_class

        # Change class by adding student, update database:
        new_student = Student(name='new student')
        assert new_student not in test_class and new_student.name not in test_class  # Confirm student not in class.
        test_class.add_student(new_student)

        assert test_json_database.update_class(test_class) is None
        # Look up name because new_student object itself is not in the loaded class object.
        assert new_student.name in test_json_database.load_class(
            test_class.name)
    def test_take_class_data_input(self, monkeypatch):
        test_class_name = 'my test class'
        test_take_student_name_input_returns = ['test_student', 'END']
        take_student_avatar_return = 'my_student_avatar.jpg'
        test_class = Class(
            name=test_class_name,
            students=[
                Student(name=test_take_student_name_input_returns[0],
                        avatar_id=take_student_avatar_return),
            ])
        test_take_student_name_input_return = (
            name for name in test_take_student_name_input_returns)

        def mocked_take_student_name_input(new_class):
            if new_class.name != test_class_name:
                raise ValueError
            return next(test_take_student_name_input_return)

        def mocked_take_student_avatar(new_class, student_name):
            if (new_class.name, student_name) != (
                    test_class_name, test_take_student_name_input_returns[0]):
                raise ValueError
            return take_student_avatar_return

        monkeypatch.setattr(class_functions, 'take_student_avatar',
                            mocked_take_student_avatar)
        monkeypatch.setattr(class_functions, 'take_student_name_input',
                            mocked_take_student_name_input)

        assert take_class_data_input(
            test_class_name).json_dict() == test_class.json_dict()
Esempio n. 15
0
    def setUp(self):
        self.no_student_name = ''
        self.blank_student_name = '_'
        self.preexisting_student_name = 'this student already exists in the class'
        self.valid_new_student_name = 'this is a valid student_name'

        self.invalid_student_name_response = 'Please enter a valid student name.'
        self.preexisting_student_response = 'This student is already a member of the class.'

        self.test_case_inputs = [
            self.no_student_name,
            self.blank_student_name,
            self.preexisting_student_name,
            self.valid_new_student_name,
        ]

        self.printed_feedback = [
            self.invalid_student_name_response,
            self.invalid_student_name_response,
            self.preexisting_student_response,
        ]

        self.test_class = Class(
            name='my_test_class',
            students=[Student(name=self.preexisting_student_name)])
Esempio n. 16
0
    def test_class_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)

        # Verify repr of (only) class in db:
        with test_database.session_scope() as test_session:
            assert repr(test_session.query(test_database.Class).one(
            )) == f"<Class(id={test_class.id}, name={test_class.name})>"
Esempio n. 17
0
    def test_get_avatar_path(self, tmpdir, request, database_backend,
                             avatar_provided):
        """"""
        test_database = request.getfixturevalue(database_backend)

        # Create avatar:
        test_avatar_data = b'some binary data'
        test_avatar_path = Path(tmpdir, 'test_avatar.png')
        test_avatar_path.write_bytes(test_avatar_data)
        # Add avatar to db:
        test_class = NewClass(
            name='test class',
            students=[
                Student(
                    name='test_student',
                    avatar_id=(test_avatar_path if avatar_provided else None),
                )
            ])
        test_database.create_class(test_class)

        # Find avatar_id, load class to verify:
        classes = test_database.get_classes()
        test_class_id = classes[0].id  # As the only class will be first item.
        loaded_test_class = test_database.load_class(test_class_id)
        test_avatar_id = loaded_test_class.students[0].avatar_id

        # Path may be different/random - test data:
        assert test_database.get_avatar_path(test_avatar_id).read_bytes() == (
            test_avatar_data if avatar_provided else
            test_database.default_avatar_path.read_bytes())
Esempio n. 18
0
    def test_instantiate_with_avatar_filename(self):
        test_instantiate_student_with_avatar = Student(
            self.test_name, avatar_filename=self.test_avatar_filename)

        assert test_instantiate_student_with_avatar.avatar_filename == self.test_avatar_filename

        assert isinstance(test_instantiate_student_with_avatar.avatar_filename,
                          str)
Esempio n. 19
0
    def test_chart_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)

        test_chart_data_dict = {
            'class_id': test_class.id,
            'class_name': test_class.name,
            'chart_name': 'test_chart_name',
            'chart_default_filename': 'test_default_chart_filename',
            'chart_params': {
                'some': 'params'
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1], test_class.students[3]],
                100: [test_class.students[2]],
            }
        }
        test_database.create_chart(test_chart_data_dict)

        # Create fake plot/image
        mock_plt = plt.figure(figsize=(19.20, 10.80))
        test_image = io.BytesIO()
        mock_plt.savefig(test_image, format='png', dpi=300)
        test_image.seek(0)  # Return pointer to start of binary stream.

        test_database.save_chart_image(test_chart_data_dict, mock_plt)

        # Verify repr of (only) chart in db:
        with test_database.session_scope() as test_session:
            assert repr(test_session.query(test_database.Chart).one()) == (
                f"<Chart("
                f"id={test_chart_data_dict['chart_id']}, "
                f"name={test_chart_data_dict['chart_name']}, "
                f"image={test_image.read1()}, "
                f"date=None"  # Not implemented yet.
                f")>")
Esempio n. 20
0
def transform_data(class_name: str, old_class_data: dict):
    """
    Take class name (eg from old style cld filename), and loaded json dict,
    transform into a new-style Class object.

    :param class_name: str
    :param old_class_data: dict
    :return: Class object
    """
    new_students = []
    for student_name in old_class_data:
        if old_class_data[student_name][0] is None:
            new_students.append(Student(name=student_name))
        else:
            new_students.append(
                Student(name=student_name,
                        avatar_filename=old_class_data[student_name][0]), )
    new_class = Class(name=class_name, students=new_students)
    return new_class
Esempio n. 21
0
    def test_store_students_as_student_names(self, empty_json_database):
        test_json_database = empty_json_database
        test_json_database.default_avatar_path = Path('default/path')

        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                              ])

        test_data_dict = {
            'class_name': "test_class_name",
            'chart_name': "test_chart_name",
            'chart_default_filename': "test_chart_default_filename",
            'chart_params': {
                "some": "chart",
                "default": "params"
            },
            'score-students_dict': {
                0: [test_class.students[0]],
                50: [test_class.students[1]],
                100: [test_class.students[2]],
            },
        }
        test_returned_sanitised_data_dict = {
            'class_name': "test_class_name",
            'chart_name': "test_chart_name",
            'chart_default_filename': "test_chart_default_filename",
            'chart_params': {
                "some": "chart",
                "default": "params"
            },
            'score-students_dict': {
                0: [test_class.students[0].name],
                50: [test_class.students[1].name],
                100: [test_class.students[2].name],
            },
        }

        assert test_json_database._store_students_as_student_names(
            test_data_dict) == test_returned_sanitised_data_dict
Esempio n. 22
0
    def setUp(self) -> None:
        self.test_class_name = 'my test class'
        self.test_student_name_input_returns = ['test_student', 'END']
        self.take_student_avatar_return = 'my_student_avatar.jpg'

        self.test_class = Class(
            name=self.test_class_name,
            students=[
                Student(name=self.test_student_name_input_returns[0],
                        avatar_filename=self.take_student_avatar_return),
            ])
Esempio n. 23
0
    def test_from_dict(self, output_json_dict):
        student_object = Student.from_dict(output_json_dict)
        assert isinstance(student_object, Student)
        # Verify instantiated object is equivalent by reserialising:
        assert student_object.json_dict() == output_json_dict

        # Test attributes
        assert student_object.name == output_json_dict['name']
        if output_json_dict.get('avatar_filename') is not None:
            assert str(student_object.avatar_filename
                       ) == output_json_dict['avatar_filename']
Esempio n. 24
0
def test_full_class() -> Class:
    test_full_class = Class(
        class_id=test_full_class_data_set['json_dict_rep']['id'],
        name=test_full_class_data_set['json_dict_rep']['name'])
    for student in test_full_class_data_set['json_dict_rep']['students']:
        test_full_class.add_student(Student(**student))

    test_full_class.json_str_rep = test_full_class_data_set['json_str_rep']
    test_full_class.json_dict_rep = test_full_class_data_set['json_dict_rep']

    return test_full_class
Esempio n. 25
0
def test_full_new_class():
    """Returns empty NewClass instantiated with students."""
    test_full_new_class = NewClass(
        test_full_class_data_set['json_dict_rep']['name'])
    for student in test_full_class_data_set['json_dict_rep']['students']:
        test_full_new_class.add_student(Student(**student))

    test_full_new_class.json_str_rep = test_full_class_data_set['json_str_rep']
    test_full_new_class.json_dict_rep = test_full_class_data_set[
        'json_dict_rep']

    return test_full_new_class
Esempio n. 26
0
    def from_dict(cls, class_dict: dict):
        """
        Instantiate Class object from JSON-serialisable dict.

        :param class_dict: dict
        :return: Class object
        """
        _name = class_dict['name']
        _students = [
            Student.from_dict(student) for student in class_dict['students']
        ]
        return Class(_name, _students)
Esempio n. 27
0
    def test_student_table_repr(self, empty_sqlite_sqlalchemy_database):
        test_database = empty_sqlite_sqlalchemy_database
        test_class = NewClass(name='test_class',
                              students=[
                                  Student(name='bad student'),
                                  Student(name='mediocre student'),
                                  Student(name='excellent student'),
                                  Student(name='another mediocre student'),
                              ])

        test_database.create_class(test_class)
        # Verify reprs of students in db:
        student_strings = [(f"<Student("
                            f"id={student.id}, "
                            f"name={student.name}, "
                            f"class_id={test_class.id}, "
                            f"avatar_id={student.avatar_id}"
                            f")>") for student in test_class.students]

        with test_database.session_scope() as test_session:
            assert repr(test_session.query(test_database.Student).all()
                        ) == f"[{', '.join(student_strings)}]"
Esempio n. 28
0
    def test__contains__identical_but_not_actual_student_obj_in_class(
            self, test_student_name_only, test_class_name_only):
        """
        Test identical student object in class.
        Should return False, since the specific object is not in the class.
        eg id(test_student) != id(test_class_name_only.students[0])
        """
        assert test_class_name_only.students == []  # No students in class
        name, avatar_id = 'test_student', 'test_student_avatar'
        test_student = Student(name=name, avatar_id=avatar_id)
        test_class_name_only.add_student(name=name, avatar_id=avatar_id)

        assert test_student not in test_class_name_only
Esempio n. 29
0
    def from_dict(cls, class_dict: dict) -> Union['Class', 'NewClass']:
        """
        Instantiate Class object from JSON-serialisable dict.

        :param class_dict: dict
        :return: Class object
        """
        _id = class_dict.get('id')  # Class may not have id if not in db.
        _name = class_dict['name']
        _students = [
            Student.from_dict(student) for student in class_dict['students']
        ]
        return cls(class_id=_id, name=_name, students=_students)
Esempio n. 30
0
    def test_save_chart_image(self, tmpdir, empty_sqlite_sqlalchemy_database):
        """Save image and verify data."""
        test_database = empty_sqlite_sqlalchemy_database

        test_data_dict = {
            'class_id': 314,
            'class_name': "test_class_name",
            'chart_name': "test_chart_name",
            'chart_default_filename': "test_chart_default_filename",
            'chart_params': {
                "some": "chart",
                "default": "params"
            },
            'score-students_dict': {
                0: [Student(student_id=42, name="Brian")],
            },
        }
        # Create chart in db:
        test_database.create_chart(test_data_dict)
        # Create fake plot/image
        mock_plt = plt.figure(figsize=(19.20, 10.80))
        test_image = io.BytesIO()
        mock_plt.savefig(test_image, format='png', dpi=300)
        test_image.seek(0)  # Return pointer to start of binary stream.

        save_chart_path = test_database.save_chart_image(
            test_data_dict, mock_plt)
        # Path exists and image at path/db is expected data:
        assert save_chart_path.exists()
        assert save_chart_path.read_bytes() == test_image.read1(
        )  # size arg can be omitted on 3.7+
        test_image.seek(
            0)  # Return pointer to start of test_image binary stream.

        # Compare db image
        with test_database.session_scope() as test_session:
            db_image = test_session.query(test_database.Chart).filter_by(
                id=test_data_dict['chart_id']).first().image
        # Images must both be saved as '.png' for comparison.
        test_image_path = Path(tmpdir, 'test_image.png')
        test_image_path.write_bytes(test_image.read1())
        test_image.seek(0)
        db_image_path = Path(tmpdir, 'db_image.png')
        db_image_path.write_bytes(db_image)
        try:
            assert not compare_images(
                db_image_path, test_image_path,
                0.0001)  # Returns str on fail, None on success.
        except MemoryError:
            pass  # fails for 32 bit python on Windows.
        assert save_chart_path.read_bytes() == test_image.read()