Básicos del Lenguaje

1

Guía de instalación y conceptos básicos

2

Archivos y slides del curso práctico de Python

3

IMPORTANTE: Instalando Ubuntu Bash en Windows para facilitarte el seguimiento del curso desde Windows.

4

¿Qué es la programación?

5

¿Por qué programar con Python?

6

Operadores matemáticos

7

Variables y expresiones

8

Presentación del proyecto

9

Funciones

10

Usando funciones en nuestro proyecto

11

Operadores lógicos

12

Estructuras condicionales

Uso de strings y ciclos

13

Strings en Python

14

Operaciones con Strings en Python

15

Operaciones con strings y el comando Update

16

Operaciones con strings y el comando Delete

17

Operaciones con strings: Slices en python

18

For loops

19

While loops

20

Iterators and generators

Estructuras de Datos

21

Uso de listas

22

Operaciones con listas

23

Agregando listas a nuestro proyecto

24

Diccionarios

25

Agregando diccionarios a nuestro proyecto

26

Tuplas y conjuntos

27

Tuplas y conjuntos en código

28

Introducción al módulo collections

29

Python comprehensions

30

Búsquedas binarias

31

Continuando con las Búsquedas Binarias

32

Manipulación de archivos en Python 3

Uso de objetos y módulos

33

Decoradores

34

Decoradores en Python

35

¿Qué es la programación orientada a objetos?

36

Programación orientada a objetos en Python

37

Scopes and namespaces

38

Introducción a Click

39

Definición a la API pública

40

Clients

41

Servicios: Lógica de negocio de nuestra aplicación

42

Interface de create: Comunicación entre servicios y el cliente

43

Actualización de cliente

44

Interface de actualización

45

Manejo de errores y jerarquía de errores en Python

46

Context managers

Python en el mundo real

47

Aplicaciones de Python en el mundo real

Conclusiones finales

48

Python 2 vs 3 (Conclusiones)

Clases bonus

49

Entorno Virtual en Python y su importancia: Python en el mundo real

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Interface de actualización

44/49
Recursos

Aportes 100

Preguntas 18

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

En que vídeo se escribió esta linea de código?

@click.argument('client_uid')

El **feedback ** es bueno para la plataforma, hasta ahora he visto pocas quejas de estas últimas clases, y las pocas quejas solo reciben un “disculpa, para la próxima lo arreglamos”, creo que seria mejor que los moderadores o personal de apoyo pusiera una nota al pie del video explicando los errores de la clase ( claro que no son atribuibles al profe, que dicho sea de paso es excelente). en fin es mi humilde opinión.

Mal, a partir del video 39 esto se fue para abajo, parese que estan correteando a David

Mi solución al reto

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """ Delete a client """
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]
    
    if client:
        client_service.delete_client(client)

        click.echo('Cliente deleted')
    else:
        click.echo('Client not found')

def delete_client(self, client_to_be_deleted):
        clients_list = self.list_clients()
        clients_list.remove(client_to_be_deleted[0])

        self._save_to_disk(clients_list)

😄



Me aparecía este error, lo solucioné poniendo “self” a la función “_save_to_disk()” y añadiendo " mode=‘w’ " en el “with open” de la misma función

Para los que les pueda interesar les dejo todo mi código en el siguiente repositorio:
https://github.com/crissebasbol/Ex_platzi_sales

Jajajajajaja se mancharon, cómo carajos vamos a poder resolver el reto de la función eliminar si no nos han explicado nada acerca de la librería click?? Aunque hayamos realizado los cursos anteriores de la ruta, a esta altura del curso no sabemos qué estamos escribiendo, solo hacemos que funcione

No me gusta decir estas cosas, pero casualmente los cursos que menos me han gustado son los de el profesor David Aroesti, siempre quedo con demasiadas dudas en sus cursos!!

Esta es mi solución de delete:
La función delete en commands.py es casi igual a update y no utilice nada en services.py

@clients.command()
@click.pass_context
def delete(ctx):
    """Deletes a client"""

    client_uid = click.prompt('Client UID to delet', type=str)
    client_service = ClientService(ctx.obj['clients_table'])
    clients_list = client_service.list_clients()
    client = [client for client in clients_list if client['uid'] != client_uid]

    client_service._save_to_disk(client)```

commands

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
defdelete(ctx, client_uid):
    """delete a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    clients_list = client_service.list_clients()

    client = [client for client in clients_list if client['uid'] != client_uid]

    if client:
        client_service. _save_to_disk(client)
        click.echo('Client removed')
    else:
        click.echo('Client not found')

En el de services no modifique nada, solo reutilize la funcion _save_to_disk, en el de commands, modifique en el comprehension la condicion (==) y la remplaze por (!=), la logica usada fue: agregar a la lista todos los clientes simpre y cundo no sea el uid sea indistinto al uid del cliente ingresado.
de esta manera guarda todos menos el que deseamos eliminar, esa es una alternativa

Definitivamente estas ultimas clases han estado de busca el error de edición 😕

El código del instructor no me funcionó. Recibía este error:

_TypeError: save_to_disk() takes 1 positional argument but 2 were given

Se resuelve muy fácil agregado al método _ save_to_disk _ su “seft”.

Resulto esto, recibía este error:

FileNotFoundError: [Errno 2] No such file or directory: ‘.clients.csv.tmp’

También se resolvía muy sencillo agregando _ _save_to_disk _ en open el argumento mode=“w”.

Con esto funcionó perfecto. Lo que no entiendo es por qué le funcionó al instructor. Pienso que es un error de edición en el video. Un novato se pude frustrar muy fácilmente con un error como este. Todo lo deben solucionar.

El reto:
En service.py

def delete_client(seft, delete_client):
        clients = seft.list_clients()

        for client in clients:
            if client["uid"] == delete_client.uid:
                clients.remove(delete_client.to_dict())

        seft._save_to_disk(clients)

En command.py:

def delete(ctx, client_uid):
    """Borra un cliente"""
    client_service = ClientService(ctx.obj["clients_table"])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client["uid"] == client_uid]

    if client:
        client = Clients(**client[0])
        client_service.delete_client(client)
        click.echo("Client deleted")
    else:
        click.echo("Client not found")

Hola! Les dejo el código de mi implementación para lo que vimos en el curso, lo hice en español y agregué un sistema de inventario en el que se pueden crear, actualizar, borrar, leer y vender productos. Todos los PR o forks son bienvenidos. Saludos, compañeros:)

El link del repo es: https://github.com/thebdsw320/cli-sistema-inventario

En la clase anterior a David se le olvido colocar el modo en el que abria el archivo, deben corrergirlo.
funcion _save_to_disk de services.py

en vez de:

with open(tmp_table_name) as f:

Escriban lo siguiente:

with open(tmp_table_name, mode = 'w') as f:

¿Qué significa el doble * en la siguiente linea?

client = _update_client_flow(Client(**client[0]))

Yo tambien tuve algunos problemas a la hora de correr el programa, pero asi es como se aprende mejor buscando las soluciones, leer un poco la documentacion de click te ayuda a orientarte con los ejemplos que tiene, si te dan el programa ya hecho no es lo mismo, claro que un feedback al final estaria bien hay algunos que somos noob de cero, pero hasta con un error de dedo un error logico, me tarde 2 dias en encontrar que habia puesto click.command y no clients.command

ahhaah Exito si nos frustramos con ese tipo de detalles, en el trabajo que te espera que te den codigos ya hechos y sin errores xD

entre otros errores, falta agregar el parametro self, asi como el modo mode='w' cuando se edita el archivo en la función def _save_to_disk(self, clients):

✅ Les paso el repositorio de GitHub que creé con los archivos del curso, por si quieren echarle un ojo.👀

Mi solución en el services, los commands la función de delete es igual a la del update

import csv
import os


from clients.model import Client


class ClientService:

    def __init__(self, table_name):
        self.table_name = table_name


    def create_client(self, client):
        with open(self.table_name, mode='a') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerow(client.to_dict())

    
    def list_clients(self):
        with open(self.table_name, mode='r') as f:
            reader = csv.DictReader(f, fieldnames=Client.schema())

            return list(reader)


    def update_client(self, updated_client):
        clients = self.list_clients()

        updated_clients = []

        for client in clients:
            if client['uid'] == updated_client.uid:
                updated_clients.append(updated_client.to_dict())
            else:
                updated_clients.append(client)
        
        self._save_to_disk(updated_clients)

    
    def delete_client(self, client_to_delete):
        clients = self.list_clients()
        
        for i, client in enumerate(clients) :
            if client['uid'] == client_to_delete:
                clients.remove(clients[i])
            else:
                continue
        
        self._save_to_disk(clients)
            

    def _save_to_disk(self, clients):
        temp_table_name = self.table_name + '.tmp'
        with open(temp_table_name, mode='w') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerows(clients)
            
        os.remove(self.table_name)
        os.rename(temp_table_name, self.table_name)```
