From 666ecd625a1f7b09c7d5065e710469c1e7f06bc4 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 15:54:21 +0100 Subject: [PATCH 01/19] :package: Move packaging info/metadata to setup.cfg * Moved existing config over * Already updated supported Python and Django versions --- setup.cfg | 99 +++++++++++++++++++++++++++++++++++++++++++++++-------- setup.py | 64 ++--------------------------------- 2 files changed, 87 insertions(+), 76 deletions(-) diff --git a/setup.cfg b/setup.cfg index f7b63b4..6afb55b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,30 +1,101 @@ +[metadata] +name = django-timeline-logger +version = 1.1.2 +description = Generic event logger for Django models. +long_description = file: README.rst +url = https://github.com/maykinmedia/django-timeline-logger +license = MIT +author = Maykin Media +author_email = support@maykinmedia.nl +keywords = TODO +classifiers = + Development Status :: 5 - Production/Stable + Framework :: Django + Framework :: Django :: 2.2 + Framework :: Django :: 3.2 + Intended Audience :: Developers + Operating System :: Unix + Operating System :: MacOS + Operating System :: Microsoft :: Windows + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Topic :: Software Development :: Libraries :: Python Modules + +[options] +zip_safe = False +include_package_data = True +packages = find: +install_requires = + pkg_resources + django>=2.2 + django-appconf +tests_require = + factory-boy + psycopg2 + pytest + pytest-cov + pytest-django + pytest-pep8 + pytest-pylint + pytest-pythonpath + pytest-runner + tox + isort + +[options.packages.find] +include = + timeline_logger + timeline_logger.* + +[options.extras_require] +tests = + factory-boy + psycopg2 + pytest + pytest-cov + pytest-django + pytest-pep8 + pytest-pylint + pytest-pythonpath + pytest-runner + tox + isort +pep8 = flake8 +coverage = pytest-cov +docs = + sphinx + sphinx-rtd-theme +release = + bumpversion + twine + +# 3rd party configuration + [aliases] test=pytest -[bdist_wheel] -universal=1 - [isort] combine_as_imports = true default_section = THIRDPARTY -include_trailing_comma = false -line_length = 79 -multi_line_output = 5 +include_trailing_comma = true +line_length = 88 +multi_line_output = 3 +force_grid_wrap = 0 +use_parentheses = True +ensure_newline_before_comments = True skip = env,.tox,.history,.eggs -skip_glob = */migrations/* -not_skip = __init__.py +known_django=django known_first_party=timeline_logger -sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER +sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER [tool:pytest] testpaths = tests +DJANGO_SETTINGS_MODULE=testapp.settings [pep8] -ignore=W293,W291,E501,E261 -max-line-length=119 -exclude=env,.tox,doc - [flake8] ignore=W293,W291,E501,E261 -max-line-length=119 +max-line-length=88 exclude=env,.tox,doc diff --git a/setup.py b/setup.py index f97ca49..6068493 100644 --- a/setup.py +++ b/setup.py @@ -1,63 +1,3 @@ -#!/usr/bin/env python +from setuptools import setup -# To use a consistent encoding -from codecs import open -from os import path - -from setuptools import find_packages, setup - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: - long_description = f.read() - -setup( - name='django-timeline-logger', - version='1.1.2', - description='Generic event logger for Django models.', - long_description=long_description, - author='Maykin Media', - author_email='support@maykinmedia.nl', - url='https://github.com/maykinmedia/django-timeline-logger', - install_requires=[ - 'Django>=1.11', - 'django-appconf', - ], - packages=find_packages(exclude=['tests*']), - include_package_data=True, - zip_safe=False, - setup_requires=['pytest-runner'], - tests_require=[ - 'factory-boy', - 'psycopg2', - 'pytest', - 'pytest-cov', - 'pytest-django', - 'pytest-pep8', - 'pytest-pylint', - 'pytest-pythonpath', - 'pytest-runner', - ], - extras_require={ - 'docs': [ - 'sphinx', - 'sphinx_rtd_theme' - ], - }, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Framework :: Django :: 1.11', - 'Framework :: Django :: 2.0', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: Unix', - 'Operating System :: MacOS', - 'Operating System :: Microsoft :: Windows', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Software Development :: Libraries :: Application Frameworks' - ] -) +setup() From 26ea39d542d56d6cb737aea4205cd6b4432b0416 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 15:58:30 +0100 Subject: [PATCH 02/19] :construction_worker: Set up desired supported versions matrix in Tox --- pytest.ini | 5 ----- setup.cfg | 4 +++- tox.ini | 60 +++++++++++++++++++++++++++++------------------------- 3 files changed, 35 insertions(+), 34 deletions(-) delete mode 100644 pytest.ini diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index bc2ff66..0000000 --- a/pytest.ini +++ /dev/null @@ -1,5 +0,0 @@ -[pytest] -django_find_project=false -DJANGO_SETTINGS_MODULE=tests.settings_pg - -python_paths=. diff --git a/setup.cfg b/setup.cfg index 6afb55b..6af0d9b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -92,7 +92,9 @@ sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER [tool:pytest] testpaths = tests -DJANGO_SETTINGS_MODULE=testapp.settings +; django_find_project = false +DJANGO_SETTINGS_MODULE = testapp.settings_pg +; python_paths = . [pep8] [flake8] diff --git a/tox.ini b/tox.ini index bdc55c2..31935fd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,43 +1,47 @@ [tox] -envlist = py27-django111,py{34,35,36}-django{111,20},isort,docs +envlist = + py{37,38,39,310}-django{22,32} + isort + black + docs skip_missing_interpreters = true +[gh-actions:env] +DJANGO = + 2.2: django22 + 3.2: django32 + [testenv] -changedir=tests +setenv = + DJANGO_SETTINGS_MODULE=testapp.settings + PYTHONPATH={toxinidir} +extras = + tests + coverage deps = - factory-boy - psycopg2 - pytest - pytest-cov - pytest-django - pytest-pep8 - pytest-pylint - pytest-pythonpath - pytest-runner - py27: mock - django111: Django>=1.11,<2 - django20: Django>=2.0,<3 -commands= - py.test \ - --cov-report=xml \ - --cov=timeline_logger \ - --verbose \ - --junit-xml=junit.xml \ - --color=yes \ - {posargs} + django22: Django~=2.2.0 + django32: Django~=3.2.0 +commands = + py.test tests \ + --junitxml=reports/junit.xml \ + --cov --cov-report xml:reports/coverage-{envname}.xml \ + {posargs} [testenv:isort] -deps = isort +extras = tests +skipsdist = True +commands = isort --check-only --diff . + +[testenv:black] +extras = tests skipsdist = True -commands = isort --recursive --check-only --diff . +commands = black --check timeline_logger docs testapp tests setup.py [testenv:docs] basepython=python changedir=docs -deps= - sphinx - sphinx_rtd_theme - pytest +skipsdist=true +extras = docs commands= py.test check_sphinx.py -v \ --junitxml=../reports/junit-{envname}.xml \ From 414ba8270781b1ce8f020216c1002131d6465169 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 15:58:42 +0100 Subject: [PATCH 03/19] :wrench: Added .editorconfig --- .editorconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d4de5fc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{scss,sass}] +indent_size = 2 + +[*.{yml,yaml}] +indent_size = 2 From 2878a1e6e28160c478cb8db63d95e5b8fc996414 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:00:16 +0100 Subject: [PATCH 04/19] :wrench: Added bump2version config file --- .bumpversion.cfg | 6 ++++++ README.rst | 6 +++--- setup.cfg | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .bumpversion.cfg diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..708735f --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,6 @@ +[bumpversion] +commit = False +tag = False +current_version = 1.1.2 + +[bumpversion:file:setup.cfg] diff --git a/README.rst b/README.rst index d2b50ad..cf62cba 100644 --- a/README.rst +++ b/README.rst @@ -17,10 +17,10 @@ A reusable Django app to log actions and display them in a timeline Prerequisites ============= -This project uses `django.contrib.postgres.JSONField`, and as such, you need: +This project uses ``django.contrib.postgres.JSONField``, and as such, you need: -* at least Django 1.11 -* at least PostgreSQL 9.4 +* at least Django 2.2+ +* at least PostgreSQL 10 * at least psycopg2 2.5.4 diff --git a/setup.cfg b/setup.cfg index 6af0d9b..adcc361 100644 --- a/setup.cfg +++ b/setup.cfg @@ -68,7 +68,7 @@ docs = sphinx sphinx-rtd-theme release = - bumpversion + bump2version twine # 3rd party configuration From 6d8d1a6fa9b2f667e073f630877782387a237996 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:03:36 +0100 Subject: [PATCH 05/19] :construction_worker: Migrate from Travis to Github Actions --- .github/workflows/ci.yml | 77 ++++++++++++++++++++++++++++++ .github/workflows/code_quality.yml | 33 +++++++++++++ .travis.yml | 28 ----------- 3 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/code_quality.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8a42432 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: Run CI + +# Run this workflow every time a new commit pushed to your repository +on: + push: + branches: + - master + - develop + tags: + - '*' + pull_request: + workflow_dispatch: + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + python: ['3.7', '3.8', '3.9', '3.10'] + django: ['2.2', '3.2'] + + services: + postgres: + image: postgres:12 + env: + POSTGRES_HOST_AUTH_METHOD: trust + ports: + - 5432:5432 + # Needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + name: Run the test suite (Python ${{ matrix.python }}, Django ${{ matrix.django }}) + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + + - name: Install dependencies + run: pip install tox tox-gh-actions codecov + + - name: Run tests + run: | + tox + export TOXENV=py${PYTHON_VERSION/./}-django${DJANGO/./} + codecov -e TOXENV,DJANGO --file reports/coverage-${TOXENV}.xml + env: + PYTHON_VERSION: ${{ matrix.python }} + DJANGO: ${{ matrix.django }} + + - name: Publish coverage report + uses: codecov/codecov-action@v1 + + publish: + name: Publish package to PyPI + runs-on: ubuntu-latest + needs: tests + + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Build sdist and wheel + run: | + pip install pip setuptools wheel --upgrade + python setup.py sdist bdist_wheel + + - name: Publish a Python distribution to PyPI + uses: pypa/gh-action-pypi-publish@v1.4.1 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml new file mode 100644 index 0000000..51ef9c1 --- /dev/null +++ b/.github/workflows/code_quality.yml @@ -0,0 +1,33 @@ +name: Code quality checks + +# Run this workflow every time a new commit pushed to your repository +on: + push: + branches: + - master + - develop + tags: + paths: + - '**.py' + pull_request: + paths: + - '**.py' + workflow_dispatch: + +jobs: + linting: + name: Code-quality checks + runs-on: ubuntu-latest + strategy: + matrix: + toxenv: [isort, black] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.7' + - name: Install dependencies + run: pip install tox + - run: tox + env: + TOXENV: ${{ matrix.toxenv }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2f99bca..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: python -python: - - "3.6" - -services: - - postgresql - -addons: - postgresql: "9.4" - -install: - - pip install codecov tox -script: - - tox -- -after_success: - - codecov -env: - - TOXENV=py27-django111 - - TOXENV=py34-django111 - - TOXENV=py35-django111 - - TOXENV=py36-django111 - - - TOXENV=py34-django20 - - TOXENV=py35-django20 - - TOXENV=py36-django20 - - - TOXENV=isort - - TOXENV=docs From 182018fdfb560a63ac3ec0e6b43ab992d2d64d0b Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:06:16 +0100 Subject: [PATCH 06/19] :alien: Update README with extra and fixed badges --- README.rst | 34 ++++++++++++++++++++++++++-------- setup.cfg | 1 - 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index cf62cba..ae2eed8 100644 --- a/README.rst +++ b/README.rst @@ -4,15 +4,9 @@ django-timeline-logger A reusable Django app to log actions and display them in a timeline -.. image:: https://travis-ci.org/maykinmedia/django-timeline-logger.svg?branch=master - :target: https://travis-ci.org/maykinmedia/django-timeline-logger - -.. image:: https://codecov.io/gh/maykinmedia/django-timeline-logger/branch/develop/graph/badge.svg - :target: https://codecov.io/gh/maykinmedia/django-timeline-logger - -.. image:: https://badge.fury.io/py/django-timeline-logger.svg - :target: https://badge.fury.io/py/django-timeline-logger +|build-status| |code-quality| |coverage| |black| +|python-versions| |django-versions| |pypi-version| Prerequisites ============= @@ -22,6 +16,7 @@ This project uses ``django.contrib.postgres.JSONField``, and as such, you need: * at least Django 2.2+ * at least PostgreSQL 10 * at least psycopg2 2.5.4 +* A modern setuptools version Installation @@ -66,3 +61,26 @@ Documentation The extended documentation is available on `Read the Docs`_. .. _Read the Docs: http://django-timeline-logger.readthedocs.io/en/latest/ + + +.. |build-status| image:: https://github.com/maykinmedia/django-timeline-logger/actions/workflows/ci.yml/badge.svg + :alt: Build status + :target: https://github.com/maykinmedia/django-timeline-logger/actions/workflows/ci.yml + +.. |code-quality| image:: https://github.com/maykinmedia/django-timeline-logger/actions//workflows/code_quality.yml/badge.svg + :alt: Code quality checks + :target: https://github.com/maykinmedia/django-timeline-logger/actions//workflows/code_quality.yml + +.. |coverage| image:: https://codecov.io/gh/maykinmedia/django-timeline-logger/branch/master/graph/badge.svg + :target: https://codecov.io/gh/maykinmedia/django-timeline-logger + :alt: Coverage status + +.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + +.. |python-versions| image:: https://img.shields.io/pypi/pyversions/django-timeline-logger.svg + +.. |django-versions| image:: https://img.shields.io/pypi/djversions/django-timeline-logger.svg + +.. |pypi-version| image:: https://img.shields.io/pypi/v/django-timeline-logger.svg + :target: https://pypi.org/project/django-timeline-logger/ diff --git a/setup.cfg b/setup.cfg index adcc361..3dfd8d7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,7 +28,6 @@ zip_safe = False include_package_data = True packages = find: install_requires = - pkg_resources django>=2.2 django-appconf tests_require = From 84b22cbff267d5fb426821d921d51671f237f658 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:14:54 +0100 Subject: [PATCH 07/19] :alien: Add Django 3.2 support --- tests/settings.py | 33 ++++++++++++++------------- tests/test_urls.py | 4 ++-- timeline_logger/models.py | 47 ++++++++++++++++++--------------------- timeline_logger/urls.py | 7 +++--- 4 files changed, 45 insertions(+), 46 deletions(-) diff --git a/tests/settings.py b/tests/settings.py index e7de3b8..225b9cb 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,35 +1,36 @@ import os -SECRET_KEY = 'Timeline logger' +SECRET_KEY = "Timeline logger" DATABASES = { - 'default': { + "default": { # Memory resident database, for easy testing. - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', + "ENGINE": "django.db.backends.sqlite3", + "NAME": ":memory:", } } +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + INSTALLED_APPS = [ - 'django.contrib.contenttypes', - 'django.contrib.auth', - 'timeline_logger', - 'tests' + "django.contrib.contenttypes", + "django.contrib.auth", + "timeline_logger", + "tests", ] -EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' +EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend" -ROOT_URLCONF = 'tests.test_urls' +ROOT_URLCONF = "tests.test_urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.abspath( - os.path.join(os.path.dirname(__file__), os.path.pardir)) + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [ + os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)) ], - 'APP_DIRS': True, - 'OPTIONS': { + "APP_DIRS": True, + "OPTIONS": { # ... some options here ... }, }, diff --git a/tests/test_urls.py b/tests/test_urls.py index 96c2375..b69c339 100644 --- a/tests/test_urls.py +++ b/tests/test_urls.py @@ -1,5 +1,5 @@ -from django.conf.urls import include, url +from django.urls import include, path urlpatterns = [ - url(r'^$', include('timeline_logger.urls')), + path("", include("timeline_logger.urls")), ] diff --git a/timeline_logger/models.py b/timeline_logger/models.py index e861d76..87c5da5 100644 --- a/timeline_logger/models.py +++ b/timeline_logger/models.py @@ -5,55 +5,50 @@ from django.contrib.postgres.fields import JSONField from django.db import models from django.template.loader import get_template, render_to_string -from django.utils.encoding import python_2_unicode_compatible -from django.utils.translation import ugettext, ugettext_lazy as _ +from django.utils.translation import gettext, gettext_lazy as _ from .conf import settings -logger = logging.getLogger('timeline_logger') +logger = logging.getLogger("timeline_logger") DEFAULT_TEMPLATE = settings.TIMELINE_DEFAULT_TEMPLATE -@python_2_unicode_compatible class TimelineLog(models.Model): content_type = models.ForeignKey( ContentType, - verbose_name=_('content type'), + verbose_name=_("content type"), on_delete=models.SET_NULL, - blank=True, null=True, + blank=True, + null=True, ) - object_id = models.TextField( - verbose_name=_('object id'), - blank=True, null=True - ) - content_object = GenericForeignKey('content_type', 'object_id') - timestamp = models.DateTimeField(verbose_name=_('timestamp'), auto_now_add=True) + object_id = models.TextField(verbose_name=_("object id"), blank=True, null=True) + content_object = GenericForeignKey("content_type", "object_id") + timestamp = models.DateTimeField(verbose_name=_("timestamp"), auto_now_add=True) extra_data = JSONField( - verbose_name=_('extra data'), - null=True, blank=True, + verbose_name=_("extra data"), + null=True, + blank=True, ) user = models.ForeignKey( settings.AUTH_USER_MODEL, - verbose_name=_('user'), + verbose_name=_("user"), on_delete=models.SET_NULL, - blank=True, null=True, + blank=True, + null=True, ) template = models.CharField(max_length=200, default=DEFAULT_TEMPLATE) class Meta: - verbose_name = _('timeline log entry') - verbose_name_plural = _('timeline log entries') + verbose_name = _("timeline log entry") + verbose_name_plural = _("timeline log entries") def __str__(self): if self.object_id: - return "{ct} - {pk}".format( - ct=self.content_type.name, - pk=self.object_id - ) + return "{ct} - {pk}".format(ct=self.content_type.name, pk=self.object_id) - return ugettext('TimelineLog Object') + return gettext("TimelineLog Object") @classmethod def log_from_request(cls, request, content_object, template=None, **extra_data): @@ -85,7 +80,9 @@ def log_from_request(cls, request, content_object, template=None, **extra_data): template=template or DEFAULT_TEMPLATE, user=user, ) - logger.debug('Logged event in %s %s', content_object._meta.object_name, content_object.pk) + logger.debug( + "Logged event in %s %s", content_object._meta.object_name, content_object.pk + ) return timeline_log def get_message(self, template=None, **extra_context): @@ -96,6 +93,6 @@ def get_message(self, template=None, **extra_context): the message. Defaults to ``self.template``. :return: The log message string. """ - context = {'log': self} + context = {"log": self} context.update(**extra_context) return render_to_string(template or self.template, context) diff --git a/timeline_logger/urls.py b/timeline_logger/urls.py index 202e6e5..1c54104 100644 --- a/timeline_logger/urls.py +++ b/timeline_logger/urls.py @@ -1,8 +1,9 @@ -from django.conf.urls import url +from django.urls import path from .views import TimelineLogListView -app_name = 'timeline' +app_name = "timeline" + urlpatterns = [ - url(r'^$', TimelineLogListView.as_view(), name='timeline'), + path("", TimelineLogListView.as_view(), name="timeline"), ] From 9649865b44bfcb0da2185cf1d9d24e978f44ff26 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:15:25 +0100 Subject: [PATCH 08/19] :art: Formatted with isort and black --- timeline_logger/__init__.py | 4 +- timeline_logger/admin.py | 6 +-- timeline_logger/apps.py | 4 +- timeline_logger/compat.py | 1 + timeline_logger/conf.py | 11 ++-- .../management/commands/report_mailing.py | 50 ++++++++++------- timeline_logger/migrations/0001_initial.py | 54 +++++++++++++++---- .../migrations/0002_auto_20160624_1045.py | 9 ++-- .../migrations/0003_auto_20171025_1414.py | 15 ++++-- .../migrations/0004_alter_fields.py | 50 ++++++++++------- timeline_logger/resources.py | 9 ++-- timeline_logger/views.py | 2 +- 12 files changed, 140 insertions(+), 75 deletions(-) diff --git a/timeline_logger/__init__.py b/timeline_logger/__init__.py index 5da51f5..bb1d05c 100644 --- a/timeline_logger/__init__.py +++ b/timeline_logger/__init__.py @@ -1,5 +1,5 @@ from pkg_resources import get_distribution -__version__ = get_distribution('django-timeline-logger').version +__version__ = get_distribution("django-timeline-logger").version -default_app_config = 'timeline_logger.apps.TimelineLoggerConfig' +default_app_config = "timeline_logger.apps.TimelineLoggerConfig" diff --git a/timeline_logger/admin.py b/timeline_logger/admin.py index f18b864..25877a9 100644 --- a/timeline_logger/admin.py +++ b/timeline_logger/admin.py @@ -5,6 +5,6 @@ @admin.register(TimelineLog) class TimelineLogAdmin(admin.ModelAdmin): - list_display = ['__str__', 'timestamp', 'template'] - list_filter = ['timestamp', 'content_type'] - list_select_related = ['content_type'] + list_display = ["__str__", "timestamp", "template"] + list_filter = ["timestamp", "content_type"] + list_select_related = ["content_type"] diff --git a/timeline_logger/apps.py b/timeline_logger/apps.py index 2f85ef3..fcc449c 100644 --- a/timeline_logger/apps.py +++ b/timeline_logger/apps.py @@ -5,8 +5,8 @@ class TimelineLoggerConfig(AppConfig): - name = 'timeline_logger' - verbose_name = _('Django Timeline Logger') + name = "timeline_logger" + verbose_name = _("Django Timeline Logger") def ready(self): from . import conf # noqa diff --git a/timeline_logger/compat.py b/timeline_logger/compat.py index 35d7860..00c49c7 100644 --- a/timeline_logger/compat.py +++ b/timeline_logger/compat.py @@ -7,4 +7,5 @@ else: # Python 2.x versions from HTMLParser import HTMLParser + html = HTMLParser() diff --git a/timeline_logger/conf.py b/timeline_logger/conf.py index d5ccac5..f7b96d3 100644 --- a/timeline_logger/conf.py +++ b/timeline_logger/conf.py @@ -1,24 +1,25 @@ from __future__ import unicode_literals -from appconf import AppConf from django.conf import settings # noqa from django.utils.translation import ugettext_lazy as _ +from appconf import AppConf + class TimelineLoggerConf(AppConf): - DEFAULT_TEMPLATE = 'timeline_logger/default.txt' + DEFAULT_TEMPLATE = "timeline_logger/default.txt" PAGINATE_BY = 25 - USER_EMAIL_FIELD = 'email' + USER_EMAIL_FIELD = "email" DIGEST_EMAIL_RECIPIENTS = None - DIGEST_EMAIL_SUBJECT = _('Events timeline') + DIGEST_EMAIL_SUBJECT = _("Events timeline") DIGEST_FROM_EMAIL = None class Meta: - prefix = 'timeline' + prefix = "timeline" def configure_digest_email_recipients(self, value): if value is None: diff --git a/timeline_logger/management/commands/report_mailing.py b/timeline_logger/management/commands/report_mailing.py index cea7a28..429260f 100644 --- a/timeline_logger/management/commands/report_mailing.py +++ b/timeline_logger/management/commands/report_mailing.py @@ -13,25 +13,33 @@ from timeline_logger.compat import html from timeline_logger.models import TimelineLog -logger = logging.getLogger('timeline_logger') +logger = logging.getLogger("timeline_logger") class Command(BaseCommand): - help = 'Sends mail notifications for last events to (admin) users.' - template_name = 'timeline_logger/notifications.html' + help = "Sends mail notifications for last events to (admin) users." + template_name = "timeline_logger/notifications.html" def add_arguments(self, parser): parser.add_argument( - '--days', type=int, - help='An integer number with the number of days to look at from today to the past.' + "--days", + type=int, + help="An integer number with the number of days to look at from today to the past.", ) recipients_group = parser.add_mutually_exclusive_group() - recipients_group.add_argument('--all', action='store_true', help=_('Send e-mail to all users')) - recipients_group.add_argument('--staff', action='store_true', help=_('Send e-mail to staff users')) recipients_group.add_argument( - '--recipients-from-setting', action='store_true', - help=_('Send e-mail to adresses listed in settings.TIMELINE_DIGEST_EMAIL_RECIPIENTS') + "--all", action="store_true", help=_("Send e-mail to all users") + ) + recipients_group.add_argument( + "--staff", action="store_true", help=_("Send e-mail to staff users") + ) + recipients_group.add_argument( + "--recipients-from-setting", + action="store_true", + help=_( + "Send e-mail to adresses listed in settings.TIMELINE_DIGEST_EMAIL_RECIPIENTS" + ), ) def handle(self, *args, **options): @@ -39,7 +47,7 @@ def handle(self, *args, **options): queryset = self.get_queryset(**options) if not queryset.exists(): - logger.info('No logs in timeline. No emails sent.') + logger.info("No logs in timeline. No emails sent.") return self.send_email(recipients, queryset) @@ -48,13 +56,15 @@ def get_queryset(self, **options): """ Filters the list of log objects to display """ - days = options.get('days') - queryset = TimelineLog.objects.order_by('-timestamp') + days = options.get("days") + queryset = TimelineLog.objects.order_by("-timestamp") if days: try: start = timezone.now() - timedelta(days=days) except TypeError: - raise CommandError("Incorrect 'days' parameter. 'days' must be a number of days.") + raise CommandError( + "Incorrect 'days' parameter. 'days' must be a number of days." + ) else: return queryset.filter(timestamp__gte=start) @@ -64,20 +74,20 @@ def get_recipients(self, **options): """ Figures out the recipients """ - if options['recipients_from_setting']: + if options["recipients_from_setting"]: return settings.TIMELINE_DIGEST_EMAIL_RECIPIENTS users = get_user_model()._default_manager.all() - if options['staff']: + if options["staff"]: users = users.filter(is_staff=True) - elif not options['all']: + elif not options["all"]: users = users.filter(is_staff=True, is_superuser=True) return users.values_list(settings.TIMELINE_USER_EMAIL_FIELD, flat=True) def get_context(self, queryset): return { - 'logs': queryset, - 'start_date': queryset[0].timestamp, + "logs": queryset, + "start_date": queryset[0].timestamp, } def send_email(self, recipients, queryset): @@ -91,6 +101,6 @@ def send_email(self, recipients, queryset): from_email=settings.TIMELINE_DIGEST_FROM_EMAIL, recipient_list=recipients, fail_silently=False, - html_message=html_content + html_message=html_content, ) - logger.info('Notification emails sent to: %s', recipients) + logger.info("Notification emails sent to: %s", recipients) diff --git a/timeline_logger/migrations/0001_initial.py b/timeline_logger/migrations/0001_initial.py index 3094f81..79ff247 100644 --- a/timeline_logger/migrations/0001_initial.py +++ b/timeline_logger/migrations/0001_initial.py @@ -2,10 +2,10 @@ # Generated by Django 1.9.4 on 2016-06-15 18:16 from __future__ import unicode_literals -from django.conf import settings import django.contrib.postgres.fields.jsonb -from django.db import migrations, models import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): @@ -14,20 +14,52 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('contenttypes', '0002_remove_content_type_name'), + ("contenttypes", "0002_remove_content_type_name"), ] operations = [ migrations.CreateModel( - name='TimelineLog', + name="TimelineLog", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('object_id', models.PositiveIntegerField()), - ('timestamp', models.DateTimeField(auto_now_add=True)), - ('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True)), - ('template', models.CharField(default='timeline_logger/default.txt', max_length=200)), - ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("object_id", models.PositiveIntegerField()), + ("timestamp", models.DateTimeField(auto_now_add=True)), + ( + "extra_data", + django.contrib.postgres.fields.jsonb.JSONField( + blank=True, null=True + ), + ), + ( + "template", + models.CharField( + default="timeline_logger/default.txt", max_length=200 + ), + ), + ( + "content_type", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="contenttypes.ContentType", + ), + ), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), ] diff --git a/timeline_logger/migrations/0002_auto_20160624_1045.py b/timeline_logger/migrations/0002_auto_20160624_1045.py index 89a2d90..d7f2c79 100644 --- a/timeline_logger/migrations/0002_auto_20160624_1045.py +++ b/timeline_logger/migrations/0002_auto_20160624_1045.py @@ -8,12 +8,15 @@ class Migration(migrations.Migration): dependencies = [ - ('timeline_logger', '0001_initial'), + ("timeline_logger", "0001_initial"), ] operations = [ migrations.AlterModelOptions( - name='timelinelog', - options={'verbose_name': 'timeline log entry', 'verbose_name_plural': 'timeline log entries'}, + name="timelinelog", + options={ + "verbose_name": "timeline log entry", + "verbose_name_plural": "timeline log entries", + }, ), ] diff --git a/timeline_logger/migrations/0003_auto_20171025_1414.py b/timeline_logger/migrations/0003_auto_20171025_1414.py index 7b19f0e..f5f7230 100644 --- a/timeline_logger/migrations/0003_auto_20171025_1414.py +++ b/timeline_logger/migrations/0003_auto_20171025_1414.py @@ -2,21 +2,26 @@ # Generated by Django 1.10.7 on 2017-10-25 14:14 from __future__ import unicode_literals +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('timeline_logger', '0002_auto_20160624_1045'), + ("timeline_logger", "0002_auto_20160624_1045"), ] operations = [ migrations.AlterField( - model_name='timelinelog', - name='user', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + model_name="timelinelog", + name="user", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + ), ), ] diff --git a/timeline_logger/migrations/0004_alter_fields.py b/timeline_logger/migrations/0004_alter_fields.py index e26d32c..9af091f 100644 --- a/timeline_logger/migrations/0004_alter_fields.py +++ b/timeline_logger/migrations/0004_alter_fields.py @@ -2,42 +2,56 @@ # Generated by Django 1.11.9 on 2018-03-13 17:38 from __future__ import unicode_literals -from django.conf import settings import django.contrib.postgres.fields.jsonb -from django.db import migrations, models import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('timeline_logger', '0003_auto_20171025_1414'), + ("timeline_logger", "0003_auto_20171025_1414"), ] operations = [ migrations.AlterField( - model_name='timelinelog', - name='content_type', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.ContentType', verbose_name='content type'), + model_name="timelinelog", + name="content_type", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="contenttypes.ContentType", + verbose_name="content type", + ), ), migrations.AlterField( - model_name='timelinelog', - name='extra_data', - field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True, verbose_name='extra data'), + model_name="timelinelog", + name="extra_data", + field=django.contrib.postgres.fields.jsonb.JSONField( + blank=True, null=True, verbose_name="extra data" + ), ), migrations.AlterField( - model_name='timelinelog', - name='object_id', - field=models.TextField(blank=True, null=True, verbose_name='object id'), + model_name="timelinelog", + name="object_id", + field=models.TextField(blank=True, null=True, verbose_name="object id"), ), migrations.AlterField( - model_name='timelinelog', - name='timestamp', - field=models.DateTimeField(auto_now_add=True, verbose_name='timestamp'), + model_name="timelinelog", + name="timestamp", + field=models.DateTimeField(auto_now_add=True, verbose_name="timestamp"), ), migrations.AlterField( - model_name='timelinelog', - name='user', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='user'), + model_name="timelinelog", + name="user", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL, + verbose_name="user", + ), ), ] diff --git a/timeline_logger/resources.py b/timeline_logger/resources.py index 376eed9..d95a471 100644 --- a/timeline_logger/resources.py +++ b/timeline_logger/resources.py @@ -1,22 +1,21 @@ -from import_export.resources import ModelResource from import_export.fields import Field +from import_export.resources import ModelResource from import_export.widgets import Widget from .models import TimelineLog class JSONWidget(Widget): - def render(self, value, obj=None): return value class TimelineLogResource(ModelResource): extra_data = Field( - attribute='extra_data', - column_name='extra_data', + attribute="extra_data", + column_name="extra_data", widget=JSONWidget(), - default=None + default=None, ) class Meta: diff --git a/timeline_logger/views.py b/timeline_logger/views.py index 321de98..cc17ae0 100644 --- a/timeline_logger/views.py +++ b/timeline_logger/views.py @@ -5,5 +5,5 @@ class TimelineLogListView(ListView): - queryset = TimelineLog.objects.order_by('-timestamp') + queryset = TimelineLog.objects.order_by("-timestamp") paginate_by = settings.TIMELINE_PAGINATE_BY From 55fe4ce2762720d424656c3281b897977cf0814a Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:17:15 +0100 Subject: [PATCH 09/19] :alien: Fixing test runner + Django deprecations --- setup.cfg | 4 +--- timeline_logger/apps.py | 2 +- timeline_logger/conf.py | 2 +- timeline_logger/management/commands/report_mailing.py | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/setup.cfg b/setup.cfg index 3dfd8d7..f939b01 100644 --- a/setup.cfg +++ b/setup.cfg @@ -91,9 +91,7 @@ sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER [tool:pytest] testpaths = tests -; django_find_project = false -DJANGO_SETTINGS_MODULE = testapp.settings_pg -; python_paths = . +DJANGO_SETTINGS_MODULE = tests.settings_pg [pep8] [flake8] diff --git a/timeline_logger/apps.py b/timeline_logger/apps.py index fcc449c..53e436c 100644 --- a/timeline_logger/apps.py +++ b/timeline_logger/apps.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, unicode_literals from django.apps import AppConfig -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class TimelineLoggerConfig(AppConfig): diff --git a/timeline_logger/conf.py b/timeline_logger/conf.py index f7b96d3..7bc6233 100644 --- a/timeline_logger/conf.py +++ b/timeline_logger/conf.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals from django.conf import settings # noqa -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from appconf import AppConf diff --git a/timeline_logger/management/commands/report_mailing.py b/timeline_logger/management/commands/report_mailing.py index 429260f..ea7b3ee 100644 --- a/timeline_logger/management/commands/report_mailing.py +++ b/timeline_logger/management/commands/report_mailing.py @@ -8,7 +8,7 @@ from django.template.loader import render_to_string from django.utils import timezone from django.utils.html import strip_tags -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from timeline_logger.compat import html from timeline_logger.models import TimelineLog From f158012595a9e2363f7b8bf770ed7e4b0babc0b7 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:18:24 +0100 Subject: [PATCH 10/19] :green_heart: Fix factory declarations --- tests/factories.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/factories.py b/tests/factories.py index 028784d..0477923 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,29 +1,28 @@ import factory -class UserFactory(factory.DjangoModelFactory): - class Meta: - model = 'auth.User' +class UserFactory(factory.django.DjangoModelFactory): + + first_name = "Test" + last_name = "User" + username = factory.Sequence(lambda n: "user_{0}".format(n)) + email = factory.Sequence(lambda n: "user_{0}@maykinmedia.nl".format(n)) + password = factory.PostGenerationMethodCall("set_password", "testing") - first_name = 'Test' - last_name = 'User' - username = factory.Sequence(lambda n: 'user_{0}'.format(n)) - email = factory.Sequence(lambda n: 'user_{0}@maykinmedia.nl'.format(n)) - password = factory.PostGenerationMethodCall('set_password', 'testing') + class Meta: + model = "auth.User" class ArticleFactory(factory.django.DjangoModelFactory): + title = factory.Faker("sentence") + date = factory.Faker("date") class Meta: - model = 'tests.Article' - - title = factory.Faker('sentence') - date = factory.Faker('date') + model = "tests.Article" class TimelineLogFactory(factory.django.DjangoModelFactory): + content_object = factory.SubFactory(ArticleFactory) class Meta: - model = 'timeline_logger.TimelineLog' - - content_object = factory.SubFactory(ArticleFactory) + model = "timeline_logger.TimelineLog" From e4d1b2be8c7f0e60082acccfa05a73b1a9337577 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:18:47 +0100 Subject: [PATCH 11/19] :art: Black & isort the tests --- tests/settings_pg.py | 14 ++++----- tests/test_management_commands.py | 51 ++++++++++++++++--------------- tests/test_models.py | 36 ++++++++++++---------- tests/test_templatetags.py | 15 ++++----- tests/test_views.py | 8 ++--- 5 files changed, 65 insertions(+), 59 deletions(-) diff --git a/tests/settings_pg.py b/tests/settings_pg.py index 104390f..7443527 100644 --- a/tests/settings_pg.py +++ b/tests/settings_pg.py @@ -3,12 +3,12 @@ from .settings import * # noqa DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'timeline_logger', - 'USER': os.getenv('PGUSER', 'postgres'), - 'PASSWORD': os.getenv('PGPASSWORD', ''), - 'HOST': os.getenv('PGHOST', ''), - 'PORT': os.getenv('PGPORT', 5432), + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": "timeline_logger", + "USER": os.getenv("PGUSER", "postgres"), + "PASSWORD": os.getenv("PGPASSWORD", ""), + "HOST": os.getenv("PGHOST", ""), + "PORT": os.getenv("PGPORT", 5432), } } diff --git a/tests/test_management_commands.py b/tests/test_management_commands.py index 0415084..79ab265 100644 --- a/tests/test_management_commands.py +++ b/tests/test_management_commands.py @@ -16,7 +16,7 @@ class ReportMailingTestCase(TestCase): def setUp(self): self.article = ArticleFactory.create() - self.user = UserFactory.create(email='jose@maykinmedia.nl') + self.user = UserFactory.create(email="jose@maykinmedia.nl") self.staff_user = UserFactory.create(is_staff=True) self.admin_user = UserFactory.create(is_staff=True, is_superuser=True) @@ -33,43 +33,50 @@ def setUp(self): user=self.user, ) - @override_settings(TIMELINE_DIGEST_EMAIL_RECIPIENTS=['jose@maykinmedia.nl']) + @override_settings(TIMELINE_DIGEST_EMAIL_RECIPIENTS=["jose@maykinmedia.nl"]) def test_recipients_from_setting_parameter(self): """ The ``--recipients-from-setting`` parameter will send notifications only to those users listed in the ``TIMELINE_DIGEST_EMAIL_RECIPIENTS`` setting. """ - call_command('report_mailing', '--recipients-from-setting') + call_command("report_mailing", "--recipients-from-setting") self.assertEqual(len(mail.outbox), 1) - self.assertListEqual(mail.outbox[0].to, settings.TIMELINE_DIGEST_EMAIL_RECIPIENTS) + self.assertListEqual( + mail.outbox[0].to, settings.TIMELINE_DIGEST_EMAIL_RECIPIENTS + ) def test_staff_parameter(self): """ The ``--staff`` parameter will send notifications only to those users marked who have ``is_staff=True``. """ - call_command('report_mailing', '--staff') + call_command("report_mailing", "--staff") self.assertEqual(len(mail.outbox), 1) - self.assertListEqual(mail.outbox[0].to, [self.staff_user.email, self.admin_user.email]) + self.assertListEqual( + mail.outbox[0].to, [self.staff_user.email, self.admin_user.email] + ) def test_all_parameter(self): """ The ``--all`` parameter will send notifications to all users. """ - call_command('report_mailing', '--all') + call_command("report_mailing", "--all") self.assertEqual(len(mail.outbox), 1) - self.assertListEqual(mail.outbox[0].to, [self.user.email, self.staff_user.email, self.admin_user.email]) + self.assertListEqual( + mail.outbox[0].to, + [self.user.email, self.staff_user.email, self.admin_user.email], + ) def test_no_recipients_parameter(self): """ When no 'recipients' parameter is passed, only those users who are 'staff' and 'superuser' will be notified. """ - call_command('report_mailing') + call_command("report_mailing") self.assertEqual(len(mail.outbox), 1) self.assertListEqual(mail.outbox[0].to, [self.admin_user.email]) @@ -83,7 +90,8 @@ def test_invalid_days_parameter(self): CommandError, "Incorrect 'days' parameter. 'days' must be a number of days.", call_command, - 'report_mailing', days='NaN' + "report_mailing", + days="NaN", ) def test_days_parameter_successful(self): @@ -97,7 +105,7 @@ def test_days_parameter_successful(self): self.log_1.save() self.log_2.save() - call_command('report_mailing', days=15) + call_command("report_mailing", days=15) self.assertEqual(len(mail.outbox), 1) @@ -106,19 +114,12 @@ def test_days_parameter_successful(self): # The 1st log `self.log_1` is NOT present in the email, because it was # generated before 15 days ago from today. self.assertNotIn( - date(self.log_1.timestamp, settings.DATETIME_FORMAT), - mail_body + date(self.log_1.timestamp, settings.DATETIME_FORMAT), mail_body ) # The other logs `self.log_2` and `self.log_3` are properly - self.assertIn( - date(self.log_2.timestamp, settings.DATETIME_FORMAT), - mail_body - ) - self.assertIn( - date(self.log_3.timestamp, settings.DATETIME_FORMAT), - mail_body - ) + self.assertIn(date(self.log_2.timestamp, settings.DATETIME_FORMAT), mail_body) + self.assertIn(date(self.log_3.timestamp, settings.DATETIME_FORMAT), mail_body) def test_no_logs_recorded(self): """ @@ -127,7 +128,7 @@ def test_no_logs_recorded(self): # Get rid of all the existent logs. TimelineLog.objects.all().delete() - call_command('report_mailing') + call_command("report_mailing") self.assertEqual(len(mail.outbox), 0) @@ -136,18 +137,18 @@ def test_no_timeline_digest_from_email_setting(self): If the ``TIMELINE_DIGEST_FROM_EMAIL`` setting is not set, the backend will default to the Django's standard ``DEFAULT_FROM_EMAIL`` setting. """ - call_command('report_mailing') + call_command("report_mailing") self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, settings.DEFAULT_FROM_EMAIL) - @override_settings(TIMELINE_DIGEST_FROM_EMAIL='reports@maykinmedia.nl') + @override_settings(TIMELINE_DIGEST_FROM_EMAIL="reports@maykinmedia.nl") def test_timeline_digest_from_email_setting(self): """ If the ``TIMELINE_DIGEST_FROM_EMAIL`` setting is not set, the backend will default to the Django's standard ``DEFAULT_FROM_EMAIL`` setting. """ - call_command('report_mailing') + call_command("report_mailing") self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, settings.TIMELINE_DIGEST_FROM_EMAIL) diff --git a/tests/test_models.py b/tests/test_models.py index 8b9d786..a29ffab 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -17,14 +17,16 @@ class TimelineLogTestCase(TestCase): def setUp(self): self.article = ArticleFactory.create() - self.user = User.objects.create(username='john_doe', email='john.doe@maykinmedia.nl') + self.user = User.objects.create( + username="john_doe", email="john.doe@maykinmedia.nl" + ) self.timeline_log = TimelineLog.objects.create( content_object=self.article, user=self.user, ) - self.request = RequestFactory().get('/my_object/') + self.request = RequestFactory().get("/my_object/") def test_log_from_request_no_user(self): """ @@ -43,8 +45,10 @@ def test_log_from_request_with_user(self): self.assertEqual(log.user, self.user) - @skipIf(settings.DATABASES['default']['ENGINE'] != 'django.db.backends.postgresql', - "'JSONField' can only be used in a PostgreSQL database.") + @skipIf( + settings.DATABASES["default"]["ENGINE"] != "django.db.backends.postgresql", + "'JSONField' can only be used in a PostgreSQL database.", + ) def test_log_from_request_no_extra_data(self): """ Test ``log_from_request`` method when no ``extra_data`` dictionary is @@ -54,17 +58,16 @@ def test_log_from_request_no_extra_data(self): self.assertIsNone(log.extra_data) - @skipIf(settings.DATABASES['default']['ENGINE'] != 'django.db.backends.postgresql', - "'JSONField' can only be used in a PostgreSQL database.") + @skipIf( + settings.DATABASES["default"]["ENGINE"] != "django.db.backends.postgresql", + "'JSONField' can only be used in a PostgreSQL database.", + ) def test_log_from_request_with_extra_data(self): """ Test ``log_from_request`` method when an ``extra_data`` dictionary is passed. """ - extra_data = { - 'status': 'published', - 'institution': 'Utrecht University' - } + extra_data = {"status": "published", "institution": "Utrecht University"} log = TimelineLog.log_from_request(self.request, self.article, **extra_data) @@ -76,7 +79,7 @@ def test_log_from_request_no_template(self): """ log = TimelineLog.log_from_request(self.request, self.article) - self.assertEqual(log.template, 'timeline_logger/default.txt') + self.assertEqual(log.template, "timeline_logger/default.txt") def test_log_from_request_wrong_template(self): """ @@ -86,7 +89,9 @@ def test_log_from_request_wrong_template(self): self.assertRaises( TemplateDoesNotExist, TimelineLog.log_from_request, - self.request, self.article, 'non_existent.html' + self.request, + self.article, + "non_existent.html", ) def test_get_message(self): @@ -97,8 +102,7 @@ def test_get_message(self): self.assertEqual( log.get_message(), - '{0} - Anonymous user event on {1}.\n'.format( - date(log.timestamp, 'DATETIME_FORMAT'), - log.content_object - ) + "{0} - Anonymous user event on {1}.\n".format( + date(log.timestamp, "DATETIME_FORMAT"), log.content_object + ), ) diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index ffdebc7..db978de 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -1,18 +1,19 @@ -import pytest from django.conf import settings from django.template.loader import render_to_string +import pytest + from .compat import patch from .factories import TimelineLogFactory @pytest.mark.skipif( - settings.DATABASES['default']['ENGINE'] != 'django.db.backends.postgresql', - reason='Requires PostgreSQL' + settings.DATABASES["default"]["ENGINE"] != "django.db.backends.postgresql", + reason="Requires PostgreSQL", ) @pytest.mark.django_db def test_render_message(): - log = TimelineLogFactory.create(extra_data={'foo': 'bar'}) - with patch.object(log, 'get_message') as mock_get_message: - render_to_string('test_render_message', {'log': log}) - mock_get_message.assert_called_once_with(template=None, extra_context='yes') + log = TimelineLogFactory.create(extra_data={"foo": "bar"}) + with patch.object(log, "get_message") as mock_get_message: + render_to_string("test_render_message", {"log": log}) + mock_get_message.assert_called_once_with(template=None, extra_context="yes") diff --git a/tests/test_views.py b/tests/test_views.py index 9ca3560..a11b7ed 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -11,9 +11,9 @@ @pytest.mark.django_db def test_listview(client): log_entries = TimelineLogFactory.create_batch(26) - response = client.get(reverse('timeline:timeline')) + response = client.get(reverse("timeline:timeline")) assert response.status_code == 200 - queryset = response.context['object_list'] + queryset = response.context["object_list"] assert queryset.count(), 25 - assert log_entries[0] not in queryset, 'Oldest object should not be displayed' - assert log_entries[-1] in queryset, 'Newest log entry should be displayed' + assert log_entries[0] not in queryset, "Oldest object should not be displayed" + assert log_entries[-1] in queryset, "Newest log entry should be displayed" From c549bd713b086c866a38dbf9ffb0ccf57288e056 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:24:15 +0100 Subject: [PATCH 12/19] :wrench: More test setup fixes --- reports/coverage-py310-django32.xml | 257 ++++++++++++++++++++++++++++ setup.cfg | 2 + tox.ini | 4 +- 3 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 reports/coverage-py310-django32.xml diff --git a/reports/coverage-py310-django32.xml b/reports/coverage-py310-django32.xml new file mode 100644 index 0000000..717f963 --- /dev/null +++ b/reports/coverage-py310-django32.xml @@ -0,0 +1,257 @@ + + + + + + /home/bbt/code/django-timeline-logger/timeline_logger + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup.cfg b/setup.cfg index f939b01..808029f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,6 +41,7 @@ tests_require = pytest-pythonpath pytest-runner tox + black isort [options.packages.find] @@ -60,6 +61,7 @@ tests = pytest-pythonpath pytest-runner tox + black isort pep8 = flake8 coverage = pytest-cov diff --git a/tox.ini b/tox.ini index 31935fd..2d0d82e 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ DJANGO = [testenv] setenv = - DJANGO_SETTINGS_MODULE=testapp.settings + DJANGO_SETTINGS_MODULE=tests.settings_pg PYTHONPATH={toxinidir} extras = tests @@ -35,7 +35,7 @@ commands = isort --check-only --diff . [testenv:black] extras = tests skipsdist = True -commands = black --check timeline_logger docs testapp tests setup.py +commands = black --check timeline_logger docs tests setup.py [testenv:docs] basepython=python From 1ac05301dbc3574f1851d1dd5a3a67d187c6241a Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:26:08 +0100 Subject: [PATCH 13/19] :see_no_evil: Don't track reports in VCS --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5e1e20e..fb3655c 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ coverage.xml cover/* .hypothesis/ junit*.xml +reports/ # Translations *.pot From fdcc68c0c2c47b115a8854ccdc5de186dd3f4b23 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:30:05 +0100 Subject: [PATCH 14/19] :green_heart: Isort and black the demo app --- demo/demo/settings.py | 88 +++++++++++++++++++++--------------------- demo/demo/urls.py | 2 +- demo/demo_app/admin.py | 3 +- demo/demo_app/apps.py | 2 +- docs/conf.py | 81 ++++++++++++++++++++++---------------- 5 files changed, 94 insertions(+), 82 deletions(-) diff --git a/demo/demo/settings.py b/demo/demo/settings.py index 5d2e3f8..3bee795 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -15,72 +15,70 @@ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -SECRET_KEY = 'such-secret-much-hiding-wow' +SECRET_KEY = "such-secret-much-hiding-wow" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = ["*"] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - - 'import_export', - 'timeline_logger', - - 'demo_app.apps.DemoAppConfig', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "import_export", + "timeline_logger", + "demo_app.apps.DemoAppConfig", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'demo.urls' +ROOT_URLCONF = "demo.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'demo.wsgi.application' +WSGI_APPLICATION = "demo.wsgi.application" # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.getenv('PGDATABASE', 'timeline_logger'), - 'USER': os.getenv('PGUSER', 'postgres'), - 'PASSWORD': os.getenv('PGPASSWORD', ''), - 'HOST': os.getenv('PGHOST', ''), - 'PORT': os.getenv('PGPORT', 5432), + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": os.getenv("PGDATABASE", "timeline_logger"), + "USER": os.getenv("PGUSER", "postgres"), + "PASSWORD": os.getenv("PGPASSWORD", ""), + "HOST": os.getenv("PGHOST", ""), + "PORT": os.getenv("PGPORT", 5432), } } @@ -90,16 +88,16 @@ AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -107,9 +105,9 @@ # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -121,4 +119,4 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" diff --git a/demo/demo/urls.py b/demo/demo/urls.py index 0d5af83..e6bad02 100644 --- a/demo/demo/urls.py +++ b/demo/demo/urls.py @@ -17,5 +17,5 @@ from django.contrib import admin urlpatterns = [ - url(r'^admin/', admin.site.urls), + url(r"^admin/", admin.site.urls), ] diff --git a/demo/demo_app/admin.py b/demo/demo_app/admin.py index 11652e1..0a3dbc6 100644 --- a/demo/demo_app/admin.py +++ b/demo/demo_app/admin.py @@ -3,8 +3,9 @@ from import_export.admin import ExportMixin from import_export.formats import base_formats from import_export_xml.formats import XML -from timeline_logger.models import TimelineLog + from timeline_logger.admin import TimelineLogAdmin +from timeline_logger.models import TimelineLog from timeline_logger.resources import TimelineLogResource admin.site.unregister(TimelineLog) diff --git a/demo/demo_app/apps.py b/demo/demo_app/apps.py index 0d5711e..a0ea082 100644 --- a/demo/demo_app/apps.py +++ b/demo/demo_app/apps.py @@ -2,4 +2,4 @@ class DemoAppConfig(AppConfig): - name = 'demo_app' + name = "demo_app" diff --git a/docs/conf.py b/docs/conf.py index e579883..fd70a8c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ # sys.path.insert(0, os.path.abspath('.')) from pkg_resources import get_distribution -FULL_VERSION = get_distribution('django-timeline-logger').version +FULL_VERSION = get_distribution("django-timeline-logger").version # -- General configuration ------------------------------------------------ @@ -36,25 +36,25 @@ extensions = [] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'Django Timeline Logger' -copyright = '2016-2018, Maykin Media' -author = 'Maykin Media' +project = "Django Timeline Logger" +copyright = "2016-2018, Maykin Media" +author = "Maykin Media" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -84,7 +84,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -106,7 +106,7 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -123,7 +123,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -237,34 +237,36 @@ # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'DjangoTimelineLoggerdoc' +htmlhelp_basename = "DjangoTimelineLoggerdoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'DjangoTimelineLogger.tex', 'Django Timeline Logger Documentation', - 'Maykin Media', 'manual'), + ( + master_doc, + "DjangoTimelineLogger.tex", + "Django Timeline Logger Documentation", + "Maykin Media", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of @@ -299,8 +301,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'djangotimelinelogger', 'Django Timeline Logger Documentation', - [author], 1) + ( + master_doc, + "djangotimelinelogger", + "Django Timeline Logger Documentation", + [author], + 1, + ) ] # If true, show URL addresses after external links. @@ -314,9 +321,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'DjangoTimelineLogger', 'Django Timeline Logger Documentation', - author, 'DjangoTimelineLogger', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "DjangoTimelineLogger", + "Django Timeline Logger Documentation", + author, + "DjangoTimelineLogger", + "One line description of project.", + "Miscellaneous", + ), ] # Documents to append as an appendix to all manuals. @@ -336,5 +349,5 @@ # texinfo_no_detailmenu = False linkcheck_ignore = [ - r'^http://localhost:\d+.*', + r"^http://localhost:\d+.*", ] From b80c890e1db6f727b156d8f44be3b3d36bd6a556 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:32:58 +0100 Subject: [PATCH 15/19] :construction_worker: Fix specifying TOXENV before calling tox --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a42432..d490235 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,8 +42,8 @@ jobs: - name: Run tests run: | - tox export TOXENV=py${PYTHON_VERSION/./}-django${DJANGO/./} + tox codecov -e TOXENV,DJANGO --file reports/coverage-${TOXENV}.xml env: PYTHON_VERSION: ${{ matrix.python }} From 9c20fabafe4bcd6fc25b6d3a492f174e3423e1af Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:35:46 +0100 Subject: [PATCH 16/19] :green_heart: Fix DB connection params on CI --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d490235..30b0d91 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,7 @@ jobs: env: PYTHON_VERSION: ${{ matrix.python }} DJANGO: ${{ matrix.django }} + PGHOST: localhost - name: Publish coverage report uses: codecov/codecov-action@v1 From e5e5a31ff1c62f7b2586fdb664139e2994937b39 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:45:17 +0100 Subject: [PATCH 17/19] :pencil: Update project urls + changelog --- docs/changelog.rst | 10 ++++++++++ setup.cfg | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6fc0a7e..603725d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,16 @@ Changelog ========= +2.0.0 (2022-02-15) +================== + +No changes in functionality or public API, just our supported versions of Python/Django. + +* Dropped Python 2, Python < 3.6 support +* Dropped Django 1.11, 2.0 and 2.1 support +* Added explicit support for Django 2.2 and 3.2 +* Added explicit support for Python 3.6, 3.7, 3.8, 3.9 and 3.10 + 1.1.2 (2018-05-30) ================== diff --git a/setup.cfg b/setup.cfg index 808029f..e61db63 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,10 +4,15 @@ version = 1.1.2 description = Generic event logger for Django models. long_description = file: README.rst url = https://github.com/maykinmedia/django-timeline-logger +project_urls = + Documentation = http://django-timeline-logger.readthedocs.io/en/latest/ + Changelog = https://github.com/maykinmedia/django-timeline-logger/blob/master/docs/changelog.rst + Bug Tracker = https://github.com/maykinmedia/django-timeline-logger/issues + Source Code = https://github.com/maykinmedia/django-timeline-logger license = MIT author = Maykin Media author_email = support@maykinmedia.nl -keywords = TODO +keywords = django, generic logging classifiers = Development Status :: 5 - Production/Stable Framework :: Django From 6090a11ccd7524e31503d12bf73c3898ac84f03a Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:46:35 +0100 Subject: [PATCH 18/19] :wrench: Properly pass connection params with tox --- tox.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tox.ini b/tox.ini index 2d0d82e..67e8a75 100644 --- a/tox.ini +++ b/tox.ini @@ -15,6 +15,11 @@ DJANGO = setenv = DJANGO_SETTINGS_MODULE=tests.settings_pg PYTHONPATH={toxinidir} +passenv = + PGHOST + PGPORT + PGUSER + PGPASSWORD extras = tests coverage From 07528e7ca40f64c216642ddbafc903372a67c5d9 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Tue, 15 Feb 2022 16:49:00 +0100 Subject: [PATCH 19/19] :bookmark: Bump to version 2.0.0 --- .bumpversion.cfg | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 708735f..a5fc6e6 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,6 +1,6 @@ [bumpversion] commit = False tag = False -current_version = 1.1.2 +current_version = 2.0.0 [bumpversion:file:setup.cfg] diff --git a/setup.cfg b/setup.cfg index e61db63..1cf321c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = django-timeline-logger -version = 1.1.2 +version = 2.0.0 description = Generic event logger for Django models. long_description = file: README.rst url = https://github.com/maykinmedia/django-timeline-logger