Repository: Stranger6667/postmarker
Pull request #201 (2022-01-14 23:40:18)

Django 4 updates


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index db668a2..2c429e1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,6 @@ on:
       - 'poetry.lock'
       - 'pyproject.toml'
       - 'tox.ini'
-      - 'mypy.ini'
   push:
     branches:
       - master
@@ -21,22 +20,22 @@ on:
 jobs:
   pre-commit:
     name: Generic pre-commit checks
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     steps:
-      - uses: actions/checkout@v1
+      - uses: actions/checkout@v2
         with:
           fetch-depth: 1
 
-      - uses: actions/setup-python@v1
+      - uses: actions/setup-python@v2
         with:
-          python-version: 3.7
+          python-version: 3.9
 
       - run: pip install pre-commit
-      - run: SKIP=pylint,mypy pre-commit run --all-files
+      - run: SKIP=pylint pre-commit run --all-files
 
   pylint:
     name: Pylint
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@v2
         with:
@@ -44,7 +43,7 @@ jobs:
 
       - uses: actions/setup-python@v2
         with:
-          python-version: 3.7
+          python-version: 3.9
 
       - run: pip install pre-commit
       - run: pre-commit run pylint --all-files
@@ -52,13 +51,8 @@ jobs:
   tests:
     strategy:
       matrix:
-        os: [ubuntu-latest, windows-latest]
-        python: [3.6, 3.7, 3.8, 3.9.0-rc.1, pypy3]
-        exclude:
-          # pytest bug on PyPy3
-          # https://github.com/Stranger6667/postmarker/pull/187/checks?check_run_id=1046220597
-          - os: windows-latest
-            python: pypy3
+        os: [ubuntu-20.04, windows-latest]
+        python: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.7", "pypy-3.8"]
 
     name: ${{ matrix.os }}/tests_${{ matrix.python }}
     runs-on: ${{ matrix.os }}
@@ -83,9 +77,7 @@ jobs:
       - run: coverage xml -i
 
       - name: Upload coverage to Codecov
-        uses: codecov/codecov-action@v1.0.7
+        uses: codecov/codecov-action@v2.1.0
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
           file: ./coverage.xml
-          flags: unittests
           name: codecov-py${{ matrix.python }}
diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml
index d3cd295..72a6add 100644
--- a/.github/workflows/commit.yml
+++ b/.github/workflows/commit.yml
@@ -10,7 +10,7 @@ on:
 jobs:
   commitsar:
     name: Verify commit messages
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     steps:
       - name: Check out code
         uses: actions/checkout@v1
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5096dc5..9985536 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -6,14 +6,13 @@ on:
 
 jobs:
   build-n-publish:
-    name: Build and publish Python 🐍distributions 📦 to PyPI
-    runs-on: ubuntu-18.04
+    name: Build and publish Python 🐍 distributions 📦 to PyPI
+    runs-on: ubuntu-20.04
     steps:
-    - uses: actions/checkout@master
-    - name: Set up Python 3.7
-      uses: actions/setup-python@v1
+    - uses: actions/checkout@v2
+    - uses: actions/setup-python@v2
       with:
-        python-version: 3.7
+        python-version: 3.9
     - name: Install tox
       run: >-
         python -m
@@ -24,16 +23,16 @@ jobs:
       run: >-
         python -m tox -e build
     - name: Publish distribution 📦 to PyPI
-      uses: pypa/gh-action-pypi-publish@master
+      uses: pypa/gh-action-pypi-publish@v1.5.0
       with:
         password: ${{ secrets.PYPI_TOKEN }}
 
   release-notes:
     name: Release Notes
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     steps:
     - name: Check out code
-      uses: actions/checkout@v1
+      uses: actions/checkout@v2
 
     - name: Release Notary Action
       uses: docker://outillage/release-notary
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 332d897..7ae8371 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,9 +1,9 @@
 default_language_version:
-  python: python3.7
+  python: python3.9
 
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v3.4.0
+    rev: v4.1.0
     hooks:
       - id: check-yaml
       - id: end-of-file-fixer
@@ -15,17 +15,17 @@ repos:
       - id: check-merge-conflict
 
   - repo: https://github.com/jorisroovers/gitlint
-    rev: v0.15.1
+    rev: v0.17.0
     hooks:
       - id: gitlint
 
   - repo: https://github.com/adrienverge/yamllint
-    rev: v1.26.1
+    rev: v1.26.3
     hooks:
       - id: yamllint
 
   - repo: https://github.com/PyCQA/pydocstyle
-    rev: 6.0.0
+    rev: 6.1.1
     hooks:
       - id: pydocstyle
 
@@ -35,7 +35,7 @@ repos:
       - id: relint
 
   - repo: https://github.com/ambv/black
-    rev: 21.5b1
+    rev: 21.12b0
     hooks:
       - id: black
         types: [python]
@@ -46,13 +46,13 @@ repos:
       - id: seed-isort-config
 
   - repo: https://github.com/pre-commit/mirrors-isort
-    rev: v5.8.0
+    rev: v5.10.1
     hooks:
       - id: isort
         additional_dependencies: ["isort[pyproject]"]
 
   - repo: https://github.com/pre-commit/mirrors-pylint
-    rev: v3.0.0a3
+    rev: v3.0.0a4
     hooks:
       - id: pylint
         additional_dependencies: ["isort[pyproject]"]
diff --git a/README.rst b/README.rst
index 422564a..85dc9ab 100644
--- a/README.rst
+++ b/README.rst
@@ -90,12 +90,12 @@ Or you can look at the docs/ directory in the repository.
 Python support
 ==============
 
-Postmarker supports Python 3.6 - 3.9 and PyPy3.
+Postmarker supports CPython 3.6 - 3.10 and PyPy 3.7 & 3.8.
 
 Thanks
 ======
 
-Many thanks to `Shmele <https://github.com/butorov>`_ and `lobziik <https://github.com/lobziik>`_ for their reviews and advices :)
+Many thanks to `Shmele <https://github.com/butorov>`_ and `lobziik <https://github.com/lobziik>`_ for their reviews and advice :)
 
 .. |Build| image:: https://github.com/Stranger6667/postmarker/workflows/build/badge.svg
    :target: https://github.com/Stranger6667/postmarker/actions
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 4f5157b..cd8fa9e 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -6,6 +6,16 @@ Changelog
 `Unreleased`_
 -------------
 
+Added
+~~~~~
+
+- Python 3.10 support
+
+Removed
+~~~~~~~
+
+- Deprecated ``yield_fixture`` usage in postmarker's pytest plugin.
+
 `0.18.2`_ - 2021-06-03
 ----------------------
 
diff --git a/setup.py b/setup.py
index 6806dfa..ab6790f 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@ setup(
     packages=find_packages(where="src"),
     package_dir={"": "src"},
     classifiers=[
-        "Development Status :: 4 - Beta",
+        "Development Status :: 5 - Production/Stable",
         "Environment :: Console",
         "Intended Audience :: Developers",
         "Operating System :: OS Independent",
@@ -35,6 +35,7 @@ setup(
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
         "Programming Language :: Python :: Implementation :: CPython",
         "Programming Language :: Python :: Implementation :: PyPy",
         "Topic :: Communications :: Email",
diff --git a/src/postmarker/django/backend.py b/src/postmarker/django/backend.py
index 2fa1003..e38086d 100644
--- a/src/postmarker/django/backend.py
+++ b/src/postmarker/django/backend.py
@@ -2,7 +2,7 @@ from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured
 from django.core.mail import EmailMessage, EmailMultiAlternatives
 from django.core.mail.backends.base import BaseEmailBackend
-from django.utils.encoding import force_text
+from django.utils.encoding import force_str
 from django.utils.functional import partition
 
 from ..core import TEST_TOKEN, PostmarkClient
@@ -82,7 +82,7 @@ class EmailBackend(BaseEmailBackend):
         instance.metadata = getattr(message, "metadata", None)
         instance.message_stream = getattr(message, "message_stream", None)
         if message.bcc:
-            instance["Bcc"] = ", ".join(map(force_text, message.bcc))
+            instance["Bcc"] = ", ".join(map(force_str, message.bcc))
         return instance
 
 
diff --git a/src/postmarker/django/signals.py b/src/postmarker/django/signals.py
index e760b91..ebd5b6c 100644
--- a/src/postmarker/django/signals.py
+++ b/src/postmarker/django/signals.py
@@ -1,5 +1,5 @@
 from django.dispatch import Signal
 
-pre_send = Signal(providing_args=["messages"])
-post_send = Signal(providing_args=["messages", "response"])
-on_exception = Signal(providing_args=["raw_messages", "exception"])
+pre_send = Signal()
+post_send = Signal()
+on_exception = Signal()
diff --git a/tox.ini b/tox.ini
index 1727f61..63ea22d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 isolated_build = true
-envlist = py{35,36,37,38,39,py3},coverage-report
+envlist = py{36,37,38,39,310,py37,py38},coverage-report
 
 [testenv]
 passenv =
@@ -8,14 +8,14 @@ passenv =
     ACCOUNT_TOKEN
 deps =
     requests
-    pytest<3.3
-    pytest-django<3.0.0
-    pytest-tornado<0.6
+    pytest
+    pytest-django
+    pytest-tornado
     coverage
     betamax
     betamax_serializers
-    tornado>4.0.0,<5.0
-    Django>=2.1.0,<2.2.0
+    tornado
+    Django==2.2
 commands =
     coverage run --source postmarker -m pytest --ds test.django.settings {posargs:test}
 
@@ -33,12 +33,12 @@ description = Report coverage over all measured test runs.
 basepython = python3.7
 deps = coverage
 skip_install = true
-depends = py{35,36,37,38,39}
+depends = py{36,37,38,39,310}
 commands =
     coverage combine
     coverage report
     coverage xml -i {posargs:}
 
 [testenv:build]
-deps = pep517
-commands = python -m pep517.build --source . --binary --out-dir dist/
+deps = build
+commands = python -m build


Test patch:
diff --git a/src/postmarker/pytest.py b/src/postmarker/pytest.py
index 2ab6a53..05ff7da 100644
--- a/src/postmarker/pytest.py
+++ b/src/postmarker/pytest.py
@@ -5,7 +5,7 @@ import pytest
 from .core import PostmarkClient, requests
 
 
-@pytest.yield_fixture
+@pytest.fixture
 def postmark_request():
     """Mocks network requests to Postmark API."""
     with patch("postmarker.core.requests.Session.request", wraps=requests.Session().request) as patched:
@@ -13,7 +13,7 @@ def postmark_request():
             yield patched
 
 
-@pytest.yield_fixture
+@pytest.fixture
 def postmark_client(postmark_request):  # pylint: disable=redefined-outer-name
     client = PostmarkClient(server_token="SERVER_TOKEN", account_token="ACCOUNT_TOKEN")
     client.mock = postmark_request
diff --git a/test/conftest.py b/test/conftest.py
index 2d2f0ea..1007a9e 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -35,7 +35,7 @@ def pytest_unconfigure(config):
         )
 
 
-@pytest.yield_fixture(autouse=True, scope="module")
+@pytest.fixture(autouse=True, scope="module")
 def betamax_recorder(request, postmark):
     """Module level Betamax recorder."""
     if request.config.getoption("--record"):
@@ -72,22 +72,22 @@ def postmark(server_token, account_token):
     return PostmarkClient(server_token=server_token, account_token=account_token)
 
 
-@pytest.fixture(scope="session")
+@pytest.fixture(scope="module")
 def bounce(postmark):
     return postmark.bounces.get(723626745)
 
 
-@pytest.fixture(scope="session")
+@pytest.fixture(scope="module")
 def server(postmark):
     return postmark.server.get()
 
 
-@pytest.fixture()
+@pytest.fixture
 def email(postmark):
     return postmark.emails.Email(From="sender@example.com", To="receiver@example.com", TextBody="text")
 
 
-@pytest.fixture()
+@pytest.fixture
 def email_template(postmark):
     return postmark.emails.EmailTemplate(
         From="sender@example.com", To="receiver@example.com", TemplateId=983381, TemplateModel={}
@@ -104,17 +104,17 @@ def email_template_batch(postmark, email):
     return postmark.emails.EmailTemplateBatch(email)
 
 
-@pytest.fixture(scope="session")
+@pytest.fixture(scope="module")
 def template(postmark):
     return postmark.templates.get(983381)
 
 
-@pytest.fixture(scope="session")
+@pytest.fixture(scope="module")
 def domain(postmark):
     return postmark.domains.get(64054)
 
 
-@pytest.fixture(scope="session")
+@pytest.fixture(scope="module")
 def outbound_message(postmark):
     return postmark.messages.outbound.all(count=1)[0]
 
diff --git a/test/django/test_backend.py b/test/django/test_backend.py
index fa104f6..8f98fdd 100644
--- a/test/django/test_backend.py
+++ b/test/django/test_backend.py
@@ -63,9 +63,7 @@ def test_send_mail(postmark_request, settings):
     (
         ("bcc", "Bcc"),
         ("cc", "Cc"),
-        pytest.mark.skipif(VERSION[:2] < (1, 7), reason="Django < 1.7 doesn't support `reply_to`")(
-            ("reply_to", "ReplyTo")
-        ),
+        ("reply_to", "ReplyTo"),
     ),
 )
 def test_reply_to_cc_bcc(postmark_request, kwarg, key):
@@ -252,10 +250,6 @@ def test_headers_encoding(postmark_request):
     assert request["To"] == ", ".join(kwargs["recipient_list"])
 
 
-@pytest.mark.skipif(
-    VERSION[:2] < (1, 7),
-    reason="Django < 1.7 does not support `html_message` argument in `send_mail` function.",
-)
 @pytest.mark.parametrize(
     "html_message",
     (
@@ -354,7 +348,6 @@ def test_extra_options(settings, postmark_request):
     )
 
 
-@pytest.mark.skipif(VERSION[:2] < (1, 8), reason="Context manager protocol was added in Django 1.8")
 def test_context_manager(postmark_request):
     with mail.get_connection() as connection:
         send_with_connection(connection)
@@ -378,7 +371,6 @@ def test_context_manager(postmark_request):
     )
 
 
-@pytest.mark.skipif(VERSION[:2] < (1, 8), reason="Context manager protocol was added in Django 1.8")
 class TestExceptions:
     @pytest.fixture(autouse=True)
     def setup(self, postmark_request):
@@ -394,7 +386,6 @@ class TestExceptions:
                 send_with_connection(connection)
 
 
-@pytest.mark.skipif(VERSION[:2] < (1, 8), reason="Context manager protocol was added in Django 1.8")
 def test_close_closed_connection():
     with mail.get_connection() as connection:
         connection.close()
diff --git a/test/test_core.py b/test/test_core.py
index 3878781..4d77dfc 100644
--- a/test/test_core.py
+++ b/test/test_core.py
@@ -66,5 +66,5 @@ def test_malformed_request(postmark, postmark_request):
     postmark_request.return_value = Response()
     postmark_request.return_value.status_code = 500
     postmark_request.return_value._content = b"Server Error"
-    with pytest.raises(HTTPError, matches="Server Error"):
+    with pytest.raises(HTTPError, match="Server Error"):
         postmark.call("GET", "endpoint")
diff --git a/test/tornado/test_handlers.py b/test/tornado/test_handlers.py
index e896996..349f1fd 100644
--- a/test/tornado/test_handlers.py
+++ b/test/tornado/test_handlers.py
@@ -41,10 +41,10 @@ class TestPostmarkMixin:
         self.assert_response(url, expected)
 
     def test_reuse_client(self):
-        self.set_postmark_response("")
+        self.set_postmark_response(b"")
         self.assert_response("/reuse/", b"True")
 
     def test_default_options(self):
         """Check if default values were used to initialize postmark client."""
-        self.set_postmark_response("")
+        self.set_postmark_response(b"")
         self.assert_response("/max_retries/", b"0")