From 98f547f278a251812c5a3b484f8c5e84707cb217 Mon Sep 17 00:00:00 2001 From: Felix Schwarz Date: Thu, 6 Jul 2023 21:38:31 +0200 Subject: [PATCH] add `utcnow()` helper function to avoid `datetime.utcnow()` `datetime.utcnow()` is deprecated since Python 3.12. This causes additional lines of output and thus breaks the test suite. I was not sure if all borg internals are ready to deal with timezone-aware datetime instances so tried to keep the changes minimal. --- src/borg/archive.py | 11 ++++++----- src/borg/archiver.py | 6 +++--- src/borg/helpers/manifest.py | 6 +++--- src/borg/helpers/time.py | 5 +++++ src/borg/repository.py | 4 ++-- src/borg/testsuite/archiver.py | 5 +++-- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/borg/archive.py b/src/borg/archive.py index 39c8fcd421..9c60b611ac 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -6,7 +6,7 @@ import time from collections import OrderedDict from contextlib import contextmanager -from datetime import datetime, timezone, timedelta +from datetime import timezone, timedelta from functools import partial from getpass import getuser from io import BytesIO @@ -42,6 +42,7 @@ from .helpers import os_stat from .helpers import msgpack from .helpers import sig_int +from .helpers import utcnow from .lrucache import LRUCache from .patterns import PathPrefixPattern, FnmatchPattern, IECommand from .item import Item, ArchiveItem, ItemDiff @@ -458,13 +459,13 @@ def __init__(self, repository, key, manifest, name, cache=None, create=False, self.noxattrs = noxattrs assert (start is None) == (start_monotonic is None), 'Logic error: if start is given, start_monotonic must be given as well and vice versa.' if start is None: - start = datetime.utcnow() + start = utcnow() start_monotonic = time.monotonic() self.chunker_params = chunker_params self.start = start self.start_monotonic = start_monotonic if end is None: - end = datetime.utcnow() + end = utcnow() self.end = end self.consider_part_files = consider_part_files self.pipeline = DownloadPipeline(self.repository, self.key) @@ -613,7 +614,7 @@ def save(self, name=None, comment=None, timestamp=None, stats=None, additional_m self.items_buffer.flush(flush=True) duration = timedelta(seconds=time.monotonic() - self.start_monotonic) if timestamp is None: - end = datetime.utcnow() + end = utcnow() start = end - duration else: end = timestamp + duration @@ -2266,7 +2267,7 @@ def save(self, archive, target, comment=None, replace_original=True): target.rename(archive.name) if self.stats: target.start = _start - target.end = datetime.utcnow() + target.end = utcnow() log_multi(DASHES, str(target), DASHES, diff --git a/src/borg/archiver.py b/src/borg/archiver.py index c990c90f0d..ccd297dc33 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -53,7 +53,7 @@ from .helpers import format_timedelta, format_file_size, parse_file_size, format_archive from .helpers import safe_encode, remove_surrogates, bin_to_hex, prepare_dump_dict, eval_escapes from .helpers import interval, prune_within, prune_split, PRUNING_PATTERNS - from .helpers import timestamp + from .helpers import timestamp, utcnow from .helpers import get_cache_dir, os_stat from .helpers import Manifest, AI_HUMAN_SORT_KEYS from .helpers import hardlinkable @@ -649,7 +649,7 @@ def create_inner(archive, cache, fso): self.noxattrs = args.noxattrs self.exclude_nodump = args.exclude_nodump dry_run = args.dry_run - t0 = datetime.utcnow() + t0 = utcnow() t0_monotonic = time.monotonic() logger.info('Creating archive at "%s"' % args.location.processed) if not dry_run: @@ -1746,7 +1746,7 @@ def do_import_tar(self, args, repository, manifest, key, cache): return self.exit_code def _import_tar(self, args, repository, manifest, key, cache, tarstream): - t0 = datetime.utcnow() + t0 = utcnow() t0_monotonic = time.monotonic() archive = Archive(repository, key, manifest, args.location.archive, cache=cache, diff --git a/src/borg/helpers/manifest.py b/src/borg/helpers/manifest.py index 84871f736f..5b595eacb9 100644 --- a/src/borg/helpers/manifest.py +++ b/src/borg/helpers/manifest.py @@ -13,7 +13,7 @@ from .datastruct import StableDict from .parseformat import bin_to_hex, safe_encode, safe_decode -from .time import parse_timestamp +from .time import parse_timestamp, utcnow from .. import shellpattern from ..constants import * # NOQA @@ -242,11 +242,11 @@ def write(self): self.config[b'tam_required'] = True # self.timestamp needs to be strictly monotonically increasing. Clocks often are not set correctly if self.timestamp is None: - self.timestamp = datetime.utcnow().strftime(ISO_FORMAT) + self.timestamp = utcnow().strftime(ISO_FORMAT) else: prev_ts = self.last_timestamp incremented = (prev_ts + timedelta(microseconds=1)).strftime(ISO_FORMAT) - self.timestamp = max(incremented, datetime.utcnow().strftime(ISO_FORMAT)) + self.timestamp = max(incremented, utcnow().strftime(ISO_FORMAT)) # include checks for limits as enforced by limited unpacker (used by load()) assert len(self.archives) <= MAX_ARCHIVES assert all(len(name) <= 255 for name in self.archives) diff --git a/src/borg/helpers/time.py b/src/borg/helpers/time.py index 8b48076f75..776c290330 100644 --- a/src/borg/helpers/time.py +++ b/src/borg/helpers/time.py @@ -10,6 +10,11 @@ def to_localtime(ts): return datetime(*time.localtime((ts - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds())[:6]) +def utcnow(): + """Returns a naive datetime instance representing the time in the UTC timezone""" + return datetime.now(timezone.utc).replace(tzinfo=None) + + def parse_timestamp(timestamp, tzinfo=timezone.utc): """Parse a ISO 8601 timestamp string""" fmt = ISO_FORMAT if '.' in timestamp else ISO_FORMAT_NO_USECS diff --git a/src/borg/repository.py b/src/borg/repository.py index 0f20d91023..9c0284831a 100644 --- a/src/borg/repository.py +++ b/src/borg/repository.py @@ -8,7 +8,6 @@ from binascii import hexlify, unhexlify from collections import defaultdict from configparser import ConfigParser -from datetime import datetime from functools import partial from itertools import islice @@ -21,6 +20,7 @@ from .helpers import secure_erase, safe_unlink from .helpers import Manifest from .helpers import msgpack +from .helpers import utcnow from .locking import Lock, LockError, LockErrorT from .logger import create_logger from .lrucache import LRUCache @@ -634,7 +634,7 @@ def rename_tmp(file): if self.append_only: with open(os.path.join(self.path, 'transactions'), 'a') as log: print('transaction %d, UTC time %s' % ( - transaction_id, datetime.utcnow().strftime(ISO_FORMAT)), file=log) + transaction_id, utcnow().strftime(ISO_FORMAT)), file=log) # Write hints file hints_name = 'hints.%d' % transaction_id diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 0d0752b5cd..2dc2bf5d3c 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -46,6 +46,7 @@ from ..helpers import MAX_S from ..helpers import msgpack from ..helpers import flags_noatime, flags_normal +from ..helpers import utcnow from ..nanorst import RstToTextLazy, rst_to_terminal from ..patterns import IECommand, PatternMatcher, parse_pattern from ..item import Item, ItemDiff, chunks_contents_equal @@ -4048,7 +4049,7 @@ def spoof_manifest(self, repository): 'version': 1, 'archives': {}, 'config': {}, - 'timestamp': (datetime.utcnow() + timedelta(days=1)).strftime(ISO_FORMAT), + 'timestamp': (utcnow() + timedelta(days=1)).strftime(ISO_FORMAT), }))) repository.commit(compact=False) @@ -4060,7 +4061,7 @@ def test_fresh_init_tam_required(self): repository.put(Manifest.MANIFEST_ID, key.encrypt(msgpack.packb({ 'version': 1, 'archives': {}, - 'timestamp': (datetime.utcnow() + timedelta(days=1)).strftime(ISO_FORMAT), + 'timestamp': (utcnow() + timedelta(days=1)).strftime(ISO_FORMAT), }))) repository.commit(compact=False)