From 5e19cd81e56937f69a6a98b80150fd473e0f8176 Mon Sep 17 00:00:00 2001 From: mccle <104479423+mccle@users.noreply.github.com> Date: Mon, 8 Jan 2024 20:04:09 -0500 Subject: [PATCH 1/3] Update track.py Add record chaining to tracked --- src/pycrumbs/track.py | 47 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/pycrumbs/track.py b/src/pycrumbs/track.py index b15ceee..a002c48 100644 --- a/src/pycrumbs/track.py +++ b/src/pycrumbs/track.py @@ -14,7 +14,7 @@ import random import sys from types import ModuleType -from typing import Any, Callable, Dict, Optional, Union, Sequence, cast +from typing import Any, Callable, Dict, Optional, Union, Sequence, cast, List from uuid import uuid4 import git @@ -314,8 +314,6 @@ def write_record( """ # Save the record to file - if not record_path.name.endswith('.json'): - record_path = record_path.with_name(record_path.stem + '.json') with record_path.open('w') as jf: json.dump(record, jf, indent=4) @@ -337,6 +335,7 @@ def tracked( include_package_inventory: bool = True, create_parents: bool = False, require_empty_directory: bool = False, + chain_records: bool = False ) -> Callable: """Store information about a function call to disc. @@ -449,6 +448,10 @@ def tracked( directory_parameter and subdirectory_name_parameter are not specified so that the called decorated function is aware of the location of the output directory. It may be used in other situations for convenience. + chain_records: bool + If True, a pre-existing record file will have a new record appended to + it within the same file. If False, a pre-existing record file will be + overwritten. Examples -------- @@ -839,7 +842,30 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: } full_record_path = record_dir / record_name_local - write_record(full_record_path, record=record) + + if not full_record_path.name.endswith(".json"): + full_record_path = full_record_path.with_name( + full_record_path.stem + ".json" + ) + + chaining = False + if chain_records: + if full_record_path.exists(): + chaining = True + with full_record_path.open("r") as jf: + previous_record = json.load(jf) + + if isinstance(previous_record, List): + out_record = previous_record + [record] + + else: + out_record = [previous_record, record] + else: + out_record = record + else: + out_record = record + + write_record(full_record_path, record=out_record) # Run the function as normal result = function(*bound_args.args, **bound_args.kwargs) @@ -848,7 +874,18 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: end_time = datetime.datetime.now() record['timing']['end_time'] = str(end_time) record['timing']['run_time'] = str(end_time - start_time) - write_record(full_record_path, record=record) + + if chaining: + if isinstance(previous_record, List): + out_record = previous_record + [record] + + else: + out_record = [previous_record, record] + + else: + out_record = record + + write_record(full_record_path, record=out_record) return result From e91b0057c3cb147cb64e9f2d626e5d3cfe931878 Mon Sep 17 00:00:00 2001 From: mccle <104479423+mccle@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:03:26 -0500 Subject: [PATCH 2/3] Incorporate Feedback Revert change to write_record. --- src/pycrumbs/track.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pycrumbs/track.py b/src/pycrumbs/track.py index a002c48..15ebeff 100644 --- a/src/pycrumbs/track.py +++ b/src/pycrumbs/track.py @@ -314,6 +314,8 @@ def write_record( """ # Save the record to file + if not record_path.name.endswith('.json'): + record_path = record_path.with_name(record_path.stem + '.json') with record_path.open('w') as jf: json.dump(record, jf, indent=4) From f99e81a168cd3d0a10978d9732ab1d7ea2ed9426 Mon Sep 17 00:00:00 2001 From: mccle <104479423+mccle@users.noreply.github.com> Date: Tue, 9 Jan 2024 17:17:42 -0500 Subject: [PATCH 3/3] Add tests --- tests/test_track.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/test_track.py b/tests/test_track.py index 0eca848..af5649f 100644 --- a/tests/test_track.py +++ b/tests/test_track.py @@ -4,6 +4,7 @@ from pathlib import Path import tempfile from uuid import uuid4 +from typing import Dict, List import pycrumbs from pycrumbs import track @@ -780,3 +781,41 @@ def some_fun(x): some_fun(0) assert subdir.exists() assert subdir.joinpath('some_fun_record.json').exists() + + +def test_record_chaining(): + """Test tracked with chain_records is True.""" + with tempfile.TemporaryDirectory() as temp: + temp = Path(temp).resolve() + + @pycrumbs.tracked(literal_directory=temp, chain_records=True) + def some_fun(x): + pass + + saved_record = temp.joinpath('some_fun_record.json') + # If a record does not yet exist, demonstrate regular behavior. + assert not saved_record.exists() + some_fun(0) + assert saved_record.exists() + with saved_record.open('r') as jf: + record_0 = json.load(jf) + assert isinstance(record_0, Dict) + + # If record already exists with 1 element, demonstrate conversion to + # list which contains the original record as its first element. + some_fun(1) + with saved_record.open('r') as jf: + record_1 = json.load(jf) + assert isinstance(record_1, List) + assert len(record_1) == 2 + assert record_0 == record_1[0] + + # If record already exists as a list of 2+ elements, demonstrate + # original elements match previous records and contain a new final element. + some_fun(2) + with saved_record.open('r') as jf: + record_2 = json.load(jf) + assert isinstance(record_2, List) + assert len(record_2) == 3 + assert record_0 == record_1[0] == record_2[0] + assert record_1[1] == record_2[1]