Mi código de delete_client quedo muy parecido al de updste_clients, lo que hice es que al encontrar el cliente con el mismo Id solo no lo agregue y siga el ciclo

Mi solución a este reto:

services.py

 def delete_client(self, client_to_be_deleted):
        clients = self.list_clients()

        for client in clients:
            if client['uid'] == client_to_be_deleted.uid:
                clients.remove(client)
                break

        self._save_to_disk(clients)

commands.py

@clients.command()
@click.argument('client_uid')
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])
    client_list = client_service.list_clients()
    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_to_delete = _delete_client_flow(Client(**client[0]))

        if client_to_delete:
            client_service.delete_client(client_to_delete)
            click.echo('Client deleted successfully')
        else:
            click.echo('Aborted')
def _delete_client_flow(client):
    click.echo('Client with UID: {uid} was found.'.format(uid=client.uid))

    delete_confirmation = click.prompt(
        'Delete? [y]/N', type=str, default='Y')

    if delete_confirmation.upper() == 'Y':
        return client

    return None```

Deben decorar la funcion update con el siguiente decorador:

@click.argument('client_uid',
                type=str) 

Lo haran para que el programa reciba el “uid” por la consola.
Coloquenlo de la siguiente manera:

@clients.command()
@click.argument('client_uid',
                type=str) #Nos pasara el uid desde la consola
@click.pass_context
def update(ctx, client_uid):
	...codigo de la funcion 

Si no lo hacen el programa les dará un error

Mi solución al reto:
***** commands.py *******

@clients.command()
@click.argument('client_uid',
                 type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]
    
    if client:
        client_service.delete_client(client[0])

        click.echo('Client deleted')

    else:
        click.echo('Client not found')

**** services.py ****

    def delete_client(self, deleted_client):
        clients = self.list_clients()

        for client in clients:
            if client == deleted_client:
                clients.remove(deleted_client)

        self._save_to_disk(clients)```

Acá mi solución al reto:

services.py

def delete_client(self, client_id):
        clients = self.list_clients()
       
        for client in clients:
            
            if client['uid'] == client_id.uid:
                clients.remove(client)

        self._save_to_disk(clients)

commands.py

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a cient"""
    client_services = ClientServices(ctx.obj['clients_table'])
    client_list = client_services.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]
    if client:
        client_services.delete_client(Client(**client[0]))

        click.echo('Client deleted')
    else:
        click.echo('Client not found')

El reto lo resolví de la siguiente manera:

service.py:

def delete_client(self, client_uid):
        tmp_clients = [client for client in self.list_clients() if client['uid'] != client_uid]
        self._save_to_disk(tmp_clients)

commans.py:

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
    "Deletes a client"
    client_service = ClientService(ctx.obj['clients_table'])
    client = [client for client in client_service.list_clients() if client['uid'] == client_uid]
    if client:   
        client_service.delete_client(client_uid)
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

El archivo en los enlace de proyecto no está completo.

Para que el codigo funcione se debe agregar como parametro de entrada en _save_data_to_disk rows y schema, así _save_data_to_disk(rows, schema). Esto porque el codigo nesecita separa las filas a actualizar de la base de datos schema, sino crea los dos en una sola entidad y entra a error de sintaxis.

tambien es nesesario hacer este cambio en los parametros de entrada de update así:

update(self, row, schema).

El codigo al final funciona así. de lo contrario van a sufrir mucho con este error.

Mi Solución al Reto:

command.py

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
	"""Deletes a client"""
	client_service = ClientService(ctx.obj["clients_table"])

	if click.confirm("Are you sure you want to delete the client with uid: {}".format(client_uid)):
		client_service.delete_client(client_uid)
		click.echo("Client Deleted")
	else:
		click.echo("Client not found")

service.py

	def delete_client(self, client_uid):
		clients = self.list_clients()

		not_deleted_clients = [client for client in clients if client["uid"] != client_uid]

		self._save_to_disk(not_deleted_clients)
Antes de registrar la forma en cómo complete los scripts services.py y commands.py; si me gustaría sumarme a las observaciones de inconformidad del curso, a partir de la migración del proyecto al framework. Antes de esto se estaba llevando un buen ritmo, pero se desbarató esa sinergia cuando se comenzó esta migración. Aquí mi método: Script services.py ```js def delete_client(self, deleted_client): clients = self.list_clients() for client in clients: if client['uid'] == deleted_client.uid: del client['uid'] self._save_to_disk(clients) ```Script commands.py ```js @clients.command() @click.argument('client_uid', type=str) @click.pass_context def delete(ctx, client_uid): """Deletes a client""" client_service = ClientService(ctx.obj['clients_table']) client_list = client_service.list_clients() client = [client for client in client_list if client['uid'] != client_uid] if len(client_list) != len(client): client_service._save_to_disk(client) click.echo('Client deleted') else: click.echo('Client not found') all = clients ```
solo estoy viendo los videos sin codear, no entinedo nada ya que del 39 todo ha sido una carrera para terminar el curso

Tuve errores ya mi cabeza no daba para el reto pero aqui lo importante delete_clients = [client for client in clients if client['uid'] != client_uid] se le dice que si es diferente al enviando lo guarde en el codigo, no se que tan eficiente sea a la larga pero es buena idea.
.
y en command pues el del profe click.confirm para y/N esta genial.

Mi solucion a eliminar cliente

services

import csv
import os
from clients.models import Client


class ClientService:

    def __init__(self, table_name):
        self.table_name = table_name

    def create_client(self, client):
        with open(self.table_name, mode='a') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerow(client.to_dict())

    def list_clients(self):
        with open(self.table_name, mode='r') as f:
            reader = csv.DictReader(f, fieldnames=Client.schema())

            return list(reader)

    def update_client(self, updated_client):
        clients = self.list_clients()

        updated_clients = []
        for client in clients:
            if client['uid'] == updated_client.uid:
                updated_clients.append(updated_client.to_dict())
            else:
                updated_clients.append(client)

        self._save_to_disk(updated_clients)

    def delete_client(self, deleted_client):
        clients = self.list_clients()

        clients_to_save = []
        for client in clients:
            if client['uid'] != deleted_client.uid:
                clients_to_save.append(client)

        self._save_to_disk(clients_to_save)

    def _save_to_disk(self, clients):
        tmp_table_name = self.table_name + '.tmp'
        with open(tmp_table_name, 'w') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerows(clients)

        os.remove(self.table_name)
        os.rename(tmp_table_name, self.table_name)

commands

import click
from clients.services import ClientService
from clients.models import Client
from prettytable import PrettyTable


@click.group()
def clients():
    """Manages the clients lifecycle"""
    pass


@clients.command()
@click.option('-n', '--name',
              type=str,
              prompt=True,
              help='The client name')
@click.option('-c', '--company',
              type=str,
              prompt=True,
              help='The client company')
@click.option('-e', '--email',
              type=str,
              prompt=True,
              help='The client email')
@click.option('-p', '--position',
              type=str,
              prompt=True,
              help='The client position')
@click.pass_context
def create(ctx, name, company, email, position):
    """Creates a new client"""
    client = Client(name, company, email, position)
    service = ClientService(ctx.obj['clients_table'])

    service.create_client(client)


@clients.command()
@click.pass_context
def list(ctx):
    """List all clients"""
    service = ClientService(ctx.obj['clients_table'])
    clients = service.list_clients()

    table = PrettyTable()
    table.field_names = [field.upper() for field in Client.schema()]

    for client in clients:
        table.add_row([
            client['uid'],
            client['name'],
            client['company'],
            client['email'],
            client['position']
        ])

    click.echo(table)


@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def update(ctx, client_uid):
    """Updates a client"""
    service = ClientService(ctx.obj['clients_table'])

    clients_list = service.list_clients()

    client = [client for client in clients_list if client['uid'] == client_uid]

    if client:
        client = _update_client_flow(Client(**client[0]))
        service.update_client(client)

        click.echo('Client updated')
    else:
        click.echo('Client not found')


@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a clients"""
    service = ClientService(ctx.obj['clients_table'])

    clients_list = service.list_clients()

    client = [client for client in clients_list if client['uid'] == client_uid]

    if client:
        service.delete_client(Client(**client[0]))

        click.echo('Client deleted')
    else:
        click.echo('Client not found')


