Przeglądaj źródła

Merge pull request #733 from dalf/searchpy

Search architecture
Adam Tauber 8 lat temu
rodzic
commit
51eafdd471

+ 4
- 4
searx/plugins/doai_rewrite.py Wyświetl plik

20
     return None
20
     return None
21
 
21
 
22
 
22
 
23
-def on_result(request, ctx):
24
-    doi = extract_doi(ctx['result']['parsed_url'])
23
+def on_result(request, search, result):
24
+    doi = extract_doi(result['parsed_url'])
25
     if doi and len(doi) < 50:
25
     if doi and len(doi) < 50:
26
         for suffix in ('/', '.pdf', '/full', '/meta', '/abstract'):
26
         for suffix in ('/', '.pdf', '/full', '/meta', '/abstract'):
27
             if doi.endswith(suffix):
27
             if doi.endswith(suffix):
28
                 doi = doi[:-len(suffix)]
28
                 doi = doi[:-len(suffix)]
29
-        ctx['result']['url'] = 'http://doai.io/' + doi
30
-        ctx['result']['parsed_url'] = urlparse(ctx['result']['url'])
29
+        result['url'] = 'http://doai.io/' + doi
30
+        result['parsed_url'] = urlparse(ctx['result']['url'])
31
     return True
31
     return True

+ 1
- 2
searx/plugins/https_rewrite.py Wyświetl plik

220
     return result
220
     return result
221
 
221
 
222
 
222
 
223
-def on_result(request, ctx):
224
-    result = ctx['result']
223
+def on_result(request, search, result):
225
     if result['parsed_url'].scheme == 'http':
224
     if result['parsed_url'].scheme == 'http':
226
         https_url_rewrite(result)
225
         https_url_rewrite(result)
227
     return True
226
     return True

+ 8
- 8
searx/plugins/self_info.py Wyświetl plik

28
 # attach callback to the post search hook
28
 # attach callback to the post search hook
29
 #  request: flask request object
29
 #  request: flask request object
30
 #  ctx: the whole local context of the pre search hook
30
 #  ctx: the whole local context of the pre search hook
31
-def post_search(request, ctx):
32
-    if ctx['search'].pageno > 1:
31
+def post_search(request, search):
32
+    if search.search_query.pageno > 1:
33
         return True
33
         return True
34
-    if ctx['search'].query == 'ip':
34
+    if search.search_query.query == 'ip':
35
         x_forwarded_for = request.headers.getlist("X-Forwarded-For")
35
         x_forwarded_for = request.headers.getlist("X-Forwarded-For")
36
         if x_forwarded_for:
36
         if x_forwarded_for:
37
             ip = x_forwarded_for[0]
37
             ip = x_forwarded_for[0]
38
         else:
38
         else:
39
             ip = request.remote_addr
39
             ip = request.remote_addr
40
-        ctx['search'].result_container.answers.clear()
41
-        ctx['search'].result_container.answers.add(ip)
42
-    elif p.match(ctx['search'].query):
40
+        search.result_container.answers.clear()
41
+        search.result_container.answers.add(ip)
42
+    elif p.match(search.search_query.query):
43
         ua = request.user_agent
43
         ua = request.user_agent
44
-        ctx['search'].result_container.answers.clear()
45
-        ctx['search'].result_container.answers.add(ua)
44
+        search.result_container.answers.clear()
45
+        search.result_container.answers.add(ua)
46
     return True
46
     return True

+ 5
- 5
searx/plugins/tracker_url_remover.py Wyświetl plik

28
 default_on = True
28
 default_on = True
29
 
29
 
30
 
30
 
31
-def on_result(request, ctx):
32
-    query = ctx['result']['parsed_url'].query
31
+def on_result(request, search, result):
32
+    query = result['parsed_url'].query
33
 
33
 
34
     if query == "":
34
     if query == "":
35
         return True
35
         return True
37
     for reg in regexes:
37
     for reg in regexes:
38
         query = reg.sub('', query)
38
         query = reg.sub('', query)
39
 
39
 
40
-    if query != ctx['result']['parsed_url'].query:
41
-        ctx['result']['parsed_url'] = ctx['result']['parsed_url']._replace(query=query)
42
-        ctx['result']['url'] = urlunparse(ctx['result']['parsed_url'])
40
+    if query != result['parsed_url'].query:
41
+        result['parsed_url'] = result['parsed_url']._replace(query=query)
42
+        result['url'] = urlunparse(result['parsed_url'])
43
 
43
 
44
     return True
44
     return True

+ 18
- 2
searx/query.py Wyświetl plik

25
 import re
25
 import re
26
 
26
 
27
 
27
 
