| 
					
				 | 
			
			
				@@ -2,10 +2,9 @@ import stat 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from collections import namedtuple 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .constants import ITEM_KEYS, ARCHIVE_KEYS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from .helpers import safe_encode, safe_decode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .helpers import StableDict 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .helpers import format_file_size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from .helpers.msgpack import timestamp_to_int, int_to_timestamp 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .helpers.msgpack import timestamp_to_int, int_to_timestamp, Timestamp 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 cdef extern from "_item.c": 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -16,6 +15,102 @@ cdef extern from "_item.c": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 API_VERSION = '1.2_01' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_key(data, key, *, errors='strict'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """if k is a bytes-typed key, migrate key/value to a str-typed key in dict data""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if isinstance(key, bytes): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        value = data.pop(key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        key = key.decode('utf-8', errors=errors) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        data[key] = value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(key, str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return key 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_str_value(data, key, errors='surrogateescape'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """makes sure that data[key] is a str (decode if it is bytes)""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(key, str)  # fix_key must be called first 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value = data[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value = want_str(value, errors=errors) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data[key] = value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_bytes_value(data, key): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """makes sure that data[key] is bytes (encode if it is str)""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(key, str)  # fix_key must be called first 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value = data[key] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value = want_bytes(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data[key] = value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_list_of_str(v): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """make sure we have a list of str""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, (tuple, list)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [want_str(e) for e in v] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_list_of_bytes(v): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """make sure we have a list of bytes""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, (tuple, list)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [want_bytes(e) for e in v] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_list_of_chunkentries(v): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """make sure we have a list of correct chunkentries""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, (tuple, list)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    chunks = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for ce in v: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert isinstance(ce, (tuple, list)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert len(ce) == 3  # id, size, csize 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert isinstance(ce[1], int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert isinstance(ce[2], int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ce_fixed = [want_bytes(ce[0]), ce[1], ce[2]]  # list! 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        chunks.append(ce_fixed)  # create a list of lists 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return chunks 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_tuple_of_str(v): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """make sure we have a tuple of str""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, (tuple, list)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return tuple(want_str(e) for e in v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_tuple_of_str_and_int(v): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """make sure we have a tuple of str""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, (tuple, list)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    t = tuple(e.decode() if isinstance(e, bytes) else e for e in v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert all(isinstance(e, (str, int)) for e in t), repr(t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return t 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def fix_timestamp(v): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """make sure v is a Timestamp""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if isinstance(v, Timestamp): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # legacy support 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if isinstance(v, bytes):  # was: bigint_to_int() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v = int.from_bytes(v, 'little', signed=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return int_to_timestamp(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def want_bytes(v, *, errors='surrogateescape'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """we know that we want bytes and the value should be bytes""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    # legacy support: it being str can be caused by msgpack unpack decoding old data that was packed with use_bin_type=False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if isinstance(v, str): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v = v.encode('utf-8', errors=errors) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, bytes), f'not a bytes object, but {v!r}' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+def want_str(v, *, errors='surrogateescape'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """we know that we want str and the value should be str""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if isinstance(v, bytes): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v = v.decode('utf-8', errors=errors) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert isinstance(v, str), f'not a str object, but {v!r}' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class PropDict: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Manage a dictionary via properties. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -112,6 +207,8 @@ class PropDict: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 raise AttributeError(attr_error_msg) from None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if decode is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 value = decode(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if not isinstance(value, value_type): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                raise TypeError(type_error_msg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         def _set(self, value): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -139,14 +236,9 @@ class Item(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Items are created either from msgpack unpacker output, from another dict, from kwargs or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     built step-by-step by setting attributes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    msgpack gives us a dict with bytes-typed keys, just give it to Item(internal_dict=d) and use item.key_name later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    msgpack gives us byte-typed values for stuff that should be str, we automatically decode when getting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    such a property and encode when setting it. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    msgpack unpacker gives us a dict, just give it to Item(internal_dict=d) and use item.key_name later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     If an Item shall be serialized, give as_dict() method output to msgpack packer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    A bug in Attic up to and including release 0.13 added a (meaningless) 'acl' key to every item. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    We must never re-use this key. See test_attic013_acl_bug for details. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     VALID_KEYS = ITEM_KEYS | {'deleted', 'nlink', }  # str-typed keys 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -155,10 +247,10 @@ class Item(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # properties statically defined, so that IDEs can know their names: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    path = PropDict._make_property('path', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    source = PropDict._make_property('source', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    user = PropDict._make_property('user', (str, type(None)), 'surrogate-escaped str or None', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    group = PropDict._make_property('group', (str, type(None)), 'surrogate-escaped str or None', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path = PropDict._make_property('path', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    source = PropDict._make_property('source', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    user = PropDict._make_property('user', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    group = PropDict._make_property('group', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     acl_access = PropDict._make_property('acl_access', bytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     acl_default = PropDict._make_property('acl_default', bytes) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -177,14 +269,13 @@ class Item(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     birthtime = PropDict._make_property('birthtime', int, 'int (ns)', encode=int_to_timestamp, decode=timestamp_to_int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # size is only present for items with a chunk list and then it is sum(chunk_sizes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # compatibility note: this is a new feature, in old archives size will be missing. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     size = PropDict._make_property('size', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     hlid = PropDict._make_property('hlid', bytes)  # hard link id: same value means same hard link. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     hardlink_master = PropDict._make_property('hardlink_master', bool)  # legacy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    chunks = PropDict._make_property('chunks', (list, type(None)), 'list or None') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    chunks_healthy = PropDict._make_property('chunks_healthy', (list, type(None)), 'list or None') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    chunks = PropDict._make_property('chunks', list, 'list') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    chunks_healthy = PropDict._make_property('chunks_healthy', list, 'list') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     xattrs = PropDict._make_property('xattrs', StableDict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -193,12 +284,10 @@ class Item(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     part = PropDict._make_property('part', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def get_size(self, hardlink_masters=None, memorize=False, compressed=False, from_chunks=False, consider_ids=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def get_size(self, memorize=False, compressed=False, from_chunks=False, consider_ids=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         Determine the (uncompressed or compressed) size of this item. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :param hardlink_masters: If given, the size of hardlink slaves is computed via the hardlink master's chunk list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        otherwise size will be returned as 0. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         :param memorize: Whether the computed size value will be stored into the item. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         :param compressed: Whether the compressed or uncompressed size will be returned. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         :param from_chunks: If true, size is computed from chunks even if a precomputed value is available. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -218,31 +307,14 @@ class Item(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # no precomputed (c)size value available, compute it: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 chunks = getattr(self, 'chunks') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                having_chunks = True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             except AttributeError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                having_chunks = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # this item has no (own) chunks list, but if this is a hardlink slave 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # and we know the master, we can still compute the size. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if hardlink_masters is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    chunks = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        master = getattr(self, 'source') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    except AttributeError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        # not a hardlink slave, likely a directory or special file w/o chunks 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        chunks = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        # hardlink slave, try to fetch hardlink master's chunks list 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        # todo: put precomputed size into hardlink_masters' values and use it, if present 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        chunks, _ = hardlink_masters.get(master, (None, None)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if chunks is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if consider_ids is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 size = sum(getattr(ChunkListEntry(*chunk), attr) for chunk in chunks if chunk.id in consider_ids) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 size = sum(getattr(ChunkListEntry(*chunk), attr) for chunk in chunks) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # if requested, memorize the precomputed (c)size for items that have an own chunks list: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if memorize and having_chunks: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if memorize: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 setattr(self, attr, size) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -290,6 +362,31 @@ class Item(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         except AttributeError: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def update_internal(self, d): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # legacy support for migration (data from old msgpacks comes in as bytes always, but sometimes we want str), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # also need to fix old timestamp data types. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for k, v in list(d.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            k = fix_key(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('path', 'source', 'user', 'group'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_str_value(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('chunks', 'chunks_healthy'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_list_of_chunkentries(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('atime', 'ctime', 'mtime', 'birthtime'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_timestamp(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('acl_access', 'acl_default', 'acl_extended', 'acl_nfs4'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_bytes_value(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'xattrs': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if not isinstance(v, StableDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v = StableDict(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v_new = StableDict() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for xk, xv in list(v.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    xk = want_bytes(xk) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    # old borg used to store None instead of a b'' value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    xv = b'' if xv is None else want_bytes(xv) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v_new[xk] = xv 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = v_new  # xattrs is a StableDict(bytes keys -> bytes values) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._dict[k] = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class EncryptedKey(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -298,18 +395,18 @@ class EncryptedKey(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     A EncryptedKey is created either from msgpack unpacker output, from another dict, from kwargs or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     built step-by-step by setting attributes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    msgpack gives us a dict with bytes-typed keys, just give it to EncryptedKey(d) and use enc_key.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    msgpack unpacker gives us a dict, just give it to EncryptedKey(d) and use enc_key.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     If a EncryptedKey shall be serialized, give as_dict() method output to msgpack packer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    VALID_KEYS = { 'version', 'algorithm', 'iterations', 'salt', 'hash', 'data', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                   'argon2_time_cost', 'argon2_memory_cost', 'argon2_parallelism', 'argon2_type' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    VALID_KEYS = {'version', 'algorithm', 'iterations', 'salt', 'hash', 'data', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  'argon2_time_cost', 'argon2_memory_cost', 'argon2_parallelism', 'argon2_type'} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     __slots__ = ("_dict", )  # avoid setting attributes not supported by properties 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     version = PropDict._make_property('version', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    algorithm = PropDict._make_property('algorithm', str, encode=str.encode, decode=bytes.decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    algorithm = PropDict._make_property('algorithm', str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     iterations = PropDict._make_property('iterations', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     salt = PropDict._make_property('salt', bytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     hash = PropDict._make_property('hash', bytes) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -317,7 +414,19 @@ class EncryptedKey(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     argon2_time_cost = PropDict._make_property('argon2_time_cost', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     argon2_memory_cost = PropDict._make_property('argon2_memory_cost', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     argon2_parallelism = PropDict._make_property('argon2_parallelism', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    argon2_type = PropDict._make_property('argon2_type', str, encode=str.encode, decode=bytes.decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    argon2_type = PropDict._make_property('argon2_type', str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def update_internal(self, d): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # legacy support for migration (data from old msgpacks comes in as bytes always, but sometimes we want str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for k, v in list(d.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            k = fix_key(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'version': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                assert isinstance(v, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('algorithm', 'argon2_type'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_str_value(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('salt', 'hash', 'data'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_bytes_value(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._dict[k] = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class Key(PropDict): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -327,7 +436,7 @@ class Key(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     A Key is created either from msgpack unpacker output, from another dict, from kwargs or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     built step-by-step by setting attributes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    msgpack gives us a dict with bytes-typed keys, just give it to Key(d) and use key.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    msgpack unpacker gives us a dict, just give it to Key(d) and use key.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     If a Key shall be serialized, give as_dict() method output to msgpack packer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -344,17 +453,15 @@ class Key(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     chunk_seed = PropDict._make_property('chunk_seed', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     tam_required = PropDict._make_property('tam_required', bool) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-def tuple_encode(t): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    """encode a tuple that might contain str items""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # we have str, but want to give bytes to msgpack.pack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return tuple(safe_encode(e) if isinstance(e, str) else e for e in t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-def tuple_decode(t): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    """decode a tuple that might contain bytes items""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    # we get bytes objects from msgpack.unpack, but want str 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return tuple(safe_decode(e) if isinstance(e, bytes) else e for e in t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def update_internal(self, d): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # legacy support for migration (data from old msgpacks comes in as bytes always, but sometimes we want str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for k, v in list(d.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            k = fix_key(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'version': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                assert isinstance(v, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('repository_id', 'enc_key', 'enc_hmac_key', 'id_key'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_bytes_value(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._dict[k] = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class ArchiveItem(PropDict): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -364,7 +471,7 @@ class ArchiveItem(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     An ArchiveItem is created either from msgpack unpacker output, from another dict, from kwargs or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     built step-by-step by setting attributes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    msgpack gives us a dict with bytes-typed keys, just give it to ArchiveItem(d) and use arch.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    msgpack unpacker gives us a dict, just give it to ArchiveItem(d) and use arch.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     If a ArchiveItem shall be serialized, give as_dict() method output to msgpack packer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -374,15 +481,15 @@ class ArchiveItem(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     __slots__ = ("_dict", )  # avoid setting attributes not supported by properties 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     version = PropDict._make_property('version', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    name = PropDict._make_property('name', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name = PropDict._make_property('name', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     items = PropDict._make_property('items', list) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     cmdline = PropDict._make_property('cmdline', list)  # list of s-e-str 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    hostname = PropDict._make_property('hostname', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    username = PropDict._make_property('username', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    time = PropDict._make_property('time', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    time_end = PropDict._make_property('time_end', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    comment = PropDict._make_property('comment', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    chunker_params = PropDict._make_property('chunker_params', tuple, 'chunker-params tuple', encode=tuple_encode, decode=tuple_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hostname = PropDict._make_property('hostname', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    username = PropDict._make_property('username', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    time = PropDict._make_property('time', str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    time_end = PropDict._make_property('time_end', str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    comment = PropDict._make_property('comment', str, 'surrogate-escaped str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    chunker_params = PropDict._make_property('chunker_params', tuple) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     recreate_cmdline = PropDict._make_property('recreate_cmdline', list)  # list of s-e-str 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     # recreate_source_id, recreate_args, recreate_partial_chunks were used in 1.1.0b1 .. b2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     recreate_source_id = PropDict._make_property('recreate_source_id', bytes) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -395,6 +502,24 @@ class ArchiveItem(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     csize_parts = PropDict._make_property('csize_parts', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     nfiles_parts = PropDict._make_property('nfiles_parts', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def update_internal(self, d): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # legacy support for migration (data from old msgpacks comes in as bytes always, but sometimes we want str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for k, v in list(d.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            k = fix_key(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'version': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                assert isinstance(v, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('name', 'hostname', 'username', 'comment'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_str_value(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('time', 'time_end'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_str_value(d, k, 'replace') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'chunker_params': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_tuple_of_str_and_int(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k in ('cmdline', 'recreate_cmdline'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_list_of_str(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'items': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_list_of_bytes(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._dict[k] = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class ManifestItem(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -403,7 +528,7 @@ class ManifestItem(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     A ManifestItem is created either from msgpack unpacker output, from another dict, from kwargs or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     built step-by-step by setting attributes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    msgpack gives us a dict with bytes-typed keys, just give it to ManifestItem(d) and use manifest.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    msgpack unpacker gives us a dict, just give it to ManifestItem(d) and use manifest.xxx later. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     If a ManifestItem shall be serialized, give as_dict() method output to msgpack packer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -413,10 +538,54 @@ class ManifestItem(PropDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     __slots__ = ("_dict", )  # avoid setting attributes not supported by properties 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     version = PropDict._make_property('version', int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    archives = PropDict._make_property('archives', dict)  # name -> dict 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    timestamp = PropDict._make_property('timestamp', str, 'surrogate-escaped str', encode=safe_encode, decode=safe_decode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    archives = PropDict._make_property('archives', dict, 'dict of str -> dict')  # name -> dict 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    timestamp = PropDict._make_property('timestamp', str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     config = PropDict._make_property('config', dict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    item_keys = PropDict._make_property('item_keys', tuple) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    item_keys = PropDict._make_property('item_keys', tuple, 'tuple of str') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def update_internal(self, d): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # legacy support for migration (data from old msgpacks comes in as bytes always, but sometimes we want str) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for k, v in list(d.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            k = fix_key(d, k) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'version': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                assert isinstance(v, int) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'archives': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ad = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                assert isinstance(ad, dict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for ak, av in list(ad.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ak = fix_key(ad, ak, errors='surrogateescape') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    assert isinstance(av, dict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for ik, iv in list(av.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ik = fix_key(av, ik) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if ik == 'id': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            fix_bytes_value(av, 'id') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if ik == 'time': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            fix_str_value(av, 'time') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    assert set(av) == {'id', 'time'} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'timestamp': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_str_value(d, k, 'replace') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'config': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cd = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                assert isinstance(cd, dict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for ck, cv in list(cd.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ck = fix_key(cd, ck) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if ck == 'tam_required': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        assert isinstance(cv, bool) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if ck == 'feature_flags': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        assert isinstance(cv, dict) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        ops = {'read', 'check', 'write', 'delete'} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        for op, specs in list(cv.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            op = fix_key(cv, op) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            assert op in ops 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            for speck, specv in list(specs.items()): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                speck = fix_key(specs, speck) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                if speck == 'mandatory': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    specs[speck] = fix_tuple_of_str(specv) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        assert set(cv).issubset(ops) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if k == 'item_keys': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v = fix_tuple_of_str(v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._dict[k] = v 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class ItemDiff: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 |