1
2
3
4 """The Driver class holds everything the program needs to perform prediction.
5
6 It gather instances of needed classes, implement some wrapper methods and the
7 very important L{drvr.Driver.predict} method which actualy compute the suggested
8 words.
9 """
10
11 try:
12 from configparser import ConfigParser
13 except ImportError:
14 from ConfigParser import ConfigParser
15 try:
16 from StringIO import StringIO
17 except ImportError:
18 from io import StringIO
19 from tipy.clbk import Callback
20 from tipy.slct import Selector
21 from tipy.prdct import PredictorRegistry, PredictorActivator
22 from tipy.cntxt import ContextMonitor
23 from os import path
24 from tipy.lg import lg
25
26
30
32 return repr('Unknown cast type "%s"' % self.value)
33
34
38
40 return repr('Section "%s" is missing from the configuration'
41 % self.value)
42
43
47
49 return repr('Section "%s" is missing from the configuration'
50 % self.value)
51
52
54 """Copy a configuration file (ini format) in memory.
55
56 This class subclass the Configparser class. Configparser is used to read() a
57 configuration file (ini format) in memory in the form of a dictionary
58 associating sections and options.
59 This class implement a new method which allow to retrieve and cast a
60 configuration option and asserts the option do exists and can be casted.
61 The config file could be edited by the user and you know... never trust
62 user input.
63
64 G{classtree Configuration}
65 """
66
68 """Configuration creator."""
69 super().__init__()
70
71 - def getas(self, section, option, typeCast=None):
72 """A more secure way to retrieve configuration options.
73
74 This method check if the section and the option is in the configuration
75 dictionary, else it raise an error. Also this method allow an optional
76 parameter for casting the result before returning it. Allowed type
77 casting are:
78 - bool: cast to bool
79 - int: cas to int
80 - float: cast to float
81 - list: cast to list
82 - intlist: cast to list and cast each element to int
83 - floatlist: cast to list and cast each element to float
84 The method makes sure the casting is possible.
85
86 @param section:
87 The section from which to retrieve the option.
88 @type section: str
89 @param option:
90 The option to retrieve inside the section.
91 @type option: str
92 @param typeCast:
93 Indicate how to cast the result. If no value are passed the
94 result is returned as a string.
95
96 @return:
97 The casted value of the given option found inside the given section.
98 @rtype:
99 str or int or bool or float or list (depends on "typeCast" param)
100
101 @raise MissingConfigurationSection:
102 If the given section cannot be found in the configuration
103 dictionary.
104 @raise MissingConfigurationOption:
105 If the given option cannot be found in the configuration dictionary.
106 @raise UnknownTypeCastError:
107 If the given typeCast value is not "bool", "int", "float", "list",
108 "intlist" or "floatlist".
109 """
110 if not self.has_section(section):
111 raise MissingConfigurationSection(section)
112 if not self.has_option(section, option):
113 raise MissingConfigurationOption(option)
114 if not typeCast or typeCast == 'str':
115 return self.get(section, option)
116 if typeCast == 'bool':
117 return self.getboolean(section, option)
118 if typeCast == 'int':
119 return self.getint(section, option)
120 if typeCast == 'float':
121 return self.getfloat(section, option)
122 if typeCast == 'list':
123 return self.get(section, option).split()
124 if typeCast == 'intlist':
125 return [int(x) for x in self.get(section, option).split()]
126 if typeCast == 'floatlist':
127 return [float(x) for x in self.get(section, option).split()]
128 raise UnknownTypeCastError(typeCast)
129
130
132 """The Driver class gather classes inctances and variables of the program.
133
134 G{classtree Driver}
135 """
136
137 - def __init__(self, callback, configFile=''):
138 """The driver class. It hold every elements needed for the prediction.
139
140 @param callback:
141 The callback is used to access the input buffers from anywhere.
142 @type callback: L{Callback}
143 @param configFile:
144 Path of the configuration file.
145 @type configFile: str
146 """
147 self.configFile = configFile
148 self.configuration = self.make_config()
149 self.callback = callback
150 self.predictorRegistry = PredictorRegistry(self.configuration)
151 self.contextMonitor = ContextMonitor(
152 self.configuration, self.predictorRegistry, callback)
153 self.predictorActivator = PredictorActivator(
154 self.configuration, self.predictorRegistry)
155 self.selector = Selector(self.configuration, self.contextMonitor)
156
158 """Request suggested words to predictors.
159
160 This method:
161 - Do the next two steps until it cannot get more suggestions.
162 - Call the L{prdct.PredictorActivator.predict} which:
163 - Call the L{prdct.Predictor.predict} method of each
164 predictors in the predictorRegistry. Each predict() method
165 should return a Prediction instance containing the suggested
166 words computed by the predictor (it may be empty).
167 - Merge the Prediction instances into a single Prediction
168 instance.
169 - Select the best suggestions in the Prediction instance and remove
170 the excess.
171 - Learn from what the user have typped.
172 - Return the selected suggestions.
173
174 @return:
175 The suggested words list.
176 @rtype: list
177 """
178 factor = 1
179 predictions = self.predictorActivator.predict(factor)
180 result = self.selector.select(predictions)
181
182 previousPredictions = predictions
183 while len(result) < self.selector.suggestions:
184 predictions = self.predictorActivator.predict(factor)
185 if len(predictions) > len(previousPredictions):
186 factor += 1
187 result = self.selector.select(predictions)
188 previousPredictions = predictions
189 else:
190 lg.warning('WARNING: Expected number of suggestions cannot be '
191 'reached.')
192 break
193 self.learn_from_buffers()
194 return result
195
197 """Simple ContextMonitor.update() wrapper for comprehension sake."""
198 self.contextMonitor.update()
199
203
205 """Close every opened predictors database."""
206 self.predictorRegistry.close_database()
207
209 """Initialize the config dictionary.
210
211 This method first try to read the configuration file and parse it into
212 a Configuration instance (dictionary).
213 If the config file is empty or dosen't exists, than a default config
214 dictionary is created.
215
216 @return:
217 The Configuration instance holding every settings (dictionary
218 style).
219 @rtype: L{drvr.Configuration}
220 """
221 config = Configuration()
222 if config.read(self.configFile) == []:
223 lg.warning('Cannot open config file "%s"' % self.configFile)
224 config.readfp(StringIO(
225 """
226 [Global]
227 language = en
228
229 [GUI]
230 font_size = 10
231
232 [MinerRegistry]
233 miners = CorpusMiner FbMiner
234
235 [CorpusMiner]
236 class = CorpusMiner
237 texts = ../txt/brown.txt
238 database = ../databases/corp.db
239 lowercase = False
240 n = 3
241
242 [DictMiner]
243 class = DictMiner
244 dictionary = /usr/share/dict/words
245 database = ../databases/dict.db
246
247 [FbMiner]
248 class = FacebookMiner
249 accesstoken = CAAUh40uO4aIBACsN37erjPUfrs0IdRZAxpbc7IhGlWpKX1REif4NPhqqD4tdZCdZBgT1J3K41ZCB3CHsjcWV78tNEDtwPwmHZBPJ3NgLV29rZCSl4vkGEqPdyEq9UNRR7OkMS1195LWO7W5jUjBrsuRYZBT7IemlZAg4FHZANrZBkaSZCwzxyrbplNYSYRB28vIdzpeLSh2s0gFZAykLoaeDQ6IKk02K9UCnK9QZD
250 database = ../databases/fb.db
251 lowercase = False
252 n = 3
253 last_update = 1433879088
254
255 [TwitterMiner]
256
257 [PredictorRegistry]
258 predictors = CorpusNgramPredictor InputNgramPredictor DictionaryPredictor
259
260 [ContextMonitor]
261 live_learning = True
262 monitored_scope = 80
263 lowercase = True
264
265 [Selector]
266 suggestions = 6
267 greedy_suggestion_threshold = 0
268
269 [PredictorActivator]
270 predict_time = 1000
271 max_partial_prediction_size = 50
272 merging_method = probabilistic
273 stoplist = ../stoplists/insanities_en.stoplist
274
275 [CorpusNgramPredictor]
276 class = WeightNgramPredictor
277 database = ../databases/corp.db
278 deltas = 0.01 0.1 0.89
279 learn = False
280
281 [InputNgramPredictor]
282 class = WeightNgramPredictor
283 database = ../databases/user.db
284 deltas = 0.01 0.1 0.89
285 learn = True
286
287 [FbNgramPredictor]
288 class = WeightNgramPredictor
289 database = ../databases/fb.db
290 deltas = 0.01 0.1 0.89
291 learn = False
292
293 [LateOccurPredictor]
294 class = LastOccurPredictor
295 lambda = 1
296 n_0 = 1
297 cutoff_threshold = 20
298
299 [MemorizePredictor]
300 class = MemorizePredictor
301 memory = ../txt/memory.txt
302 trigger = 3
303 learn = True
304
305 [DictionaryPredictor]
306 class = DictionaryPredictor
307 database = ../databases/dict.db
308 probability = 0.000001
309 """))
310 else:
311 for section in config._sections:
312 for key, value in config._sections[section].items():
313 config.set(section, key, value.replace(
314 '~', path.expanduser("~")))
315 return config
316