28
-class Query(object):
29
-    """parse query"""
28
+class RawTextQuery(object):
29
+    """parse raw text query (the value from the html input)"""
30
 
30
 
31
     def __init__(self, query, disabled_engines):
31
     def __init__(self, query, disabled_engines):
32
         self.query = query
32
         self.query = query
130
     def getFullQuery(self):
130
     def getFullQuery(self):
131
         # get full querry including whitespaces
131
         # get full querry including whitespaces
132
         return string.join(self.query_parts, '')
132
         return string.join(self.query_parts, '')
133
+
134
+
135
+class SearchQuery(object):
136
+    """container for all the search parameters (query, language, etc...)"""
137
+
138
+    def __init__(self, query, engines, categories, lang, safesearch, pageno, time_range):
139
+        self.query = query
140
+        self.engines = engines
141
+        self.categories = categories
142
+        self.lang = lang
143
+        self.safesearch = safesearch
144
+        self.pageno = pageno
145
+        self.time_range = time_range
146
+
147
+    def __str__(self):
148
+        return str(self.query) + ";" + str(self.engines)

+ 14
- 3
searx/results.py Wyświetl plik

128
         self.suggestions = set()
128
         self.suggestions = set()
129
         self.answers = set()
129
         self.answers = set()
130
         self._number_of_results = []
130
         self._number_of_results = []
131
+        self._ordered = False
132
+        self.paging = False
131
 
133
 
132
     def extend(self, engine_name, results):
134
     def extend(self, engine_name, results):
133
         for result in list(results):
135
         for result in list(results):
153
 
155
 
154
         self.results[engine_name].extend(results)
156
         self.results[engine_name].extend(results)
155
 
157
 
158
+        if not self.paging and engines[engine_name].paging:
159
+            self.paging = True
160
+
156
         for i, result in enumerate(results):
161
         for i, result in enumerate(results):
157
             try:
162
             try:
158
                 result['url'] = result['url'].decode('utf-8')
163
                 result['url'] = result['url'].decode('utf-8')
219
             with RLock():
224
             with RLock():
220
                 self._merged_results.append(result)
225
                 self._merged_results.append(result)
221
 
226
 
222
-    def get_ordered_results(self):
227
+    def order_results(self):
223
         for result in self._merged_results:
228
         for result in self._merged_results:
224
             score = result_score(result)
229
             score = result_score(result)
225
             result['score'] = score
230
             result['score'] = score
269
                 # update categoryIndex
274
                 # update categoryIndex
270
                 categoryPositions[category] = {'index': len(gresults), 'count': 8}
275
                 categoryPositions[category] = {'index': len(gresults), 'count': 8}
271
 
276
 
272
-        # return gresults
273
-        return gresults
277
+        # update _merged_results
278
+        self._ordered = True
279
+        self._merged_results = gresults
280
+
281
+    def get_ordered_results(self):
282
+        if not self._ordered:
283
+            self.order_results()
284
+        return self._merged_results
274
 
285
 
275
     def results_length(self):
286
     def results_length(self):
276
         return len(self._merged_results)
287
         return len(self._merged_results)

+ 151
- 127
searx/search.py Wyświetl plik

25
     categories, engines
25
     categories, engines
26
 )
26
 )
27
 from searx.utils import gen_useragent
27
 from searx.utils import gen_useragent
28
-from searx.query import Query
28
+from searx.query import RawTextQuery, SearchQuery
29
 from searx.results import ResultContainer
29
 from searx.results import ResultContainer
30
 from searx import logger
30
 from searx import logger
31
+from searx.plugins import plugins
31
 
32
 
32
 logger = logger.getChild('search')
33
 logger = logger.getChild('search')
33
 
34
 
127
     return process_callback
128
     return process_callback
128
 
129
 
129
 
130
 
130
-class Search(object):
131
-
132
-    """Search information container"""
133
-
134
-    def __init__(self, request):
135
-        # init vars
136
-        super(Search, self).__init__()
137
-        self.query = None
138
-        self.engines = []
139
-        self.categories = []
140
-        self.paging = False
141
-        self.pageno = 1
142
-        self.lang = 'all'
143
-        self.time_range = None
144
-        self.is_advanced = None
145
-
146
-        # set blocked engines
147
-        self.disabled_engines = request.preferences.engines.get_disabled()
148
-
149
-        self.result_container = ResultContainer()
150
-        self.request_data = {}
151
-
152
-        # set specific language if set
153
-        self.lang = request.preferences.get_value('language')
154
-
155
-        # set request method
156
-        if request.method == 'POST':
157
-            self.request_data = request.form
158
-        else:
159
-            self.request_data = request.args
160
-
161
-        # TODO better exceptions
162
-        if not self.request_data.get('q'):
163
-            raise Exception('noquery')
164
-
165
-        # set pagenumber
166
-        pageno_param = self.request_data.get('pageno', '1')
167
-        if not pageno_param.isdigit() or int(pageno_param) < 1:
168
-            pageno_param = 1
169
-
170
-        self.pageno = int(pageno_param)
171
-
172
-        # parse query, if tags are set, which change
173
-        # the serch engine or search-language
174
-        query_obj = Query(self.request_data['q'], self.disabled_engines)
175
-        query_obj.parse_query()
176
-
177
-        # set query
178
-        self.query = query_obj.getSearchQuery()
179
-
180
-        # get last selected language in query, if possible
181
-        # TODO support search with multible languages
182
-        if len(query_obj.languages):
183
-            self.lang = query_obj.languages[-1]
184
-
185
-        self.time_range = self.request_data.get('time_range')
186
-        self.is_advanced = self.request_data.get('advanced_search')
187
-
188
-        self.engines = query_obj.engines
189
-
190
-        # if engines are calculated from query,
191
-        # set categories by using that informations
192
-        if self.engines and query_obj.specific:
193
-            self.categories = list(set(engine['category']
194
-                                       for engine in self.engines))
195
-
196
-        # otherwise, using defined categories to
197
-        # calculate which engines should be used
131
+def get_search_query_from_webapp(preferences, form):
132
+    query = None
133
+    query_engines = []
134
+    query_categories = []
135
+    query_paging = False
136
+    query_pageno = 1
137
+    query_lang = 'all'
138
+    query_time_range = None
139
+
140
+    # set blocked engines
141
+    disabled_engines = preferences.engines.get_disabled()
142
+
143
+    # set specific language if set
144
+    query_lang = preferences.get_value('language')
145
+
146
+    # safesearch
147
+    query_safesearch = preferences.get_value('safesearch')
148
+
149
+    # TODO better exceptions
150
+    if not form.get('q'):
151
+        raise Exception('noquery')
152
+
153
+    # set pagenumber
154
+    pageno_param = form.get('pageno', '1')
155
+    if not pageno_param.isdigit() or int(pageno_param) < 1:
156
+        pageno_param = 1
157
+
158
+    query_pageno = int(pageno_param)
159
+
160
+    # parse query, if tags are set, which change
161
+    # the serch engine or search-language
162
+    raw_text_query = RawTextQuery(form['q'], disabled_engines)
163
+    raw_text_query.parse_query()
164
+
165
+    # set query
166
+    query = raw_text_query.getSearchQuery()
167
+
168
+    # get last selected language in query, if possible
169
+    # TODO support search with multible languages
170
+    if len(raw_text_query.languages):
171
+        query_lang = raw_text_query.languages[-1]
172
+
173
+    query_time_range = form.get('time_range')
174
+
175
+    query_engines = raw_text_query.engines
176
+
177
+    # if engines are calculated from query,
178
+    # set categories by using that informations
179
+    if query_engines and raw_text_query.specific:
180
+        query_categories = list(set(engine['category']
181
+                                    for engine in query_engines))
182
+
183
+    # otherwise, using defined categories to
184
+    # calculate which engines should be used
185
+    else:
186
+        # set categories/engines
187
+        load_default_categories = True
188
+        for pd_name, pd in form.items():
189
+            if pd_name == 'categories':
190
+                query_categories.extend(categ for categ in map(unicode.strip, pd.split(',')) if categ in categories)
191
+            elif pd_name == 'engines':
192
+                pd_engines = [{'category': engines[engine].categories[0],
193
+                               'name': engine}
194
+                              for engine in map(unicode.strip, pd.split(',')) if engine in engines]
195
+                if pd_engines:
196
+                    query_engines.extend(pd_engines)
197
+                    load_default_categories = False
198
+            elif pd_name.startswith('category_'):
199
+                category = pd_name[9:]
200
+
201
+                # if category is not found in list, skip
202
+                if category not in categories:
203
+                    continue
204
+
205
+                if pd != 'off':
206
+                    # add category to list
207
+                    query_categories.append(category)
208
+                elif category in query_categories:
209
+                    # remove category from list if property is set to 'off'
210
+                    query_categories.remove(category)
211
+
212
+        if not load_default_categories:
213
+            if not query_categories:
214
+                query_categories = list(set(engine['category']
215
+                                            for engine in engines))
198
         else:
216
         else:
