def test_filter(): users_pd = PathDict(users, deep_copy=True) users_filtered = users_pd.filtered("users", f=lambda k, v: v["age"] <= 30) assert users_filtered["users"] == { "1": { "age": 22, "name": "Joe" } } assert isinstance(users_filtered, PathDict) premium_users = users_pd["users"].filtered(f=lambda k, v: int(k) in users_pd["premium_users"]) assert isinstance(premium_users, PathDict) assert premium_users == { "1": { "age": 22, "name": "Joe" }, "3": { "age": 32, "name": "Sue" } } follows_includes_joe = users_pd.filtered("follows", f=lambda e: "Joe" in e) assert isinstance(follows_includes_joe["follows"], list) assert follows_includes_joe["follows"] == [ ["Joe", "Ben"], ["Ben", "Joe"], ]
def referencing(): p_table = { "p1": PathDict(), "p2": PathDict(), "p3": PathDict({}), "p4": PathDict({}), } for a in p_table: for b in p_table: if a == b: continue assert p_table[a].data is not p_table[b].data shared_d1 = {} p1_with_shared_d1 = PathDict(shared_d1) p2_with_shared_d1 = PathDict(shared_d1) assert p1_with_shared_d1.data is p2_with_shared_d1.data p_with_deep_copy_d1 = PathDict(shared_d1, deep_copy=True) p3_with_shared_d1 = PathDict(shared_d1) # Deep copy should have its own value assert p_with_deep_copy_d1.data is not p1_with_shared_d1.data # Ensure deep_copy is set to False again assert p3_with_shared_d1.data is p1_with_shared_d1.data
def test_star_operations(): winners_original = PathDict({ "2017": { "podium": { "17-place-1": {"name": "Joe", "age": 22}, "17-place-2": {"name": "Ben", "age": 13}, "17-place-3": {"name": "Sue", "age": 98}, }, "prices_list": ["Car", "Bike", "Plane"], }, "2018": { "podium": { "18-place-1": {"name": "Bernd", "age": 50}, "18-place-2": {"name": "Sara", "age": 32}, "18-place-3": {"name": "Jan", "age": 26}, }, "prices_list": ["Beer", "Coffee", "Cigarette"], }, }) # assert winners == winners["*"] # Increment age of all users by 1 winners = winners_original.deepcopy winners["*", "podium", "*", "age"] = lambda x: x + 1 assert winners["2017", "podium", "17-place-1", "age"] == 23 assert winners["2017", "podium", "17-place-2", "age"] == 14 assert winners["2017", "podium", "17-place-3", "age"] == 99 assert winners["2018", "podium", "18-place-1", "age"] == 51 assert winners["2018", "podium", "18-place-2", "age"] == 33 assert winners["2018", "podium", "18-place-3", "age"] == 27
def initialization(): # Pre-checks assert isinstance(None, PathDict) == False assert PathDict().data == {} # Empty pd_empty = PathDict({}) assert pd_empty.dict == {} # Wrong inits for wrong in ["", None, 1, [1]]: try: _ = PathDict(wrong) assert False except Exception: assert True # Init with PathDict init_pd = PathDict({"test": 1}) pd_from_pd = PathDict(init_pd) assert init_pd == pd_from_pd assert init_pd.data is pd_from_pd.data # Init with dict init_dict = copy.deepcopy(users) pd = PathDict(init_dict) assert pd.data is pd.dict assert pd.dict is init_dict assert pd is not init_dict assert pd == init_dict assert pd["users"].dict is init_dict["users"] assert isinstance(pd["premium_users"], list) assert pd["premium_users"] is init_dict["premium_users"] # Deep copy behavior dc_pd = PathDict(users, deep_copy=True) assert dc_pd.dict is not users dc_pd_deepcopy = dc_pd.deepcopy assert dc_pd is not dc_pd_deepcopy
def test_PathDict(): d = { "total_users": 3, "premium_users": [1, 3], "users": { "1": {"name": "Joe", "age": 22}, "2": {"name": "Ben", "age": 49}, "3": {"name": "Sue", "age": 32}, }, "follows": [ ["Ben", "Sue"], ["Joe", "Ben"], ["Ben", "Joe"], ] } o = PathDict(d) # Getting attributes assert o["total_users"] == 3 assert o["not_exists"] is None assert o["users"] == { "1": {"name": "Joe", "age": 22}, "2": {"name": "Ben", "age": 49}, "3": {"name": "Sue", "age": 32}} assert o["users", "1"] == {"name": "Joe", "age": 22} assert o["users", "3", "name"] == "Sue" assert o["follows"][0] == ["Ben", "Sue"] # Setting attributes o["total_users"] = 4 assert o["total_users"] == 4 o["users", "3", "age"] = 99 assert o["users", "3", "age"] == 99 o["users", "4"] = {"name": "Ron", "age": 62} assert o["users", "4"] == {"name": "Ron", "age": 62} o["1", "1", "1", "1"] = 1 assert o["1", "1", "1"] == {"1": 1} # Apply functions o["follows"] = lambda x: [list(reversed(e)) for e in x] assert o["follows"] == [ ["Sue", "Ben"], ["Ben", "Joe"], ["Joe", "Ben"]] assert o.dict == { "1": {"1": {"1": {"1": 1}}}, "total_users": 4, "premium_users": [1, 3], "users": { "1": {"name": "Joe", "age": 22}, "2": {"name": "Ben", "age": 49}, "3": {"name": "Sue", "age": 99}, "4": {"name": "Ron", "age": 62}, }, "follows": [ ["Sue", "Ben"], ["Ben", "Joe"], ["Joe", "Ben"]] }
def test_contains(): users_dict = copy.deepcopy(users) users_pd = PathDict(users_dict) assert ("" in users_pd) == False assert ("total_users" in users_pd) == True assert (["premium_users", 1] in users_pd) == False assert (["users","1"] in users_pd) == True assert (["users","999999"] in users_pd) == False assert (["users","1","name"] in users_pd) == True assert (["users","999999","name"] in users_pd) == False assert (["users","1","name","joe"] in users_pd) == False assert (["users","1","name","joe","Brown"] in users_pd) == False # too many paths
def multiread(*pattern, as_PathDict: bool = False): """ Mutliread reads multiple dbs and returns them as a single dict or PathDict. Path components can be "*" (all), a specific name or a list (only those from list). """ pattern_paths = expand_find_path_pattern(pattern) res = {} for db_name in pattern_paths: res[db_name] = utils.protected_read_json_as_dict(db_name) if as_PathDict: return PathDict(res) return res
def __enter__(self): self.write_locks = [utils.WriteLock(x) for x in self.db_names] self.in_session = True try: self.dicts = { n: utils.unprotected_read_json_as_dict(n) for n in self.db_names } if self.as_PathDict: self.dicts = PathDict(self.dicts) except BaseException: for write_lock in self.write_locks: write_lock.unlock() raise return self, self.dicts
def test_get_path(): users_dict = copy.deepcopy(users) users_pd = PathDict(users_dict) assert users_pd["total_users"] == 3 assert users_pd["users", "1", "name"] == "Joe" # Non existent but correct paths return None assert users_pd["users", "-1", "name"] is None # If value is not a dict, return that value assert isinstance(users_pd["follows"], list) # If value is a dict, return a PathDict assert isinstance(users_pd["users"], PathDict) assert users_pd["users"].dict is users_dict["users"] # Wrong path accesses, eg. get key on list, raise an exception try: _ = users_pd["follows", 0] assert False except BaseException: assert True
def __enter__(self): """ Any number of read tasks can be carried out in parallel. Each read task creates a read lock while reading, to signal that it is reading. As soon as a session starts, it writes a wants-to-write lock, No new read tasks will be allowed. When all read tasks are done, the session aquire the write lock. Now, it can savely read and write while all other tasks wait. """ self.write_lock = utils.WriteLock(self.db_name) self.in_session = True try: self.dict = utils.unprotected_read_json_as_dict(self.db_name) if self.as_PathDict: self.dict = PathDict(self.dict) except BaseException: self.write_lock.unlock() raise return self, self.dict
def test_deepcopy(): # Test deepcopy with object class TestObject(): def __init__(self, data): self.data = data def __repr__(self): return f"TestObject({self.data})" pd = PathDict({}) pd["test", "test"] = TestObject({"test": "test"}) assert str(pd) == """PathDict({\n "test": {\n "test": "TestObject({'test': 'test'})"\n }\n})""" try: pd_deepcopy = pd.deepcopy assert str(pd) == str(pd_deepcopy) except Exception: raise AssertionError("pd.deepcopy failed")
def test_aggregate(): users_pd = PathDict(users, deep_copy=True) users_ages = users_pd.aggregate("users", init=0, f=lambda k, v, a: a + v["age"]) assert users_ages == 103
def test_list_gets(): users_dict = copy.deepcopy(users) users_pd = PathDict(users_dict) assert users_pd[["users", "2", "age"]] == 49
import json from path_dict import PathDict import os db_directory = "./test_data/production_database" class TestObject(object): def __init__(self, data): self.data = data def get_path(self, path): print(path) users = PathDict(json.loads(open(db_directory + "/users.json", "r").read())) tasks = PathDict(json.loads(open(db_directory + "/tasks.json", "r").read())) users.filter(f=lambda k, v: v.get("status") != "archived") sorted_users_list = sorted(users.dict.values(), key=lambda x: x["first_name"]) tasks["test", "test"] = TestObject({"test": "test"}) def agg(tasks, sorted_users_list): # Get active users total_active_tasks_sum = 0 total_pending_tasks_sum = 0 for user in sorted_users_list: print(user["last_name"]) user_active_tasks = tasks.filtered(
def read(*name, as_PathDict: bool = False) -> dict | PathDict: name = _to_path_if_tuple(name) db = utils.protected_read_json_as_dict(name) if as_PathDict: return PathDict(db) return db