4
"""Classes and functions for dealing with video statistics.
6
Future interface ideas:
8
* Display certain records, or a range of records (records 1-10; last 15 records;
9
records with a certain field (or any field) matching given text/regexp
10
* Display formatted output of all records, or a selection of records,
11
with control over which fields are displayed
19
# Order of fields in stats.tovid
23
'length', # a.k.a. CUR_LENGTH
32
'encoding_time', # SCRIPT_TOT_TIME
47
# Integer numeric fields
63
"""A list of statistics that may be queried with a simple database-like
65
def __init__(self, records=None, filename=''):
66
"""Create a Statlist, using the given list of records, or by reading
67
from the given filename (CSV text).
69
# Use provided records, if any
71
self.records = copy(records)
72
# Otherwise, read from any provided filename
75
if filename is not '':
76
self.read_csv(filename)
78
def read_csv(self, filename):
79
"""Import stats from a CSV (comma-delimited quoted text) file."""
81
statfile = open(filename, 'r')
82
csv_reader = csv.DictReader(statfile, FIELDS, skipinitialspace=True)
83
for line in csv_reader:
84
# Convert some string and numeric fields
85
line['format'] = str.lower("%s" % line['format'])
86
line['tvsys'] = str.lower("%s" % line['tvsys'])
87
for field in int_fields:
89
num = int("%s" % line[field])
90
except ValueError, TypeError:
93
self.records.append(line)
96
print "Read %s lines from %s" % (len(self.records), filename)
98
def unique(self, field):
99
"""Return a list of unique values of the given field."""
101
for record in self.records:
102
if record[field] not in unique_values:
103
unique_values.append(record[field])
106
def count_unique(self, field):
107
"""Count the occurrences of each unique value of the given field.
108
Return a dictionary of unique values and the number of occurrences
111
# Go through all records and total up occurrences of each value
112
for record in self.records:
113
value = record[field]
114
if value is None or value == '':
116
elif value not in counts:
122
def average(self, attribute):
123
"""Calculate the average value for a given numeric VidStat attribute.
124
For example, average('bitrate') returns the average overall bitrate of
125
all videos in the list."""
126
# Error if attribute is non-numeric
127
if attribute not in int_fields:
128
print "Can't average %s: not defined as a numeric field"
132
for record in self.records:
133
# Only append non-zero values
134
if record[attribute] != 0:
135
values.append(record[attribute])
137
return float(sum(values) / len(values))
141
def average_by(self, attribute, by_attribute):
142
"""Return a dictionary of averages of an attribute, indexed by another
143
attribute. For example, average_by('bitrate', 'format') returns average
144
bitrates for each format."""
145
# Error if attribute is non-numeric
146
if attribute not in int_fields:
147
print "Can't average %s: not defined as a numeric field"
150
values_by = self.list_by(attribute, by_attribute)
151
# Calculate averages for each value-list
153
if len(values_by) > 0:
154
for key, samples in values_by.iteritems():
156
averages[key] = float(sum(samples) / len(samples))
157
except ZeroDivisionError:
161
def list_by(self, attribute, by_attribute, sort_lists=False):
162
"""Return a dictionary of lists of values of the given attribute,
163
indexed by another attribute. If sort_lists is True, sort all lists."""
164
# Create a dictionary of value-lists, indexed by by_attribute
166
for record in self.records:
167
byval = record[by_attribute]
168
if not values_by.has_key(byval):
169
values_by[byval] = []
170
# Only include non-zero values
171
if record[attribute] != 0:
172
values_by[byval].append(record[attribute])
174
for index in values_by.iterkeys():
175
values_by[index].sort()
178
def get_matching(self, attribute, value):
179
"""Return a list of records where the given attribute equals the given
180
value. Records are field-indexed dictionaries of values.
182
# List of matching records
184
for record in self.records:
185
if record[attribute] == value:
186
matches.append(record)
189
def length(self, field):
190
"""Return the length of the longest record in the given field, or the
191
width of the field name itself, whichever is greater."""
193
for record in self.records:
194
cur_len = len(str(record[field]))
195
if cur_len > longest:
199
def show(self, show_records='all', show_fields=FIELDS):
200
"""Print records matching given criteria, showing only the given fields.
202
show_records: Number of record to show, or range of numbers
203
show_fields: List of fields, by name as shown in FIELDS
205
# Remember field sizes (character widths)
207
# Create field headings
209
for field in show_fields:
211
size[field] = self.length(field)
212
heading += "%s " % str.ljust(field, size[field])
214
print "Error: field '%s' does not exist" % field
217
# Print fields from matching records
218
for record in self.records:
219
# TODO: support show_records
221
for field in show_fields:
222
line += "%s " % str.ljust(str(record[field]), size[field])
224
# Print heading at end too
b'\\ No newline at end of file'