199
-            # set categories/engines
200
-            load_default_categories = True
201
-            for pd_name, pd in self.request_data.items():
202
-                if pd_name == 'categories':
203
-                    self.categories.extend(categ for categ in map(unicode.strip, pd.split(',')) if categ in categories)
204
-                elif pd_name == 'engines':
205
-                    pd_engines = [{'category': engines[engine].categories[0],
206
-                                   'name': engine}
207
-                                  for engine in map(unicode.strip, pd.split(',')) if engine in engines]
208
-                    if pd_engines:
209
-                        self.engines.extend(pd_engines)
210
-                        load_default_categories = False
211
-                elif pd_name.startswith('category_'):
212
-                    category = pd_name[9:]
213
-
214
-                    # if category is not found in list, skip
215
-                    if category not in categories:
216
-                        continue
217
-
218
-                    if pd != 'off':
219
-                        # add category to list
220
-                        self.categories.append(category)
221
-                    elif category in self.categories:
222
-                        # remove category from list if property is set to 'off'
223
-                        self.categories.remove(category)
224
-
225
-            if not load_default_categories:
226
-                if not self.categories:
227
-                    self.categories = list(set(engine['category']
228
-                                               for engine in self.engines))
229
-                return
230
-
231
             # if no category is specified for this search,
217
             # if no category is specified for this search,
232
             # using user-defined default-configuration which
218
             # using user-defined default-configuration which
233
             # (is stored in cookie)
219
             # (is stored in cookie)
234
-            if not self.categories:
235
-                cookie_categories = request.preferences.get_value('categories')
220
+            if not query_categories:
221
+                cookie_categories = preferences.get_value('categories')
236
                 for ccateg in cookie_categories:
222
                 for ccateg in cookie_categories:
237
                     if ccateg in categories:
223
                     if ccateg in categories:
238
-                        self.categories.append(ccateg)
224
+                        query_categories.append(ccateg)
239
 
225
 
240
             # if still no category is specified, using general
226
             # if still no category is specified, using general
241
             # as default-category
227
             # as default-category
242
-            if not self.categories:
243
-                self.categories = ['general']
228
+            if not query_categories:
229
+                query_categories = ['general']
244
 
230
 
245
             # using all engines for that search, which are
231
             # using all engines for that search, which are
246
             # declared under the specific categories
232
             # declared under the specific categories
247
-            for categ in self.categories:
248
-                self.engines.extend({'category': categ,
249
-                                     'name': engine.name}
250
-                                    for engine in categories[categ]
251
-                                    if (engine.name, categ) not in self.disabled_engines)
233
+            for categ in query_categories:
234
+                query_engines.extend({'category': categ,
235
+                                      'name': engine.name}
236
+                                     for engine in categories[categ]
237
+                                     if (engine.name, categ) not in disabled_engines)
252
 
238
 
253
-        # remove suspended engines
254
-        self.engines = [e for e in self.engines
255
-                        if engines[e['name']].suspend_end_time <= time()]
239
+    return SearchQuery(query, query_engines, query_categories,
240
+                       query_lang, query_safesearch, query_pageno, query_time_range)
241
+
242
+
243
+class Search(object):
244
+
245
+    """Search information container"""
246
+
247
+    def __init__(self, search_query):
248
+        # init vars
249
+        super(Search, self).__init__()
250
+        self.search_query = search_query
251
+        self.result_container = ResultContainer()
256
 
252
 
257
     # do search-request
253
     # do search-request
258
-    def search(self, request):
254
+    def search(self):
259
         global number_of_searches
255
         global number_of_searches
260
 
256
 
261
         # init vars
257
         # init vars
268
         # user_agent = request.headers.get('User-Agent', '')
264
         # user_agent = request.headers.get('User-Agent', '')
269
         user_agent = gen_useragent()
265
         user_agent = gen_useragent()
270
 
266
 
267
+        search_query = self.search_query
268
+
271
         # start search-reqest for all selected engines
269
         # start search-reqest for all selected engines
272
-        for selected_engine in self.engines:
270
+        for selected_engine in search_query.engines:
273
             if selected_engine['name'] not in engines:
271
             if selected_engine['name'] not in engines:
274
                 continue
272
                 continue
275
 
273
 
276
             engine = engines[selected_engine['name']]
274
             engine = engines[selected_engine['name']]
277
 
275
 
276
+            # skip suspended engines
277
+            if engine.suspend_end_time and engine.suspend_end_time <= time():
278
+                continue
279
+
278
             # if paging is not supported, skip
280
             # if paging is not supported, skip
279
-            if self.pageno > 1 and not engine.paging:
281
+            if search_query.pageno > 1 and not engine.paging:
280
                 continue
282
                 continue
281
 
283
 
282
             # if search-language is set and engine does not
284
             # if search-language is set and engine does not
283
             # provide language-support, skip
285
             # provide language-support, skip
284
-            if self.lang != 'all' and not engine.language_support:
286
+            if search_query.lang != 'all' and not engine.language_support:
285
                 continue
287
                 continue
