[stats_cableurs2] Maj pour les adhésions glissantes, et rationalisation.

* Il y a une fonction pour afficher des tableaux, j'ai ajouté le colour swapping
 sur les lignes.
 * Le parsing des arguments est amélioré.
 * J'ai viré les tabulations.
 * Il faut aérer le code !
This commit is contained in:
Pierre-Elliott Bécue 2014-09-01 00:06:15 +02:00
parent 87cfd39b7f
commit 096a243c77
2 changed files with 119 additions and 130 deletions

View file

@ -9,8 +9,8 @@
# --------- # ---------
# #
# Décorateur : # Décorateur :
# static_var(name, val), un décorateur pour créer une variable # static_var([(name, val)]), un décorateur pour créer des variables
# statique dans une fonction # statiques dans une fonction
# #
# Fonctions : # Fonctions :
# getTerminalSize(), une fonction qui récupère le couple # getTerminalSize(), une fonction qui récupère le couple
@ -47,13 +47,14 @@ term_format = '\x1b\[[0-1];([0-9]|[0-9][0-9])m'
dialog_format = '\\\Z.' dialog_format = '\\\Z.'
sep_col = u"|" sep_col = u"|"
def static_var(name, val): def static_var(couples):
"""Decorator setting static variable """Decorator setting static variable
to a function. to a function.
""" """
def decorate(fun): def decorate(fun):
functools.wraps(fun) functools.wraps(fun)
for (name, val) in couples:
setattr(fun, name, val) setattr(fun, name, val)
return fun return fun
return decorate return decorate
@ -220,7 +221,7 @@ def nostyle(dialog=False):
return "\Zn" return "\Zn"
return "\033[1;0m" return "\033[1;0m"
@static_var("styles", {}) @static_var([("styles", {})])
def style(texte, what=[], dialog=False): def style(texte, what=[], dialog=False):
""" """
Pretty text is pretty Pretty text is pretty
@ -396,7 +397,7 @@ def format_data(data, format):
return "%.2f %s" % (data/oct_sizes[i], oct_names[i]) return "%.2f %s" % (data/oct_sizes[i], oct_names[i])
return "%.0f o" % (data) return "%.0f o" % (data)
def tableau(data, titre=None, largeur=None, alignement=None, format=None, dialog=False, width=None, styles=None): def tableau(data, titre=None, largeur=None, alignement=None, format=None, dialog=False, width=None, styles=None, swap=[]):
""" """
Retourne une chaine formatée repésentant un tableau. Retourne une chaine formatée repésentant un tableau.
@ -418,6 +419,10 @@ def tableau(data, titre=None, largeur=None, alignement=None, format=None, dialog
o = octet o = octet
Si None, s pour chaque colonne Si None, s pour chaque colonne
width : force la largeur width : force la largeur
styles : applique une liste de styles, un à chaque colonne.
swap : Met styles à None et alterne une ligne sur deux niveau couleurs.
""" """
if data and isinstance(data, list): if data and isinstance(data, list):
@ -428,6 +433,11 @@ def tableau(data, titre=None, largeur=None, alignement=None, format=None, dialog
if format is None: if format is None:
format = ['s'] * nb_cols format = ['s'] * nb_cols
if swap != []:
styles = None
else:
swap = [None]
if styles is None: if styles is None:
styles = [None] * nb_cols styles = [None] * nb_cols
@ -465,7 +475,15 @@ def tableau(data, titre=None, largeur=None, alignement=None, format=None, dialog
# Les données # Les données
############# #############
chaine += u'\n'.join([sep_col + sep_col.join([style(ligne[i], styles[i]) for i in range(nb_cols)]) + sep_col for ligne in data]) j = 0
for ligne in data:
chaine += u"%s" % (sep_col,)
if swap:
chaine += sep_col.join([style(ligne[i], swap[j]) for i in range(nb_cols)])
else:
chaine += sep_col.join([style(ligne[i], styles[i]) for i in range(nb_cols)])
chaine += u"%s\n" % (sep_col,)
j = (j + 1) % len(swap)
return chaine return chaine

View file

@ -1,10 +1,11 @@
#!/bin/bash /usr/scripts/python.sh #!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# stats.py # stats_cableurs.py
# ----------------- # -----------------
# #
# Copyright (C) 2013,2014 Raphaël-David Lasseri <lasseri@crans.org>, # Copyright (C) 2013-2015 Raphaël-David Lasseri <lasseri@crans.org>,
# Pierre-Elliott Bécue <becue@crans.org>,
# #
# This file is free software; you can redistribute it and/or modify # This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -20,24 +21,27 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
import sys, re, datetime, string import sys
import re
import datetime
import string
import argparse import argparse
from lc_ldap import shortcuts from lc_ldap import shortcuts
from gestion.config import ann_scol import lc_ldap.crans_utils as crans_utils
import gestion.config as config
import gestion.affichage as affichage
### Appels à LDAP et tri initial sur l'année en cours ### Appels à LDAP et tri initial sur l'année en cours
db = shortcuts.lc_ldap_readonly() db = shortcuts.lc_ldap_readonly()
adherents=db.search(u'(&(paiement=%s)(aid=*))' % (ann_scol), sizelimit=2000) adherents = db.search(u'(&(debutAdhesion>=%s)(aid=*))' % (crans_utils.toGeneralizedTimeFormat(config.debut_periode_transitoire)), sizelimit=2000)
cableurs= db.search(u'(|(droits=cableur)(droits=nounou))') cableurs = db.search(u'(|(droits=cableur)(droits=nounou))')
scores=[] scores = []
historique=[] historique = []
#### On prends les historiques de tout les adhérents #### On prends les historiques de tout les adhérents
def parse_historique(ligne): def parse_historique(ligne):
u"""Parse une ligne d'historique et renvoie [ligne parsée],action """Parse une ligne d'historique et renvoie [ligne parsée],action
du cableur, date de l'action""" du cableur, date de l'action"""
champ = ligne.value.replace(',','').replace(':','').split(' ') champ = ligne.value.replace(',','').replace(':','').split(' ')
sdate = champ[0].split('/') sdate = champ[0].split('/')
@ -46,7 +50,7 @@ def parse_historique(ligne):
return champ,champ_action,date return champ,champ_action,date
def actions_cableurs(): def actions_cableurs():
u"""Renvoie l'historique de tous les adherents et tri en fonction """Renvoie l'historique de tous les adherents et tri en fonction
des actions éffectuées.""" des actions éffectuées."""
for adherent in adherents: for adherent in adherents:
histo=adherent.get('historique',None) histo=adherent.get('historique',None)
@ -54,120 +58,87 @@ def actions_cableurs():
champ=parse_historique(histo[j])[0] champ=parse_historique(histo[j])[0]
champ_action=parse_historique(histo[j])[1] champ_action=parse_historique(histo[j])[1]
date=parse_historique(histo[j])[2] date=parse_historique(histo[j])[2]
if ((champ_action==u'inscription' or champ_action==u'paiement+'+str(ann_scol)) or len(champ)>5 and (champ[5]==u'paiement+'+str(ann_scol) or champ[5]==u'inscription')) and date > datetime.date(ann_scol,8,1) : if ((champ_action == u'inscription' or champ_action == u'debutAdhesion+%s' % (crans_utils.toGeneralizedTimeFormat(config.debut_periode_transitoire),) ) or len(champ) > 5 and (champ[5] == u'debutAdhesion+%s' % (crans_utils.toGeneralizedTimeFormat(config.debut_periode_transitoire), ) or champ[5] == u'inscription')) and date > datetime.date(config.ann_scol, 8, 16) :
historique.append(champ) historique.append(champ)
return historique return historique
#### On parse l'historique et on trie #### On parse l'historique et on trie
def score_cableurs(): def score_cableurs():
u"""Calcul le score de tout les câbleurs en fonction des actions """Calcul le score de tout les câbleurs en fonction des actions
effectuées """ effectuées """
for cableur in cableurs: for cableur in cableurs:
inscriptions=reinscriptions=0 inscriptions = reinscriptions=0
nom=cableur.get(u'nom',None)[0].value nom = cableur.get(u'nom',None)[0].value
prenom=cableur.get(u'prenom',None)[0].value prenom = cableur.get(u'prenom',None)[0].value
uid=cableur.get(u'uid',None)[0].value uid = cableur.get(u'uid',None)[0].value
for l in range (0,len(historique)): for l in range (0,len(historique)):
histo_uid=historique[l][2] histo_uid = historique[l][2]
histo_action=historique[l][4] histo_action = historique[l][4]
if histo_uid==uid and histo_action==u'inscription': if histo_uid == uid and histo_action == u'inscription':
inscriptions=inscriptions+1 inscriptions = inscriptions+1
if histo_uid==uid and (histo_action==u'paiement+'+str(ann_scol) or (len(historique[l])>5 and (historique[l][5]==u'paiement+'+str(ann_scol)))): if histo_uid == uid and (histo_action == u'debutAdhesion+%s' % (crans_utils.toGeneralizedTimeFormat(config.debut_periode_transitoire),) or (len(historique[l])>5 and (historique[l][5] == u'debutAdhesion+%s' % (crans_utils.toGeneralizedTimeFormat(config.debut_periode_transitoire),)))):
reinscriptions=reinscriptions+1 reinscriptions = reinscriptions+1
score = 2*inscriptions+reinscriptions score = 2*inscriptions + reinscriptions
scores.append([prenom+' '+nom,score,inscriptions,reinscriptions]) scores.append(["%s %s" % (prenom, nom), score, inscriptions, reinscriptions])
return scores return scores
### Tri par score ### Tri par score
def sort_by_score(): def sort_by_score():
u"""Tri la liste des câbleurs par ordre de score décroissant de score""" """Tri la liste des câbleurs par ordre de score décroissant de score"""
return score_cableurs().sort(key=lambda x:int(x[1]),reverse=True) return score_cableurs().sort(key=lambda x:int(x[1]),reverse=True)
def sort_by_inverse_score(): def sort_by_inverse_score():
u"""Tri la liste des câbleurs par ordre de score croissant de score""" """Tri la liste des câbleurs par ordre de score croissant de score"""
return score_cableurs().sort(key=lambda x:int(x[1])) return score_cableurs().sort(key=lambda x:int(x[1]))
def cableurs_utiles(): def cableurs_utiles():
u"""Renvoi le nombre de cableurs ayant un score non nul""" """Renvoi le nombre de cableurs ayant un score non nul"""
useless_cableurs=0 useless_cableurs=0
for k in range(0,len(cableurs)): for k in range(0,len(cableurs)):
if (scores[k][1]==0): if (scores[k][1] == 0):
useless_cableurs=useless_cableurs+1 useless_cableurs = useless_cableurs+1
return len(cableurs)-useless_cableurs return len(cableurs) - useless_cableurs
#### Affichage ou x est le nombre de câbleurs à afficher #### Affichage ou x est le nombre de câbleurs à afficher
def show_all(x): def show_all(limit, swap):
u"""Tableau fait main pour un effet plus visuel""" """Tableau fait main pour un effet plus visuel"""
print '\033[0m ' + '\033[4m|',' '*8,u'Câbleur',' '*6,'|',u'Score',' |',u'Inscriptions',' ','|',u'Réinscriptions','\033[0m' titre = [u"Câbleur", u"Score", u"Inscriptions", u"Réinscriptions"]
for k in range(0,x): largeur = [25, 8, 16, 16]
if k%2==01: alignement = ["c", "c", "c", "c"]
print '\033[92m',string.ljust('|'+unicode((scores[k][0])),25), string.ljust('|'+str(scores[k][1]),8), string.ljust('|'+str(scores[k][2]),16),string.ljust('|'+str(scores[k][3]),16),'\033[0m' data = [[elem for elem in scores[index]] for index in xrange(limit)]
else: print affichage.tableau(data, titre=titre, largeur=largeur, alignement=alignement, swap=swap)
print '\033[0m',string.ljust('|'+unicode((scores[k][0])),25), string.ljust('|'+str(scores[k][1]),8), string.ljust('|'+str(scores[k][2]),16),string.ljust('|'+str(scores[k][3]),16),'\033[0m'
def show_all_no_color(x):
u"""Tableau fait main pour un effet plus visuel sans couleur"""
print '\033[0m ' + '\033[4m|',' '*8,u'Câbleur',' '*6,'|',u'Score',' |',u'Inscriptions',' ','|',u'Réinscriptions','\033[0m'
for k in range(0,x):
print '\033[0m',string.ljust('|'+unicode((scores[k][0])),25), string.ljust('|'+str(scores[k][1]),8), string.ljust('|'+str(scores[k][2]),16),string.ljust('|'+str(scores[k][3]),16),'\033[0m'
#### On définit le Parser #### On définit le Parser
if __name__ == "__main__": if __name__ == "__main__":
actions_cableurs() actions_cableurs()
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("-a", "--all", help="Affiche les scores de tout les câbleurs", parser.add_argument("-a", "--all", help="Affiche les scores de tout les câbleurs", action="store_true")
action="store_true") parser.add_argument("-t", "--top", help="Affiche seulement les meilleurs câbleurs", action="store_true")
parser.add_argument("-t", "--top", help="Affiche seulement les meilleurs câbleurs", parser.add_argument("-s", "--scores", help="Affiche seulement les câbleurs ayant un score non nul", action="store_true")
action="store_true") parser.add_argument("-m", "--menage", help="Affiche seulement les câbleurs ayant un score nul", action="store_true")
parser.add_argument("-s", "--scores", help="Affiche seulement les câbleurs ayant un score non nul", parser.add_argument("-n", "--nocolour", help="Désactive la couleur", action="store_true")
action="store_true")
parser.add_argument("-m", "--menage", help="Affiche seulement les câbleurs ayant un score nul",
action="store_true")
parser.add_argument("-a_nc", "--ncall", help="Affiche les scores de tout les câbleurs (sans couleur)",
action="store_true")
parser.add_argument("-t_nc", "--nctop",
action="store_true")
parser.add_argument("-s_nc", "--ncscores",
action="store_true")
parser.add_argument("-m_nc", "--ncmenage",
action="store_true")
args = parser.parse_args() args = parser.parse_args()
if args.nocolour:
swap = []
else:
swap = [None, "vert"]
if args.all: if args.all:
sort_by_score() sort_by_score()
show_all(len(cableurs)) show_all(len(cableurs), swap=swap)
elif args.scores: elif args.scores:
sort_by_score() sort_by_score()
show_all(cableurs_utiles()) show_all(cableurs_utiles(), swap=swap)
elif args.menage: elif args.menage:
sort_by_inverse_score() sort_by_inverse_score()
show_all(len(cableurs)-cableurs_utiles()) show_all(len(cableurs)-cableurs_utiles(), swap=swap)
elif args.top: elif args.top:
sort_by_score() sort_by_score()
show_all(5) show_all(5, swap=swap)
elif args.ncall:
sort_by_score()
show_all_no_color(len(cableurs))
elif args.ncscores:
sort_by_score()
show_all_no_color(cableurs_utiles())
elif args.ncmenage:
sort_by_inverse_score()
show_all_no_color(len(cableurs)-cableurs_utiles())
elif args.nctop:
sort_by_score()
show_all_no_color(5)
else: else:
sort_by_score() sort_by_score()
show_all(10) show_all(10, swap=swap)