././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1710424540.792483 celery-haystack-ng-2.0.1/0000755000175000017500000000000014574600735014641 5ustar00wethjowethjo././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/AUTHORS0000644000175000017500000000015714574600307015707 0ustar00wethjowethjoJosh Bohde Germán M. Bravo Jannis Leidel Daniel Lindsley Stefan Wehrmeyer Dominik George ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/LICENSE0000644000175000017500000000301414574600307015637 0ustar00wethjowethjoCopyright (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=1710424263.0 celery-haystack-ng-2.0.1/MANIFEST.in0000644000175000017500000000006314574600307016371 0ustar00wethjowethjoinclude AUTHORS include LICENSE include README.rst ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1710424540.792483 celery-haystack-ng-2.0.1/PKG-INFO0000644000175000017500000000601314574600735015736 0ustar00wethjowethjoMetadata-Version: 2.1 Name: celery-haystack-ng Version: 2.0.1 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 Project-URL: Code, https://edugit.org/AlekSIS/libs/celery-haystack-ng 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 License-File: LICENSE License-File: AUTHORS Requires-Dist: django-appconf>=0.4.1 Requires-Dist: django-haystack>=2.0 Requires-Dist: celery>=4.0 ================== 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/README.rst0000644000175000017500000000437714574600307016336 0ustar00wethjowethjo================== 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=1710424540.792483 celery-haystack-ng-2.0.1/celery_haystack/0000755000175000017500000000000014574600735020013 5ustar00wethjowethjo././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424449.0 celery-haystack-ng-2.0.1/celery_haystack/__init__.py0000644000175000017500000000002614574600601022112 0ustar00wethjowethjo__version__ = '2.0.1' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/conf.py0000644000175000017500000000425114574600307021307 0ustar00wethjowethjofrom 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', "celery_haystack.signals.CelerySignalProcessor") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/indexes.py0000644000175000017500000000012614574600307022016 0ustar00wethjowethjofrom haystack import indexes class CelerySearchIndex(indexes.SearchIndex): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/signals.py0000644000175000017500000000406714574600307022027 0ustar00wethjowethjofrom django.db import transaction from django.db.models import signals from haystack.signals import RealtimeSignalProcessor from haystack.exceptions import NotHandled from haystack.utils import get_identifier from .conf import settings from .utils import get_update_task from .indexes import CelerySearchIndex class CelerySignalProcessor(RealtimeSignalProcessor): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._queue = [] self._on_commit_registered = False def handle_save(self, sender, instance, **kwargs): return self.enqueue('update', instance, sender, **kwargs) def handle_delete(self, sender, instance, **kwargs): return self.enqueue('delete', instance, sender, **kwargs) def run_task(self): options = {} if settings.CELERY_HAYSTACK_QUEUE: options['queue'] = settings.CELERY_HAYSTACK_QUEUE if settings.CELERY_HAYSTACK_COUNTDOWN: options['countdown'] = settings.CELERY_HAYSTACK_COUNTDOWN if self._queue: task = get_update_task() task.apply_async((self._queue,), {}, **options) self._queue = [] 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 self._queue.append((action, get_identifier(instance))) if not self._on_commit_registered: transaction.on_commit(self.run_task) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/tasks.py0000644000175000017500000001513514574600307021512 0ustar00wethjowethjofrom 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__) @current_app.register_task 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, queue, **kwargs): """Trigger actual index handler for a list of actions.""" for action, identifier in queue: self._run_one(action, identifier) def _run_one(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) @current_app.register_task 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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/test_settings.py0000644000175000017500000000152714574600307023264 0ustar00wethjowethjoimport 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=1710424540.792483 celery-haystack-ng-2.0.1/celery_haystack/tests/0000755000175000017500000000000014574600735021155 5ustar00wethjowethjo././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/tests/__init__.py0000644000175000017500000000000014574600307023247 0ustar00wethjowethjo././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/tests/models.py0000644000175000017500000000022214574600307023001 0ustar00wethjowethjofrom django.db import models class Note(models.Model): content = models.TextField() def __unicode__(self): return self.content ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/tests/search_indexes.py0000644000175000017500000000046614574600307024514 0ustar00wethjowethjofrom 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=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/tests/search_sites.py0000644000175000017500000000005114574600307024172 0ustar00wethjowethjoimport haystack haystack.autodiscover() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/tests/tests.py0000644000175000017500000000475214574600307022674 0ustar00wethjowethjofrom 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=1710424263.0 celery-haystack-ng-2.0.1/celery_haystack/utils.py0000644000175000017500000000140214574600307021515 0ustar00wethjowethjofrom django.core.exceptions import ImproperlyConfigured try: from importlib import import_module except ImportError: from django.utils.importlib import import_module 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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1710424540.792483 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/0000755000175000017500000000000014574600735022171 5ustar00wethjowethjo././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424540.0 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/PKG-INFO0000644000175000017500000000601314574600734023265 0ustar00wethjowethjoMetadata-Version: 2.1 Name: celery-haystack-ng Version: 2.0.1 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 Project-URL: Code, https://edugit.org/AlekSIS/libs/celery-haystack-ng 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 License-File: LICENSE License-File: AUTHORS Requires-Dist: django-appconf>=0.4.1 Requires-Dist: django-haystack>=2.0 Requires-Dist: celery>=4.0 ================== 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424540.0 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/SOURCES.txt0000644000175000017500000000123714574600734024057 0ustar00wethjowethjoAUTHORS 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=1710424540.0 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/dependency_links.txt0000644000175000017500000000000114574600734026236 0ustar00wethjowethjo ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424426.0 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/not-zip-safe0000644000175000017500000000000114574600552024414 0ustar00wethjowethjo ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424540.0 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/requires.txt0000644000175000017500000000006714574600734024573 0ustar00wethjowethjodjango-appconf>=0.4.1 django-haystack>=2.0 celery>=4.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424540.0 celery-haystack-ng-2.0.1/celery_haystack_ng.egg-info/top_level.txt0000644000175000017500000000002014574600734024712 0ustar00wethjowethjocelery_haystack ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1710424540.7964833 celery-haystack-ng-2.0.1/setup.cfg0000644000175000017500000000144714574600735016470 0ustar00wethjowethjo[metadata] name = celery-haystack-ng version = attr: celery_haystack.__version__ author = Dominik George author_email = dominik.george@teckids.org description = An app for integrating Celery with Haystack long_description = file: README.rst url = http://celery-haystack-ng.rtfd.org/ project_urls = Code=https://edugit.org/AlekSIS/libs/celery-haystack-ng classifiers = 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] packages = find: install_requires = django-appconf>=0.4.1 django-haystack>=2.0 celery>=4.0 zip_safe = False [wheel] universal = 1 [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1710424263.0 celery-haystack-ng-2.0.1/setup.py0000644000175000017500000000007414574600307016347 0ustar00wethjowethjo#!/usr/bin/env python from setuptools import setup setup()