Browse Source

Merge pull request #7717 from FelixSchwarz/borg12-py312

add `utcnow()` helper function to avoid `datetime.utcnow()`
TW 1 year ago
parent
commit
c79e970b78

+ 6 - 5
src/borg/archive.py

@@ -6,7 +6,7 @@ import sys
 import time
 import time
 from collections import OrderedDict
 from collections import OrderedDict
 from contextlib import contextmanager
 from contextlib import contextmanager
-from datetime import datetime, timezone, timedelta
+from datetime import timezone, timedelta
 from functools import partial
 from functools import partial
 from getpass import getuser
 from getpass import getuser
 from io import BytesIO
 from io import BytesIO
@@ -42,6 +42,7 @@ from .helpers import os_open, flags_normal, flags_dir
 from .helpers import os_stat
 from .helpers import os_stat
 from .helpers import msgpack
 from .helpers import msgpack
 from .helpers import sig_int
 from .helpers import sig_int
+from .helpers import utcnow
 from .lrucache import LRUCache
 from .lrucache import LRUCache
 from .patterns import PathPrefixPattern, FnmatchPattern, IECommand
 from .patterns import PathPrefixPattern, FnmatchPattern, IECommand
 from .item import Item, ArchiveItem, ItemDiff
 from .item import Item, ArchiveItem, ItemDiff
@@ -458,13 +459,13 @@ class Archive:
         self.noxattrs = noxattrs
         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.'
         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:
         if start is None:
-            start = datetime.utcnow()
+            start = utcnow()
             start_monotonic = time.monotonic()
             start_monotonic = time.monotonic()
         self.chunker_params = chunker_params
         self.chunker_params = chunker_params
         self.start = start
         self.start = start
         self.start_monotonic = start_monotonic
         self.start_monotonic = start_monotonic
         if end is None:
         if end is None:
-            end = datetime.utcnow()
+            end = utcnow()
         self.end = end
         self.end = end
         self.consider_part_files = consider_part_files
         self.consider_part_files = consider_part_files
         self.pipeline = DownloadPipeline(self.repository, self.key)
         self.pipeline = DownloadPipeline(self.repository, self.key)
@@ -613,7 +614,7 @@ Utilization of max. archive size: {csize_max:.0%}
         self.items_buffer.flush(flush=True)
         self.items_buffer.flush(flush=True)
         duration = timedelta(seconds=time.monotonic() - self.start_monotonic)
         duration = timedelta(seconds=time.monotonic() - self.start_monotonic)
         if timestamp is None:
         if timestamp is None:
-            end = datetime.utcnow()
+            end = utcnow()
             start = end - duration
             start = end - duration
         else:
         else:
             end = timestamp + duration
             end = timestamp + duration
@@ -2266,7 +2267,7 @@ class ArchiveRecreater:
             target.rename(archive.name)
             target.rename(archive.name)
         if self.stats:
         if self.stats:
             target.start = _start
             target.start = _start
-            target.end = datetime.utcnow()
+            target.end = utcnow()
             log_multi(DASHES,
             log_multi(DASHES,
                       str(target),
                       str(target),
                       DASHES,
                       DASHES,

+ 3 - 3
src/borg/archiver.py

@@ -53,7 +53,7 @@ try:
     from .helpers import format_timedelta, format_file_size, parse_file_size, format_archive
     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 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 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 get_cache_dir, os_stat
     from .helpers import Manifest, AI_HUMAN_SORT_KEYS
     from .helpers import Manifest, AI_HUMAN_SORT_KEYS
     from .helpers import hardlinkable
     from .helpers import hardlinkable
@@ -649,7 +649,7 @@ class Archiver:
         self.noxattrs = args.noxattrs
         self.noxattrs = args.noxattrs
         self.exclude_nodump = args.exclude_nodump
         self.exclude_nodump = args.exclude_nodump
         dry_run = args.dry_run
         dry_run = args.dry_run
-        t0 = datetime.utcnow()
+        t0 = utcnow()
         t0_monotonic = time.monotonic()
         t0_monotonic = time.monotonic()
         logger.info('Creating archive at "%s"' % args.location.processed)
         logger.info('Creating archive at "%s"' % args.location.processed)
         if not dry_run:
         if not dry_run:
@@ -1746,7 +1746,7 @@ class Archiver:
         return self.exit_code
         return self.exit_code
 
 
     def _import_tar(self, args, repository, manifest, key, cache, tarstream):
     def _import_tar(self, args, repository, manifest, key, cache, tarstream):
-        t0 = datetime.utcnow()
+        t0 = utcnow()
         t0_monotonic = time.monotonic()
         t0_monotonic = time.monotonic()
 
 
         archive = Archive(repository, key, manifest, args.location.archive, cache=cache,
         archive = Archive(repository, key, manifest, args.location.archive, cache=cache,

+ 3 - 3
src/borg/helpers/manifest.py

@@ -13,7 +13,7 @@ logger = create_logger()
 
 
 from .datastruct import StableDict
 from .datastruct import StableDict
 from .parseformat import bin_to_hex, safe_encode, safe_decode
 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 .. import shellpattern
 from ..constants import *  # NOQA
 from ..constants import *  # NOQA
 
 
@@ -242,11 +242,11 @@ class Manifest:
             self.config[b'tam_required'] = True
             self.config[b'tam_required'] = True
         # self.timestamp needs to be strictly monotonically increasing. Clocks often are not set correctly
         # self.timestamp needs to be strictly monotonically increasing. Clocks often are not set correctly
         if self.timestamp is None:
         if self.timestamp is None:
-            self.timestamp = datetime.utcnow().strftime(ISO_FORMAT)
+            self.timestamp = utcnow().strftime(ISO_FORMAT)
         else:
         else:
             prev_ts = self.last_timestamp
             prev_ts = self.last_timestamp
             incremented = (prev_ts + timedelta(microseconds=1)).strftime(ISO_FORMAT)
             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())
         # include checks for limits as enforced by limited unpacker (used by load())
         assert len(self.archives) <= MAX_ARCHIVES
         assert len(self.archives) <= MAX_ARCHIVES
         assert all(len(name) <= 255 for name in self.archives)
         assert all(len(name) <= 255 for name in self.archives)

+ 5 - 0
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])
     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):
 def parse_timestamp(timestamp, tzinfo=timezone.utc):
     """Parse a ISO 8601 timestamp string"""
     """Parse a ISO 8601 timestamp string"""
     fmt = ISO_FORMAT if '.' in timestamp else ISO_FORMAT_NO_USECS
     fmt = ISO_FORMAT if '.' in timestamp else ISO_FORMAT_NO_USECS

