[Python-modules-commits] [django-haystack] 01/04: Import django-haystack_2.6.1.orig.tar.gz

Michael Fladischer fladi at moszumanska.debian.org
Wed May 31 09:54:16 UTC 2017


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch experimental
in repository django-haystack.

commit b533a1dbabab2adf7aa63e3a0280b9945f7b1291
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Wed May 31 10:19:21 2017 +0200

    Import django-haystack_2.6.1.orig.tar.gz
---
 README.rst                        |  1 +
 docs/rich_content_extraction.rst  |  4 ++--
 docs/tutorial.rst                 | 11 ++++++++++-
 haystack/backends/__init__.py     | 29 +++++++++++------------------
 haystack/backends/solr_backend.py | 25 +++++++++++++++----------
 haystack/fields.py                |  2 +-
 haystack/indexes.py               | 14 ++++++++++----
 haystack/views.py                 |  2 +-
 test_haystack/test_fields.py      |  8 ++++++++
 test_haystack/test_views.py       | 10 +++++++++-
 10 files changed, 68 insertions(+), 38 deletions(-)

diff --git a/README.rst b/README.rst
index b8c47db..b9879b8 100644
--- a/README.rst
+++ b/README.rst
@@ -33,6 +33,7 @@ Documentation
 =============
 
 * Development version: http://docs.haystacksearch.org/
+* v2.6.X: https://django-haystack.readthedocs.io/en/v2.6.0/
 * v2.5.X: https://django-haystack.readthedocs.io/en/v2.5.0/
 * v2.4.X: https://django-haystack.readthedocs.io/en/v2.4.1/
 * v2.3.X: https://django-haystack.readthedocs.io/en/v2.3.0/
diff --git a/docs/rich_content_extraction.rst b/docs/rich_content_extraction.rst
index a23c85d..a6e4da7 100644
--- a/docs/rich_content_extraction.rst
+++ b/docs/rich_content_extraction.rst
@@ -27,7 +27,7 @@ Indexing Extracted Content
 
 Generally you will want to include the extracted text in your main document
 field along with everything else specified in your search template. This example
-shows how to override a hypothetical ``FileIndex``'s ``prepare`` method to 
+shows how to override a hypothetical ``FileIndex``'s ``prepare`` method to
 include the extract content along with information retrieved from the database::
 
     def prepare(self, obj):
@@ -39,7 +39,7 @@ include the extract content along with information retrieved from the database::
         # manually before calling extract_file_contents:
         file_obj = obj.the_file.open()
 
-        extracted_data = self.backend.extract_file_contents(file_obj)
+        extracted_data = self.get_backend().extract_file_contents(file_obj)
 
         # Now we'll finally perform the template processing to render the
         # text field with *all* of our metadata visible for templating:
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 76b0388..6e46bf5 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -127,7 +127,7 @@ Example::
 Elasticsearch
 ~~~~~~~~~~~~~
 
-Example::
+Example (ElasticSearch 1.x)::
 
     HAYSTACK_CONNECTIONS = {
         'default': {
@@ -137,6 +137,15 @@ Example::
         },
     }
 
+Example (ElasticSearch 2.x)::
+
+    HAYSTACK_CONNECTIONS = {
+        'default': {
+            'ENGINE': 'haystack.backends.elasticsearch2_backend.Elasticsearch2SearchEngine',
+            'URL': 'http://127.0.0.1:9200/',
+            'INDEX_NAME': 'haystack',
+        },
+    }
 
 Whoosh
 ~~~~~~
diff --git a/haystack/backends/__init__.py b/haystack/backends/__init__.py
index 0ce6c4c..5074499 100644
--- a/haystack/backends/__init__.py
+++ b/haystack/backends/__init__.py
@@ -20,6 +20,7 @@ VALID_GAPS = ['year', 'month', 'day', 'hour', 'minute', 'second']
 
 SPELLING_SUGGESTION_HAS_NOT_RUN = object()
 
+
 def log_query(func):
     """
     A decorator for pseudo-logging search queries. Used in the ``SearchBackend``
@@ -77,7 +78,7 @@ class BaseSearchBackend(object):
         self.silently_fail = connection_options.get('SILENTLY_FAIL', True)
         self.distance_available = connection_options.get('DISTANCE_AVAILABLE', False)
 
-    def update(self, index, iterable):
+    def update(self, index, iterable, commit=True):
         """
         Updates the backend when given a SearchIndex and a collection of
         documents.
