diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b384d05..b577c72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,18 +15,18 @@ jobs: matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] django-version: ["3.2", "4.1", "4.2"] - es-dsl-version: ["6.4", "7.4"] - es-version: ["8.10.2"] + open-dsl-version: ["2.1", "2.4"] exclude: - python-version: "3.11" django-version: "3.2" steps: - - name: Install and Run Elasticsearch - uses: elastic/elastic-github-actions/elasticsearch@master + - name: Install and Run Opensearch + uses: esmarkowski/opensearch-github-action@v1.0.0 with: - stack-version: ${{ matrix.es-version }} + version: 2.12.0 + security-disabled: true - uses: actions/checkout@v4 @@ -47,12 +47,12 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install "Django==${{ matrix.django-version }}" - python -m pip install "elasticsearch-dsl==${{ matrix.es-dsl-version }}" + python -m pip install "opensearchpy==${{ matrix.open-dsl-version }}" python -m pip install -r requirements_test.txt - - name: Run tests with Python ${{ matrix.python-version }} and Django ${{ matrix.django-version }} and elasticsearch-dsl-py ${{ matrix.es-dsl-version }} + - name: Run tests with Python ${{ matrix.python-version }} and Django ${{ matrix.django-version }} and opensearchpy ${{ matrix.open-dsl-version }} run: | - TOX_ENV=$(echo "py${{ matrix.python-version }}-django-${{ matrix.django-version }}-es${{ matrix.es-dsl-version }}" | tr -d .) + TOX_ENV=$(echo "py${{ matrix.python-version }}-django-${{ matrix.django-version }}-open${{ matrix.open-dsl-versionn }}" | tr -d .) python -m tox -e $TOX_ENV -- --elasticsearch python -m tox -e $TOX_ENV -- --elasticsearch --signal-processor celery diff --git a/HISTORY.rst b/HISTORY.rst index 250f2a6..7c5048c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -25,7 +25,7 @@ History ~~~~~~~~~~~~~~~~~~ * Support for Django `DecimalField` #141 * Indexing speedup by using `parallel` indexing. #213. - Now you can pass `--parallel` or set `ELASTICSEARCH_DSL_PARALLEL` + Now you can pass `--parallel` or set `OPENSEARCH_DSL_PARALLEL` in your settings to get indexing speed boost while indexing through management command. * Fixing name resolution in management command #206 diff --git a/MANIFEST.in b/MANIFEST.in index 56e2e68..da930fa 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,4 +3,4 @@ include CONTRIBUTING.rst include HISTORY.rst include LICENSE include README.rst -recursive-include django_elasticsearch_dsl *.html *.png *.gif *js *.css *jpg *jpeg *svg *py +recursive-include django_opensearch_dsl *.html *.png *.gif *js *.css *jpg *jpeg *svg *py diff --git a/django_elasticsearch_dsl/__init__.py b/django_opensearch_dsl/__init__.py similarity index 100% rename from django_elasticsearch_dsl/__init__.py rename to django_opensearch_dsl/__init__.py diff --git a/django_elasticsearch_dsl/apps.py b/django_opensearch_dsl/apps.py similarity index 56% rename from django_elasticsearch_dsl/apps.py rename to django_opensearch_dsl/apps.py index 73e451c..43edf11 100644 --- a/django_elasticsearch_dsl/apps.py +++ b/django_opensearch_dsl/apps.py @@ -1,36 +1,35 @@ from django.apps import AppConfig from django.conf import settings from django.utils.module_loading import import_string - -from elasticsearch_dsl.connections import connections +from opensearchpy.connection import connections class DEDConfig(AppConfig): - name = 'django_elasticsearch_dsl' - verbose_name = "Django elasticsearch-dsl" + name = 'django_opensearch_dsl' + verbose_name = "Django opensearch-dsl" signal_processor = None def ready(self): self.module.autodiscover() - connections.configure(**settings.ELASTICSEARCH_DSL) + connections.configure(**settings.OPENSEARCH_DSL) # Setup the signal processor. if not self.signal_processor: signal_processor_path = getattr( settings, - 'ELASTICSEARCH_DSL_SIGNAL_PROCESSOR', - 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor' + 'OPENSEARCH_DSL_SIGNAL_PROCESSOR', + 'django_opensearch_dsl.signals.RealTimeSignalProcessor' ) signal_processor_class = import_string(signal_processor_path) self.signal_processor = signal_processor_class(connections) @classmethod def autosync_enabled(cls): - return getattr(settings, 'ELASTICSEARCH_DSL_AUTOSYNC', True) + return getattr(settings, 'OPENSEARCH_DSL_AUTOSYNC', True) @classmethod def default_index_settings(cls): - return getattr(settings, 'ELASTICSEARCH_DSL_INDEX_SETTINGS', {}) + return getattr(settings, 'OPENSEARCH_DSL_INDEX_SETTINGS', {}) @classmethod def auto_refresh_enabled(cls): - return getattr(settings, 'ELASTICSEARCH_DSL_AUTO_REFRESH', True) + return getattr(settings, 'OPENSEARCH_DSL_AUTO_REFRESH', True) diff --git a/django_elasticsearch_dsl/documents.py b/django_opensearch_dsl/documents.py similarity index 95% rename from django_elasticsearch_dsl/documents.py rename to django_opensearch_dsl/documents.py index 4671064..6bbdcf3 100644 --- a/django_elasticsearch_dsl/documents.py +++ b/django_opensearch_dsl/documents.py @@ -6,11 +6,11 @@ from django import VERSION as DJANGO_VERSION from django.db import models -from elasticsearch.helpers import bulk, parallel_bulk -from elasticsearch_dsl import Document as DSLDocument +from opensearchpy.helpers import bulk, parallel_bulk +from opensearchpy import Document as DSLDocument from six import iteritems -from .exceptions import ModelFieldNotMappedError +from .exceptions import ModelFieldNotMappedError, RedeclaredFieldError from .fields import ( BooleanField, DateField, @@ -150,7 +150,7 @@ def prepare(self, instance): @classmethod def get_model_field_class_to_field_class(cls): """ - Returns dict of relationship from model field class to elasticsearch + Returns dict of relationship from model field class to opensearch field class You may want to override this if you have model field class not included @@ -161,7 +161,7 @@ def get_model_field_class_to_field_class(cls): @classmethod def to_field(cls, field_name, model_field): """ - Returns the elasticsearch field instance appropriate for the model + Returns the opensearch field instance appropriate for the model field class. This is a good place to hook into if you have more complex model field to ES field logic """ @@ -200,7 +200,7 @@ def parallel_bulk(self, actions, **kwargs): def generate_id(cls, object_instance): """ The default behavior is to use the Django object's pk (id) as the - elasticseach index id (_id). If needed, this method can be overloaded + opensearch index id (_id). If needed, this method can be overloaded to change this default behavior. """ return object_instance.pk @@ -219,10 +219,10 @@ def _get_actions(self, object_list, action): for object_instance in object_list: if action == 'delete' or self.should_index_object(object_instance): yield self._prepare_action(object_instance, action) - + def get_actions(self, object_list, action): """ - Generate the elasticsearch payload. + Generate the opensearch payload. """ return self._get_actions(object_list, action) diff --git a/django_elasticsearch_dsl/exceptions.py b/django_opensearch_dsl/exceptions.py similarity index 100% rename from django_elasticsearch_dsl/exceptions.py rename to django_opensearch_dsl/exceptions.py diff --git a/django_elasticsearch_dsl/fields.py b/django_opensearch_dsl/fields.py similarity index 97% rename from django_elasticsearch_dsl/fields.py rename to django_opensearch_dsl/fields.py index 2652b68..b310690 100644 --- a/django_elasticsearch_dsl/fields.py +++ b/django_opensearch_dsl/fields.py @@ -1,16 +1,12 @@ from types import MethodType -import django from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.db.models.fields.files import FieldFile -if django.VERSION < (4, 0): - from django.utils.encoding import force_text as force_str -else: - from django.utils.encoding import force_str +from django.utils.encoding import force_str from django.utils.functional import Promise -from elasticsearch_dsl.field import ( +from opensearchpy.helpers.field import ( Boolean, Byte, Completion, diff --git a/django_elasticsearch_dsl/indices.py b/django_opensearch_dsl/indices.py similarity index 93% rename from django_elasticsearch_dsl/indices.py rename to django_opensearch_dsl/indices.py index 115874d..d162f4f 100644 --- a/django_elasticsearch_dsl/indices.py +++ b/django_opensearch_dsl/indices.py @@ -1,6 +1,6 @@ from copy import deepcopy -from elasticsearch_dsl import Index as DSLIndex +from opensearchpy import Index as DSLIndex from six import python_2_unicode_compatible from .apps import DEDConfig diff --git a/django_elasticsearch_dsl/management/__init__.py b/django_opensearch_dsl/management/__init__.py similarity index 100% rename from django_elasticsearch_dsl/management/__init__.py rename to django_opensearch_dsl/management/__init__.py diff --git a/django_elasticsearch_dsl/management/commands/__init__.py b/django_opensearch_dsl/management/commands/__init__.py similarity index 100% rename from django_elasticsearch_dsl/management/commands/__init__.py rename to django_opensearch_dsl/management/commands/__init__.py diff --git a/django_elasticsearch_dsl/management/commands/search_index.py b/django_opensearch_dsl/management/commands/search_index.py similarity index 96% rename from django_elasticsearch_dsl/management/commands/search_index.py rename to django_opensearch_dsl/management/commands/search_index.py index 06bf851..41f4470 100644 --- a/django_elasticsearch_dsl/management/commands/search_index.py +++ b/django_opensearch_dsl/management/commands/search_index.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals, absolute_import from datetime import datetime -from elasticsearch_dsl import connections +from opensearchpy.connection import connections from django.conf import settings from django.core.management.base import BaseCommand, CommandError from six.moves import input @@ -9,7 +9,7 @@ class Command(BaseCommand): - help = 'Manage elasticsearch index.' + help = 'Manage opensearch index.' def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) @@ -21,28 +21,28 @@ def add_arguments(self, parser): metavar='app[.model]', type=str, nargs='*', - help="Specify the model or app to be updated in elasticsearch" + help="Specify the model or app to be updated in opensearch" ) parser.add_argument( '--create', action='store_const', dest='action', const='create', - help="Create the indices in elasticsearch" + help="Create the indices in opensearch" ) parser.add_argument( '--populate', action='store_const', dest='action', const='populate', - help="Populate elasticsearch indices with models data" + help="Populate opensearch indices with models data" ) parser.add_argument( '--delete', action='store_const', dest='action', const='delete', - help="Delete the indices in elasticsearch" + help="Delete the indices in opensearch" ) parser.add_argument( '--rebuild', @@ -84,7 +84,7 @@ def add_arguments(self, parser): '--use-alias' args """ ) - parser.set_defaults(parallel=getattr(settings, 'ELASTICSEARCH_DSL_PARALLEL', False)) + parser.set_defaults(parallel=getattr(settings, 'OPENSEARCH_DSL_PARALLEL', False)) parser.add_argument( '--refresh', action='store_true', diff --git a/django_elasticsearch_dsl/models.py b/django_opensearch_dsl/models.py similarity index 100% rename from django_elasticsearch_dsl/models.py rename to django_opensearch_dsl/models.py diff --git a/django_elasticsearch_dsl/registries.py b/django_opensearch_dsl/registries.py similarity index 95% rename from django_elasticsearch_dsl/registries.py rename to django_opensearch_dsl/registries.py index e2623dd..edfe3ef 100644 --- a/django_elasticsearch_dsl/registries.py +++ b/django_opensearch_dsl/registries.py @@ -5,11 +5,11 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ImproperlyConfigured -from elasticsearch_dsl import AttrDict +from opensearchpy import AttrDict from six import itervalues, iterkeys, iteritems -from django_elasticsearch_dsl.exceptions import RedeclaredFieldError from .apps import DEDConfig +from .exceptions import RedeclaredFieldError class DocumentRegistry(object): @@ -129,7 +129,7 @@ def delete_related(self, instance, **kwargs): def update(self, instance, **kwargs): """ - Update all the elasticsearch documents attached to this model (if their + Update all the opensearch documents attached to this model (if their ignore_signals flag allows it) """ if not DEDConfig.autosync_enabled(): @@ -142,7 +142,7 @@ def update(self, instance, **kwargs): def delete(self, instance, **kwargs): """ - Delete all the elasticsearch documents attached to this model (if their + Delete all the opensearch documents attached to this model (if their ignore_signals flag allows it) """ self.update(instance, action="delete", **kwargs) diff --git a/django_elasticsearch_dsl/search.py b/django_opensearch_dsl/search.py similarity index 90% rename from django_elasticsearch_dsl/search.py rename to django_opensearch_dsl/search.py index bc66d82..c6ee12a 100644 --- a/django_elasticsearch_dsl/search.py +++ b/django_opensearch_dsl/search.py @@ -1,7 +1,7 @@ from django.db.models import Case, When from django.db.models.fields import IntegerField -from elasticsearch_dsl import Search as DSLSearch +from opensearchpy import Search as DSLSearch class Search(DSLSearch): @@ -16,7 +16,7 @@ def _clone(self): def filter_queryset(self, queryset, keep_search_order=True): """ - Filter an existing django queryset using the elasticsearch result. + Filter an existing django queryset using the opensearch result. It costs a query to the sql db. """ s = self @@ -52,7 +52,7 @@ def _get_queryset(self): def to_queryset(self, keep_order=True): """ - Return a django queryset from the elasticsearch result. + Return a django queryset from the opensearch result. It costs a query to the sql db. """ qs = self._get_queryset() diff --git a/django_elasticsearch_dsl/signals.py b/django_opensearch_dsl/signals.py similarity index 97% rename from django_elasticsearch_dsl/signals.py rename to django_opensearch_dsl/signals.py index 48f4224..dac3bfa 100644 --- a/django_elasticsearch_dsl/signals.py +++ b/django_opensearch_dsl/signals.py @@ -1,6 +1,6 @@ # encoding: utf-8 """ -A convenient way to attach django-elasticsearch-dsl to Django's signals and +A convenient way to attach django-opensearch-dsl to Django's signals and cause things to index. """ @@ -169,8 +169,8 @@ def prepare_registry_delete_related_task(self, instance): def registry_delete_task(doc_label, data): """ Handle the bulk delete data on the registry as a Celery task. - The different implementations used are due to the difference between delete and update operations. - The update operation can re-read the updated data from the database to ensure eventual consistency, + The different implementations used are due to the difference between delete and update operations. + The update operation can re-read the updated data from the database to ensure eventual consistency, but the delete needs to be processed before the database record is deleted to obtain the associated data. """ doc_instance = import_module(doc_label) diff --git a/django_elasticsearch_dsl/test/__init__.py b/django_opensearch_dsl/test/__init__.py similarity index 100% rename from django_elasticsearch_dsl/test/__init__.py rename to django_opensearch_dsl/test/__init__.py diff --git a/django_elasticsearch_dsl/test/testcases.py b/django_opensearch_dsl/test/testcases.py similarity index 94% rename from django_elasticsearch_dsl/test/testcases.py rename to django_opensearch_dsl/test/testcases.py index 12c3a80..7179797 100644 --- a/django_elasticsearch_dsl/test/testcases.py +++ b/django_opensearch_dsl/test/testcases.py @@ -1,7 +1,7 @@ import re from django.test.utils import captured_stderr -from elasticsearch_dsl.connections import connections +from opensearchpy.connection.connections import connections from ..registries import registry diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c831dc9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,46 @@ +--- +version: '3' +services: + opensearch-node1: + image: opensearchproject/opensearch:2.11.1 + container_name: opensearch-node1 + environment: + - cluster.name=opensearch-cluster + - node.name=opensearch-node1 + - discovery.type=single-node + - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping + - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m # minimum and maximum Java heap size, recommend setting both to 50% of system RAM + - DISABLE_INSTALL_DEMO_CONFIG=true + - DISABLE_SECURITY_PLUGIN=true + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 # maximum number of open files for the OpenSearch user, set to at least 65536 on modern systems + hard: 65536 + volumes: + - opensearch-data1:/usr/share/opensearch/data + ports: + - 9200:9200 + - 9600:9600 # required for Performance Analyzer + networks: + - opensearch-net + opensearch-dashboards: + image: opensearchproject/opensearch-dashboards:2.11.1 + container_name: opensearch-dashboards + ports: + - 5601:5601 + expose: + - '5601' + environment: + OPENSEARCH_HOSTS: '["http://opensearch-node1:9200"]' + networks: + - opensearch-net + +volumes: + opensearch-data1: + opensearch-data2: + +networks: + opensearch-net: diff --git a/docs/source/conf.py b/docs/source/conf.py index 21e7a78..6010de1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -235,7 +235,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'django_elasticsearch_dsl.tex', 'Django Elasticsearch DSL Documentation', + (master_doc, 'django_opensearch_dsl.tex', 'Django Elasticsearch DSL Documentation', author, 'manual'), ] @@ -265,7 +265,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'django_elasticsearch_dsl', 'Django Elasticsearc DSL Documentation', + (master_doc, 'django_opensearch_dsl', 'Django Elasticsearc DSL Documentation', [author], 1) ] @@ -279,8 +279,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'django_elasticsearch_dsl', 'Django Elasticsearch DSL Documentation', - author, 'django_elasticsearch_dsl', 'elasticsearch-dsl intégration in Django', + (master_doc, 'django_opensearch_dsl', 'Django Elasticsearch DSL Documentation', + author, 'django_opensearch_dsl', 'elasticsearch-dsl intégration in Django', 'Miscellaneous'), ] diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index f3b02b8..c49a668 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -12,20 +12,20 @@ Install Django Elasticsearch DSL:: Then add ``django_elasticsearch_dsl`` to the INSTALLED_APPS -You must define ``ELASTICSEARCH_DSL`` in your django settings. +You must define ``OPENSEARCH_DSL`` in your django settings. For example: .. code-block:: python - ELASTICSEARCH_DSL={ + OPENSEARCH_DSL={ 'default': { 'hosts': 'localhost:9200', 'http_auth': ('username', 'password') } } -``ELASTICSEARCH_DSL`` is then passed to ``elasticsearch-dsl-py.connections.configure`` (see here_). +``OPENSEARCH_DSL`` is then passed to ``elasticsearch-dsl-py.connections.configure`` (see here_). .. _here: http://elasticsearch-dsl.readthedocs.io/en/stable/configuration.html#multiple-clusters @@ -91,7 +91,7 @@ It is required to define ``Document`` class in ``documents.py`` in your app dir # Configure how the index should be refreshed after an update. # See Elasticsearch documentation for supported options: # https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-refresh.html - # This per-Document setting overrides settings.ELASTICSEARCH_DSL_AUTO_REFRESH. + # This per-Document setting overrides settings.OPENSEARCH_DSL_AUTO_REFRESH. # auto_refresh = False # Paginate the django queryset used to populate the index with the specified size diff --git a/docs/source/settings.rst b/docs/source/settings.rst index ae8d5ee..51e2b5c 100644 --- a/docs/source/settings.rst +++ b/docs/source/settings.rst @@ -2,28 +2,28 @@ Settings ######## -ELASTICSEARCH_DSL_AUTOSYNC +OPENSEARCH_DSL_AUTOSYNC ========================== Default: ``True`` Set to ``False`` to globally disable auto-syncing. -ELASTICSEARCH_DSL_INDEX_SETTINGS +OPENSEARCH_DSL_INDEX_SETTINGS ================================ Default: ``{}`` Additional options passed to the elasticsearch-dsl Index settings (like ``number_of_replicas`` or ``number_of_shards``). -ELASTICSEARCH_DSL_AUTO_REFRESH +OPENSEARCH_DSL_AUTO_REFRESH ============================== Default: ``True`` Set to ``False`` not force an `index refresh `_ with every save. -ELASTICSEARCH_DSL_SIGNAL_PROCESSOR +OPENSEARCH_DSL_SIGNAL_PROCESSOR ================================== This (optional) setting controls what SignalProcessor class is used to handle @@ -33,7 +33,7 @@ An example: .. code-block:: python - ELASTICSEARCH_DSL_SIGNAL_PROCESSOR = 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor' + OPENSEARCH_DSL_SIGNAL_PROCESSOR = 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor' Defaults to ``django_elasticsearch_dsl.signals.RealTimeSignalProcessor``. @@ -47,7 +47,7 @@ And celery needs to be pre-configured in the django project, for example `Using You could, for instance, make a ``CustomSignalProcessor`` which would apply update jobs as your wish. -ELASTICSEARCH_DSL_PARALLEL +OPENSEARCH_DSL_PARALLEL ========================== Default: ``False`` diff --git a/example/README.rst b/example/README.rst index 27335c3..73a8118 100644 --- a/example/README.rst +++ b/example/README.rst @@ -2,7 +2,7 @@ Django Elasticsearch DSL Test App ================================= -Simple django app for test some django-elasticsearch-dsl features. +Simple django app for test some django-opensearchpy-dsl features. Installation @@ -18,7 +18,7 @@ connections setting in example/settings.py. .. code:: python - ELASTICSEARCH_DSL={ + OPENSEARCH_DSL={ 'default': { 'hosts': 'localhost:9200' }, diff --git a/example/example/settings.py b/example/example/settings.py index 9367615..035e00f 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -34,7 +34,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', - 'django_elasticsearch_dsl', + 'django_opensearch_dsl', # if your app has other dependencies that need to be added to the site # they should be added here @@ -81,13 +81,13 @@ } } -ELASTICSEARCH_DSL = { +OPENSEARCH_DSL = { 'default': { 'hosts': 'localhost:9200' }, } -ELASTICSEARCH_DSL_INDEX_SETTINGS = { +OPENSEARCH_DSL_INDEX_SETTINGS = { 'number_of_shards': 1 } diff --git a/example/test_app/documents.py b/example/test_app/documents.py index e1e449d..bd73e01 100644 --- a/example/test_app/documents.py +++ b/example/test_app/documents.py @@ -1,6 +1,6 @@ -from elasticsearch_dsl import analyzer -from django_elasticsearch_dsl import Document, Index, fields -from django_elasticsearch_dsl.registries import registry +from opensearchpy import analyzer +from django_opensearchpy_dsl import Document, Index, fields +from django_opensearchpy_dsl.registries import registry from .models import Ad, Car, Manufacturer diff --git a/requirements.txt b/requirements.txt index 53d79b3..fb79a42 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ django>=3.2 -elasticsearch-dsl>=8.0.0,<9.0.0 +opensearch-py diff --git a/requirements_dev.txt b/requirements_dev.txt index 43b5c3f..e1accee 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,7 +1,7 @@ bumpversion==0.6.0 wheel==0.41.2 django>=3.2 -elasticsearch-dsl>=7.0.0,<8.0.0 +opensearch-py twine sphinx -e . diff --git a/runtests.py b/runtests.py index 0b61338..52d4736 100644 --- a/runtests.py +++ b/runtests.py @@ -11,17 +11,17 @@ def get_settings(signal_processor): elasticsearch_dsl_default_settings = { 'hosts': os.environ.get( - 'ELASTICSEARCH_URL', + 'OPENSEARCH_URL', 'https://127.0.0.1:9200' ), 'basic_auth': ( - os.environ.get('ELASTICSEARCH_USERNAME'), - os.environ.get('ELASTICSEARCH_PASSWORD') + os.environ.get('OPENSEARCH_USERNAME'), + os.environ.get('OPENSEARCH_PASSWORD') ) } elasticsearch_certs_path = os.environ.get( - 'ELASTICSEARCH_CERTS_PATH' + 'OPENSEARCH_CERTS_PATH' ) if elasticsearch_certs_path: elasticsearch_dsl_default_settings['ca_certs'] = ( @@ -31,8 +31,8 @@ def get_settings(signal_processor): elasticsearch_dsl_default_settings['verify_certs'] = False PROCESSOR_CLASSES = { - 'realtime': 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor', - 'celery': 'django_elasticsearch_dsl.signals.CelerySignalProcessor', + 'realtime': 'django_opensearch_dsl.signals.RealTimeSignalProcessor', + 'celery': 'django_opensearch_dsl.signals.CelerySignalProcessor', } signal_processor = PROCESSOR_CLASSES[signal_processor] @@ -48,19 +48,19 @@ def get_settings(signal_processor): "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sites", - "django_elasticsearch_dsl", + "django_opensearch_dsl", "tests", ], SITE_ID=1, MIDDLEWARE_CLASSES=(), - ELASTICSEARCH_DSL={ + OPENSEARCH_DSL={ 'default': elasticsearch_dsl_default_settings }, DEFAULT_AUTO_FIELD="django.db.models.BigAutoField", CELERY_BROKER_URL='memory://localhost/', CELERY_TASK_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, - ELASTICSEARCH_DSL_SIGNAL_PROCESSOR=signal_processor + OPENSEARCH_DSL_SIGNAL_PROCESSOR=signal_processor ) try: @@ -120,20 +120,20 @@ def make_parser(): def run_tests(*test_args): args, test_args = make_parser().parse_known_args(test_args) if args.elasticsearch: - os.environ.setdefault('ELASTICSEARCH_URL', "https://127.0.0.1:9200") + os.environ.setdefault('OPENSEARCH_URL', "https://127.0.0.1:9200") username = args.elasticsearch_username or "elastic" password = args.elasticsearch_password or "changeme" os.environ.setdefault( - 'ELASTICSEARCH_USERNAME', username + 'OPENSEARCH_USERNAME', username ) os.environ.setdefault( - 'ELASTICSEARCH_PASSWORD', password + 'OPENSEARCH_PASSWORD', password ) if args.elasticsearch_certs_path: os.environ.setdefault( - 'ELASTICSEARCH_CERTS_PATH', args.elasticsearch_certs_path + 'OPENSEARCH_CERTS_PATH', args.elasticsearch_certs_path ) if not test_args: diff --git a/setup.cfg b/setup.cfg index e3fc229..fb9b20d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,7 +5,7 @@ tag = True [bumpversion:file:setup.py] -[bumpversion:file:django_elasticsearch_dsl/__init__.py] +[bumpversion:file:django_opensearch_dsl/__init__.py] [bumpversion:file:docs/source/conf.py] diff --git a/setup.py b/setup.py index a3c60e1..52e64a5 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ author='Sabricot', url='https://github.com/sabricot/django-elasticsearch-dsl', packages=[ - 'django_elasticsearch_dsl', + 'django_opensearch_dsl', ], include_package_data=True, install_requires=[ diff --git a/tests/__init__.py b/tests/__init__.py index 7f06df2..6f5522a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,3 @@ -from elasticsearch_dsl import VERSION +from opensearchpy import VERSION ES_MAJOR_VERSION = VERSION[0] diff --git a/tests/documents.py b/tests/documents.py index 08ef83f..9bfc9a0 100644 --- a/tests/documents.py +++ b/tests/documents.py @@ -1,6 +1,6 @@ -from elasticsearch_dsl import analyzer -from django_elasticsearch_dsl import Document, fields -from django_elasticsearch_dsl.registries import registry +from opensearchpy import analyzer +from django_opensearch_dsl import Document, fields +from django_opensearch_dsl.registries import registry from .models import Ad, Category, Car, Manufacturer, Article diff --git a/tests/fixtures.py b/tests/fixtures.py index 4d3bad9..49d9f69 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -2,7 +2,7 @@ from django.db import models -from django_elasticsearch_dsl.documents import DocType +from django_opensearch_dsl.documents import DocType class WithFixturesMixin(object): diff --git a/tests/test_commands.py b/tests/test_commands.py index 6d78738..5266b17 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -5,9 +5,9 @@ from django.core.management import call_command from six import StringIO -from django_elasticsearch_dsl import Index -from django_elasticsearch_dsl.management.commands.search_index import Command -from django_elasticsearch_dsl.registries import DocumentRegistry +from django_opensearch_dsl import Index +from django_opensearch_dsl.management.commands.search_index import Command +from django_opensearch_dsl.registries import DocumentRegistry from .fixtures import WithFixturesMixin @@ -16,7 +16,7 @@ class SearchIndexTestCase(WithFixturesMixin, TestCase): def _mock_setup(self): # Mock Patch object patch_registry = patch( - 'django_elasticsearch_dsl.management.commands.search_index.registry', self.registry) + 'django_opensearch_dsl.management.commands.search_index.registry', self.registry) patch_registry.start() @@ -83,7 +83,7 @@ def test_no_action_error(self): def test_delete_foo_index(self): with patch( - 'django_elasticsearch_dsl.management.commands.search_index.input', + 'django_opensearch_dsl.management.commands.search_index.input', Mock(return_value="y") ): call_command('search_index', stdout=self.out, diff --git a/tests/test_documents.py b/tests/test_documents.py index d7dd2ac..c0a13c9 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -10,15 +10,13 @@ from django.utils.translation import ugettext_lazy as _ else: from django.utils.translation import gettext_lazy as _ -from elasticsearch_dsl import GeoPoint, InnerDoc +from opensearchpy import GeoPoint, InnerDoc from mock import patch, Mock -from django_elasticsearch_dsl import fields -from django_elasticsearch_dsl.documents import DocType -from django_elasticsearch_dsl.exceptions import (ModelFieldNotMappedError, - RedeclaredFieldError) -from django_elasticsearch_dsl.registries import registry -from tests import ES_MAJOR_VERSION +from django_opensearch_dsl import fields +from django_opensearch_dsl.documents import DocType +from django_opensearch_dsl.exceptions import (ModelFieldNotMappedError, RedeclaredFieldError) +from django_opensearch_dsl.registries import registry from .models import Article @@ -72,10 +70,10 @@ class BaseDocTypeTestCase(object): @classmethod def setUpClass(cls): from django.conf import settings - if cls.TARGET_PROCESSOR != settings.ELASTICSEARCH_DSL_SIGNAL_PROCESSOR: + if cls.TARGET_PROCESSOR != settings.OPENSEARCH_DSL_SIGNAL_PROCESSOR: raise SkipTest( "Skipped because {} is required, not {}".format( - cls.TARGET_PROCESSOR, settings.ELASTICSEARCH_DSL_SIGNAL_PROCESSOR + cls.TARGET_PROCESSOR, settings.OPENSEARCH_DSL_SIGNAL_PROCESSOR ) ) super(BaseDocTypeTestCase,cls).setUpClass() @@ -151,7 +149,7 @@ def test_to_field_with_unknown_field(self): doc.to_field('manufacturer', Car._meta.get_field('manufacturer')) def test_mapping(self): - text_type = 'string' if ES_MAJOR_VERSION == 2 else 'text' + text_type = 'text' self.assertEqual( CarDocument._doc_type.mapping.to_dict(), { @@ -253,7 +251,7 @@ def test_model_instance_update(self): doc = CarDocument() car = Car(name="Type 57", price=5400000.0, not_indexed="not_indexex", pk=51) - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update(car) actions = [{ '_id': car.pk, @@ -281,7 +279,7 @@ def test_model_instance_iterable_update(self): not_indexed="not_indexex", pk=51) car2 = Car(name=_("Type 42"), price=50000.0, not_indexed="not_indexex", pk=31) - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update([car, car2], action='update') actions = [{ '_id': car.pk, @@ -318,7 +316,7 @@ def test_model_instance_update_no_refresh(self): doc = CarDocument() doc.django.auto_refresh = False car = Car() - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update(car) self.assertNotIn('refresh', mock.call_args_list[0][1]) @@ -326,7 +324,7 @@ def test_model_instance_update_refresh_true(self): doc = CarDocument() doc.django.auto_refresh = False car = Car() - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update(car, refresh=True) self.assertEqual( mock.call_args_list[0][1]['refresh'], True @@ -336,7 +334,7 @@ def test_model_instance_update_refresh_wait_for(self): doc = CarDocument() doc.django.auto_refresh = False car = Car() - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update(car, refresh='wait_for') self.assertEqual( mock.call_args_list[0][1]['refresh'], 'wait_for' @@ -346,7 +344,7 @@ def test_model_instance_update_auto_refresh_wait_for(self): doc = CarDocument() doc.django.auto_refresh = 'wait_for' car = Car() - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update(car) self.assertEqual( mock.call_args_list[0][1]['refresh'], 'wait_for' @@ -356,7 +354,7 @@ def test_model_instance_update_refresh_overrides_auto_refresh(self): doc = CarDocument() doc.django.auto_refresh = True car = Car() - with patch('django_elasticsearch_dsl.documents.bulk') as mock: + with patch('django_opensearch_dsl.documents.bulk') as mock: doc.update(car, refresh=False) self.assertEqual( mock.call_args_list[0][1]['refresh'], False @@ -373,8 +371,8 @@ class Django: car2 = Car() car3 = Car() - bulk = "django_elasticsearch_dsl.documents.bulk" - parallel_bulk = "django_elasticsearch_dsl.documents.parallel_bulk" + bulk = "django_opensearch_dsl.documents.bulk" + parallel_bulk = "django_opensearch_dsl.documents.parallel_bulk" with patch(bulk) as mock_bulk, patch(parallel_bulk) as mock_parallel_bulk: doc.update([car1, car2, car3]) self.assertEqual( @@ -393,8 +391,8 @@ class Django: car1 = Car() car2 = Car() car3 = Car() - bulk = "django_elasticsearch_dsl.documents.bulk" - parallel_bulk = "django_elasticsearch_dsl.documents.parallel_bulk" + bulk = "django_opensearch_dsl.documents.bulk" + parallel_bulk = "django_opensearch_dsl.documents.parallel_bulk" with patch(bulk) as mock_bulk, patch(parallel_bulk) as mock_parallel_bulk: doc.update([car1, car2, car3], parallel=True) self.assertEqual(mock_bulk.call_count, 0, "bulk is not called") @@ -407,13 +405,13 @@ def test_init_prepare_correct(self): self.assertEqual(len(d._prepared_fields), 4) expect = { - 'color': ("", + 'color': ("", ("", "")), # py3, py2 - 'type': ("", + 'type': ("", ("", "")), - 'name': ("", + 'name': ("", ("", "")), - 'price': ("", + 'price': ("", ("", "")), } @@ -451,9 +449,9 @@ def test_init_prepare_results(self): # Mock the elasticsearch connection because we need to execute the bulk so that the generator # got iterated and generate_id called. - # If we mock the bulk in django_elasticsearch_dsl.document + # If we mock the bulk in django_opensearch_dsl.document # the actual bulk will be never called and the test will fail - @patch('elasticsearch_dsl.connections.Elasticsearch.bulk') + @patch('opensearchpy.OpenSearch.bulk') def test_default_generate_id_is_called(self, _): article = Article( id=124594, @@ -481,7 +479,7 @@ class Index: d.update(article) patched_method.assert_called() - @patch('elasticsearch_dsl.connections.Elasticsearch.bulk') + @patch('opensearchpy.OpenSearch.bulk') def test_custom_generate_id_is_called(self, mock_bulk): article = Article( id=54218, @@ -508,16 +506,16 @@ def generate_id(cls, article): # Get the data from the elasticsearch low level API because # The generator get executed there. - data = json.loads(mock_bulk.call_args[1]['operations'][1]) + data = json.loads(mock_bulk.call_args[0][0].split()[1]) assert data['slug'] == article.slug - @patch('elasticsearch_dsl.connections.Elasticsearch.bulk') + @patch('opensearchpy.OpenSearch.bulk') def test_should_index_object_is_called(self, mock_bulk): doc = CarDocument() car1 = Car() car2 = Car() car3 = Car() - should_index_object = ("django_elasticsearch_dsl.documents." + should_index_object = ("django_opensearch_dsl.documents." "DocType.should_index_object") with patch(should_index_object) as mock_should_index_object: doc.update([car1, car2, car3]) @@ -525,7 +523,7 @@ def test_should_index_object_is_called(self, mock_bulk): self.assertEqual(mock_should_index_object.call_count, 3, "should_index_object is called") - @patch('elasticsearch_dsl.connections.Elasticsearch.bulk') + @patch('opensearchpy.OpenSearch.bulk') def test_should_index_object_working_perfectly(self, mock_bulk): article1 = Article(slug='article1') article2 = Article(slug='article2') @@ -549,7 +547,7 @@ def should_index_object(self, obj): d = ArticleDocument() d.update([article1, article2]) - operations = mock_bulk.call_args[1]['operations'] + operations = mock_bulk.call_args[0][0].split() slugs = [ json.loads(operation)['slug'] for operation in operations if 'slug' in json.loads(operation) @@ -558,8 +556,8 @@ def should_index_object(self, obj): self.assertTrue(article2.slug not in slugs) class RealTimeDocTypeTestCase(BaseDocTypeTestCase, TestCase): - TARGET_PROCESSOR = 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor' + TARGET_PROCESSOR = 'django_opensearch_dsl.signals.RealTimeSignalProcessor' class CeleryDocTypeTestCase(BaseDocTypeTestCase, TestCase): - TARGET_PROCESSOR = 'django_elasticsearch_dsl.signals.CelerySignalProcessor' + TARGET_PROCESSOR = 'django_opensearch_dsl.signals.CelerySignalProcessor' diff --git a/tests/test_fields.py b/tests/test_fields.py index edcffe8..d574cf0 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -9,15 +9,14 @@ from mock import Mock, NonCallableMock from six import string_types -from django_elasticsearch_dsl.exceptions import VariableLookupError -from django_elasticsearch_dsl.fields import (BooleanField, ByteField, CompletionField, DEDField, +from django_opensearch_dsl.exceptions import VariableLookupError +from django_opensearch_dsl.fields import (BooleanField, ByteField, CompletionField, DEDField, DateField, DoubleField, FileField, FloatField, GeoPointField, GeoShapeField, IntegerField, IpField, KeywordField, ListField, LongField, NestedField, ObjectField, ScaledFloatField, ShortField, TextField ) -from tests import ES_MAJOR_VERSION class DEDFieldTestCase(TestCase): @@ -80,7 +79,7 @@ def test_get_mapping(self): 'last_name': TextField() }) - expected_type = 'string' if ES_MAJOR_VERSION == 2 else 'text' + expected_type = 'text' self.assertEqual({ 'type': 'object', @@ -257,7 +256,7 @@ def test_get_mapping(self): 'last_name': TextField() }) - expected_type = 'string' if ES_MAJOR_VERSION == 2 else 'text' + expected_type = 'text' self.assertEqual({ 'type': 'nested', @@ -397,7 +396,7 @@ class FileFieldTestCase(TestCase): def test_get_mapping(self): field = FileField() - expected_type = 'string' if ES_MAJOR_VERSION == 2 else 'text' + expected_type = 'text' self.assertEqual({ 'type': expected_type, @@ -424,7 +423,7 @@ class TextFieldTestCase(TestCase): def test_get_mapping(self): field = TextField() - expected_type = 'string' if ES_MAJOR_VERSION == 2 else 'text' + expected_type = 'text' self.assertEqual({ 'type': expected_type, @@ -435,12 +434,6 @@ class KeywordFieldTestCase(TestCase): def test_get_mapping(self): field = KeywordField() - if ES_MAJOR_VERSION == 2: - self.assertEqual({ - 'type': 'string', - 'index': 'not_analyzed', - }, field.to_dict()) - else: - self.assertEqual({ - 'type': 'keyword', - }, field.to_dict()) + self.assertEqual({ + 'type': 'keyword', + }, field.to_dict()) diff --git a/tests/test_indices.py b/tests/test_indices.py index 11f4f5b..d5327f7 100644 --- a/tests/test_indices.py +++ b/tests/test_indices.py @@ -3,8 +3,8 @@ from django.conf import settings -from django_elasticsearch_dsl.indices import Index -from django_elasticsearch_dsl.registries import DocumentRegistry +from django_opensearch_dsl.indices import Index +from django_opensearch_dsl.registries import DocumentRegistry from .fixtures import WithFixturesMixin @@ -15,7 +15,7 @@ def setUp(self): def test_documents_add_to_register(self): registry = self.registry - with patch('django_elasticsearch_dsl.indices.registry', new=registry): + with patch('django_opensearch_dsl.indices.registry', new=registry): index = Index('test') doc_a1 = self._generate_doc_mock(self.ModelA) doc_a2 = self._generate_doc_mock(self.ModelA) @@ -33,7 +33,7 @@ def test__str__(self): self.assertEqual(index.__str__(), 'test') def test__init__(self): - settings.ELASTICSEARCH_DSL_INDEX_SETTINGS = { + settings.OPENSEARCH_DSL_INDEX_SETTINGS = { 'number_of_replicas': 0, 'number_of_shards': 2, } @@ -44,4 +44,4 @@ def test__init__(self): 'number_of_shards': 2, }) - settings.ELASTICSEARCH_DSL_INDEX_SETTINGS = {} + settings.OPENSEARCH_DSL_INDEX_SETTINGS = {} diff --git a/tests/test_integration.py b/tests/test_integration.py index f01d578..3335f1d 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -4,16 +4,12 @@ import django from django.core.management import call_command from django.test import TestCase, TransactionTestCase -if django.VERSION < (4, 0): - from django.utils.translation import ugettext_lazy as _ -else: - from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from six import StringIO -from elasticsearch.exceptions import NotFoundError -from elasticsearch_dsl import Index as DSLIndex -from django_elasticsearch_dsl.test import ESTestCase, is_es_online -from tests import ES_MAJOR_VERSION +from opensearchpy.exceptions import NotFoundError +from opensearchpy import Index as DSLIndex +from django_opensearch_dsl.test import ESTestCase, is_es_online from .documents import ( ad_index, @@ -180,7 +176,7 @@ def test_doc_to_dict(self): def test_index_to_dict(self): self.maxDiff = None index_dict = car_index.to_dict() - text_type = 'string' if ES_MAJOR_VERSION == 2 else 'text' + text_type = 'text' test_index = DSLIndex('test_index').settings(**index_settings) test_index.document(CarDocument) diff --git a/tests/test_registries.py b/tests/test_registries.py index c72894c..edc07a7 100644 --- a/tests/test_registries.py +++ b/tests/test_registries.py @@ -3,8 +3,8 @@ from django.conf import settings -from django_elasticsearch_dsl import Index -from django_elasticsearch_dsl.registries import DocumentRegistry +from django_opensearch_dsl import Index +from django_opensearch_dsl.registries import DocumentRegistry from .fixtures import WithFixturesMixin @@ -137,10 +137,10 @@ def test_delete_instance(self): self.doc_a2.update.assert_called_once_with(instance, action='delete') def test_autosync(self): - settings.ELASTICSEARCH_DSL_AUTOSYNC = False + settings.OPENSEARCH_DSL_AUTOSYNC = False instance = self.ModelA() self.registry.update(instance) self.assertFalse(self.doc_a1.update.called) - settings.ELASTICSEARCH_DSL_AUTOSYNC = True + settings.OPENSEARCH_DSL_AUTOSYNC = True diff --git a/tests/test_signals.py b/tests/test_signals.py index d117cb6..478fcb0 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -2,17 +2,17 @@ from mock import Mock, patch -from django_elasticsearch_dsl.documents import DocType -from django_elasticsearch_dsl.registries import registry -from django_elasticsearch_dsl.signals import post_index +from django_opensearch_dsl.documents import DocType +from django_opensearch_dsl.registries import registry +from django_opensearch_dsl.signals import post_index from .models import Car class PostIndexSignalTestCase(TestCase): - @patch('django_elasticsearch_dsl.documents.DocType._get_actions') - @patch('django_elasticsearch_dsl.documents.bulk') + @patch('django_opensearch_dsl.documents.DocType._get_actions') + @patch('django_opensearch_dsl.documents.bulk') def test_post_index_signal_sent(self, bulk, get_actions): @registry.register_document diff --git a/tox.ini b/tox.ini index 54fd05f..5431c21 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = - py{38,39,310}-django-{32,41,42}-{es64,es74} - py{311}-django-{41,42}-{es64,es74} + py{39}-django-{32,42}-{open21,open24} + py{311}-django-{41,42}-{open21,open24} [testenv] @@ -11,14 +11,11 @@ commands = coverage run --source django_elasticsearch_dsl runtests.py {posargs} deps = django-32: Django>=3.2,<3.3 - django-41: Django>=4.1,<4.2 django-42: Django>=4.2,<4.3 - es64: elasticsearch-dsl>=6.4.0,<7.0.0 - es74: elasticsearch-dsl>=7.4.0,<8 + open21: opensearch-py>=2.1.0,<2.2.0 + open24: opensearch-py>=2.4.0,<2.5.0 -r{toxinidir}/requirements_test.txt basepython = - py38: python3.8 py39: python3.9 - py310: python3.10 py311: python3.11