libs.zazac.link

simplesuit.json v0.2.1

Un fichier JSON utilisé comme un petit dictionnaire qui reste

Inclus dans simplesuit : installe simplesuit pour l'avoir.

import simplesuit.json · PyPI : simplesuit · Python 3.9+ · dépend de psutil

Guide

Un fichier JSON utilisé comme un petit dictionnaire qui reste après la fermeture du programme : réglages, scores, liste d'utilisateurs, compteur de lancements… Une ligne pour écrire, une ligne pour relire, pas de open() ni de json.load() à écrire.

L'essentiel#

python
from simplesuit import json as sj

sj.put("theme", "sombre")          # Écrire (crée data.json si besoin)
sj.put("volume", 70)

sj.get("theme")                    # "sombre"
sj.get("langue", "fr")             # "fr" : la clé n'existe pas, valeur par défaut
sj.has("volume")                   # True
sj.delete("volume")                # Supprimer une clé (True si elle existait)

sj.load()                          # Tout le fichier, en dict
sj.show()                          # Tout le fichier, joliment, en couleurs
résultat
# data.json
{
    "theme": "sombre"
}

Chaque fonction relit le fichier et chaque écriture le sauvegarde tout de suite : si le programme plante ou que tu le fermes, rien n'est perdu.

Où est le fichier ?#

Par défaut, data.json, à côté du script lancé, pas dans le dossier où tu te trouves dans le terminal. python3 ~/projets/jeu/main.py lancé depuis n'importe où utilise toujours ~/projets/jeu/data.json.

python
sj.set("users.json")               # Change de fichier pour tous les appels suivants
sj.get_file()                      # Le chemin complet du fichier utilisé
sj.get("score", file="scores.json")  # Un autre fichier juste pour cet appel

Des listes qui grandissent#

append(cle, valeur) ajoute à la liste d'une clé, et crée la liste si la clé n'existe pas encore. Il renvoie la liste complète.

python
sj.set("users.json")
sj.append("users", {"name": "Zoe", "age": 14})
users = sj.append("users", {"name": "Izac", "age": 15})
print(len(users), "utilisateurs")

for user in sj.get("users", []):
    print(user["name"])
résultat
2 utilisateurs
Zoe
Izac

append sur une clé qui n'est pas une liste

Si "users" contient déjà un dict ou un texte, append refuse avec TypeError: simplesuit.json : 'users' n'est pas une liste (dict), utilise put(). Dans le fichier, une liste s'écrit avec des crochets : "users": [ … ].

put remplace, il n'ajoute pas

sj.put("user", nouveau) écrase l'ancienne valeur : il ne reste qu'un seul utilisateur. Pour en garder plusieurs, c'est append sur une liste.

Afficher joliment#

sj.show() affiche le fichier avec des couleurs (clés en bleu, textes en vert, nombres en orange…) et un retour à la ligne par valeur. Il marche aussi avec n'importe quel dict ou liste :

python
sj.show()                          # Le fichier actuel
sj.show("users.json")              # Un autre fichier
sj.show({"ok": True, "n": 3})      # Un dict (par exemple une réponse de capy)
texte = sj.pretty(sj.load())       # Le même texte, sans l'afficher

Pas de couleurs dans un fichier

Redirigé vers un fichier (python3 main.py > sortie.txt), show() enlève les couleurs tout seul. Pour les forcer ou les enlever : sj.show(colors=True) / sj.show(colors=False).

Récupérer une valeur dans une liste#

Les fonctions travaillent sur les clés du haut du fichier. Pour chercher dans une liste, on la parcourt :

python
def trouver(nom):
    for user in sj.get("users", []):
        if user["name"] == nom:
            return user
    return None

print(trouver("Zoe"))      # {'name': 'Zoe', 'age': 14}

Pour modifier un élément : on relit, on change, on réécrit.

python
users = sj.get("users", [])
for user in users:
    if user["name"] == "Zoe":
        user["age"] += 1
sj.put("users", users)

Astuces et pièges#

Une valeur par défaut, toujours

sj.get("score", 0) plutôt que sj.get("score") : au 1er lancement, la clé n'existe pas encore et tu évites un None qui fait planter + 1.

Seulement des types JSON

Textes, nombres, True/False, None, listes et dicts. Un set, un tuple (relu comme une liste) ou une date ne survivent pas : convertis-les avant (list(...), date.isoformat()).

Les clés deviennent du texte

En JSON, une clé est toujours un texte : sj.put("scores", {1: 50}) se relit {"1": 50}.

Pas pour plusieurs programmes en même temps

