celery-haystack-0.10/0000755000076500000240000000000012641012674014301 5ustar swstaff00000000000000celery-haystack-0.10/AUTHORS0000644000076500000240000000013712204366720015351 0ustar swstaff00000000000000Josh Bohde Germán M. Bravo Jannis Leidel Daniel Lindsley Stefan Wehrmeyercelery-haystack-0.10/celery_haystack/0000755000076500000240000000000012641012674017453 5ustar swstaff00000000000000celery-haystack-0.10/celery_haystack/__init__.py0000644000076500000240000000014112641010467021556 0ustar swstaff00000000000000__version__ = '0.10' def version_hook(config): config['metadata']['version'] = __version__ celery-haystack-0.10/celery_haystack/conf.py0000644000076500000240000000457112641005474020761 0ustar swstaff00000000000000from django.conf import settings # noqa from django.core.exceptions import ImproperlyConfigured from haystack import constants from haystack.management.commands import update_index as cmd from appconf import AppConf class CeleryHaystack(AppConf): #: The default alias to DEFAULT_ALIAS = None #: The delay (in seconds) before task will be executed (Celery countdown) COUNTDOWN = 0 #: The delay (in seconds) after which a failed index is retried RETRY_DELAY = 5 * 60 #: The number of retries that are done MAX_RETRIES = 1 #: The default Celery task class DEFAULT_TASK = 'celery_haystack.tasks.CeleryHaystackSignalHandler' #: The name of the celery queue to use, or None for default QUEUE = None #: Whether the task should be handled transaction safe TRANSACTION_SAFE = True #: The batch size used by the CeleryHaystackUpdateIndex task COMMAND_BATCH_SIZE = None #: The max age of items used by the CeleryHaystackUpdateIndex task COMMAND_AGE = None #: Wehther to remove items from the index that aren't in the DB anymore COMMAND_REMOVE = False #: The number of multiprocessing workers used by the CeleryHaystackUpdateIndex task COMMAND_WORKERS = 0 #: The names of apps to run update_index for COMMAND_APPS = [] #: The verbosity level of the update_index call COMMAND_VERBOSITY = 1 def configure_default_alias(self, value): return value or getattr(constants, 'DEFAULT_ALIAS', None) def configure_command_batch_size(self, value): return value or getattr(cmd, 'DEFAULT_BATCH_SIZE', None) def configure_command_age(self, value): return value or getattr(cmd, 'DEFAULT_AGE', None) def configure(self): data = {} for name, value in self.configured_data.items(): if name in ('RETRY_DELAY', 'MAX_RETRIES', 'COMMAND_WORKERS', 'COMMAND_VERBOSITY'): value = int(value) data[name] = value return data signal_processor = getattr(settings, 'HAYSTACK_SIGNAL_PROCESSOR', None) if signal_processor is None: raise ImproperlyConfigured("When using celery-haystack with Haystack 2.X " "the HAYSTACK_SIGNAL_PROCESSOR setting must be " "set. Use 'celery_haystack.signals." "CelerySignalProcessor' as default.") celery-haystack-0.10/celery_haystack/indexes.py0000644000076500000240000000012612641003777021467 0ustar swstaff00000000000000from haystack import indexes class CelerySearchIndex(indexes.SearchIndex): pass celery-haystack-0.10/celery_haystack/models.py0000644000076500000240000000000012242667764021313 0ustar swstaff00000000000000celery-haystack-0.10/celery_haystack/signals.py0000644000076500000240000000302712641000147021457 0ustar swstaff00000000000000from django.db.models import signals from haystack.signals import BaseSignalProcessor from haystack.exceptions import NotHandled from .utils import enqueue_task from .indexes import CelerySearchIndex class CelerySignalProcessor(BaseSignalProcessor): def setup(self): signals.post_save.connect(self.enqueue_save) signals.post_delete.connect(self.enqueue_delete) def teardown(self): signals.post_save.disconnect(self.enqueue_save) signals.post_delete.disconnect(self.enqueue_delete) def enqueue_save(self, sender, instance, **kwargs): return self.enqueue('update', instance, sender, **kwargs) def enqueue_delete(self, sender, instance, **kwargs): return self.enqueue('delete', instance, sender, **kwargs) def enqueue(self, action, instance, sender, **kwargs): """ Given an individual model instance, determine if a backend handles the model, check if the index is Celery-enabled and enqueue task. """ using_backends = self.connection_router.for_write(instance=instance) for using in using_backends: try: connection = self.connections[using] index = connection.get_unified_index().get_index(sender) except NotHandled: continue # Check next backend if isinstance(index, CelerySearchIndex): if action == 'update' and not index.should_update(instance): continue enqueue_task(action, instance) celery-haystack-0.10/celery_haystack/tasks.py0000644000076500000240000001426412641004142021150 0ustar swstaff00000000000000from django.core.exceptions import ImproperlyConfigured from django.core.management import call_command from django.apps import apps get_model = apps.get_model from .conf import settings from haystack import connections, connection_router from haystack.exceptions import NotHandled as IndexNotFoundException from celery.task import Task # noqa from celery.utils.log import get_task_logger logger = get_task_logger(__name__) class CeleryHaystackSignalHandler(Task): using = settings.CELERY_HAYSTACK_DEFAULT_ALIAS max_retries = settings.CELERY_HAYSTACK_MAX_RETRIES default_retry_delay = settings.CELERY_HAYSTACK_RETRY_DELAY def split_identifier(self, identifier, **kwargs): """ Break down the identifier representing the instance. Converts 'notes.note.23' into ('notes.note', 23). """ bits = identifier.split('.') if len(bits) < 2: logger.error("Unable to parse object " "identifer '%s'. Moving on..." % identifier) return (None, None) pk = bits[-1] # In case Django ever handles full paths... object_path = '.'.join(bits[:-1]) return (object_path, pk) def get_model_class(self, object_path, **kwargs): """ Fetch the model's class in a standarized way. """ bits = object_path.split('.') app_name = '.'.join(bits[:-1]) classname = bits[-1] model_class = get_model(app_name, classname) if model_class is None: raise ImproperlyConfigured("Could not load model '%s'." % object_path) return model_class def get_instance(self, model_class, pk, **kwargs): """ Fetch the instance in a standarized way. """ instance = None try: instance = model_class._default_manager.get(pk=pk) except model_class.DoesNotExist: logger.error("Couldn't load %s.%s.%s. Somehow it went missing?" % (model_class._meta.app_label.lower(), model_class._meta.object_name.lower(), pk)) except model_class.MultipleObjectsReturned: logger.error("More than one object with pk %s. Oops?" % pk) return instance def get_indexes(self, model_class, **kwargs): """ Fetch the model's registered ``SearchIndex`` in a standarized way. """ try: using_backends = connection_router.for_write(**{'models': [model_class]}) for using in using_backends: index_holder = connections[using].get_unified_index() yield index_holder.get_index(model_class), using except IndexNotFoundException: raise ImproperlyConfigured("Couldn't find a SearchIndex for %s." % model_class) def run(self, action, identifier, **kwargs): """ Trigger the actual index handler depending on the given action ('update' or 'delete'). """ # First get the object path and pk (e.g. ('notes.note', 23)) object_path, pk = self.split_identifier(identifier, **kwargs) if object_path is None or pk is None: msg = "Couldn't handle object with identifier %s" % identifier logger.error(msg) raise ValueError(msg) # Then get the model class for the object path model_class = self.get_model_class(object_path, **kwargs) for current_index, using in self.get_indexes(model_class, **kwargs): current_index_name = ".".join([current_index.__class__.__module__, current_index.__class__.__name__]) if action == 'delete': # If the object is gone, we'll use just the identifier # against the index. try: current_index.remove_object(identifier, using=using) except Exception as exc: logger.exception(exc) self.retry(exc=exc) else: msg = ("Deleted '%s' (with %s)" % (identifier, current_index_name)) logger.debug(msg) elif action == 'update': # and the instance of the model class with the pk instance = self.get_instance(model_class, pk, **kwargs) if instance is None: logger.debug("Failed updating '%s' (with %s)" % (identifier, current_index_name)) raise ValueError("Couldn't load object '%s'" % identifier) # Call the appropriate handler of the current index and # handle exception if neccessary try: current_index.update_object(instance, using=using) except Exception as exc: logger.exception(exc) self.retry(exc=exc) else: msg = ("Updated '%s' (with %s)" % (identifier, current_index_name)) logger.debug(msg) else: logger.error("Unrecognized action '%s'. Moving on..." % action) raise ValueError("Unrecognized action %s" % action) class CeleryHaystackUpdateIndex(Task): """ A celery task class to be used to call the update_index management command from Celery. """ def run(self, apps=None, **kwargs): defaults = { 'batchsize': settings.CELERY_HAYSTACK_COMMAND_BATCH_SIZE, 'age': settings.CELERY_HAYSTACK_COMMAND_AGE, 'remove': settings.CELERY_HAYSTACK_COMMAND_REMOVE, 'using': [settings.CELERY_HAYSTACK_DEFAULT_ALIAS], 'workers': settings.CELERY_HAYSTACK_COMMAND_WORKERS, 'verbosity': settings.CELERY_HAYSTACK_COMMAND_VERBOSITY, } defaults.update(kwargs) if apps is None: apps = settings.CELERY_HAYSTACK_COMMAND_APPS # Run the update_index management command logger.info("Starting update index") call_command('update_index', *apps, **defaults) logger.info("Finishing update index") celery-haystack-0.10/celery_haystack/test_settings.py0000644000076500000240000000154712641002711022722 0ustar swstaff00000000000000import os from celery import Celery app = Celery('celery_haystack') app.config_from_object('django.conf:settings') DEBUG = True TEST_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), 'tests')) INSTALLED_APPS = [ 'haystack', 'djcelery', 'celery_haystack', 'celery_haystack.tests', ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', } } SECRET_KEY = 'really-not-secret' BROKER_TRANSPORT = "memory" CELERY_ALWAYS_EAGER = True CELERY_IGNORE_RESULT = True CELERYD_LOG_LEVEL = "DEBUG" CELERY_DEFAULT_QUEUE = "celery-haystack" HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine', 'PATH': os.path.join(TEST_ROOT, 'whoosh_index'), } } HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor' celery-haystack-0.10/celery_haystack/tests/0000755000076500000240000000000012641012674020615 5ustar swstaff00000000000000celery-haystack-0.10/celery_haystack/tests/__init__.py0000644000076500000240000000000012020162164022703 0ustar swstaff00000000000000celery-haystack-0.10/celery_haystack/tests/models.py0000644000076500000240000000022212113677635022456 0ustar swstaff00000000000000from django.db import models class Note(models.Model): content = models.TextField() def __unicode__(self): return self.content celery-haystack-0.10/celery_haystack/tests/search_indexes.py0000644000076500000240000000046612641005406024154 0ustar swstaff00000000000000from haystack import indexes from .models import Note from ..indexes import CelerySearchIndex # Simplest possible subclass that could work. class NoteIndex(CelerySearchIndex, indexes.Indexable): text = indexes.CharField(document=True, model_attr='content') def get_model(self): return Note celery-haystack-0.10/celery_haystack/tests/search_sites.py0000644000076500000240000000005112020162164023626 0ustar swstaff00000000000000import haystack haystack.autodiscover() celery-haystack-0.10/celery_haystack/tests/tests.py0000644000076500000240000000475212641002711022330 0ustar swstaff00000000000000from django.core.management import call_command from django.test import TransactionTestCase from haystack.query import SearchQuerySet from .models import Note class QueuedSearchIndexTestCase(TransactionTestCase): def assertSearchResultLength(self, count): self.assertEqual(count, len(SearchQuerySet())) def assertSearchResultContains(self, pk, text): results = SearchQuerySet().filter(id='tests.note.%s' % pk) self.assertTrue(results) self.assertTrue(text in results[0].text) def setUp(self): # Nuke the index. call_command('clear_index', interactive=False, verbosity=0) # Throw away all Notes Note.objects.all().delete() def test_update(self): self.assertSearchResultLength(0) note1 = Note.objects.create(content='Because everyone loves tests.') self.assertSearchResultLength(1) self.assertSearchResultContains(note1.pk, 'loves') note2 = Note.objects.create(content='More test data.') self.assertSearchResultLength(2) self.assertSearchResultContains(note2.pk, 'More') note3 = Note.objects.create(content='The test data. All done.') self.assertSearchResultLength(3) self.assertSearchResultContains(note3.pk, 'All done') note3.content = 'Final test note FOR REAL' note3.save() self.assertSearchResultLength(3) self.assertSearchResultContains(note3.pk, 'FOR REAL') def test_delete(self): note1 = Note.objects.create(content='Because everyone loves tests.') note2 = Note.objects.create(content='More test data.') note3 = Note.objects.create(content='The test data. All done.') self.assertSearchResultLength(3) note1.delete() self.assertSearchResultLength(2) note2.delete() self.assertSearchResultLength(1) note3.delete() self.assertSearchResultLength(0) def test_complex(self): note1 = Note.objects.create(content='Because everyone loves test.') self.assertSearchResultLength(1) Note.objects.create(content='More test data.') self.assertSearchResultLength(2) note1.delete() self.assertSearchResultLength(1) note3 = Note.objects.create(content='The test data. All done.') self.assertSearchResultLength(2) note3.title = 'Final test note FOR REAL' note3.save() self.assertSearchResultLength(2) note3.delete() self.assertSearchResultLength(1) celery-haystack-0.10/celery_haystack/utils.py0000644000076500000240000000324212641010443021156 0ustar swstaff00000000000000from django.core.exceptions import ImproperlyConfigured try: from importlib import import_module except ImportError: from django.utils.importlib import import_module from django.db import connection, transaction from haystack.utils import get_identifier from .conf import settings def get_update_task(task_path=None): import_path = task_path or settings.CELERY_HAYSTACK_DEFAULT_TASK module, attr = import_path.rsplit('.', 1) try: mod = import_module(module) except ImportError as e: raise ImproperlyConfigured('Error importing module %s: "%s"' % (module, e)) try: Task = getattr(mod, attr) except AttributeError: raise ImproperlyConfigured('Module "%s" does not define a "%s" ' 'class.' % (module, attr)) return Task() def enqueue_task(action, instance, **kwargs): """ Common utility for enqueing a task for the given action and model instance. """ identifier = get_identifier(instance) options = {} if settings.CELERY_HAYSTACK_QUEUE: options['queue'] = settings.CELERY_HAYSTACK_QUEUE if settings.CELERY_HAYSTACK_COUNTDOWN: options['countdown'] = settings.CELERY_HAYSTACK_COUNTDOWN task = get_update_task() task_func = lambda: task.apply_async((action, identifier), kwargs, **options) if hasattr(transaction, 'on_commit'): # Django 1.9 on_commit hook transaction.on_commit( task_func ) elif hasattr(connection, 'on_commit'): # Django-transaction-hooks connection.on_commit( task_func ) else: task_func() celery-haystack-0.10/celery_haystack.egg-info/0000755000076500000240000000000012641012674021145 5ustar swstaff00000000000000celery-haystack-0.10/celery_haystack.egg-info/dependency_links.txt0000644000076500000240000000000112641012674025213 0ustar swstaff00000000000000 celery-haystack-0.10/celery_haystack.egg-info/not-zip-safe0000644000076500000240000000000112537040624023373 0ustar swstaff00000000000000 celery-haystack-0.10/celery_haystack.egg-info/PKG-INFO0000644000076500000240000000755712641012674022260 0ustar swstaff00000000000000Metadata-Version: 1.1 Name: celery-haystack Version: 0.10 Summary: An app for integrating Celery with Haystack. Home-page: http://celery-haystack.rtfd.org/ Author: Jannis Leidel Author-email: jannis@leidel.info License: UNKNOWN Description: =============== celery-haystack =============== .. image:: https://secure.travis-ci.org/django-haystack/celery-haystack.png?branch=develop :alt: Build Status :target: http://travis-ci.org/django-haystack/celery-haystack This Django app allows you to utilize Celery for automatically updating and deleting objects in a Haystack_ search index. Requirements ------------ * Django 1.8+ * Haystack_ `2.X`_ * Celery_ 3.X You also need to install your choice of one of the supported search engines for Haystack and one of the supported backends for Celery. .. _Haystack: http://haystacksearch.org .. _Celery: http://www.celeryproject.org Installation ------------ Use your favorite Python package manager to install the app from PyPI, e.g.:: pip install celery-haystack For Django < 1.9 you need to install and configure `django-transaction-hooks`_ -- an app that brings transaction commit hooks to Django. .. _django-transaction-hooks: https://github.com/carljm/django-transaction-hooks Usage ----- 1. Add ``'celery_haystack'`` to the ``INSTALLED_APPS`` setting .. code:: python INSTALLED_APPS = [ # .. 'celery_haystack', ] 2. Enable the celery-haystack signal processor in the settings .. code:: python HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor' 3. Alter all of your ``SearchIndex`` subclasses to inherit from ``celery_haystack.indexes.CelerySearchIndex`` and ``haystack.indexes.Indexable`` .. code:: python from haystack import indexes from celery_haystack.indexes import CelerySearchIndex from myapp.models import Note class NoteIndex(CelerySearchIndex, indexes.Indexable): text = indexes.CharField(document=True, model_attr='content') def get_model(self): return Note 4. Ensure your Celery instance is running. Thanks ------ This app is a blatant rip-off of Daniel Lindsley's queued_search_ app but uses Ask Solem Hoel's Celery_ instead of the equally awesome queues_ library by Matt Croyden. .. _queued_search: https://github.com/toastdriven/queued_search/ .. _Celery: http://celeryproject.org/ .. _queues: http://code.google.com/p/queues/ Issues ------ Please use the `Github issue tracker`_ for any bug reports or feature requests. .. _`Github issue tracker`: https://github.com/django-haystack/celery-haystack/issues Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Utilities celery-haystack-0.10/celery_haystack.egg-info/requires.txt0000644000076500000240000000002612641012674023543 0ustar swstaff00000000000000django-appconf>=0.4.1 celery-haystack-0.10/celery_haystack.egg-info/SOURCES.txt0000644000076500000240000000124712641012674023035 0ustar swstaff00000000000000AUTHORS LICENSE MANIFEST.in README.rst setup.cfg setup.py celery_haystack/__init__.py celery_haystack/conf.py celery_haystack/indexes.py celery_haystack/models.py celery_haystack/signals.py celery_haystack/tasks.py celery_haystack/test_settings.py celery_haystack/utils.py celery_haystack.egg-info/PKG-INFO celery_haystack.egg-info/SOURCES.txt celery_haystack.egg-info/dependency_links.txt celery_haystack.egg-info/not-zip-safe celery_haystack.egg-info/requires.txt celery_haystack.egg-info/top_level.txt celery_haystack/tests/__init__.py celery_haystack/tests/models.py celery_haystack/tests/search_indexes.py celery_haystack/tests/search_sites.py celery_haystack/tests/tests.pycelery-haystack-0.10/celery_haystack.egg-info/top_level.txt0000644000076500000240000000002012641012674023667 0ustar swstaff00000000000000celery_haystack celery-haystack-0.10/LICENSE0000644000076500000240000000301412204366720015303 0ustar swstaff00000000000000Copyright (c) 2011-2013, Jannis Leidel and contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of celery-haystack nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. celery-haystack-0.10/MANIFEST.in0000644000076500000240000000006312537040737016043 0ustar swstaff00000000000000include AUTHORS include LICENSE include README.rst celery-haystack-0.10/PKG-INFO0000644000076500000240000000755712641012674015414 0ustar swstaff00000000000000Metadata-Version: 1.1 Name: celery-haystack Version: 0.10 Summary: An app for integrating Celery with Haystack. Home-page: http://celery-haystack.rtfd.org/ Author: Jannis Leidel Author-email: jannis@leidel.info License: UNKNOWN Description: =============== celery-haystack =============== .. image:: https://secure.travis-ci.org/django-haystack/celery-haystack.png?branch=develop :alt: Build Status :target: http://travis-ci.org/django-haystack/celery-haystack This Django app allows you to utilize Celery for automatically updating and deleting objects in a Haystack_ search index. Requirements ------------ * Django 1.8+ * Haystack_ `2.X`_ * Celery_ 3.X You also need to install your choice of one of the supported search engines for Haystack and one of the supported backends for Celery. .. _Haystack: http://haystacksearch.org .. _Celery: http://www.celeryproject.org Installation ------------ Use your favorite Python package manager to install the app from PyPI, e.g.:: pip install celery-haystack For Django < 1.9 you need to install and configure `django-transaction-hooks`_ -- an app that brings transaction commit hooks to Django. .. _django-transaction-hooks: https://github.com/carljm/django-transaction-hooks Usage ----- 1. Add ``'celery_haystack'`` to the ``INSTALLED_APPS`` setting .. code:: python INSTALLED_APPS = [ # .. 'celery_haystack', ] 2. Enable the celery-haystack signal processor in the settings .. code:: python HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor' 3. Alter all of your ``SearchIndex`` subclasses to inherit from ``celery_haystack.indexes.CelerySearchIndex`` and ``haystack.indexes.Indexable`` .. code:: python from haystack import indexes from celery_haystack.indexes import CelerySearchIndex from myapp.models import Note class NoteIndex(CelerySearchIndex, indexes.Indexable): text = indexes.CharField(document=True, model_attr='content') def get_model(self): return Note 4. Ensure your Celery instance is running. Thanks ------ This app is a blatant rip-off of Daniel Lindsley's queued_search_ app but uses Ask Solem Hoel's Celery_ instead of the equally awesome queues_ library by Matt Croyden. .. _queued_search: https://github.com/toastdriven/queued_search/ .. _Celery: http://celeryproject.org/ .. _queues: http://code.google.com/p/queues/ Issues ------ Please use the `Github issue tracker`_ for any bug reports or feature requests. .. _`Github issue tracker`: https://github.com/django-haystack/celery-haystack/issues Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Utilities celery-haystack-0.10/README.rst0000644000076500000240000000453412641012173015770 0ustar swstaff00000000000000=============== celery-haystack =============== .. image:: https://secure.travis-ci.org/django-haystack/celery-haystack.png?branch=develop :alt: Build Status :target: http://travis-ci.org/django-haystack/celery-haystack This Django app allows you to utilize Celery for automatically updating and deleting objects in a Haystack_ search index. Requirements ------------ * Django 1.8+ * Haystack_ `2.X`_ * Celery_ 3.X You also need to install your choice of one of the supported search engines for Haystack and one of the supported backends for Celery. .. _Haystack: http://haystacksearch.org .. _Celery: http://www.celeryproject.org Installation ------------ Use your favorite Python package manager to install the app from PyPI, e.g.:: pip install celery-haystack For Django < 1.9 you need to install and configure `django-transaction-hooks`_ -- an app that brings transaction commit hooks to Django. .. _django-transaction-hooks: https://github.com/carljm/django-transaction-hooks Usage ----- 1. Add ``'celery_haystack'`` to the ``INSTALLED_APPS`` setting .. code:: python INSTALLED_APPS = [ # .. 'celery_haystack', ] 2. Enable the celery-haystack signal processor in the settings .. code:: python HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor' 3. Alter all of your ``SearchIndex`` subclasses to inherit from ``celery_haystack.indexes.CelerySearchIndex`` and ``haystack.indexes.Indexable`` .. code:: python from haystack import indexes from celery_haystack.indexes import CelerySearchIndex from myapp.models import Note class NoteIndex(CelerySearchIndex, indexes.Indexable): text = indexes.CharField(document=True, model_attr='content') def get_model(self): return Note 4. Ensure your Celery instance is running. Thanks ------ This app is a blatant rip-off of Daniel Lindsley's queued_search_ app but uses Ask Solem Hoel's Celery_ instead of the equally awesome queues_ library by Matt Croyden. .. _queued_search: https://github.com/toastdriven/queued_search/ .. _Celery: http://celeryproject.org/ .. _queues: http://code.google.com/p/queues/ Issues ------ Please use the `Github issue tracker`_ for any bug reports or feature requests. .. _`Github issue tracker`: https://github.com/django-haystack/celery-haystack/issues celery-haystack-0.10/setup.cfg0000644000076500000240000000200112641012674016113 0ustar swstaff00000000000000[global] setup-hooks = celery_haystack.version_hook [metadata] name = celery-haystack author = Jannis Leidel author-email = jannis@leidel.info summary = An app for integrating Celery with Haystack. description-file = README.rst home-page = http://celery-haystack.rtfd.org/ project-url = Github, https://github.com/django-haystack/celery-haystack/ classifier = Development Status :: 4 - Beta Environment :: Web Environment Framework :: Django Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 2.6 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 Topic :: Utilities requires-dist = django-appconf>=0.4.1 [files] packages = celery_haystack celery_haystack.tests extra_files = README.rst AUTHORS [backwards_compat] zip_safe = False [wheel] universal = 1 [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 celery-haystack-0.10/setup.py0000644000076500000240000000014012537032124016002 0ustar swstaff00000000000000#!/usr/bin/env python from setuptools import setup setup(setup_requires=['d2to1'], d2to1=True)