# Parcial 2 2021/22 (c) 2022 Baltasar MIT License <jbgarcia@uvigo.es>
import json
from datetime import datetime
class RegistroTelefonico:
"""La clase RegistroTelefonico es capaz de albergar
cuándo se produjeron las llamadas de los usuarios
de una compañía telefónica, a través de un diccionario
de claves datetime (hasta el segundo, no microsegundo) y
valores de listas conteniendo varias
cadenas de caracteres correspondientes a las diferentes
llamadas comenzadas en ese momento.
Las listas con los números de teléfono pueden ser
accedidos como tuplas por el momento en el que se produjeron las llamadas,
mediante el método ficticio get_for(d: datetime) -> tuple[str],
o bien mediante un método ficticio get(i: int) -> tuple[str],
de manera que get(0) devuelve la primera tupla de teléfonos
ordenadas según el momento de la llamada.
por nombre construido (r#i), o por índice.
El constructor no necesita ningún parámetro.
Los únicos métodos en la clase son:
__init__(), add(d: datetime, ll: str), __getattr__(),
__len__() (que devuelve el número de elementos),
y __str__() (que devuelve el contenido del objeto como
texto, en el formato: <formato_datetime_defecto>: 999999999, 999999999).
"""
def __init__(self):
self._modified = True
self._cache = tuple()
self._reg = {}
@staticmethod
def __datetime_cnv(d: datetime):
"""Convierte un datetime con microsegundos a otro sin él."""
return datetime(d.year, d.month, d.day, d.hour, d.minute, d.second)
def inserta(self, d: datetime, tlf: str):
"""Añade un teléfono a la lista para ese momento"""
self._modified = True
dm = RegistroTelefonico.__datetime_cnv(d)
lls = self._reg.get(dm)
if not lls:
self._reg[dm] = [tlf]
else:
lls.append(tlf)
def __crea_cache(self):
if self._modified:
self._cache = list(self._reg.items())
self._cache.sort(key=lambda it: it[0])
self._cache = tuple(self._cache)
self._modified = False
def __getattr__(self, item):
if item == "get":
self.__crea_cache()
return lambda i: tuple(self._cache[i])
elif item == "get_for":
return lambda d: tuple(self._reg.get(d)) if self._reg.get(d) else tuple()
raise AttributeError(item)
def to_json(self):#, f):
"""
Convertir los datos del objeto en JSON a un fichero.
Formato:
{
'2022-05-13 10:41:00': ["988387000", "988387002"],
'2022-05-13 10:41:35': ["988387001"]
}
"""
d_dump = {str(k): v for k, v in self._reg.items()}
return json.dumps(d_dump)#, f)
@staticmethod
def from_json(str_json_data):# f):
"""
Convertir los datos del fichero a JSON y asignar el diccionario.
Formato:
{
'2022-05-13 10:41:00': ["988387000", "988387002"],
'2022-05-13 10:41:35': ["988387001"]
}
"""
d_dump = json.loads(str_json_data)# f)
d_dump = {datetime.strptime(k, "%Y-%m-%d %H:%M:%S"): v for k, v in d_dump.items()}
toret = RegistroTelefonico()
toret._reg = d_dump
return toret
def filter(self, pred: callable):
"""Devolver aquellos elementos (completos) de la cache que cumplen pred."""
return [tupla for tupla in self._cache if pred(tupla)]
def __len__(self):
return len(self._reg)
def __str__(self):
self.__crea_cache()
return str.join("\n", [str(pair[0]) + ": "
+ ", ".join([tlf for tlf in pair[1]])
for pair in self._cache])
if __name__ == "__main__":
r = RegistroTelefonico()
r.inserta(datetime(2022, 9, 13, 10, 41), "988387000")
r.inserta(datetime(2022, 9, 13, 10, 41), "988387002")
r.inserta(datetime(2022, 9, 13, 10, 41, 35), "988387001")
print(r.get(0))
print("Filtrado por segundo no 0: " + str(r.filter(lambda t: t[0].second != 0)))
print("Filtrado primer tlf acabado en 02: " + str(r.filter(lambda t: t[1][0].endswith("01"))))
# Modificado para que se pueda ejecutar en IDEOne,
# Se pedía utilizar ficheros y json.dump()/json.load()
# en lugar de json.dumps()/json.loads()
json_data = r.to_json()
print("Guardando: " + json_data)
print("Recuperando:\n" + str(RegistroTelefonico.from_json(json_data)))