././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1613081681.419286 celery-haystack-ng-0.20.post2/0000755000175000017500000000000000000000000014320 5ustar00niknik././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613080177.0 celery-haystack-ng-0.20.post2/AUTHORS0000644000175000017500000000015700000000000015373 0ustar00niknikJosh Bohde Germán M. Bravo Jannis Leidel Daniel Lindsley Stefan Wehrmeyer Dominik George ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/LICENSE0000644000175000017500000000301400000000000015323 0ustar00niknikCopyright (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. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/MANIFEST.in0000644000175000017500000000006300000000000016055 0ustar00niknikinclude AUTHORS include LICENSE include README.rst ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1613081681.419286 celery-haystack-ng-0.20.post2/PKG-INFO0000644000175000017500000000712300000000000015420 0ustar00niknikMetadata-Version: 1.1 Name: celery-haystack-ng Version: 0.20.post2 Summary: An app for integrating Celery with Haystack Home-page: http://celery-haystack-ng.rtfd.org/ Author: Dominik George Author-email: dominik.george@teckids.org License: UNKNOWN Description: ================== celery-haystack-ng ================== This Django app allows you to utilize Celery for automatically updating and deleting objects in a Haystack_ search index. Forked from the original celery-haystack_. Requirements ------------ * Django 2.1+ * Haystack_ 2.X+ * Celery_ 4.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-haystack: https://github.com/django-haystack/celery-haystack Installation ------------ Use your favorite Python package manager to install the app from PyPI, e.g.:: pip install celery-haystack-ng 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 `EduGit issue tracker`_ for any bug reports or feature requests. .. _`EduGit issue tracker`: https://edugit.org/AlekSIS/libs/celery-haystack-ng/-/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 :: 3 Classifier: Topic :: Utilities ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081063.0 celery-haystack-ng-0.20.post2/README.rst0000644000175000017500000000437700000000000016022 0ustar00niknik================== celery-haystack-ng ================== This Django app allows you to utilize Celery for automatically updating and deleting objects in a Haystack_ search index. Forked from the original celery-haystack_. Requirements ------------ * Django 2.1+ * Haystack_ 2.X+ * Celery_ 4.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-haystack: https://github.com/django-haystack/celery-haystack Installation ------------ Use your favorite Python package manager to install the app from PyPI, e.g.:: pip install celery-haystack-ng 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 `EduGit issue tracker`_ for any bug reports or feature requests. .. _`EduGit issue tracker`: https://edugit.org/AlekSIS/libs/celery-haystack-ng/-/issues ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1613081681.419286 celery-haystack-ng-0.20.post2/celery_haystack/0000755000175000017500000000000000000000000017472 5ustar00niknik././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081648.0 celery-haystack-ng-0.20.post2/celery_haystack/__init__.py0000644000175000017500000000014700000000000021605 0ustar00niknik__version__ = '0.20.post2' def version_hook(config): config['metadata']['version'] = __version__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077841.0 celery-haystack-ng-0.20.post2/celery_haystack/conf.py0000644000175000017500000000470500000000000020777 0ustar00niknikfrom 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 #: Whether the task results should be ignored IGNORE_RESULT = False #: 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 #: Whether 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.") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/indexes.py0000644000175000017500000000012600000000000021502 0ustar00niknikfrom haystack import indexes class CelerySearchIndex(indexes.SearchIndex): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/signals.py0000644000175000017500000000302700000000000021506 0ustar00niknikfrom 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613079787.0 celery-haystack-ng-0.20.post2/celery_haystack/tasks.py0000644000175000017500000001472400000000000021201 0ustar00niknikfrom django.core.exceptions import ImproperlyConfigured from django.core.management import call_command from django.apps import apps from .conf import settings from haystack import connections, connection_router from haystack.exceptions import NotHandled as IndexNotFoundException from celery import current_app # noqa from celery.utils.log import get_task_logger logger = get_task_logger(__name__) class CeleryHaystackSignalHandler(current_app.Task): name = "haystack_signal_handler" using = settings.CELERY_HAYSTACK_DEFAULT_ALIAS max_retries = settings.CELERY_HAYSTACK_MAX_RETRIES default_retry_delay = settings.CELERY_HAYSTACK_RETRY_DELAY ignore_result = settings.CELERY_HAYSTACK_IGNORE_RESULT store_errors_even_if_ignored = True 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 = apps.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(current_app.Task): """ A celery task class to be used to call the update_index management command from Celery. """ name = "haystack_update_index" 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") current_app.tasks.register(CeleryHaystackSignalHandler) current_app.tasks.register(CeleryHaystackUpdateIndex) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/test_settings.py0000644000175000017500000000152700000000000022750 0ustar00niknikimport 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', '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' ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1613081681.419286 celery-haystack-ng-0.20.post2/celery_haystack/tests/0000755000175000017500000000000000000000000020634 5ustar00niknik././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/tests/__init__.py0000644000175000017500000000000000000000000022733 0ustar00niknik././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/tests/models.py0000644000175000017500000000022200000000000022465 0ustar00niknikfrom django.db import models class Note(models.Model): content = models.TextField() def __unicode__(self): return self.content ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/tests/search_indexes.py0000644000175000017500000000046600000000000024200 0ustar00niknikfrom 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/tests/search_sites.py0000644000175000017500000000005100000000000023656 0ustar00niknikimport haystack haystack.autodiscover() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/tests/tests.py0000644000175000017500000000475200000000000022360 0ustar00niknikfrom 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/celery_haystack/utils.py0000644000175000017500000000324200000000000021205 0ustar00niknikfrom 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() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1613081681.419286 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/0000755000175000017500000000000000000000000021650 5ustar00niknik././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081681.0 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/PKG-INFO0000644000175000017500000000712300000000000022750 0ustar00niknikMetadata-Version: 1.1 Name: celery-haystack-ng Version: 0.20.post2 Summary: An app for integrating Celery with Haystack Home-page: http://celery-haystack-ng.rtfd.org/ Author: Dominik George Author-email: dominik.george@teckids.org License: UNKNOWN Description: ================== celery-haystack-ng ================== This Django app allows you to utilize Celery for automatically updating and deleting objects in a Haystack_ search index. Forked from the original celery-haystack_. Requirements ------------ * Django 2.1+ * Haystack_ 2.X+ * Celery_ 4.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-haystack: https://github.com/django-haystack/celery-haystack Installation ------------ Use your favorite Python package manager to install the app from PyPI, e.g.:: pip install celery-haystack-ng 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 `EduGit issue tracker`_ for any bug reports or feature requests. .. _`EduGit issue tracker`: https://edugit.org/AlekSIS/libs/celery-haystack-ng/-/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 :: 3 Classifier: Topic :: Utilities ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081681.0 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/SOURCES.txt0000644000175000017500000000123700000000000023537 0ustar00niknikAUTHORS LICENSE MANIFEST.in README.rst setup.cfg setup.py celery_haystack/__init__.py celery_haystack/conf.py celery_haystack/indexes.py celery_haystack/signals.py celery_haystack/tasks.py celery_haystack/test_settings.py celery_haystack/utils.py 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.py celery_haystack_ng.egg-info/PKG-INFO celery_haystack_ng.egg-info/SOURCES.txt celery_haystack_ng.egg-info/dependency_links.txt celery_haystack_ng.egg-info/not-zip-safe celery_haystack_ng.egg-info/requires.txt celery_haystack_ng.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081681.0 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/dependency_links.txt0000644000175000017500000000000100000000000025716 0ustar00niknik ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613080375.0 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/not-zip-safe0000644000175000017500000000000100000000000024076 0ustar00niknik ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081681.0 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/requires.txt0000644000175000017500000000006700000000000024253 0ustar00niknikcelery>=4.0 django-appconf>=0.4.1 django-haystack>=2.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613081681.0 celery-haystack-ng-0.20.post2/celery_haystack_ng.egg-info/top_level.txt0000644000175000017500000000002000000000000024372 0ustar00niknikcelery_haystack ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1613081681.419286 celery-haystack-ng-0.20.post2/setup.cfg0000644000175000017500000000161300000000000016142 0ustar00niknik[global] setup-hooks = celery_haystack.version_hook [metadata] name = celery-haystack-ng author = Dominik George author-email = dominik.george@teckids.org summary = An app for integrating Celery with Haystack description-file = README.rst home-page = http://celery-haystack-ng.rtfd.org/ project-url = https://edugit.org/AlekSIS/libs/celery-haystack-ng 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 :: 3 Topic :: Utilities [options] install_requires = django-appconf>=0.4.1 django-haystack>=2.0 celery>=4.0 [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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613077759.0 celery-haystack-ng-0.20.post2/setup.py0000644000175000017500000000014000000000000016025 0ustar00niknik#!/usr/bin/env python from setuptools import setup setup(setup_requires=['d2to1'], d2to1=True)