Surveiller si fichier modifié par d'autres programmes

bonjour à tou[te]s

petit souci dans le script :

#!/usr/bin/python -Bu
# -*- coding: utf-8 -*-
import gi,sys
gi.require_version("Gtk","4.0")
from gi.repository import Gtk,Gio
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
class call():
	def back(a,b,c,evt,*_):
		print("*"+str(evt)+"*")
class ecran(Gtk.ApplicationWindow):
	def __init__(self,app,*args,**kwargs):
		Gtk.ApplicationWindow.__init__(self,application=app)
		btn=Gtk.Button(label=	"surveillance de "+sys.argv[0]+
								"\ncliquer pour quitter")
		btn.connect("clicked",self.quitter)
		self.set_child(btn)
		self.present()
		**#======== *mis ici, ça ne donne rien* ========**
**		fich=Gio.File.new_for_path(sys.argv[0])**
**		mon=fich.monitor_file(Gio.FileMonitorFlags.NONE,None)**
**		mon.connect("changed",call.back)**
**		#================**
	def quitter(self,*_):
		self.close()
app=Gtk.Application()
app.connect('activate',ecran)
**"""**
**#======== *mis ici, ça baigne* ========**
**fich=Gio.File.new_for_path(sys.argv[0])**
**mon=fich.monitor_file(Gio.FileMonitorFlags.NONE,None)**
**mon.connect("changed",call.back)**
**#================**
**"""**
app.run(sys.argv)

je tente de surveiller si un fichier est modifié par un autre programme
( pour le test, le script lui-même )
si je place le contrôle dans le corps du programme,
aucune réaction, alors qu’au lancement, ça marche
dans mon application j’ai besoin de mettre cette
surveillance “en dynamique”, au fur et à mesure
on peut faire comment ?
merci d’avance

J’ai tenté, mais je n’arrive même pas à installer la v4 de Gtk qui n’est pas compatible avec la v3…

Ah et sinon il doit y avoir moyen de surveiller un répertoire depuis le système (plus efficace je pense) et de remonter les signaux au programme qui gère suivant ce qu’il doit surveiller exactement. Mais je ne sais pas quelles sont tes contraintes.

merci pour votre intervention

oh que oui ! de plus, bonjour la doc pour gtk4 !
mais bon, le “problème” doit être le même en gtk3

en fait, à la demande, j’ouvre différents fichiers dans mon
programme, venant de n’importe quel répertoire,
je tente d’être prévenu si “quelqu’un d’autre”
les modifie

Quoi qu’il en soit, je suppose que ton code n’est appelé qu’une seule fois dans l’appli. C’est pour ça qu’il ne fonctionne pas je pense.

pas compris !?!
mais bon, en gérant cela “hors du
corps du programme”, réussi à
faire ce que je voulais
merci de votre aide

1 « J'aime »

Ce que je veux dire c’est que GTK doit gérer une “boucle d’événements” une fois l’application lancée. Le code qui crée l’écran est donc appelé pendant l’initialisation et tu modifies tes fichiers plus tard, donc plus géré par le code ?

Je n’utilise pas GTK donc peu pas aider la-dessus mais… Sur Windows et Linux quand tu regarde les propriétés d’un fichier tu a la date de création et la date de modification… En théorie si tu récupère cette deuxième info tout les 10 sec (pour ne pas surcharger le système pour rien) tu devrais savoir rapidement si modif ou pas non?
Je n’aurais pas pu t’aider plus.
avec un while et un truc qui ferait une pause de 10sec peut-être?.. Je pense toujours d’abord console/interpreteur donc je dit peut-être des bêtises mais perso j’aurais tendance a vouloir faire mes classfonctions en dehors du reste ne serais-ce que pour tester différentes valeurs et voir en print() les résultats. Exemple si je voulais changer la valeur d’un pixel d’image je “simulerais” les valeurs de couleurs du pixel a la main pour voir si l’interpreteur me rendrais ce que je veux puis je testerais sur une copie d’image de 10x10mixels maxi avec copie soit en texte soit dans une autre image et le tout en remplissant le répertoire de l’image a la main. Puis enfin je pense que je créerais la version graphique avec du print ou un autre moyen de voir ce que le code prend comme valeurs (que je copie/colle comme valeur de mon code hors app pour être sur) avant de “lier le tout” et retester.

Exact, mais il utilise monitor_file de la glib, qui, si elle ne peut pas faire mieux fait ce que tu proposes, mais si elle peut faire mieux, elle fait mieux en utilisant inotify.

inotify est un ensemble de syscalls pour demander au kernel de se débrouiller à nous remonter les informations de modifications de fichiers.

Si tu veux tester sur Debian il y a par exemple le paquet entr qui expose inotify sous la forme d’un programme simple à utiliser, par exemple si tu code en C et que tu veux recompiler a chaque modif :

ls *.c *.h | entr make
1 « J'aime »

Hi,
J’arrive un peu tard, désolé.

Pour la surveillance d’un fichier il y a la bibliothèque watchdog :

Pour la mettre dans gtk (c’est ici du gtk3+), il y a un hack que j’ai trouvé il y a peu. Cela donne un truc du style :

import sys, os
import threading # Multithreading
import time

from watchdog.observers import Observer # Watchdog
from watchdog.events import FileSystemEvent, FileSystemEventHandler

import gi # GTK+3
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk, Gdk, GdkPixbuf


#######################################################
# Watchdog
# Surveillance de 'file'
#######################################################

class watchdog_handler(FileSystemEventHandler):
    def on_modified(self, event):
        if event.is_directory:
            return None
        else:
            GLib.idle_add(event_wd)

def watchdog_thread():
    
    file="test.txt"
    
    event_handler = watchdog_handler()
    observer = Observer()
    observer.schedule(event_handler, file, recursive=False)
    observer.start()
    try:
        while True:
            time.sleep(1)
    finally:
        observer.stop()
        observer.join()

#######################################################
# Traitement
#######################################################

def event_wd():
    print("Changement !")

#######################################################
# Boucle principale
#######################################################

if __name__ == "__main__":
    
    # Fenêtre
    win = Gtk.Window()
    win.connect("destroy", Gtk.main_quit)
    win.show_all()


    # Watchdog
    wd_thread = threading.Thread(target=watchdog_thread)
    wd_thread.daemon = True
    wd_thread.start()
    
    # Go !
    Gtk.main()

Je viens corriger une coquille ‘event’ est devenu ‘event_wd’.

Si tu veux tester sur Debian il y a par exemple le paquet entr qui expose inotify sous la forme d’un programme simple à utiliser,

Après l’idéal ce serait que ce ne soit pas dépendant d’un système et qu’un même code marche sur Windows, linux, mac et mobile sans devoir gerer des exceptions/erreurs spécifiques a un seul OS…

Mettre tous les OS d’accord sur un ensemble d’APIs qu’ils doivent exposer ? Sacrée utopie, on est déjà pas capable de s’entendre sur la séquence d’octets pour représenter un retour à la ligne… Microsoft qui utilise encore CP1252 alors que tout le monde est passé à UTF-8… alors se mettre d’accord sur des détails comme inotify, c’est foutu.

La seule issue favorable que j’imagine serait pour Microsoft d’abandonner son Kernel (et d’utiliser Linux à la place), en gardant juste le gestionnaire de fenêtres et leurs apps ça serait transparent pour les utilisateurs, ça leur économiserai probablement pas mal d’argent, et ça ferait un OS en moins à gérer quand on code.

Avec la bibliothèque watchdog c’est le même code pour Linux et Windows, je n’ai pas testé mac ou mobile.