@@ -251,10 +252,8 @@ class SearchNode(tree.Node):
 
     def __str__(self):
         if self.negated:
-            return '(NOT (%s: %s))' % (self.connector, ', '.join([str(c) for c
-                    in self.children]))
-        return '(%s: %s)' % (self.connector, ', '.join([str(c) for c in
-                self.children]))
+            return '(NOT (%s: %s))' % (self.connector, ', '.join([str(c) for c in self.children]))
+        return '(%s: %s)' % (self.connector, ', '.join([str(c) for c in self.children]))
 
     def __deepcopy__(self, memodict):
         """
@@ -299,14 +298,12 @@ class SearchNode(tree.Node):
         if len(self.children) < 2:
             self.connector = conn_type
         if self.connector == conn_type:
-            if isinstance(node, SearchNode) and (node.connector == conn_type or
-                    len(node) == 1):
+            if isinstance(node, SearchNode) and (node.connector == conn_type or len(node) == 1):
                 self.children.extend(node.children)
             else:
                 self.children.append(node)
         else:
-            obj = self._new_instance(self.children, self.connector,
-                    self.negated)
+            obj = self._new_instance(self.children, self.connector, self.negated)
             self.connector = conn_type
             self.children = [obj, node]
 
@@ -320,8 +317,7 @@ class SearchNode(tree.Node):
         Interpreting the meaning of this negate is up to client code. This
         method is useful for implementing "not" arrangements.
         """
-        self.children = [self._new_instance(self.children, self.connector,
-                not self.negated)]
+        self.children = [self._new_instance(self.children, self.connector, not self.negated)]
         self.connector = self.default
 
     def start_subtree(self, conn_type):
@@ -333,13 +329,11 @@ class SearchNode(tree.Node):
         if len(self.children) == 1:
             self.connector = conn_type
         elif self.connector != conn_type:
-            self.children = [self._new_instance(self.children, self.connector,
-                    self.negated)]
+            self.children = [self._new_instance(self.children, self.connector, self.negated)]
             self.connector = conn_type
             self.negated = False
 
-        self.subtree_parents.append(self.__class__(self.children,
-                self.connector, self.negated))
+        self.subtree_parents.append(self.__class__(self.children, self.connector, self.negated))
         self.connector = self.default
         self.negated = False
         self.children = []
