From 4c7694e7ba30359bf785c6502e5a5b18da014296 Mon Sep 17 00:00:00 2001 From: Yuji Imamura <23151008+imaxyz@users.noreply.github.com> Date: Mon, 11 Apr 2022 12:29:56 +0900 Subject: [PATCH] =?UTF-8?q?py3.9=E5=AF=BE=E5=BF=9C+=E6=AC=A1=E3=83=90?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=200.48=20=E7=94=A8?= =?UTF-8?q?=E3=81=AE=E8=A8=98=E8=BF=B0=E3=82=92setup.py=E3=81=AB=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * py36-django22を通すための改修を反映。py 2.7とdjango1.11のテストを削除。 * celery 4.2系, celery5.1系を指定する記述を追加 * py39のテストシナリオを追加 * Django 3系の条件を追記。対応はまだ。 * wip: py39-django32でfailする * django3.2のtoxがpassするように調整 * コメントを追加 * travis-ciの設定を削除。GitHub Actionsの設定を追加。 * tox.iniにtox-gh-actionsの設定を追加 * コメントを追加。github-actionsのmatrix条件を追加。 * py3.9のテストが起動しなくなったので、matrixの条件を減らす意図で、celeryの条件を削除 * strategy.max-parallelを指定。tox.iniに[gh-actions:env]の項目を追加。matrixにceleryの条件を追加。 * max-paraallelの記述を削除。toxのオプションを削除。 * 記述が難しくなったので、test.ymlの記述をいったん簡略化。 * gh-actions関連の修正 * gh-actions関連の修正 * gh-actions関連の修正 * gh-actions設定の調整 * gh-actions設定の調整 * コメントを修正 * setup.pyの記述をtox.iniの情報に合うように変更。バージョンを0.48に変更。リンク参照先とリンク先を異なるものにしたいため、READMEをrst形式の記述に変更。 * READMEをmd形式からrst形式に変更するにあたってに影響する箇所を修正。PyPIに掲載する情報を他のbp管理パッケージに合わせて追加。 * setup.pyのinstall_requires: 'django-jsonfield>=1.0.1' は記述を省けなかったので元に戻す。記述理由のコメントを追加。 * readmeの依存パッケージの記述を修正 * コメント文を修正 * suggestionを反映 Co-authored-by: Takayuki SHIMIZUKAWA * メソッド名変更に伴いテストコードも調整 * mockは標準ライブラリ unittestのmockを使うように変更 * ChageLogを追加 * 変更点を追記 * manifest.inにchageLogを追加 * change logを修正しました。 mockパッケージの件は、bpnotifyパッケージ内部の話なので、Featuresに変更しました。 サポート終了の話題を、Imcompatible Changesの欄に移動しました。 Celeryのメソッド名という表現をタスク名に変更しました(さらに、メソッド名ではなく、関数名だった) Co-authored-by: Takayuki SHIMIZUKAWA --- .github/workflows/tests.yml | 41 ++++++++++++++ .travis.yml | 12 ---- CHANGES.rst | 19 +++++++ MANIFEST.in | 3 +- README.md | 11 ---- README.rst | 20 +++++++ beproud/django/notify/tasks.py | 51 ++++++----------- beproud/django/notify/tests/test_tasks.py | 8 +-- release_checklist.rst | 37 ++++++++++++ setup.py | 16 ++++-- test_settings.py | 60 ++++++++++++++++++++ tests.py | 69 ++++++----------------- tox.ini | 28 ++++----- 13 files changed, 243 insertions(+), 132 deletions(-) create mode 100644 .github/workflows/tests.yml delete mode 100644 .travis.yml create mode 100644 CHANGES.rst delete mode 100644 README.md create mode 100644 README.rst create mode 100644 release_checklist.rst create mode 100644 test_settings.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..5ae22dd --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,41 @@ +name: Tests + +# push と pull request イベント毎にGtihubのWorkflowを起動する +on: + - push + - pull_request + +jobs: + # ジョブの名称 + test_with_tox: + name: build (Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}) + runs-on: ubuntu-latest + + # 並列して実行する各ジョブのPythonバージョン + strategy: + matrix: + python-version: ['3.6', '3.9'] + django-version: ['2.2', '3.2'] + + steps: + # ソースコードをチェックアウト + - uses: actions/checkout@v2 + + # ジョブのPython環境を設定 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + # Github Actionsからtoxを実行するために必要なパッケージをインストール + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install tox tox-gh-actions + + # Github Actionsからtoxを実行 + - name: Test with tox + run: | + tox -v + env: + DJANGO: ${{ matrix.django-version }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 26207c8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: python -sudo: false - -install: - - pip install tox-travis -python: - - "2.7" - - "3.6" -env: - - DJANGO="1.11" - - DJANGO="2.2" -script: tox diff --git a/CHANGES.rst b/CHANGES.rst new file mode 100644 index 0000000..3a19a67 --- /dev/null +++ b/CHANGES.rst @@ -0,0 +1,19 @@ +ChangeLog +========= + +0.48 (2022-04-11) +=================== + +Features: + + +- Python3.9のサポートを追加しました。 +- toxの実行環境を、Travis CIからGitHubに変更しました。 +- READMEの書式をmarkdownからreStructuredTxtに変更しました。  +- mockパッケージに関して、標準ライブラリのunitestに含まれるmockを使用するように変更しました。 + +Incompatible Changes: + +- Python2.7のサポートを終了しました。 +- Django1.11のサポートを終了しました。 +- Celeryのタスク名を `Notify` から `notify` に変更しました。 diff --git a/MANIFEST.in b/MANIFEST.in index 6e162cd..4a467e1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ recursive-include beproud/django/notify/tests/templates * recursive-include beproud/django/notify/templates * recursive-include beproud/django/notify/fixtures * -include README.md +include README.rst +include CHANGES.rst diff --git a/README.md b/README.md deleted file mode 100644 index 3b598d1..0000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ -[![Build Status](https://travis-ci.org/beproud/bpnotify.svg?branch=master)](https://travis-ci.org/beproud/bpnotify) - -`bpnotify` is notification routing for Django. Application notify function with targets, notify_type, media, extra_data, then bpnotify send notify with backend (example: mail). - -# Requirements - -* Python (2.7, 3.6) -* Celery (4.1) -* Django (1.8, 1.11) -* django-jsonfield (1.0.1) - diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..5a8adc5 --- /dev/null +++ b/README.rst @@ -0,0 +1,20 @@ +.. image:: https://github.com/beproud/bpnotify/actions/workflows/tests.yml/badge.svg + :target: https://github.com/beproud/bpnotify/actions + :alt: GitHub Actions + +`bpnotify` is notification routing for Django. Application notify function with targets, notify_type, media, extra_data, then bpnotify send notify with backend (example: mail). + +Requirements +============ + +* Python (3.6, 3.9) +* Celery (4.2, 5.1, 5.2) +* Django (2.2, 3.2) +* six +* django-jsonfield (1.0.1) + +Links +================= + +* `release checklist `_ + diff --git a/beproud/django/notify/tasks.py b/beproud/django/notify/tasks.py index 196a9e3..8db8531 100644 --- a/beproud/django/notify/tasks.py +++ b/beproud/django/notify/tasks.py @@ -4,41 +4,24 @@ from django.conf import settings import celery -from celery.task import Task -from celery.registry import tasks - -if celery.VERSION < (3, 1): - try: - import djcelery # NOQA - except ImportError: - from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured("when used celery<3.1, djcelery is required!") - - if 'djcelery' not in settings.INSTALLED_APPS: - from django.core.exceptions import ImproperlyConfigured - raise ImproperlyConfigured("djcelery not in INSTALLED_APPS!") +from celery import shared_task from beproud.django.notify import notify_now - -class Notify(Task): - - def run(self, targets, notify_type, extra_data={}, include_media=None, exclude_media=[], +@shared_task(bind=True) +def notify(self, targets, notify_type, extra_data={}, include_media=None, exclude_media=[], max_retries=3, retry_countdown=10, **kwargs): - try: - return notify_now( - targets, - notify_type, - extra_data=extra_data, - include_media=include_media, - exclude_media=exclude_media, - ) - except Exception as e: - return self.retry( - exc=e, - countdown=retry_countdown, - max_retries=max_retries, - ) - - -tasks.register(Notify) + try: + return notify_now( + targets, + notify_type, + extra_data=extra_data, + include_media=include_media, + exclude_media=exclude_media, + ) + except Exception as e: + return self.retry( + exc=e, + countdown=retry_countdown, + max_retries=max_retries, + ) \ No newline at end of file diff --git a/beproud/django/notify/tests/test_tasks.py b/beproud/django/notify/tests/test_tasks.py index 485e0fb..a02834b 100644 --- a/beproud/django/notify/tests/test_tasks.py +++ b/beproud/django/notify/tests/test_tasks.py @@ -1,6 +1,6 @@ #:coding=utf8: -import mock +from unittest import mock from django.test import TestCase from django.contrib.auth.models import User @@ -40,7 +40,7 @@ def test_notify_task(self): Simple task to test the Notify task. """ user = User.objects.get(pk=2) - notify_tasks.Notify.delay( + notify_tasks.notify.delay( targets=[user], notify_type='private_msg', ) @@ -67,7 +67,7 @@ def _notify_now(*args, **kwargs): notify_now.side_effect = _notify_now user = User.objects.get(pk=2) - notify_tasks.Notify.delay( + notify_tasks.notify.delay( targets=[user], notify_type='private_msg', ) @@ -92,7 +92,7 @@ def _notify_now(*args, **kwargs): notify_now.side_effect = _notify_now user = User.objects.get(pk=2) - notify_tasks.Notify.delay( + notify_tasks.notify.delay( targets=[user], notify_type='private_msg', ) diff --git a/release_checklist.rst b/release_checklist.rst new file mode 100644 index 0000000..dcda7ec --- /dev/null +++ b/release_checklist.rst @@ -0,0 +1,37 @@ +リリース手順 +============== + +事前準備 +-------------- + +* GitHub, PyPI, TestPyPIのアカウントにbpnotifyの編集権限を設定 +* パッケージのビルドに使用するパッケージをインストール + + * ``pip install wheel twine`` + + +手順 +-------------------- +1. 次バージョンのパッケージをビルド + + * ``python setup.py sdist bdist_wheel`` + +2. twineのコマンドを実行して、エラーが出ないことを確認 + + * ``twine check --strict dist/*`` + +3. dist/に作成したパッケージをTestPyPIへアップロード + + * ``twine upload --repository testpypi dist/*`` + +4. TestPyPIで、descriptionがエラーなく表示されていることと、ビルドしたパッケージがアップロードされていることを確認 + + * TestPyPIへアップロードした内容に問題がある場合、修正したパッケージをTestPyPIに再度アップロード + +5. GitHubで次バージョンのReleaseタグを作成し、Publish Releaseを実行 + + * dist/に試行錯誤したパッケージが残っている場合、一度全て削除し、本番アップロード用のパッケージを再度作成 + +6. dist/に作成したパッケージを本番環境のPyPIにアップロード + + * ``twine upload dist/*`` diff --git a/setup.py b/setup.py index ac2a7fe..7bfab3c 100644 --- a/setup.py +++ b/setup.py @@ -14,13 +14,14 @@ def read_file(filename): setup( name='bpnotify', - version='0.47', + version='0.48', description='Notification routing for Django', author='BeProud', author_email='project@beproud.jp', - long_description=read_file('README.md'), - long_description_content_type="text/markdown", + long_description=read_file('README.rst'), + long_description_content_type="text/x-rst", url='https://github.com/beproud/bpnotify/', + python_requires='>=3.6', classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Plugins', @@ -28,6 +29,12 @@ def read_file(filename): 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.9', + 'Framework :: Django', + 'Framework :: Django :: 2.2', + 'Framework :: Django :: 3.2', 'Topic :: Software Development :: Libraries :: Python Modules', ], include_package_data=True, @@ -35,8 +42,9 @@ def read_file(filename): namespace_packages=['beproud', 'beproud.django'], test_suite='tests.main', install_requires=[ - 'Django>=1.11', + 'Django>=2.2', 'django-jsonfield>=1.0.1', + 'Celery>=4.2', 'six', ], zip_safe=False, diff --git a/test_settings.py b/test_settings.py new file mode 100644 index 0000000..240e1cd --- /dev/null +++ b/test_settings.py @@ -0,0 +1,60 @@ +# Django3では、標準のdjango.conf.global_settingsの定数をオーバーライドすると例外が発生する場合がある。 +# https://github.com/django/django/blob/70035fb0444ae7c01613374212ca5e3c27c9782c/django/conf/__init__.py#L188 +# そのため、testではdjango.conf.global_settingsを直接利用せず、このtest用settings定数を使用する。 + +SECRET_KEY = "SECRET" +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'beproud.django.notify', +) + +# kombu.exceptions.EncodeError: Object of type User is not JSON serializable エラーを抑止する +# (参考) +# https://github.com/celery/celery/issues/5922 +# https://stackoverflow.com/questions/49373825/kombu-exceptions-encodeerror-user-is-not-json-serializable +CELERY_TASK_SERIALIZER = "pickle" + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': ':memory:', + } +} + +import os +BASE_PATH = os.path.dirname(__file__) + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_PATH, 'beproud', 'django', 'notify', 'tests', 'templates') + ], + }, +] + +CELERY_TASK_ALWAYS_EAGER = True + +BPNOTIFY_MEDIA = { + "news": { + "verbose_name": "News", + "default_types": ("new_user", "follow", "private_msg"), + "backends": ( + "beproud.django.notify.backends.model.ModelBackend", + ), + }, + "private_messages": { + "verbose_name": "Private Message", + "default_types": ("private_msg", "notify_type_with_length_over_thirty"), + "backends": ( + "beproud.django.notify.backends.model.ModelBackend", + "beproud.django.notify.backends.mail.EmailBackend", + ), + }, +} +BPNOTIFY_SETTINGS_STORAGE = 'beproud.django.notify.storage.db.DBStorage' + +# The name of the class to use to run the test suite +TEST_RUNNER = 'django.test.runner.DiscoverRunner' + diff --git a/tests.py b/tests.py index a768e8b..8945737 100644 --- a/tests.py +++ b/tests.py @@ -3,6 +3,7 @@ import django import celery +import test_settings BASE_PATH = os.path.dirname(__file__) @@ -13,69 +14,33 @@ def main(): You can play with a django model without a complete django app installation. http://www.djangosnippets.org/snippets/1044/ """ - os.environ["DJANGO_SETTINGS_MODULE"] = "django.conf.global_settings" - from django.conf import global_settings - global_settings.SECRET_KEY = "SECRET" - global_settings.INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'beproud.django.notify', - ) - - global_settings.DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': ':memory:', - } - } - - #global_settings.ROOT_URLCONF = 'notify.tests.urls' - global_settings.TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.join(BASE_PATH, 'beproud', 'django', 'notify', 'tests', 'templates') - ], - }, - ] - - global_settings.CELERY_TASK_ALWAYS_EAGER = True - - global_settings.BPNOTIFY_MEDIA = { - "news": { - "verbose_name": "News", - "default_types": ("new_user", "follow", "private_msg"), - "backends": ( - "beproud.django.notify.backends.model.ModelBackend", - ), - }, - "private_messages": { - "verbose_name": "Private Message", - "default_types": ("private_msg", "notify_type_with_length_over_thirty"), - "backends": ( - "beproud.django.notify.backends.model.ModelBackend", - "beproud.django.notify.backends.mail.EmailBackend", - ), - }, - } - global_settings.BPNOTIFY_SETTINGS_STORAGE = 'beproud.django.notify.storage.db.DBStorage' + # Django標準のdjango.conf.global_settingsを設定してしまうと、 + # Django3では、global_settingsの全ての定数を上書きする挙動になってしまい、 + # Django3の仕様で、多重上書き禁止エラーが検知され、例外が発生する。 + # (例) https://github.com/django/django/blob/70035fb0444ae7c01613374212ca5e3c27c9782c/django/conf/__init__.py#L188 + # そのため、自前のテスト用settingsモジュール(test_settings.py)を設定する。 + os.environ["DJANGO_SETTINGS_MODULE"] = "test_settings" app = celery.Celery() app.config_from_object('django.conf:settings', namespace='CELERY') - app.autodiscover_tasks(lambda: global_settings.INSTALLED_APPS) + app.autodiscover_tasks(lambda: test_settings.INSTALLED_APPS) django.setup() from django.test.utils import get_runner - test_runner = get_runner(global_settings) - test_runner = test_runner() - - # See: https://docs.djangoproject.com/en/1.6/topics/testing/overview/#running-tests - failures = test_runner.run_tests(['beproud.django.notify']) + # test用のsettings情報を用いて、Djangoのtest runnerクラスを取得 + TestRunner = get_runner(test_settings) + + # test runnerオブジェクトを生成 + test_runner = TestRunner() + + # test runnerにbpnotifyの単体テストのPathを渡して、bpnotifyの単体テストを実行する + failures = test_runner.run_tests(['beproud.django.notify.tests']) sys.exit(failures) + if __name__ == '__main__': main() diff --git a/tox.ini b/tox.ini index 9d18cc7..4512907 100644 --- a/tox.ini +++ b/tox.ini @@ -1,30 +1,30 @@ # content of: tox.ini , put in same dir as setup.py [tox] -envlist = py27-django{111,22},py36-django{111,22} +# celery5.2はPython3.7以降に対応しているため、Python3.6のテストではcelery 5.1までを使用する +envlist = py36-django{22,32}-celery{42,51},py39-django{22,32}-celery{51,52} [testenv] basepython = - py27: python2.7 py36: python3.6 + py39: python3.9 deps = six - django111: Django>=1.11,<2.0 - django111: celery>=4.2,<4.3 django22: Django~=2.2.12 - django22: celery>=4.2,<4.3 - mock>=0.7.2 + django32: Django~=3.2.1 + celery42: celery>=4.2,<4.3 + celery51: celery>=5.0,<5.2 + celery52: celery>=5.2,<5.3 commands=python setup.py test -[travis] -os = - linux: py27-django111, py36-django{111,22} +# tox-gh-actionsパッケージの設定 +[gh-actions] python = - 2.7: py27 - 3.6: py36 + 3.6: py36 + 3.9: py39 -[travis:env] +[gh-actions:env] DJANGO = - 1.11: django111 - 2.2: django22 + 2.2: django22 + 3.2: django32