Package: jsop
JSOP - JSON-Style Object PersistenceJSOPis a persistence engine that allows an application to store a large amount of JSON-style data on disk, but to access it in an efficient way.It is based on thedbmmodule, but offers a much easier-to-use API.JSOP is also designed to enable easy migration of data in existing applications, that already store data in JSON files, with minimal changes to the code.Installationpip3installjsopQuickstart GuideCreating a new JSOP fileProgrammatically :# 'data' is any JSON-serializable object.importjsopjsop.JSOP("/path/to/jsop").init(data)Or from the command line:python3-mjsopinit/path/to/jsop/path/to/data.json(If an initial JSON file is not given, the file will be initialized with an empty map.)Read and Writewithjsop.JSOP("/path/to/jsop")asdata:name=data["name"]data["age"]=30forfriendindata["friends"]:print(friend["name"])Supported OperationsAssignmentsYou can store any JSON-serializable data with JSOP using simple assignment. For example:path="/path/to/jsop"jsop.JSOP(path).init()# initalize with an empty map.withjsop.JSOP(path)asdata:data["string"]="Hello, World!"data["boolean"]=Truedata["map"]={"a":1,"b":2,"c":3}data["map"]["d"]=4data["map"]["list"]=[5,6,7]The file will be saved once thewithblock exits.Accessing DataWhen you retrieve data of primitive types, you just get the corresponding python type:withjsop.JSOP(path)asdata:my_string=data["string"]# type(my_string) is strmy_int=data["map"]["c"]# type(my_int) is intHowever, when you retrieve a map or a list, you get special objects, namedJDictandJList, respectively.Map OperationsWithJDict, you can do most of the things you can do with a pythondict. For example:withjsop.JSOP(path)asdata:my_map=data["map"]# type(my_map) is JDicta=my_map["a"]# item accessmy_map["b"]=3# item assignmentdelmy_map["c"]# item removalif"d"inmy_map:pass# using the "in" operatorlength=len(my_map)# getting map's sizekeys=my_map.keys()# getting list of keysforkeyinmy_map:pass# iteration over keysifmy_map==my_map:pass# comparison with a JDictifmy_map=={"a":1,"b":3}:pass# comparison with a Python dictmy_map.clear()# removing all keys from a mapAlso, you can convert the map to a regular pythondict, using theexport()method:withjsop.JSOP(path)asdata:my_map=data["map"].export()# type(my_map) is dictmy_map["e"]=5data["map"]=my_mapNote that like a JSON map, the keys in a JSOP map are always strings. If a different object is given as a key, it is converted to a string.List OperationsLikewise, TheJListobject supports virtually all operations supported by a pythonlist. For Example:withjsop.JSOP(path)asdata:my_list=data["map"]["list"]# type(my_list) is JListforiteminmy_list:pass# iteration over itemsmy_list.append(8)# adding an itemeight=my_list.pop()# removing (and returning) the last itemsix=my_list[1]# item access by indexmy_list[1]=9# item assignmentmy_list.remove(9)# removing an arbitrary itemif8inmy_list:pass# using the "in" operatorlength=len(my_list)# getting list's sizeifmy_list==my_list:pass# comparison with a JListifmy_list==[5,6,7]:pass# comparison with a Python listmy_list.clear()# removing all items from listLike as inJDict,JListalso supports theexport()method, which returns a pythonlist:withjsop.JSOP(path)asdata:my_list=data["map"]["list"].export()# type(my_list) is listHandling ReferencesOne should be a bit careful when keeping references toJDictandJListobjects.Unlike Python's regulardictandlistobjects, these are not references to objects in memory, but to certain "paths" in the JSOP root object. For example:withjsop.JSOP(path)asdata:data["list_of_lists"]=[[1,2,3],[4,5,6]]item=data["list_of_lists"][0]# Since `item` is a JList, it is a reference to the first item of# the list under the key "list_of_lists" in `data`.deldata["list_of_lists"]# Now the list_of_lists does not exit, and `item` became an# invalid reference.print(item[2])# This will raise an exception.LockingIf multiple concurrent processes may access the database simultaneously, you need a locking mechanism to ensure data consistency.Some DBM implementations, such as GDBM, provide an internal locking mechanism. For others, such as NDBM, you need to use an external locking mechanism, that may depend on your specific OS and file system (but in most cases,filelockis the solution).In either case, it's best to distinguish between read-only access and full access. When you need read-only access to the database, You can useJSOP(path, readonly=True). It prevents writing, and it also passes the flag forward to the DBM implementation.Copy and BackupIn order to create copy a JSOP file, it is recommended to export its content to JSON. The reason is that JSON files take less space, and also because of portability: this practice avoids problems resulting from the use of differentdbmimplementations on different systems.This can be done from the command line:python3-mjsopexport/path/to/jsop/path/to/copy.jsonIf JSON file path is not given, the result will be printed to the standard output.Note that the output of dictionaries will be sorted by key, to ensure efficency of diff-based backup systems.Choosing DBM ImplementationYou can choose which DBM implementation to use, by overriding thejsop.dbmvariable. For example:importjsopimportdbm.gnujsop.dbm=dbm.gnu