@@ -35,6 +35,7 @@ engines = {}
3535
3636categories = {'general': []}
3737
38+
3839def load_module(filename):
3940 modname = splitext(filename)[0]
4041 if modname in sys.modules:
@@ -50,7 +51,7 @@ if not 'engines' in settings or not settings['engines']:
5051
5152for engine_data in settings['engines']:
5253 engine_name = engine_data['engine']
53− engine = load_module(engine_name+'.py')
54+ engine = load_module(engine_name + '.py')
5455 for param_name in engine_data:
5556 if param_name == 'engine':
5657 continue
@@ -58,38 +59,50 @@ for engine_data in settings['engines']:
5859 if engine_data['categories'] == 'none':
5960 engine.categories = []
6061 else:
61− engine.categories = map(str.strip, engine_data['categories'].split(','))
62+ engine.categories = map(
63+ str.strip, engine_data['categories'].split(','))
6264 continue
6365 setattr(engine, param_name, engine_data[param_name])
6466 for engine_attr in dir(engine):
6567 if engine_attr.startswith('_'):
6668 continue
6769 if getattr(engine, engine_attr) == None:
68− print '[E] Engine config error: Missing attribute "{0}.{1}"'.format(engine.name, engine_attr)
70+ print '[E] Engine config error: Missing attribute "{0}.{1}"'.format(engine.name, engine_attr) # noqa
6971 sys.exit(1)
7072 engines[engine.name] = engine
71− engine.stats = {'result_count': 0, 'search_count': 0, 'page_load_time': 0, 'score_count': 0, 'errors': 0}
73+ engine.stats = {
74+ 'result_count': 0,
75+ 'search_count': 0,
76+ 'page_load_time': 0,
77+ 'score_count': 0,
78+ 'errors': 0
79+ }
7280 if hasattr(engine, 'categories'):
7381 for category_name in engine.categories:
7482 categories.setdefault(category_name, []).append(engine)
7583 else:
7684 categories['general'].append(engine)
7785
86+
7887def default_request_params():
79− return {'method': 'GET', 'headers': {}, 'data': {}, 'url': '', 'cookies': {}}
88+ return {
89+ 'method': 'GET', 'headers': {}, 'data': {}, 'url': '', 'cookies': {}}
90+
8091
8192def make_callback(engine_name, results, suggestions, callback, params):
8293 # creating a callback wrapper for the search engine results
8394 def process_callback(response, **kwargs):
8495 cb_res = []
8596 response.search_params = params
86− engines[engine_name].stats['page_load_time'] += (datetime.now() - params['started']).total_seconds()
97+ engines[engine_name].stats['page_load_time'] += \
98+ (datetime.now() - params['started']).total_seconds()
8799 try:
88100 search_results = callback(response)
89101 except Exception, e:
90102 engines[engine_name].stats['errors'] += 1
91103 results[engine_name] = cb_res
92− print '[E] Error with engine "{0}":\n\t{1}'.format(engine_name, str(e))
104+ print '[E] Error with engine "{0}":\n\t{1}'.format(
105+ engine_name, str(e))
93106 return
94107 for result in search_results:
95108 result['engine'] = engine_name
@@ -101,23 +114,25 @@ def make_callback(engine_name, results, suggestions, callback, params):
101114 results[engine_name] = cb_res
102115 return process_callback
103116
117+
104118def score_results(results):
105− flat_res = filter(None, chain.from_iterable(izip_longest(*results.values())))
119+ flat_res = filter(
120+ None, chain.from_iterable(izip_longest(*results.values())))
106121 flat_len = len(flat_res)
107122 engines_len = len(results)
108123 results = []
109124 # deduplication + scoring
110− for i,res in enumerate(flat_res):
125+ for i, res in enumerate(flat_res):
111126 res['parsed_url'] = urlparse(res['url'])
112127 res['engines'] = [res['engine']]
113128 weight = 1.0
114129 if hasattr(engines[res['engine']], 'weight'):
115130 weight = float(engines[res['engine']].weight)
116− score = int((flat_len - i)/engines_len)*weight+1
131+ score = int((flat_len - i) / engines_len) * weight + 1
117132 duplicated = False
118133 for new_res in results:
119− p1 = res['parsed_url'].path[:-1] if res['parsed_url'].path.endswith('/') else res['parsed_url'].path
120− p2 = new_res['parsed_url'].path[:-1] if new_res['parsed_url'].path.endswith('/') else new_res['parsed_url'].path
134+ p1 = res['parsed_url'].path[:-1] if res['parsed_url'].path.endswith('/') else res['parsed_url'].path # noqa
135+ p2 = new_res['parsed_url'].path[:-1] if new_res['parsed_url'].path.endswith('/') else new_res['parsed_url'].path # noqa
121136 if res['parsed_url'].netloc == new_res['parsed_url'].netloc and\
122137 p1 == p2 and\
123138 res['parsed_url'].query == new_res['parsed_url'].query and\
@@ -125,7 +140,7 @@ def score_results(results):
125140 duplicated = new_res
126141 break
127142 if duplicated:
128− if len(res.get('content', '')) > len(duplicated.get('content', '')):
143+ if len(res.get('content', '')) > len(duplicated.get('content', '')): # noqa
129144 duplicated['content'] = res['content']
130145 duplicated['score'] += score
131146 duplicated['engines'].append(res['engine'])
@@ -139,6 +154,7 @@ def score_results(results):
139154 results.append(res)
140155 return sorted(results, key=itemgetter('score'), reverse=True)
141156
157+
142158def search(query, request, selected_engines):
143159 global engines, categories, number_of_searches
144160 requests = []
@@ -160,13 +176,20 @@ def search(query, request, selected_engines):
160176 request_params['started'] = datetime.now()
161177 request_params = engine.request(query, request_params)
162178
163− callback = make_callback(selected_engine['name'], results, suggestions, engine.response, request_params)
164−
165− request_args = dict(headers = request_params['headers']
166− ,hooks = dict(response=callback)
167− ,cookies = request_params['cookies']
168− ,timeout = settings['server']['request_timeout']
169− )
179+ callback = make_callback(
180+ selected_engine['name'],
181+ results,
182+ suggestions,
183+ engine.response,
184+ request_params
185+ )
186+
187+ request_args = dict(
188+ headers=request_params['headers'],
189+ hooks=dict(response=callback),
190+ cookies=request_params['cookies'],
191+ timeout=settings['server']['request_timeout']
192+ )
170193
171194 if request_params['method'] == 'GET':
172195 req = grequests.get
@@ -180,7 +203,7 @@ def search(query, request, selected_engines):
180203
181204 requests.append(req(request_params['url'], **request_args))
182205 grequests.map(requests)
183− for engine_name,engine_results in results.items():
206+ for engine_name, engine_results in results.items():
184207 engines[engine_name].stats['search_count'] += 1
185208 engines[engine_name].stats['result_count'] += len(engine_results)
186209
@@ -192,6 +215,7 @@ def search(query, request, selected_engines):
192215
193216 return results, suggestions
194217
218+
195219def get_engines_stats():
196220 # TODO refactor
197221 pageloads = []
@@ -200,14 +224,15 @@ def get_engines_stats():
200224 errors = []
201225 scores_per_result = []
202226
203− max_pageload = max_results = max_score = max_errors = max_score_per_result = 0
227+ max_pageload = max_results = max_score = max_errors = max_score_per_result = 0 # noqa
204228 for engine in engines.values():
205229 if engine.stats['search_count'] == 0:
206230 continue
207− results_num = engine.stats['result_count']/float(engine.stats['search_count'])
208− load_times = engine.stats['page_load_time']/float(engine.stats['search_count'])
231+ results_num = \
232+ engine.stats['result_count'] / float(engine.stats['search_count'])
233+ load_times = engine.stats['page_load_time'] / float(engine.stats['search_count']) # noqa
209234 if results_num:
210− score = engine.stats['score_count'] / float(engine.stats['search_count'])
235+ score = engine.stats['score_count'] / float(engine.stats['search_count']) # noqa
211236 score_per_result = score / results_num
212237 else:
213238 score = score_per_result = 0.0
@@ -220,30 +245,39 @@ def get_engines_stats():
220245 results.append({'avg': results_num, 'name': engine.name})
221246 scores.append({'avg': score, 'name': engine.name})
222247 errors.append({'avg': engine.stats['errors'], 'name': engine.name})
223− scores_per_result.append({'avg': score_per_result, 'name': engine.name})
248+ scores_per_result.append({
249+ 'avg': score_per_result,
250+ 'name': engine.name
251+ })
224252
225253 for engine in pageloads:
226− engine['percentage'] = int(engine['avg']/max_pageload*100)
254+ engine['percentage'] = int(engine['avg'] / max_pageload * 100)
227255
228256 for engine in results:
229− engine['percentage'] = int(engine['avg']/max_results*100)
257+ engine['percentage'] = int(engine['avg'] / max_results * 100)
230258
231259 for engine in scores:
232− engine['percentage'] = int(engine['avg']/max_score*100)
260+ engine['percentage'] = int(engine['avg'] / max_score * 100)
233261
234262 for engine in scores_per_result:
235− engine['percentage'] = int(engine['avg']/max_score_per_result*100)
263+ engine['percentage'] = int(engine['avg'] / max_score_per_result * 100)
236264
237265 for engine in errors:
238266 if max_errors:
239− engine['percentage'] = int(float(engine['avg'])/max_errors*100)
267+ engine['percentage'] = int(float(engine['avg']) / max_errors * 100)
240268 else:
241269 engine['percentage'] = 0
242270
243−
244− return [('Page loads (sec)', sorted(pageloads, key=itemgetter('avg')))
245− ,('Number of results', sorted(results, key=itemgetter('avg'), reverse=True))
246− ,('Scores', sorted(scores, key=itemgetter('avg'), reverse=True))
247− ,('Scores per result', sorted(scores_per_result, key=itemgetter('avg'), reverse=True))
248− ,('Errors', sorted(errors, key=itemgetter('avg'), reverse=True))
249− ]
271+ return [
272+ ('Page loads (sec)', sorted(pageloads, key=itemgetter('avg'))),
273+ (
274+ 'Number of results',
275+ sorted(results, key=itemgetter('avg'), reverse=True)
276+ ),
277+ ('Scores', sorted(scores, key=itemgetter('avg'), reverse=True)),
278+ (
279+ 'Scores per result',
280+ sorted(scores_per_result, key=itemgetter('avg'), reverse=True)
281+ ),
282+ ('Errors', sorted(errors, key=itemgetter('avg'), reverse=True)),
283+ ]