@@ -728,7 +722,6 @@ class BaseSearchQuery(object):
         """
         raise NotImplementedError("Subclasses must provide a way to generate query fragments via the 'build_query_fragment' method.")
 
-
     # Standard methods to alter the query.
 
     def clean(self, query_fragment):
@@ -856,7 +849,7 @@ class BaseSearchQuery(object):
         self._more_like_this = True
         self._mlt_instance = model_instance
 
-    def add_stats_query(self,stats_field,stats_facets):
+    def add_stats_query(self, stats_field, stats_facets):
         """Adds stats and stats_facets queries for the Solr backend."""
         self.stats[stats_field] = stats_facets
 
@@ -902,7 +895,7 @@ class BaseSearchQuery(object):
     def add_date_facet(self, field, start_date, end_date, gap_by, gap_amount=1):
         """Adds a date-based facet on a field."""
         from haystack import connections
-        if not gap_by in VALID_GAPS:
+        if gap_by not in VALID_GAPS:
             raise FacetingError("The gap_by ('%s') must be one of the following: %s." % (gap_by, ', '.join(VALID_GAPS)))
 
         details = {
diff --git a/haystack/backends/solr_backend.py b/haystack/backends/solr_backend.py
index 533410e..fa1b20a 100644
--- a/haystack/backends/solr_backend.py
+++ b/haystack/backends/solr_backend.py
@@ -42,10 +42,11 @@ class SolrSearchBackend(BaseSearchBackend):
     def __init__(self, connection_alias, **connection_options):
         super(SolrSearchBackend, self).__init__(connection_alias, **connection_options)
 
-        if not 'URL' in connection_options:
+        if 'URL' not in connection_options:
             raise ImproperlyConfigured("You must specify a 'URL' in your settings for connection '%s'." % connection_alias)
 
-        self.conn = Solr(connection_options['URL'], timeout=self.timeout, **connection_options.get('KWARGS', {}))
+        self.conn = Solr(connection_options['URL'], timeout=self.timeout,
+                         **connection_options.get('KWARGS', {}))
         self.log = logging.getLogger('haystack')
 
     def update(self, index, iterable, commit=True):
@@ -139,7 +140,10 @@ class SolrSearchBackend(BaseSearchBackend):
             self.log.error("Failed to query Solr using '%s': %s", query_string, e, exc_info=True)
             raw_results = EmptyResults()
 
-        return self._process_results(raw_results, highlight=kwargs.get('highlight'), result_class=kwargs.get('result_class', SearchResult), distance_point=kwargs.get('distance_point'))
+        return self._process_results(raw_results,
+                                     highlight=kwargs.get('highlight'),
+                                     result_class=kwargs.get('result_class', SearchResult),
+                                     distance_point=kwargs.get('distance_point'))
 
     def build_search_kwargs(self, query_string, sort_by=None, start_offset=0, end_offset=None,
                             fields='', highlight=False, facets=None,
@@ -193,7 +197,7 @@ class SolrSearchBackend(BaseSearchBackend):
                 # this makes option dicts shorter: {'maxAnalyzedChars': 42}
                 # and lets some of options be used as keyword arguments: `.highlight(preserveMulti=False)`
                 kwargs.update({
-                    key if key.startswith("hl.") else ('hl.' + key): highlight[key] 
+                    key if key.startswith("hl.") else ('hl.' + key): highlight[key]
                     for key in highlight.keys()
                 })
 
@@ -367,8 +371,8 @@ class SolrSearchBackend(BaseSearchBackend):
         if result_class is None:
             result_class = SearchResult
 
-        if hasattr(raw_results,'stats'):
-            stats = raw_results.stats.get('stats_fields',{})
+        if hasattr(raw_results, 'stats'):
+            stats = raw_results.stats.get('stats_fields', {})
 
         if hasattr(raw_results, 'facets'):
             facets = {
@@ -381,7 +385,8 @@ class SolrSearchBackend(BaseSearchBackend):
                 for facet_field in facets[key]:
                     # Convert to a two-tuple, as Solr's json format returns a list of
                     # pairs.
-                    facets[key][facet_field] = list(zip(facets[key][facet_field][::2], facets[key][facet_field][1::2]))
+                    facets[key][facet_field] = list(zip(facets[key][facet_field][::2],
+                                                        facets[key][facet_field][1::2]))
 
         if self.include_spelling and hasattr(raw_results, 'spellcheck'):
             # Solr 5+ changed the JSON response format so the suggestions will be key-value mapped rather
@@ -504,7 +509,7 @@ class SolrSearchBackend(BaseSearchBackend):
 
         return (content_field_name, schema_fields)
 
-    def extract_file_contents(self, file_obj):
+    def extract_file_contents(self, file_obj, **kwargs):
         """Extract text and metadata from a structured file (PDF, MS Word, etc.)
 
         Uses the Solr ExtractingRequestHandler, which is based on Apache Tika.
@@ -530,7 +535,7 @@ class SolrSearchBackend(BaseSearchBackend):
         """
 
         try:
-            return self.conn.extract(file_obj)
+            return self.conn.extract(file_obj, **kwargs)
         except Exception as e:
             self.log.warning(u"Unable to extract file contents: %s", e,
                              exc_info=True, extra={"data": {"file": file_obj}})
@@ -720,7 +725,7 @@ class SolrSearchQuery(BaseSearchQuery):
         self._results = results.get('results', [])
         self._hit_count = results.get('hits', 0)
         self._facet_counts = self.post_process_facets(results)
-        self._stats = results.get('stats',{})
+        self._stats = results.get('stats', {})
         self._spelling_suggestion = results.get('spelling_suggestion', None)
 
     def run_mlt(self, **kwargs):
diff --git a/haystack/fields.py b/haystack/fields.py
index 7024631..24fd85a 100644
--- a/haystack/fields.py
+++ b/haystack/fields.py
@@ -89,7 +89,7 @@ class SearchField(object):
 
             if len(values) == 1:
                 return values[0]
-            else:
+            elif len(values) > 1:
                 return values
 
         if self.has_default():
diff --git a/haystack/indexes.py b/haystack/indexes.py
index 9f2b2ba..5c5ace7 100644
--- a/haystack/indexes.py
+++ b/haystack/indexes.py
@@ -239,6 +239,11 @@ class SearchIndex(with_metaclass(DeclarativeMetaclass, threading.local)):
         return weights
 
     def _get_backend(self, using):
+        warnings.warn('SearchIndex._get_backend is deprecated; use SearchIndex.get_backend instead',
+                      DeprecationWarning)
+        return self.get_backend(using)
+
+    def get_backend(self, using=None):
         if using is None:
             try:
                 using = connection_router.for_write(index=self)[0]
@@ -256,7 +261,8 @@ class SearchIndex(with_metaclass(DeclarativeMetaclass, threading.local)):
         used. Default relies on the routers to decide which backend should
         be used.
         """
-        backend = self._get_backend(using)
+
+        backend = self.get_backend(using)
 
         if backend is not None:
             backend.update(self, self.index_queryset(using=using))
@@ -272,7 +278,7 @@ class SearchIndex(with_metaclass(DeclarativeMetaclass, threading.local)):
         """
         # Check to make sure we want to index this first.
         if self.should_update(instance, **kwargs):
-            backend = self._get_backend(using)
+            backend = self.get_backend(using)
 
             if backend is not None:
                 backend.update(self, [instance])
@@ -286,7 +292,7 @@ class SearchIndex(with_metaclass(DeclarativeMetaclass, threading.local)):
         used. Default relies on the routers to decide which backend should
         be used.
         """
-        backend = self._get_backend(using)
+        backend = self.get_backend(using)
 
         if backend is not None:
             backend.remove(instance, **kwargs)
@@ -299,7 +305,7 @@ class SearchIndex(with_metaclass(DeclarativeMetaclass, threading.local)):
         used. Default relies on the routers to decide which backend should
         be used.
         """
-        backend = self._get_backend(using)
+        backend = self.get_backend(using)
 
         if backend is not None:
             backend.clear(models=[self.get_model()])
diff --git a/haystack/views.py b/haystack/views.py
index 7549589..0de46b1 100644
--- a/haystack/views.py
+++ b/haystack/views.py
@@ -135,7 +135,7 @@ class SearchView(object):
             'suggestion': None,
         }
 
-        if self.results and hasattr(self.results, 'query') and self.results.query.backend.include_spelling:
+        if hasattr(self.results, 'query') and self.results.query.backend.include_spelling:
             context['suggestion'] = self.form.get_suggestion()
 
         context.update(self.extra_context())
diff --git a/test_haystack/test_fields.py b/test_haystack/test_fields.py
index 024a50c..fe8cb16 100644
--- a/test_haystack/test_fields.py
+++ b/test_haystack/test_fields.py
@@ -85,6 +85,14 @@ class SearchFieldTestCase(TestCase):
 
         self.assertEqual([1, 1], field.resolve_attributes_lookup([obj], ['related', 'related', 'value']))
 
+    def test_prepare_with_null_django_onetomany_rel(self):
+        left_model = OneToManyLeftSideModel.objects.create()
+
+        field = SearchField(model_attr='right_side__pk', null=True)
+        result = field.prepare(left_model)
+
+        self.assertEqual(None, result)
+
 
 class CharFieldTestCase(TestCase):
     def test_init(self):
diff --git a/test_haystack/test_views.py b/test_haystack/test_views.py
index bbd4030..9803537 100644
--- a/test_haystack/test_views.py
+++ b/test_haystack/test_views.py
@@ -140,11 +140,19 @@ class SearchViewTestCase(TestCase):
         from django.conf import settings
         old = settings.HAYSTACK_CONNECTIONS['default'].get('INCLUDE_SPELLING', None)
 
+        settings.HAYSTACK_CONNECTIONS['default']['INCLUDE_SPELLING'] = True
+
         sv = SearchView()
         sv.query = 'Nothing'
         sv.results = []
         sv.build_page = lambda: (None, None)
-        output = sv.create_response()
+        sv.create_response()
+        context = sv.get_context()
+
+        self.assertIn('suggestion', context,
+                      msg='Spelling suggestions should be present even if'
+                          ' no results were returned')
+        self.assertEqual(context['suggestion'], None)
 
         # Restore
         settings.HAYSTACK_CONNECTIONS['default']['INCLUDE_SPELLING'] = old

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-haystack.git



More information about the Python-modules-commits mailing list