1236b842bfbeacc2cf30d84fff14b8948ebb7454
1 # Copyright (C) 2012 W. Trevor King <wking@tremily.us>
2 #
3 # This file is part of pygrader.
4 #
5 # pygrader is free software: you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 3 of the License, or (at your option) any later
8 # version.
9 #
10 # pygrader is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along with
17 import math as _math  # for numpy workarounds and testing
18 import sys as _sys
20 _numpy_import_error = None
21 try:
22     import numpy as _numpy
23 except ImportError as e:
24     _numpy = None
25     _numpy_import_error = e
27 from . import LOG as _LOG
28 from .color import standard_colors as _standard_colors
29 from .color import write_color as _write_color
32 def _mean(iterable):  # missing-numpy workaround
33     """Return the mean of a list of items.
35     >>> print(_mean([0,1,2,3,4,5,6]))
36     3.0
37     """
38     length = len(iterable)
39     return sum(iterable) / float(length)
41 def _std(iterable):  # missing-numpy workaround
42     """Return the standard deviation of a list of items.
44     >>> print(_std([0,1,2,3,4,5,6]))
45     2.0
46     """
47     length = len(iterable)
48     m = _mean(iterable)
49     return _math.sqrt(sum((x-m)**2 for x in iterable) / length)
51 if _numpy is None:
52     _statistics_container = list
53 else:
54     _statistics_container = _numpy.array
56 def _statistic(iterable, statistic):
57     """Calculate statistics on an list of numbers
58     """
59     global _numpy_import_error
60     if _numpy_import_error:
61         assert _numpy_import_error is not None
62         _LOG.warning('error importing numpy, falling back to workarounds')
63         _LOG.warning(str(_numpy_import_error))
64         _numpy_import_error = None
65     if statistic == 'Mean':
66         if _numpy is None:  # work around missing numpy
67             return _mean(iterable)
68         else:
69             return gs.mean()
70     elif statistic == 'Std. Dev.':
71         if _numpy is None:  # work around missing numpy
72             sval = _std(iterable)
73         else:
74             return gs.std()
75     else:
76         raise NotImplementedError(statistic)
78 def tabulate(course, statistics=False, stream=None, use_color=None, **kwargs):
79     """Return a table of student's grades to date
80     """
81     if stream is None:
82         stream = _sys.stdout
84     colors = [highlight, lowlight]
85     assignments = sorted(set(
88     _write_color(string='Student', color=colors, stream=stream)
89     for i,assignment in enumerate(assignments):
90         string = '\t{}'.format(assignment.name)
91         color = colors[(i+1)%len(colors)]
92         _write_color(string=string, color=color, stream=stream)
93     if len(assignments) == len(course.assignments):
94         string = '\t{}'.format('Total')
95         color = colors[(i+2)%len(colors)]
96         _write_color(string=string, color=color, stream=stream)
97     _write_color(string='\n', stream=stream)
98     for student in students:
99         _write_color(string=student.name, color=colors, stream=stream)
100         for i,assignment in enumerate(assignments):
101             try:
104             except ValueError:
105                 gs = '-'
106             string = '\t{}'.format(gs)
107             color = colors[(i+1)%len(colors)]
108             _write_color(string=string, color=color, stream=stream)
109         if len(assignments) == len(course.assignments):
110             string = '\t{}'.format(course.total(student))
111             color = colors[(i+2)%len(colors)]
112             _write_color(string=string, color=color, stream=stream)
113         _write_color(string='\n', stream=stream)
114     if statistics:
115         _write_color(string='--\n', stream=stream)
116         for stat in ['Mean', 'Std. Dev.']:
117             _write_color(string=stat, color=colors, stream=stream)
118             for i,assignment in enumerate(assignments):
119                 color = colors[(i+1)%len(colors)]