286
 
288
 
287
-            if self.time_range and not engine.time_range_support:
289
+            # if time_range is not supported, skip
290
+            if search_query.time_range and not engine.time_range_support:
288
                 continue
291
                 continue
289
 
292
 
290
             # set default request parameters
293
             # set default request parameters
292
             request_params['headers']['User-Agent'] = user_agent
295
             request_params['headers']['User-Agent'] = user_agent
293
             request_params['category'] = selected_engine['category']
296
             request_params['category'] = selected_engine['category']
294
             request_params['started'] = time()
297
             request_params['started'] = time()
295
-            request_params['pageno'] = self.pageno
298
+            request_params['pageno'] = search_query.pageno
296
 
299
 
297
             if hasattr(engine, 'language') and engine.language:
300
             if hasattr(engine, 'language') and engine.language:
298
                 request_params['language'] = engine.language
301
                 request_params['language'] = engine.language
299
             else:
302
             else:
300
-                request_params['language'] = self.lang
303
+                request_params['language'] = search_query.lang
301
 
304
 
302
             # 0 = None, 1 = Moderate, 2 = Strict
305
             # 0 = None, 1 = Moderate, 2 = Strict
303
-            request_params['safesearch'] = request.preferences.get_value('safesearch')
304
-            request_params['time_range'] = self.time_range
305
-            request_params['advanced_search'] = self.is_advanced
306
+            request_params['safesearch'] = search_query.safesearch
307
+            request_params['time_range'] = search_query.time_range
306
 
308
 
307
             # update request parameters dependent on
309
             # update request parameters dependent on
308
             # search-engine (contained in engines folder)
310
             # search-engine (contained in engines folder)
309
-            engine.request(self.query.encode('utf-8'), request_params)
311
+            engine.request(search_query.query.encode('utf-8'), request_params)
310
 
312
 
311
             if request_params['url'] is None:
313
             if request_params['url'] is None:
312
                 # TODO add support of offline engines
314
                 # TODO add support of offline engines
346
                              selected_engine['name']))
348
                              selected_engine['name']))
347
 
349
 
348
         if not requests:
350
         if not requests:
349
-            return self
351
+            return self.result_container
350
         # send all search-request
352
         # send all search-request
351
         threaded_requests(requests)
353
         threaded_requests(requests)
352
         start_new_thread(gc.collect, tuple())
354
         start_new_thread(gc.collect, tuple())
353
 
355
 
354
         # return results, suggestions, answers and infoboxes
356
         # return results, suggestions, answers and infoboxes
355
-        return self
357
+        return self.result_container
358
+
359
+
360
+class SearchWithPlugins(Search):
361
+
362
+    """Similar to the Search class but call the plugins."""
363
+
364
+    def __init__(self, search_query, request):
365
+        super(SearchWithPlugins, self).__init__(search_query)
366
+        self.request = request
367
+
368
+    def search(self):
369
+        if plugins.call('pre_search', self.request, self):
370
+            super(SearchWithPlugins, self).search()
371
+
372
+        plugins.call('post_search', self.request, self)
373
+
374
+        results = self.result_container.get_ordered_results()
375
+
376
+        for result in results:
377
+            plugins.call('on_result', self.request, self, result)
378
+
379
+        return self.result_container

+ 47
- 49
searx/webapp.py Wyświetl plik

62
 )
62
 )
63
 from searx.version import VERSION_STRING
63
 from searx.version import VERSION_STRING
64
 from searx.languages import language_codes
64
 from searx.languages import language_codes
65
-from searx.search import Search
66
-from searx.query import Query
65
+from searx.search import Search, SearchWithPlugins, get_search_query_from_webapp
66
+from searx.query import RawTextQuery, SearchQuery
67
 from searx.autocomplete import searx_bang, backends as autocomplete_backends
67
 from searx.autocomplete import searx_bang, backends as autocomplete_backends
68
 from searx.plugins import plugins
68
 from searx.plugins import plugins
69
 from searx.preferences import Preferences, ValidationException
69
 from searx.preferences import Preferences, ValidationException
373
         logger.warning('Invalid config')
373
         logger.warning('Invalid config')
374
     request.preferences = preferences
374
     request.preferences = preferences
375
 
375
 
376
+    # request.form
376
     request.form = dict(request.form.items())
377
     request.form = dict(request.form.items())
377
     for k, v in request.args.items():
378
     for k, v in request.args.items():
378
         if k not in request.form:
379
         if k not in request.form:
379
             request.form[k] = v
380
             request.form[k] = v
380
 
381
 
382
+    # request.user_plugins
381
     request.user_plugins = []
383
     request.user_plugins = []
382
     allowed_plugins = preferences.plugins.get_enabled()
