Exécution de la commande déclenchée par la mise à jour du fichier (édition python)

C'était il y a quelque temps, mais j'ai trouvé un article comme celui-ci sur Qiita. Ou plutôt, il venait de @wpythonnews.

Exécutez le test unitaire au moment où vous enregistrez le fichier

La méthode introduite ici consiste à enregistrer l'horodatage de la dernière mise à jour et à vérifier un par un l'heure de mise à jour des fichiers sous le répertoire cible.

Le contrôle lui-même est exécuté toutes les 100 ms, et bien qu'il n'exécute pas le processeur à pleine capacité, il a toujours une certaine charge. Environ 77% de charge sur mon Mac. De plus, ce code me donne l'impression d'être illisible lorsque plusieurs fichiers sont mis à jour en 100 ms (les résultats varient en fonction de l'ordre dans lequel ils sont évalués).

En revanche, il est certain qu'il existe des situations où ce type de «confirmation de mise à jour de fichier» est nécessaire. Par conséquent, les systèmes d'exploitation récents ont un support au niveau du noyau.

Il existe peut-être des modules Python qui les utilisent. Donc, quand je regarde ça, ça sort de différentes manières.

À propos, epoll et kqueue sont supportés par le module Python standard (select) avec un niveau I / F inférieur à celui des autres. Il y a.

Parmi les modules ci-dessus, watchdog semble être le meilleur si vous écrivez un programme à usage général en utilisant différentes API pour chaque plate-forme. Alors, j'ai essayé de l'utiliser.

Utilisez le pip habituel pour l'installation.

shell::


$ pip install watchdog

Et l'exemple de code ressemble à ceci.

python::dirwatch2.py


#!/usr/bin/env python
from __future__ import print_function

import sys
import time
import subprocess
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler


class MyHandler(PatternMatchingEventHandler):
    def __init__(self, command, patterns):
        super(MyHandler, self).__init__(patterns=patterns)
        self.command = command

    def _run_command(self):
        subprocess.call([self.command, ])

    def on_moved(self, event):
        self._run_command()

    def on_created(self, event):
        self._run_command()

    def on_deleted(self, event):
        self._run_command()

    def on_modified(self, event):
        self._run_command()


def watch(path, command, extension):
    event_handler = MyHandler(command, ["*"+extension])
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()


if __name__ == "__main__":
    if 4 > len(sys.argv):
        print("Usage:", sys.argv[0], "dir_to_watch command extension")
    else:
        watch(sys.argv[1], sys.argv[2], sys.argv[3])

C'est un peu plus long, mais les bases sont simples, créez simplement une classe qui hérite de l'une des classes de gestionnaire d'événements préparées et implémentez le contenu de on_moved, on_created, on_deleted, on_modified. Ces méthodes sont appelées lors du déplacement, de la création, de la suppression ou de la modification de fichiers.

À propos, les quatre classes de gestionnaire d'événements suivantes sont préparées.

La première est une classe de base qui gère le traitement des événements de changement de fichier, et les deuxième et troisième sont l'ajout d'une fonction pour affiner les fichiers par correspondance de modèles ou expressions régulières. Le quatrième est un gestionnaire qui écrit les événements de modification de fichier sous forme de journal.

Puisqu'il est censé être réduit par extension ici, PatternMatchingEventHandler est hérité et implémenté de sorte que la commande soit émise quelle que soit la méthode appelée parmi les quatre méthodes de gestion.

Ensuite, créez simplement une instance de la classe Observer, passez le gestionnaire d'événements et le répertoire à surveiller à schedule () et start (). Après cela, il y a un processus qui se produit toutes les secondes dans une boucle infinie, mais il s'agit de capturer l'événement clé afin que l'exécution puisse être arrêtée avec Ctrl-C. Cela consomme un peu de CPU, mais c'est environ 10% à portée de main. Eh bien, est-ce acceptable? Il peut être réduit davantage en augmentant l'intervalle.

Ainsi, bien que l'exemple soit exécuté, l'argument de la commande correspond au dirwatch de "Exécuter le test unitaire au moment où le fichier est enregistré. L'exécution est comme ça.

shell::


$ python dirwatch2.py <directory_to_watch> <command> <extension>

Un fichier avec l'extension spécifiée sous le répertoire spécifié La commande spécifiée est émise lorsque le fichier est modifié.

Notez que ce module Python appelé watchdog est livré avec un outil watchmedo pour faire la même chose. Avec lui, vous pouvez écrire comme ceci:

shell::


$ watchmedo shell-command \
	--patterns="*"$3 \
	--command $2 \
	--recursive \
	$1

C'était assez facile à battre.

De la même manière, "surveiller les fichiers et les répertoires et faire quelque chose s'il y a un changement" peut être fait assez normalement avec les outils Node.js tels que Grunt et Gulp. J'aimerais aussi les résumer.

Recommended Posts

Exécution de la commande déclenchée par la mise à jour du fichier (édition python)
Exécution de commandes externes en Python
Exécution par sous-shell (et mise à jour des variables)
Lisez le fichier ligne par ligne avec Python
Mise à jour Python (2.6-> 2.7)
Lisez le fichier ligne par ligne avec Python
Notifier l'erreur et la fin de l'exécution par LINE [Python]
Lire ligne par ligne à partir d'un fichier avec Python
Obtenez la date de mise à jour du fichier de mémorandum Python.
Fichier python de script
Traitement de fichiers Python
Lisez le fichier xml en vous référant au didacticiel Python
Reconnaissance vocale des fichiers par l'API Google Speech v2 à l'aide de Python