From 11f78fa85b9d857d17d8c2b188604e764f88f840 Mon Sep 17 00:00:00 2001 From: Matti Lamppu Date: Wed, 23 Nov 2022 17:50:32 +0200 Subject: [PATCH] Update django-settings-holder version --- poetry.lock | 61 ++++++++++++++----------- pyproject.toml | 13 +++--- signal_webhooks/settings.py | 5 +-- tests/test_hooks.py | 89 ++++++++++++++++++++++++++++++++++++- 4 files changed, 129 insertions(+), 39 deletions(-) diff --git a/poetry.lock b/poetry.lock index ecb6ee0..28a519f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,10 +38,10 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] -name = "backports.zoneinfo" +name = "backports-zoneinfo" version = "0.2.1" description = "Backport of the standard library zoneinfo module" category = "main" @@ -102,7 +102,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode_backport = ["unicodedata2"] +unicode-backport = ["unicodedata2"] [[package]] name = "click" @@ -178,7 +178,7 @@ optional = false python-versions = "*" [[package]] -name = "Django" +name = "django" version = "4.1.3" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." category = "main" @@ -197,7 +197,7 @@ bcrypt = ["bcrypt"] [[package]] name = "django-settings-holder" -version = "0.0.5" +version = "0.1.0" description = "Object that allows settings to be accessed with attributes." category = "main" optional = false @@ -244,7 +244,7 @@ optional = false python-versions = "*" [[package]] -name = "EditorConfig" +name = "editorconfig" version = "0.12.3" description = "EditorConfig File Locator and Interpreter for Python" category = "dev" @@ -404,7 +404,7 @@ optional = false python-versions = "*" [[package]] -name = "Jinja2" +name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." category = "dev" @@ -430,7 +430,7 @@ editorconfig = ">=0.12.2" six = ">=1.13.0" [[package]] -name = "Markdown" +name = "markdown" version = "3.3.7" description = "Python implementation of Markdown." category = "dev" @@ -444,7 +444,7 @@ importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} testing = ["coverage", "pyyaml"] [[package]] -name = "MarkupSafe" +name = "markupsafe" version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" @@ -633,7 +633,7 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] -name = "Pygments" +name = "pygments" version = "2.13.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" @@ -724,7 +724,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" six = ">=1.5" [[package]] -name = "PyYAML" +name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" category = "dev" @@ -732,7 +732,7 @@ optional = false python-versions = ">=3.6" [[package]] -name = "pyyaml_env_tag" +name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " category = "dev" @@ -758,7 +758,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rfc3986" @@ -881,7 +881,7 @@ optional = false python-versions = "*" [[package]] -name = "types-PyYAML" +name = "types-pyyaml" version = "6.0.12.2" description = "Typing stubs for PyYAML" category = "dev" @@ -960,7 +960,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.8,<4" -content-hash = "790af794ccca212a7c8cd902f78d17512c5db27a73e47183b8f0bbf7a09b333f" +content-hash = "f8b25102c26968ae86d4abde49ca928b6f1e680f0775484406b2f25b53269200" [metadata.files] anyio = [ @@ -975,7 +975,7 @@ attrs = [ {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] -"backports.zoneinfo" = [ +backports-zoneinfo = [ {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, @@ -1171,13 +1171,13 @@ distlib = [ {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, ] -Django = [ +django = [ {file = "Django-4.1.3-py3-none-any.whl", hash = "sha256:6b1de6886cae14c7c44d188f580f8ba8da05750f544c80ae5ad43375ab293cd5"}, {file = "Django-4.1.3.tar.gz", hash = "sha256:678bbfc8604eb246ed54e2063f0765f13b321a50526bdc8cb1f943eda7fa31f1"}, ] django-settings-holder = [ - {file = "django-settings-holder-0.0.5.tar.gz", hash = "sha256:b18a9402ac0ef4097c14fb76ef74d737cb7ac0804e1a6a11b8dbfaf4b3223e9d"}, - {file = "django_settings_holder-0.0.5-py3-none-any.whl", hash = "sha256:044979653e2cad7973498c3338f111b757573b5b795e6643418ec2a3049742f2"}, + {file = "django_settings_holder-0.1.0-py3-none-any.whl", hash = "sha256:807b2f43f9b237da5edd2f427f4179b79ec1d48e5478601cec2ad34f9492dd82"}, + {file = "django_settings_holder-0.1.0.tar.gz", hash = "sha256:af1db14574158df38177526d15c7e9172dfeef78981649f7c3526919f78c6cb1"}, ] django-stubs = [ {file = "django-stubs-1.13.0.tar.gz", hash = "sha256:424fdd1935f859a802365056f9ccf4db12d1d93a5ab3de6d5633dddba0c5fc76"}, @@ -1190,7 +1190,7 @@ django-stubs-ext = [ docopt = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, ] -EditorConfig = [ +editorconfig = [ {file = "EditorConfig-0.12.3-py3-none-any.whl", hash = "sha256:6b0851425aa875b08b16789ee0eeadbd4ab59666e9ebe728e526314c4a2e52c1"}, {file = "EditorConfig-0.12.3.tar.gz", hash = "sha256:57f8ce78afcba15c8b18d46b5170848c88d56fd38f05c2ec60dbbfcb8996e89e"}, ] @@ -1242,18 +1242,18 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] -Jinja2 = [ +jinja2 = [ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] jsbeautifier = [ {file = "jsbeautifier-1.14.7.tar.gz", hash = "sha256:77993254db1ff6f84eb6e1d75e3b6b72cba2ef20813a585b2d81e8e5e3c713c6"}, ] -Markdown = [ +markdown = [ {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, ] -MarkupSafe = [ +markupsafe = [ {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, @@ -1379,7 +1379,7 @@ pycparser = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] -Pygments = [ +pygments = [ {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, ] @@ -1407,7 +1407,7 @@ python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] -PyYAML = [ +pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, @@ -1415,6 +1415,13 @@ PyYAML = [ {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, @@ -1442,7 +1449,7 @@ PyYAML = [ {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] -pyyaml_env_tag = [ +pyyaml-env-tag = [ {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, ] @@ -1494,7 +1501,7 @@ types-pytz = [ {file = "types-pytz-2022.6.0.1.tar.gz", hash = "sha256:d078196374d1277e9f9984d49373ea043cf2c64d5d5c491fbc86c258557bd46f"}, {file = "types_pytz-2022.6.0.1-py3-none-any.whl", hash = "sha256:bea605ce5d5a5d52a8e1afd7656c9b42476e18a0f888de6be91587355313ddf4"}, ] -types-PyYAML = [ +types-pyyaml = [ {file = "types-PyYAML-6.0.12.2.tar.gz", hash = "sha256:6840819871c92deebe6a2067fb800c11b8a063632eb4e3e755914e7ab3604e83"}, {file = "types_PyYAML-6.0.12.2-py3-none-any.whl", hash = "sha256:1e94e80aafee07a7e798addb2a320e32956a373f376655128ae20637adb2655b"}, ] diff --git a/pyproject.toml b/pyproject.toml index 71d1112..6dfa12e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-signal-webhooks" -version = "0.2.0" +version = "0.2.1" description = "Add webhooks to django using signals." authors = [ "Matti Lamppu ", @@ -52,7 +52,7 @@ Django = ">=3.1" asgiref = ">=3.5.0" httpx = ">=0.23.0" cryptography = ">=36.0.0" -django-settings-holder = ">=0.0.4" +django-settings-holder = ">=0.1.0" [tool.poetry.group.test.dependencies] pytest = "7.2.0" @@ -171,10 +171,11 @@ deps = django40: Django>=4.0,<4.1 django41: Django>=4.1,<4.2 - asgiref - httpx - cryptography - django-settings-holder + asgiref>=3.5.0 + httpx>=0.23.0 + cryptography>=36.0.0 + django-settings-holder>=0.1.0 + pytest pytest-django pytest-freezegun diff --git a/signal_webhooks/settings.py b/signal_webhooks/settings.py index 2006044..bdd8fe6 100644 --- a/signal_webhooks/settings.py +++ b/signal_webhooks/settings.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.test.signals import setting_changed from settings_holder import SettingsHolder, reload_settings @@ -74,8 +73,6 @@ class DefaultSettings(NamedTuple): SETTING_NAME: str = "SIGNAL_WEBHOOKS" -USER_SETTINGS: Optional[Dict[str, Any]] = getattr(settings, SETTING_NAME, None) - DEFAULTS = DefaultSettings()._asdict() IMPORT_STRINGS: Set[Union[bytes, str]] = { @@ -110,7 +107,7 @@ def perform_import(self, val: Any, setting: str) -> Any: webhook_settings = WebhookSettingsHolder( - user_settings=USER_SETTINGS, + setting_name=SETTING_NAME, defaults=DEFAULTS, import_strings=IMPORT_STRINGS, removed_settings=REMOVED_SETTINGS, diff --git a/tests/test_hooks.py b/tests/test_hooks.py index 3804d97..c890d13 100644 --- a/tests/test_hooks.py +++ b/tests/test_hooks.py @@ -893,7 +893,7 @@ def test_webhook__single_webhook__disable_hooks_dont_fire(settings): @pytest.mark.django_db(transaction=True) -def test_webhook__single_webhook__keep_reponse(settings): +def test_webhook__single_webhook__keep_response(settings): settings.SIGNAL_WEBHOOKS = { "TASK_HANDLER": "signal_webhooks.handlers.sync_task_handler", "HOOKS": { @@ -932,7 +932,7 @@ def test_webhook__single_webhook__keep_reponse(settings): @pytest.mark.django_db(transaction=True) -def test_webhook__single_webhook__dont_keep_reponse(settings): +def test_webhook__single_webhook__dont_keep_response(settings): settings.SIGNAL_WEBHOOKS = { "TASK_HANDLER": "signal_webhooks.handlers.sync_task_handler", "HOOKS": { @@ -970,6 +970,45 @@ def test_webhook__single_webhook__dont_keep_reponse(settings): assert hook.last_response == "" +@pytest.mark.django_db(transaction=True) +def test_webhook__single_webhook__keep_response__failure(settings): + settings.SIGNAL_WEBHOOKS = { + "TASK_HANDLER": "signal_webhooks.handlers.sync_task_handler", + "HOOKS": { + "django.contrib.auth.models.User": ..., + }, + } + + Webhook.objects.create( + name="foo", + signal=SignalChoices.ALL, + ref="django.contrib.auth.models.User", + endpoint="http://www.example.com/", + keep_last_response=True, + ) + + user = User( + username="x", + email="user@user.com", + is_staff=True, + is_superuser=True, + ) + + resp = Response(400) + resp._content = b"bar" + + with patch("signal_webhooks.handlers.httpx.AsyncClient.post", return_value=resp) as mock: + user.save() + + mock.assert_called_once() + + hook = Webhook.objects.get(name="foo") + + assert hook.last_success is None + assert hook.last_failure is not None + assert hook.last_response == "bar" + + @pytest.mark.django_db(transaction=True) def test_webhook__single_webhook__sending_timeout(settings): settings.SIGNAL_WEBHOOKS = { @@ -1138,6 +1177,52 @@ def test_webhook__multiple_webhooks__failure(settings): assert hook_2.last_failure is not None +@pytest.mark.django_db(transaction=True) +def test_webhook__multiple_webhooks__failure(settings): + settings.SIGNAL_WEBHOOKS = { + "TASK_HANDLER": "signal_webhooks.handlers.sync_task_handler", + "HOOKS": { + "django.contrib.auth.models.User": ..., + }, + } + + Webhook.objects.create( + name="foo", + signal=SignalChoices.ALL, + ref="django.contrib.auth.models.User", + endpoint="http://www.example.com/", + ) + + Webhook.objects.create( + name="bar", + signal=SignalChoices.ALL, + ref="django.contrib.auth.models.User", + endpoint="http://www.example1.com/", + ) + + user = User( + username="x", + email="user@user.com", + is_staff=True, + is_superuser=True, + ) + + with patch("signal_webhooks.handlers.httpx.AsyncClient.post", return_value=Response(400)) as mock: + user.save() + + mock.assert_called() + assert mock.call_count == 2 + + hook_1 = Webhook.objects.get(name="foo") + hook_2 = Webhook.objects.get(name="bar") + + assert hook_1.last_success is None + assert hook_1.last_failure is not None + + assert hook_2.last_success is None + assert hook_2.last_failure is not None + + @pytest.mark.django_db(transaction=True) def test_webhook__multiple_webhooks__sending_timeout(settings): settings.SIGNAL_WEBHOOKS = {