[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