data: Add PostingMeta.detached() method.
This commit is contained in:
parent
dfdb9b65d5
commit
52adf1f0a5
2 changed files with 36 additions and 9 deletions
|
@ -512,10 +512,9 @@ class PostingMeta(Metadata):
|
||||||
self.txn = txn
|
self.txn = txn
|
||||||
self.index = index
|
self.index = index
|
||||||
self.post = post
|
self.post = post
|
||||||
if post.meta is None:
|
self.meta: collections.ChainMap = collections.ChainMap(txn.meta)
|
||||||
self.meta = self.txn.meta
|
if post.meta is not None:
|
||||||
else:
|
self.meta = self.meta.new_child(post.meta)
|
||||||
self.meta = collections.ChainMap(post.meta, txn.meta)
|
|
||||||
|
|
||||||
def __getitem__(self, key: MetaKey) -> MetaValue:
|
def __getitem__(self, key: MetaKey) -> MetaValue:
|
||||||
try:
|
try:
|
||||||
|
@ -527,17 +526,16 @@ class PostingMeta(Metadata):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def __setitem__(self, key: MetaKey, value: MetaValue) -> None:
|
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})
|
self.post = self.post._replace(meta={key: value})
|
||||||
|
assert self.post.meta is not None
|
||||||
self.txn.postings[self.index] = self.post
|
self.txn.postings[self.index] = self.post
|
||||||
# mypy complains that self.post.meta could be None, but we know
|
self.meta = self.meta.new_child(self.post.meta)
|
||||||
# from two lines up that it's not.
|
|
||||||
self.meta = collections.ChainMap(self.post.meta, self.txn.meta) # type:ignore[arg-type]
|
|
||||||
else:
|
else:
|
||||||
super().__setitem__(key, value)
|
super().__setitem__(key, value)
|
||||||
|
|
||||||
def __delitem__(self, key: MetaKey) -> None:
|
def __delitem__(self, key: MetaKey) -> None:
|
||||||
if self.post.meta is None:
|
if len(self.meta.maps) == 1:
|
||||||
raise KeyError(key)
|
raise KeyError(key)
|
||||||
else:
|
else:
|
||||||
super().__delitem__(key)
|
super().__delitem__(key)
|
||||||
|
@ -550,6 +548,17 @@ class PostingMeta(Metadata):
|
||||||
def date(self) -> datetime.date:
|
def date(self) -> datetime.date:
|
||||||
return self.txn.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):
|
class Posting(BasePosting):
|
||||||
"""Enhanced Posting objects
|
"""Enhanced Posting objects
|
||||||
|
|
|
@ -126,6 +126,24 @@ def test_date(date):
|
||||||
for index, post in enumerate(txn.postings):
|
for index, post in enumerate(txn.postings):
|
||||||
assert data.PostingMeta(txn, index, post).date == date
|
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
|
# The .get() tests are arguably testing the stdlib, but they're short and
|
||||||
# they confirm that we're using the stdlib as we intend.
|
# they confirm that we're using the stdlib as we intend.
|
||||||
def test_get_with_meta_value(simple_txn):
|
def test_get_with_meta_value(simple_txn):
|
||||||
|
|
Loading…
Reference in a new issue