384
     allowed_plugins = preferences.plugins.get_enabled()
383
     disabled_plugins = preferences.plugins.get_disabled()
385
     disabled_plugins = preferences.plugins.get_disabled()
400
             'index.html',
402
             'index.html',
401
         )
403
         )
402
 
404
 
405
+    # search
406
+    search_query = None
407
+    result_container = None
403
     try:
408
     try:
404
-        search = Search(request)
409
+        search_query = get_search_query_from_webapp(request.preferences, request.form)
410
+        # search = Search(search_query) #  without plugins
411
+        search = SearchWithPlugins(search_query, request)
412
+        result_container = search.search()
405
     except:
413
     except:
406
         return render(
414
         return render(
407
             'index.html',
415
             'index.html',
408
         )
416
         )
409
 
417
 
410
-    if plugins.call('pre_search', request, locals()):
411
-        search.search(request)
418
+    results = result_container.get_ordered_results()
412
 
419
 
413
-    plugins.call('post_search', request, locals())
414
-
415
-    results = search.result_container.get_ordered_results()
420
+    # UI
421
+    advanced_search = request.form.get('advanced_search', None)
422
+    output_format = request.form.get('format', 'html')
423
+    if output_format not in ['html', 'csv', 'json', 'rss']:
424
+        output_format = 'html'
416
 
425
 
426
+    # output
417
     for result in results:
427
     for result in results:
418
-
419
-        plugins.call('on_result', request, locals())
420
-        if not search.paging and engines[result['engine']].paging:
421
-            search.paging = True
422
-
423
-        if search.request_data.get('format', 'html') == 'html':
428
+        if output_format == 'html':
424
             if 'content' in result and result['content']:
429
             if 'content' in result and result['content']:
425
-                result['content'] = highlight_content(result['content'][:1024], search.query.encode('utf-8'))
426
-            result['title'] = highlight_content(result['title'], search.query.encode('utf-8'))
430
+                result['content'] = highlight_content(result['content'][:1024], search_query.query.encode('utf-8'))
431
+            result['title'] = highlight_content(result['title'], search_query.query.encode('utf-8'))
427
         else:
432
         else:
428
             if result.get('content'):
433
             if result.get('content'):
429
                 result['content'] = html_to_text(result['content']).strip()
434
                 result['content'] = html_to_text(result['content']).strip()
450
                 else:
455
                 else:
451
                     result['publishedDate'] = format_date(result['publishedDate'])
456
                     result['publishedDate'] = format_date(result['publishedDate'])
452
 
457
 
453
-    number_of_results = search.result_container.results_number()
454
-    if number_of_results < search.result_container.results_length():
458
+    number_of_results = result_container.results_number()
459
+    if number_of_results < result_container.results_length():
455
         number_of_results = 0
460
         number_of_results = 0
456
 
461
 
457
-    if search.request_data.get('format') == 'json':
458
-        return Response(json.dumps({'query': search.query,
462
+    if output_format == 'json':
463
+        return Response(json.dumps({'query': search_query.query,
459
                                     'number_of_results': number_of_results,
464
                                     'number_of_results': number_of_results,
460
                                     'results': results}),
465
                                     'results': results}),
461
                         mimetype='application/json')
466
                         mimetype='application/json')
462
-    elif search.request_data.get('format') == 'csv':
467
+    elif output_format == 'csv':
463
         csv = UnicodeWriter(cStringIO.StringIO())
468
         csv = UnicodeWriter(cStringIO.StringIO())
464
         keys = ('title', 'url', 'content', 'host', 'engine', 'score')
469
         keys = ('title', 'url', 'content', 'host', 'engine', 'score')
465
         csv.writerow(keys)
470
         csv.writerow(keys)
468
             csv.writerow([row.get(key, '') for key in keys])
473
             csv.writerow([row.get(key, '') for key in keys])
469
         csv.stream.seek(0)
474
         csv.stream.seek(0)
470
         response = Response(csv.stream.read(), mimetype='application/csv')
475
         response = Response(csv.stream.read(), mimetype='application/csv')
471
-        cont_disp = 'attachment;Filename=searx_-_{0}.csv'.format(search.query.encode('utf-8'))
476
+        cont_disp = 'attachment;Filename=searx_-_{0}.csv'.format(search_query.query.encode('utf-8'))
472
         response.headers.add('Content-Disposition', cont_disp)
477
         response.headers.add('Content-Disposition', cont_disp)
473
         return response
478
         return response
