quote_matcher_with_timestamp = re.compile(config.quote_regexp_with_timestamp, flags=re.UNICODE)
spaces_matcher = re.compile(u"\s", flags=re.U)
+def equivalence_partition(iterable, relation):
+ """ Partitionne l'itérable en classes d'équivalences. """
+ classes = []
+ for o in iterable:
+ # find the class it is in
+ found = False
+ for c in classes:
+ if relation( iter(c).next(), o ): # is it equivalent to this class?
+ c.add( o )
+ found = True
+ break
+ if not found: # it is in a new class
+ classes.append( set( [ o ] ) )
+ return classes
+
def get_now():
""" Renvoie la date actuelle """
return datetime.datetime(*time.localtime()[:6])
class Quote(object):
""" Une citation """
- def __init__(self, author, content, timestamp=None):
+ def __init__(self, author, content, timestamp=None, place=None, quoter=None):
if timestamp is None:
timestamp = get_now()
elif isinstance(timestamp, basestring):
self.author = sanitize_author(author)
self.content = content
self.timestamp = timestamp
+ self.place = place
+ self.quoter = quoter
def jsonize(self):
d = {"author" : self.author, "content" : self.content,
- "timestamp" : self.timestamp.strftime(u"%F_%T")}
+ "timestamp" : self.timestamp.strftime(u"%F_%T"),
+ "place" : self.place, "quoter" : self.quoter}
return d
def __unicode__(self):
def __str__(self):
return unicode(self).encode("utf-8")
+ def full_str(self):
+ """ Retourne une chaîne représentant la totalité des infos de la quote,
+ tout en étant parsable et human-readable. """
+ place = self.place if self.place else ""
+ quoter = self.quoter if self.quoter else ""
+ return (u"%s %s | %s | %s" % (self.timestamp.strftime("%F_%T"), unicode(self), place, quoter)).encode("utf-8")
+
def __eq__(self, otherquote):
""" Vérifie si cette phrase n'a pas déjà été dite par la même personne.
Indépendamment de la date et de la casse. """
""" Sauvegarde la DB dans le fichier de quotes """
save_file(self.quotelist, config.quote_file)
- def store(self, author, content, timestamp=None):
+ def _collapse_author(self, author):
+ """ Renvoie ``author`` avec la casse déjà utilisée si il a déjà été quoté
+ sinon, le renvoie sans le modifier. """
+ authors = list(set([q.author for q in self.quotelist if q.author.lower() == author.lower()]))
+ if len(authors) > 1:
+ print "Warning : authors %s" % authors
+ if authors:
+ return authors[0]
+ else:
+ return author
+
+ def get_clash_authors(self):
+ """ Renvoie une liste de liste d'auteurs qui sont enresgitrés avec des casses différentes. """
+ authors = list(set([q.author for q in self.quotelist]))
+ authors = equivalence_partition(authors, lambda x,y: x.lower() == y.lower())
+ authors = [list(c) for c in authors if len(c) > 1]
+ return authors
+
+ def store(self, timestamp=None, **kwargs):
""" Enregistre une nouvelle quote, sauf si elle existe déjà.
+ Force l'auteur à utiliser la même casse si un auteur de casse différente existait déjà.
Renvoie ``True`` si elle a été ajoutée, ``False`` si elle existait. """
- newquote = Quote(author, content, timestamp)
+ kwargs["author"] = self._collapse_author(kwargs["author"])
+ kwargs["timestamp"] = timestamp
+ newquote = Quote(**kwargs)
if not newquote in self.quotelist:
+ self.search
self.quotelist.append(newquote)
return True
return False
-
+
def __repr__(self):
return repr(self.quotelist)
-
+
def random(self):
""" Sort une quote aléatoire """
return random.choice(self.quotelist)
author = ""
l = [q for q in self.quotelist if inquote in q.content and author in q.author]
return l
-
+
def search_authors(self, author=None, regexp=False):
"""Renvoie la liste des auteurs contenant ``author`` ou qui matchent la regexp."""
if regexp:
"""Pour exporter les quotes dans un format readable vers un fichier."""
if dump_file is None:
dump_file = config.quote_dump_file
- t = "\n".join(["%s %s" % (q.timestamp.strftime("%F_%T"), q) for q in quotedb.quotelist]) + "\n"
+ t = "\n".join([q.full_str() for q in quotedb.quotelist]) + "\n"
with open(dump_file, "w") as f:
f.write(t)