Package: constellationPy
ConstellationPyCette librarie offre un clientConstellationpour Python. Elle fonctionne en lançant
unserveur ws Constellationlocal, avec lequel elle gère ensuite la communication par websocket.InstallationVous pouvez installer ConstellationPy avecpoetry:poetry add constellationPy... ou bien avecpippip install constellationPySi le serveur Constellation n'est pas déjà installé sur votre machine, ConstellationPy l'installera automatiquement pour
vous. Pour ce faire, vous devrez au tout minimum avoirNode.jsinstallé localement.UtilisationConstellationPy est une librariesasynchronebasée surtrio. Étant donné que le serveur
Constellation est fondamentalement asynchrone aussi, c'était la décision naturelle.Cependant, nous comprenons bien que la grande majorité des utilisatrices et utilisateurs de Python n'ont aucune idée de
ce qu'est la programmation asynchrone, ni aucun goût ou raison de l'apprendre. C'est pour cela que ConstellationPy vous
offre également un IPA synchrone.Vous ne savez pas ce que « synchrone » ou « asynchrone » veulent dire ? Ne vous en faites pas
et utilisez l'IPA synchrone. « Synchrone » est le terme technique pour le style de code « normal »
Python que vous connaissez bien. Si vous voulez en savoir plus,voiciune belle présentation de la différence
entre les deux (en JavaScript).Attention ! L'IPA synchrone fonctionne bien pour des petites tâches (p. ex., récupérer un ou deux jeux de données), mais
l'IPA asynchrone est beaucoup plus efficace si vous traitez de grands nombres de données ou de requêtes à Constellation.
Si vous avez besoin d'accéder beaucoup de différentes bases de données Constellation, peut-être que ça vaudrait la
peine, après tout,d'apprendrecomment utiliser ces drôles deasyncetawaiten
Python.IPA synchroneEn premier lieu, nous devons lancer le serveur Constellation. C'est absolument nécessaire, à moins que vous n'aviez déjà
lancé un serveur Constellationmanuellement, lorsque, par
exemple, vous voulez exécuter plusieurs codes Python qui utilisent Constellation en parallèle sans dupliquer le
serveur (oui, c'est bien possible) !Donc, on commence. La façon la plus sure, c'est d'utiliser un blocwith, car celui-ci fermera automatiquement le
serveur une fois que vous aurez terminé avec.Cette syntaxe permettra aussi au client Constellation de détecter
automatiquement le port auquel il devra se connecter.fromconstellationPyimportServeur,ClientSyncwithServeur():client=ClientSync()données=client.appelerUneFonction()...Vous pouvez aussi lancer le client Constellation manuellement. Cette option est particulièrement utile si vous voulez
obtenir les données les plus à jour du réseau.
N'oubliez pas que Constellation est unréseaud'utilisatrices et d'utilisateurs comme vous ! Il n'y
a donc pas de « serveur central » Constellation en tant que tel pour garder une copie des données.
Si les données qui vous intéressent sont sur
l'ordinateur ou le téléphone d'une autre participante au réseau, cela peut prendre un peu de temps
pour que votre nœud local puisse se connecter à la nuée d'autres nœuds Constellation et reçoive
les données les plus récentes. Comme règle générale, le plus longtemps le nœud reste en ligne,
le plus de connexions et de données il obtiendra.Vous pouvez donc lancer votre nœud local à l'aide de la ligne de commande. Vous pouvez utiliser
n'importe quel port libre (ici 5001). Vous pouvez le laisser rouler aussi longtemps que vous voudrez,
il y se synchronisera automatiquement avec le réseau Constellation.
Tout client pyConstellation que vous lancerez en même temps obtiendra ainsi les données les plus
à jour disponibles.Note : pour installer Constellation pour la première fois, faites rouler le code suivant une seule
fois sur votre ordinateur :fromconstellationPyimportmettre_constellation_à_jourmettre_constellation_à_jour()Vous pourrez ensuite invoquer le serveur Constellation ainsi :constllancer--port5001-bVous ne savez pas quel port mettre ? Lancez tout simplementconstl lanceret puis Constellation
vous donnera le numéro du port libre qu'elle aura trouvé.Vu que vous avez déjà lancé votre propre serveur Constellation, vous devrez spécifier le port manuellement dans le client :fromconstellationPyimportClientSyncclient=ClientSync(port=5001)...Note : vous pouvez également spécifier le port du client surClientetouvrir_client(voir ci-dessous).Fonctions disponiblesToutes* les fonctions de l'IPA (Interface de programmation
d'application)Constellationsont disponibles.Note : vous pouvez appeler les fonctions Constellation en forme kebab (ma_fonction, style Python)
ou bien chameau (maFonction, style JavaScript). À titre d'exemple :fromconstellationPyimportClientSync,ServeurwithServeur():client=ClientSync()résultatChameau=client.obtIdDispositif()résultat_kebab=client.obt_id_dispositif()print(résultatChameau==résultat_kebab)Vous pouvez également accéder les sous-objets de Constellation (profil,bds,tableaux, et ainsi de suite) :fromconstellationPyimportClientSync,ServeurwithServeur():client=ClientSync()client.profil.sauvegarder_nom(langue="fr",nom="moi !")client.bds.créer_bd(licence="ODbl-1.0")Fonctions bien commodesL'IPA du client Python vous offre aussi quelques fonctions plus commodes qui n'existent pas dans l'IPA original de
Constellation :fromconstellationPyimportClientSync,Serveurid_tableau="/orbitdb/zdpu..."withServeur():client=ClientSync()données=client.obt_données_tableau(id_tableau=id_tableau)Vous pouvez également obtenir les données en format Pandas, y compris avec les colonnes identifiées selon
le nom des variables correspondantes dans la langue de votre choix, si elle est disponible :fromconstellationPyimportClientSync,Serveurid_tableau="/orbitdb/zdpu..."withServeur():client=ClientSync()données=client.obt_données_tableau(id_tableau=id_tableau,langues=["fr","es"],formatDonnées="pandas")Quelques points importantsLes fonctions plus obscures qui prennent plus qu'une autre fonction comme argument (p.
ex.client.suivreBdDeFonction) ne fonctionnent pas avec le client Python. Ne vous en faites pas. Elles sont obscures
pour une raison. Laissez-les en paix. Vous avez amplement de quoi vous amuser avec le reste de l'IPA.Vousdevezutiliser des paramètres nommés (p. ex.,client.bds.créerBd(licence="ODbl-1.0")). Si vous ne le
faites pas (client.bds.créerBd("ODbl-1.0")), ça va vous créer des ennuis. Les noms des paramètres doivent être
les mêmes que dans l'IPA Constellation JavaScript (p. ex., l'exemple précédent provient de la version JavaSCriptclient.bds.créerBd({ licence: "ODbl-1.0" })).Avec le client synchrone, les fonctions de suivi (voir ci-dessous) doivent être appelées avec une fonction vide (p.
ex.,lambda: passou bien tout simplementfais_rien) à la place de la fonction de suivi.Vous vous demandez où trouver tous ces drôles de « id tableau » pour les bases de données qui vous intéressent ? Il
s'agit de l'identifiant unique d'un tableau ou d'une base de données, que vous pouvez récupérer lorsque vous créez la
base de données, ou bien visuellement avec
l'appli Constellation(recherchez l'icône lien 🔗).Fonctions de suiviConstellation, dans sa version asynchrone JavaScript, offre des fonctions qui, plutôt que de rendre le résultat
immédiatement,suiventle résultat à travers le temps et vous notifient (selon une fonction que vous choisissez)
chaque fois que le résultat change. La grande majorité des fonctions utiles de l'IPA de Constellation (p.
ex.,client.tableaux.suivreDonnées) sont de ce genre.Évidemment, ce comportement n'est pas util dans un programme synchrone. Le client synchroneClientSyncs'occupe donc de vous rendre le résultat, sans tracas. Il vous suffira de passer une fonction vide là où la fonction
originale s'attendait à avoir la fonction de suivi. Par exemple, si l'on appellerait la fonction comme suit dans
Constellation JavaScript,constdonnées=awaitclient.tableaux.suivreDonnées({idTableau:id_tableau,f:fSuivi});Ici, en Python, nous ferons ainsi :fromconstellationPyimportClientSync,Serveur,fais_rienid_tableau="/orbitdb/zdpu..."withServeur():client=ClientSync()mes_données=client.tableaux.suivre_données(id_tableau=id_tableau,f=fais_rien)IPA asynchroneL'IPA asynchrone doit être utilisée avectrio. Il a les mêmes fonctions que l'IPA
synchrone, mais dois être invoqué dans un blocasync with ouvrir_client() as client:importtriofromconstellationPyimportServeur,ouvrir_clientid_tableau="/orbitdb/zdpu..."asyncdefprincipale():withServeur():asyncwithouvrir_client()asclient:données=awaitclient.obt_données_tableau(id_tableau=id_tableau)print(données)...trio.run(principale)Fonctions de suivi etune_foisTel que mentionné ci-dessus, la majorité des fonctions utiles de Constellation sont des fonctions de suivi. Nous devons
les appeler avec une fonction qui sera invoquée à chaque fois que le résultat sera mis à jour.importtriofromconstellationPyimportServeur,ouvrir_clientid_tableau="/orbitdb/zdpu..."asyncdefprincipale():withServeur():asyncwithouvrir_client()asclient:# Suivre les données du réseau pour 15 secondes, et imprimer les résultats au fur et à mesure# qu'ils nous parviennent du réseauoublier_données=awaitclient.tableaux.suivre_données(id_tableau=id_tableau,f=print)awaittrio.sleep(15)oublier_données()# Maintenant, on ne recevra plus les mises à jour des donnéestrio.run(principale)Mais en Python, il est probable que, au lieu de vouloir suivre le résultat de la fonction à travers le temps, vous
préférerez obtenir les données présentes et puis poursuivre vos analyses. La fonctionune_foisvous permet de faire justement cela :importtriofromconstellationPyimportServeur,ouvrir_client,une_foisid_tableau="/orbitdb/zdpu..."asyncdefprincipale():withServeur():asyncwithouvrir_client()asclient:# On doit définir une fonction auxiliaire qui ne prend que la fonction de suivi# en tant qu'argumentasyncdeff_données(f):returnawaitclient.tableaux.suivre_données(id_tableau=id_tableau,f=f)# La fonction `une_fois` appellera `f_données`, attendra le premier résultat,# et nous renverra celui-ci.données=awaitune_fois(f_données,client)returndonnéesmes_données=trio.run(principale)print(mes_données)Utilisation avancéeVoici un exemple un peu plus avancé. Si vous avez plusieurs coroutines Python que vous voulez exécuter en parallèle avec
Constellation, vous pouvez créer une pouponnièretrioet la réutiliser pour les deux coroutines en invoquantClientdirectement.importtriofromconstellationPyimportClientrésultats={}asyncdefcoroutine1(client):données=awaitclient.appelerUneFonction()résultats["1"]=donnéesasyncdefcoroutine2(client):données=awaitclient.appelerUneFonction()résultats["2"]=donnéesasyncdefprincipale():asyncwithtrio.open_nursery()aspouponnière:asyncwithClient(pouponnière)asclient:awaitclient.connecter()# À ne pas oublier ! Sinon je ne suis pas responsable.pouponnière.start_soon(coroutine1,client)pouponnière.start_soon(coroutine2,client)trio.run(principale)print(résultats)Ceci peut aussi être utile avec
lescanauxdetriopour communiquer entre les coroutines :importtriofromconstellationPyimportClientid_tableau="/orbitdb/zdpu..."asyncdefcoroutine_constellation(pouponnière,canal_envoie):asyncwithClient(pouponnière)asclient:awaitclient.connecter()# À ne pas oublier ! Sinon je ne suis pas responsable.données=awaitclient.obt_données_tableau(id_tableau=id_tableau)asyncwithcanal_envoie:awaitcanal_envoie.send(données)asyncdefune_autre_coroutine(canal_réception):asyncwithcanal_réception:asyncformessageincanal_réception:print(message)# En réalité, faire quelque chose d'asynchrone, comme écrire au disqueasyncdefprincipale():asyncwithtrio.open_nursery()aspouponnière:canal_envoie,canal_réception=trio.open_memory_channel(0)pouponnière.start_soon(coroutine_constellation,pouponnière,canal_envoie)pouponnière.start_soon(une_autre_coroutine,canal_réception)trio.run(principale)Traitement des erreursVous pouvez aussi initialiserClientavec un canaltriopour recevoir les erreurs. Si le client ou le serveur
encontre une erreur, celle-ci sera envoyée au canal erreur au lieu de soulever une erreur et d'arrêter exécution du
programme. Cette option peut être utile lorsque vous ne voulez pas qu'une erreur sur une requête arrête toute
l'exécution du logiciel.importtriofromconstellationPyimportServeur,Clientasyncdefcoroutine_client(pouponnière,canal_envoie_erreur):asyncwithcanal_envoie_erreur:asyncwithClient(pouponnière)asclient:awaitclient.connecter(canal_envoie_erreur)# À ne pas oublier ! Sinon je ne suis pas responsable.# Faire quelque chose avec le clientasyncdefcoroutine_erreurs(canal_reçoie_erreurs):asyncwithcanal_reçoie_erreurs:asyncforerreurincanal_reçoie_erreurs:print(erreur)# Ou écrire à un fichier journal sur le disque...asyncdefprincipale():withServeur():asyncwithtrio.open_nursery()aspouponnière:canal_envoie_erreur,canal_reçoie_erreur=trio.open_memory_channel(0)pouponnière.start_soon(coroutine_client,pouponnière,canal_envoie_erreur)pouponnière.start_soon(coroutine_erreurs,canal_reçoie_erreur)trio.run(principale)