ソースを参照

remove custom microformat from stats

i saw the errors in my ways: __format__ is only to customize the
"format mini-language", what comes after ":" in a new string
format. unfortunately, we cannot easily refer to individual fields in
there, short of re-implementing a new formatting language, which seems
silly.

instead, we use properties to extract human-readable versions of the
statistics. more intuitive and certainly a more common pattern than
the exotic __format__().

also add unit tests to prove this all works
Antoine Beaupré 9 年 前
コミット
118ee8679f
2 ファイル変更59 行追加13 行削除
  1. 16 12
      borg/helpers.py
  2. 43 1
      borg/testsuite/helpers.py

+ 16 - 12
borg/helpers.py

@@ -168,22 +168,26 @@ class Statistics:
         return buf
 
     def __str__(self):
-        return format(self, """\
+        return """\
                        Original size      Compressed size    Deduplicated size
-%-15s {0.osize:>20s} {0.csize:>20s} {0.usize:>20s}""")
+%-15s {0.osize_fmt:>20s} {0.csize_fmt:>20s} {0.usize_fmt:>20s}""".format(self)
 
-    def __format__(self, format_spec):
-        sizes = ['osize', 'csize', 'usize']
-        others = ['nfiles']
-        fields = list(map(format_file_size, [ getattr(self, x) for x in sizes ]))
-        fields += [ getattr(self, x) for x in others ]
-        FormattedStats = namedtuple('FormattedStats', sizes + others)
-        return format_spec.format(FormattedStats(*fields))
+    @property
+    def osize_fmt(self):
+        return format_file_size(self.osize)
 
-    def show_progress(self, item=None, final=False):
+    @property
+    def usize_fmt(self):
+        return format_file_size(self.usize)
+
+    @property
+    def csize_fmt(self):
+        return format_file_size(self.csize)
+
+    def show_progress(self, item=None, final=False, stream=None):
         (columns, lines) = get_terminal_size((80, 24))
         if not final:
-            msg = format(self, '{0.osize} O {0.csize} C {0.usize} D {0.nfiles} N ')
+            msg = '{0.osize_fmt} O {0.csize_fmt} C {0.usize_fmt} D {0.nfiles} N '.format(self)
             path = remove_surrogates(item[b'path']) if item else ''
             space = columns - len(msg)
             if space < len('...') + len(path):
@@ -191,7 +195,7 @@ class Statistics:
             msg += "{0:<{space}}".format(path, space=space)
         else:
             msg = ' ' * columns
-        print(msg, file=sys.stderr, end=final and "\n" or "\r")
+        print(msg, file=stream or sys.stderr, end=final and "\n" or "\r")
 
 
 def get_keys_dir():

+ 43 - 1
borg/testsuite/helpers.py

@@ -1,6 +1,9 @@
+import pdb
+
 import hashlib
 from time import mktime, strptime
 from datetime import datetime, timezone, timedelta
+from io import StringIO
 import os
 
 import pytest
@@ -8,7 +11,7 @@ import sys
 import msgpack
 
 from ..helpers import adjust_patterns, exclude_path, Location, format_timedelta, IncludePattern, ExcludePattern, make_path_safe, \
-    prune_within, prune_split, get_cache_dir, \
+    prune_within, prune_split, get_cache_dir, Statistics, \
     StableDict, int_to_bigint, bigint_to_int, parse_timestamp, CompressionSpec, ChunkerParams
 from . import BaseTestCase
 
@@ -399,3 +402,42 @@ def test_get_cache_dir():
     # reset old env
     if old_env is not None:
         os.environ['BORG_CACHE_DIR'] = old_env
+
+@pytest.fixture()
+def stats():
+    stats = Statistics()
+    stats.update(10, 10, unique=True)
+    return stats
+
+def test_stats_basic(stats):
+    assert stats.osize == stats.csize == stats.usize == 10
+    stats.update(10, 10, unique=False)
+    assert stats.osize == stats.csize == 20
+    assert stats.usize == 10
+
+def tests_stats_progress(stats, columns = 80):
+    os.environ['COLUMNS'] = str(columns)
+    io = StringIO()
+    stats.show_progress(stream=io)
+    s = '10 B O 10 B C 10 B D 0 N '
+    buf = ' ' * (columns - len(s))
+    assert io.getvalue() == s + buf + "\r"
+
+    io = StringIO()
+    stats.update(10**3, 0, unique=False)
+    stats.show_progress(item={b'path': 'foo'}, final=False, stream=io)
+    s = '1.01 kB O 10 B C 10 B D 0 N foo'
+    buf = ' ' * (columns - len(s))
+    assert io.getvalue() == s + buf + "\r"
+    io = StringIO()
+    stats.show_progress(item={b'path': 'foo'*40}, final=False, stream=io)
+    s = '1.01 kB O 10 B C 10 B D 0 N foofoofoofoofoofoofoofo...oofoofoofoofoofoofoofoofoo'
+    buf = ' ' * (columns - len(s))
+    assert io.getvalue() == s + buf + "\r"
+
+def test_stats_format(stats):
+    assert str(stats) == """\
+                       Original size      Compressed size    Deduplicated size
+%-15s                 10 B                 10 B                 10 B"""
+    s = "{0.osize_fmt}".format(stats)
+    assert s == "10 B"