From dce8aca428d5aeb456c910080f57bbfc5b6ac02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ben=20St=C3=A4hli?= Date: Mon, 22 Jan 2024 21:53:39 +0100 Subject: [PATCH] black, pre-commit, ruff --- .github/workflows/ci.yml | 15 ++- .github/workflows/release.yml | 37 +++--- .gitignore | 1 - .pre-commit-config.yaml | 61 ++++++++++ CHANGELOG.txt => CHANGELOG.md | 1 - DESCRIPTION | 2 +- manage.py | 8 +- postgres_searchindex/__init__.py | 1 + postgres_searchindex/conf.py | 25 +++- .../commands/postgres_searchindex_update.py | 21 ++-- .../migrations/0001_initial.py | 58 +++++++--- postgres_searchindex/tests/__init__.py | 1 + postgres_searchindex/tests/settings.py | 108 ++++++++++++++++++ .../tests/test_app/__init__.py | 0 postgres_searchindex/tests/test_app/admin.py | 5 + .../tests/test_app/fixtures/test_app.json | 20 ++++ .../tests/test_app/index_sources.py | 20 ++++ .../tests/test_app/migrations/0001_initial.py | 29 +++++ .../migrations/0002_testmodel_published.py | 17 +++ .../tests/test_app/migrations/__init__.py | 0 postgres_searchindex/tests/test_app/models.py | 17 +++ .../tests/test_app/templates/cms_dummy.html | 0 .../templates/test_app/testmodel_detail.html | 7 ++ postgres_searchindex/tests/test_app/views.py | 7 ++ .../tests/test_contrib_cms.py | 0 postgres_searchindex/tests/test_indexing.py | 46 ++++++++ .../tests/test_multilanguage_indexing.py | 0 .../tests/test_signal_indexing.py | 0 .../tests/test_templatetags.py | 0 postgres_searchindex/tests/urls.py | 15 +++ postgres_searchindex/tests/utils/__init__.py | 2 + .../tests/utils/django_utils.py | 6 + postgres_searchindex/views.py | 9 +- pyproject.toml | 82 +++++++++++++ requirements_dev.txt | 12 +- setup.cfg | 3 - setup.py | 20 ++-- tox.ini | 30 ++--- 38 files changed, 580 insertions(+), 106 deletions(-) create mode 100644 .pre-commit-config.yaml rename CHANGELOG.txt => CHANGELOG.md (94%) create mode 100644 postgres_searchindex/tests/__init__.py create mode 100644 postgres_searchindex/tests/settings.py create mode 100644 postgres_searchindex/tests/test_app/__init__.py create mode 100644 postgres_searchindex/tests/test_app/admin.py create mode 100644 postgres_searchindex/tests/test_app/fixtures/test_app.json create mode 100644 postgres_searchindex/tests/test_app/index_sources.py create mode 100644 postgres_searchindex/tests/test_app/migrations/0001_initial.py create mode 100644 postgres_searchindex/tests/test_app/migrations/0002_testmodel_published.py create mode 100644 postgres_searchindex/tests/test_app/migrations/__init__.py create mode 100644 postgres_searchindex/tests/test_app/models.py create mode 100644 postgres_searchindex/tests/test_app/templates/cms_dummy.html create mode 100644 postgres_searchindex/tests/test_app/templates/test_app/testmodel_detail.html create mode 100644 postgres_searchindex/tests/test_app/views.py create mode 100644 postgres_searchindex/tests/test_contrib_cms.py create mode 100644 postgres_searchindex/tests/test_indexing.py create mode 100644 postgres_searchindex/tests/test_multilanguage_indexing.py create mode 100644 postgres_searchindex/tests/test_signal_indexing.py create mode 100644 postgres_searchindex/tests/test_templatetags.py create mode 100644 postgres_searchindex/tests/urls.py create mode 100644 postgres_searchindex/tests/utils/__init__.py create mode 100644 postgres_searchindex/tests/utils/django_utils.py create mode 100644 pyproject.toml delete mode 100644 setup.cfg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e83fb3..c593d7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,13 +1,13 @@ name: CI -on: [push, pull_request, ] +on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: matrix: - python: [3.8, 3.9, "3.10", "3.11"] + python: [3.8, 3.9, "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 - name: Setup Python ${{ matrix.python }} @@ -39,21 +39,20 @@ jobs: # run: tox -e py${{ matrix.python }}-${{ matrix.django }} run: tox -e py39-django32-coverage - lint: runs-on: ubuntu-latest strategy: matrix: - python: [3.9] + python: [3.12] steps: - uses: actions/checkout@v2 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python }} - - name: Install flake8 - run: pip install flake8 - - name: Run flake8 + - name: pre-commit + run: pip install pre-commit + - name: Run pre-commit # Run tox using the version of Python in `PATH` # run: tox -e py${{ matrix.python }}-${{ matrix.django }} - run: flake8 + run: pre-commit run --all-files diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a8779f5..295cf34 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,28 +1,27 @@ name: Release on PYPI on: push: - branches: [main] - + branches: [main] jobs: build-and-publish: runs-on: ubuntu-latest if: github.repository == 'bnzk/django-postgres-searchindex' steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - - name: Install build dependencies - run: | - python -m pip install --upgrade pip - pip install --upgrade setuptools wheel twine - - name: Build - run: | - python setup.py sdist - python setup.py bdist_wheel --universal - - name: Publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USER_BNZK }} - TWINE_PASSWORD: ${{ secrets.PYPI_PW_BNZK }} - run: twine upload dist/* + - name: Checkout + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade setuptools wheel twine + - name: Build + run: | + python setup.py sdist + python setup.py bdist_wheel --universal + - name: Publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USER_BNZK }} + TWINE_PASSWORD: ${{ secrets.PYPI_PW_BNZK }} + run: twine upload dist/* diff --git a/.gitignore b/.gitignore index e7bc9fa..a3ce90a 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,3 @@ coverage.xml # Sphinx documentation docs/_build/ - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4d7d9e1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,61 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +exclude: "^package.json|^package-lock.json" +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + # syntax + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-xml + - id: pretty-format-json + args: ["--autofix"] + # git & filesystem + - id: check-added-large-files + - id: check-symlinks + - id: detect-private-key + - id: check-merge-conflict + - id: check-case-conflict # file conflicts: a.txt vs. A.txt + # formatters + - id: mixed-line-ending + - id: trailing-whitespace + exclude: "(.*\\.html|.*\\.md)$" + - id: end-of-file-fixer + exclude: "(.*\\.xml|.*\\.svg)$" + # python + - id: check-ast # abstract syntax tree + - id: check-builtin-literals # no {} and [], but dict() and list() + - id: debug-statements + # - id: name-tests-test + # args: [--pytest-test-first] + # django-upgrade suggestions + - repo: https://github.com/adamchainz/django-upgrade + rev: "1.14.0" + hooks: + - id: django-upgrade + args: [--target-version, "4.2"] + # tha black + - repo: https://github.com/psf/black-pre-commit-mirror + rev: "23.7.0" + hooks: + - id: black + # flake8 replacement (&more) + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.284" + hooks: + - id: ruff + args: [--fix] + # js/sass/etc formatter + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.0.2 + hooks: + - id: prettier + args: [--list-different] + exclude: "(.*\\.html|.*\\.md)$" + # eslinth, shall we? urrfff +# - repo: https://github.com/pre-commit/mirrors-eslint +# rev: v8.47.0 +# hooks: +# - id: eslint diff --git a/CHANGELOG.txt b/CHANGELOG.md similarity index 94% rename from CHANGELOG.txt rename to CHANGELOG.md index 8cd4949..f4333ef 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.md @@ -1,2 +1 @@ === (ongoing) === - diff --git a/DESCRIPTION b/DESCRIPTION index 80e63f3..8333280 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,2 +1,2 @@ Everything in postgres, accessible via Django ORM, using -postgres fullext search capabilites \ No newline at end of file +postgres fullext search capabilites diff --git a/manage.py b/manage.py index 6c87038..adbd36f 100755 --- a/manage.py +++ b/manage.py @@ -3,9 +3,11 @@ import sys if __name__ == "__main__": - os.environ.setdefault('DJANGO_SETTINGS_MODULE', - # 'postgres_searchindex.tests.south_settings') - 'postgres_searchindex.tests.settings') + os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + # 'postgres_searchindex.tests.south_settings') + "postgres_searchindex.tests.settings", + ) from django.core.management import execute_from_command_line diff --git a/postgres_searchindex/__init__.py b/postgres_searchindex/__init__.py index e69de29..f102a9c 100644 --- a/postgres_searchindex/__init__.py +++ b/postgres_searchindex/__init__.py @@ -0,0 +1 @@ +__version__ = "0.0.1" diff --git a/postgres_searchindex/conf.py b/postgres_searchindex/conf.py index 346e3f1..ca872d7 100644 --- a/postgres_searchindex/conf.py +++ b/postgres_searchindex/conf.py @@ -1,5 +1,20 @@ -LANGUAGE_2_PGCONFIG = { - "en": "english", - "de": "german", - "fr": "french", -} +from django.conf import settings + +POSTGRES_SEARCHINDEX = getattr( + settings, + "POSTGRES_SEARCHINDEX", + { + "default": {}, + }, +) + + +LANGUAGE_2_PGCONFIG = getattr( + settings, + "POSTGRES_SEARCHINDEX_LANGUAGE_2_PGCONFIG", + { + "en": "english", + "de": "german", + "fr": "french", + }, +) diff --git a/postgres_searchindex/management/commands/postgres_searchindex_update.py b/postgres_searchindex/management/commands/postgres_searchindex_update.py index 9c1f8df..1c9e0cb 100644 --- a/postgres_searchindex/management/commands/postgres_searchindex_update.py +++ b/postgres_searchindex/management/commands/postgres_searchindex_update.py @@ -1,7 +1,7 @@ -from django.conf import settings -from django.core.management import BaseCommand from django.contrib.contenttypes.models import ContentType +from django.core.management import BaseCommand +from postgres_searchindex import conf from postgres_searchindex.models import IndexEntry from postgres_searchindex.source_pool import source_pool @@ -10,7 +10,7 @@ class Command(BaseCommand): help = "Update/build index" def handle(self, *args, **options): - for index_key, index in settings.POSTGRES_SEARCHINDEX.items(): + for index_key, index in conf.POSTGRES_SEARCHINDEX.items(): self.stdout.write("====================================") self.stdout.write( f"Updating index \"{index_key}\" with kwargs {index.get('kwargs', {})}" @@ -28,14 +28,11 @@ def handle(self, *args, **options): current_ids.append(obj.id) # remove no more existing content_type = ContentType.objects.get_for_model(source.model) - delete_result = ( - IndexEntry.objects.filter( - index_key=index_key, - content_type=content_type, - ) - .exclude( - object_id__in=current_ids, - ) - .delete() + to_delete = IndexEntry.objects.filter( + index_key=index_key, + content_type=content_type, + ).exclude( + object_id__in=current_ids, ) + delete_result = to_delete.delete() self.stdout.write(f"> Done. Removed from index: {delete_result[0]}") diff --git a/postgres_searchindex/migrations/0001_initial.py b/postgres_searchindex/migrations/0001_initial.py index f8614c7..36f547d 100644 --- a/postgres_searchindex/migrations/0001_initial.py +++ b/postgres_searchindex/migrations/0001_initial.py @@ -1,37 +1,61 @@ # Generated by Django 3.2.21 on 2024-01-14 17:21 -from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +from django.db import migrations, models class Migration(migrations.Migration): - initial = True dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('sites', '0002_alter_domain_unique'), + ("contenttypes", "0002_remove_content_type_name"), + ("sites", "0002_alter_domain_unique"), ] operations = [ migrations.CreateModel( - name='IndexEntry', + name="IndexEntry", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('modified_at', models.DateTimeField(auto_now=True)), - ('index_key', models.CharField(default='default', max_length=32)), - ('object_id', models.PositiveIntegerField()), - ('original_modified_at', models.DateTimeField(default=django.utils.timezone.now)), - ('title', models.CharField(max_length=1024)), - ('content', models.TextField(default='')), - ('url', models.TextField()), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), - ('site_id', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sites.site')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("modified_at", models.DateTimeField(auto_now=True)), + ("index_key", models.CharField(default="default", max_length=32)), + ("object_id", models.PositiveIntegerField()), + ( + "original_modified_at", + models.DateTimeField(default=django.utils.timezone.now), + ), + ("title", models.CharField(max_length=1024)), + ("content", models.TextField(default="")), + ("url", models.TextField()), + ( + "content_type", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="contenttypes.contenttype", + ), + ), + ( + "site_id", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="sites.site", + ), + ), ], options={ - 'abstract': False, + "abstract": False, }, ), ] diff --git a/postgres_searchindex/tests/__init__.py b/postgres_searchindex/tests/__init__.py new file mode 100644 index 0000000..fef48e6 --- /dev/null +++ b/postgres_searchindex/tests/__init__.py @@ -0,0 +1 @@ +__author__ = "benzkji" diff --git a/postgres_searchindex/tests/settings.py b/postgres_searchindex/tests/settings.py new file mode 100644 index 0000000..a55659a --- /dev/null +++ b/postgres_searchindex/tests/settings.py @@ -0,0 +1,108 @@ +import logging +import os +import tempfile + +DEBUG = True + +logging.getLogger("factory").setLevel(logging.WARN) + +SITE_ID = 1 + +APP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "db.sqlite", + } +} + +LANGUAGE_CODE = "en" +LANGUAGES = ( + ( + "en", + "ENGLISHS", + ), +) + +X_FRAME_OPTIONS = "SAMEORIGIN" +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" +ROOT_URLCONF = "postgres_searchindex.tests.urls" + +# media root is overridden when needed in tests +MEDIA_ROOT = tempfile.mkdtemp(suffix="ckeditor_media_root") +MEDIA_URL = "/media/" +STATIC_URL = "/static/" +STATIC_ROOT = os.path.join(APP_ROOT, "../test_app_static") +STATICFILES_DIRS = (os.path.join(APP_ROOT, "static"),) + +COVERAGE_REPORT_HTML_OUTPUT_DIR = os.path.join(os.path.join(APP_ROOT, "tests/coverage")) +COVERAGE_MODULE_EXCLUDES = [ + "tests$", + "settings$", + "urls$", + "locale$", + "migrations", + "fixtures", + "admin$", + "django_extensions", +] + +EXTERNAL_APPS = ( + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.messages", + "django.contrib.sessions", + "django.contrib.staticfiles", + "django.contrib.sitemaps", + "django.contrib.sites", + "cms", + "treebeard", + "menus", + "sekizai", +) +INTERNAL_APPS = ( + "postgres_searchindex", + "postgres_searchindex.tests.test_app", +) + + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.i18n", + "django.template.context_processors.request", + "django.template.context_processors.media", + "django.template.context_processors.static", + "sekizai.context_processors.sekizai", + "cms.context_processors.cms_settings", + ], + "loaders": [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + # 'django.template.loaders.eggs.Loader', + ], + }, + }, +] + + +MIDDLEWARE = ( + "django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + # Uncomment the next line for simple clickjacking protection: + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "django.middleware.locale.LocaleMiddleware", +) + +INSTALLED_APPS = EXTERNAL_APPS + INTERNAL_APPS +COVERAGE_MODULE_EXCLUDES += EXTERNAL_APPS + +SECRET_KEY = "foobarXXXxxsasdvasdvsd()&/%vXY" diff --git a/postgres_searchindex/tests/test_app/__init__.py b/postgres_searchindex/tests/test_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/test_app/admin.py b/postgres_searchindex/tests/test_app/admin.py new file mode 100644 index 0000000..6ca8d7f --- /dev/null +++ b/postgres_searchindex/tests/test_app/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from .models import TestModel + +admin.site.register(TestModel) diff --git a/postgres_searchindex/tests/test_app/fixtures/test_app.json b/postgres_searchindex/tests/test_app/fixtures/test_app.json new file mode 100644 index 0000000..0e0093a --- /dev/null +++ b/postgres_searchindex/tests/test_app/fixtures/test_app.json @@ -0,0 +1,20 @@ +[ + { + "fields": { + "richtext": "

None

", + "richtext_second": "

what

", + "title": "Test 1 One" + }, + "model": "test_app.testmodel", + "pk": 1 + }, + { + "fields": { + "richtext": "

Two

", + "richtext_second": "

Threee

", + "title": "Testing Two" + }, + "model": "test_app.testmodel", + "pk": 2 + } +] diff --git a/postgres_searchindex/tests/test_app/index_sources.py b/postgres_searchindex/tests/test_app/index_sources.py new file mode 100644 index 0000000..3deda5d --- /dev/null +++ b/postgres_searchindex/tests/test_app/index_sources.py @@ -0,0 +1,20 @@ +from django.utils.html import strip_tags + +from postgres_searchindex.base import IndexSource +from postgres_searchindex.source_pool import source_pool + +from .models import TestModel + + +@source_pool.register +class TestModelIndexSource(IndexSource): + model = TestModel + + def get_title(self, obj): + return obj.title + + def get_content(self, obj): + return strip_tags(obj.richtext) + strip_tags(obj.richtext_second) + + def get_queryset(self): + return self.model.objects.filter(published=True) diff --git a/postgres_searchindex/tests/test_app/migrations/0001_initial.py b/postgres_searchindex/tests/test_app/migrations/0001_initial.py new file mode 100644 index 0000000..41867a8 --- /dev/null +++ b/postgres_searchindex/tests/test_app/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.23 on 2024-01-22 14:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="TestModel", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=255)), + ("richtext", models.TextField(default="")), + ("richtext_second", models.TextField(default="")), + ], + ), + ] diff --git a/postgres_searchindex/tests/test_app/migrations/0002_testmodel_published.py b/postgres_searchindex/tests/test_app/migrations/0002_testmodel_published.py new file mode 100644 index 0000000..ef77e70 --- /dev/null +++ b/postgres_searchindex/tests/test_app/migrations/0002_testmodel_published.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.23 on 2024-01-22 14:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("test_app", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="testmodel", + name="published", + field=models.BooleanField(default=True), + ), + ] diff --git a/postgres_searchindex/tests/test_app/migrations/__init__.py b/postgres_searchindex/tests/test_app/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/test_app/models.py b/postgres_searchindex/tests/test_app/models.py new file mode 100644 index 0000000..641296d --- /dev/null +++ b/postgres_searchindex/tests/test_app/models.py @@ -0,0 +1,17 @@ +from django.db import models +from django.urls import reverse + + +class TestModel(models.Model): + published = models.BooleanField(default=True) + title = models.CharField( + max_length=255, + ) + richtext = models.TextField(default="") + richtext_second = models.TextField(default="") + + def __str__(self): + return "%s" % self.title + + def get_absolute_url(self): + return reverse("testmodel_detail", args=(self.id,)) diff --git a/postgres_searchindex/tests/test_app/templates/cms_dummy.html b/postgres_searchindex/tests/test_app/templates/cms_dummy.html new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/test_app/templates/test_app/testmodel_detail.html b/postgres_searchindex/tests/test_app/templates/test_app/testmodel_detail.html new file mode 100644 index 0000000..a6a26d7 --- /dev/null +++ b/postgres_searchindex/tests/test_app/templates/test_app/testmodel_detail.html @@ -0,0 +1,7 @@ +{% load ckeditor_link_tags %} + +

{{ object.title }}

+ +{{ object.richtext|ckeditor_link_add_links|safe }} + +{{ object.richtext_second|ckeditor_link_add_links|safe }} diff --git a/postgres_searchindex/tests/test_app/views.py b/postgres_searchindex/tests/test_app/views.py new file mode 100644 index 0000000..526428d --- /dev/null +++ b/postgres_searchindex/tests/test_app/views.py @@ -0,0 +1,7 @@ +from django.views.generic import DetailView + +from .models import TestModel + + +class TestModelDetailView(DetailView): + model = TestModel diff --git a/postgres_searchindex/tests/test_contrib_cms.py b/postgres_searchindex/tests/test_contrib_cms.py new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/test_indexing.py b/postgres_searchindex/tests/test_indexing.py new file mode 100644 index 0000000..64b9caa --- /dev/null +++ b/postgres_searchindex/tests/test_indexing.py @@ -0,0 +1,46 @@ +from django.core.management import call_command +from django.test import TestCase + +from postgres_searchindex.models import IndexEntry +from postgres_searchindex.tests.test_app.models import TestModel + + +class IndexingTests(TestCase): + fixtures = [ + "test_app.json", + ] + + def setUp(self): + super().setUp() + + def tearDown(self): + pass + + def test_indexing(self): + call_command("postgres_searchindex_update") + qs = IndexEntry.objects.all() + self.assertEqual(qs.count(), 2) + self.assertEqual(qs.filter(title__contains="One").count(), 1) + + def test_indexing_unpublish(self): + """ + unpublishing something requires index update + """ + qs = IndexEntry.objects.all() + call_command("postgres_searchindex_update") + one = TestModel.objects.filter(title__contains="One").first() + one.published = False + one.save() + call_command("postgres_searchindex_update") + self.assertEqual(qs.count(), 1) + self.assertEqual(qs.filter(title__contains="One").count(), 0) + + def test_indexing_deletion(self): + """ + generic relations do cascade deletion + """ + qs = IndexEntry.objects.all() + call_command("postgres_searchindex_update") + TestModel.objects.filter(title__contains="One").delete() + self.assertEqual(qs.count(), 1) + self.assertEqual(qs.filter(title__contains="One").count(), 0) diff --git a/postgres_searchindex/tests/test_multilanguage_indexing.py b/postgres_searchindex/tests/test_multilanguage_indexing.py new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/test_signal_indexing.py b/postgres_searchindex/tests/test_signal_indexing.py new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/test_templatetags.py b/postgres_searchindex/tests/test_templatetags.py new file mode 100644 index 0000000..e69de29 diff --git a/postgres_searchindex/tests/urls.py b/postgres_searchindex/tests/urls.py new file mode 100644 index 0000000..a76179e --- /dev/null +++ b/postgres_searchindex/tests/urls.py @@ -0,0 +1,15 @@ +"""URLs to run the tests.""" +from django.contrib import admin +from django.urls import include, path + +from postgres_searchindex.tests.test_app.views import TestModelDetailView + +urlpatterns = [ + path("admin/", admin.site.urls), + path( + "testmodel//", + TestModelDetailView.as_view(), + name="testmodel_detail", + ), + path("", include("cms.urls")), +] diff --git a/postgres_searchindex/tests/utils/__init__.py b/postgres_searchindex/tests/utils/__init__.py new file mode 100644 index 0000000..dd4d363 --- /dev/null +++ b/postgres_searchindex/tests/utils/__init__.py @@ -0,0 +1,2 @@ +__author__ = "benzkji" +__doc__ = "Various test utils" diff --git a/postgres_searchindex/tests/utils/django_utils.py b/postgres_searchindex/tests/utils/django_utils.py new file mode 100644 index 0000000..94fddcd --- /dev/null +++ b/postgres_searchindex/tests/utils/django_utils.py @@ -0,0 +1,6 @@ +from django.contrib.auth.models import User + + +def create_superuser(): + superuser = User.objects.create_superuser("admin", "admin@free.fr", "secret") + return superuser diff --git a/postgres_searchindex/views.py b/postgres_searchindex/views.py index 2c27b8d..6e02609 100644 --- a/postgres_searchindex/views.py +++ b/postgres_searchindex/views.py @@ -1,16 +1,14 @@ from django import forms from django.contrib.postgres.search import SearchVector from django.views.generic import ListView -from textblocks.utils import textblock_lazy as _t -from . import conf from postgres_searchindex.models import IndexEntry +from . import conf + class SearchForm(forms.Form): - q = forms.CharField( - widget=forms.TextInput(attrs={"placeholder": _t("Suchbegriff")}) - ) + q = forms.CharField(widget=forms.TextInput()) class SearchView(ListView): @@ -30,7 +28,6 @@ def get_queryset(self): if self.form.is_valid(): q = self.form.cleaned_data["q"] config = conf.LANGUAGE_2_PGCONFIG.get(self.request.LANGUAGE_CODE, "english") - print(config) return IndexEntry.objects.annotate( search=SearchVector( "content", diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..589a964 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,82 @@ +[tool.ruff] +# Enable the pycodestyle (`E`) and Pyflakes (`F`) rules by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +# B = Bugbear +# DJ = django +# T20 = print +select = [ + # pyflakes, pycodestyle + "F", "E", "W", + # mmcabe + "C90", + # isort + "I", + # pep8-naming + # "N", + # pyupgrade + # "UP", + # flake8-2020 + "YTT", + # flake8-boolean-trap + # "FBT", + # flake8-bugbear + # "B", + # flake8-comprehensions + "C4", + # flake8-django + "DJ", + # flake8-pie + # "PIE", + # flake8-simplify + # "SIM", + # flake8-gettext + "INT", + # pygrep-hooks + # "PGH", + # pylint + # "PL", + # unused noqa + "RUF100", + # flake8-print + "T20", +] +ignore = [] +# Avoid trying to fix flake8-bugbear (`B`) violations. +unfixable = ["B"] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + # "migrations", +] +per-file-ignores = {} + +# Same as Black. +line-length = 88 + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.9 +target-version = "py39" diff --git a/requirements_dev.txt b/requirements_dev.txt index 6b5e950..16e4608 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,11 +1,9 @@ # mainly to have migrations compatible with the oldest supported django version -django<3 -django-cms<3.8 +django<4 +django-cms<3.9 -# test utils, so you can do a quick manage.py test without tox (that is, included as well) +# dev & test utils, so you can do a quick manage.py test without tox (that is, included as well) +pre-commit coverage django-coverage -factory_boy -mock -selenium -tox \ No newline at end of file +tox diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index c5e1ba0..0000000 --- a/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] -ignore = F999,E501,E128,E124 -exclude = .git,*/migrations/*,*/south_migrations/*,*/static/CACHE/*,.tox,build diff --git a/setup.py b/setup.py index f9daf69..184c8e2 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,9 @@ """ import os -from setuptools import setup, find_packages + +from setuptools import find_packages, setup + import postgres_searchindex as app @@ -38,21 +40,21 @@ def read(fname): install_requires = [ - 'django', + "django", ] setup( name="django-postgres-searchindex", version=app.__version__, - description=read('DESCRIPTION'), - long_description=read('README.md'), + description=read("DESCRIPTION"), + long_description=read("README.md"), long_description_content_type="text/markdown", - license='The MIT License', - platforms=['OS Independent'], - keywords='django, redirect', - author='Ben Stähli', - author_email='bnzk@bnzk.ch', + license="The MIT License", + platforms=["OS Independent"], + keywords="django, search, index, postgres fts", + author="Ben Stähli", + author_email="bnzk@bnzk.ch", url="https://github.com/bnzk/django-postgres-searchindex", packages=find_packages(), include_package_data=True, diff --git a/tox.ini b/tox.ini index 42ba66e..8464c2b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,22 +1,21 @@ [tox] -envlist = py{38,39,310,311}-django{22,32,40,41,42}, py39-django32-coverage, flake8 +envlist = py{38,39,310,311,312}-django{32,42}, py39-django42-coverage, pre-commit [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 -[testenv:flake8] +[testenv:pre-commit] deps = - flake8 - flake8-print -commands = flake8 + pre-commit +commands = pre-commit run --all-files -[testenv:py39-django32-coverage] +[testenv:py39-django42-coverage] allowlist_externals = echo commands = # https://github.com/nedbat/coveragepy/issues/1272 @@ -33,16 +32,19 @@ setenv = DJANGO_SETTINGS_MODULE=postgres_searchindex.tests.settings PYTHONPATH={toxinidir} deps = - django22: Django>=2.2,<2.3 django32: Django>=3.1,<3.3 - django40: Django>=4.0,<4.1 - django41: Django>=4.1,<4.2 django42: Django>=4.2,<4.3 + django50: Django>=5.0,<5.1 + django-cms==3.11.4 coverage - factory_boy - mock -[testenv:py37-django40] + +[testenv:py38-django50] +allowlist_externals = echo +deps = +commands= echo "no django 5.0 on python 3.8!" + +[testenv:py39-django50] allowlist_externals = echo deps = -commands= echo "no django 4.0 on python 3.7!" +commands= echo "no django 5.0 on python 3.9!"