+ 2 - 2
src/borg/repository.py

@@ -8,7 +8,6 @@ import time
 from binascii import hexlify, unhexlify
 from binascii import hexlify, unhexlify
 from collections import defaultdict
 from collections import defaultdict
 from configparser import ConfigParser
 from configparser import ConfigParser
-from datetime import datetime
 from functools import partial
 from functools import partial
 from itertools import islice
 from itertools import islice
 
 
@@ -21,6 +20,7 @@ from .helpers import bin_to_hex
 from .helpers import secure_erase, safe_unlink
 from .helpers import secure_erase, safe_unlink
 from .helpers import Manifest
 from .helpers import Manifest
 from .helpers import msgpack
 from .helpers import msgpack
+from .helpers import utcnow
 from .locking import Lock, LockError, LockErrorT
 from .locking import Lock, LockError, LockErrorT
 from .logger import create_logger
 from .logger import create_logger
 from .lrucache import LRUCache
 from .lrucache import LRUCache
@@ -634,7 +634,7 @@ class Repository:
         if self.append_only:
         if self.append_only:
             with open(os.path.join(self.path, 'transactions'), 'a') as log:
             with open(os.path.join(self.path, 'transactions'), 'a') as log:
                 print('transaction %d, UTC time %s' % (
                 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
         # Write hints file
         hints_name = 'hints.%d' % transaction_id
         hints_name = 'hints.%d' % transaction_id

+ 3 - 2
src/borg/testsuite/archiver.py

@@ -46,6 +46,7 @@ from ..helpers import bin_to_hex
 from ..helpers import MAX_S
 from ..helpers import MAX_S
 from ..helpers import msgpack
 from ..helpers import msgpack
 from ..helpers import flags_noatime, flags_normal
 from ..helpers import flags_noatime, flags_normal
+from ..helpers import utcnow
 from ..nanorst import RstToTextLazy, rst_to_terminal
 from ..nanorst import RstToTextLazy, rst_to_terminal
 from ..patterns import IECommand, PatternMatcher, parse_pattern
 from ..patterns import IECommand, PatternMatcher, parse_pattern
 from ..item import Item, ItemDiff, chunks_contents_equal
 from ..item import Item, ItemDiff, chunks_contents_equal
@@ -4048,7 +4049,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase):
                 'version': 1,
                 'version': 1,
                 'archives': {},
                 'archives': {},
                 'config': {},
                 'config': {},
-                'timestamp': (datetime.utcnow() + timedelta(days=1)).strftime(ISO_FORMAT),
+                'timestamp': (utcnow() + timedelta(days=1)).strftime(ISO_FORMAT),
             })))
             })))
             repository.commit(compact=False)
             repository.commit(compact=False)
 
 
@@ -4060,7 +4061,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase):
             repository.put(Manifest.MANIFEST_ID, key.encrypt(msgpack.packb({
             repository.put(Manifest.MANIFEST_ID, key.encrypt(msgpack.packb({
                 'version': 1,
                 'version': 1,
                 'archives': {},
                 'archives': {},
-                'timestamp': (datetime.utcnow() + timedelta(days=1)).strftime(ISO_FORMAT),
+                'timestamp': (utcnow() + timedelta(days=1)).strftime(ISO_FORMAT),
             })))
             })))
             repository.commit(compact=False)
             repository.commit(compact=False)