Changeset - 52adf1f0a583
[Not reviewed]
0 2 0
Brett Smith - 4 years ago 2020-08-29 14:26:21
brettcsmith@brettcsmith.org
data: Add PostingMeta.detached() method.
2 files changed with 36 insertions and 9 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/data.py
Show inline comments
...
 
@@ -512,10 +512,9 @@ class PostingMeta(Metadata):
 
        self.txn = txn
 
        self.index = index
 
        self.post = post
 
        if post.meta is None:
 
            self.meta = self.txn.meta
 
        else:
 
            self.meta = collections.ChainMap(post.meta, txn.meta)
 
        self.meta: collections.ChainMap = collections.ChainMap(txn.meta)
 
        if post.meta is not None:
 
            self.meta = self.meta.new_child(post.meta)
 

	
 
    def __getitem__(self, key: MetaKey) -> MetaValue:
 
        try:
...
 
@@ -527,17 +526,16 @@ class PostingMeta(Metadata):
 
                raise
 

	
 
    def __setitem__(self, key: MetaKey, value: MetaValue) -> None:
 
        if self.post.meta is None:
 
        if len(self.meta.maps) == 1:
 
            self.post = self.post._replace(meta={key: value})
 
            assert self.post.meta is not None
 
            self.txn.postings[self.index] = self.post
 
            # mypy complains that self.post.meta could be None, but we know
 
            # from two lines up that it's not.
 
            self.meta = collections.ChainMap(self.post.meta, self.txn.meta)  # type:ignore[arg-type]
 
            self.meta = self.meta.new_child(self.post.meta)
 
        else:
 
            super().__setitem__(key, value)
 

	
 
    def __delitem__(self, key: MetaKey) -> None:
 
        if self.post.meta is None:
 
        if len(self.meta.maps) == 1:
 
            raise KeyError(key)
 
        else:
 
            super().__delitem__(key)
...
 
@@ -550,6 +548,17 @@ class PostingMeta(Metadata):
 
    def date(self) -> datetime.date:
 
        return self.txn.date
 

	
 
    def detached(self) -> 'PostingMeta':
 
        """Create a copy of this PostingMeta detached from the original post
 

	
 
        Changes you make to the detached copy will not propagate to the
 
        underlying data structures. This is mostly useful for reporting code
 
        that may want to "split" and manipulate the metadata multiple times.
 
        """
 
        retval = type(self)(self.txn, self.index, self.post)
 
        retval.meta = retval.meta.new_child()
 
        return retval
 

	
 

	
 
class Posting(BasePosting):
 
    """Enhanced Posting objects
tests/test_data_posting_meta.py
Show inline comments
...
 
@@ -126,6 +126,24 @@ def test_date(date):
 
    for index, post in enumerate(txn.postings):
 
        assert data.PostingMeta(txn, index, post).date == date
 

	
 
def test_mutable_copy():
 
    txn = testutil.Transaction(
 
        filename='f', lineno=130, txnkey='one', postings=[
 
        ('Assets:Cash', 18),
 
        ('Income:Donations', -18),
 
    ])
 
    meta = data.PostingMeta(txn, 1).detached()
 
    meta['layerkey'] = 'two'
 
    assert dict(meta) == {
 
        'filename': 'f',
 
        'lineno': 130,
 
        'txnkey': 'one',
 
        'layerkey': 'two',
 
    }
 
    assert 'layerkey' not in txn.meta
 
    assert all(post.meta is None for post in txn.postings)
 
    assert meta.date == txn.date
 

	
 
# The .get() tests are arguably testing the stdlib, but they're short and
 
# they confirm that we're using the stdlib as we intend.
 
def test_get_with_meta_value(simple_txn):
0 comments (0 inline, 0 general)