def update_typer_html(typer, errors): '''Organizational function. Given a Typer, updates its html based on settings (not including invisible mode)''' #dict : str -> str ; original and displacement strs in error region (for easier display) v = unicode(typer.toPlainText()) v_err_replacements = {} if Settings.get('text_area_replace_spaces'): #if want to make replacements change spaces in text area as well (risky!) v_err_replacements.update( space_replacement_dict_from_setting( 'text_area_mistakes_space_char')) if Settings.get('text_area_replace_return'): #want to make replacements change returns in text area as well (a little less risky since there's usually fewer) v_err_replacements["\n"] = Settings.get('text_area_return_replacement') error_colors = {} #dict : int -> str, mapping errors to color v_replaced_list = list( v) #list of strs, initially one char each, to operate on v_replaced_list = html_list_process_spaces(v_replaced_list) if Settings.get("show_text_area_mistakes"): error_colors = dict( map(lambda i: (i, Settings.get('text_area_mistakes_color')), errors)) v_replaced_list = replace_at_locs(v_replaced_list, v_err_replacements, errors) v_colored_list = html_color_strs(v_replaced_list, error_colors) htmlized = "".join(v_colored_list).replace("\n", "<BR>") set_typer_html(typer, htmlized)
def to_lessons(sentences): backlog = [] backlen = 0 min_chars = Settings.get('min_chars') max_chars = Settings.get('max_chars') sweet_size = 3*(min_chars + max_chars) // 4 for s in sentences: ssplit = [] while len(s) > sweet_size: idx = s.find(' ', sweet_size) if idx == -1: break if idx != -1: ssplid.append(s[:idx]) s = s[idx+1:] ssplit.append(s) for xs in ssplit: backlog.append(xs) backlen += len(xs) if backlen >= min_chars: yield u' '.join(backlog) backlog = [] backlen = 0 if backlen > 0: yield u' '.join(backlog)
def cleanup(self): s_in_day = 24*60*60 now = time.time() pending = [] for idx, grp, lim in [ (1, 30, Settings.get("group_month")), (2, 7, Settings.get("group_week")), (3, 1, Settings.get("group_day")), ]: minimum = now - s_in_day * lim binsize = s_in_day * grp pending.extend(DB.fetchall(f""" select avg(w), data, type, agg_mean(time, count), sum(count), sum(mistakes), agg_median(viscosity) from statistic where w <= {minimum} group by data, type, cast(w/{binsize} as int)""")) self.progressbar.set_fraction(idx/5) DB.executemany("""insert into statistic (w, data, type, time, count, mistakes, viscosity) values (?,?,?,?,?,?,?)""", pending) self.progressbar.set_fraction(4/5) # FIXME vacuum not supported # DB.execute("vacuum") self.progressbar.set_fraction(5/5) DB.commit() self.progressbar.set_fraction(0)
def __init__(self): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) self.result = Gtk.Label() self.typer = Typer() self.label = Gtk.Label(wrap=True, xalign=0, yalign=1) update_result_vis = lambda: self.result.set_visible( Settings.get("show_last")) update_result_vis() sync_font = lambda: self.label.override_font( Pango.FontDescription.from_string(Settings.get("typer_font"))) sync_font() self.typer.connect("done", lambda *_: self.done()) self.typer.connect("want-text", lambda *_: self.emit("want-text")) Settings.connect("change_typer_font", sync_font) Settings.connect("change_show_last", update_result_vis) self.text = ("", 0, "") self.pack_start(self.result, False, False, 0) body = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=True, spacing=24) body.add(self.label) body.add(self.typer) self.pack_start(body, True, True, 0)
def to_lessons(sentences): backlog = [] backlen = 0 min_chars = Settings.get('min_chars') max_chars = Settings.get('max_chars') sweet_size = 3 * (min_chars + max_chars) // 4 for s in sentences: ssplit = [] while len(s) > sweet_size: idx = s.find(' ', sweet_size) if idx == -1: break if idx != -1: ssplid.append(s[:idx]) s = s[idx + 1:] ssplit.append(s) for xs in ssplit: backlog.append(xs) backlen += len(xs) if backlen >= min_chars: yield ' '.join(backlog) backlog = [] backlen = 0 if backlen > 0: yield ' '.join(backlog)
def filter_words(self, words): num = Settings.get('str_extra') what = Settings.get('str_what') if what == 'r': # random pass else: control = self.get_list() if not control: return if what == 'e': # encompassing stream = [(sum([x.count(c) for c in control]), x) for x in words] #print "str:", list(stream)[0:10] preres = list(itertools.islice(filter(lambda x: x[0] > 0, stream), 4*num)) #print "pre:", preres preres.sort(key=lambda x: x[0], reverse=True) words = [x[1] for x in preres] else: # similar words = filter(lambda x: 0 < min( editdist.distance( x.encode('latin1', 'replace'), y.encode('latin1', 'replace'))/max(len(y), len(x)) for y in control) < .26, words) if Settings.get('str_clear') == 'r': # replace = clear GtkUtil.textbuf_clear(self.buf()) self.add_list(itertools.islice(words, num))
def to_lessons(sentences): backlog = [] backlen = 0 min_chars = Settings.get('min_chars') max_chars = Settings.get('max_chars') sweet_size = 3 * (min_chars + max_chars) // 4 for sent in sentences: ssplit = [] while len(sent) > sweet_size: idx = sent.find(' ', sweet_size) if idx == -1: break ssplit.append(sent[:idx]) sent = sent[idx + 1:] ssplit.append(sent) for part in ssplit: backlog.append(part) backlen += len(part) if backlen >= min_chars: yield ' '.join(backlog) backlog = [] backlen = 0 if backlen: yield ' '.join(backlog)
def update_typer_html(typer,errors): '''Organizational function. Given a Typer, updates its html based on settings (not including invisible mode)''' #dict : str -> str ; original and displacement strs in error region (for easier display) v = unicode(typer.toPlainText()) v_err_replacements = {} if Settings.get('text_area_replace_spaces'): #if want to make replacements change spaces in text area as well (risky!) v_err_replacements.update(space_replacement_dict_from_setting('text_area_mistakes_space_char')) if Settings.get('text_area_replace_return'): #want to make replacements change returns in text area as well (a little less risky since there's usually fewer) v_err_replacements["\n"] = Settings.get('text_area_return_replacement') error_colors = {} #dict : int -> str, mapping errors to color v_replaced_list = list(v) #list of strs, initially one char each, to operate on v_replaced_list = html_list_process_spaces(v_replaced_list) if Settings.get("show_text_area_mistakes"): error_colors = dict(map(lambda i : (i,Settings.get('text_area_mistakes_color')),errors)) v_replaced_list = replace_at_locs(v_replaced_list,v_err_replacements,errors) v_colored_list = html_color_strs(v_replaced_list,error_colors) htmlized = "".join(v_colored_list).replace("\n","<BR>") set_typer_html(typer,htmlized)
def __init__(self, fname): super(LessonMiner, self).__init__() with codecs.open(fname, "r", "utf_8_sig") as f: self.text = f.read() self.lessons = None self.min_chars = Settings.get('min_chars') self.split_regex = Settings.get('sentence_regex') self.split = re.compile(self.split_regex).split(self.text)
def paras(self, f): p = [] ps = [] previous_line_empty = True for l in f: #designated replacements for unicode text if Settings.get('transliteration_manual_unicode'): for orig, repl in unicode_replacements: l = l.replace(orig, repl) ascii_line = l if unidecode_imported and Settings.get( 'transliteration_method' ) == INDEX_TRANSLITERATION_UNIDECODE: #tries to use unidecode if it exists ascii_line = unidecode.unidecode(ascii_line) elif Settings.get( 'transliteration_method') == INDEX_TRANSLITERATION_DELETE: #deletes all remaining non-ascii chars try: ascii_line = ascii_line.decode('ascii') except UnicodeEncodeError: ascii_line = '' for c in l: if ord(c) < 128: ascii_line += c else: ascii_line += "" #replaces any 1+ adjacent whitespace chars (spaces, tabs, newlines, etc) with one ascii space if Settings.get('single_space_only'): ascii_line = re.sub("\s+", " ", ascii_line) #designated replacements for ascii text if Settings.get('transliteration_manual_ascii'): for orig, repl in ascii_replacements: ascii_line = ascii_line.replace(orig, repl) l = ascii_line.strip() current_line_empty = not l #the current line is empty: insert empty line #or the current line and previous line both nonempty: need to insert empty line between them if (current_line_empty or not previous_line_empty) and len(p) > 0: ps.append(SentenceSplitter(u" ".join(p))) p = [] if not current_line_empty: p.append(l) previous_line_empty = current_line_empty if len(p) > 0: ps.append(SentenceSplitter(u" ".join(p))) return ps
def update_data(self): if self.editflag: return where = [] where_query = "" selected = self.cb_source.get_active_id() if selected == "last text": where.append( "r.text_id = (select text_id from result order by w desc limit 1)" ) elif selected == "all texts": where.append("s.discount is null") elif selected == "all lessons": where.append("s.discount is not null") elif selected and selected.isdigit(): rowid = int(selected) where.append(f"r.source = {rowid}") if where: where_query = "where " + " and ".join(where) sql_template = """select agg_first(text_id),avg(r.w) as w,count(r.rowid) || ' result(s)',agg_median(r.wpm), 100.0*agg_median(r.accuracy),agg_median(r.viscosity) from result as r left join source as s on (r.source = s.rowid) %s %s order by w desc limit %d""" groupby = Settings.get("perf_group_by") group = "" print(groupby) if groupby == 1: # by def_group_by DB.reset_counter() group = "group by cast(counter()/%d as int)" % max( Settings.get("def_group_by"), 1) elif groupby == 2: # by sitting mis = Settings.get("minutes_in_sitting") * 60.0 DB.reset_time_group() group = "group by time_group(%f, r.w)" % mis elif groupby == 3: # by day group = "group by cast((r.w+4*3600)/86400 as int)" elif not groupby: # no grouping sql_template = """select text_id,w,s.name,wpm,100.0*accuracy,viscosity from result as r left join source as s on (r.source = s.rowid) %s %s order by w desc limit %d""" items = Settings.get("perf_items") sql = sql_template % (where_query, group, items) self.model.set_stats([list(r) for r in DB.fetchall(sql)]) self.update_graph()
def generate_automatic_insertion_regex(): '''From settings info, returns the regex for which to re.match the automatically inserted chars Or None if no chars are to be automatically inserted.''' #the str of characters (in regex-escaped form, but not regex) to automatically insert automatically_inserted_chars = "" if Settings.get('use_automatic_other_insertion'): automatically_inserted_chars += re.escape(Settings.get('automatic_other_insertion')) for s,c in ('automatic_space_insertion',u" "),('automatic_return_insertion',u"\n"): if Settings.get(s): automatically_inserted_chars += re.escape(c) return "[{0}]+".format(automatically_inserted_chars) if automatically_inserted_chars else None
def color_position(settings_color_var, use_space_var, space_var): '''Colors position with the color stored in settings_color_var. strs use_space_var and space_var are settings variables to look up. If [setting] use_space_var, space at position is replaced with [setting] space_var Returns the new text_strs list (for assignment).''' colors[position] = Settings.get(settings_color_var) if Settings.get(use_space_var): return replace_at_locs(text_strs,space_replacement_dict_from_setting(space_var),[position]) else: return text_strs
def paras(self, f): p = [] ps = [] previous_line_empty = True for l in f: #designated replacements for unicode text if Settings.get('transliteration_manual_unicode'): for orig, repl in unicode_replacements: l = l.replace(orig, repl) ascii_line = l if unidecode_imported and Settings.get('transliteration_method') == INDEX_TRANSLITERATION_UNIDECODE: #tries to use unidecode if it exists ascii_line = unidecode.unidecode(ascii_line) elif Settings.get('transliteration_method') == INDEX_TRANSLITERATION_DELETE: #deletes all remaining non-ascii chars try: ascii_line = ascii_line.decode('ascii') except UnicodeEncodeError: ascii_line = '' for c in l: if ord(c) < 128: ascii_line += c else: ascii_line += "" #replaces any 1+ adjacent whitespace chars (spaces, tabs, newlines, etc) with one ascii space if Settings.get('single_space_only'): ascii_line = re.sub("\s+"," ",ascii_line) #designated replacements for ascii text if Settings.get('transliteration_manual_ascii'): for orig, repl in ascii_replacements: ascii_line = ascii_line.replace(orig, repl) l = ascii_line.strip() current_line_empty = not l #the current line is empty: insert empty line #or the current line and previous line both nonempty: need to insert empty line between them if (current_line_empty or not previous_line_empty) and len(p) > 0: ps.append(SentenceSplitter(u" ".join(p))) p = [] if not current_line_empty: p.append(l) previous_line_empty = current_line_empty if len(p) > 0: ps.append(SentenceSplitter(u" ".join(p))) return ps
def generate_lesson(self, words): copies = Settings.get('gen_copies') take = Settings.get('gen_take') mix = Settings.get('gen_mix') sentences = [] while words: sen = words[:take] * copies words[:take] = [] if mix == 'm': # mingle random.shuffle(sen) sentences.append(' '.join(sen)) return sentences
def color_position(settings_color_var, use_space_var, space_var): '''Colors position with the color stored in settings_color_var. strs use_space_var and space_var are settings variables to look up. If [setting] use_space_var, space at position is replaced with [setting] space_var Returns the new text_strs list (for assignment).''' colors[position] = Settings.get(settings_color_var) if Settings.get(use_space_var): return replace_at_locs( text_strs, space_replacement_dict_from_setting(space_var), [position]) else: return text_strs
def __init__(self, *args): super(Quizzer, self).__init__(*args) self.result = QLabel() self.typer = Typer() self.label = WWLabel() self.result.setVisible(Settings.get("show_last")) #self.label.setFrameStyle(QFrame.Raised | QFrame.StyledPanel) #self.typer.setBuddy(self.label) #self.info = QLabel() self.connect(self.typer, SIGNAL("done"), self.done) self.connect(self.typer, SIGNAL("textChanged"), self.checkText) self.connect(self.typer, SIGNAL("cancel"), SIGNAL("wantText")) self.connect(Settings, SIGNAL("change_typer_font"), self.readjust) self.connect(Settings, SIGNAL("change_show_last"), self.result.setVisible) self.text = ('','', 0, None) layout = QVBoxLayout() #layout.addWidget(self.info) #layout.addSpacing(20) layout.addWidget(self.result, 0, Qt.AlignRight) layout.addWidget(self.label, 1, Qt.AlignBottom) layout.addWidget(self.typer, 1) self.setLayout(layout) self.readjust()
def next_text(self): kind = Settings.get("select_method") if kind != 1: # Not in order targets = DB.execute( f"""select id,source,text from text where disabled is null order by random() limit {Settings.get("num_rand")}""" ).fetchall() if not targets: target = None elif kind == 2: target = min(targets, key=self.diff_eval) elif kind == 3: target = max(targets, key=self.diff_eval) else: target = targets[0] # random, just pick the first else: # Fetch in order prev = (0, ) result = DB.fetchone( """select r.text_id from result as r left join source as s on (r.source = s.rowid) where (s.discount is null) or (s.discount = 1) order by r.w desc limit 1""", None) if result is not None: prev = DB.fetchone("select rowid from text where id = ?", prev, result) target = DB.fetchone( """select id,source,text from text where rowid > ? and disabled is null order by rowid asc limit 1""", None, prev) if target is None: target = self.default_text self.emit("set-text", *target)
def generate_automatic_insertion_regex(): '''From settings info, returns the regex for which to re.match the automatically inserted chars Or None if no chars are to be automatically inserted.''' #the str of characters (in regex-escaped form, but not regex) to automatically insert automatically_inserted_chars = "" if Settings.get('use_automatic_other_insertion'): automatically_inserted_chars += re.escape( Settings.get('automatic_other_insertion')) for s, c in ('automatic_space_insertion', u" "), ('automatic_return_insertion', u"\n"): if Settings.get(s): automatically_inserted_chars += re.escape(c) return "[{0}]+".format( automatically_inserted_chars) if automatically_inserted_chars else None
def update_graph(self): what = Settings.get("graph_what") y_coords = [row[what] for row in iter(self.model)] if Settings.get("chrono_x"): x_coords = [row[0] for row in iter(self.model)] else: x_coords = list(range(len(y_coords) - 1, 0 - 1, -1)) if Settings.get("dampen_graph"): window = Settings.get("dampen_average") y_coords = list(dampen(y_coords, window)) x_coords = list(dampen(x_coords, window)) plot = Plotters.Plot(x_coords, y_coords) self.plot.set_data(plot)
def __init__(self, fname): super(LessonMiner, self).__init__() #print time.clock() with codecs.open(fname, "r", "utf_8_sig") as f: self.paras = self.paras(f) self.lessons = None self.min_chars = Settings.get('min_chars')
def __init__(self, *args): super(Quizzer, self).__init__(*args) self.result = QLabel() self.typer = Typer() self.label = WWLabel() self.result.setVisible(Settings.get("show_last")) #self.label.setFrameStyle(QFrame.Raised | QFrame.StyledPanel) #self.typer.setBuddy(self.label) #self.info = QLabel() self.connect(self.typer, SIGNAL("done"), self.done) self.connect(self.typer, SIGNAL("textChanged"), self.checkText) self.connect(self.typer, SIGNAL("cancel"), SIGNAL("wantText")) self.connect(Settings, SIGNAL("change_typer_font"), self.readjust) self.connect(Settings, SIGNAL("change_show_last"), self.result.setVisible) self.text = ('', '', 0, None) layout = QVBoxLayout() #layout.addWidget(self.info) #layout.addSpacing(20) layout.addWidget(self.result, 0, Qt.AlignRight) layout.addWidget(self.label, 1, Qt.AlignBottom) layout.addWidget(self.typer, 1) self.setLayout(layout) self.readjust()
def __init__(self, x, y, *args): super(Plot, self).__init__(*args) # self.connect(self, SIGNAL("sceneRectChanged(QRectF)"), self.setSceneRect) if len(x) < 2: return min_x, max_x = min(x), max(x) min_y, max_y = min(y), max(y) p = QPen(Qt.blue) p.setCosmetic(True) p.setWidthF(2.0) p.setCapStyle(Qt.RoundCap) for i in range(0, len(x) - 1): self.addLine(x[i], -y[i], x[i + 1], -y[i + 1], p) # Add axes if Settings.get("show_xaxis"): if min_y > 0: min_y = 0 elif max_y < 0: max_y = 0 if min_y <= 0 <= min_y: self.addLine(min_x, 0, max_x, 0) if min_x <= 0 <= max_x: self.addLine(0, -min_y, 0, -max_y) w, h = max_x - min_x, max_y - min_y if h <= 0 or w <= 0: return # Add background lines spc = math.pow(10.0, math.ceil(math.log10(h) - 1)) while h / spc < 5: spc /= 2 ns = int(min_y / spc) * spc start = ns qp = QPen(QColor(Qt.lightGray)) qp.setStyle(Qt.DotLine) while start < max_y + spc: lin = self.addLine(min_x, -start, max_x, -start, qp) lin.setZValue(-1.0) lbl = QGraphicsSimpleTextItem("%g" % start) th, tw = lbl.boundingRect().height(), lbl.boundingRect().width() lbl.scale(0.026 * w / tw, spc / th) lbl.setPos(QPointF(min_x - 0.03 * w, -start - spc / 2)) self.addItem(lbl) start += spc qr = QRectF(min_x - 0.03 * w, -start + spc / 2, 1.03 * w, start - ns) self.setSceneRect(qr)
def getWaitText(self): if Settings.get("req_space"): return ( "Press SPACE and then immediately start typing the text\n" + "Press ESCAPE to restart with a new text at any time" ) else: return "Press ESCAPE to restart with a new text at any time"
def paras(self, f): p = [] ps = [] previous_line_empty = True for l in f: #designated replacements for unicode text if Settings.get('transliteration_manual_unicode'): for orig, repl in unicode_replacements: l = l.replace(orig, repl) ascii_line = l if unidecode_imported and Settings.get('transliteration_method') == INDEX_TRANSLITERATION_UNIDECODE: #tries to use unidecode if it exists ascii_line = unidecode.unidecode(ascii_line) elif Settings.get('transliteration_method') == INDEX_TRANSLITERATION_DELETE: #deletes all remaining non-ascii chars try: ascii_line = ascii_line.decode('ascii') except UnicodeEncodeError: ascii_line = filter(lambda c : ord(c) < 128, ascii_line) #replaces any 1+ adjacent whitespace chars (spaces, tabs, newlines, etc) with one ascii space if Settings.get('single_space_only'): ascii_line = re.sub("\s+"," ",ascii_line) #TODO: newlines doesn't work since all this is done line-by-line #replaces multiple adjacent instances (possibly including spaces, newlines) of those characters #in list multiple_replacements (e.g. "start ! !!!!! ! ! !!\n !\nend" might get replaced with #"start !\nend") if Settings.get('multiple_replacement_enabled'): additional_chars = (" " if Settings.get('multiple_replacement_allow_spaces') else "") + ("\n" if Settings.get('multiple_replacement_allow_newlines') else "") for m in Settings.get('multiple_replacement_chars'): ascii_line = re.sub("{0}[{0}{1}]*{0}".format(re.escape(m),additional_chars), m, ascii_line) #designated replacements for ascii text if Settings.get('transliteration_manual_ascii'): for orig, repl in ascii_replacements: ascii_line = ascii_line.replace(orig, repl) l = ascii_line.strip() current_line_empty = not l #the current line is empty: insert empty line #or the current line and previous line both nonempty: need to insert empty line between them if (current_line_empty or not previous_line_empty) and len(p) > 0: ps.append(SentenceSplitter(u" ".join(p))) p = [] if not current_line_empty: p.append(l) previous_line_empty = current_line_empty if len(p) > 0: ps.append(SentenceSplitter(u" ".join(p))) return ps
def check_text(self): if not self.target or self.edit_flag: return text = GtkUtil.textbuf_get_text(self.get_buffer()) if self.when[0] == 0: # We're just starting space = text and text[-1] == " " self.edit_flag = True if space: self.when[0] = timer() self.get_buffer().set_text("", -1) self.update_palette("right") elif Settings.get("req_space"): # reset self.get_buffer().set_text(get_wait_text(), -1) self.get_buffer().select_range(*self.get_buffer().get_bounds()) self.edit_flag = False if space or Settings.get("req_space"): return self.when[0] = -1 # find first difference for upto in range(min(len(text), len(self.target))): if text[upto] != self.target[upto]: break else: upto = min(len(text), len(self.target)) self.where = upto if self.when[upto] == 0 and upto == len(text): self.when[upto] = timer() if upto: self.times[upto - 1] = self.when[upto] - self.when[upto - 1] if upto == len(self.target): self.emit("done") return if upto < len(text) and upto < len(self.target): self.mistake[upto] = True self.mistakes[upto] = self.target[upto] + text[upto] self.update_palette("right" if upto == len(text) else "wrong")
def update(self): which = Settings.get("ana_which") what = Settings.get("ana_what") limit = Settings.get("ana_many") least = Settings.get("ana_count") hist = time.time() - Settings.get("history") * 86400.0 sql = f"""select data,12.0/time as wpm, 100.0-100.0*misses/cast(total as real) as accuracy, viscosity,total,misses, total*time*time*(1.0+misses/total) as damage from (select data,agg_median(time) as time,agg_median(viscosity) as viscosity, sum(count) as total,sum(mistakes) as misses from statistic where w >= ? and type = ? group by data) where total >= ? order by {which} limit {limit}""" self.model.set_stats(DB.fetchall(sql, (hist, what, least)))
def set_select(self): method = Settings.get("select_method") if method in (0, 1): self.diff_eval = lambda x: 1 self.next_text() return hist = time.time() - 86400 * Settings.get("history") tri = dict( DB.execute( """ select data,agg_median(time) as wpm from statistic where w >= ? and type = 1 group by data""", (hist, )).fetchall()) vals = list(tri.values()) if not vals: self.diff_eval = lambda x: 1 self.next_text() return vals.sort(reverse=True) expect = vals[len(vals) // 4] def func(target): text = target[2] # FIXME what does v do here? # v = 0 total = 0.0 for i in range(0, len(text) - 2): trigram = text[i:i + 3] if trigram in tri: total += tri[trigram] else: total += expect # v += 1 avg = total / (len(text) - 2) return 12.0 / avg self.diff_eval = func self.next_text()
def updateLabel(self,position,errors): '''Populates the label with colors depending on current position and errors.''' #dict : str -> str ; original and displacement strs in error region (for easier display) err_replacements = {"\n":u"{0}<BR>".format(Settings.get('label_return_symbol'))} colors = {} #dict : int -> str, mapping errors to color if Settings.get('show_label_mistakes'): #showing mistakes; need to populate color colors = dict([(i,Settings.get('label_mistakes_color')) for i in errors]) if Settings.get('label_replace_spaces_in_mistakes'): err_replacements.update(space_replacement_dict_from_setting('label_mistakes_space_char')) text_strs = list(self.text[2]) #list of strs, initially one char each, to operate on text_strs = html_list_process_spaces(text_strs) text_strs = replace_at_locs(text_strs,err_replacements,errors) def color_position(settings_color_var, use_space_var, space_var): '''Colors position with the color stored in settings_color_var. strs use_space_var and space_var are settings variables to look up. If [setting] use_space_var, space at position is replaced with [setting] space_var Returns the new text_strs list (for assignment).''' colors[position] = Settings.get(settings_color_var) if Settings.get(use_space_var): return replace_at_locs(text_strs,space_replacement_dict_from_setting(space_var),[position]) else: return text_strs #designates colors and replacements of position if Settings.get('show_label_position_with_prior_mistake') and position - 1 in errors: text_strs = color_position('label_position_with_prior_mistake_color', 'label_replace_spaces_in_position_with_prior_mistake', 'label_position_with_prior_mistake_space_char') elif Settings.get('show_label_position_with_mistakes') and errors: text_strs = color_position('label_position_with_mistakes_color', 'label_replace_spaces_in_position_with_mistakes', 'label_position_with_mistakes_space_char') elif Settings.get('show_label_position'): text_strs = color_position('label_position_color', 'label_replace_spaces_in_position', 'label_position_space_char') htmlized = "".join(html_color_strs(text_strs,colors)) htmlized = htmlized.replace(u"\n", u"{0}<BR>".format(Settings.get('label_return_symbol'))) self.label.setText(htmlized)
def checkText(self): if self.target is None or self.editflag: return v = unicode(self.toPlainText()) if self.when[0] == 0: space = len(v) > 0 and v[-1] == u" " req = Settings.get('req_space') self.editflag = True if space: self.when[0] = timer() self.clear() self.setPalette(self.palettes['right']) elif req: self.setText(self.getWaitText()) self.selectAll() self.editflag = False if req or space: return else: self.when[0] = -1 y = 0 for y in xrange(min(len(v), len(self.target)), -1, -1): if v[0:y] == self.target[0:y]: break lcd = v[0:y] self.where = y if self.when[y] == 0 and y == len(v): self.when[y] = timer() if y > 0: self.times[y-1] = self.when[y] - self.when[y-1] if lcd == self.target: self.emit(SIGNAL("done")) return if y < len(v) and y < len(self.target): self.mistake[y] = True self.mistakes[y] = self.target[y] + v[y] if v == lcd: self.setPalette(self.palettes['right']) else: self.setPalette(self.palettes['wrong'])
def __init__(self): GtkUtil.AmphBoxLayout.__init__(self) self.plotcol = 3 self.plot = Plotters.Plotter() self.editflag = False self.model = ResultModel() self.cb_source = Gtk.ComboBoxText() self.refresh_sources() self.cb_source.set_active_id("all") self.cb_source.connect("changed", lambda _: self.update_data()) tree = GtkUtil.AmphTreeView(self.model) tree.treeview.connect("row-activated", self.double_clicked) Settings.on_any_change( ["graph_what", "show_xaxis", "chrono_x", "dampen_graph"], self.update_graph) Settings.on_any_change(["perf_items", "perf_group_by", "lesson_stats"], self.update_data) self.append_layout([ [ "Show", SettingsEdit("perf_items"), "items from", self.cb_source, "and group by", SettingsCombo("perf_group_by", [ "<no grouping>", "%d sessions" % Settings.get("def_group_by"), "sitting", "day" ]), None, GtkUtil.new_button("Update", self.update_data) ], (tree, ), [ "Plot", SettingsCombo("graph_what", ((3, "WPM"), (4, "accuracy"), (5, "viscosity"))), SettingsCheckBox("show_xaxis", "Show X-axis"), SettingsCheckBox("chrono_x", "Use time-scaled X-axis"), SettingsCheckBox("dampen_graph", "Dampen graph values") ], (self.plot, ), ]) self.update_data()
def __init__(self): Gtk.TextView.__init__(self, wrap_mode=Gtk.WrapMode.WORD) sync_font = lambda: self.override_font( Pango.FontDescription.from_string(Settings.get("typer_font"))) sync_font() self.connect("key-press-event", lambda _, key: self.key_press(key)) self.get_buffer().connect("end-user-action", lambda _: self.check_text()) Settings.on_any_change([ "quiz_wrong_fg", "quiz_wrong_bg", "quiz_right_fg", "quiz_right_bg", ], self.update_palette) Settings.on_any_change(["typer_font"], sync_font) self.set_target("") # clear input
def __init__(self, *args): super(Quizzer, self).__init__(*args) self.result = QLabel() self.typer = Typer() self.label = WWLabel() self.tryout_label = QLabel() self.tryout_label.setText("Tryout layout: ") self.tryout_layout = QComboBox() self.result.setVisible(Settings.get("show_last")) #self.label.setFrameStyle(QFrame.Raised | QFrame.StyledPanel) #self.typer.setBuddy(self.label) #self.info = QLabel() self.connect(self.typer, SIGNAL("done"), self.done) self.connect(self.typer, SIGNAL("cancel"), SIGNAL("wantText")) self.connect(Settings, SIGNAL("change_typer_font"), self.readjust) self.connect(Settings, SIGNAL("change_show_last"), self.result.setVisible) self.connect(self.tryout_layout, SIGNAL("currentIndexChanged(int)"), self.changeTryoutLayout) self.text = ('','', '', None) self.originalText = ('','', '', None) self.keyboardLayouts = [] layout = QVBoxLayout() #layout.addWidget(self.info) #layout.addSpacing(20) hlayout = QHBoxLayout() hlayout.addWidget(self.tryout_label, 0, Qt.AlignLeft) hlayout.addWidget(self.tryout_layout, 0, Qt.AlignLeft) hlayout.addStretch() hlayout.addWidget(self.result, 0, Qt.AlignRight) layout.addLayout(hlayout) layout.addWidget(self.label, 1, Qt.AlignBottom) layout.addWidget(self.typer, 1) self.setLayout(layout) self.readjust() self.addLayouts()
def __iter__(self): p = [0] sen = re.compile(Settings.get('sentence_regex')) return ifilter(None, imap(lambda x: self.pars(p, x), sen.finditer(self.string)))
def new_error(position,errors): '''Given list of error positions and current position, returns whether or there's a new error at position''' #considers adjacent errors to be part of the same error if the setting is toggled return position in errors and not (Settings.get('adjacent_errors_not_counted') and position - 1 in errors)
def checkText(self, automatically_inserted = False): if self.typer.target is None or self.typer.editflag: return v = unicode(self.typer.toPlainText()) if Settings.get('allow_mistakes') and len(v) >= len(self.typer.target): v = self.typer.target if self.typer.start_time == None and Settings.get('req_space'): #space is required before beginning the passage proper if v == u" ": #the first char typed was space #the first space only starts the session; clear the typer set_typer_text(self.typer,"",cursor_position=0) self.typer.start_time = 0 return else: #reset the wait text set_typer_text(self.typer,self.typer.getWaitText()) self.typer.selectAll() return if not self.typer.start_time: self.typer.start_time = timer() if 1 < len(v) < len(self.typer.target): #checks whether wait text was accidentally left in diff = list(difflib.Differ().compare(list(self.typer.getWaitText()),list(v))) #the vast majority of the wait text is still there wait_text_present = len(filter(lambda line : line[0] == "-", diff)) <= 1 if wait_text_present: #leave only the additional typed text new_str = "".join(line[2:] for line in diff if line[0] == "+") set_typer_text(self.typer,new_str,cursor_position=len(new_str)) v = new_str old_cursor = self.typer.textCursor() old_position = old_cursor.position() old_str_position = old_position - 1 #the position that has (presumably, unless delete was used) just been typed #colors text in typer depending on errors errors = disagreements(v,self.typer.target,case_sensitive=Settings.get('case_sensitive')) first_error = errors[0] if errors else None #records time that any char was hit #except that if we've already been correct farther, we don't record if self.typer.farthest_correct < old_str_position < len(self.typer.target): if old_str_position not in errors: self.typer.farthest_correct = old_str_position #invalidates all farther-out times that might have previously been written if old_str_position < self.typer.farthest_data: for i in xrange(old_str_position+1, self.typer.farthest_data + 1): self.typer.data[i].when = None self.typer.farthest_data = old_str_position self.typer.data[old_str_position] = Letter(char=self.typer.target[old_str_position], when=timer(), automatically_inserted=automatically_inserted) automatic_insertion_regex = generate_automatic_insertion_regex() #TODO: refactor so this doesn't rely on text setting then re-calling gimmick #TODO: change statistics to account for this #Automatically insert characters into the text area if automatic_insertion_regex and old_position == len(v): #only works if cursor is at the end automatic_insertion = re.match(automatic_insertion_regex,self.typer.target[old_position:]) if automatic_insertion: new_end = old_position + automatic_insertion.end() set_typer_text(self.typer, v[:old_position] + self.typer.target[old_position:new_end], cursor_position = new_end) self.checkText(automatically_inserted=True) #recovers the formatting return #TODO: refactor so this doesn't rely on text setting then re-calling gimmick #Prevent advancement until user correctly types space if Settings.get('ignore_until_correct_space') and self.typer.target[old_str_position] == u" " and old_str_position in errors: #gets rid of new character (sets as plaintext) set_typer_text(self.typer,v[:old_str_position] + v[old_str_position+1:],cursor_position = old_position - 1) self.checkText() #recovers the formatting return if len(v) >= len(self.typer.target) and (not first_error or first_error >= len(self.typer.target)): self.done() return if new_error(old_str_position,errors): self.typer.mistake[old_str_position] = True self.typer.mistakes[old_str_position] = self.typer.target[old_str_position] + v[old_str_position] if Settings.get('quiz_invisible'): self.typer.activate_invisibility() else: if Settings.get("quiz_use_wrong_palette") and errors: self.typer.setPalette(self.typer.palettes['wrong']) else: self.typer.setPalette(self.typer.palettes['right']) update_typer_html(self.typer,errors) #updates the label depending on errors self.updateLabel(old_position,errors)
def checkText(self): if self.typer.target is None or self.typer.editflag: return v = unicode(self.typer.toPlainText()) if Settings.get('allow_mistakes') and len(v) >= len(self.typer.target): v = self.typer.target if not self.typer.started: if Settings.get('req_space'): #space is required before beginning the passage proper if v == u" ": #the first char typed was space #the first space only starts the session; clear the typer set_typer_text(self.typer, "", cursor_position=0) self.typer.when[0] = timer() self.typer.started = True return else: #reset the wait text set_typer_text(self.typer, self.typer.getWaitText()) self.typer.selectAll() return else: self.typer.when[0] = -1 self.typer.when[1] = timer( ) #have to set starting time regardless of correctness self.typer.started = True old_cursor = self.typer.textCursor() old_position = old_cursor.position() old_str_position = old_position - 1 #the position that has (presumably) just been typed #colors text in typer depending on errors errors = disagreements(v, self.typer.target, case_sensitive=Settings.get('case_sensitive')) first_error = errors[0] if errors else None #records time that any char was correctly hit #except that if we've already been correct farther, we don't record if self.typer.farthest_correct < old_str_position < len( self.typer.target) and not old_str_position in errors: self.typer.when[old_str_position + 1] = timer() #zeroth position is original space self.typer.farthest_correct = old_str_position automatic_insertion_regex = generate_automatic_insertion_regex() #TODO: refactor so this doesn't rely on text setting then re-calling gimmick #TODO: change statistics to account for this #Automatically insert characters into the text area if automatic_insertion_regex and old_position == len( v): #only works if cursor is at the end automatic_insertion = re.match(automatic_insertion_regex, self.typer.target[old_position:]) if automatic_insertion: new_end = old_position + automatic_insertion.end() set_typer_text(self.typer, v[:old_position] + self.typer.target[old_position:new_end], cursor_position=new_end) self.checkText() #recovers the formatting return #TODO: refactor so this doesn't rely on text setting then re-calling gimmick #Prevent advancement until user correctly types space if Settings.get('ignore_until_correct_space') and self.typer.target[ old_str_position] == u" " and old_str_position in errors: #gets rid of new character (sets as plaintext) set_typer_text(self.typer, v[:old_str_position] + v[old_str_position + 1:], cursor_position=old_position - 1) self.checkText() #recovers the formatting return if len(v) >= len(self.typer.target) and ( not first_error or first_error >= len(self.typer.target)): self.done() return if new_error(old_str_position, errors): self.typer.mistake[old_str_position] = True self.typer.mistakes[old_str_position] = self.typer.target[ old_str_position] + v[old_str_position] if Settings.get('quiz_invisible'): self.typer.activate_invisibility() else: if Settings.get("quiz_use_wrong_palette") and errors: self.typer.setPalette(self.typer.palettes['wrong']) else: self.typer.setPalette(self.typer.palettes['right']) update_typer_html(self.typer, errors) #updates the label depending on errors self.updateLabel(old_position, errors)
def done(self): now = time.time() elapsed, chars, times, mis, mistakes = self.typer.getStats() assert chars == len(self.text[2]) accuracy = 1.0 - len(filter(None, mis)) / chars spc = elapsed / chars viscosity = sum(map(lambda x: ((x - spc) / spc)**2, times)) / chars DB.execute( 'insert into result (w,text_id,source,wpm,accuracy,viscosity) values (?,?,?,?,?,?)', (now, self.text[0], self.text[1], 12.0 / spc, accuracy, viscosity)) v2 = DB.fetchone( """select agg_median(wpm),agg_median(acc) from (select wpm,100.0*accuracy as acc from result order by w desc limit %d)""" % Settings.get('def_group_by'), (0.0, 100.0)) self.result.setText( "Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)" % ((12.0 / spc, 100.0 * accuracy) + v2)) self.emit(SIGNAL("statsChanged")) stats = collections.defaultdict(Statistic) visc = collections.defaultdict(Statistic) text = self.text[2] for c, t, m in zip(text, times, mis): stats[c].append(t, m) visc[c].append(((t - spc) / spc)**2) def gen_tup(s, e): perch = sum(times[s:e]) / (e - s) visc = sum(map(lambda x: ((x - perch) / perch)**2, times[s:e])) / (e - s) return (text[s:e], perch, len(filter(None, mis[s:e])), visc) for tri, t, m, v in [gen_tup(i, i + 3) for i in xrange(0, chars - 2)]: stats[tri].append(t, m > 0) visc[tri].append(v) regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*") for w, t, m, v in [ gen_tup(*x.span()) for x in regex.finditer(text) if x.end() - x.start() > 3 ]: stats[w].append(t, m > 0) visc[w].append(v) def type(k): if len(k) == 1: return 0 elif len(k) == 3: return 1 return 2 vals = [] for k, s in stats.iteritems(): v = visc[k].median() vals.append( (s.median(), v * 100.0, now, len(s), s.flawed(), type(k), k)) is_lesson = DB.fetchone("select discount from source where rowid=?", (None, ), (self.text[1], ))[0] if Settings.get('use_lesson_stats') or not is_lesson: DB.executemany_( '''insert into statistic (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)''', vals) DB.executemany_( 'insert into mistake (w,target,mistake,count) values (?,?,?,?)', [(now, k[0], k[1], v) for k, v in mistakes.iteritems()]) if is_lesson: mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: mins = (Settings.get("min_wpm"), Settings.get("min_acc")) if 12.0 / spc < mins[0] or accuracy < mins[1] / 100.0: self.setText(self.text) elif not is_lesson and Settings.get('auto_review'): ws = filter(lambda x: x[5] == 2, vals) if len(ws) == 0: self.emit(SIGNAL("wantText")) return ws.sort(key=lambda x: (x[4], x[0]), reverse=True) i = 0 while ws[i][4] != 0: i += 1 i += (len(ws) - i) // 4 self.emit(SIGNAL("wantReview"), map(lambda x: x[6], ws[0:i])) else: self.emit(SIGNAL("wantText"))
def setText(self, text): self.text = text self.label.setText(self.text[2].replace( u"\n", u"{0}\n".format(Settings.get('label_return_symbol')))) self.typer.setTarget(self.text[2]) self.typer.setFocus()
def setText(self, text): self.text = text self.label.setText(self.text[2].replace(u"\n", u"{0}\n".format(Settings.get('label_return_symbol')))) self.typer.setTarget(self.text[2]) self.typer.setFocus()
def done(self): now = time.time() elapsed, chars, times, mis, mistakes = self.typer.getStats() assert chars == len(self.text[2]) accuracy = 1.0 - len(filter(None, mis)) / chars spc = elapsed / chars viscosity = sum(map(lambda x: ((x-spc)/spc)**2, times)) / chars DB.execute('insert into result (w,text_id,source,wpm,accuracy,viscosity) values (?,?,?,?,?,?)', (now, self.text[0], self.text[1], 12.0/spc, accuracy, viscosity)) v2 = DB.fetchone("""select agg_median(wpm),agg_median(acc) from (select wpm,100.0*accuracy as acc from result order by w desc limit %d)""" % Settings.get('def_group_by'), (0.0, 100.0)) self.result.setText("Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)" % ((12.0/spc, 100.0*accuracy) + v2)) self.emit(SIGNAL("statsChanged")) stats = collections.defaultdict(Statistic) visc = collections.defaultdict(Statistic) text = self.text[2] for c, t, m in zip(text, times, mis): stats[c].append(t, m) visc[c].append(((t-spc)/spc)**2) def gen_tup(s, e): perch = sum(times[s:e])/(e-s) visc = sum(map(lambda x: ((x-perch)/perch)**2, times[s:e]))/(e-s) return (text[s:e], perch, len(filter(None, mis[s:e])), visc) for tri, t, m, v in [gen_tup(i, i+3) for i in xrange(0, chars-2)]: stats[tri].append(t, m > 0) visc[tri].append(v) regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*") for w, t, m, v in [gen_tup(*x.span()) for x in regex.finditer(text) if x.end()-x.start() > 3]: stats[w].append(t, m > 0) visc[w].append(v) def type(k): if len(k) == 1: return 0 elif len(k) == 3: return 1 return 2 vals = [] for k, s in stats.iteritems(): v = visc[k].median() vals.append( (s.median(), v*100.0, now, len(s), s.flawed(), type(k), k) ) is_lesson = DB.fetchone("select discount from source where rowid=?", (None,), (self.text[1], ))[0] if Settings.get('use_lesson_stats') or not is_lesson: DB.executemany_('''insert into statistic (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)''', vals) DB.executemany_('insert into mistake (w,target,mistake,count) values (?,?,?,?)', [(now, k[0], k[1], v) for k, v in mistakes.iteritems()]) if is_lesson: mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: mins = (Settings.get("min_wpm"), Settings.get("min_acc")) if 12.0/spc < mins[0] or accuracy < mins[1]/100.0: self.setText(self.text) elif not is_lesson and Settings.get('auto_review'): ws = filter(lambda x: x[5] == 2, vals) if len(ws) == 0: self.emit(SIGNAL("wantText")) return ws.sort(key=lambda x: (x[4],x[0]), reverse=True) i = 0 while ws[i][4] != 0: i += 1 i += (len(ws) - i) // 4 self.emit(SIGNAL("wantReview"), map(lambda x:x[6], ws[0:i])) else: self.emit(SIGNAL("wantText"))
def get_wait_text(): if Settings.get("req_space"): return ("Press SPACE and then immediately start typing the text\n" "Press ESCAPE to restart with a new text at any time") return "Press ESCAPE to restart with a new text at any time"
def checkText(self): if self.typer.target is None or self.typer.editflag: return v = unicode(self.typer.toPlainText()) if Settings.get('allow_mistakes') and len(v) >= len(self.typer.target): v = self.typer.target if not self.typer.started: if Settings.get('req_space'): #space is required before beginning the passage proper if v == u" ": #the first char typed was space #the first space only starts the session; clear the typer set_typer_text(self.typer,"",cursor_position=0) self.typer.when[0] = timer() self.typer.started = True return else: #reset the wait text set_typer_text(self.typer,self.typer.getWaitText()) self.typer.selectAll() return else: self.typer.when[0] = -1 self.typer.when[1] = timer() #have to set starting time regardless of correctness self.typer.started = True old_cursor = self.typer.textCursor() old_position = old_cursor.position() old_str_position = old_position - 1 #the position that has (presumably) just been typed #colors text in typer depending on errors errors = disagreements(v,self.typer.target,case_sensitive=Settings.get('case_sensitive')) first_error = errors[0] if errors else None #records time that any char was correctly hit #except that if we've already been correct farther, we don't record if self.typer.farthest_correct < old_str_position < len(self.typer.target) and not old_str_position in errors: self.typer.when[old_str_position+1] = timer() #zeroth position is original space self.typer.farthest_correct = old_str_position automatic_insertion_regex = generate_automatic_insertion_regex() #TODO: refactor so this doesn't rely on text setting then re-calling gimmick #TODO: change statistics to account for this #Automatically insert characters into the text area if automatic_insertion_regex and old_position == len(v): #only works if cursor is at the end automatic_insertion = re.match(automatic_insertion_regex,self.typer.target[old_position:]) if automatic_insertion: new_end = old_position + automatic_insertion.end() set_typer_text(self.typer, v[:old_position] + self.typer.target[old_position:new_end], cursor_position = new_end) self.checkText() #recovers the formatting return #TODO: refactor so this doesn't rely on text setting then re-calling gimmick #Prevent advancement until user correctly types space if Settings.get('ignore_until_correct_space') and self.typer.target[old_str_position] == u" " and old_str_position in errors: #gets rid of new character (sets as plaintext) set_typer_text(self.typer,v[:old_str_position] + v[old_str_position+1:],cursor_position = old_position - 1) self.checkText() #recovers the formatting return if len(v) >= len(self.typer.target) and (not first_error or first_error >= len(self.typer.target)): self.done() return if new_error(old_str_position,errors): self.typer.mistake[old_str_position] = True self.typer.mistakes[old_str_position] = self.typer.target[old_str_position] + v[old_str_position] if Settings.get('quiz_invisible'): self.typer.activate_invisibility() else: if Settings.get("quiz_use_wrong_palette") and errors: self.typer.setPalette(self.typer.palettes['wrong']) else: self.typer.setPalette(self.typer.palettes['right']) update_typer_html(self.typer,errors) #updates the label depending on errors self.updateLabel(old_position,errors)
def done(self): print("DONE") # TODO split into smaller bits now = timer() elapsed, chars, times, mis, mistakes = self.typer.get_stats() text = self.text[2] assert chars == len(text) accuracy = 1.0 - sum(1 for f in mis if f) / chars spc = elapsed / chars viscosity = sum((t / spc - 1)**2 for t in times) / chars DB.execute( """insert into result (w, text_id, source, wpm, accuracy, viscosity) values (?,?,?,?,?,?)""", (now, self.text[0], self.text[1], 12.0 / spc, accuracy, viscosity)) wpm_median, acc_median = DB.fetchone( f"""select agg_median(wpm),agg_median(acc) from (select wpm,100.0*accuracy as acc from result order by w desc limit {Settings.get("def_group_by")})""", (0.0, 100.0)) self.result.set_text( "Last: {:.1f}wpm ({:.1f}%), last 10 average: {:.1f}wpm ({:.1f}%)". format(12.0 / spc, 100.0 * accuracy, wpm_median, acc_median)) self.emit("stats-changed") stats = collections.defaultdict(Statistic) viscs = collections.defaultdict(Statistic) for char, time, mistake in zip(text, times, mis): stats[char].append(time, mistake) viscs[char].append((time / spc - 1)**2) def gen_tup(start, end): span = end - start char_avg = sum(times[start:end]) / span visc = sum((t / char_avg - 1)**2 for t in times[start:end]) / span return (text[start:end], char_avg, sum(1 for f in mis[start:end] if f), visc) for trigraph, time, mist, visc in [ gen_tup(i, i + 3) for i in range(0, chars - 2) ]: stats[trigraph].append(time, mist > 0) viscs[trigraph].append(visc) regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*") for word, time, mist, visc in [ gen_tup(*m.span()) for m in regex.finditer(text) if m.end() - m.start() > 3 ]: stats[word].append(time, mist > 0) viscs[word].append(visc) def kind(key): if len(key) == 1: return 0 if len(key) == 3: return 1 return 2 vals = [] for key, stat in stats.items(): visc = viscs[key].median() vals.append((stat.median(), visc * 100.0, now, len(stat), stat.flawed(), kind(key), key)) is_lesson = DB.fetchone("select discount from source where rowid=?", (None, ), (self.text[1], ))[0] if Settings.get("use_lesson_stats") or not is_lesson: DB.executemany( """insert into statistic (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)""", vals) DB.executemany( "insert into mistake (w,target,mistake,count) values (?,?,?,?)", [(now, k[0], k[1], v) for k, v in mistakes.items()]) if is_lesson: mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: mins = (Settings.get("min_wpm"), Settings.get("min_acc")) if 12.0 / spc < mins[0] or accuracy < mins[1] / 100.0: self.set_target(self.text) elif not is_lesson and Settings.get('auto_review'): words = [x for x in vals if x[5] == 2] if not words: self.emit("want-text") return words.sort(key=lambda x: (x[4], x[0]), reverse=True) i = 0 while words[i][4] != 0: i += 1 i += (len(words) - i) // 4 # TODO support want-review # self.emit("want-review", [x[6] for x in words[0:i]]) else: self.emit("want-text")
def executemany_(self, *args): sqlite3.Connection.executemany(self, *args) def executemany(self, *args): sqlite3.Connection.executemany(self, *args) #self.commit() def fetchall(self, *args): return sqlite3.Connection.execute(self, *args).fetchall() def fetchone(self, sql, default, *args): x = sqlite3.Connection.execute(self, sql, *args) g = x.fetchone() if g is None: return default return g def getSource(self, source, lesson=None): v = self.fetchall('select rowid from source where name = ? limit 1', (source, )) if len(v) > 0: sqlite3.Connection.execute(self, 'update source set disabled = NULL where rowid = ?', v[0]) sqlite3.Connection.commit(self) return v[0][0] sqlite3.Connection.execute(self, 'insert into source (name, discount) values (?, ?)', (source, lesson)) return self.getSource(source) dbname = Settings.get("db_name") # GLOBAL DB = sqlite3.connect(dbname, 5, 0, "DEFERRED", False, AmphDatabase)
def activate_invisibility(self): '''Turns on invisible mode''' self.setPalette(self.palettes['invisible']) set_colored_typer_text(self,Settings.get('quiz_invisible_color')) #flushes out html with plaintext
def fetchall(self, *args): return sqlite3.Connection.execute(self, *args).fetchall() def fetchone(self, sql, default, *args): x = sqlite3.Connection.execute(self, sql, *args) g = x.fetchone() if g is None: return default return g def getSource(self, source, lesson=None): v = self.fetchall('select rowid from source where name = ? limit 1', (source, )) if len(v) > 0: sqlite3.Connection.execute( self, 'update source set disabled = NULL where rowid = ?', v[0]) sqlite3.Connection.commit(self) return v[0][0] sqlite3.Connection.execute( self, 'insert into source (name, discount) values (?, ?)', (source, lesson)) return self.getSource(source) dbname = Settings.get("db_name") # GLOBAL DB = sqlite3.connect(dbname, 5, 0, "DEFERRED", False, AmphDatabase)
def space_replacement_dict_from_setting(replacement_var): '''Returns a dict that assigns to html spaces the value in the setting replacement_var''' return space_replacement_dict(Settings.get(replacement_var))