%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

# 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.
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 ```


[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

# 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.
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 ```


[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

# 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.
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 ```


[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 - 0.0.25-1 - Package Spec generated