maintenance.scantex
Outils d'analyse de fichiers sources ou produits par LateX.
Modifié le 22/01/23 @author: remy
Travaille dans le répertoire courant c'est à dire celui du dépôt à maintenir.
1# -*- coding: utf-8 -*- 2""" 3Outils d'analyse de fichiers sources ou produits par LateX. 4 5Modifié le 22/01/23 @author: remy 6 7Travaille dans le répertoire courant c'est à dire celui du dépôt à maintenir. 8""" 9import os 10import glob 11 12def latex2accent(texte): 13 LatexAccent = { 14 r"\IeC {\'e}": "é", 15 r"\IeC {\'E}": "É", 16 r"\IeC {\`e}": "è", 17 r"\IeC {\^e}": "ê", 18 r"\IeC {\^E}": "Ê", 19 r"\IeC {\¨e}": "ë", 20 r"\IeC {\¨E}": "Ë", 21 r"\IeC {\`a}": "à", 22 r"\IeC {\'A}": "À", 23 r"\IeC {\^a}": "â", 24 r"\IeC {\^A}": "Â", 25 r"\IeC {\^i}": "î", 26 r"\IeC {\^I}": "Î", 27 r"\IeC {\¨i}": "ï", 28 r"\IeC {\¨I}": "Ï", 29 r"\IeC {\^o}": "ô", 30 r"\IeC {\^O}": "Ô", 31 r"\IeC {\^u}": "û", 32 r"\IeC {\^U}": "Û", 33 r"\IeC {\¨u}": "ü", 34 r"\IeC {\¨U}": "Ü", 35 r"\IeC {\c c}": "ç", 36 r"\IeC {\oe}": "œ", 37 r"\'e": "é", 38 r"\`e": "è", 39 r"\`a": "à" 40 } 41 for latex, accent in LatexAccent.items(): 42 texte = texte.replace(latex,accent) 43 return texte 44 45def get_date_srce(nom): 46 """ 47 Renvoie une date de source. 48 49 Fonction récursive. 50 51 - Si le fichier ne contient ni input ni includegraphics, 52 - renvoie la date de maj du fichier. 53 - Sinon 54 - renvoie la date la plus récente entre sa date de maj et celle 55 des input et includegraphics. 56 """ 57 try: 58 date_srce = os.path.getmtime(nom) 59 except FileNotFoundError: 60 print(nom, ' pas trouvé') 61 date_srce = 0 62 63 # date des sources tex inputtés 64 try: 65 liste = get_liste_inputs(nom) 66 except UnicodeDecodeError: 67 print(nom) 68 for fic in liste: 69 t = get_date_srce(fic) 70 # print(fic,t) 71 if t > date_srce: 72 date_srce = t 73 74 # date des figures et des lignes de code incluses 75 liste = get_liste_includegraphics(nom) + get_liste_lstinputlistings(nom) 76 for fic in liste: 77 try: 78 t = os.path.getmtime(fic) 79 except FileNotFoundError: 80 print('Erreur : ', fic, ' pas trouvé') 81 t = 0 82 # print(fic, t) 83 if t > date_srce: 84 date_srce = t 85 return date_srce 86 87 88def get_liste_inputs(nom): 89 """Renvoie la liste des sources tex dans des input.""" 90 fifi = open(nom, 'r') 91 text = fifi.read() 92 long = len(text) 93 inputs = [] 94 c, cc = 0, 0 # compteurs dans la chaine de caractère 95 while c != -1: 96 c = text.find('\\input{', cc, long) 97 if c != -1: 98 c += 7 99 cc = text.find('}', c, long) 100 nominput = text[c:cc] 101 if '.' not in nominput: 102 nominput += '.tex' 103 if nominput not in inputs: 104 inputs.append(nominput) 105 return inputs 106 107 108def get_liste_includegraphics(nom): 109 """Renvoie la liste des figures (pdf) dans des includegraphics.""" 110 fifi = open(nom, 'r') 111 text = fifi.read() 112 long = len(text) 113 includes = [] 114 c, cc = 0, 0 # compteurs dans la chaine de caractère 115 while c != -1: 116 c = text.find('\\includegraphics', cc, long) 117 if c != -1: 118 # il peut y avoir une option '[width= ]' 119 c = text.find('{', c, long) 120 c += 1 121 cc = text.find('}', c, long) 122 fig = text[c:cc] 123 # si pas d'extension on place .pdf 124 if not os.path.splitext(fig)[1]: 125 print('extension pdf manque dans', nom) 126 fig += '.pdf' 127 if fig not in includes: 128 includes.append(fig) 129 return includes 130 131 132def get_liste_lstinputlistings(nom): 133 """ 134 Renvoie une liste des fichiers. 135 136 Ceux contenant des lignes de codes insérées par `lstinputlisting`. 137 """ 138 fifi = open(nom, 'r') 139 text = fifi.read() 140 long = len(text) 141 lstinputs = [] 142 c, cc = 0, 0 # compteurs dans la chaine de caractère 143 while c != -1: 144 c = text.find('\\lstinputlisting', cc, long) 145 if c != -1: 146 # il y a une option '[width= ] à sauter' 147 c = text.find('{', c, long) 148 c += 1 149 cc = text.find('}', c, long) 150 lstinput = text[c:cc] 151 # si pas d'extension on place .py 152 if not os.path.splitext(lstinput)[1]: 153 print('extension pdf manque dans', nom) 154 lstinput += '.py' 155 if lstinput not in lstinputs: 156 lstinputs.append(lstinput) 157 return lstinputs 158 159 160def aexec(src): 161 """Renvoie `Vrai` si un `input` plus récent que le `.pdf`.""" 162 ext = os.path.splitext(src)[1] 163 img = src.replace(ext, '.pdf') 164 # print(img) 165 date_img = 0 166 date_src = get_date_srce(src) 167 if os.path.exists(img): 168 date_img = os.path.getmtime(img) 169 return date_src > date_img 170 171 172def acompiler(src, img): 173 """ 174 Renvoie `Vrai` si `src` est à compiler. 175 176 C'est à dire si un `input` de la source est plus récent que l'image. 177 178 #### Parameters 179 180 - src : . 181 - img : chaine de caractère représentant le nom du fichier image. 182 183 #### Returns 184 185 None. 186 187 """ 188 # imgext = os.path.splitext(img)[1] 189 # print(img) 190 date_img = 0 191 date_src = get_date_srce(src) 192 if os.path.exists(img): 193 date_img = os.path.getmtime(img) 194 # if imgext == '.html': 195 # print(img, date_src > date_img) 196 197 return date_src > date_img 198 199def get_liste_indexations(path_pattern): 200 """ 201 Renvoie la liste des indexations. 202 203 Examine les fichiers .idx créés par la commande d'indexation lors de la 204 compilation. 205 206 #### Paramètres 207 208 `path_pattern`: str, pattern de la chaine de caractère des chemins des fichiers 209 idx d'index.' 210 Exemple `auxdir/A*.idx`. 211 212 #### Returns 213 214 Une liste de couples `[nomfic, litteral]` où 215 - `nomfic` est un nom de fichier .tex 216 - `litteral` est une chaine de caractères indexée dans `nomfic`. 217 """ 218 219 indexations = [] 220 idxpaths = glob.glob(path_pattern) 221 for idxpath in idxpaths: 222 doc = os.path.basename(idxpath) 223 #doc = doc.removeprefix('A') 224 doc = doc.removesuffix(('.idx')) 225 f = open(idxpath) 226 for line in f: 227 if '\\indexentry{' in line: 228 line = line.removeprefix('\\indexentry{') 229 if '|hyperpage' in line : 230 i = line.find('|hyperpage') 231 else: 232 i = line.find('}') 233 line = line[0:i] 234 line = latex2accent(line) 235 indexations.append([doc,line]) 236 f.close() 237 # print(indexations) 238 return indexations 239 240def get_liste_descriptions(description_pattern): 241 """ 242 Renvoie la liste des descriptions. 243 244 245 #### Parametres 246 description_pattern : dictionnaire 247 { 248 'path_pattern': pattern des chemins des fichiers à examiner, 249 'tags': paire de balises entourant la description 250 } 251 252 #### Renvoie 253 254 Liste de couples ['nom du document', 'description de document'] 255 256 """ 257 descriptions = [] 258 path_pattern = description_pattern['path_pattern'] 259 tags = description_pattern['tags'] 260 nomfics = glob.glob(path_pattern) 261 for nomfic in nomfics: 262 file = open(nomfic) 263 fictex = file.read() 264 file.close() 265 if i:= fictex.find(tags[0]) >= 0: 266 i += len(tags[0]) - 1 267 j = fictex.find(tags[1]) 268 nomfic = nomfic.removeprefix(path_pattern[0]) 269 nomfic = nomfic.removesuffix('.tex') 270 descriptions.append([nomfic,fictex[i:j]]) 271 return descriptions 272 273def get_entre_tags(nom,debut,fin): 274 """ 275 Renvoie la chaine de caractère entre les tags. 276 """ 277 fifi = open(nom, 'r') 278 text = fifi.read() 279 ind_debut = text.find(debut) + len(debut) 280 ind_fin = text.find(fin, ind_debut) 281 return text[ind_debut:ind_fin] 282 283
13def latex2accent(texte): 14 LatexAccent = { 15 r"\IeC {\'e}": "é", 16 r"\IeC {\'E}": "É", 17 r"\IeC {\`e}": "è", 18 r"\IeC {\^e}": "ê", 19 r"\IeC {\^E}": "Ê", 20 r"\IeC {\¨e}": "ë", 21 r"\IeC {\¨E}": "Ë", 22 r"\IeC {\`a}": "à", 23 r"\IeC {\'A}": "À", 24 r"\IeC {\^a}": "â", 25 r"\IeC {\^A}": "Â", 26 r"\IeC {\^i}": "î", 27 r"\IeC {\^I}": "Î", 28 r"\IeC {\¨i}": "ï", 29 r"\IeC {\¨I}": "Ï", 30 r"\IeC {\^o}": "ô", 31 r"\IeC {\^O}": "Ô", 32 r"\IeC {\^u}": "û", 33 r"\IeC {\^U}": "Û", 34 r"\IeC {\¨u}": "ü", 35 r"\IeC {\¨U}": "Ü", 36 r"\IeC {\c c}": "ç", 37 r"\IeC {\oe}": "œ", 38 r"\'e": "é", 39 r"\`e": "è", 40 r"\`a": "à" 41 } 42 for latex, accent in LatexAccent.items(): 43 texte = texte.replace(latex,accent) 44 return texte
46def get_date_srce(nom): 47 """ 48 Renvoie une date de source. 49 50 Fonction récursive. 51 52 - Si le fichier ne contient ni input ni includegraphics, 53 - renvoie la date de maj du fichier. 54 - Sinon 55 - renvoie la date la plus récente entre sa date de maj et celle 56 des input et includegraphics. 57 """ 58 try: 59 date_srce = os.path.getmtime(nom) 60 except FileNotFoundError: 61 print(nom, ' pas trouvé') 62 date_srce = 0 63 64 # date des sources tex inputtés 65 try: 66 liste = get_liste_inputs(nom) 67 except UnicodeDecodeError: 68 print(nom) 69 for fic in liste: 70 t = get_date_srce(fic) 71 # print(fic,t) 72 if t > date_srce: 73 date_srce = t 74 75 # date des figures et des lignes de code incluses 76 liste = get_liste_includegraphics(nom) + get_liste_lstinputlistings(nom) 77 for fic in liste: 78 try: 79 t = os.path.getmtime(fic) 80 except FileNotFoundError: 81 print('Erreur : ', fic, ' pas trouvé') 82 t = 0 83 # print(fic, t) 84 if t > date_srce: 85 date_srce = t 86 return date_srce
Renvoie une date de source.
Fonction récursive.
- Si le fichier ne contient ni input ni includegraphics,
- renvoie la date de maj du fichier.
- Sinon
- renvoie la date la plus récente entre sa date de maj et celle des input et includegraphics.
89def get_liste_inputs(nom): 90 """Renvoie la liste des sources tex dans des input.""" 91 fifi = open(nom, 'r') 92 text = fifi.read() 93 long = len(text) 94 inputs = [] 95 c, cc = 0, 0 # compteurs dans la chaine de caractère 96 while c != -1: 97 c = text.find('\\input{', cc, long) 98 if c != -1: 99 c += 7 100 cc = text.find('}', c, long) 101 nominput = text[c:cc] 102 if '.' not in nominput: 103 nominput += '.tex' 104 if nominput not in inputs: 105 inputs.append(nominput) 106 return inputs
Renvoie la liste des sources tex dans des input.
109def get_liste_includegraphics(nom): 110 """Renvoie la liste des figures (pdf) dans des includegraphics.""" 111 fifi = open(nom, 'r') 112 text = fifi.read() 113 long = len(text) 114 includes = [] 115 c, cc = 0, 0 # compteurs dans la chaine de caractère 116 while c != -1: 117 c = text.find('\\includegraphics', cc, long) 118 if c != -1: 119 # il peut y avoir une option '[width= ]' 120 c = text.find('{', c, long) 121 c += 1 122 cc = text.find('}', c, long) 123 fig = text[c:cc] 124 # si pas d'extension on place .pdf 125 if not os.path.splitext(fig)[1]: 126 print('extension pdf manque dans', nom) 127 fig += '.pdf' 128 if fig not in includes: 129 includes.append(fig) 130 return includes
Renvoie la liste des figures (pdf) dans des includegraphics.
133def get_liste_lstinputlistings(nom): 134 """ 135 Renvoie une liste des fichiers. 136 137 Ceux contenant des lignes de codes insérées par `lstinputlisting`. 138 """ 139 fifi = open(nom, 'r') 140 text = fifi.read() 141 long = len(text) 142 lstinputs = [] 143 c, cc = 0, 0 # compteurs dans la chaine de caractère 144 while c != -1: 145 c = text.find('\\lstinputlisting', cc, long) 146 if c != -1: 147 # il y a une option '[width= ] à sauter' 148 c = text.find('{', c, long) 149 c += 1 150 cc = text.find('}', c, long) 151 lstinput = text[c:cc] 152 # si pas d'extension on place .py 153 if not os.path.splitext(lstinput)[1]: 154 print('extension pdf manque dans', nom) 155 lstinput += '.py' 156 if lstinput not in lstinputs: 157 lstinputs.append(lstinput) 158 return lstinputs
Renvoie une liste des fichiers.
Ceux contenant des lignes de codes insérées par lstinputlisting
.
161def aexec(src): 162 """Renvoie `Vrai` si un `input` plus récent que le `.pdf`.""" 163 ext = os.path.splitext(src)[1] 164 img = src.replace(ext, '.pdf') 165 # print(img) 166 date_img = 0 167 date_src = get_date_srce(src) 168 if os.path.exists(img): 169 date_img = os.path.getmtime(img) 170 return date_src > date_img
Renvoie Vrai
si un input
plus récent que le .pdf
.
173def acompiler(src, img): 174 """ 175 Renvoie `Vrai` si `src` est à compiler. 176 177 C'est à dire si un `input` de la source est plus récent que l'image. 178 179 #### Parameters 180 181 - src : . 182 - img : chaine de caractère représentant le nom du fichier image. 183 184 #### Returns 185 186 None. 187 188 """ 189 # imgext = os.path.splitext(img)[1] 190 # print(img) 191 date_img = 0 192 date_src = get_date_srce(src) 193 if os.path.exists(img): 194 date_img = os.path.getmtime(img) 195 # if imgext == '.html': 196 # print(img, date_src > date_img) 197 198 return date_src > date_img
Renvoie Vrai
si src
est à compiler.
C'est à dire si un input
de la source est plus récent que l'image.
Parameters
- src : .
- img : chaine de caractère représentant le nom du fichier image.
Returns
None.
200def get_liste_indexations(path_pattern): 201 """ 202 Renvoie la liste des indexations. 203 204 Examine les fichiers .idx créés par la commande d'indexation lors de la 205 compilation. 206 207 #### Paramètres 208 209 `path_pattern`: str, pattern de la chaine de caractère des chemins des fichiers 210 idx d'index.' 211 Exemple `auxdir/A*.idx`. 212 213 #### Returns 214 215 Une liste de couples `[nomfic, litteral]` où 216 - `nomfic` est un nom de fichier .tex 217 - `litteral` est une chaine de caractères indexée dans `nomfic`. 218 """ 219 220 indexations = [] 221 idxpaths = glob.glob(path_pattern) 222 for idxpath in idxpaths: 223 doc = os.path.basename(idxpath) 224 #doc = doc.removeprefix('A') 225 doc = doc.removesuffix(('.idx')) 226 f = open(idxpath) 227 for line in f: 228 if '\\indexentry{' in line: 229 line = line.removeprefix('\\indexentry{') 230 if '|hyperpage' in line : 231 i = line.find('|hyperpage') 232 else: 233 i = line.find('}') 234 line = line[0:i] 235 line = latex2accent(line) 236 indexations.append([doc,line]) 237 f.close() 238 # print(indexations) 239 return indexations
Renvoie la liste des indexations.
Examine les fichiers .idx créés par la commande d'indexation lors de la compilation.
Paramètres
path_pattern
: str, pattern de la chaine de caractère des chemins des fichiers
idx d'index.'
Exemple auxdir/A*.idx
.
Returns
Une liste de couples [nomfic, litteral]
où
nomfic
est un nom de fichier .texlitteral
est une chaine de caractères indexée dansnomfic
.
241def get_liste_descriptions(description_pattern): 242 """ 243 Renvoie la liste des descriptions. 244 245 246 #### Parametres 247 description_pattern : dictionnaire 248 { 249 'path_pattern': pattern des chemins des fichiers à examiner, 250 'tags': paire de balises entourant la description 251 } 252 253 #### Renvoie 254 255 Liste de couples ['nom du document', 'description de document'] 256 257 """ 258 descriptions = [] 259 path_pattern = description_pattern['path_pattern'] 260 tags = description_pattern['tags'] 261 nomfics = glob.glob(path_pattern) 262 for nomfic in nomfics: 263 file = open(nomfic) 264 fictex = file.read() 265 file.close() 266 if i:= fictex.find(tags[0]) >= 0: 267 i += len(tags[0]) - 1 268 j = fictex.find(tags[1]) 269 nomfic = nomfic.removeprefix(path_pattern[0]) 270 nomfic = nomfic.removesuffix('.tex') 271 descriptions.append([nomfic,fictex[i:j]]) 272 return descriptions
Renvoie la liste des descriptions.
Parametres
description_pattern : dictionnaire { 'path_pattern': pattern des chemins des fichiers à examiner, 'tags': paire de balises entourant la description }
Renvoie
Liste de couples ['nom du document', 'description de document']