[stats_cableurs] Rcriture du script
Ignore-this: 61894b618f182f8d08129c2ba96a5ee1 * ne marche pas en unicode * ne marche pas sous python 2.4 darcs-hash:20090329213507-bd074-27b2cad7615c89c4dfbd4ecf6d487d63aada99d0.gz
This commit is contained in:
parent
f1cb76f449
commit
8036930aa5
1 changed files with 238 additions and 174 deletions
|
@ -23,10 +23,14 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
|
||||
|
||||
import sys, re, datetime, time
|
||||
import sys, re, datetime
|
||||
from optparse import OptionParser
|
||||
|
||||
sys.path.append("/usr/scripts/gestion/")
|
||||
from ldap_crans import CransLdap
|
||||
from affich_tools import cprint
|
||||
from config import ann_scol
|
||||
|
||||
|
||||
|
||||
db = CransLdap()
|
||||
|
||||
|
@ -42,7 +46,8 @@ def parse_ligne_histo(ligne):
|
|||
return date, champ
|
||||
|
||||
def parse_historique(truc):
|
||||
u"""Parse l'historique"""
|
||||
u"""Parse l'historique et renvoie la liste des actions sous la forme
|
||||
(['dd', 'mm', 'yyyy'], ['date', 'heure', 'who', 'what'])"""
|
||||
return [ parse_ligne_histo(ligne) for ligne in truc.historique() ]
|
||||
|
||||
def dec_date(date):
|
||||
|
@ -54,12 +59,21 @@ def dec_date(date):
|
|||
class StatsCableursBase:
|
||||
u"""Classe prototype pour afficher des stats de câbleurs."""
|
||||
|
||||
colonnes = [('score', u'Son score')]
|
||||
colonnes = []
|
||||
nbmois = 4
|
||||
stats = {}
|
||||
score = {}
|
||||
kwargs = {}
|
||||
|
||||
def __init__(self, mois = -4):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.kwargs.update(kwargs)
|
||||
self.affiche (self.kwargs, 'd')
|
||||
|
||||
# On regarde s'il y a un mois à partir duquel on veuille partir.
|
||||
mois = kwargs.get("mois", -4)
|
||||
|
||||
# On compte ensuite combien de mois ça fait
|
||||
if mois > 0:
|
||||
# si on demande depuis 09 (septembre) , on remonte
|
||||
# jusqu'à septembre
|
||||
|
@ -69,50 +83,87 @@ class StatsCableursBase:
|
|||
# mois
|
||||
self.nbmois = - mois
|
||||
|
||||
# On récupère les statistiques
|
||||
# On regarde si on avait pas déjà précisé sur combien de mois on
|
||||
# voulait partir.
|
||||
self.nbmois = kwargs.get("nbmois", self.nbmois)
|
||||
|
||||
# bout de code à mon avis explicite
|
||||
self.def_columns()
|
||||
self.affiche("Génération des stats")
|
||||
self.get_stats()
|
||||
self.calc_score()
|
||||
cableurs = self.sort_cableurs()
|
||||
self.print_stats(cableurs)
|
||||
|
||||
# On les affiche
|
||||
self.print_stats()
|
||||
|
||||
def def_columns(self):
|
||||
u"""Fonction qui sera appelée pour éventuellement mettre à jour
|
||||
self.colonnes"""
|
||||
pass
|
||||
|
||||
def get_stats(self):
|
||||
u"""Génération dummy de statistiques"""
|
||||
self.stats = {}
|
||||
u"""Fonction censée récupérer les stats des différents câbleurs,
|
||||
et les fouttre dans self.stats"""
|
||||
raise NotImplementedError
|
||||
|
||||
def print_stats(self):
|
||||
def calc_score(self):
|
||||
u"""Fonction censée calculer le score en fonction des stats, et
|
||||
le mettre dans self.score"""
|
||||
raise NotImplementedError
|
||||
|
||||
def sort_cableurs(self):
|
||||
u"""Renvoie la liste des câbleurs triés, en fonction de leur score"""
|
||||
cableurs = self.stats.keys()
|
||||
cableurs.sort(lambda x, y : cmp(self.score[x], self.score[y]), reverse=True)
|
||||
|
||||
if self.kwargs.get('top', 10) != 0:
|
||||
cableurs = cableurs[:self.kwargs.get('top', 10)]
|
||||
return cableurs
|
||||
|
||||
def print_stats(self, cableurs):
|
||||
u"""Affiche pour chaque cableur les valeurs de ses différentes colonnes
|
||||
définies dans self.colonnes."""
|
||||
stats = self.stats
|
||||
cableurs = stats.keys()
|
||||
|
||||
### Si quelqu'un trouve une manière plus élégante de faire…
|
||||
try:
|
||||
cableurs.sort(lambda x, y : cmp(stats[x]['score'], stats[y]['score']), reverse=True)
|
||||
except TypeError:
|
||||
cableurs.sort(lambda x, y : cmp(stats[x][0], stats[y][0]), reverse=True)
|
||||
# On génère la liste des noms sous lesquels on va afficher nos câbleurs
|
||||
noms = {}
|
||||
for cableur in cableurs:
|
||||
try:
|
||||
ldap_cableur = db.search('login=%s' % cableur)['adherent'][0]
|
||||
ids = { 'nom' : ldap_cableur.nom(),
|
||||
'prenom' : ldap_cableur.prenom(),
|
||||
'droits' : reduce(unicode.__add__,
|
||||
[d[0] for d in ldap_cableur.droits()], u''),
|
||||
'login' : cableur }
|
||||
noms[cableur] = self.kwargs.get("fqn", "%(prenom)s %(nom)s") % ids
|
||||
except IndexError:
|
||||
self.affiche ("Unknown cableur %s!" % cableur, 'd')
|
||||
noms[cableur] = cableur+'*'
|
||||
|
||||
long_max = reduce(lambda m, c : max(m, len(c)), cableurs, len('cableur'))
|
||||
# On récupère la liste des câbleurs, triés en fonction de leur score
|
||||
long_max = reduce(lambda m, c : max(m, len(c)), noms.values(), len('cableur'))
|
||||
|
||||
# Titres des colonnes
|
||||
ligne = "%-*s" % (long_max, u'Câbleur')
|
||||
for typ, nom in self.colonnes:
|
||||
ligne += " | %s" % nom
|
||||
cprint(ligne)
|
||||
ligne += " | Score"
|
||||
for col in self.colonnes:
|
||||
ligne += " | %s" % col
|
||||
print(ligne)
|
||||
|
||||
# Ligne pour délimiter
|
||||
ligne = ''.center(long_max, '-')
|
||||
for typ, nom in self.colonnes:
|
||||
ligne += "-+-%s" % ''.center(len(nom), '-')
|
||||
cprint(ligne)
|
||||
ligne = '-' * long_max
|
||||
ligne += "-+-%s" % ('-' * len ("score"))
|
||||
for col in self.colonnes:
|
||||
ligne += "-+-%s" % ('-' * len(col))
|
||||
print(ligne)
|
||||
|
||||
# Statiqtiques par câbleur
|
||||
for cableur in cableurs:
|
||||
acts = stats[cableur]
|
||||
ligne = "%-*s" % (long_max, cableur)
|
||||
for typ, nom in self.colonnes:
|
||||
ligne += " | %*d" % (len(nom), acts[typ])
|
||||
cprint(ligne)
|
||||
acts = self.stats[cableur]
|
||||
ligne = "%-*s" % (long_max, noms[cableur])
|
||||
ligne += " | %*d" % (len ("score"), self.score[cableur])
|
||||
for i in range (len (self.colonnes)):
|
||||
ligne += " | %*d" % (len(self.colonnes[i]), acts[i])
|
||||
print(ligne)
|
||||
|
||||
def sort_events(self, events):
|
||||
u"""Split une liste d'évènements selon les mois"""
|
||||
|
@ -129,12 +180,25 @@ class StatsCableursBase:
|
|||
sorted_events.append(events)
|
||||
return sorted_events
|
||||
|
||||
def affiche(self, msg, reqs= 'v'):
|
||||
u"""Fonction de print qui n'affiche que si on est dans un mode
|
||||
kikoolol, debug ou verbose suffisamment avancé."""
|
||||
try:
|
||||
pool = list (self.kwargs.get('flags', ''))
|
||||
for i in reqs:
|
||||
pool.remove(i)
|
||||
print msg
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
|
||||
class StatsCableursMachines(StatsCableursBase):
|
||||
u"""Cette classe s'occupe de recenser l'activité des différents
|
||||
câbleurs sur les machines, ce qui représente le travail typique du
|
||||
câbleur en milieu d'année"""
|
||||
|
||||
kwargs = { 'fqn' : '%(login)s' , 'top' : 0 }
|
||||
|
||||
def ajoute_actions(self, machine, hist):
|
||||
u"""Ajoute dans hist la liste des actions effectués par
|
||||
chacuns des câbleurs sur la machine pendant les mois."""
|
||||
|
@ -152,6 +216,18 @@ class StatsCableursMachines(StatsCableursBase):
|
|||
except KeyError:
|
||||
hist[champ[2]] = [ (date, champ[3]) ]
|
||||
|
||||
def def_columns(self):
|
||||
u"""Simplement une par mois, plus une pour toutes les actions
|
||||
d'avant."""
|
||||
|
||||
month = datetime.date.replace(datetime.date.today(), day=1)
|
||||
for i in range(self.nbmois):
|
||||
self.colonnes.append("%d/%02d" % (month.month, month.year - 2000))
|
||||
month = dec_date(month)
|
||||
|
||||
self.colonnes.append("< " + self.colonnes[-1])
|
||||
|
||||
|
||||
def get_stats(self):
|
||||
u"""Récupère les statistiques des différents câbleurs sur les
|
||||
différentes machines"""
|
||||
|
@ -178,151 +254,139 @@ class StatsCableursMachines(StatsCableursBase):
|
|||
for cableur in hists.keys():
|
||||
split_hist[cableur] = self.sort_events(hists[cableur])
|
||||
self.stats[cableur] = [ len(i) for i in split_hist[cableur] ]
|
||||
score = sum (self.stats[cableur][:-1])
|
||||
self.stats[cableur].insert(0, score)
|
||||
|
||||
month = datetime.date.today()
|
||||
for i in range(self.nbmois):
|
||||
self.colonnes.append( (i + 1, "%d/%02d" % (month.month, month.year - 2000)))
|
||||
month = dec_date(month)
|
||||
|
||||
self.colonnes[0] = (0, "%d last" % self.nbmois)
|
||||
self.colonnes.append( (self.nbmois +1, "< " + self.colonnes[-1][1]) )
|
||||
def calc_score(self):
|
||||
u"""Le calcul se fait simplement comme la somme des actions
|
||||
(indépendamment de leur type pour l'instant) sur les mois
|
||||
concernés."""
|
||||
|
||||
for cableur in self.stats.keys():
|
||||
self.score[cableur] = sum (self.stats[cableur][:-1])
|
||||
|
||||
|
||||
|
||||
class StatsCableursAdherents(StatsCableursBase):
|
||||
u"""Cette classe s'occupe de recenser les actions que les câbleurs
|
||||
font sur les adhérents (en fait les {,re}adhésions)."""
|
||||
|
||||
colonnes = [ u'Inscriptions', u'Réinscriptions' ]
|
||||
|
||||
debut_ann_scol = datetime.date(ann_scol, 8, 1)
|
||||
paiement_ann_scol = "paiement+%d" % ann_scol
|
||||
|
||||
def donne_cableur(self, adherent):
|
||||
u""" Cherche le cableur qui a inscrit ou réinscrit un adhérent. """
|
||||
|
||||
# Est-ce qu'on recherche une inscription ou une reinscription?
|
||||
date_inscr = datetime.date.fromtimestamp(adherent.dateInscription())
|
||||
if date_inscr < self.debut_ann_scol:
|
||||
action = 1 # 'reinscription'
|
||||
action_filtre = self.paiement_ann_scol
|
||||
else:
|
||||
action = 0 # 'inscription'
|
||||
action_filtre = 'inscription'
|
||||
|
||||
for date, champ in parse_historique(adherent):
|
||||
if date >= self.debut_ann_scol:
|
||||
# Maintenant on regarde si l'action recherchee est ici
|
||||
if action_filtre in champ[3:]:
|
||||
return action, champ[2]
|
||||
|
||||
return action, None
|
||||
|
||||
|
||||
def get_stats(self):
|
||||
u"""Calcule le nombre d'inscriptions et réinscription pour tous
|
||||
les cableurs ayant inscrit ou réinscrit quelqu'un pour l'année
|
||||
en cours."""
|
||||
|
||||
liste = db.search("paiement=%s" % ann_scol)['adherent']
|
||||
|
||||
for adherent in liste:
|
||||
action, cableur = self.donne_cableur(adherent)
|
||||
if cableur:
|
||||
if not self.stats.has_key(cableur):
|
||||
self.stats[cableur] = [0, 0]
|
||||
self.stats[cableur][action] += 1
|
||||
|
||||
|
||||
def calc_score(self):
|
||||
u"""Calcule le score d'un câbleur, en fonction du nombre
|
||||
d'adhésions qu'il a effectué"""
|
||||
|
||||
# On calcule le score total pour chaque cableur
|
||||
for cableur in self.stats.keys():
|
||||
self.score[cableur] = 2 * self.stats[cableur][0] + self.stats[cableur][1]
|
||||
|
||||
|
||||
|
||||
|
||||
def update_fqn(option, opt_str, value, this, fmt):
|
||||
u"""Utilisée dans le parser, cette fonction permet de mettre à jour
|
||||
correctement la chaîne de format"""
|
||||
try:
|
||||
if opt_str not in ['-d', '--droits']:
|
||||
if re.match ('^ \(%\(droits\)s\)', this.values.fqn):
|
||||
this.values.fqn = fmt + this.values.fqn
|
||||
else:
|
||||
this.values.fqn = this.values.fqn + (' (%s)' % fmt)
|
||||
else:
|
||||
this.values.fqn = this.values.fqn + fmt
|
||||
except TypeError:
|
||||
this.values.fqn = fmt
|
||||
|
||||
def notimplerr(option, opt_str, value, parseur):
|
||||
u"""Un callback pour le parser pour renvoyer un NotImplementedError"""
|
||||
raise NotImplementedError
|
||||
|
||||
if __name__ == "__main__":
|
||||
StatsCableursMachines()
|
||||
usage = "usage: %prog [options]\n %prog [options] [--efficiency -e]"
|
||||
parser = OptionParser(usage=usage)
|
||||
|
||||
## class StatsCableursAdherents:
|
||||
## u"""Cette classe s'occupe de recenser les actions que les câbleurs
|
||||
## font sur les adhérents (en fait les {,re}adhésions)."""
|
||||
##
|
||||
## colonnes = [('inscription', u'inscription'),
|
||||
## ('reinscription', u'réinscription'),
|
||||
## ('total', u'score total')]
|
||||
##
|
||||
## date_debut_ann_scol = time.mktime((ann_scol, 8, 1, 0, 0, 0, 0, 0, 0))
|
||||
## paiement_ann_scol = "paiement+%d" % ann_scol
|
||||
##
|
||||
## def donne_cableur(mois, adherent):
|
||||
## u""" Cherche le cableur qui a inscrit ou réinscrit un adhérent. """
|
||||
## cableur = None
|
||||
##
|
||||
## # Est-ce qu'on recherche une inscription ou une reinscription?
|
||||
## if adherent.dateInscription() < self.date_debut_ann_scol:
|
||||
## action = 'reinscription'
|
||||
## action_filtre = self.paiement_ann_scol
|
||||
## else:
|
||||
## action = 'inscription'
|
||||
## action_filtre = 'inscription'
|
||||
##
|
||||
## for hist in adherent.historique():
|
||||
## # On decoupe pour avoir un truc utilisable
|
||||
## champ = hist.replace(',', '').replace(': ', '').split(' ')
|
||||
## # On inspecte la date
|
||||
## date = champ[0].split('/')
|
||||
## if int(date[1]) in mois and int(date[2]) == ann_scol:
|
||||
## # Maintenant on regarde si l'action recherchee est ici
|
||||
## if action_filtre in champ[3:]:
|
||||
## return action, champ[2]
|
||||
##
|
||||
## return action, None
|
||||
##
|
||||
## def calcul_score(mois):
|
||||
## u""" Calcul le score de tous les cableurs ayant inscrit ou
|
||||
## réinscrit quelqu'un pour l'année en cours. """
|
||||
##
|
||||
## liste = db.search("paiement=2008")['adherent']
|
||||
##
|
||||
## score = {}
|
||||
## for adherent in liste:
|
||||
## action, cableur = donne_cableur(mois, adherent)
|
||||
## if cableur:
|
||||
## if not score.has_key(cableur):
|
||||
## score[cableur] = { 'inscription': 0,
|
||||
## 'reinscription': 0 }
|
||||
## score[cableur][action] += 1
|
||||
##
|
||||
## # On calcul le score total pour chaque cableur
|
||||
## for s in score.values():
|
||||
## s['total'] = 2 * s['inscription'] + s['reinscription']
|
||||
##
|
||||
## return score
|
||||
##
|
||||
## def classement(score={}):
|
||||
## u""" Retourne la liste des câbleurs classé par score total décroisant. """
|
||||
## cableurs = score.keys()
|
||||
## cableurs.sort(lambda x, y : cmp(score[x]['total'], score[y]['total']), reverse=True)
|
||||
## return cableurs
|
||||
##
|
||||
##
|
||||
##
|
||||
## if __name__ == "__main__":
|
||||
## nb_affiche = 10
|
||||
## mois = range(8, 11)
|
||||
## if len(sys.argv) > 1:
|
||||
## if sys.argv[1] == '-e':
|
||||
## mois = range(8, 13)
|
||||
## if len(sys.argv) > 2:
|
||||
## try:
|
||||
## nb_affiche = int(sys.argv[2])
|
||||
## except ValueError:
|
||||
## nb_affiche = 10
|
||||
## else:
|
||||
## try:
|
||||
## nb_affiche = int(sys.argv[1])
|
||||
## except ValueError:
|
||||
## nb_affiche = 10
|
||||
##
|
||||
## if sys.argv[1] == '--efficiency':
|
||||
## ActionsCableurs([(1, 2009), (2, 2009), (3, 2009)])
|
||||
## sys.exit(0)
|
||||
##
|
||||
## score = calcul_score(mois)
|
||||
## classement = classe(score)
|
||||
##
|
||||
## if nb_affiche > 0:
|
||||
## classement = classement[0:nb_affiche]
|
||||
##
|
||||
## # On cherche les noms des câbleurs parceque c'est quand même mieux
|
||||
## nom_reel = {}
|
||||
## for cableur in classement:
|
||||
## nom_reel[cableur] = db.search('uid=%s' % cableur)['adherent'][0].Nom()
|
||||
##
|
||||
## # Calcul des statistiques
|
||||
## total_inscription = 0
|
||||
## total_reinscription = 0
|
||||
## total = 0
|
||||
## for s in score.values():
|
||||
## total_inscription += s['inscription']
|
||||
## total_reinscription += s['reinscription']
|
||||
## total += s['total']
|
||||
## cprint(u"""Statistiques globales:
|
||||
## - inscriptions: %(inscription)d
|
||||
## - réinscription: %(reinscription)d
|
||||
## - total: %(total)d
|
||||
##
|
||||
## """ % { 'inscription': total_inscription,
|
||||
## 'reinscription': total_reinscription,
|
||||
## 'total': total }, newline=False)
|
||||
##
|
||||
## # Calcul la longueur du nom le plus long
|
||||
## long_max = reduce(lambda m, c : max(m, len(c)), nom_reel.values(), len('cableur'))
|
||||
##
|
||||
##
|
||||
## # Titres des colonnes
|
||||
## ligne = "%-*s" % (long_max, u'câbleur')
|
||||
## for typ, nom in colonnes:
|
||||
## ligne += " | %s" % nom
|
||||
## cprint(ligne)
|
||||
## # Ligne pour délimiter
|
||||
## ligne = ''.center(long_max, '-')
|
||||
## for typ, nom in colonnes:
|
||||
## ligne += "-+-%s" % ''.center(len(nom), '-')
|
||||
## cprint(ligne)
|
||||
## # Statiqtiques par câbleur
|
||||
## for cableur in classement:
|
||||
## score_cableur = score[cableur]
|
||||
## ligne = "%-*s" % (long_max, nom_reel[cableur])
|
||||
## for typ, nom in colonnes:
|
||||
## ligne += " | %*d" % (len(nom), score_cableur[typ])
|
||||
## cprint(ligne)
|
||||
# options pour décider le nombre de câbleurs à afficher
|
||||
parser.add_option('-a', '--all', help= u"Affiche tous les câbleurs",
|
||||
action='store_const', const=0, dest='top')
|
||||
parser.add_option('-t', '--top', metavar= "NB", help= u"N'affiche que les NB meilleurs câbleurs",
|
||||
type= 'int', dest='top')
|
||||
|
||||
# options pour le format d'affichage des câbleurs
|
||||
parser.add_option('-d', '--droits', help= u"Affiche les droits du câbleur",
|
||||
action='callback', callback= update_fqn, callback_kwargs= { 'fmt': ' (%(droits)s)'})
|
||||
parser.add_option('-F', '--full-name', help=u"Affiche Prenom Nom des câbleurs",
|
||||
action='callback', callback= update_fqn, callback_kwargs= { 'fmt': '%(prenom)s %(nom)s'})
|
||||
parser.add_option('-l', '--login', help= u"Affiche le login des câbleurs",
|
||||
action='callback', callback= update_fqn, callback_kwargs= { 'fmt': '%(login)s'})
|
||||
parser.add_option('--fqn', dest='fqn',
|
||||
help= u"Définit le format d'affichage du nom du câbleur, les champs possibles sont %(droits)s, %(nom)s, %(prenom)s, %(login)s")
|
||||
|
||||
# options de verbosité
|
||||
parser.add_option('-D', '--debug', help= u"Affiche des informations de debuggage",
|
||||
action='append_const', const='d', dest= 'flags')
|
||||
parser.add_option('-k', '--kikoolol', help="Affiche des trucs kikoolol",
|
||||
action='callback', callback= notimplerr)
|
||||
parser.add_option('-v', '--verbose', help= u"Augmente la verbosité",
|
||||
action='append_const', const= 'd', dest= 'flags')
|
||||
|
||||
# options sur la durée étudiée
|
||||
parser.add_option('-f', '--for', metavar= 'N', help= u"Affiche les statistiqes depuis N mois",
|
||||
type= 'int', dest='nbmois')
|
||||
parser.add_option('-s', '--since', metavar= 'MM', help= u'Affiche les stats depuis MOIS',
|
||||
type= 'int', dest='mois')
|
||||
|
||||
# Devrait plutôt être un argument qu'une option
|
||||
parser.add_option('-e', '--efficiency', help= u"Compte les actions effectuées sur les machines",
|
||||
action= 'store_const', const= StatsCableursMachines, dest= 'default_stats',
|
||||
default= StatsCableursAdherents)
|
||||
|
||||
# on parse, enfin, on laisse optparse le faire pour nous
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
# Parce que les clefs ont par défaut la valeur None
|
||||
kwargs = {}
|
||||
for lbl, field in options.__dict__.items():
|
||||
if field != None and lbl != 'default_stats':
|
||||
kwargs[lbl] = field
|
||||
|
||||
# On apelle les stats que l'on veut calculer
|
||||
options.default_stats(**kwargs)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue