From 690b4fe460b5b619300a43790247b45397c54b7f Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Sun, 13 Aug 2023 02:12:53 +0200 Subject: [PATCH 1/7] Test on 3.12 --- .github/workflows/main.yml | 9 ++++++--- tox.ini | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e0f8f9e..68f65e6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: "actions/checkout@v3" @@ -35,6 +35,7 @@ jobs: with: python-version: "${{ matrix.python-version }}" cache: pip + allow-prereleases: true - name: "Install dependencies" run: | set -xe @@ -53,7 +54,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] arch: ["x86", "x64"] env: @@ -66,6 +67,7 @@ jobs: python-version: "${{ matrix.python-version }}" architecture: "${{ matrix.arch }}" cache: pip + allow-prereleases: true - run: python -VV - run: python -m site @@ -82,7 +84,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: "actions/checkout@v3" @@ -91,6 +93,7 @@ jobs: python-version: "${{ matrix.python-version }}" architecture: "${{ matrix.arch }}" cache: pip + allow-prereleases: true - name: "Install dependencies" run: | set -xe diff --git a/tox.ini b/tox.ini index f082af0..499ed52 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{38,39,310,311}{,-nospeedups},pypy,docs +envlist = py{38,39,310,311,312}{,-nospeedups},pypy,docs [testenv] extras = @@ -31,3 +31,4 @@ python = 3.9: py39 3.10: py310 3.11: py311, docs + 3.12: py312 From 58b2ee3192f4e6f743781539050843c06bce1b26 Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Sun, 13 Aug 2023 02:32:26 +0200 Subject: [PATCH 2/7] Improve diff on test failure --- tests/test_logging_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_logging_compat.py b/tests/test_logging_compat.py index 74f08fa..e35f0ef 100644 --- a/tests/test_logging_compat.py +++ b/tests/test_logging_compat.py @@ -87,6 +87,6 @@ def test_warning_redirections(): finally: redirector.end() - assert len(handler.records) == 1 + assert len(handler.formatted_records) == 1 assert handler.formatted_records[0].startswith("[WARNING] RuntimeWarning: Testing") assert __file_without_pyc__ in handler.records[0].filename From b9621a12703a6ad22d70a2e9548ded33a9d47199 Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Wed, 6 Sep 2023 00:58:34 +0200 Subject: [PATCH 3/7] Ignore utcnow deprecation in redirected_warnings test --- tests/test_logging_compat.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/test_logging_compat.py b/tests/test_logging_compat.py index e35f0ef..f02b16d 100644 --- a/tests/test_logging_compat.py +++ b/tests/test_logging_compat.py @@ -1,4 +1,6 @@ import functools +import re +import warnings from io import StringIO from random import randrange @@ -77,15 +79,16 @@ def test_warning_redirections(): from logbook.compat import redirected_warnings with logbook.TestHandler() as handler: - redirector = redirected_warnings() - redirector.start() - try: - from warnings import resetwarnings, warn - - resetwarnings() - warn(RuntimeWarning("Testing" + str(next(test_warning_redirections_i)))) - finally: - redirector.end() + with redirected_warnings(): + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + re.escape("datetime.utcnow() is deprecated"), + DeprecationWarning, + ) + warnings.warn( + RuntimeWarning(f"Testing {next(test_warning_redirections_i)}") + ) assert len(handler.formatted_records) == 1 assert handler.formatted_records[0].startswith("[WARNING] RuntimeWarning: Testing") From 4e05a5ba325767c490b6729368938e6e69ebc52e Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Wed, 6 Sep 2023 01:33:02 +0200 Subject: [PATCH 4/7] Fix asyncio deprecation warning --- tests/test_asyncio.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_asyncio.py b/tests/test_asyncio.py index d136728..21ae55f 100644 --- a/tests/test_asyncio.py +++ b/tests/test_asyncio.py @@ -16,9 +16,10 @@ async def task(handler, msg): await asyncio.sleep(0) # allow for context switch - asyncio.get_event_loop().run_until_complete( - asyncio.gather(task(h1, "task1"), task(h2, "task2")) - ) + async def main(): + await asyncio.gather(task(h1, "task1"), task(h2, "task2")) + + asyncio.run(main()) assert len(h1.records) == ITERATIONS assert all(["task1" == r.msg for r in h1.records]) From 70d78e8916f45017b2cde176b45a79d7682a1fa5 Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Wed, 6 Sep 2023 23:55:14 +0200 Subject: [PATCH 5/7] Add 3.12 classifier --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index ae7a9d0..96614b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] requires-python = ">=3.8" dynamic = ["version"] From 5273fa2d6af6fb6b611741ee4a1dfc803f9d4a89 Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Fri, 15 Sep 2023 23:35:21 +0200 Subject: [PATCH 6/7] Stop using datetime.utcnow on 3.12+ --- src/logbook/base.py | 11 ++++++++--- src/logbook/handlers.py | 4 ++-- src/logbook/helpers.py | 17 +++++++++++++++-- tests/test_logging_compat.py | 12 +++--------- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/logbook/base.py b/src/logbook/base.py index 1b7759b..470577a 100644 --- a/src/logbook/base.py +++ b/src/logbook/base.py @@ -16,7 +16,12 @@ from weakref import ref as weakref from logbook.concurrency import greenlet_get_ident, thread_get_ident, thread_get_name -from logbook.helpers import cached_property, parse_iso8601, to_safe_json +from logbook.helpers import ( + cached_property, + datetime_utcnow, + parse_iso8601, + to_safe_json, +) _has_speedups = False try: @@ -39,7 +44,7 @@ group_reflected_property, ) -_datetime_factory = datetime.utcnow +_datetime_factory = datetime_utcnow def set_datetime_format(datetime_format): @@ -94,7 +99,7 @@ def utc_tz(): """ global _datetime_factory if datetime_format == "utc": - _datetime_factory = datetime.utcnow + _datetime_factory = datetime_utcnow elif datetime_format == "local": _datetime_factory = datetime.now elif callable(datetime_format): diff --git a/src/logbook/handlers.py b/src/logbook/handlers.py index 7a78a02..287e3fc 100644 --- a/src/logbook/handlers.py +++ b/src/logbook/handlers.py @@ -42,7 +42,7 @@ lookup_level, ) from logbook.concurrency import new_fine_grained_lock -from logbook.helpers import rename +from logbook.helpers import datetime_utcnow, rename DEFAULT_FORMAT_STRING = ( "[{record.time:%Y-%m-%d %H:%M:%S.%f%z}] " @@ -506,7 +506,7 @@ def check_delivery(self, record): try: allow_delivery = None suppression_count = old_count = 0 - first_count = now = datetime.utcnow() + first_count = now = datetime_utcnow() if hash in self._record_limits: last_count, suppression_count = self._record_limits[hash] diff --git a/src/logbook/helpers.py b/src/logbook/helpers.py index 9852960..eb58304 100644 --- a/src/logbook/helpers.py +++ b/src/logbook/helpers.py @@ -13,7 +13,7 @@ import re import sys import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone # this regexp also matches incompatible dates like 20070101 because # some libraries (like the python xmlrpclib modules) use this @@ -144,10 +144,23 @@ def _convert(obj): return _convert(data) +if sys.version_info >= (3, 12): + + def datetime_utcnow(): + """datetime.utcnow() but doesn't emit a deprecation warning. + + Will be fixed by https://github.com/getlogbook/logbook/issues/353 + """ + return datetime.now(timezone.utc).replace(tzinfo=None) + +else: + datetime_utcnow = datetime.utcnow + + def format_iso8601(d=None): """Returns a date in iso8601 format.""" if d is None: - d = datetime.utcnow() + d = datetime_utcnow() rv = d.strftime("%Y-%m-%dT%H:%M:%S") if d.microsecond: rv += "." + str(d.microsecond) diff --git a/tests/test_logging_compat.py b/tests/test_logging_compat.py index f02b16d..18cbf09 100644 --- a/tests/test_logging_compat.py +++ b/tests/test_logging_compat.py @@ -80,15 +80,9 @@ def test_warning_redirections(): with logbook.TestHandler() as handler: with redirected_warnings(): - with warnings.catch_warnings(): - warnings.filterwarnings( - "ignore", - re.escape("datetime.utcnow() is deprecated"), - DeprecationWarning, - ) - warnings.warn( - RuntimeWarning(f"Testing {next(test_warning_redirections_i)}") - ) + warnings.warn( + RuntimeWarning(f"Testing {next(test_warning_redirections_i)}") + ) assert len(handler.formatted_records) == 1 assert handler.formatted_records[0].startswith("[WARNING] RuntimeWarning: Testing") From 4eafa1a095e9ea9e5fb5eceb84101c0845698090 Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Sun, 17 Sep 2023 23:22:28 +0200 Subject: [PATCH 7/7] Add to CHANGES --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index f682643..a7274bc 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,7 @@ Unreleased - Dropped support for Python 3.7 - Passing (keyfile, certfile) to MailHandler's `secure` argument is deprecated in favour of passing an ssl.SSLContext. +- Python 3.12 support Version 1.6.0 -------------