Coverage for lib/datamodel/datasource.py: 82%
76 statements
« prev ^ index » next coverage.py v7.10.1, created at 2025-07-28 07:25 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2025-07-28 07:25 +0000
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
4# Hermes : Change Data Capture (CDC) tool from any source(s) to any target
5# Copyright (C) 2023, 2024 INSA Strasbourg
6#
7# This file is part of Hermes.
8#
9# Hermes is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# Hermes is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with Hermes. If not, see <https://www.gnu.org/licenses/>.
23from collections.abc import KeysView, ValuesView, ItemsView
24from typing import Any, Iterator
26from lib.datamodel.dataobjectlist import DataObjectList
27from lib.datamodel.dataschema import Dataschema
29from copy import deepcopy
32class Datasource:
33 """Generic data source offering basic methods for data access
34 Also offers optional trashbin and cache management
35 """
37 def __init__(
38 self,
39 schema: Dataschema,
40 enableTrashbin: bool = False,
41 enableCache: bool = True,
42 cacheFilePrefix: str = "",
43 cacheFileSuffix: str = "",
44 ):
45 self._hasTrashbin: bool = enableTrashbin
46 self._hasCache: bool = enableCache
47 self.__cacheFilePrefix: str = cacheFilePrefix
48 self.__cacheFileSuffix: str = cacheFileSuffix
49 self.schema: Dataschema = schema
50 """Copy of Dataschema used to build current datasource"""
52 self._data: dict[str, DataObjectList] = {}
53 """Dictionary containing the datamodel object types specified in server
54 datamodel or in client schema with object name as key, and their corresponding
55 DataObjectList as value"""
57 for objtype, objlistcls in self.schema.objectlistTypes.items():
58 self._data[objtype] = objlistcls(from_json_dict=[])
60 if self._hasTrashbin:
61 for objtype, objlistcls in self.schema.objectlistTypes.items():
62 self._data["trashbin_" + objtype] = objlistcls(from_json_dict=[])
64 if self._hasCache:
65 self._cache: Datasource = Datasource(
66 schema=self.schema,
67 enableTrashbin=self._hasTrashbin,
68 enableCache=False,
69 cacheFilePrefix=cacheFilePrefix,
70 cacheFileSuffix=cacheFileSuffix,
71 )
72 self._cache.loadFromCache()
74 @property
75 def cache(self) -> "Datasource":
76 """Returns the cache"""
77 if self._hasCache:
78 return self._cache
79 raise AttributeError("Asking for cache on an instance with cache disabled")
81 def loadFromCache(self):
82 for objtype, objlistcls in self.schema.objectlistTypes.items():
83 self._data[objtype] = objlistcls.loadcachefile(
84 f"{self.__cacheFilePrefix}{objtype}{self.__cacheFileSuffix}"
85 )
87 if self._hasTrashbin:
88 for objtype, objlistcls in self.schema.objectlistTypes.items():
89 self._data["trashbin_" + objtype] = objlistcls.loadcachefile(
90 f"{self.__cacheFilePrefix}trashbin_"
91 f"{objtype}{self.__cacheFileSuffix}"
92 )
94 def save(self):
95 for objtype in self.schema.objectlistTypes:
96 self._data[objtype].savecachefile(
97 f"{self.__cacheFilePrefix}{objtype}{self.__cacheFileSuffix}"
98 )
100 if self._hasTrashbin:
101 for objtype in self.schema.objectlistTypes:
102 self._data["trashbin_" + objtype].savecachefile(
103 f"{self.__cacheFilePrefix}trashbin_"
104 f"{objtype}{self.__cacheFileSuffix}"
105 )
107 def __len__(self) -> int:
108 return self._data.__len__()
110 def __getitem__(self, key: str) -> DataObjectList:
111 return self._data.__getitem__(key)
113 def __setitem__(self, key: str, value: DataObjectList):
114 self._data.__setitem__(key, value)
116 def __delitem__(self, key: str):
117 self._data.__delitem__(key)
119 def __iter__(self) -> Iterator[str]:
120 return self._data.__iter__()
122 def __reversed__(self) -> Iterator[str]:
123 return self._data.__reversed__()
125 def __contains__(self, key: str) -> bool:
126 return self._data.__contains__(key)
128 def keys(self) -> KeysView[str]:
129 return self._data.keys()
131 def values(self) -> ValuesView[DataObjectList]:
132 return self._data.values()
134 def items(self) -> ItemsView[str, DataObjectList]:
135 return self._data.items()
137 def get(self, key: str, default: Any = None) -> DataObjectList | Any:
138 return self._data.get(key, default)
140 def clear(self):
141 return self._data.clear()
143 def setdefault(self, key: str, default: DataObjectList) -> DataObjectList:
144 return self._data.setdefault(key, default)
146 def pop(self, key: str, default: Any = None) -> DataObjectList | Any:
147 return self._data.pop(key, default)
149 def popitem(self) -> tuple[str, DataObjectList]:
150 return self._data.popitem()
152 def copy(self) -> dict[str, DataObjectList]:
153 return self._data.copy()
155 def deepcopy(self) -> dict[str, DataObjectList]:
156 return deepcopy(self._data)
158 def update(self, **kwargs: DataObjectList):
159 self._data.update(kwargs)