474
-    elif search.request_data.get('format') == 'rss':
479
+    elif output_format == 'rss':
475
         response_rss = render(
480
         response_rss = render(
476
             'opensearch_response_rss.xml',
481
             'opensearch_response_rss.xml',
477
             results=results,
482
             results=results,
478
-            q=search.request_data['q'],
483
+            q=request.form['q'],
479
             number_of_results=number_of_results,
484
             number_of_results=number_of_results,
480
             base_url=get_base_url()
485
             base_url=get_base_url()
481
         )
486
         )
484
     return render(
489
     return render(
485
         'results.html',
490
         'results.html',
486
         results=results,
491
         results=results,
487
-        q=search.request_data['q'],
488
-        selected_categories=search.categories,
489
-        paging=search.paging,
492
+        q=request.form['q'],
493
+        selected_categories=search_query.categories,
494
+        pageno=search_query.pageno,
495
+        time_range=search_query.time_range,
490
         number_of_results=format_decimal(number_of_results),
496
         number_of_results=format_decimal(number_of_results),
491
-        pageno=search.pageno,
492
-        advanced_search=search.is_advanced,
493
-        time_range=search.time_range,
497
+        advanced_search=advanced_search,
498
+        suggestions=result_container.suggestions,
499
+        answers=result_container.answers,
500
+        infoboxes=result_container.infoboxes,
501
+        paging=result_container.paging,
494
         base_url=get_base_url(),
502
         base_url=get_base_url(),
495
-        suggestions=search.result_container.suggestions,
496
-        answers=search.result_container.answers,
497
-        infoboxes=search.result_container.infoboxes,
498
         theme=get_current_theme_name(),
503
         theme=get_current_theme_name(),
499
         favicons=global_favicons[themes.index(get_current_theme_name())]
504
         favicons=global_favicons[themes.index(get_current_theme_name())]
500
     )
505
     )
511
 @app.route('/autocompleter', methods=['GET', 'POST'])
516
 @app.route('/autocompleter', methods=['GET', 'POST'])
512
 def autocompleter():
517
 def autocompleter():
513
     """Return autocompleter results"""
518
     """Return autocompleter results"""
514
-    request_data = {}
515
-
516
-    # select request method
517
-    if request.method == 'POST':
518
-        request_data = request.form
519
-    else:
520
-        request_data = request.args
521
 
519
 
522
     # set blocked engines
520
     # set blocked engines
523
     disabled_engines = request.preferences.engines.get_disabled()
521
     disabled_engines = request.preferences.engines.get_disabled()
524
 
522
 
525
     # parse query
523
     # parse query
526
-    query = Query(request_data.get('q', '').encode('utf-8'), disabled_engines)
527
-    query.parse_query()
524
+    raw_text_query = RawTextQuery(request.form.get('q', '').encode('utf-8'), disabled_engines)
525
+    raw_text_query.parse_query()
528
 
526
 
529
     # check if search query is set
527
     # check if search query is set
530
-    if not query.getSearchQuery():
528
+    if not raw_text_query.getSearchQuery():
531
         return '', 400
529
         return '', 400
532
 
530
 
533
     # run autocompleter
531
     # run autocompleter
534
     completer = autocomplete_backends.get(request.preferences.get_value('autocomplete'))
532
     completer = autocomplete_backends.get(request.preferences.get_value('autocomplete'))
535
 
533
 
536
     # parse searx specific autocompleter results like !bang
534
     # parse searx specific autocompleter results like !bang
537
-    raw_results = searx_bang(query)
535
+    raw_results = searx_bang(raw_text_query)
538
 
536
 
539
     # normal autocompletion results only appear if max 3 inner results returned
537
     # normal autocompletion results only appear if max 3 inner results returned
540
     if len(raw_results) <= 3 and completer:
538
     if len(raw_results) <= 3 and completer:
545
         else:
543
         else:
546
             language = language.split('_')[0]
544
             language = language.split('_')[0]
547
         # run autocompletion
545
         # run autocompletion
548
-        raw_results.extend(completer(query.getSearchQuery(), language))
546
+        raw_results.extend(completer(raw_text_query.getSearchQuery(), language))
549
 
547
 
550
     # parse results (write :language and !engine back to result string)
548
     # parse results (write :language and !engine back to result string)
551
     results = []
549
     results = []
552
     for result in raw_results:
550
     for result in raw_results:
553
-        query.changeSearchQuery(result)
551
+        raw_text_query.changeSearchQuery(result)
554
 
552
 
555
         # add parsed result
553
         # add parsed result
556
-        results.append(query.getFullQuery())
554
+        results.append(raw_text_query.getFullQuery())
557
 
555
 
558
     # return autocompleter results
556
     # return autocompleter results
559
-    if request_data.get('format') == 'x-suggestions':
560
-        return Response(json.dumps([query.query, results]),
557
+    if request.form.get('format') == 'x-suggestions':
558
+        return Response(json.dumps([raw_text_query.query, results]),
561
                         mimetype='application/json')
559
                         mimetype='application/json')