def _update_client_flow(client):
    click.echo('Leave empty if you dont want to modify the value')

    client.name = click.prompt('New name', type=str, default=client.name)
    client.company = click.prompt(
        'New company', type=str, default=client.company)
    client.email = click.prompt('New email', type=str, default=client.email)
    client.position = click.prompt(
        'New position', type=str, default=client.position)

    return client


all = clients

Dejo el reto resuelto con los metodos creados en services y en command:

En service:

En commands:

Espero les sirva! Pese a algunos saltos temporales que podrían complicar a los mas novatos, el curso está muy bueno!

Mi solucion consiste en agregar una funcion en el archivo commands y otra en la de services

#Esta es la que es encesaria agregar en el commands de donde se llama al metodo dentro de la clase ClientService

@clients.command()
@click.argument('client_uid',
                 type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a single client in te list"""
    client_service = ClientService(ctx.obj['clients_table'])
    client_list = client_service.list_clients()
    client = [client for client in client_service.list_clients() if client['uid'] == client_uid]
    _tmp_dic = client[0]

    if client:
        client_service.delete_client(client)
        click.echo('\n\t Client {} was deleted successfully! \n'.format(_tmp_dic['name']))
    else:
        click.echo('\n\t Client not found... \n')

El siguiente es el metodo que agregué dentro de la clase ClientService


    def delete_client(self, client_to_delete):
        clients = self.list_clients()

        num = int(len(clients))
        _pivot = client_to_delete[0]
        for _flag in _pivot.values():
            _cnt = _flag
        updated_clients = []

        for client in clients:
            if client['uid'] == _cnt:
                pass
            else:
                updated_clients.append(client)
        self._save_to_disk(updated_clients)

Hola les dejo el reto,

en el command .py —> esto :

@clients.command()
@click.argument('client_uid',type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete client"""
    client_service = ClientService(ctx.obj['clients_table'])
    
    clients_list = client_service.list_clients()

    client = [client for client in clients_list if client['uid'] == client_uid]

    if client == []:
        return click.echo('No client with this ID')
    else:
        client_service.delete_client(Client(**client[0]))   
        click.echo('Client was deleted')

y en el services .py —> esto :

def delete_client(self, deleted_client):
        clients = self.list_clients()

        new_list_clients = []
        for client in clients:
            if client['uid'] == deleted_client.uid:
                continue    #Jump the user wants to delete.
            else:
                new_list_clients.append(client)

        self._save_to_disk(new_list_clients)

Espero que a alguien le sirva

A mi me funciono de esta manera##

< @clients.command()
@click.option("-u", “uid”, type=str, prompt=True, help = “The client uid”)
@click.pass_context
def delete(ctx, uid:str):
""“Delete a client”""

client_service = ClientsService(ctx.obj["clients_table"])
client_list = client_service.list_clients()
client = [client for client in client_list if client["uid"] == uid]

if client:
   client = Client(**client[0])
   client = client_service.delete_client(client)
   click.echo("Client deleted!! ")
else:
    click.echo("Client not found!! ")>

<def delete_client(self, client_to_del):
clients_list = self.list_clients()

    for client in clients_list:
        if client["uid"] == client_to_del.uid:
            clients_list.remove(client)
                            

    self._save_to_disk(clients_list)>
@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_service = ClientService(ctx.obj['clients_table'])
    client_list = client_service.list_clients()
    client = [client for client in client_list if client['uid'] == client_uid]

    if client:       
        client_service.delete_client(client[0])
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

def delete_client(self, client_to_delete):
        clients = self.list_clients()
        updated_clients = []
        for client in clients:
            
            if client['uid'] == client_to_delete['uid']:
                pass
            else:
                updated_clients.append(client)
        self._save_to_disk(updated_clients)

Hice el reto de Delete, y fue bastante parecido al de Update, quién lo diría, pero para variar agrege una function que nos manda un prompt para confirmar la eliminación del cliente.

def _confirm_action (label:str) -> bool:
    confirmation = click.prompt(label, default="n", confirmation_prompt=True)

    if confirmation.lower()[0] == "y":
        return True

    return False

Hola, estoy teniendo el siguiente error, espero puedan ayudarme:

my codigo es el siguiente:
Services.py

def update_client(self,updated_client):
		clients=self.list_clients()

		updated_clients=[]
		for index, client in enumerate(clients):
			if client['uid'] == updated_client.uid:

				updated_clients.append(updated_client.to_dict())
			
			else:
				updated_clients.append(client)
		
		self._save_to_disk(updated_clients)

commands.py

@clients.command()
@click.argument('client_uid',
				type=str)
@click.pass_context
def update(ctx,client_uid):
	"""Updates a client"""
	client_service=ClientService(ctx.obj['clients_table'])
	client_list = client_service.list_clients()

	client= [client for client in client_list if client['uid']== client_uid]

	if client:
		client = _update_client_flow(Client(**client[0]))
		client_service.update_client(client)

		click.echo('Client Updated')
	else:
		click.echo('Client not found')


def _update_client_flow(client):
	click.echo('Leave empty if you dont want to modify the value')

	client.name=click.prompt('New name', type=str,default=client.name)
	client.company=click.prompt('New company', type=str,default=client.company)
	client.email=click.prompt('New email', type=str,default=client.email)
	client.position=click.prompt('New position', type=str,default=client.position)

	return client

Solución al Reto
Modificaciones implementadas en el archivo commands

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_service = ClientService(ctx.obj['clients_table'])
    client_list = client_service.list_clients()
    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        deleted_client = _delete_client_flow(Client(**client[0]))

        if deleted_client:
            client_service.delete_client(deleted_client)
            click.echo('Client deleted')
        else:
            click.echo('Client not found')


def _delete_client_flow(client):
    click.echo(f'Client with UID {client.uid} is to be deleted!')

    return client

Modificaciones implementadas en el archivo services

def delete_client(self, deleted_client):
    clients = self.list_clients()
    
    for client in clients:
        if client['uid'] == deleted_client.uid:
            clients.remove(client)
            break

    self._save_to_disk(clients)

Va mi solución al reto:

@clients.command()
@click.argument('client_uid')
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    clients_list = client_service.list_clients()
    client = [client for client in clients_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(Client(**client[0]))

        click.echo('Client deleted')
    else:
        click.echo('Client not found')
    def delete_client(self, client_to_delete):
        clients = self.list_clients()

        updated_clients = [
            client for client in clients if client['uid'] != client_to_delete.uid]

        self._save_to_disk(updated_clients)
    def delete_client(self, deleted_client_uid):
        clients = self.list_clients()

        current_clients=[]
        print(deleted_client_uid)
        for client in clients:
            print(client['uid'])
            if client['uid']==deleted_client_uid:
                pass
            else:
                print('here')
                current_clients.append(client)

        self._save_to_disk(current_clients)

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service=ClientService(ctx.obj['clients_table'])

    client_list=client_service.list_clients()

    for client in client_list:
        if client['uid']==client_uid: 
            client_to_delete=client['uid']

    if client_to_delete:
        client_service.delete_client(client_to_delete)
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

Este es el método delete del reto:
Para el archivo de comandos el código es:

@clients.command()
@click.argument('client_uid',type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(Client(**client[0]))

        click.echo('Client deleted')
    else:
        click.echo('Client not found')

Para el archivo de servicios el código es:

    def delete_client(self,deleted_client):
        clients = self.list_clients()

        active_clients = []
        for client in clients:
            if client['uid'] != deleted_client.uid:
                active_clients.append(client)
    
        self._save_to_disk(active_clients)

Reto

Les comparto mi solución del desafío.

Commands


@clients.command()
@click.option('-u', '--uid', type=str, prompt=True, help='The client UID.')
@click.pass_context
def delete(ctx: click.Context, uid: str):
    """Deletes a client.

    Time Complexity: O(n)
    """
    
    client_service = ClientService(ctx.obj['clients_table'])
    clients = client_service.list_clients()
    
    found: bool = False
    c: dict
    for c in clients:
        if c['uid'] == uid:
            found = True
            break

    if not found:
        click.echo('Client not found')
        return

    client_service.delete_client(uid, clients)

Service


    def delete_client(self, client_uid: str, clients: List[dict] = None):
        """Deletes a client.
        
        Time Complexity: O(n)

        Args:
            client_uid (str): The client's UID.
        """

        if clients is None:
            clients = self.list_clients()

        updated_clients: List[dict] = []

        client: dict
        for client in clients:
            if client['uid'] != client_uid:
                updated_clients.append(client)

        self._save_to_disk(updated_clients)

Me costó un poco pero acá está una solución rápida y un poco inspirada en lo que comentaron mis compañeros pero con menos código

En commands_py:

Es un poco parecido al update pero en services_py solo hay que poner el nuevo diccionario con la misma fucion save to disk

Fue una odisea, sobre todo porque hay algunas cosas que no han quedado del todo claras en las clases. Además, como se ha visto hay algunos errores en el código que aparece en pantalla. En fin.
.
La verdad me costó un huevo y la mitad del otro, pero la lógica es la siguiente:
.
1.- Tener en cuenta que para eliminar un cliente necesitamos identificarlo por su id.
2.- Luego nos vamos a clients/services. Vamos a seguir el ejemplo de update_client, es decir, vamos a pasar al cliente que queremos elimianr 'deleted_client’
2.1.- Nos traemos la lista completa de clientes y lo guaradamos en una variable.
2.2.- Generamos una lista de clientes con la condición que el ID sea diferente al del cliente que queremos eliminar.
2.3.- Nota, tendríamos una lista con todos los clientes y otra excluyento al cliente que queremos eliminar.
2.4.- Lo guardamos a disco. Como esa función ya está implementada no necesitamos pensar más.

    def delete_client(self, deleted_client):
        clients = self.list_clients()

        new_client = [client for client in clients if client['uid'] != deleted_client ]

        self._save_to_disk(new_client)

3.- Nos vamos clients/commands
4.- Agregamos el argumento client_uid, porque lo vamos a necesitar.
5.- Recuperamos nuestra tabla con los clientes, 'clients_table’
6.- También recuperamos la lista con los clientes y lo guardamos en una variable, 'client_list’
7.- Creamos una lista donde excluimos al cliente que queremos eliminar.
8.- Luego hacemos una condición en la que eliminamos al cliente y enviamos un mensaje indicando que la operación se realizó


@clients.command()
@click.argument('client_uid',
        type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [ client for client in client_list if client['uid'] != client_uid ]

    if client:
        client_service.delete_client(client_uid)
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

Asi quedaría el archivo services

import csv
import os

from clients.models import Client


class ClientService:
    def __init__(self, table_name):
        self.table_name = table_name

    def create_client(self, client):
        with open(self.table_name, mode='a') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerow(client.to_dict())


    def list_clients(self):
        with open(self.table_name, mode='r') as f:
            reader = csv.DictReader(f, fieldnames=Client.schema())

            return list(reader)

    def update_client(self, updated_client):
        clients = self.list_clients()

        updated_clients = []
        for client in clients:
            if client['uid'] == updated_client.uid:
                updated_clients.append(updated_client.to_dict())
            else:
                updated_clients.append(client)

        self._save_to_disk(updated_clients)

    def _save_to_disk(self, clients):
        tmp_table_name = self.table_name + '.tmp'
        with open(tmp_table_name, mode='w') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerows(clients)

        os.remove(self.table_name)
        os.rename(tmp_table_name, self.table_name)

Y asi quedaría el archivo command

import click
from clients.services import ClientService
from clients.models import Client

@click.group()
def clients():
    """Manages the clients lifecycle"""
    pass

@clients.command()
@click.option('-n','--name',
        type=str,
        prompt=True,
        help='The client name')
@click.option('-c','--company',
        type=str,
        prompt=True,
        help='The client company')
@click.option('-e','--email',
        type=str,
        prompt=True,
        help='The client email')
@click.option('-p','--position',
        type=str,
        prompt=True,
        help='The client position')
@click.pass_context
def create(ctx, name, company, email, position):
    """Create a new clients"""
    client = Client(name, company, email, position)
    client_service = ClientService(ctx.obj['clients_table'])

    client_service.create_client(client)


@clients.command()
@click.pass_context
def list(ctx):
    """List all clients"""
    client_service = ClientService(ctx.obj['clients_table'])

    clients_list = client_service.list_clients()

    click.echo('  ID  | NAME  |  COMPANY  |  EMAIL  |  POSITION')
    click.echo('*'*50)

    for client in clients_list:
        print('{uid} | {name} | {company} | {email} | {position}'.format(
            uid = client['uid'],
            name = client['name'],
            company = client['company'],
            email = client['email'],
            position = client['position']
            ))


@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def update(ctx, client_uid):
    """Update a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
         client = _update_client_flow(Client(**client[0]))
         client_service.update_client(client)

         click.echo('Client updated')
    else:
        click.echo('Client not found')



def _update_client_flow(client):
    click.echo('Leave empty if you dont want to modify the value')

    client.name = click.prompt('New name ', type=str, default=client.name)
    client.company = click.prompt('New company ', type=str, default=client.company)
    client.email = click.prompt('New email ', type=str, default=client.email)
    client.position = click.prompt('New position ', type=str, default=client.position)

    return client

@clients.command()
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    pass


all = clients

Truchas con los typos, si les surge un error, chequen cada clase, cada línea para que vean si la tienen igual, por una letra, una coma o un punto les puede estar fallando todo el programa.
A eso añadanle que hay unas líneas de código que escribe mal el profe, o que no aparece en la clase cuándo la escribieron. Lo bueno es que tenemos los comentarios y alguien siempre ya ha visto ese error.

Si tienen Visual studio code pueden poner el cursor sobre una variable y si esta está repetida, al presionar ctrl + d les permitirá modificar las demás variables repetidas 👌

Para eliminar clientes:

# clients/services.py

class ClientService:

    # ...

    def delete_client(self, deleted_client):
        clients = self.read_clients()
        clients = [client for client in clients if client['uid'] != deleted_client.uid]
        self._save_to_disk(clients)

    # ...
# clients/commands.py

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    "Deletes a client"
    client_service = ClientService(ctx.obj['clients_table'])
    client_list = client_service.read_clients()
    client = [client for client in client_list if client['uid'] == client_uid]

    if len(client) > 0:
        client_service.delete_client(Client(**client[0]))
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

Mi solución…
commands :

@clients.command()
@click.argument('client_uid',type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['table'])
    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(client)
    else:
        click.echo('Client not found')

services :

def delete_client(self,old_client):
        clients = self.list_clients()
        new_clients= [client for client in clients if client['uid'] != old_client[0]['uid'] ]

        self._save_to_disk(new_clients)

Mi solución, commands:

@clients.command()
@click.argument('client_uid',type=str)
@click.pass_context
def delete(ctx,client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(client_uid)

        click.echo('Client deleted')
    else:
        click.echo('Client not found')

services:

def delete_client(self,client_uid):
        clients = self.list_clients()

        updated_clients = []
        for client in clients:
            if client['uid'] != client_uid:
                updated_clients.append(client)

        self._save_to_disk(updated_clients)

Mi solucion al metodo eliminar

	#En services.py
	def delete_client(self, deleted_client):
		clients = self.list_clients()
		updated_clients = []
		for client in clients:
			if client['uid'] == deleted_client.uid:
				continue #Simplemente no se agrega el usuario a eliminar al tmp_clients_table
			else:
				updated_clients.append(client)

		self._save_to_disk(updated_clients)
#En commands.py
@clients.command()
@click.argument('client_uid')
@click.pass_context
def delete(ctx, client_uid):
	""" Deletes a client based on his uid """
	client_service = ClientService(ctx.obj['clients_table'])
	clients = client_service.list_clients()

	client = [ client for client in clients if client['uid']==client_uid]

	if client:
		client_service.delete_client(Client(**client[0]))
		click.echo('Client deleted')
	else:
		click.echo('Client not found')

Hola chavos!
A manera de reto por ser nuevo en python, realice el proyecto utilizando JSON en lugar de CSV, les dejo el link del repositorio por si gustan pasar a verlo o utlizarlo de inspiración.

A continuacion mi codigo en services

import csv
import os

from clients.models import Client

class ClientService:

    def __init__(self, table_name):
        self.table_name = table_name


    def create_client(self, client):
        with open(self.table_name, mode='a') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerow(client.to_dict())


    def list_clients(self):
        with open(self.table_name, mode='r') as f:
            reader = csv.DictReader(f, fieldnames=Client.schema())

            return list(reader)


    def update_client(self, updated_client):
        clients = self.list_clients()

        updated_clients = []
        for client in clients:
            if client['uid'] == updated_client.uid:
                updated_clients.append(updated_client.to_dict())
            else:
                updated_clients.append(client)

        self._save_to_disk(updated_clients)

    def _save_to_disk(self, clients):
        tmp_table_name = self.table_name + '.tmp'
        with open(tmp_table_name, mode='w') as f:
            writer = csv.DictWriter(f, fieldnames=Client.schema())
            writer.writerows(clients)

        os.remove(self.table_name)
        os.rename(tmp_table_name, self.table_name)


    def delete(self, row_uid, schema):
        rows = self.list_clients()
        updated_rows = [row for row in rows if row['uid'] != row_uid]

        self._save_to_disk(updated_rows)


    def delete_client(self, client_uid):
        self.delete(client_uid, Client.schema())

Les recomiendo usar la @click.option tanto para el update como delete en lugar de @click.argument, esto porque con argument no me reconocía el client_uid como argumento. Cuando lo cambie funciono todo super bien.

Podrían subir el código a github?

Mi Services

    def delete_client(self, client_uid):
        clients = self.list_client()
        clients_no_deleted = []
        for client in clients:
            if client['uid'] == client_uid:
                continue
            else:
                clients_no_deleted.append(client)
        self._save_to_disk(clients_no_deleted)

Mi solución.
Comando:

@clients.command()
@click.argument('client_uid', type = str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client """
    client_service = ClientService(ctx.obj['clients_table'])

    if client_service.delete_client(client_uid) :
        click.echo('Client deleted!')
    else:
        click.echo('Client not in the list!')

Servicio:

  def delete_client(self, client_uid):
        clients = self.list_clients()
        size = len(clients)
        updated_clients = [client for client in clients if client['uid'] != client_uid]
        updated_size = len (updated_clients)

        self._save_to_disk(updated_clients)

        if size == updated_size:
            return False
        else:
            return True

Hola, mi solución al método delete:

Services.py

## Delete client
	def delete_client(self,deleted_client):
		clients=self.list_clients()
		
		for indx, client in enumerate (clients):
			if client['uid'] == deleted_client.uid:
				clients.remove(clients[indx])
			else:
				continue

		self._save_to_disk(clients)

commands.py

@clients.command()
@click.argument('client_uid',
				type=str)
@click.pass_context
def delete(ctx, client_uid):
	"""Deletes a client"""
	client_service=ClientService(ctx.obj['clients_table'])
	client_list = client_service.list_clients()

	client= [client for client in client_list if client['uid']== client_uid]
	if client:
		client=Client(**client[0])
		client_service.delete_client(client)
		click.echo('Client Deleted')
	else:
		click.echo('Client not found')

si tienen el siguiente error “UnsupportedOperation: not writable”. Agreguen la clausula mode=‘a’, para poder guardar en disco.

    def _save_to_disk(self,clients):
        tmp_table_name = self.table_name + '.tmp'
        with open(tmp_table_name, mode='a') as f:
            writer = csv.DictWriter(f, fieldnames = ClientModel.schema())
            writer.writerows(clients)

        os.remove(self.table_name)
        os.rename(tmp_table_name, self.table_name)```

Mi command 😄

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_services = ClientService(ctx.obj['clients_table'])
    client_list = client_services.list_client()
    client = [client for client in client_list if client['uid'] == client_uid]
    if client:
        client_services.delete_client(client_uid)
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

Me está mostrando este error cuando ejecuto la línea “pv clients update XXXXXXXX”:

TypeError: update() got an unexpected keyword argument 'cliente_uid'```

No sé a qué se debe. Gracias de antemano!

Solución al reto

	@clients.command()
	@click.argument('client_uid',
               		     type=str)
	@click.pass_context
	def delete(ctx, client_uid):
		"""Deletes a client"""
    		client_service = Clients_Service(ctx.obj['clients_table'])

    		client_list = client_service.list_clients()
    		client = [client for client in client_list if client['uid'] == client_uid]
   		 if client:
	        	client = Client(**client[0])
	        	client_service.delete_client(client)
        
        	click.echo('Client deleted')
	   	else:
        		click.echo('Client not found')
	def delete_client(self, deleted_client):
        	clients = self.list_clients()
        
       	 for index, client in enumerate(clients):
            		if client['uid'] == deleted_client.uid:
               	 	del clients[index]

        	self._self_save_to_disk(clients)

Services.py

def delete_client(self, deleted_client):
        clients = self.list_clients()

        for index, client in enumerate(clients):
            if client['uid'] == deleted_client.uid:
                clients.pop(index)

        self._save_to_disk(clients)

commands.py

def delete(ctx, client_uid):
    '''Deletes a client'''
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client = Client(**client[0])
        client_service.delete_client(client)

        click.echo('Client Deleted')
    else:
        click.echo('Client not found')

Mi solución fue esta:
En “commands.py”:

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""

    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(Client(**client[0]))

        click.echo('Client delete')
    else:
        click.echo('Client not Found')

En “services.py”:

    def delete_client(self, deleted_client):
        clients = self.list_clients()

        deleted_clients = []

        for client in clients:
            if client['uid'] == deleted_client.uid:
                pass
            else:
                deleted_clients.append(client)

        self._save_to_disk(deleted_clients)

Mi recomendación es que si en alguna parte de perdiste y no entendiste que hizo David, no pierdas la calma y sobre todo no te frustres. Sé que es muy molesto los errores, pero es parte de programar.
Los errores de escritura que más cometi fue con Client, client, Clients y clients; fíjate mucho en eso. También en saber si lo que manejas es un objeto o una función, que se diferencian con los paréntesis [Igual si te queda duda usa type()]
Lo que puedes hacer es hacer un proceso de debug con algunos print(). Utiliza type() para saber que es lo que estás manejando y dir() para entender que propiedades tienes.
Como consejo si no sabes que como resolverlo, es que Delete es muy parecido a Update. Así que puedes intentar entender que hace update e implementalo con el reto.
Siéntate, prepárate algo de tomar y date a la idea de que veras una pila de errores que podrás ir resolviendo uno por uno, únicamente leyendo lo que te dice la consola, te adelanto que si bien puedes buscar el error en StackOverflow, en la mayoría de casos no te será de utilidad.

Suerte

Bueno, mi aporte:


def delete_client(self, client_to_delete):
        clients = self.list_clients()

        clients_after_deleting = []

        for client in clients:
            if client['uid'] == client_to_delete.uid:
                continue;
            else:
                clients_after_deleting.append(client)

        self._save_to_disk(clients_after_deleting)

Y:


@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client = Client(**client[0])
        client_service.delete_client(client)

        click.echo('Client has been Deleted!')
    else:
        click.echo('Client has not been found!!!')

Mi aporte
####################################################################
services.py

def delete_client(self, deleted_client):
        clients = self.list_clients()

        updated_clients = []

        for client in clients:
            if client['uid'] == deleted_client.uid:
                pass
            else:
                updated_clients.append(client)

        self._save_to_disk(updated_clients)

####################################################################
commands.py

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(context, client_uid):
    """ Deletes a client """
    client_service = ClientService(context.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client = Client(**client[0])
        client_service.delete_client(client)

        click.echo('Client deleted')
    else:
        click.echo('Client not found')
(venv) joel@joel-Inspiron-5575:~/Documents/apuntes-programacion/python/platzi-ventas$ pv clients update 0abd1db5-67d4-44f7-b93b-4b0ed637bea7
Usage: pv clients update [OPTIONS]
Try "pv clients update --help" for help.

Error: Got unexpected extra argument (0abd1db5-67d4-44f7-b93b-4b0ed637bea7)
(venv) joel@joel-Inspiron-5575:~/Documents/apuntes-programacion/python/platzi-ventas$ 

me sale este error pero he revisado una y otra vez el codigo. esta igual que el de david, no entiendo porque no acepta el argumento.
porque si no le pongo el uid me dice que falta el argumento

def delete_client(self, deleted_client):
    self._save_to_disk([
        client 
        for client in self.list_clients()
        if client['uid'] != deleted_client.uid
    ])


@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete_client(context, client_uid):
    """ Eliminación de cliente """
    client_service = ClientService(context.obj['clients_table'])
    client = [
        client 
        for client in client_service.list_clients() 
        if client['uid'] == client_uid
    ]
    msg = 'Cliente eliminado' if client else 'Cliente no encontrado'
    if client:
        client_service.delete_client(Client(**client[0]))
    click.echo(msg)

Este sería el comando:

@clients.command()
@click.argument('client_uid',type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client""" 
    client_service = ClientService(ctx.obj['clients_table'])

    clients_list = client_service.list_clients()

    client = [client for client in clients_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(Client(**client[0]))
        click.echo('Client deleted')
    else:
        click.echo('Client not found')

y este el servicio:

 def delete_client(self,client_delete):
        clients = self.list_clients()

        for index,value in enumerate(clients):
            if value['uid'] == client_delete.uid:
                clients.pop(index)
                break
        
        self._save_to_disk(clients)

Aquí comparto mi código para delete en services.py:

  def delete_client(self, deleted_client):
    clients = self.list_clients()

    for client in clients:
      if client['uid'] == deleted_client[0]['uid']:
        clients.remove(deleted_client[0])

    self._save_to_disk(clients)

  def _save_to_disk(self, clients):
    tmp_table_name = self.table_name + '.tmp'
    with open(tmp_table_name, mode='w') as f:
      writer = csv.DictWriter(f, fieldnames=ClientModel.schema())
      writer.writerows(clients)

    os.remove(self.table_name)
    os.rename(tmp_table_name, self.table_name)

En commands.py:

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
  """Deletes a client"""
  client_service = ClientService(ctx.obj['clients_table'])

  client_list = client_service.list_clients()

  client = [client for client in client_list if client['uid'] == client_uid]

  if client:
    click.echo(client)
    client_service.delete_client(client)
    click.echo('Client deleted')
  else:
    click.echo('Client not found')

He adaptado el código de update_cliente para que también sirva en la eliminación.

En services.py

def delete_client(self, client_to_delete):

        clients = self.list_clients()
        updated_clients = []

        for client in clients:
            if client['uid'] == client_to_delete.uid:
                continue
            else:
                updated_clients.append(client)
        
        self._save_to_disk(updated_clients)

Y en commands.py

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(Client(**client[0]))

        click.echo('Client deleted')
    else:
        click.echo('Client not found')

Que buena clase! Lejos, el mejor profe de Python

command.py


@clients.command()
@click.argument('client_uid',
								type=str)
@click.pass_context
def delete(ctx, client_uid):
	'''Delete a client'''
	client_service = ClientService(ctx.obj['client_table'])
	clients_list = client_service.list_clients()
	client = [client for client in clients_list if client['uid'] == client_uid]

	if client:
		client_service.delete_client(Client(**client[0]))

		click.echo('Client deleted')
	else:
		click.echo('Client not found')

service.py


def delete_client(self, client_to_delete):
		clients = self.list_clients()

		for idx, client in enumerate(clients):
			if client['uid'] == client_to_delete.uid:
				del clients[idx]
				break

Funciona el código que esta en archivo?, yo trato de ver services y commands y no me funciona el proyecto.

Hola amigos, al intentar ejecutar el

pv clients update

me da el siguiente error:

Typeerror: update() missing 1 required positional argument: ‘client_uid’

Veo en muchos comentarios que los que ya han desarrollado la función delete(), metieron el decorador

@click.argument(‘client_uid’, type=str)

antes de su definición en commands.py

Dado el error que tengo en update () intenté hacer lo mismo , pero de esta vez me da otro error que es el siguiente:

Missing argument ‘CLIENT_UID’

Alguien me podría ayudar?
Muchas gracias.
Un saludo.

Aquí mi solución al reto:

services.py

def delete_client(self, client_uid):
        clients = self.list_clients()
        updated_clients = [client for client in clients if client['uid'] != client_uid] #Creacion list comprehension de todos los usuarios diferentes al usuario a eliminar
        self._save_to_disk(updated_clients)

commands.py

@clients.command()
@click.pass_context
def delete(ctx):
    """Deletes a client"""
    client_uid = click.prompt('Write the id of the client to delete: ', type=str)

    client_service = ClientService(ctx.obj['clients_table'])
    
    if click.confirm('Are you sure to delete the client? '):
        client_service.delete_client(client_uid)
        click.echo('The client has been deleted')

command.py

@clients.command()
@click.option('-uid', '--client_uid',
                type=str,
                prompt=True,
                help='The client uid')
@click.pass_context
def delete(context, client_uid):
    """Delete a client"""
    client_service = ClientService(context.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service.delete_client(ClientModel(**client[0]))

        click.echo('Client deleted')
    else:
        click.echo('Client not found')

service.py

    def delete_client(self, delete_client):
        clients = self.list_clients()

        for client in clients:
            if  client['uid'] == delete_client.uid:
                clients.remove(client)
                break
        
        self._save_to_disk(clients)

Por qué inicializamos en cada comando un nuevo ClientService ? Por qué no inicializarlo de forma global y utilizarlo en cada comando?
Saludos

Me parece que los nombres que pone el profesor a las variables son muy confusas en cierto punto. Muchas veces, por lo menos yo, no entiendo el porque del nombre de algunas variables.

cuando ejecuto los comandos pv clients --help o pv clients create no hace nada, ya instale la aplicación ye tengo el ambiente virtual bien instalado

que podría tener mal si al ejecutar los comandos desde el entorno virtual no hacen nada :

(platzi-ventas) C:\platzi-ventas>pv clients --help

(platzi-ventas) C:\platzi-ventas>pv clients create

(platzi-ventas) C:\platzi-ventas>

command.py

DEF UPDATE
ULTRA SENCILLO Y FACIL DE ENTENDER

@clients.command()
@click.argument('client_name',
                type=str)
@click.pass_context
def update(ctx,client_name):
    """Update a client"""
    client_service= ClientService(ctx.obj['client_table'])
    client_service.update_client(client_name)

SERVICE.PY**
FUNCION UPDATE

def update_client(self, client_name):
    	clients=self.list_clients("u")

    	search=self.search(client_name)#BUSCAMOS SI EL CLIENTE EXISTE
    	if search==True:
    		click.echo("FOUNDED")
    	else:
    		click.echo("NOT FOUNDED")
    		return
    	updated_client=self._values()
    	clientes_actualizados= []
    	for client in clients:
    		if client['name']==client_name:
    			clientes_actualizados.append(updated_client.to_dict())
    		else:
    			clientes_actualizados.append(client)

    	self._save_to_disk(clientes_actualizados)

    def _save_to_disk(self,clients):
    	tmp_table=self.table_name+'.tmp'
    	with open(tmp_table, mode='w') as f:
    		writer=csv.DictWriter(f,fieldnames=Client.schema())
    		writer.writerows(clients)

    	os.remove(self.table_name)
    	os.rename(tmp_table,self.table_name)

Commands.py

import click
from clients.services import ClientServices
from clients.models import Client


@click.group()
def clients():
    """ Manages the clients lifecycle"""
    pass


@clients.command()
@click.option('-n', '--name',
                type=str,
                prompt=True,
                help='The client name')

@click.option('-c', '--company',
                type=str,
                prompt=True,
                help='The client Company')
                

@click.option('-e', '--email',
                type=str,
                prompt=True,
                help='The client email')


@click.option('-p', '--position',
                type=str,
                prompt=True,
                help='The client position')



@click.pass_context
def create(ctx, name, company, email, position):
    """Create a new client """
    client = Client(name, company, email, position)
    client_service = ClientServices(ctx.obj['clients_table'])

    client_service.create_client(client)


@clients.command()
@click.pass_context
def list_clients(ctx):
    """List all clients"""
    client_services = ClientServices(ctx.obj['clients_table'])
    client_list = client_services.list_clients()

    click.echo('  ID  |  NAME  |  COMPANY  |  EMAIL  |  POSITION')
    click.echo('*'*50)

    for client in client_list:
        print('{uid}  |  {name}  |  {company}  |  {email}  |  {position}'.format(
            uid = client['uid'],
            name = client['name'],
            company = client['company'],
            email = client['email'],
            position = client['position']
        ))

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def update(ctx, client_uid):
    """Update a client """
    client_service = ClientServices(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client = _update_client_flow(Client(**client[0]))
        client_service.update_client(client)

        click.echo('Client Updated')
    else:
        click.echo('Client not found')
    

def _update_client_flow(client):
    click.echo('Leave empty if you do not want to modify the value')

    client.name = click.prompt('New Name', type=str, default=client.name)
    client.company = click.prompt('New Company', type=str, default=client.company)
    client.email = click.prompt('New Email', type=str, default=client.email)
    client.position = click.prompt('New Position', type=str, default=client.position)

    return client

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_service = ClientServices(ctx.obj['clients_table'])
    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service._delete_client(Client(**client[0]))
        click.echo('Remove it')
    else:
        click.echo('Client not found')

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def search(ctx, client_uid):
    """Search a client """
    client_service = ClientServices(ctx.obj['clients_table'])
    client_found = client_service.search_client(client_uid)

    click.echo('  ID  |  NAME  |  COMPANY  |  EMAIL  |  POSITION')
    click.echo('*'*50)

    for client in client_found:
        print('{uid}  |  {name}  |  {company}  |  {email}  |  {position}'.format(
            uid = client['uid'],
            name = client['name'],
            company = client['company'],
            email = client['email'],
            position = client['position']
        ))

all = clients

services.py

import click
from clients.services import ClientServices
from clients.models import Client


@click.group()
def clients():
    """ Manages the clients lifecycle"""
    pass


@clients.command()
@click.option('-n', '--name',
                type=str,
                prompt=True,
                help='The client name')

@click.option('-c', '--company',
                type=str,
                prompt=True,
                help='The client Company')
                

@click.option('-e', '--email',
                type=str,
                prompt=True,
                help='The client email')


@click.option('-p', '--position',
                type=str,
                prompt=True,
                help='The client position')



@click.pass_context
def create(ctx, name, company, email, position):
    """Create a new client """
    client = Client(name, company, email, position)
    client_service = ClientServices(ctx.obj['clients_table'])

    client_service.create_client(client)


@clients.command()
@click.pass_context
def list_clients(ctx):
    """List all clients"""
    client_services = ClientServices(ctx.obj['clients_table'])
    client_list = client_services.list_clients()

    click.echo('  ID  |  NAME  |  COMPANY  |  EMAIL  |  POSITION')
    click.echo('*'*50)

    for client in client_list:
        print('{uid}  |  {name}  |  {company}  |  {email}  |  {position}'.format(
            uid = client['uid'],
            name = client['name'],
            company = client['company'],
            email = client['email'],
            position = client['position']
        ))

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def update(ctx, client_uid):
    """Update a client """
    client_service = ClientServices(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client = _update_client_flow(Client(**client[0]))
        client_service.update_client(client)

        click.echo('Client Updated')
    else:
        click.echo('Client not found')
    

def _update_client_flow(client):
    click.echo('Leave empty if you do not want to modify the value')

    client.name = click.prompt('New Name', type=str, default=client.name)
    client.company = click.prompt('New Company', type=str, default=client.company)
    client.email = click.prompt('New Email', type=str, default=client.email)
    client.position = click.prompt('New Position', type=str, default=client.position)

    return client

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_service = ClientServices(ctx.obj['clients_table'])
    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client_service._delete_client(Client(**client[0]))
        click.echo('Remove it')
    else:
        click.echo('Client not found')

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def search(ctx, client_uid):
    """Search a client """
    client_service = ClientServices(ctx.obj['clients_table'])
    client_found = client_service.search_client(client_uid)

    click.echo('  ID  |  NAME  |  COMPANY  |  EMAIL  |  POSITION')
    click.echo('*'*50)

    for client in client_found:
        print('{uid}  |  {name}  |  {company}  |  {email}  |  {position}'.format(
            uid = client['uid'],
            name = client['name'],
            company = client['company'],
            email = client['email'],
            position = client['position']
        ))

all = clients

retos cumplidos

Ahora si, despues de muchos intentos, funconando.

mi codigo del reto:

services.py

 def delete_client(self, uid):
        clients = self.list_clients()

        updated_clients = list()

        for cli in clients:

            if cli['uid'] == uid:
                pass
            else:
                updated_clients.append(cli)
        
        self._save_to_disk(updated_clients)```


commands.py:



@clients.command()
@click.argument(‘client_uid’,
type=str)
@click.pass_context
def delete(ctx, client_uid):
""“delete a client”""
client_service = ClientService(ctx.obj[‘clients_table’])

client_list = client_service.list_clients()

deleted_client = [client for client in client_list if client['uid'] == client_uid]

if deleted_client:
    client_service.delete_client(client_uid)
    click.echo('client successfully deleted')
else:
    click.echo('client not found')```

Mi solución al reto. Funciona similar a Update con $pv clients update <uid>

Mis métodos de list se lama read y read_clients por si ven la diferencia:

**
services.py**

    def delete_client(self, deleted_client):
        clients = self.read_clients()

        updated_clients = []
        
        for client in clients:
            if client['uid'] != deleted_client.uid:
                updated_clients.append(client)
      
        self._save_to_disk(updated_clients)

commands.py

@clients.command()
@click.argument('client_uid',
                type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Deletes a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    clients_list = client_service.read_clients()

    client = [client for client in clients_list if client['uid'] == client_uid]

    if client:
        client = Client(**client[0])
        client_service.delete_client(client)

        click.echo('Client deleted')
    else:
        click.echo('Client not found')

¡Mi solucion al reto!

en el archivo services.py

def delete_client(self,deleted_client_uid):
        clients=self.list_client()
        not_deleted_clients=[]

        for client in clients:
            if client['uid'] != deleted_client_uid:
                 not_deleted_clients.append(client)

        self._save_to_disk(not_deleted_clients)

y en el archivo commands.py

@clients.command()
@click.pass_context
@click.argument('client_uid',type=str)
def delete(ctx,client_uid):
    """Delete a client"""
    client_service=ClientService(ctx.obj['clients_table'])
    client_list = client_service.list_client()
    client = [client for client in client_list if client['uid']==client_uid]
    if client:
        client_service.delete_client(client_uid)
        click.echo('Client deleted')            
    else:
        click.echo('Client not found')```

Hay algo que si tengo que decir de este ejercicio con el api, uno usualmente sigue el código, que esta ejecutando el profesor, y sale un error, entonces vas a descargar los archivos y el diferente el código 😕 realmente un tema importante a nivel de explicacion del codigo implementado no se esta haciendo acá 😦

Mi contribución

services.py

commands.py

Aquí les comparto una solución al reto: Método delete:

archivo “services.py: Creamos el metodo delete_client(), el cual usa un dictionary comprehension para detectar el cliente que queremos borrar (sólo usamos 3 lineas de código). Los demás clientes los guarda en la lista “final_clients” y la guarda en disco.

def delete_client(self, del_client):
		clients = self.list_clients()

		final_clients = [client for client in clients if not (client['uid'] == del_client.uid)]

		self._save_to_disk(final_clients)

archivo “commands.py: Creamos el comando delete(), que es muy similar al código del comando update(). El comando delete() llama al método delete_client() que creamos en el archivo anterior.

@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
	"""Deletes a client"""
	client_service = ClientService(ctx.obj['clients_table'])
	
	client_list = client_service.list_clients()

	client = [client for client in client_list if client['uid'] == client_uid]

	if client:
		
		client_service.delete_client(Client(**client[0]))

		click.echo('Client deleted')
	else:
		click.echo('Client not found')

Me encanto esta práctica, gracias profesor David Aroesti!
Esta fue mi solución
[commands.py]

@clients.command()
@click.argument('client_email',
                type=str)
@click.pass_context
def delete(ctx, client_email):
    """Delete a client"""
    clients_service = ClientService(ctx.obj['clients_table'])
    clients_list = clients_service.list_clients()

    client_to_delete = [client for client in clients_list
                        if client['email'] == client_email]
    if client_to_delete:
#        print('cliente no descomprimido:::')
#        print(client_to_delete)
#        print('cliente descomprimido:::')
#        print(**client_to_delete)
        client_to_delete = Client(**client_to_delete[0])
        clients_service.delete_client(client_to_delete)
        click.echo('Client {} deleted'.format(client_email))
    else:
        click.echo('Client {} not found'.format(client_email))

[services.py]

    def delete_client(self, client_to_delete):
        clients = self.list_clients()
        updated_clients = []
        for client in clients:
            if client['email'] == client_to_delete.email:
                pass
            else:
                updated_clients.append(client)
        self._save_to_disk(updated_clients)	

Les comparto la documentacion de Click esta super genial para entender esta clase si te sientes un poco perdido.

Click documentation

Hasta ahorita he notado bastante hate sobre el curso, estamos en un curso para aprender a desarrollar y siendo una comunidad tan grande me decepciona la actitud de algunos compañeros.
Prefiero 100% pagar los cursos de platzi y aprender lo que yo quiero en un año y generar ingresos, y no pagar durante 5 años una universidad que quizá aprenda el 80 o 90% de lo que estudie ahí.

bueno algo confuso de errores, pero viendo comentarios solucionamos el error

A continuación mi código en command

import click

from clients.services import ClientService
from clients.models import Client

@click.group()
def clients():
    """Manages the clients lifeclycle"""
    pass


@clients.command()
@click.option('-n', '--name', 
              type=str,
              prompt=True,
              help='The client name')
@click.option('-c', '--company', 
              type=str,
              prompt=True,
              help='The client company')
@click.option('-e', '--email', 
              type=str,
              prompt=True,
              help='The client email')
@click.option('-p', '--position', 
              type=str,
              prompt=True,
              help='The client position')
@click.pass_context
def create(ctx, name, company, email, position):
    """Creates a new cliente"""
    client_service = ClientService(ctx.obj['clients_table'])
    client = Client(name, company, email, position)

    client_service.create_client(client)


@clients.command()
@click.pass_context
def list(ctx):
    """List all clientes"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    click.echo(' ID  |  NAME  |  COMPANY  | EMAIL  |  POSITION')
    click.echo('*' * 100)

    for client in client_list:
        click.echo('{uid} | {name} | {company} | {email} | {position}'.format(
            uid=client['uid'],
            name=client['name'],
            company=client['company'],
            email=client['email'],
            position=client['position']
        ))


@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def update(ctx, client_uid):
    """Updates a clients"""
    client_service = ClientService(ctx.obj['clients_table'])

    client_list = client_service.list_clients()

    client = [client for client in client_list if client['uid'] == client_uid]

    if client:
        client = _update_client_flow(Client(**client[0]))
        client_service.update_client(client)

        click.echo('Client update')
    else:
        click.echo('Client not found')


def _update_client_flow(client):
    click.echo('Leave empty if you dont want to modify the value')

    client.name = click.prompt('New name', type=str, default=client.name)
    client.company = click.prompt('New company', type=str, default=client.company)
    client.email = click.prompt('New email', type=str, default=client.email)
    client.position = click.prompt('New position', type=str, default=client.position)

    return client


@clients.command()
@click.argument('client_uid', type=str)
@click.pass_context
def delete(ctx, client_uid):
    """Delete a client"""
    client_service = ClientService(ctx.obj['clients_table'])

    if click.confirm('Are you sure want to delete the client with uid: {}'.format(client_uid)):
        client_service.delete_client(client_uid)


all = clients

Hola, la verdad no he podido entender, es muy rápido y aunque uno repita los videos no logro entender que está haciendo, estoy así desde que empezó los diferentes archivos…

Aquí hay información de como utilizar la instrucción:
@click.pass_context
https://click.palletsprojects.com/en/7.x/complex/
(yo tuve dudas de lo que hacia y cuando utilizarlo)

No he podido correr mi código, no logro conectar los métodos de comands con pv. Este es el error que me aparace

D:\Vacaciones\Python\pv> pv clients create
Usage: pv clients [OPTIONS] COMMAND [ARGS]…
Try “pv clients --help” for help.

Error: No such command “create”.

comands.py

<import click
from clientes.servicios import ClientService
from clientes.modelos import Client

@click.group()
def clients():
  # Maneja el ciclo de los clientes
  pass

@click.command()
@click.option('-n', '--name',
              type = str,
              prompt = True,
              help = 'The client name')
@click.option('-c', '--company',
              type = str,
              prompt = True,
              help = 'The client company')
@click.option('-e', '--email',
              type = str,
              prompt = True,
              help = 'The client email')
@click.option('-p', '--position',
              type = str,
              prompt = True,
              help = 'The client position')
@click.pass_context
def create(ctx, name, company, email, position):
   #Crea un nuevo cliente
   client = Client(name, company, email, position)
   client_service = ClientService(ctx.obj['clients_table'])
   client_service.create_client(client)


@click.command()
@click.pass_context
def list(ctx):
    #List all clients
    client_service = ClientService(ctx.obj['clients_table'])
    clients_list = client_service.list()
    click.echo('  ID   |   Name   |   Company   |    Email   |   Position  ')
    click.echo ('*'*50)
    for client in clients_list:
     click.echo ( ' {uid} | {name} | {company} | {email} | {position}'.format(
      uid = client['uid'],
      name = client['name'],
      company = client['company'],
      email = client['email'],
      position = client['position'],))


@click.command()
@click.pass_context
def update(ctx, cliente_id):
  #Updates a client
 pass


@click.command()
@click.pass_context
def delete(ctx, cliente_id):
 # Deletes a client
 pass

all = clients>

pv.py

<import click
from clientes import comandos as comandos_clientes

CLIENTS_TABLE = '.clients.csv'

@click.group()
@click.pass_context
def cli(ctx):
    ctx.obj = {}
    ctx.obj['clients_table'] = CLIENTS_TABLE


cli.add_command(comandos_clientes.all)>