From 45b53db765838216370365eaefa2fb0ba6e36a9c Mon Sep 17 00:00:00 2001 From: Commandre Benjamin <benjamin.commandre@irstea.fr> Date: Fri, 13 Nov 2020 16:02:55 +0100 Subject: [PATCH] Update --- app/Archive.py | 2 +- app/Outils.py | 394 ++++++++++++++++++++++++---------------------- app/Satellites.py | 13 +- telis.py | 4 +- 4 files changed, 217 insertions(+), 196 deletions(-) diff --git a/app/Archive.py b/app/Archive.py index 9d1f56b..20f80ff 100644 --- a/app/Archive.py +++ b/app/Archive.py @@ -221,7 +221,7 @@ class Archive: Méthode pour lister les images disponibles sur la plateforme 'Theia Land' correspondant à la zone. """ - if hasattr(self, 'liste_tuiles'): + if self.liste_tuiles is not None: self.listing_by_tile() else: self.listing_by_coord() diff --git a/app/Outils.py b/app/Outils.py index fc2bf3d..17f3585 100644 --- a/app/Outils.py +++ b/app/Outils.py @@ -1,98 +1,108 @@ #!/bin/env python3 # -*- coding: utf-8 -*- -import sys import argparse +import ast +import configparser +import inspect import logging -from logging.handlers import RotatingFileHandler import signal +import sys from contextlib import contextmanager -import inspect +from datetime import datetime +from logging.handlers import RotatingFileHandler + from osgeo import gdal + import app.Constantes as Constantes -import configparser -import ast -from datetime import datetime import app.Satellites as Satellites +import app.Telechargement as Telechargement + class Fusion(argparse.Action): - def __init__(self, option_strings, dest, nargs=None, **kwargs): - super(Fusion, self).__init__(option_strings, dest, nargs, **kwargs) - def __call__(self, parser, namespace, values, option_string=None): - setattr(namespace, self.dest, ' '.join(values).lower()) + def __init__(self, option_strings, dest, nargs=None, **kwargs): + super(Fusion, self).__init__(option_strings, dest, nargs, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, ' '.join(values).lower()) + class Log(object): - def __init__(self, dossier, nomFichier, niveau=None): + def __init__(self, dossier, nom_fichier, niveau=None): + + super(Log, self).__init__() + + stack = inspect.stack() + nom_classe = stack[1][0].f_locals["self"].__class__.__name__ - super(Log, self).__init__() + self.__logger__ = logging.getLogger(nom_fichier) - stack = inspect.stack() - nom_classe = stack[1][0].f_locals["self"].__class__.__name__ + if niveau is None: + try: + niveau = Constantes.NIVEAU_DEFAUT + except Exception: + niveau = logging.DEBUG - self.__logger__ = logging.getLogger(nomFichier) + self.__logger__.setLevel(niveau) - if niveau is None: - try: - niveau = Constantes.NIVEAU_DEFAUT - except : - niveau = logging.DEBUG + format_fichier = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s', datefmt='%d-%m-%Y %H:%M:%S') + fichier_log = RotatingFileHandler("{0}/{1}.log".format(dossier, nom_fichier), 'a', 1000000, 1) - self.__logger__.setLevel(niveau) + fichier_log.setLevel(niveau) + fichier_log.setFormatter(format_fichier) + self.__logger__.addHandler(fichier_log) - format_fichier = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s', datefmt='%d-%m-%Y %H:%M:%S') - fichierLog = RotatingFileHandler("{0}/{1}.log".format(dossier, nomFichier), 'a', 1000000, 1) + format_console = logging.Formatter('%(asctime)s :: {0} :: %(levelname)s :: %(message)s'.format(nom_classe), + datefmt='%d-%m-%Y %H:%M:%S') - fichierLog.setLevel(niveau) - fichierLog.setFormatter(format_fichier) - self.__logger__.addHandler(fichierLog) + console = logging.StreamHandler() + console.setLevel(niveau) + console.setFormatter(format_console) - format_console = logging.Formatter('%(asctime)s :: {0} :: %(levelname)s :: %(message)s'.format(nom_classe), datefmt='%d-%m-%Y %H:%M:%S') + self.__logger__.addHandler(console) - console = logging.StreamHandler() - console.setLevel(niveau) - console.setFormatter(format_console) - self.__logger__.addHandler(console) + def info(self, message): + self.__logger__.info(message) - def info(self, message): - self.__logger__.info(message) + def debug(self, message): + self.__logger__.debug(message) - def debug(self, message): - self.__logger__.debug(message) + def warning(self, message): + self.__logger__.warning(message) - def warning(self, message): - self.__logger__.warning(message) + def error(self, message): + self.__logger__.error(message) - def error(self, message): - self.__logger__.error(message) + def critical(self, message): + self.__logger__.critical(message) - def critical(self, message): - self.__logger__.critical(message) + def exception(self, message): + self.__logger__.exception(message) - def exception(self, message): - self.__logger__.exception(message) + def close(self): + for handler in self.__logger__.handlers[:]: + handler.close() + self.__logger__.removeHandler(handler) - def close(self): - for handler in self.__logger__.handlers[:] : - handler.close() - self.__logger__.removeHandler(handler) +class TimeoutException(Exception): + pass -class TimeoutException(Exception): pass @contextmanager def limitation_temporelle(secondes): + def signal_handler(): + raise TimeoutException - def signal_handler(signum, frame): - raise TimeoutException + signal.signal(signal.SIGALRM, signal_handler) + signal.alarm(secondes) - signal.signal(signal.SIGALRM, signal_handler) - signal.alarm(secondes) + try: + yield + finally: + signal.alarm(0) - try: - yield - finally: - signal.alarm(0) # Utilisation : # @@ -103,146 +113,158 @@ def limitation_temporelle(secondes): # pass def clip(image, cut, form="Mem", dst="", type_sortie=gdal.GDT_Float32, nodata="NaN"): - """ - Découpe une image selon un shapefile donné. Si le type de l'image en sortie - n'est pas spécifié, l'image sera retournée en pointeur mémoire et ne sera pas sauvegardée. + """ + Découpe une image selon un shapefile donné. Si le type de l'image en sortie + n'est pas spécifié, l'image sera retournée en pointeur mémoire et ne sera pas sauvegardée. - :param image: Chemin vers l'image dans laquelle on veut découper l'emprise. - :type image: Chaîne de caractères + :param image: Chemin vers l'image dans laquelle on veut découper l'emprise. + :type image: Chaîne de caractères - :param cut: Chemin vers le shapefile représentant l'emprise. - :type cut: Chaîne de caractères + :param cut: Chemin vers le shapefile représentant l'emprise. + :type cut: Chaîne de caractères - :param form: Format de l'image en sortie. - :type form: Chaîne de caractères + :param form: Format de l'image en sortie. + :type form: Chaîne de caractères - :param dst: Chemin de l'image en sortie. - :type dst: Chaîne de caractères - """ + :param dst: Chemin de l'image en sortie. + :type dst: Chaîne de caractères - option_clip = gdal.WarpOptions(cropToCutline=True,\ - cutlineDSName=cut, outputType=type_sortie , format=form, dstNodata=nodata) + :param nodata: Valeur nodata. + :type nodata: Chaîne de caractères ou Entier + + :param type_sortie: Type du pixel de l'image de sortie. + :type type_sortie: gdal.GDT + """ + + option_clip = gdal.WarpOptions(cropToCutline=True, cutlineDSName=cut, + outputType=type_sortie, format=form, + dstNodata=nodata) + + return gdal.Warp(dst, image, options=option_clip) - return gdal.Warp(dst, image, options=option_clip) def str2bool(v): return v.lower() in (["false"]) -def checkDate(date): - - d = date.split('-') - - try: - if not date : - - annee = datetime.now().year - - if datetime.now().month < 10 : - mois = "0{}".format(datetime.now().month) - else : - mois = datetime.now().month - - if datetime.now().day < 10 : - jour = "0{}".format(datetime.now().day) - else : - jour = datetime.now().day - - elif len(d) == 1 : - annee = d[0] - mois = "01" - jour = "01" - elif len(d) == 2 : - annee = d[0] - mois = d[1] - jour = "01" - elif len(d) == 3 : - annee = d[0] - mois = d[1] - jour = d[2] - - datetime(int(annee), int(mois), int(jour)) - return "{annee}-{mois}-{jour}".format(annee=annee, mois=mois, jour=jour) - except ValueError: - print("Format invalide") - sys.exit(1) - except IndexError: - print("La date doit être au format 'AAAA-MM-JJ', 'AAAA-MM' ou 'AAAA'") - sys.exit(1) + +def check_date(date): + d = date.split('-') + + annee = None + mois = None + jour = None + + try: + if not date: + + annee = datetime.now().year + + if datetime.now().month < 10: + mois = "0{}".format(datetime.now().month) + else: + mois = datetime.now().month + + if datetime.now().day < 10: + jour = "0{}".format(datetime.now().day) + else: + jour = datetime.now().day + + elif len(d) == 1: + annee = d[0] + mois = "01" + jour = "01" + elif len(d) == 2: + annee = d[0] + mois = d[1] + jour = "01" + elif len(d) == 3: + annee = d[0] + mois = d[1] + jour = d[2] + + # datetime(int(annee), int(mois), int(jour)) + return "{annee}-{mois}-{jour}".format(annee=annee, mois=mois, jour=jour) + except ValueError: + print("Format invalide") + sys.exit(1) + except IndexError: + print("La date doit être au format 'AAAA-MM-JJ', 'AAAA-MM' ou 'AAAA'") + sys.exit(1) def get_variable(self, config): - """ - Récupération des variables dans le fichier de configuration - """ - - configfile = configparser.ConfigParser() - configfile.read(config) - - self.requete = dict() - self.requete["lang"] = "fr" - self.requete["_pretty"] = "true" - self.requete["maxRecord"] = 500 - - # Capteur utilisé - self.capteur = configfile["satellite"]["capteur"] - self.bandes = configfile["satellite"]["bandes"] - self.requete["processingLevel"] = configfile["satellite"]["processingLevel"] - - # Dossier contenant les résultats - self.dossier_sortie = configfile["sortie"]["chemin"] - - try: - if str2bool(configfile["sortie"]["extraction"]): - self.extraction = False - else : - self.extraction = True - except : - self.extraction = True - - self.groupe = configfile["sortie"]["groupe"] - - # Date de début et de fin de la recherche - try: - # self.date_debut = configfile["donnees"]["date_debut"] - self.requete["startDate"] = checkDate(configfile["donnees"]["date_debut"]) - except Exception as e: - raise "L'année de départ est requise." - - self.requete["completionDate"] = checkDate(configfile["donnees"]["date_fin"]) - - self.seuil_nuage = float(configfile["donnees"]["seuil_nuage"])/100.0 if configfile["donnees"]["seuil_nuage"] else 0.0 - - # Emprise et zone de l'étude - self.emprise = configfile["donnees"]["chemin_emprise"] - - if self.emprise : - self.zone_etude = configfile["donnees"]["chemin_zone_etude"] - if not self.zone_etude : - self.zone_etude = self.emprise - else : - try: - self.liste_tuiles = list(ast.literal_eval(configfile["donnees"]["liste_tuiles"])) - except Exception as e: - raise "Aucune emprise ni aucune tuile n'a été renseigné." - - - self.nombre_image = configfile["donnees"]["nombre_image"] - - # Identifiant, mot de passe et proxy pour le téléchargement des images Théia - self.id = configfile["theia"]["identifiant"] - self.mdp = configfile["theia"]["mdp"] - self.proxy = configfile["theia"]["proxy"] - - if self.bandes == "RGB" : - self.extent_img = Satellites.SATELLITE[self.capteur][self.requete["processingLevel"]][:-1] - else : - self.extent_img = Satellites.SATELLITE[self.capteur][self.requete["processingLevel"]] - - if self.requete["processingLevel"] == "LEVEL2A" : - self.nuage = Satellites.SATELLITE[self.capteur]["NUAGE"] - else : - self.nuage = None - - self.serveur = Satellites.SATELLITE[self.capteur]["serveur"] - self.resto = Satellites.SATELLITE[self.capteur]["resto"] - self.token_type = Satellites.SATELLITE[self.capteur]["token_type"] + """ + Récupération des variables dans le fichier de configuration + """ + + configfile = configparser.ConfigParser() + configfile.read(config) + + self.requete = dict() + self.requete["lang"] = "fr" + self.requete["_pretty"] = "true" + self.requete["maxRecord"] = 500 + + # Capteur utilisé + self.capteur = configfile["satellite"]["capteur"] + self.bandes = list(ast.literal_eval(configfile["satellite"]["bandes"])) + self.requete["processingLevel"] = configfile["satellite"]["processingLevel"] + + # Dossier contenant les résultats + self.dossier_sortie = configfile["sortie"]["chemin"] + + try: + if str2bool(configfile["sortie"]["extraction"]): + self.extraction = False + else: + self.extraction = True + except Exception: + self.extraction = True + + self.groupe = configfile["sortie"]["groupe"] + + # Date de début et de fin de la recherche + try: + # self.date_debut = configfile["donnees"]["date_debut"] + self.requete["startDate"] = check_date(configfile["donnees"]["date_debut"]) + except Exception: + raise Exception("L'année de départ est requise.") + + self.requete["completionDate"] = check_date(configfile["donnees"]["date_fin"]) + + self.seuil_nuage = float(configfile["donnees"]["seuil_nuage"]) / 100.0 if configfile["donnees"][ + "seuil_nuage"] else 0.0 + + # Emprise et zone de l'étude + self.emprise = configfile["donnees"]["chemin_emprise"] + + if self.emprise: + self.zone_etude = configfile["donnees"]["chemin_zone_etude"] + if not self.zone_etude: + self.zone_etude = self.emprise + else: + try: + self.liste_tuiles = list(ast.literal_eval(configfile["donnees"]["liste_tuiles"])) + except Exception: + raise Exception("Aucune emprise ni aucune tuile n'a été renseigné.") + + self.nombre_image = configfile["donnees"]["nombre_image"] + + if self.requete["processingLevel"] == "LEVEL2A": + self.nuage = Satellites.SATELLITE[self.capteur]["NUAGE"] + else: + self.nuage = None + + self.prefix = Satellites.SATELLITE[self.capteur][configfile["satellite"]["processingLevel"]] + + # Identifiant, mot de passe et proxy pour le téléchargement des images Théia + # self.id = configfile["theia"]["identifiant"] + # self.mdp = configfile["theia"]["mdp"] + # self.proxy = configfile["theia"]["proxy"] + + self.serveur = Satellites.SATELLITE[self.capteur]["serveur"] + self.resto = Satellites.SATELLITE[self.capteur]["resto"] + + self.api = Telechargement.Telechargement(self.serveur, configfile["theia"]["identifiant"], + configfile["theia"]["mdp"], configfile["theia"]["proxy"]) + # self.token_type = Satellites.SATELLITE[self.capteur]["token_type"] diff --git a/app/Satellites.py b/app/Satellites.py index 1a3d0ce..e8e17e6 100644 --- a/app/Satellites.py +++ b/app/Satellites.py @@ -5,24 +5,23 @@ import collections SATELLITE = collections.defaultdict(dict) -# Informations obtenues sur le site 'Theia-land' ou sur le blog d'Olivier HAGOLLE +# Informations obtenues sur le site 'Theia-land' ou sur le blog d'Olivier HAGOLLE -########################## SENTINEL2 ############################### +# ######################### SENTINEL2 ############################### SATELLITE["SENTINEL2"]["serveur"] = "https://theia.cnes.fr/atdistrib" SATELLITE["SENTINEL2"]["resto"] = "resto2" SATELLITE["SENTINEL2"]["token_type"] = "text" SATELLITE["SENTINEL2"]["R"] = 2 SATELLITE["SENTINEL2"]["PIR"] = 3 -SATELLITE["SENTINEL2"]["LEVEL2A"] = ['_FRE_B2.tif', '_FRE_B3.tif', '_FRE_B4.tif', '_FRE_B8.tif'] -SATELLITE["SENTINEL2"]["NUAGE"] = ['_CLM_R1.tif'] -SATELLITE["SENTINEL2"]["LEVEL3A"] = ['_FRC_B2.tif', '_FRC_B3.tif', '_FRC_B4.tif', '_FRC_B8.tif'] +SATELLITE["SENTINEL2"]["LEVEL2A"] = 'FRE' +SATELLITE["SENTINEL2"]["LEVEL3A"] = 'FRC' +SATELLITE["SENTINEL2"]["NUAGE"] = '_CLM_R1' -########################## LANDSAT ################################# +# ######################### LANDSAT ################################# SATELLITE["Landsat"]["serveur"] = "https://theia-landsat.cnes.fr" SATELLITE["Landsat"]["resto"] = "resto" SATELLITE["Landsat"]["token_type"] = "json" SATELLITE["Landsat"]["R"] = 3 SATELLITE["Landsat"]["PIR"] = 4 - diff --git a/telis.py b/telis.py index 5de8db0..ea3541f 100644 --- a/telis.py +++ b/telis.py @@ -22,12 +22,12 @@ class Telechargement(object): """ Fonction pour lancer le programme """ - # Début du processus + # Début du processus debut = time.time() prog = Archive(self.config) prog.listing() - prog.download_auto() + prog.download() # Fin du processus fin = time.time() -- GitLab