Si deux programmes (ou deux threads d'un serveur capy) écrivent le même fichier au même moment, l'un peut écraser l'autre. Pour un serveur, protège tes écritures avec un threading.Lock().

Et pour beaucoup de données ?

Chaque appel relit tout le fichier : c'est parfait jusqu'à quelques milliers d'éléments. Au-delà, ou pour des recherches compliquées, passe à sqlite3 (inclus dans Python).

Exemples

Sauvegarder des réglages

Un fichier JSON utilisé comme un petit dictionnaire qui reste après la fermeture du programme. Le fichier (data.json par défaut) est créé à côté du script lancé.

reglages.py
from simplesuit import json as sj

sj.put("theme", "sombre")
sj.put("volume", 70)
sj.put("favoris", ["capy", "simplesuit"])

print(sj.get("theme"))                  # sombre
print(sj.get("langue", default="fr"))   # fr (la clé n'existe pas encore)
print(sj.has("volume"))                 # True
print(sj.load())                        # tout le fichier, en dict

sj.delete("volume")
print(sj.get_file())                    # chemin du fichier utilisé

Compter les lancements

Le nombre augmente à chaque fois que tu relances le script.

compteur.py
from simplesuit import json as sj

lancements = sj.get("lancements", 0) + 1
sj.put("lancements", lancements)

print(f"Ce script a été lancé {lancements} fois")

Plusieurs fichiers

set() choisit le fichier pour toutes les fonctions ; file= pour un seul appel.

plusieurs_fichiers.py
from simplesuit import json as sj

sj.set("scores.json")
sj.put("alice", 120)
sj.put("bob", 95)

sj.put("derniere_partie", "2026-10-18", file="historique.json")

meilleur = max(sj.load(), key=sj.load().get)
print("Meilleur score :", meilleur)                     # alice
print(sj.get("derniere_partie", file="historique.json"))

sj.clear()  # Vide scores.json

Une liste qui grandit, et un bel affichage

append() ajoute à la liste d'une clé (et la crée si elle n'existe pas encore). show() affiche le fichier avec des couleurs et des retours à la ligne.

liste_et_affichage.py
from simplesuit import json as sj

sj.set("users.json")

sj.append("users", {"name": "Zoe", "age": 14, "id": 30})
sj.append("users", {"name": "Izac", "age": 15, "id": 31})

sj.show()                    # Tout le fichier, en couleurs
sj.show({"ok": True})        # Marche aussi avec un dict
texte = sj.pretty(sj.load()) # Le même texte coloré, sans l'afficher

Référence

Fonctions

set(file)

Choisir le fichier json à utiliser

Exset("users.json")

Voir le code
python
def set(file):
    global current_file  # Modifie la variable du module, pas une variable locale
    current_file = _path(file)

get_file()

Savoir quel fichier est utilisé

Voir le code
python
def get_file():
    return current_file

load(file=None) -> dict

Lire tout le fichier -> renvoie un dict

Voir le code
python
def load(file=None) -> dict:
    path = _path(file)
    # Fichier absent ou vide -> dict vide au lieu de planter
    if not path.exists() or path.read_text().strip() == "":
        return {}
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)

save(data, file=None)

Écrire tout le dict dans le fichier (écrase l'ancien contenu)

Voir le code
python
def save(data, file=None):
    with open(_path(file), "w", encoding="utf-8") as f:
        json.dump(data, f, indent=4, ensure_ascii=False)

clear(file=None)

Tout effacer

Voir le code
python
def clear(file=None):
    save({}, file)

get(key, default=None, file=None) -> Any

Lire une valeur (default si la clé n'existe pas)

-> Any : la valeur peut être de n'importe quel type (sinon Pylance croit qu'elle vaut None)

Voir le code
python
def get(key, default=None, file=None) -> Any:
    return load(file).get(key, default)

put(key, value, file=None)

Écrire / modifier une valeur

Voir le code
python
def put(key, value, file=None):
    data = load(file)
    data[key] = value
    save(data, file)

delete(key, file=None)

Supprimer une clé (renvoie True si elle existait)

Voir le code
python
def delete(key, file=None):
    data = load(file)
    if key not in data:
        return False
    del data[key]
    save(data, file)
    return True

has(key, file=None)

Vérifier si une clé existe

Voir le code
python
def has(key, file=None):
    return key in load(file)

append(key, value, file=None) -> list

Ajouter une valeur à la liste d'une clé (crée la clé si elle n'existe pas)

Exappend("users", {"name": "Zoe"}) -> {"users": [{"name": "Zoe"}]}

Renvoie la liste complète

Voir le code
python
def append(key, value, file=None) -> list:
    data = load(file)
    items = data.setdefault(key, [])
    if not isinstance(items, list):
        raise TypeError(f"simplesuit.json : '{key}' n'est pas une liste ({type(items).__name__}), utilise put()")
    items.append(value)
    save(data, file)
    return items

show(data=None, file=None, colors=None)

Afficher joliment le fichier (ou un dict / une liste) : couleurs + indentation

Exshow() / show("users.json") / show({"a": 1})

Sans couleurs si la sortie n'est pas un terminal (ex : python3 main.py > out.txt)

Voir le code
python
def show(data=None, file=None, colors=None):
    if colors is None:
        colors = sys.stdout.isatty()
    if data is None or isinstance(data, (str, pth.Path)):
        path = _path(data if data is not None else file)
        print(_paint(f"# {path.name}", "punct", colors))
        data = load(path)
    print(pretty(data, colors))

pretty(data, colors=True, indent=4)

Le texte coloré de show(), sans l'afficher

Voir le code
python
def pretty(data, colors=True, indent=4):
    return _pretty(data, colors, indent, 0)

Constantes

BASE_DIR

Les chemins relatifs partent du dossier du script,

peu importe d'où on lance le programme

BASE_DIR = _main_dir()

THEME

Couleurs de show() (thème Catppuccin Mocha)

key'mochablue'
str'mochagreen'
number'mochapeach'
bool'mochamauve'
null'mochared'
punct'mochaoverlay1'