summaryrefslogtreecommitdiff
path: root/python-shared.spec
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-10 05:54:17 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-10 05:54:17 +0000
commit05badfe4e38f8eb032c932db5a4b526eeaff81d1 (patch)
tree4904d07b80eb05e7837997c10b0d402a28571a8b /python-shared.spec
parent324321a59b8b42b80be3bf903f24dd64093bd427 (diff)
automatic import of python-sharedopeneuler20.03
Diffstat (limited to 'python-shared.spec')
-rw-r--r--python-shared.spec1867
1 files changed, 1867 insertions, 0 deletions
diff --git a/python-shared.spec b/python-shared.spec
new file mode 100644
index 0000000..1aedf7c
--- /dev/null
+++ b/python-shared.spec
@@ -0,0 +1,1867 @@
+%global _empty_manifest_terminate_build 0
+Name: python-shared
+Version: 0.0.25
+Release: 1
+Summary: Triptych for data exchange and persistence
+License: MIT
+URL: https://github.com/pyrustic/shared
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/b0/8b/dbcab2843edfc112af5ef6da4103833fd723ed6dc3a04100ac02166005fd/shared-0.0.25.tar.gz
+BuildArch: noarch
+
+Requires: python3-jesth
+
+%description
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+[![PyPI package version](https://img.shields.io/pypi/v/shared)](https://pypi.org/project/shared)
+[![Downloads](https://pepy.tech/badge/shared)](https://pepy.tech/project/shared)
+
+<!-- Cover -->
+<div align="center">
+ <img src="https://raw.githubusercontent.com/pyrustic/misc/master/assets/shared/cover.png" alt="Cover" width="541">
+ <p align="center">
+ <i> </i>
+ </p>
+</div>
+
+
+
+# Pyrustic Shared
+**Data exchange and persistence**
+
+This project is part of the [Pyrustic Open Ecosystem](https://pyrustic.github.io).
+> [Installation](#installation) . [Latest](https://github.com/pyrustic/shared/tags) . [Modules](https://github.com/pyrustic/shared/tree/master/docs/modules#readme)
+
+## Table of contents
+- [Overview](#overview)
+- [Document](#document)
+- [Dossier](#dossier)
+- [Database](#database)
+- [Command line interface](#command-line-interface)
+- [Miscellaneous](#miscellaneous)
+- [Installation](#installation)
+
+# Overview
+**Shared** is a Python package created to be the programmer's companion when it comes to storing application data, managing configuration files, caching data, and exchanging data with other programs.
+
+Although a lightweight package, **Shared** smoothly handles collections (**dict**, **list**, **set**), **binary** data, and **SQL** queries.
+
+## Designed as a triptych
+
+**Shared**'s intuitive application programming interface is designed as a [triptych](https://en.wikipedia.org/wiki/Triptych). Thus, three classes with similar interfaces are created to cover the needs of data exchange and persistence: `Document`, `Dossier`, and `Database`.
+
+|Class|Relevance|
+|---|---|
+|`Document`|For individual access to [Jesth](https://github.com/pyrustic/jesth#readme) and [JSON](https://en.wikipedia.org/wiki/JSON) files that are likely to be **manually edited by a human**.|
+|`Dossier`|To store collections and binary data in a dossier **without worrying about how they are actually saved**.|
+|`Database`|For an intuitive interaction with [SQLite](https://www.sqlite.org) **databases**.|
+
+> **Note:** The `Document` class is not intended to be used directly. Instead, depending on the requirement, one will use the `JsonDoc` or `JesthDoc` class which subclasses the `Document` class.
+
+## Some characteristics
+Since all three classes share similar interfaces, some handy functionality has been replicated in all of them with a few exceptions.
+
+### Initialization
+All three classes emphasize **initialization**:
+- `Document` and `Dossier` give the possibility to define **default data**.
+- `Database` allows the definition of an **initialization SQL script** which is only executed to create a new database.
+
+### Data access
+All three classes provide an optional **read-only** access to data and also allow the creation of **temporary data** which is automatically deleted when the user closes the application.
+
+`Document` and `Dossier` provide **Autosave** functionality, while `Database` automatically closes the underlying database connection when the user closes the application.
+
+### Command-line interface
+
+Among the three classes, `Dossier` is the class of which a single instance can handle multiple underlying files. The `Dossier` class has its own protocol for organizing data. For this reason, `Dossier` offers a simple yet powerful **command-line interface** that allows other programs or a human to read and write the contents of a dossier.
+
+<br>
+
+Let's explore the [Document](#document), [Dossier](#dossier), and [Database](#database) classes in the next sections !
+
+# Document
+The `Document` class represents an interface for reading and writing an underlying file whose format is either [Jesth](https://github.com/pyrustic/jesth#readme) or [JSON](https://en.wikipedia.org/wiki/JSON).
+
+As stated previously in the [Overview](#overview) section, the `Document` class is not intended to be used directly. Instead, depending on the requirement, one will use the `JsonDoc` or `JesthDoc` class which subclasses the `Document` class.
+
+Since **JSON** is very popular, we will focus on the `JsonDoc` class in the following examples.
+
+Accessing a document or creating a new one is as simple as this:
+
+```python
+from shared import JsonDoc
+
+# Create a new document instance which will be linked to the 'my-data.json' file.
+# If this file doesn't exist yet, it will be automatically created
+document = JsonDoc("my-data.json")
+
+# From now, we can use 'document' to read and write the contents of 'my-data.json' !
+# ...
+```
+
+The string `my-data.json` is the base name of a file that will be created if it does not yet exist. This string is called **Target** and can be an absolute path or an instance of [pathlib.Path](https://docs.python.org/3/library/pathlib.html). The `Document` class exposes the `read` and `write` methods, respectively, to read and write the underlying document.
+
+
+
+## Initialization
+A document can be initialized with a conditional statement or by defining default data. By default, the `Document` class will assign a `dict` to the null parameter `default_data`.
+
+### Use a conditional statement
+It's as simple as testing a boolean to check if the underlying document file is newly created or not:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json")
+
+# let's initialize the content of 'my-data.json'
+if document.new:
+ data = {"name": "alex", "job": "evangelist"}
+ document.write(data) # persisted !
+```
+
+### Set default data
+The most elegant, less verbose and recommended way to initialize a document is to set some default data to the `default` parameter:
+
+```python
+from shared import JsonDoc
+
+# default data to init the file 'my-data.json'
+DEFAULT_DATA = {"name": "alex", "job": "evangelist"}
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", default=DEFAULT_DATA)
+
+# From now, thanks to the initialization functionality, the underlying
+# document contains the default data, assuming that 'my-data.json'
+# did not exist before the `Document` class was instantiated
+```
+
+## Data location
+The only mandatory argument to be supplied to the `Document` class constructor is the `target`. For convenience, the `target` is either the absolute path or the base name of a file. Its data type is either a string or an instance of [pathlib.Path](https://docs.python.org/3/library/pathlib.html).
+
+The optional `directory` parameter exists to supplement the `target` value when that value is not an absolute path.
+
+### Default directory
+By default, document files are saved in `$HOME/PyrusticHome/shared`. You can change the location according to your needs:
+
+```python
+from shared import JsonDoc
+
+DIRECTORY = "/home/alex/private"
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", directory=DIRECTORY)
+
+# From now, you can access these properties:
+# document.name == "my-data.json"
+# document.directory == "/home/alex/private"
+# document.target == "my-data.json"
+
+```
+
+### Absolute pathname
+You can set an absolute path as the target. In this case, the `Document` class ignores the `directory` parameter.
+
+```python
+from shared import JsonDoc
+
+pathname = "/home/alex/private/my-data.json"
+
+# access 'my-data.json'
+document = JsonDoc(pathname)
+
+# From now, you can access these properties:
+# document.name == "my-data.json"
+# document.directory == "/home/alex/private"
+# document.target == "/home/alex/private/my-data.json"
+```
+
+### Temporary data
+Setting the `temporary` boolean can enable temporary mode, so a document can only be created and used while the application is running, and then safely deleted when the application closes:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", temporary=True)
+
+# This document will be created in a temporary directory
+# then it will be safely deleted when the application closes
+# or when the developer explicitly calls the 'close' or 'delete' method
+```
+
+The `Document` class uses [tempfile.TemporaryDirectory](https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryDirectory) to implement this functionality.
+
+
+## Autosave
+Thanks to [atexit](https://docs.python.org/3/library/atexit.html) module, `Document` can autosave content when the application is closed:
+
+```python
+import sys
+from shared import JsonDoc
+
+# access 'my-config.json' with `autosave` mode enabled
+document = JsonDoc("my-config.json", autosave=True, default=[])
+# load the data
+data = document.read()
+
+# few lines of code later...
+
+data.append("batman") # data modified
+
+sys.exit() # data automatically saved !
+```
+Along with `atexit` module, the `Document` class also uses a caching mechanism to implement the `autosave` functionality.
+
+## Caching
+By default, `caching` mode is enabled, so the user can access cached data through the `cache` property of an instance of the `Document` class:
+
+```python
+from shared import JsonDoc
+
+DEFAULT_DATA = {"name": "alex", "job": "evangelist"}
+
+# access 'my-config.json'
+document = JsonDoc("my-config.json", caching=True, default=DEFAULT_DATA)
+
+data = document.read()
+
+if data is document.cache:
+ print("Same same !")
+```
+
+## Readonly
+Setting the `readonly` parameter to `True` prevents the running application from accidentally modifying the content of a document:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", readonly=True)
+
+# when you set readonly to True, you can no longer edit the content !
+# shared.ReadonlyError will be raised if you try to mess with a readonly document
+
+```
+
+## Clear data
+You can delete the underlying file of a document (assuming the file isn't in readonly mode):
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json")
+
+# delete 'my-data.json'
+document.delete()
+
+if document.deleted:
+ print("Successfully deleted !")
+```
+
+## Convenience functions
+Four convenience functions are available for the `JsonDoc` class (also for the `JesthDoc` class):
+
+```python
+from shared import json_create, json_readonly, json_write, json_autosave
+
+# quickly create a document
+DEFAULT = ["red", "violet"]
+json_create("my-data.json", default=DEFAULT)
+
+# quickly open a document in readonly mode
+data = json_readonly("my-data.json")
+
+# quickly change the content of a document
+data = ["red", "green"]
+json_write("my-data.json", data)
+
+# quickly read the content of a document in autosave mode
+data = json_autosave("my-data.json")
+data.append("blue") # data will be automatically saved on exit
+```
+
+## Recapitulation
+For individual access to [Jesth](https://github.com/pyrustic/jesth#readme) and [JSON](https://en.wikipedia.org/wiki/JSON) files that are likely to be **manually edited by a human**, the `Document` class is the recommended interface.
+
+For more technical details about this class and the subclasses `JesthDoc` and `JsonDoc`, read the [reference documentation](https://github.com/pyrustic/shared/tree/master/docs/modules#readme).
+
+# Dossier
+The `Dossier` class stores collections (**list**, **dict**, **set**) and **binary data** with a unified interface inside a [dossier](https://dictionary.cambridge.org/dictionary/english/dossier). **Shared** allows to read and write a dossier not only programmatically but also from the [command line](#command-line-interface).
+
+This class shares a similar interface with the `Document` class. Thus, the `Dossier` class constructor has `target`, `directory`, `autosave`, `readonly` and `temporary` as parameters. These parameters are already covered in the `Document` class [section](#document).
+
+Under the hood, `Dossier` uses [files](https://en.wikipedia.org/wiki/Computer_file) and [JSON](https://en.wikipedia.org/wiki/JSON) to store data.
+
+## Example
+Let's create a dossier with **script_1.py**:
+
+```python
+# script_1.py
+from shared import Dossier
+
+# data
+people = {"Jack": "male", "Jane": "female"} # dict
+planets = ["Mars", "Venus", "Jupiter"] # list
+colors = {"red", "green", "blue"} # set
+
+# let's persist the data in 'my-dossier'
+dossier = Dossier("my-dossier")
+dossier.set("people", people) # set the 'people' entry
+dossier.set("planets", planets) # set the 'planets' entry
+dossier.set("colors", colors) # set the 'colors' entry
+
+# Done ! The data is persisted !
+```
+
+From **script_2.py**, let's access the dossier created with **script_1.py**:
+```python
+# script_2.py
+from shared import Dossier
+
+# let's access the shared dossier
+dossier = Dossier("my-dossier")
+
+# get data from the shared dossier
+people = dossier.get("people") # get the 'people' entry
+planets = dossier.get("planets") # get the 'planets' entry'
+colors = dossier.get("colors") # get the 'colors' entry
+
+print(people)
+# output: {'Jack': 'male', 'Jane': 'female'}
+
+print(planets)
+# output: ['Mars', 'Venus', 'Jupiter']
+
+print(set(colors)) # there is nothing called 'set' in JSON [1]
+# output: {'red', 'green', 'blue'}
+
+
+# [1] the value of 'colors' is this dictionary:
+# {'red': None, 'green': None, 'blue': None}
+```
+
+## Binary data
+You can store binary data with the same unified interface:
+
+```python
+# script_1.py
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+with open("/home/alex/selfie.png", "rb") as file:
+ data = file.read()
+ dossier.set("selfie", data) # set the 'selfie' entry
+
+# the 'set' method returns the path to the binary file that stores the binary entry
+```
+
+The above code can also be expressed like this:
+
+```python
+# script_1.py
+import pathlib
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+path = pathlib.Path("/home/alex/selfie.png")
+dossier.set("selfie", path) # set the 'selfie' entry
+
+# the 'set' method returns the path to the binary file that stores the binary entry
+```
+
+You can retrieve your binary data from another script:
+```python
+# script_2.py
+from shared import Dossier
+from shutil import copyfile
+
+dossier = Dossier("my-dossier")
+source_path = dossier.get("selfie") # get the filename of the 'selfie' bin entry
+destination_path = "/home/alex/new.png"
+
+# copy the content from source to destination
+copyfile(source_path, destination_path)
+
+```
+
+## Check
+Use the `check` method to check the contents of a dossier or a specific entry:
+
+```python
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+# check a specific entry
+info = dossier.check("entry")
+if info:
+ # info is a 3-tuple (name, container, filename).
+ # The name is simply the entry name.
+ # The container is a string that represents the type of the entry.
+ # containers: "dict", "list", "set", and "bin"
+ # The filename is either the path to a JSON file or a binary file
+ name, container, filename = info
+
+# check the contents of the dossier
+dossier_info = dossier.check() # returns a dict, keys are entries and values are 3-tuples
+
+for entry, info in dossier_info.items():
+ print("Entry:", info.name) # the entry name
+ print("Container:", info.container) # 'dict', 'set', 'list', or 'bin'
+ print("Filename:", info.filename) # the underlying file in which the data is stored
+ print()
+```
+
+
+## Clear data
+You can decide to delete a specific entry, a group of entries, or the dossier:
+
+```python
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+# delete a specific entry
+dossier.delete("entry_1")
+
+# delete a group of entries
+dossier.delete("entry_2", "entry_3")
+
+# delete the dossier
+dossier.delete() # collections, binary data, and meta data are gone
+```
+
+## Recapitulation
+To store collections and binary data in a dossier **without worrying about how they are actually saved**, the `Dossier` class is the interface to use.
+
+For more technical details about this class, read its [documentation](https://github.com/pyrustic/shared/blob/master/docs/modules/content/shared/content/classes/Dossier.md#class-dossier).
+
+
+# Database
+Intuitive interaction with **SQLite** databases.
+
+## Example
+The following example shows how nice it is to work with the `Database` class:
+
+```python
+from shared import Database
+
+# Initialization script
+# This SQL script will create two tables: friends and projects
+INIT_SCRIPT = """\
+CREATE TABLE friends (name TEXT PRIMARY KEY,
+ age INTEGER NOT NULL);
+
+CREATE TABLE projects (name TEXT PRIMARY KEY,
+ language TEXT NOT NULL);
+"""
+
+# If this database doesn't exist yet,
+# it will be created with the initialization script
+database = Database("my-database", init_script=INIT_SCRIPT)
+
+# This will only be executed once !
+# So you can safely restart this script again and again...
+if database.new:
+ # Populate this database
+ sql = """INSERT INTO friends VALUES ("Jack", 20)"""
+ database.edit(sql)
+
+ # few lines of code later...
+
+ # Populate this database
+ sql = """INSERT INTO friends VALUES (?, ?)"""
+ parameters = ("Jane", 21)
+ database.edit(sql, param=parameters)
+
+# Read data
+sql = "SELECT * FROM friends"
+columns, data = database.query(sql) # returns a shared.dto.QueryResult namedtuple
+
+print(columns)
+# output: ['name', 'age']
+
+print(data)
+# output: [('Jack', 20), ('Jane', 21)]
+
+```
+
+For more technical details about this class, read its [documentation](https://github.com/pyrustic/shared/blob/master/docs/modules/content/shared/content/classes/Database.md#class-database).
+
+
+# Command line interface
+**Shared** comes with an intuitive command line interface for the `Dossier` class. Type `help` in the command line interface to display a short manual.
+
+For the following subsections, assume we have a pre-populated dossier named `my-dossier` and located in `/home/alex/dossiers`.
+
+## Check the content
+Check the contents of `my-dossier` or a specific entry:
+```bash
+$ cd /home/alex/dossiers/my-dossier
+
+$ shared check
+- 'colors' set 56B
+- 'people' dict 44B
+- 'planets' list 42B
+
+$ shared check people
+'people' dict 44B
+
+$ shared check colors
+'colors' set 56B
+```
+
+## Read the content of a specific entry
+
+```bash
+$ cd /home/alex/dossiers/my-dossier
+
+$ shared get people
+{
+ "Jack": "male",
+ "Jane": "female"
+}
+
+$ shared get planets
+[
+ "Mars",
+ "Venus",
+ "Jupiter"
+]
+
+shared get colors
+{
+ "red": null,
+ "blue": null,
+ "green": null
+}
+
+```
+The output text is the exact **JSON** representation as stored in a file. So the **output can be consumed as is** by another program and deserialized with a **JSON** library. Note that the `colors` entry is a `set` but represented as a `dict` in **JSON**.
+
+## Store binary data
+```bash
+$ shared set selfie bin: '/home/alex/selfie.png'
+Entry successfully updated !
+```
+
+You can copy a binary entry into an arbitrary file from the command line:
+
+```bash
+$ shared get selfie > '/home/alex/selfie-copy.png'
+```
+
+## Store a collection
+```bash
+$ shared set countries list: '/home/alex/countries.json'
+Entry successfully updated !
+
+$ shared set my_config dict: '/home/alex/app_config.json'
+Entry successfully updated !
+```
+
+## Delete an entry
+
+```bash
+$ shared del "selfie"
+Entry successfully deleted !
+
+$ shared check selfie
+This entry doesn't exist.
+```
+
+## Delete a dossier
+Right-click on the folder with your mouse, then send it safely to the trash... ;)
+
+# Miscellaneous
+
+
+# Installation
+**Shared** is **cross platform** and versions under **1.0.0** will be considered **Beta** at best. It should work on **Python 3.5** or [newer](https://www.python.org/downloads/).
+
+## For the first time
+
+```bash
+$ pip install shared
+```
+
+## Upgrade
+```bash
+$ pip install shared --upgrade --upgrade-strategy eager
+
+```
+
+## Show information
+```bash
+$ pip show shared
+```
+
+
+<br>
+<br>
+<br>
+
+[Back to top](#readme)
+
+
+
+
+%package -n python3-shared
+Summary: Triptych for data exchange and persistence
+Provides: python-shared
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-shared
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+[![PyPI package version](https://img.shields.io/pypi/v/shared)](https://pypi.org/project/shared)
+[![Downloads](https://pepy.tech/badge/shared)](https://pepy.tech/project/shared)
+
+<!-- Cover -->
+<div align="center">
+ <img src="https://raw.githubusercontent.com/pyrustic/misc/master/assets/shared/cover.png" alt="Cover" width="541">
+ <p align="center">
+ <i> </i>
+ </p>
+</div>
+
+
+
+# Pyrustic Shared
+**Data exchange and persistence**
+
+This project is part of the [Pyrustic Open Ecosystem](https://pyrustic.github.io).
+> [Installation](#installation) . [Latest](https://github.com/pyrustic/shared/tags) . [Modules](https://github.com/pyrustic/shared/tree/master/docs/modules#readme)
+
+## Table of contents
+- [Overview](#overview)
+- [Document](#document)
+- [Dossier](#dossier)
+- [Database](#database)
+- [Command line interface](#command-line-interface)
+- [Miscellaneous](#miscellaneous)
+- [Installation](#installation)
+
+# Overview
+**Shared** is a Python package created to be the programmer's companion when it comes to storing application data, managing configuration files, caching data, and exchanging data with other programs.
+
+Although a lightweight package, **Shared** smoothly handles collections (**dict**, **list**, **set**), **binary** data, and **SQL** queries.
+
+## Designed as a triptych
+
+**Shared**'s intuitive application programming interface is designed as a [triptych](https://en.wikipedia.org/wiki/Triptych). Thus, three classes with similar interfaces are created to cover the needs of data exchange and persistence: `Document`, `Dossier`, and `Database`.
+
+|Class|Relevance|
+|---|---|
+|`Document`|For individual access to [Jesth](https://github.com/pyrustic/jesth#readme) and [JSON](https://en.wikipedia.org/wiki/JSON) files that are likely to be **manually edited by a human**.|
+|`Dossier`|To store collections and binary data in a dossier **without worrying about how they are actually saved**.|
+|`Database`|For an intuitive interaction with [SQLite](https://www.sqlite.org) **databases**.|
+
+> **Note:** The `Document` class is not intended to be used directly. Instead, depending on the requirement, one will use the `JsonDoc` or `JesthDoc` class which subclasses the `Document` class.
+
+## Some characteristics
+Since all three classes share similar interfaces, some handy functionality has been replicated in all of them with a few exceptions.
+
+### Initialization
+All three classes emphasize **initialization**:
+- `Document` and `Dossier` give the possibility to define **default data**.
+- `Database` allows the definition of an **initialization SQL script** which is only executed to create a new database.
+
+### Data access
+All three classes provide an optional **read-only** access to data and also allow the creation of **temporary data** which is automatically deleted when the user closes the application.
+
+`Document` and `Dossier` provide **Autosave** functionality, while `Database` automatically closes the underlying database connection when the user closes the application.
+
+### Command-line interface
+
+Among the three classes, `Dossier` is the class of which a single instance can handle multiple underlying files. The `Dossier` class has its own protocol for organizing data. For this reason, `Dossier` offers a simple yet powerful **command-line interface** that allows other programs or a human to read and write the contents of a dossier.
+
+<br>
+
+Let's explore the [Document](#document), [Dossier](#dossier), and [Database](#database) classes in the next sections !
+
+# Document
+The `Document` class represents an interface for reading and writing an underlying file whose format is either [Jesth](https://github.com/pyrustic/jesth#readme) or [JSON](https://en.wikipedia.org/wiki/JSON).
+
+As stated previously in the [Overview](#overview) section, the `Document` class is not intended to be used directly. Instead, depending on the requirement, one will use the `JsonDoc` or `JesthDoc` class which subclasses the `Document` class.
+
+Since **JSON** is very popular, we will focus on the `JsonDoc` class in the following examples.
+
+Accessing a document or creating a new one is as simple as this:
+
+```python
+from shared import JsonDoc
+
+# Create a new document instance which will be linked to the 'my-data.json' file.
+# If this file doesn't exist yet, it will be automatically created
+document = JsonDoc("my-data.json")
+
+# From now, we can use 'document' to read and write the contents of 'my-data.json' !
+# ...
+```
+
+The string `my-data.json` is the base name of a file that will be created if it does not yet exist. This string is called **Target** and can be an absolute path or an instance of [pathlib.Path](https://docs.python.org/3/library/pathlib.html). The `Document` class exposes the `read` and `write` methods, respectively, to read and write the underlying document.
+
+
+
+## Initialization
+A document can be initialized with a conditional statement or by defining default data. By default, the `Document` class will assign a `dict` to the null parameter `default_data`.
+
+### Use a conditional statement
+It's as simple as testing a boolean to check if the underlying document file is newly created or not:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json")
+
+# let's initialize the content of 'my-data.json'
+if document.new:
+ data = {"name": "alex", "job": "evangelist"}
+ document.write(data) # persisted !
+```
+
+### Set default data
+The most elegant, less verbose and recommended way to initialize a document is to set some default data to the `default` parameter:
+
+```python
+from shared import JsonDoc
+
+# default data to init the file 'my-data.json'
+DEFAULT_DATA = {"name": "alex", "job": "evangelist"}
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", default=DEFAULT_DATA)
+
+# From now, thanks to the initialization functionality, the underlying
+# document contains the default data, assuming that 'my-data.json'
+# did not exist before the `Document` class was instantiated
+```
+
+## Data location
+The only mandatory argument to be supplied to the `Document` class constructor is the `target`. For convenience, the `target` is either the absolute path or the base name of a file. Its data type is either a string or an instance of [pathlib.Path](https://docs.python.org/3/library/pathlib.html).
+
+The optional `directory` parameter exists to supplement the `target` value when that value is not an absolute path.
+
+### Default directory
+By default, document files are saved in `$HOME/PyrusticHome/shared`. You can change the location according to your needs:
+
+```python
+from shared import JsonDoc
+
+DIRECTORY = "/home/alex/private"
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", directory=DIRECTORY)
+
+# From now, you can access these properties:
+# document.name == "my-data.json"
+# document.directory == "/home/alex/private"
+# document.target == "my-data.json"
+
+```
+
+### Absolute pathname
+You can set an absolute path as the target. In this case, the `Document` class ignores the `directory` parameter.
+
+```python
+from shared import JsonDoc
+
+pathname = "/home/alex/private/my-data.json"
+
+# access 'my-data.json'
+document = JsonDoc(pathname)
+
+# From now, you can access these properties:
+# document.name == "my-data.json"
+# document.directory == "/home/alex/private"
+# document.target == "/home/alex/private/my-data.json"
+```
+
+### Temporary data
+Setting the `temporary` boolean can enable temporary mode, so a document can only be created and used while the application is running, and then safely deleted when the application closes:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", temporary=True)
+
+# This document will be created in a temporary directory
+# then it will be safely deleted when the application closes
+# or when the developer explicitly calls the 'close' or 'delete' method
+```
+
+The `Document` class uses [tempfile.TemporaryDirectory](https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryDirectory) to implement this functionality.
+
+
+## Autosave
+Thanks to [atexit](https://docs.python.org/3/library/atexit.html) module, `Document` can autosave content when the application is closed:
+
+```python
+import sys
+from shared import JsonDoc
+
+# access 'my-config.json' with `autosave` mode enabled
+document = JsonDoc("my-config.json", autosave=True, default=[])
+# load the data
+data = document.read()
+
+# few lines of code later...
+
+data.append("batman") # data modified
+
+sys.exit() # data automatically saved !
+```
+Along with `atexit` module, the `Document` class also uses a caching mechanism to implement the `autosave` functionality.
+
+## Caching
+By default, `caching` mode is enabled, so the user can access cached data through the `cache` property of an instance of the `Document` class:
+
+```python
+from shared import JsonDoc
+
+DEFAULT_DATA = {"name": "alex", "job": "evangelist"}
+
+# access 'my-config.json'
+document = JsonDoc("my-config.json", caching=True, default=DEFAULT_DATA)
+
+data = document.read()
+
+if data is document.cache:
+ print("Same same !")
+```
+
+## Readonly
+Setting the `readonly` parameter to `True` prevents the running application from accidentally modifying the content of a document:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", readonly=True)
+
+# when you set readonly to True, you can no longer edit the content !
+# shared.ReadonlyError will be raised if you try to mess with a readonly document
+
+```
+
+## Clear data
+You can delete the underlying file of a document (assuming the file isn't in readonly mode):
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json")
+
+# delete 'my-data.json'
+document.delete()
+
+if document.deleted:
+ print("Successfully deleted !")
+```
+
+## Convenience functions
+Four convenience functions are available for the `JsonDoc` class (also for the `JesthDoc` class):
+
+```python
+from shared import json_create, json_readonly, json_write, json_autosave
+
+# quickly create a document
+DEFAULT = ["red", "violet"]
+json_create("my-data.json", default=DEFAULT)
+
+# quickly open a document in readonly mode
+data = json_readonly("my-data.json")
+
+# quickly change the content of a document
+data = ["red", "green"]
+json_write("my-data.json", data)
+
+# quickly read the content of a document in autosave mode
+data = json_autosave("my-data.json")
+data.append("blue") # data will be automatically saved on exit
+```
+
+## Recapitulation
+For individual access to [Jesth](https://github.com/pyrustic/jesth#readme) and [JSON](https://en.wikipedia.org/wiki/JSON) files that are likely to be **manually edited by a human**, the `Document` class is the recommended interface.
+
+For more technical details about this class and the subclasses `JesthDoc` and `JsonDoc`, read the [reference documentation](https://github.com/pyrustic/shared/tree/master/docs/modules#readme).
+
+# Dossier
+The `Dossier` class stores collections (**list**, **dict**, **set**) and **binary data** with a unified interface inside a [dossier](https://dictionary.cambridge.org/dictionary/english/dossier). **Shared** allows to read and write a dossier not only programmatically but also from the [command line](#command-line-interface).
+
+This class shares a similar interface with the `Document` class. Thus, the `Dossier` class constructor has `target`, `directory`, `autosave`, `readonly` and `temporary` as parameters. These parameters are already covered in the `Document` class [section](#document).
+
+Under the hood, `Dossier` uses [files](https://en.wikipedia.org/wiki/Computer_file) and [JSON](https://en.wikipedia.org/wiki/JSON) to store data.
+
+## Example
+Let's create a dossier with **script_1.py**:
+
+```python
+# script_1.py
+from shared import Dossier
+
+# data
+people = {"Jack": "male", "Jane": "female"} # dict
+planets = ["Mars", "Venus", "Jupiter"] # list
+colors = {"red", "green", "blue"} # set
+
+# let's persist the data in 'my-dossier'
+dossier = Dossier("my-dossier")
+dossier.set("people", people) # set the 'people' entry
+dossier.set("planets", planets) # set the 'planets' entry
+dossier.set("colors", colors) # set the 'colors' entry
+
+# Done ! The data is persisted !
+```
+
+From **script_2.py**, let's access the dossier created with **script_1.py**:
+```python
+# script_2.py
+from shared import Dossier
+
+# let's access the shared dossier
+dossier = Dossier("my-dossier")
+
+# get data from the shared dossier
+people = dossier.get("people") # get the 'people' entry
+planets = dossier.get("planets") # get the 'planets' entry'
+colors = dossier.get("colors") # get the 'colors' entry
+
+print(people)
+# output: {'Jack': 'male', 'Jane': 'female'}
+
+print(planets)
+# output: ['Mars', 'Venus', 'Jupiter']
+
+print(set(colors)) # there is nothing called 'set' in JSON [1]
+# output: {'red', 'green', 'blue'}
+
+
+# [1] the value of 'colors' is this dictionary:
+# {'red': None, 'green': None, 'blue': None}
+```
+
+## Binary data
+You can store binary data with the same unified interface:
+
+```python
+# script_1.py
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+with open("/home/alex/selfie.png", "rb") as file:
+ data = file.read()
+ dossier.set("selfie", data) # set the 'selfie' entry
+
+# the 'set' method returns the path to the binary file that stores the binary entry
+```
+
+The above code can also be expressed like this:
+
+```python
+# script_1.py
+import pathlib
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+path = pathlib.Path("/home/alex/selfie.png")
+dossier.set("selfie", path) # set the 'selfie' entry
+
+# the 'set' method returns the path to the binary file that stores the binary entry
+```
+
+You can retrieve your binary data from another script:
+```python
+# script_2.py
+from shared import Dossier
+from shutil import copyfile
+
+dossier = Dossier("my-dossier")
+source_path = dossier.get("selfie") # get the filename of the 'selfie' bin entry
+destination_path = "/home/alex/new.png"
+
+# copy the content from source to destination
+copyfile(source_path, destination_path)
+
+```
+
+## Check
+Use the `check` method to check the contents of a dossier or a specific entry:
+
+```python
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+# check a specific entry
+info = dossier.check("entry")
+if info:
+ # info is a 3-tuple (name, container, filename).
+ # The name is simply the entry name.
+ # The container is a string that represents the type of the entry.
+ # containers: "dict", "list", "set", and "bin"
+ # The filename is either the path to a JSON file or a binary file
+ name, container, filename = info
+
+# check the contents of the dossier
+dossier_info = dossier.check() # returns a dict, keys are entries and values are 3-tuples
+
+for entry, info in dossier_info.items():
+ print("Entry:", info.name) # the entry name
+ print("Container:", info.container) # 'dict', 'set', 'list', or 'bin'
+ print("Filename:", info.filename) # the underlying file in which the data is stored
+ print()
+```
+
+
+## Clear data
+You can decide to delete a specific entry, a group of entries, or the dossier:
+
+```python
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+# delete a specific entry
+dossier.delete("entry_1")
+
+# delete a group of entries
+dossier.delete("entry_2", "entry_3")
+
+# delete the dossier
+dossier.delete() # collections, binary data, and meta data are gone
+```
+
+## Recapitulation
+To store collections and binary data in a dossier **without worrying about how they are actually saved**, the `Dossier` class is the interface to use.
+
+For more technical details about this class, read its [documentation](https://github.com/pyrustic/shared/blob/master/docs/modules/content/shared/content/classes/Dossier.md#class-dossier).
+
+
+# Database
+Intuitive interaction with **SQLite** databases.
+
+## Example
+The following example shows how nice it is to work with the `Database` class:
+
+```python
+from shared import Database
+
+# Initialization script
+# This SQL script will create two tables: friends and projects
+INIT_SCRIPT = """\
+CREATE TABLE friends (name TEXT PRIMARY KEY,
+ age INTEGER NOT NULL);
+
+CREATE TABLE projects (name TEXT PRIMARY KEY,
+ language TEXT NOT NULL);
+"""
+
+# If this database doesn't exist yet,
+# it will be created with the initialization script
+database = Database("my-database", init_script=INIT_SCRIPT)
+
+# This will only be executed once !
+# So you can safely restart this script again and again...
+if database.new:
+ # Populate this database
+ sql = """INSERT INTO friends VALUES ("Jack", 20)"""
+ database.edit(sql)
+
+ # few lines of code later...
+
+ # Populate this database
+ sql = """INSERT INTO friends VALUES (?, ?)"""
+ parameters = ("Jane", 21)
+ database.edit(sql, param=parameters)
+
+# Read data
+sql = "SELECT * FROM friends"
+columns, data = database.query(sql) # returns a shared.dto.QueryResult namedtuple
+
+print(columns)
+# output: ['name', 'age']
+
+print(data)
+# output: [('Jack', 20), ('Jane', 21)]
+
+```
+
+For more technical details about this class, read its [documentation](https://github.com/pyrustic/shared/blob/master/docs/modules/content/shared/content/classes/Database.md#class-database).
+
+
+# Command line interface
+**Shared** comes with an intuitive command line interface for the `Dossier` class. Type `help` in the command line interface to display a short manual.
+
+For the following subsections, assume we have a pre-populated dossier named `my-dossier` and located in `/home/alex/dossiers`.
+
+## Check the content
+Check the contents of `my-dossier` or a specific entry:
+```bash
+$ cd /home/alex/dossiers/my-dossier
+
+$ shared check
+- 'colors' set 56B
+- 'people' dict 44B
+- 'planets' list 42B
+
+$ shared check people
+'people' dict 44B
+
+$ shared check colors
+'colors' set 56B
+```
+
+## Read the content of a specific entry
+
+```bash
+$ cd /home/alex/dossiers/my-dossier
+
+$ shared get people
+{
+ "Jack": "male",
+ "Jane": "female"
+}
+
+$ shared get planets
+[
+ "Mars",
+ "Venus",
+ "Jupiter"
+]
+
+shared get colors
+{
+ "red": null,
+ "blue": null,
+ "green": null
+}
+
+```
+The output text is the exact **JSON** representation as stored in a file. So the **output can be consumed as is** by another program and deserialized with a **JSON** library. Note that the `colors` entry is a `set` but represented as a `dict` in **JSON**.
+
+## Store binary data
+```bash
+$ shared set selfie bin: '/home/alex/selfie.png'
+Entry successfully updated !
+```
+
+You can copy a binary entry into an arbitrary file from the command line:
+
+```bash
+$ shared get selfie > '/home/alex/selfie-copy.png'
+```
+
+## Store a collection
+```bash
+$ shared set countries list: '/home/alex/countries.json'
+Entry successfully updated !
+
+$ shared set my_config dict: '/home/alex/app_config.json'
+Entry successfully updated !
+```
+
+## Delete an entry
+
+```bash
+$ shared del "selfie"
+Entry successfully deleted !
+
+$ shared check selfie
+This entry doesn't exist.
+```
+
+## Delete a dossier
+Right-click on the folder with your mouse, then send it safely to the trash... ;)
+
+# Miscellaneous
+
+
+# Installation
+**Shared** is **cross platform** and versions under **1.0.0** will be considered **Beta** at best. It should work on **Python 3.5** or [newer](https://www.python.org/downloads/).
+
+## For the first time
+
+```bash
+$ pip install shared
+```
+
+## Upgrade
+```bash
+$ pip install shared --upgrade --upgrade-strategy eager
+
+```
+
+## Show information
+```bash
+$ pip show shared
+```
+
+
+<br>
+<br>
+<br>
+
+[Back to top](#readme)
+
+
+
+
+%package help
+Summary: Development documents and examples for shared
+Provides: python3-shared-doc
+%description help
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+[![PyPI package version](https://img.shields.io/pypi/v/shared)](https://pypi.org/project/shared)
+[![Downloads](https://pepy.tech/badge/shared)](https://pepy.tech/project/shared)
+
+<!-- Cover -->
+<div align="center">
+ <img src="https://raw.githubusercontent.com/pyrustic/misc/master/assets/shared/cover.png" alt="Cover" width="541">
+ <p align="center">
+ <i> </i>
+ </p>
+</div>
+
+
+
+# Pyrustic Shared
+**Data exchange and persistence**
+
+This project is part of the [Pyrustic Open Ecosystem](https://pyrustic.github.io).
+> [Installation](#installation) . [Latest](https://github.com/pyrustic/shared/tags) . [Modules](https://github.com/pyrustic/shared/tree/master/docs/modules#readme)
+
+## Table of contents
+- [Overview](#overview)
+- [Document](#document)
+- [Dossier](#dossier)
+- [Database](#database)
+- [Command line interface](#command-line-interface)
+- [Miscellaneous](#miscellaneous)
+- [Installation](#installation)
+
+# Overview
+**Shared** is a Python package created to be the programmer's companion when it comes to storing application data, managing configuration files, caching data, and exchanging data with other programs.
+
+Although a lightweight package, **Shared** smoothly handles collections (**dict**, **list**, **set**), **binary** data, and **SQL** queries.
+
+## Designed as a triptych
+
+**Shared**'s intuitive application programming interface is designed as a [triptych](https://en.wikipedia.org/wiki/Triptych). Thus, three classes with similar interfaces are created to cover the needs of data exchange and persistence: `Document`, `Dossier`, and `Database`.
+
+|Class|Relevance|
+|---|---|
+|`Document`|For individual access to [Jesth](https://github.com/pyrustic/jesth#readme) and [JSON](https://en.wikipedia.org/wiki/JSON) files that are likely to be **manually edited by a human**.|
+|`Dossier`|To store collections and binary data in a dossier **without worrying about how they are actually saved**.|
+|`Database`|For an intuitive interaction with [SQLite](https://www.sqlite.org) **databases**.|
+
+> **Note:** The `Document` class is not intended to be used directly. Instead, depending on the requirement, one will use the `JsonDoc` or `JesthDoc` class which subclasses the `Document` class.
+
+## Some characteristics
+Since all three classes share similar interfaces, some handy functionality has been replicated in all of them with a few exceptions.
+
+### Initialization
+All three classes emphasize **initialization**:
+- `Document` and `Dossier` give the possibility to define **default data**.
+- `Database` allows the definition of an **initialization SQL script** which is only executed to create a new database.
+
+### Data access
+All three classes provide an optional **read-only** access to data and also allow the creation of **temporary data** which is automatically deleted when the user closes the application.
+
+`Document` and `Dossier` provide **Autosave** functionality, while `Database` automatically closes the underlying database connection when the user closes the application.
+
+### Command-line interface
+
+Among the three classes, `Dossier` is the class of which a single instance can handle multiple underlying files. The `Dossier` class has its own protocol for organizing data. For this reason, `Dossier` offers a simple yet powerful **command-line interface** that allows other programs or a human to read and write the contents of a dossier.
+
+<br>
+
+Let's explore the [Document](#document), [Dossier](#dossier), and [Database](#database) classes in the next sections !
+
+# Document
+The `Document` class represents an interface for reading and writing an underlying file whose format is either [Jesth](https://github.com/pyrustic/jesth#readme) or [JSON](https://en.wikipedia.org/wiki/JSON).
+
+As stated previously in the [Overview](#overview) section, the `Document` class is not intended to be used directly. Instead, depending on the requirement, one will use the `JsonDoc` or `JesthDoc` class which subclasses the `Document` class.
+
+Since **JSON** is very popular, we will focus on the `JsonDoc` class in the following examples.
+
+Accessing a document or creating a new one is as simple as this:
+
+```python
+from shared import JsonDoc
+
+# Create a new document instance which will be linked to the 'my-data.json' file.
+# If this file doesn't exist yet, it will be automatically created
+document = JsonDoc("my-data.json")
+
+# From now, we can use 'document' to read and write the contents of 'my-data.json' !
+# ...
+```
+
+The string `my-data.json` is the base name of a file that will be created if it does not yet exist. This string is called **Target** and can be an absolute path or an instance of [pathlib.Path](https://docs.python.org/3/library/pathlib.html). The `Document` class exposes the `read` and `write` methods, respectively, to read and write the underlying document.
+
+
+
+## Initialization
+A document can be initialized with a conditional statement or by defining default data. By default, the `Document` class will assign a `dict` to the null parameter `default_data`.
+
+### Use a conditional statement
+It's as simple as testing a boolean to check if the underlying document file is newly created or not:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json")
+
+# let's initialize the content of 'my-data.json'
+if document.new:
+ data = {"name": "alex", "job": "evangelist"}
+ document.write(data) # persisted !
+```
+
+### Set default data
+The most elegant, less verbose and recommended way to initialize a document is to set some default data to the `default` parameter:
+
+```python
+from shared import JsonDoc
+
+# default data to init the file 'my-data.json'
+DEFAULT_DATA = {"name": "alex", "job": "evangelist"}
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", default=DEFAULT_DATA)
+
+# From now, thanks to the initialization functionality, the underlying
+# document contains the default data, assuming that 'my-data.json'
+# did not exist before the `Document` class was instantiated
+```
+
+## Data location
+The only mandatory argument to be supplied to the `Document` class constructor is the `target`. For convenience, the `target` is either the absolute path or the base name of a file. Its data type is either a string or an instance of [pathlib.Path](https://docs.python.org/3/library/pathlib.html).
+
+The optional `directory` parameter exists to supplement the `target` value when that value is not an absolute path.
+
+### Default directory
+By default, document files are saved in `$HOME/PyrusticHome/shared`. You can change the location according to your needs:
+
+```python
+from shared import JsonDoc
+
+DIRECTORY = "/home/alex/private"
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", directory=DIRECTORY)
+
+# From now, you can access these properties:
+# document.name == "my-data.json"
+# document.directory == "/home/alex/private"
+# document.target == "my-data.json"
+
+```
+
+### Absolute pathname
+You can set an absolute path as the target. In this case, the `Document` class ignores the `directory` parameter.
+
+```python
+from shared import JsonDoc
+
+pathname = "/home/alex/private/my-data.json"
+
+# access 'my-data.json'
+document = JsonDoc(pathname)
+
+# From now, you can access these properties:
+# document.name == "my-data.json"
+# document.directory == "/home/alex/private"
+# document.target == "/home/alex/private/my-data.json"
+```
+
+### Temporary data
+Setting the `temporary` boolean can enable temporary mode, so a document can only be created and used while the application is running, and then safely deleted when the application closes:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", temporary=True)
+
+# This document will be created in a temporary directory
+# then it will be safely deleted when the application closes
+# or when the developer explicitly calls the 'close' or 'delete' method
+```
+
+The `Document` class uses [tempfile.TemporaryDirectory](https://docs.python.org/3/library/tempfile.html#tempfile.TemporaryDirectory) to implement this functionality.
+
+
+## Autosave
+Thanks to [atexit](https://docs.python.org/3/library/atexit.html) module, `Document` can autosave content when the application is closed:
+
+```python
+import sys
+from shared import JsonDoc
+
+# access 'my-config.json' with `autosave` mode enabled
+document = JsonDoc("my-config.json", autosave=True, default=[])
+# load the data
+data = document.read()
+
+# few lines of code later...
+
+data.append("batman") # data modified
+
+sys.exit() # data automatically saved !
+```
+Along with `atexit` module, the `Document` class also uses a caching mechanism to implement the `autosave` functionality.
+
+## Caching
+By default, `caching` mode is enabled, so the user can access cached data through the `cache` property of an instance of the `Document` class:
+
+```python
+from shared import JsonDoc
+
+DEFAULT_DATA = {"name": "alex", "job": "evangelist"}
+
+# access 'my-config.json'
+document = JsonDoc("my-config.json", caching=True, default=DEFAULT_DATA)
+
+data = document.read()
+
+if data is document.cache:
+ print("Same same !")
+```
+
+## Readonly
+Setting the `readonly` parameter to `True` prevents the running application from accidentally modifying the content of a document:
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json", readonly=True)
+
+# when you set readonly to True, you can no longer edit the content !
+# shared.ReadonlyError will be raised if you try to mess with a readonly document
+
+```
+
+## Clear data
+You can delete the underlying file of a document (assuming the file isn't in readonly mode):
+
+```python
+from shared import JsonDoc
+
+# access 'my-data.json'
+document = JsonDoc("my-data.json")
+
+# delete 'my-data.json'
+document.delete()
+
+if document.deleted:
+ print("Successfully deleted !")
+```
+
+## Convenience functions
+Four convenience functions are available for the `JsonDoc` class (also for the `JesthDoc` class):
+
+```python
+from shared import json_create, json_readonly, json_write, json_autosave
+
+# quickly create a document
+DEFAULT = ["red", "violet"]
+json_create("my-data.json", default=DEFAULT)
+
+# quickly open a document in readonly mode
+data = json_readonly("my-data.json")
+
+# quickly change the content of a document
+data = ["red", "green"]
+json_write("my-data.json", data)
+
+# quickly read the content of a document in autosave mode
+data = json_autosave("my-data.json")
+data.append("blue") # data will be automatically saved on exit
+```
+
+## Recapitulation
+For individual access to [Jesth](https://github.com/pyrustic/jesth#readme) and [JSON](https://en.wikipedia.org/wiki/JSON) files that are likely to be **manually edited by a human**, the `Document` class is the recommended interface.
+
+For more technical details about this class and the subclasses `JesthDoc` and `JsonDoc`, read the [reference documentation](https://github.com/pyrustic/shared/tree/master/docs/modules#readme).
+
+# Dossier
+The `Dossier` class stores collections (**list**, **dict**, **set**) and **binary data** with a unified interface inside a [dossier](https://dictionary.cambridge.org/dictionary/english/dossier). **Shared** allows to read and write a dossier not only programmatically but also from the [command line](#command-line-interface).
+
+This class shares a similar interface with the `Document` class. Thus, the `Dossier` class constructor has `target`, `directory`, `autosave`, `readonly` and `temporary` as parameters. These parameters are already covered in the `Document` class [section](#document).
+
+Under the hood, `Dossier` uses [files](https://en.wikipedia.org/wiki/Computer_file) and [JSON](https://en.wikipedia.org/wiki/JSON) to store data.
+
+## Example
+Let's create a dossier with **script_1.py**:
+
+```python
+# script_1.py
+from shared import Dossier
+
+# data
+people = {"Jack": "male", "Jane": "female"} # dict
+planets = ["Mars", "Venus", "Jupiter"] # list
+colors = {"red", "green", "blue"} # set
+
+# let's persist the data in 'my-dossier'
+dossier = Dossier("my-dossier")
+dossier.set("people", people) # set the 'people' entry
+dossier.set("planets", planets) # set the 'planets' entry
+dossier.set("colors", colors) # set the 'colors' entry
+
+# Done ! The data is persisted !
+```
+
+From **script_2.py**, let's access the dossier created with **script_1.py**:
+```python
+# script_2.py
+from shared import Dossier
+
+# let's access the shared dossier
+dossier = Dossier("my-dossier")
+
+# get data from the shared dossier
+people = dossier.get("people") # get the 'people' entry
+planets = dossier.get("planets") # get the 'planets' entry'
+colors = dossier.get("colors") # get the 'colors' entry
+
+print(people)
+# output: {'Jack': 'male', 'Jane': 'female'}
+
+print(planets)
+# output: ['Mars', 'Venus', 'Jupiter']
+
+print(set(colors)) # there is nothing called 'set' in JSON [1]
+# output: {'red', 'green', 'blue'}
+
+
+# [1] the value of 'colors' is this dictionary:
+# {'red': None, 'green': None, 'blue': None}
+```
+
+## Binary data
+You can store binary data with the same unified interface:
+
+```python
+# script_1.py
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+with open("/home/alex/selfie.png", "rb") as file:
+ data = file.read()
+ dossier.set("selfie", data) # set the 'selfie' entry
+
+# the 'set' method returns the path to the binary file that stores the binary entry
+```
+
+The above code can also be expressed like this:
+
+```python
+# script_1.py
+import pathlib
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+path = pathlib.Path("/home/alex/selfie.png")
+dossier.set("selfie", path) # set the 'selfie' entry
+
+# the 'set' method returns the path to the binary file that stores the binary entry
+```
+
+You can retrieve your binary data from another script:
+```python
+# script_2.py
+from shared import Dossier
+from shutil import copyfile
+
+dossier = Dossier("my-dossier")
+source_path = dossier.get("selfie") # get the filename of the 'selfie' bin entry
+destination_path = "/home/alex/new.png"
+
+# copy the content from source to destination
+copyfile(source_path, destination_path)
+
+```
+
+## Check
+Use the `check` method to check the contents of a dossier or a specific entry:
+
+```python
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+# check a specific entry
+info = dossier.check("entry")
+if info:
+ # info is a 3-tuple (name, container, filename).
+ # The name is simply the entry name.
+ # The container is a string that represents the type of the entry.
+ # containers: "dict", "list", "set", and "bin"
+ # The filename is either the path to a JSON file or a binary file
+ name, container, filename = info
+
+# check the contents of the dossier
+dossier_info = dossier.check() # returns a dict, keys are entries and values are 3-tuples
+
+for entry, info in dossier_info.items():
+ print("Entry:", info.name) # the entry name
+ print("Container:", info.container) # 'dict', 'set', 'list', or 'bin'
+ print("Filename:", info.filename) # the underlying file in which the data is stored
+ print()
+```
+
+
+## Clear data
+You can decide to delete a specific entry, a group of entries, or the dossier:
+
+```python
+from shared import Dossier
+
+dossier = Dossier("my-dossier")
+
+# delete a specific entry
+dossier.delete("entry_1")
+
+# delete a group of entries
+dossier.delete("entry_2", "entry_3")
+
+# delete the dossier
+dossier.delete() # collections, binary data, and meta data are gone
+```
+
+## Recapitulation
+To store collections and binary data in a dossier **without worrying about how they are actually saved**, the `Dossier` class is the interface to use.
+
+For more technical details about this class, read its [documentation](https://github.com/pyrustic/shared/blob/master/docs/modules/content/shared/content/classes/Dossier.md#class-dossier).
+
+
+# Database
+Intuitive interaction with **SQLite** databases.
+
+## Example
+The following example shows how nice it is to work with the `Database` class:
+
+```python
+from shared import Database
+
+# Initialization script
+# This SQL script will create two tables: friends and projects
+INIT_SCRIPT = """\
+CREATE TABLE friends (name TEXT PRIMARY KEY,
+ age INTEGER NOT NULL);
+
+CREATE TABLE projects (name TEXT PRIMARY KEY,
+ language TEXT NOT NULL);
+"""
+
+# If this database doesn't exist yet,
+# it will be created with the initialization script
+database = Database("my-database", init_script=INIT_SCRIPT)
+
+# This will only be executed once !
+# So you can safely restart this script again and again...
+if database.new:
+ # Populate this database
+ sql = """INSERT INTO friends VALUES ("Jack", 20)"""
+ database.edit(sql)
+
+ # few lines of code later...
+
+ # Populate this database
+ sql = """INSERT INTO friends VALUES (?, ?)"""
+ parameters = ("Jane", 21)
+ database.edit(sql, param=parameters)
+
+# Read data
+sql = "SELECT * FROM friends"
+columns, data = database.query(sql) # returns a shared.dto.QueryResult namedtuple
+
+print(columns)
+# output: ['name', 'age']
+
+print(data)
+# output: [('Jack', 20), ('Jane', 21)]
+
+```
+
+For more technical details about this class, read its [documentation](https://github.com/pyrustic/shared/blob/master/docs/modules/content/shared/content/classes/Database.md#class-database).
+
+
+# Command line interface
+**Shared** comes with an intuitive command line interface for the `Dossier` class. Type `help` in the command line interface to display a short manual.
+
+For the following subsections, assume we have a pre-populated dossier named `my-dossier` and located in `/home/alex/dossiers`.
+
+## Check the content
+Check the contents of `my-dossier` or a specific entry:
+```bash
+$ cd /home/alex/dossiers/my-dossier
+
+$ shared check
+- 'colors' set 56B
+- 'people' dict 44B
+- 'planets' list 42B
+
+$ shared check people
+'people' dict 44B
+
+$ shared check colors
+'colors' set 56B
+```
+
+## Read the content of a specific entry
+
+```bash
+$ cd /home/alex/dossiers/my-dossier
+
+$ shared get people
+{
+ "Jack": "male",
+ "Jane": "female"
+}
+
+$ shared get planets
+[
+ "Mars",
+ "Venus",
+ "Jupiter"
+]
+
+shared get colors
+{
+ "red": null,
+ "blue": null,
+ "green": null
+}
+
+```
+The output text is the exact **JSON** representation as stored in a file. So the **output can be consumed as is** by another program and deserialized with a **JSON** library. Note that the `colors` entry is a `set` but represented as a `dict` in **JSON**.
+
+## Store binary data
+```bash
+$ shared set selfie bin: '/home/alex/selfie.png'
+Entry successfully updated !
+```
+
+You can copy a binary entry into an arbitrary file from the command line:
+
+```bash
+$ shared get selfie > '/home/alex/selfie-copy.png'
+```
+
+## Store a collection
+```bash
+$ shared set countries list: '/home/alex/countries.json'
+Entry successfully updated !
+
+$ shared set my_config dict: '/home/alex/app_config.json'
+Entry successfully updated !
+```
+
+## Delete an entry
+
+```bash
+$ shared del "selfie"
+Entry successfully deleted !
+
+$ shared check selfie
+This entry doesn't exist.
+```
+
+## Delete a dossier
+Right-click on the folder with your mouse, then send it safely to the trash... ;)
+
+# Miscellaneous
+
+
+# Installation
+**Shared** is **cross platform** and versions under **1.0.0** will be considered **Beta** at best. It should work on **Python 3.5** or [newer](https://www.python.org/downloads/).
+
+## For the first time
+
+```bash
+$ pip install shared
+```
+
+## Upgrade
+```bash
+$ pip install shared --upgrade --upgrade-strategy eager
+
+```
+
+## Show information
+```bash
+$ pip show shared
+```
+
+
+<br>
+<br>
+<br>
+
+[Back to top](#readme)
+
+
+
+
+%prep
+%autosetup -n shared-0.0.25
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-shared -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Wed May 10 2023 Python_Bot <Python_Bot@openeuler.org> - 0.0.25-1
+- Package Spec generated