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. """
- return [self.author, self.content] == [otherquote.author, otherquote.content]
+ Indépendamment de la date et de la casse. """
+ return [self.author.lower(), self.content.lower()] == [otherquote.author.lower(), otherquote.content.lower()]
def parse(text, date=None):
""" 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)
+ def quotesfrom(self, author):
+ """ Sort toutes les quotes de ``author`` """
+ return [q for q in self.quotelist if q.author == author]
def randomfrom(self, author):
""" Sort une quote aléatoire de ``author`` """
- return random.choice([q for q in self.quotelist if q.author == author])
+ return random.choice(self.quotesfrom(author))
def search(self, inquote=None, author=None, regexp=False):
"""Fait une recherche dans les quotes."""
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)