Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import sys
- import sqlite3
- import os.path
- from functools import total_ordering
- BANCO = """
- create table tipos(id integer primary key autoincrement,
- descripción text);
- create table nombres(id integer primary key autoincrement,
- nombre text);
- create table teléfonos(id integer primary key autoincrement,
- id_nombre integer,
- número text,
- id_tipo integer);
- insert into tipos(descripción) values ("Celular");
- insert into tipos(descripción) values ("Fijo");
- insert into tipos(descripción) values ("Fax");
- insert into tipos(descripción) values ("Casa");
- insert into tipos(descripción) values ("Trabajo");
- """
- def nulo_o_vacío(texto):
- return texto == None or not texto.strip()
- def valida_franja_entero(pregunta, inicio, fin, estándar=None):
- while True:
- try:
- entrada = input(pregunta)
- if nulo_o_vacío(entrada) and estándar != None:
- entrada = estándar
- valor = int(entrada)
- if inicio <= valor <= fin:
- return(valor)
- except ValueError:
- print("Valor inválido, favor digitar entre %d y %d" %
- (inicio, fin))
- def valida_franja_entero_o_blanco(pregunta, inicio, fin):
- while True:
- try:
- entrada = input(pregunta)
- if nulo_o_vacío(entrada):
- return None
- valor = int(entrada)
- if inicio <= valor <= fin:
- return(valor)
- except ValueError:
- print("Valor inválido, favor digitar entre %d y %d" %
- (inicio, fin))
- class ListaÚnica:
- def __init__(self, elem_class):
- self.lista = []
- self.elem_class = elem_class
- def __len__(self):
- return len(self.lista)
- def __iter__(self):
- return iter(self.lista)
- def __getitem__(self, p):
- return self.lista[p]
- def indiceVálido(self, i):
- return i >= 0 and i < len(self.lista)
- def adiciona(self, elem):
- if self.investigación(elem) == -1:
- self.lista.append(elem)
- def remove(self, elem):
- self.lista.remove(elem)
- def investigación(self, elem):
- self.verifica_tipo(elem)
- try:
- return self.lista.index(elem)
- except ValueError:
- return -1
- def verifica_tipo(self, elem):
- if type(elem) != self.elem_class:
- raise TypeError("Tipo inválido")
- def ordena(self, clave=None):
- self.lista.sort(key=clave)
- class DBListaÚnica(ListaÚnica):
- def __init__(self, elem_class):
- super().__init__(elem_class)
- self.borrados = []
- def remove(self, elem):
- if elem.id is not None:
- self.borrados.append(elem.id)
- super().remove(elem)
- def limpia(self):
- self.borrados = []
- @total_ordering
- class Nombre:
- def __init__(self, nombre):
- self.nombre = nombre
- def __str__(self):
- return self.nombre
- def __repr__(self):
- return "<Clase {3} en 0x{0:x} Nombre: {1} Clave: {2}>".format(
- id(self), self.__nombre, self.__clave, type(self).__name__)
- def __eq__(self, otro):
- return self.nombre == otro.nombre
- def __lt__(self, otro):
- return self.nombre < otro.nombre
- @property
- def nombre(self):
- return self.__nombre
- @nombre.setter
- def nombre(self, valor):
- if nulo_o_vacío(valor):
- raise ValueError("Nombre no puede ser nulo ni en blanco")
- self.__nombre = valor
- self.__clave = Nombre.CreaClave(valor)
- @property
- def clave(self):
- return self.__clave
- @staticmethod
- def CreaClave(nombre):
- return nombre.strip().lower()
- class DBNome(Nombre):
- def __init__(self, nombre, id_=None):
- super().__init__(nombre)
- self.id = id_
- @total_ordering
- class TipoTeléfono:
- def __init__(self, tipo):
- self.tipo = tipo
- def __str__(self):
- return "({0})".format(self.tipo)
- def __eq__(self, otro):
- if otro is None:
- return False
- return self.tipo == otro.tipo
- def __lt__(self, otro):
- return self.tipo < otro.tipo
- class DBTipoTeléfono(TipoTeléfono):
- def __init__(self, id_, tipo):
- super().__init__(tipo)
- self.id = id_
- class Teléfono:
- def __init__(self, número, tipo=None):
- self.número = número
- self.tipo = tipo
- def __str__(self):
- if self.tipo != None:
- tipo = self.tipo
- else:
- tipo = ""
- return "{0} {1}".format(self.número, tipo)
- def __eq__(self, otro):
- return self.número == otro.número and (
- (self.tipo == otro.tipo) or (
- self.tipo == None or otro.tipo == None))
- @property
- def número(self):
- return self.__número
- @número.setter
- def número(self, valor):
- if nulo_o_vacío(valor):
- raise ValueError("Número no puede ser None o en blanco")
- self.__número = valor
- class DBTeléfono(Teléfono):
- def __init__(self, número, tipo=None, id_=None, id_nombre=None):
- super().__init__(número, tipo)
- self.id = id_
- self.id_nombre = id_nombre
- class DBTeléfonos(DBListaÚnica):
- def __init__(self):
- super().__init__(DBTeléfono)
- class DBTiposTeléfono(ListaÚnica):
- def __init__(self):
- super().__init__(DBTipoTeléfono)
- class DBDadoAgenda:
- def __init__(self, nombre):
- self.nombre = nombre
- self.teléfonos = DBTeléfonos()
- @property
- def nombre(self):
- return self.__nombre
- @nombre.setter
- def nombre(self, valor):
- if type(valor) != DBNome:
- raise TypeError("nombre debe ser una instancia de la clase DBNome")
- self.__nombre = valor
- def investigaciónTeléfono(self, teléfono):
- posición = self.teléfonos.investigación(DBTeléfono(teléfono))
- if posición == -1:
- return None
- else:
- return self.teléfonos[posición]
- class DBAgenda:
- def __init__(self, banco):
- self.tiposTeléfono = DBTiposTeléfono()
- self.banco = banco
- nuevo = not os.path.isfile(banco)
- self.conexión = sqlite3.connect(banco)
- self.conexión.row_factory = sqlite3.Row
- if nuevo:
- self.crea_banco()
- self.cargaTipos()
- def cargaTipos(self):
- for tipo in self.conexión.execute("select * from tipos"):
- id_ = tipo["id"]
- descripción = tipo["descripción"]
- self.tiposTeléfono.adiciona(DBTipoTeléfono(id_, descripción))
- def crea_banco(self):
- self.conexión.executescript(BANCO)
- def investigaciónNombre(self, nombre):
- if not isinstance(nombre, DBNome):
- raise TypeError("nombre debe ser del tipo DBNome")
- encontrado = self.conexión.execute("""select count(*)
- from nombres where nombre = ?""",
- (nombre.nombre,)).fetchone()
- if(encontrado[0] > 0):
- return self.carga_por_nombre(nombre)
- else:
- return None
- def carga_por_id(self, id):
- consulta = self.conexión.execute(
- "select * from nombres where id = ?", (id,))
- return carga(consulta.fetchone())
- def carga_por_nombre(self, nombre):
- consulta = self.conexión.execute(
- "select * from nombres where nombre = ?", (nombre.nombre,))
- return self.carga(consulta.fetchone())
- def carga(self, consulta):
- if consulta is None:
- return None
- nuevo = DBDadoAgenda(DBNome(consulta["nombre"], consulta["id"]))
- for teléfono in self.conexión.execute(
- "select * from teléfonos where id_nombre = ?",
- (nuevo.nombre.id,)):
- ntel = DBTeléfono(teléfono["número"], None,
- teléfono["id"], teléfono["id_nombre"])
- for tipo in self.tiposTeléfono:
- if tipo.id == teléfono["id_tipo"]:
- ntel.tipo = tipo
- break
- nuevo.teléfonos.adiciona(ntel)
- return nuevo
- def lista(self):
- consulta = self.conexión.execute(
- "select * from nombres order by nombre")
- for registro in consulta:
- yield self.carga(registro)
- def nuevo(self, registro):
- try:
- cur = self.conexión.cursor()
- cur.execute("insert into nombres(nombre) values (?)",
- (str(registro.nombre),))
- registro.nombre.id = cur.lastrowid
- for teléfono in registro.teléfonos:
- cur.execute("""insert into teléfonos(número,
- id_tipo, id_nombre) values (?,?,?)""",
- (teléfono.número, teléfono.tipo.id,
- registro.nombre.id))
- teléfono.id = cur.lastrowid
- self.conexión.commit()
- except:
- self.conexión.rollback()
- raise
- finally:
- cur.close()
- def actualiza(self, registro):
- try:
- cur = self.conexión.cursor()
- cur.execute("update nombres set nombre=? where id = ?",
- (str(registro.nombre), registro.nombre.id))
- for teléfono in registro.teléfonos:
- if teléfono.id is None:
- cur.execute("""insert into teléfonos(número,
- id_tipo, id_nombre)
- values (?,?,?)""",
- (teléfono.número, teléfono.tipo.id,
- registro.nombre.id))
- teléfono.id = cur.lastrowid
- else:
- cur.execute("""update teléfonos set número=?,
- id_tipo=?, id_nombre=?
- where id = ?""",
- (teléfono.número, teléfono.tipo.id,
- registro.nombre.id, teléfono.id))
- for borrado in registro.teléfonos.borrados:
- cur.execute("delete from teléfonos where id = ?", (borrado,))
- self.conexión.commit()
- registro.teléfonos.limpia()
- except:
- self.conexión.rollback()
- raise
- finally:
- cur.close()
- def borra(self, registro):
- try:
- cur = self.conexión.cursor()
- cur.execute("delete from teléfonos where id_nombre = ?",
- (registro.nombre.id,))
- cur.execute("delete from nombres where id = ?",
- (registro.nombre.id,))
- self.conexión.commit()
- except:
- self.conexión.rollback()
- raise
- finally:
- cur.close()
- class Menú:
- def __init__(self):
- self.opciones = [["Salir", None]]
- def adicionaopción(self, nombre, función):
- self.opciones.append([nombre, función])
- def exhibe(self):
- print("====")
- print("Menú")
- print("====\n")
- for i, opción in enumerate(self.opciones):
- print("[{0}] - {1}".format(i, opción[0]))
- print()
- def ejecute(self):
- while True:
- self.exhibe()
- elija = valida_franja_entero("Elija una opción: ",
- 0, len(self.opciones) - 1)
- if elija == 0:
- break
- self.opciones[elija][1]()
- class AppAgenda:
- @staticmethod
- def pide_nombre():
- return(input("Nombre: "))
- @staticmethod
- def pide_teléfono():
- return(input("Teléfono: "))
- @staticmethod
- def muestra_datos(datos):
- print("Nombre: %s" % datos.nombre)
- for teléfono in datos.teléfonos:
- print("Teléfono: %s" % teléfono)
- print()
- @staticmethod
- def muestra_datos_teléfono(datos):
- print("Nombre: %s" % datos.nombre)
- for i, teléfono in enumerate(datos.teléfonos):
- print("{0} - Teléfono: {1}".format(i, teléfono))
- print()
- def __init__(self, banco):
- self.agenda = DBAgenda(banco)
- self.menú = Menú()
- self.menú.adicionaopción("Nuevo", self.nuevo)
- self.menú.adicionaopción("Altera", self.altera)
- self.menú.adicionaopción("Borra", self.borra)
- self.menú.adicionaopción("Lista", self.lista)
- self.ultimo_nombre = None
- def pide_tipo_teléfono(self, estándar=None):
- for i, tipo in enumerate(self.agenda.tiposTeléfono):
- print(" {0} - {1} ".format(i, tipo), end=None)
- t = valida_franja_entero("Tipo: ", 0,
- len(self.agenda.tiposTeléfono) - 1, estándar)
- return self.agenda.tiposTeléfono[t]
- def investigación(self, nombre):
- if type(nombre) == str:
- nombre = DBNome(nombre)
- dato = self.agenda.investigaciónNombre(nombre)
- return dato
- def nuevo(self):
- nuevo = AppAgenda.pide_nombre()
- if nulo_o_vacío(nuevo):
- return
- nombre = DBNome(nuevo)
- if self.investigación(nombre) != None:
- print("¡Nombre ya existe!")
- return
- registro = DBDadoAgenda(nombre)
- self.menú_teléfonos(registro)
- self.agenda.nuevo(registro)
- def borra(self):
- nombre = AppAgenda.pide_nombre()
- if(nulo_o_vacío(nombre)):
- return
- p = self.investigación(nombre)
- if p != None:
- self.agenda.borra(p)
- else:
- print("Nombre no encontrado.")
- def altera(self):
- nombre = AppAgenda.pide_nombre()
- if(nulo_o_vacío(nombre)):
- return
- p = self.investigación(nombre)
- if p != None:
- print("\nEncontrado:\n")
- AppAgenda.muestra_datos(p)
- print("Digite enter en caso de que no quiera alterar el nombre")
- nuevo = AppAgenda.pide_nombre()
- if not nulo_o_vacío(nuevo):
- p.nombre.nombre = nuevo
- self.menú_teléfonos(p)
- self.agenda.actualiza(p)
- else:
- print("¡Nombre no encontrado!")
- def menú_teléfonos(self, datos):
- while True:
- print("\nEditando teléfonos\n")
- AppAgenda.muestra_datos_teléfono(datos)
- if(len(datos.teléfonos) >= 0):
- print("\n[A] - alterar\n[D] - borrar\n", end="")
- print("[N] - nuevo\n[S] - salir\n")
- operación = input("Elija una operación: ")
- operación = operación.lower()
- if operación not in ["a", "d", "n", "s"]:
- print("Operación inválida. Digite A, D, N o S")
- continue
- if operación == 'a' and len(datos.teléfonos) > 0:
- self.altera_teléfonos(datos)
- elif operación == 'd' and len(datos.teléfonos) > 0:
- self.borra_teléfono(datos)
- elif operación == 'n':
- self.nuevo_teléfono(datos)
- elif operación == "s":
- break
- def nuevo_teléfono(self, datos):
- teléfono = AppAgenda.pide_teléfono()
- if nulo_o_vacío(teléfono):
- return
- if datos.investigaciónTeléfono(teléfono) != None:
- print("Teléfono ya existe")
- tipo = self.pide_tipo_teléfono()
- datos.teléfonos.adiciona(DBTeléfono(teléfono, tipo))
- def borra_teléfono(self, datos):
- t = valida_franja_entero_o_blanco(
- "Digite la posición del número a borrar, enter para salir: ",
- 0, len(datos.teléfonos) - 1)
- if t == None:
- return
- datos.teléfonos.remove(datos.teléfonos[t])
- def altera_teléfonos(self, datos):
- t = valida_franja_entero_o_blanco(
- "Digite la posición del número a alterar, enter para salir: ",
- 0, len(datos.teléfonos) - 1)
- if t == None:
- return
- teléfono = datos.teléfonos[t]
- print("Teléfono: %s" % teléfono)
- print("Digite enter en caso de que no quiera alterar el número")
- nuevoteléfono = AppAgenda.pide_teléfono()
- if not nulo_o_vacío(nuevoteléfono):
- teléfono.número = nuevoteléfono
- print("Digite enter en caso de que no quiera alterar el tipo")
- teléfono.tipo = self.pide_tipo_teléfono(
- self.agenda.tiposTeléfono.investigación(teléfono.tipo))
- def lista(self):
- print("\nAgenda")
- print("-" * 60)
- for e in self.agenda.lista():
- AppAgenda.muestra_datos(e)
- print("-" * 60)
- def ejecute(self):
- self.menú.ejecute()
- if __name__ == "__main__":
- if len(sys.argv) > 1:
- app = AppAgenda(sys.argv[1])
- app.ejecute()
- else:
- print("Error: nombre del banco de datos no informado")
- print(" agenda.py nombre_del_banco")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement