diff --git a/src/watson/__init__.py b/src/watson/__init__.py index e4eac4c..26dbd95 100644 --- a/src/watson/__init__.py +++ b/src/watson/__init__.py @@ -6,6 +6,8 @@ Developed by Dave Hall. """ +from __future__ import unicode_literals + from watson.admin import SearchAdmin from watson.registration import SearchAdapter, default_search_engine, search_context_manager @@ -24,4 +26,4 @@ get_adapter = default_search_engine.get_adapter # Easy context management. -update_index = search_context_manager.update_index \ No newline at end of file +update_index = search_context_manager.update_index diff --git a/src/watson/admin.py b/src/watson/admin.py index b15e558..598560f 100644 --- a/src/watson/admin.py +++ b/src/watson/admin.py @@ -1,5 +1,7 @@ """Admin integration for django-watson.""" +from __future__ import unicode_literals + from django.contrib import admin from django.contrib.admin.views.main import ChangeList @@ -73,4 +75,4 @@ class SearchAdmin(admin.ModelAdmin): def get_changelist(self, request, **kwargs): """Returns the ChangeList class for use on the changelist page.""" - return WatsonSearchChangeList \ No newline at end of file + return WatsonSearchChangeList diff --git a/src/watson/backends.py b/src/watson/backends.py index 650dfd0..002727b 100644 --- a/src/watson/backends.py +++ b/src/watson/backends.py @@ -1,5 +1,7 @@ """Search backends used by django-watson.""" +from __future__ import unicode_literals + import re, abc from django.contrib.contenttypes.models import ContentType @@ -13,7 +15,7 @@ from watson.models import SearchEntry, has_int_pk def regex_from_word(word): """Generates a regext from the given search word.""" - return u"(\s{word})|(^{word})".format( + return "(\s{word})|(^{word})".format( word = re.escape(word), ) @@ -99,23 +101,23 @@ class RegexSearchMixin(six.with_metaclass(abc.ABCMeta)): pk = model._meta.pk id = connection.ops.quote_name(pk.db_column or pk.attname) # Add in basic filters. - word_query = [u""" + word_query = [""" ({db_table}.{engine_slug} = %s) """, """ ({db_table}.{content_type_id} = %s) """] word_kwargs= { - u"db_table": db_table, - u"model_db_table": model_db_table, - u"engine_slug": connection.ops.quote_name(u"engine_slug"), - u"title": connection.ops.quote_name(u"title"), - u"description": connection.ops.quote_name(u"description"), - u"content": connection.ops.quote_name(u"content"), - u"content_type_id": connection.ops.quote_name(u"content_type_id"), - u"object_id": connection.ops.quote_name(u"object_id"), - u"object_id_int": connection.ops.quote_name(u"object_id_int"), - u"id": id, - u"iregex_operator": connection.operators["iregex"], + "db_table": db_table, + "model_db_table": model_db_table, + "engine_slug": connection.ops.quote_name("engine_slug"), + "title": connection.ops.quote_name("title"), + "description": connection.ops.quote_name("description"), + "content": connection.ops.quote_name("content"), + "content_type_id": connection.ops.quote_name("content_type_id"), + "object_id": connection.ops.quote_name("object_id"), + "object_id_int": connection.ops.quote_name("object_id_int"), + "id": id, + "iregex_operator": connection.operators["iregex"], } word_args = [ engine_slug, @@ -133,12 +135,12 @@ class RegexSearchMixin(six.with_metaclass(abc.ABCMeta)): # Add in all words. for word in search_text.split(): regex = regex_from_word(word) - word_query.append(u""" + word_query.append(""" ({db_table}.{title} {iregex_operator} OR {db_table}.{description} {iregex_operator} OR {db_table}.{content} {iregex_operator}) """) word_args.extend((regex, regex, regex)) # Compile the query. - full_word_query = u" AND ".join(word_query).format(**word_kwargs) + full_word_query = " AND ".join(word_query).format(**word_kwargs) return queryset.extra( tables = (db_table,), where = (full_word_query,), @@ -151,7 +153,7 @@ class RegexSearchBackend(RegexSearchMixin, SearchBackend): """A search backend that works with SQLite3.""" -escape_postgres_query_chars = make_escaper(u"():|!&*'") +escape_postgres_query_chars = make_escaper("():|!&*'") class PostgresSearchBackend(SearchBackend): @@ -163,8 +165,8 @@ class PostgresSearchBackend(SearchBackend): def escape_postgres_query(self, text): """Escapes the given text to become a valid ts_query.""" - return u" & ".join( - u"{0}:*".format(word) + return " & ".join( + "{0}:*".format(word) for word in escape_postgres_query_chars(text).split() ) @@ -305,7 +307,7 @@ class PostgresLegacySearchBackend(PostgresSearchBackend): def escape_postgres_query(self, text): """Escapes the given text to become a valid ts_query.""" - return u" & ".join(escape_postgres_query_chars(text).split()) + return " & ".join(escape_postgres_query_chars(text).split()) class PostgresPrefixLegacySearchBackend(RegexSearchMixin, PostgresLegacySearchBackend): @@ -319,11 +321,11 @@ class PostgresPrefixLegacySearchBackend(RegexSearchMixin, PostgresLegacySearchBa """ -escape_mysql_boolean_query_chars = make_escaper(u"+-<>()*\"") +escape_mysql_boolean_query_chars = make_escaper("+-<>()*\"") def escape_mysql_boolean_query(search_text): - return u" ".join( - u'+{word}*'.format( + return " ".join( + '+{word}*'.format( word = word, ) for word in escape_mysql_boolean_query_chars(search_text).split() diff --git a/src/watson/management/__init__.py b/src/watson/management/__init__.py index da78763..44a4bbb 100644 --- a/src/watson/management/__init__.py +++ b/src/watson/management/__init__.py @@ -1 +1,3 @@ -"""Management routines used by django-watson.""" \ No newline at end of file +"""Management routines used by django-watson.""" + +from __future__ import unicode_literals diff --git a/src/watson/management/commands/__init__.py b/src/watson/management/commands/__init__.py index d885917..151c48b 100644 --- a/src/watson/management/commands/__init__.py +++ b/src/watson/management/commands/__init__.py @@ -1 +1,3 @@ -"""Management commands used by django-watson.""" \ No newline at end of file +"""Management commands used by django-watson.""" + +from __future__ import unicode_literals diff --git a/src/watson/management/commands/buildwatson.py b/src/watson/management/commands/buildwatson.py index 8766e60..b683aaa 100644 --- a/src/watson/management/commands/buildwatson.py +++ b/src/watson/management/commands/buildwatson.py @@ -1,5 +1,7 @@ """Rebuilds the database indices needed by django-watson.""" +from __future__ import unicode_literals, print_function + from django.core.management.base import NoArgsCommand from django.contrib import admin from django.contrib.contenttypes.models import ContentType @@ -32,21 +34,21 @@ class Command(NoArgsCommand): entries_to_create.extend(search_engine._update_obj_index_iter(obj)) local_refreshed_model_count += 1 if verbosity >= 3: - print(u"Refreshed search entry for {model} {obj} in {engine_slug!r} search engine.".format( + print("Refreshed search entry for {model} {obj} in {engine_slug!r} search engine.".format( model = model._meta.verbose_name, obj = obj, engine_slug = engine_slug, )) refreshed_model_count += local_refreshed_model_count if verbosity == 2: - print(u"Refreshed {local_refreshed_model_count} {model} search entry(s) in {engine_slug!r} search engine.".format( + print("Refreshed {local_refreshed_model_count} {model} search entry(s) in {engine_slug!r} search engine.".format( model = model._meta.verbose_name, local_refreshed_model_count = local_refreshed_model_count, engine_slug = engine_slug, )) _bulk_save_search_entries(entries_to_create) if verbosity == 1: - print(u"Refreshed {refreshed_model_count} search entry(s) in {engine_slug!r} search engine.".format( + print("Refreshed {refreshed_model_count} search entry(s) in {engine_slug!r} search engine.".format( refreshed_model_count = refreshed_model_count, engine_slug = engine_slug, )) @@ -61,7 +63,7 @@ class Command(NoArgsCommand): if stale_entry_count > 0: stale_entries.delete() if verbosity >= 1: - print(u"Deleted {stale_entry_count} stale search entry(s) in {engine_slug!r} search engine.".format( + print("Deleted {stale_entry_count} stale search entry(s) in {engine_slug!r} search engine.".format( stale_entry_count = stale_entry_count, engine_slug = engine_slug, )) diff --git a/src/watson/management/commands/installwatson.py b/src/watson/management/commands/installwatson.py index 1540a3b..da90a95 100644 --- a/src/watson/management/commands/installwatson.py +++ b/src/watson/management/commands/installwatson.py @@ -1,5 +1,7 @@ """Creates the database indices needed by django-watson.""" +from __future__ import unicode_literals + from django.core.management.base import NoArgsCommand from django.db import transaction @@ -24,4 +26,4 @@ class Command(NoArgsCommand): else: backend.do_install() if verbosity >= 2: - self.stdout.write("django-watson has been successfully installed.\n") \ No newline at end of file + self.stdout.write("django-watson has been successfully installed.\n") diff --git a/src/watson/management/commands/uninstallwatson.py b/src/watson/management/commands/uninstallwatson.py index 66af0a4..b86b9ff 100644 --- a/src/watson/management/commands/uninstallwatson.py +++ b/src/watson/management/commands/uninstallwatson.py @@ -1,5 +1,7 @@ """Destroys the database indices needed by django-watson.""" +from __future__ import unicode_literals + from django.core.management.base import NoArgsCommand from django.db import transaction @@ -24,4 +26,4 @@ class Command(NoArgsCommand): self.stdout.write("django-watson has been successfully uninstalled.\n") else: if verbosity >= 2: - self.stdout.write("django-watson is not installed.\n") \ No newline at end of file + self.stdout.write("django-watson is not installed.\n") diff --git a/src/watson/middleware.py b/src/watson/middleware.py index 56c05f7..64a364d 100644 --- a/src/watson/middleware.py +++ b/src/watson/middleware.py @@ -1,5 +1,7 @@ """Middleware used by django-watson.""" +from __future__ import unicode_literals + from watson.registration import search_context_manager @@ -29,4 +31,4 @@ class SearchContextMiddleware(object): def process_exception(self, request, exception): """Closes the search context.""" search_context_manager.invalidate() - self._close_search_context(request) \ No newline at end of file + self._close_search_context(request) diff --git a/src/watson/models.py b/src/watson/models.py index f29c693..0a846e2 100644 --- a/src/watson/models.py +++ b/src/watson/models.py @@ -1,5 +1,7 @@ """Models used by django-watson.""" +from __future__ import unicode_literals + from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic @@ -85,4 +87,4 @@ class SearchEntry(models.Model): return self.title class Meta: - verbose_name_plural = "search entries" \ No newline at end of file + verbose_name_plural = "search entries" diff --git a/src/watson/registration.py b/src/watson/registration.py index e107e10..1de8f1c 100644 --- a/src/watson/registration.py +++ b/src/watson/registration.py @@ -1,5 +1,7 @@ """Adapters for registering models with django-watson.""" +from __future__ import unicode_literals + import sys from itertools import chain from threading import local @@ -66,11 +68,11 @@ class SearchAdapter(object): # Look up recursive fields. if len(name_parts) == 2: if isinstance(value, (QuerySet, models.Manager)): - return u" ".join(force_text(self._resolve_field(obj, name_parts[1])) for obj in value.all()) + return " ".join(force_text(self._resolve_field(obj, name_parts[1])) for obj in value.all()) return self._resolve_field(value, name_parts[1]) # Resolve querysets. if isinstance(value, (QuerySet, models.Manager)): - value = u" ".join(force_text(related) for related in value.all()) + value = " ".join(force_text(related) for related in value.all()) # Resolution complete! return value @@ -98,9 +100,9 @@ class SearchAdapter(object): this should contains a short description of the search entry, it's excellent for providing a summary in your search results. - The default implementation returns `u""`. + The default implementation returns `""`. """ - return u"" + return "" def get_content(self, obj): """ @@ -116,7 +118,7 @@ class SearchAdapter(object): # Exclude named fields. field_names = (field_name for field_name in field_names if field_name not in self.exclude) # Create the text. - return self.prepare_content(u" ".join( + return self.prepare_content(" ".join( force_text(self._resolve_field(obj, field_name)) for field_name in field_names )) @@ -125,7 +127,7 @@ class SearchAdapter(object): """Return the URL of the given obj.""" if hasattr(obj, "get_absolute_url"): return obj.get_absolute_url() - return u"" + return "" def get_meta(self, obj): """Returns a dictionary of meta information about the given obj.""" @@ -331,7 +333,8 @@ class SearchEngine(object): )) # Perform any customization. if field_overrides: - adapter_cls = type("Custom" + adapter_cls.__name__, (adapter_cls,), field_overrides) + # Conversion to str is needed because Python 2 doesn't accept unicode for class name + adapter_cls = type(str("Custom") + adapter_cls.__name__, (adapter_cls,), field_overrides) # Perform the registration. adapter_obj = adapter_cls(model) self._registered_models[model] = adapter_obj diff --git a/src/watson/templatetags/__init__.py b/src/watson/templatetags/__init__.py index 265ebf1..2c28d32 100644 --- a/src/watson/templatetags/__init__.py +++ b/src/watson/templatetags/__init__.py @@ -1 +1,3 @@ -"""Template tags used by watson search.""" \ No newline at end of file +"""Template tags used by watson search.""" + +from __future__ import unicode_literals diff --git a/src/watson/templatetags/watson.py b/src/watson/templatetags/watson.py index 2164f78..cf799b9 100644 --- a/src/watson/templatetags/watson.py +++ b/src/watson/templatetags/watson.py @@ -1,5 +1,7 @@ """Template helpers used by watsons search.""" +from __future__ import unicode_literals + from django import template @@ -45,4 +47,4 @@ def search_result_item(context, search_result): "watson/includes/search_result_item.html", ), context) finally: - context.pop() \ No newline at end of file + context.pop() diff --git a/src/watson/tests.py b/src/watson/tests.py index 99f5ba6..89b553e 100644 --- a/src/watson/tests.py +++ b/src/watson/tests.py @@ -6,6 +6,8 @@ that are 3 letters or fewer. Thus, the standard metasyntactic variables in these tests have been amended to 'fooo' and 'baar'. Ho hum. """ +from __future__ import unicode_literals + import os from unittest import skipUnless @@ -444,14 +446,14 @@ class RankingTest(SearchTestBase): def testRankingWithSearch(self): self.assertEqual( [entry.title for entry in watson.search("FOOO")], - [u"title model1 instance11 fooo baar fooo", u"title model1 instance12"] + ["title model1 instance11 fooo baar fooo", "title model1 instance12"] ) @skipUnless(get_backend().supports_ranking, "search backend does not support ranking") def testRankingWithFilter(self): self.assertEqual( [entry.title for entry in watson.filter(WatsonTestModel1, "FOOO")], - [u"title model1 instance11 fooo baar fooo", u"title model1 instance12"] + ["title model1 instance11 fooo baar fooo", "title model1 instance12"] ) diff --git a/src/watson/urls.py b/src/watson/urls.py index 5368323..d49ff11 100644 --- a/src/watson/urls.py +++ b/src/watson/urls.py @@ -1,5 +1,7 @@ """URLs for the built-in site search functionality.""" +from __future__ import unicode_literals + try: from django.conf.urls import * except ImportError: # Django<1.4 @@ -12,4 +14,4 @@ urlpatterns = patterns("watson.views", url("^json/$", "search_json", name="search_json"), -) \ No newline at end of file +) diff --git a/src/watson/views.py b/src/watson/views.py index 2c47b4f..7c21762 100644 --- a/src/watson/views.py +++ b/src/watson/views.py @@ -1,5 +1,7 @@ """Views used by the built-in site search functionality.""" +from __future__ import unicode_literals + from django.shortcuts import redirect from django.http import HttpResponse from django.utils import simplejson as json @@ -40,7 +42,7 @@ class SearchMixin(object): def get_query(self, request): """Parses the query from the request.""" - return request.GET.get(self.get_query_param(), u"").strip() + return request.GET.get(self.get_query_param(), "").strip() empty_query_redirect = None