562
 
560
 
563
     return Response(json.dumps(results),
561
     return Response(json.dumps(results),

+ 26
- 27
tests/unit/test_plugins.py Wyświetl plik

6
 
6
 
7
 
7
 
8
 def get_search_mock(query, **kwargs):
8
 def get_search_mock(query, **kwargs):
9
-    return {'search': Mock(query=query,
10
-                           result_container=Mock(answers=set()),
11
-                           **kwargs)}
9
+    return Mock(search_query=Mock(query=query, **kwargs),
10
+                result_container=Mock(answers=set()))
12
 
11
 
13
 
12
 
14
 class PluginStoreTest(SearxTestCase):
13
 class PluginStoreTest(SearxTestCase):
52
         request = Mock(user_plugins=store.plugins,
51
         request = Mock(user_plugins=store.plugins,
53
                        remote_addr='127.0.0.1')
52
                        remote_addr='127.0.0.1')
54
         request.headers.getlist.return_value = []
53
         request.headers.getlist.return_value = []
55
-        ctx = get_search_mock(query='ip', pageno=1)
56
-        store.call('post_search', request, ctx)
57
-        self.assertTrue('127.0.0.1' in ctx['search'].result_container.answers)
54
+        search = get_search_mock(query='ip', pageno=1)
55
+        store.call('post_search', request, search)
56
+        self.assertTrue('127.0.0.1' in search.result_container.answers)
58
 
57
 
59
-        ctx = get_search_mock(query='ip', pageno=2)
60
-        store.call('post_search', request, ctx)
61
-        self.assertFalse('127.0.0.1' in ctx['search'].result_container.answers)
58
+        search = get_search_mock(query='ip', pageno=2)
59
+        store.call('post_search', request, search)
60
+        self.assertFalse('127.0.0.1' in search.result_container.answers)
62
 
61
 
63
         # User agent test
62
         # User agent test
64
         request = Mock(user_plugins=store.plugins,
63
         request = Mock(user_plugins=store.plugins,
65
                        user_agent='Mock')
64
                        user_agent='Mock')
66
         request.headers.getlist.return_value = []
65
         request.headers.getlist.return_value = []
67
 
66
 
68
-        ctx = get_search_mock(query='user-agent', pageno=1)
69
-        store.call('post_search', request, ctx)
70
-        self.assertTrue('Mock' in ctx['search'].result_container.answers)
67
+        search = get_search_mock(query='user-agent', pageno=1)
68
+        store.call('post_search', request, search)
69
+        self.assertTrue('Mock' in search.result_container.answers)
71
 
70
 
72
-        ctx = get_search_mock(query='user-agent', pageno=2)
73
-        store.call('post_search', request, ctx)
74
-        self.assertFalse('Mock' in ctx['search'].result_container.answers)
71
+        search = get_search_mock(query='user-agent', pageno=2)
72
+        store.call('post_search', request, search)
73
+        self.assertFalse('Mock' in search.result_container.answers)
75
 
74
 
76
-        ctx = get_search_mock(query='user-agent', pageno=1)
77
-        store.call('post_search', request, ctx)
78
-        self.assertTrue('Mock' in ctx['search'].result_container.answers)
75
+        search = get_search_mock(query='user-agent', pageno=1)
76
+        store.call('post_search', request, search)
77
+        self.assertTrue('Mock' in search.result_container.answers)
79
 
78
 
80
-        ctx = get_search_mock(query='user-agent', pageno=2)
81
-        store.call('post_search', request, ctx)
82
-        self.assertFalse('Mock' in ctx['search'].result_container.answers)
79
+        search = get_search_mock(query='user-agent', pageno=2)
80
+        store.call('post_search', request, search)
81
+        self.assertFalse('Mock' in search.result_container.answers)
83
 
82
 
84
-        ctx = get_search_mock(query='What is my User-Agent?', pageno=1)
85
-        store.call('post_search', request, ctx)
86
-        self.assertTrue('Mock' in ctx['search'].result_container.answers)
83
+        search = get_search_mock(query='What is my User-Agent?', pageno=1)
84
+        store.call('post_search', request, search)
85
+        self.assertTrue('Mock' in search.result_container.answers)
87
 
86
 
88
-        ctx = get_search_mock(query='What is my User-Agent?', pageno=2)
89
-        store.call('post_search', request, ctx)
90
-        self.assertFalse('Mock' in ctx['search'].result_container.answers)
87
+        search = get_search_mock(query='What is my User-Agent?', pageno=2)
88
+        store.call('post_search', request, search)
89
+        self.assertFalse('Mock' in search.result_container.answers)