Repository: mouredev/Hello-Python Branch: main Commit: 55e1bb457840 Files: 44 Total size: 64.6 KB Directory structure: gitextract_uv6mnn0a/ ├── .gitignore ├── Backend/ │ ├── FastAPI/ │ │ ├── db/ │ │ │ ├── client.py │ │ │ ├── models/ │ │ │ │ └── user.py │ │ │ └── schemas/ │ │ │ └── user.py │ │ ├── main.py │ │ ├── requirements.txt │ │ ├── routers/ │ │ │ ├── basic_auth_users.py │ │ │ ├── jwt_auth_users.py │ │ │ ├── products.py │ │ │ ├── users.py │ │ │ └── users_db.py │ │ └── vercel.json │ └── type_hints.py ├── Basic/ │ ├── 00_helloworld.py │ ├── 01_variables.py │ ├── 02_operators.py │ ├── 03_strings.py │ ├── 04_lists.py │ ├── 05_tuples.py │ ├── 06_sets.py │ ├── 07_dicts.py │ ├── 08_conditionals.py │ ├── 09_loops.py │ ├── 10_functions.py │ ├── 11_classes.py │ ├── 12_exceptions.py │ ├── 13_modules.py │ └── my_module.py ├── Intermediate/ │ ├── 00_dates.py │ ├── 01_list_comprehension.py │ ├── 02_challenges.py │ ├── 03_lambdas.py │ ├── 04_higher_order_functions.py │ ├── 05_error_types.py │ ├── 06_file_handling.py │ ├── 07_regular_expressions.py │ ├── 08_python_package_manager.py │ ├── my_file.csv │ ├── my_file.json │ ├── my_file.txt │ └── mypackage/ │ ├── __init__.py │ └── arithmetics.py ├── LICENSE └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ __pycache__/ *.py[cod] ================================================ FILE: Backend/FastAPI/db/client.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=20480) ### MongoDB client ### # Descarga versión community: https://www.mongodb.com/try/download # Instalación:https://www.mongodb.com/docs/manual/tutorial # Módulo conexión MongoDB: pip install pymongo # Ejecución: sudo mongod --dbpath "/path/a/la/base/de/datos/" # Conexión: mongodb://localhost from pymongo import MongoClient # Descomentar el db_client local o remoto correspondiente # Base de datos local MongoDB db_client = MongoClient().local # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=25470 # Base de datos remota MongoDB Atlas (https://mongodb.com) # db_client = MongoClient( # "mongodb+srv://:@/?retryWrites=true&w=majority").test # Despliegue API en la nube: # Deta (deprecado) - https://www.deta.sh/ # Vercel - https://www.vercel.com # Instrucciones - https://cleverzone.medium.com/fastapi-deployment-into-vercel-0fa4e6478014 # MUY IMPORTANTE - Al desplegar en producción, preparar el proyecto para trabajar con variables de entorno que hagan referencia a datos sensibles: # - Nunca subas a un repositorio público el valor de las variables # - Puedes usar dotenv en Python # - Añade el valor de las variables desde el proveedor de hosting ================================================ FILE: Backend/FastAPI/db/models/user.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=20480 ### User model ### from pydantic import BaseModel from typing import Optional class User(BaseModel): id: Optional[str] = None username: str email: str ================================================ FILE: Backend/FastAPI/db/schemas/user.py ================================================ # Clase en vídeo (22/12/2022): https://www.twitch.tv/videos/1686104006 ### User schema ### def user_schema(user) -> dict: return {"id": str(user["_id"]), "username": user["username"], "email": user["email"]} def users_schema(users) -> list: return [user_schema(user) for user in users] ================================================ FILE: Backend/FastAPI/main.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A ### Hola Mundo ### # Documentación oficial: https://fastapi.tiangolo.com/es/ # Instala FastAPI: pip install "fastapi[all]" from fastapi import FastAPI from routers import products, users, basic_auth_users, jwt_auth_users, users_db from fastapi.staticfiles import StaticFiles import os app = FastAPI() # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=12475 app.include_router(products.router) app.include_router(users.router) # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=14094 app.include_router(basic_auth_users.router) # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=17664 app.include_router(jwt_auth_users.router) # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=20480 app.include_router(users_db.router) # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=13618 app.mount("/static", StaticFiles(directory="static"), name="static") # Url local: http://127.0.0.1:8000 @app.get("/") async def root(): return "Hola FastAPI!" # Url local: http://127.0.0.1:8000/url @app.get("/url") async def url(): return {"url": "https://mouredev.com/python"} # Inicia el server: uvicorn main:app --reload # Detener el server: CTRL+C # Documentación con Swagger: http://127.0.0.1:8000/docs # Documentación con Redocly: http://127.0.0.1:8000/redoc ================================================ FILE: Backend/FastAPI/requirements.txt ================================================ fastapi[standard] python-jose passlib bcrypt pymongo ================================================ FILE: Backend/FastAPI/routers/basic_auth_users.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=14094 ### Users API con autorización OAuth2 básica ### from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm router = APIRouter( prefix="/basicauth", tags=["basicauth"], responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}} ) oauth2 = OAuth2PasswordBearer(tokenUrl="login") class User(BaseModel): username: str full_name: str email: str disabled: bool class UserDB(User): password: str users_db = { "mouredev": { "username": "mouredev", "full_name": "Brais Moure", "email": "braismoure@mouredev.com", "disabled": False, "password": "123456" }, "mouredev2": { "username": "mouredev2", "full_name": "Brais Moure 2", "email": "braismoure2@mouredev.com", "disabled": True, "password": "654321" } } def search_user_db(username: str): if username in users_db: return UserDB(**users_db[username]) def search_user(username: str): if username in users_db: return User(**users_db[username]) async def current_user(token: str = Depends(oauth2)): user = search_user(token) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Credenciales de autenticación inválidas", headers={"WWW-Authenticate": "Bearer"}) if user.disabled: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Usuario inactivo") return user @router.post("/login") async def login(form: OAuth2PasswordRequestForm = Depends()): user_db = users_db.get(form.username) if not user_db: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="El usuario no es correcto") user = search_user_db(form.username) if not form.password == user.password: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="La contraseña no es correcta") return {"access_token": user.username, "token_type": "bearer"} @router.get("/users/me") async def me(user: User = Depends(current_user)): return user ================================================ FILE: Backend/FastAPI/routers/jwt_auth_users.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=17664 ### Users API con autorización OAuth2 JWT ### from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import jwt, JWTError from passlib.context import CryptContext from datetime import datetime, timedelta, timezone ALGORITHM = "HS256" ACCESS_TOKEN_DURATION = 1 SECRET = "201d573bd7d1344d3a3bfce1550b69102fd11be3db6d379508b6cccc58ea230b" router = APIRouter( prefix="/jwtauth", tags=["jwtauth"], responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}} ) oauth2 = OAuth2PasswordBearer(tokenUrl="login") crypt = CryptContext(schemes=["bcrypt"]) class User(BaseModel): username: str full_name: str email: str disabled: bool class UserDB(User): password: str users_db = { "mouredev": { "username": "mouredev", "full_name": "Brais Moure", "email": "braismoure@mouredev.com", "disabled": False, "password": "$2a$12$B2Gq.Dps1WYf2t57eiIKjO4DXC3IUMUXISJF62bSRiFfqMdOI2Xa6" }, "mouredev2": { "username": "mouredev2", "full_name": "Brais Moure 2", "email": "braismoure2@mouredev.com", "disabled": True, "password": "$2a$12$SduE7dE.i3/ygwd0Kol8bOFvEABaoOOlC8JsCSr6wpwB4zl5STU4S" } } def search_user_db(username: str): if username in users_db: return UserDB(**users_db[username]) def search_user(username: str): if username in users_db: return User(**users_db[username]) async def auth_user(token: str = Depends(oauth2)): exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Credenciales de autenticación inválidas", headers={"WWW-Authenticate": "Bearer"}) try: username = jwt.decode(token, SECRET, algorithms=[ALGORITHM]).get("sub") if username is None: raise exception except JWTError: raise exception return search_user(username) async def current_user(user: User = Depends(auth_user)): if user.disabled: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Usuario inactivo") return user @router.post("/login") async def login(form: OAuth2PasswordRequestForm = Depends()): user_db = users_db.get(form.username) if not user_db: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="El usuario no es correcto") user = search_user_db(form.username) if not crypt.verify(form.password, user.password): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="La contraseña no es correcta") access_token = {"sub": user.username, "exp": datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_DURATION)} return {"access_token": jwt.encode(access_token, SECRET, algorithm=ALGORITHM), "token_type": "bearer"} @router.get("/users/me") async def me(user: User = Depends(current_user)): return user ================================================ FILE: Backend/FastAPI/routers/products.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=12475 ### Products API ### from fastapi import APIRouter router = APIRouter( prefix="/products", tags=["products"], responses={404: {"message": "No encontrado"}} ) products_list = ["Producto 1", "Producto 2", "Producto 3", "Producto 4", "Producto 5"] @router.get("/") async def products(): return products_list @router.get("/{id}") async def products(id: int): return products_list[id] ================================================ FILE: Backend/FastAPI/routers/users.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=5382 ### Users API ### from fastapi import APIRouter, HTTPException from pydantic import BaseModel # Inicia el server: uvicorn users:app --reload router = APIRouter() class User(BaseModel): id: int name: str surname: str url: str age: int users_list = [User(id=1, name="Brais", surname="Moure", url="https://moure.dev", age=35), User(id=2, name="Moure", surname="Dev", url="https://mouredev.com", age=35), User(id=3, name="Brais", surname="Dahlberg", url="https://haakon.com", age=33)] @router.get("/usersjson") async def usersjson(): # Creamos un JSON a mano return [{"name": "Brais", "surname": "Moure", "url": "https://moure.dev", "age": 35}, {"name": "Moure", "surname": "Dev", "url": "https://mouredev.com", "age": 35}, {"name": "Haakon", "surname": "Dahlberg", "url": "https://haakon.com", "age": 33}] @router.get("/users") async def users(): return users_list @router.get("/user/{id}") # Path async def user(id: int): return search_user(id) @router.get("/user/") # Query async def user(id: int): return search_user(id) # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=8529 @router.post("/user/", response_model=User, status_code=201) async def user(user: User): if type(search_user(user.id)) == User: raise HTTPException(status_code=404, detail="El usuario ya existe") users_list.append(user) return user @router.put("/user/") async def user(user: User): found = False for index, saved_user in enumerate(users_list): if saved_user.id == user.id: users_list[index] = user found = True if not found: return {"error": "No se ha actualizado el usuario"} return user @router.delete("/user/{id}") async def user(id: int): found = False for index, saved_user in enumerate(users_list): if saved_user.id == id: del users_list[index] found = True if not found: return {"error": "No se ha eliminado el usuario"} def search_user(id: int): users = filter(lambda user: user.id == id, users_list) try: return list(users)[0] except: return {"error": "No se ha encontrado el usuario"} ================================================ FILE: Backend/FastAPI/routers/users_db.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=20480 ### Users DB API ### from fastapi import APIRouter, HTTPException, status from db.models.user import User from db.schemas.user import user_schema, users_schema from db.client import db_client from bson import ObjectId router = APIRouter( prefix="/userdb", tags=["userdb"], responses={status.HTTP_404_NOT_FOUND: {"message": "No encontrado"}}) @router.get("/", response_model=list[User]) async def users(): return users_schema(db_client.users.find()) @router.get("/{id}") # Path async def user(id: str): return search_user("_id", ObjectId(id)) @router.get("/") # Query async def user(id: str): return search_user("_id", ObjectId(id)) @router.post("/", response_model=User, status_code=status.HTTP_201_CREATED) async def user(user: User): if type(search_user("email", user.email)) == User: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="El usuario ya existe") user_dict = dict(user) del user_dict["id"] id = db_client.users.insert_one(user_dict).inserted_id new_user = user_schema(db_client.users.find_one({"_id": id})) return User(**new_user) @router.put("/", response_model=User) async def user(user: User): user_dict = dict(user) del user_dict["id"] try: db_client.users.find_one_and_replace( {"_id": ObjectId(user.id)}, user_dict) except: return {"error": "No se ha actualizado el usuario"} return search_user("_id", ObjectId(user.id)) @router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT) async def user(id: str): found = db_client.users.find_one_and_delete({"_id": ObjectId(id)}) if not found: return {"error": "No se ha eliminado el usuario"} # Helper def search_user(field: str, key): try: user = db_client.users.find_one({field: key}) return User(**user_schema(user)) except: return {"error": "No se ha encontrado el usuario"} ================================================ FILE: Backend/FastAPI/vercel.json ================================================ { "builds": [ { "src": "main.py", "use": "@vercel/python" } ], "routes": [ { "src": "/(.*)", "dest": "main.py" } ] } ================================================ FILE: Backend/type_hints.py ================================================ # Clase en vídeo: https://youtu.be/_y9qQZXE24A?t=1810 ### Type Hints ### my_string_variable = "My String variable" print(my_string_variable) print(type(my_string_variable)) my_string_variable = 5 print(my_string_variable) print(type(my_string_variable)) my_typed_variable: str = "My typed String variable" print(my_typed_variable) print(type(my_typed_variable)) my_typed_variable = 5 print(my_typed_variable) print(type(my_typed_variable)) ================================================ FILE: Basic/00_helloworld.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc ### Hola Mundo ### # Nuestro hola mundo en Python print("Hola Python") print('Hola Python') # Esto es un comentario """ Este es un comentario en varias líneas """ ''' Este también es un comentario en varias líneas ''' # Cómo consultar el tipo de dato print(type("Soy un dato str")) # Tipo 'str' print(type(5)) # Tipo 'int' print(type(1.5)) # Tipo 'float' print(type(3 + 1j)) # Tipo 'complex' print(type(True)) # Tipo 'bool' print(type(print("Mi cadena de texto"))) # Tipo 'NoneType' ================================================ FILE: Basic/01_variables.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=2938 ### Variables ### my_string_variable = "My String variable" print(my_string_variable) my_int_variable = 5 print(my_int_variable) my_int_to_str_variable = str(my_int_variable) print(my_int_to_str_variable) print(type(my_int_to_str_variable)) my_bool_variable = False print(my_bool_variable) # Concatenación de variables en un print print(my_string_variable, my_int_to_str_variable, my_bool_variable) print("Este es el valor de:", my_bool_variable) # Algunas funciones del sistema print(len(my_string_variable)) # Variables en una sola línea. ¡Cuidado con abusar de esta sintaxis! name, surname, alias, age = "Brais", "Moure", 'MoureDev', 35 print("Me llamo:", name, surname, ". Mi edad es:", age, ". Y mi alias es:", alias) # Inputs name = input('¿Cuál es tu nombre? ') age = input('¿Cuántos años tienes? ') print(name) print(age) # Cambiamos su tipo name = 35 age = "Brais" print(name) print(age) # ¿Forzamos el tipo? address: str = "Mi dirección" address = True address = 5 address = 1.2 print(type(address)) ================================================ FILE: Basic/02_operators.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=5665 ### Operadores Aritméticos ### # Operaciones con enteros print(3 + 4) print(3 - 4) print(3 * 4) print(3 / 4) print(10 % 3) print(10 // 3) print(2 ** 3) print(2 ** 3 + 3 - 7 / 1 // 4) # Operaciones con cadenas de texto print("Hola " + "Python " + "¿Qué tal?") print("Hola " + str(5)) # Operaciones mixtas print("Hola " * 5) print("Hola " * (2 ** 3)) my_float = 2.5 * 2 print("Hola " * int(my_float)) ### Operadores Comparativos ### # Operaciones con enteros print(3 > 4) print(3 < 4) print(3 >= 4) print(4 <= 4) print(3 == 4) print(3 != 4) # Operaciones con cadenas de texto print("Hola" > "Python") print("Hola" < "Python") print("aaaa" >= "abaa") # Ordenación alfabética por ASCII print(len("aaaa") >= len("abaa")) # Cuenta caracteres print("Hola" <= "Python") print("Hola" == "Hola") print("Hola" != "Python") ### Operadores Lógicos ### # Basada en el Álgebra de Boole https://es.wikipedia.org/wiki/%C3%81lgebra_de_Boole print(3 > 4 and "Hola" > "Python") print(3 > 4 or "Hola" > "Python") print(3 < 4 and "Hola" < "Python") print(3 < 4 or "Hola" > "Python") print(3 < 4 or ("Hola" > "Python" and 4 == 4)) print(not (3 > 4)) ================================================ FILE: Basic/03_strings.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=8643 ### Strings ### my_string = "Mi String" my_other_string = 'Mi otro String' print(len(my_string)) print(len(my_other_string)) print(my_string + " " + my_other_string) my_new_line_string = "Este es un String\ncon salto de línea" print(my_new_line_string) my_tab_string = "\tEste es un String con tabulación" print(my_tab_string) my_scape_string = "\\tEste es un String \\n escapado" print(my_scape_string) # Formateo name, surname, age = "Brais", "Moure", 35 print("Mi nombre es {} {} y mi edad es {}".format(name, surname, age)) print("Mi nombre es %s %s y mi edad es %d" % (name, surname, age)) print("Mi nombre es " + name + " " + surname + " y mi edad es " + str(age)) print(f"Mi nombre es {name} {surname} y mi edad es {age}") # Desempaqueado de caracteres language = "python" a, b, c, d, e, f = language print(a) print(e) # División language_slice = language[1:3] print(language_slice) language_slice = language[1:] print(language_slice) language_slice = language[-2] print(language_slice) language_slice = language[0:6:2] print(language_slice) # Reverse reversed_language = language[::-1] print(reversed_language) # Funciones del lenguaje print(language.capitalize()) print(language.upper()) print(language.count("t")) print(language.isnumeric()) print("1".isnumeric()) print(language.lower()) print(language.lower().isupper()) print(language.startswith("Py")) print("Py" == "py") # No es lo mismo ================================================ FILE: Basic/04_lists.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=10872 ### Lists ### # Definición my_list = list() my_other_list = [] print(len(my_list)) my_list = [35, 24, 62, 52, 30, 30, 17] print(my_list) print(len(my_list)) my_other_list = [35, 1.77, "Brais", "Moure"] print(type(my_list)) print(type(my_other_list)) # Acceso a elementos y búsqueda print(my_other_list[0]) print(my_other_list[1]) print(my_other_list[-1]) print(my_other_list[-4]) print(my_list.count(30)) # print(my_other_list[4]) IndexError # print(my_other_list[-5]) IndexError print(my_other_list.index("Brais")) age, height, name, surname = my_other_list print(name) name, height, age, surname = my_other_list[2], my_other_list[1], my_other_list[0], my_other_list[3] print(age) # Concatenación print(my_list + my_other_list) #print(my_list - my_other_list) # Creación, inserción, actualización y eliminación my_other_list.append("MoureDev") print(my_other_list) my_other_list.insert(1, "Rojo") print(my_other_list) my_other_list[1] = "Azul" print(my_other_list) my_other_list.remove("Azul") print(my_other_list) my_list.remove(30) print(my_list) print(my_list.pop()) print(my_list) my_pop_element = my_list.pop(2) print(my_pop_element) print(my_list) del my_list[2] print(my_list) # Operaciones con listas my_new_list = my_list.copy() my_list.clear() print(my_list) print(my_new_list) my_new_list.reverse() print(my_new_list) my_new_list.sort() print(my_new_list) # Sublistas print(my_new_list[1:3]) # Cambio de tipo my_list = "Hola Python" print(my_list) print(type(my_list)) ================================================ FILE: Basic/05_tuples.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=14711 ### Tuples ### # Definición my_tuple = tuple() my_other_tuple = () my_tuple = (35, 1.77, "Brais", "Moure", "Brais") my_other_tuple = (35, 60, 30) print(my_tuple) print(type(my_tuple)) # Acceso a elementos y búsqueda print(my_tuple[0]) print(my_tuple[-1]) # print(my_tuple[4]) IndexError # print(my_tuple[-6]) IndexError print(my_tuple.count("Brais")) print(my_tuple.index("Moure")) print(my_tuple.index("Brais")) # my_tuple[1] = 1.80 'tuple' object does not support item assignment # Concatenación my_sum_tuple = my_tuple + my_other_tuple print(my_sum_tuple) # Subtuplas print(my_sum_tuple[3:6]) # Tupla mutable con conversión a lista my_tuple = list(my_tuple) print(type(my_tuple)) my_tuple[4] = "MoureDev" my_tuple.insert(1, "Azul") my_tuple = tuple(my_tuple) print(my_tuple) print(type(my_tuple)) # Eliminación # del my_tuple[2] TypeError: 'tuple' object doesn't support item deletion del my_tuple # print(my_tuple) NameError: name 'my_tuple' is not defined ================================================ FILE: Basic/06_sets.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=16335 ### Sets ### # Definición my_set = set() my_other_set = {} print(type(my_set)) print(type(my_other_set)) # Inicialmente es un diccionario my_other_set = {"Brais", "Moure", 35} print(type(my_other_set)) print(len(my_other_set)) # Inserción my_other_set.add("MoureDev") print(my_other_set) # Un set no es una estructura ordenada my_other_set.add("MoureDev") # Un set no admite repetidos print(my_other_set) # Búsqueda print("Moure" in my_other_set) print("Mouri" in my_other_set) # Eliminación my_other_set.remove("Moure") print(my_other_set) my_other_set.clear() print(len(my_other_set)) del my_other_set # print(my_other_set) NameError: name 'my_other_set' is not defined # Transformación my_set = {"Brais", "Moure", 35} my_list = list(my_set) print(my_list) print(my_list[0]) my_other_set = {"Kotlin", "Swift", "Python"} # Otras operaciones my_new_set = my_set.union(my_other_set) print(my_new_set.union(my_new_set).union(my_set).union({"JavaScript", "C#"})) print(my_new_set.difference(my_set)) ================================================ FILE: Basic/07_dicts.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc ### Dictionaries ### # Definición my_dict = dict() my_other_dict = {} print(type(my_dict)) print(type(my_other_dict)) my_other_dict = {"Nombre": "Brais", "Apellido": "Moure", "Edad": 35, 1: "Python"} my_dict = { "Nombre": "Brais", "Apellido": "Moure", "Edad": 35, "Lenguajes": {"Python", "Swift", "Kotlin"}, 1: 1.77 } print(my_other_dict) print(my_dict) print(len(my_other_dict)) print(len(my_dict)) # Búsqueda print(my_dict[1]) print(my_dict["Nombre"]) print("Moure" in my_dict) print("Apellido" in my_dict) # Inserción my_dict["Calle"] = "Calle MoureDev" print(my_dict) # Actualización my_dict["Nombre"] = "Pedro" print(my_dict["Nombre"]) # Eliminación del my_dict["Calle"] print(my_dict) # Otras operaciones print(my_dict.items()) print(my_dict.keys()) print(my_dict.values()) my_list = ["Nombre", 1, "Piso"] my_new_dict = dict.fromkeys((my_list)) print(my_new_dict) my_new_dict = dict.fromkeys(("Nombre", 1, "Piso")) print((my_new_dict)) my_new_dict = dict.fromkeys(my_dict) print((my_new_dict)) my_new_dict = dict.fromkeys(my_dict, "MoureDev") print((my_new_dict)) my_values = my_new_dict.values() print(type(my_values)) print(my_new_dict.values()) print(list(dict.fromkeys(list(my_new_dict.values())).keys())) print(tuple(my_new_dict)) print(set(my_new_dict)) ================================================ FILE: Basic/08_conditionals.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=21442 ### Conditionals ### # if my_condition = False if my_condition: # Es lo mismo que if my_condition == True: print("Se ejecuta la condición del if") my_condition = 5 * 5 if my_condition == 10: print("Se ejecuta la condición del segundo if") # if, elif, else if my_condition > 10 and my_condition < 20: print("Es mayor que 10 y menor que 20") elif my_condition == 25: print("Es igual a 25") else: print("Es menor o igual que 10 o mayor o igual que 20 o distinto de 25") print("La ejecución continúa") # Condicional con ispección de valor my_string = "" if not my_string: print("Mi cadena de texto es vacía") if my_string == "Mi cadena de textoooooo": print("Estas cadenas de texto coinciden") ================================================ FILE: Basic/09_loops.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=23822 ### Loops ### # While my_condition = 0 while my_condition < 10: print(my_condition) my_condition += 2 else: # Es opcional print("Mi condición es mayor o igual que 10") print("La ejecución continúa") while my_condition < 20: my_condition += 1 if my_condition == 15: print("Se detiene la ejecución") break print(my_condition) print("La ejecución continúa") # For my_list = [35, 24, 62, 52, 30, 30, 17] for element in my_list: print(element) my_tuple = (35, 1.77, "Brais", "Moure", "Brais") for element in my_tuple: print(element) my_set = {"Brais", "Moure", 35} for element in my_set: print(element) my_dict = {"Nombre": "Brais", "Apellido": "Moure", "Edad": 35, 1: "Python"} for element in my_dict: print(element) if element == "Edad": break else: print("El bucle for para el diccionario ha finalizado") print("La ejecución continúa") for element in my_dict: print(element) if element == "Edad": continue print("Se ejecuta") else: print("El bluce for para diccionario ha finalizado") ================================================ FILE: Basic/10_functions.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=26619 ### Functions ### # Definición def my_function(): print("Esto es una función") my_function() my_function() my_function() # Función con parámetros de entrada/argumentos def sum_two_values(first_value: int, second_value): print(first_value + second_value) sum_two_values(5, 7) sum_two_values(54754, 71231) sum_two_values("5", "7") sum_two_values(1.4, 5.2) # Función con parámetros de entrada/argumentos y retorno def sum_two_values_with_return(first_value, second_value): my_sum = first_value + second_value return my_sum my_result = sum_two_values(1.4, 5.2) print(my_result) my_result = sum_two_values_with_return(10, 5) print(my_result) # Función con parámetros de entrada/argumentos por clave def print_name(name, surname): print(f"{name} {surname}") print_name(surname="Moure", name="Brais") # Función con parámetros de entrada/argumentos por defecto def print_name_with_default(name, surname, alias="Sin alias"): print(f"{name} {surname} {alias}") print_name_with_default("Brais", "Moure") print_name_with_default("Brais", "Moure", "MoureDev") # Función con parámetros de entrada/argumentos arbitrarios def print_upper_texts(*texts): print(type(texts)) for text in texts: print(text.upper()) print_upper_texts("Hola", "Python", "MoureDev") print_upper_texts("Hola") ================================================ FILE: Basic/11_classes.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=29327 ### Classes ### # Definición class MyEmptyPerson: pass # Para poder dejar la clase vacía print(MyEmptyPerson) print(MyEmptyPerson()) # Clase con constructor, funciones y propiedades privadas y públicas class Person: def __init__(self, name, surname, alias="Sin alias"): self.full_name = f"{name} {surname} ({alias})" # Propiedad pública self.__name = name # Propiedad privada def get_name(self): return self.__name def walk(self): print(f"{self.full_name} está caminando") my_person = Person("Brais", "Moure") print(my_person.full_name) print(my_person.get_name()) my_person.walk() my_other_person = Person("Brais", "Moure", "MoureDev") print(my_other_person.full_name) my_other_person.walk() my_other_person.full_name = "Héctor de León (El loco de los perros)" print(my_other_person.full_name) my_other_person.full_name = 666 print(my_other_person.full_name) ================================================ FILE: Basic/12_exceptions.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=32030 ### Exception Handling ### numberOne = 5 numberTwo = 1 numberTwo = "1" # Excepción base: try except try: print(numberOne + numberTwo) print("No se ha producido un error") except: # Se ejecuta si se produce una excepción print("Se ha producido un error") # Flujo completo de una excepción: try except else finally try: print(numberOne + numberTwo) print("No se ha producido un error") except: print("Se ha producido un error") else: # Opcional # Se ejecuta si no se produce una excepción print("La ejecución continúa correctamente") finally: # Opcional # Se ejecuta siempre print("La ejecución continúa") # Excepciones por tipo try: print(numberOne + numberTwo) print("No se ha producido un error") except ValueError: print("Se ha producido un ValueError") except TypeError: print("Se ha producido un TypeError") # Captura de la información de la excepción try: print(numberOne + numberTwo) print("No se ha producido un error") except ValueError as error: print(error) except Exception as my_random_error_name: print(my_random_error_name) ================================================ FILE: Basic/13_modules.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=34583 ### Modules ### from math import pi as PI_VALUE import math from my_module import sumValue, printValue import my_module my_module.sumValue(5, 3, 1) my_module.printValue("Hola Python!") sumValue(5, 3, 1) printValue("Hola python") print(math.pi) print(math.pow(2, 8)) print(PI_VALUE) ================================================ FILE: Basic/my_module.py ================================================ # Clase en vídeo: https://youtu.be/Kp4Mvapo5kc?t=34583 ### Módulo para pruebas ### def sumValue(numberOne, numberTwo, numberThree): print(numberOne + numberTwo + numberThree) def printValue(value): print(value) ================================================ FILE: Intermediate/00_dates.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU ### Dates ### # Date time from datetime import timedelta from datetime import date from datetime import time from datetime import datetime now = datetime.now() def print_date(date): print(date.year) print(date.month) print(date.day) print(date.hour) print(date.minute) print(date.second) print(date.timestamp()) print_date(now) year_2023 = datetime(2023, 1, 1) print_date(year_2023) # Time current_time = time(21, 6, 0) print(current_time.hour) print(current_time.minute) print(current_time.second) # Date current_date = date.today() print(current_date.year) print(current_date.month) print(current_date.day) current_date = date(2022, 10, 6) print(current_date.year) print(current_date.month) print(current_date.day) current_date = date(current_date.year, current_date.month + 1, current_date.day) print(current_date.month) # Operaciones con fechas diff = year_2023 - now print(diff) diff = year_2023.date() - current_date print(diff) # Timedelta start_timedelta = timedelta(200, 100, 100, weeks=10) end_timedelta = timedelta(300, 100, 100, weeks=13) print(end_timedelta - start_timedelta) print(end_timedelta + start_timedelta) ================================================ FILE: Intermediate/01_list_comprehension.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=3239 ### List Comprehension ### my_original_list = [0, 1, 2, 3, 4, 5, 6, 7] print(my_original_list) my_range = range(8) print(list(my_range)) # Definición my_list = [i + 1 for i in range(8)] print(my_list) my_list = [i * 2 for i in range(8)] print(my_list) my_list = [i * i for i in range(8)] print(my_list) def sum_five(number): return number + 5 my_list = [sum_five(i) for i in range(8)] print(my_list) ================================================ FILE: Intermediate/02_challenges.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=4142 ### Challenges ### """ EL FAMOSO "FIZZ BUZZ”: Escribe un programa que muestre por consola (con un print) los números de 1 a 100 (ambos incluidos y con un salto de línea entre cada impresión), sustituyendo los siguientes: - Múltiplos de 3 por la palabra "fizz". - Múltiplos de 5 por la palabra "buzz". - Múltiplos de 3 y de 5 a la vez por la palabra "fizzbuzz". """ def fizzbuzz(): for index in range(1, 101): if index % 3 == 0 and index % 5 == 0: print("fizzbuzz") elif index % 3 == 0: print("fizz") elif index % 5 == 0: print("buzz") else: print(index) fizzbuzz() """ ¿ES UN ANAGRAMA? Escribe una función que reciba dos palabras (String) y retorne verdadero o falso (Bool) según sean o no anagramas. - Un Anagrama consiste en formar una palabra reordenando TODAS las letras de otra palabra inicial. - NO hace falta comprobar que ambas palabras existan. - Dos palabras exactamente iguales no son anagrama. """ def is_anagram(word_one, word_two): if word_one.lower() == word_two.lower(): return False return sorted(word_one.lower()) == sorted(word_two.lower()) print(is_anagram("Amor", "Roma")) """ LA SUCESIÓN DE FIBONACCI Escribe un programa que imprima los 50 primeros números de la sucesión de Fibonacci empezando en 0. - La serie Fibonacci se compone por una sucesión de números en la que el siguiente siempre es la suma de los dos anteriores. 0, 1, 1, 2, 3, 5, 8, 13... """ def fibonacci(): prev = 0 next = 1 for index in range(0, 50): print(prev) fib = prev + next prev = next next = fib fibonacci() """ ¿ES UN NÚMERO PRIMO? Escribe un programa que se encargue de comprobar si un número es o no primo. Hecho esto, imprime los números primos entre 1 y 100. """ def is_prime(): for number in range(1, 101): if number >= 2: is_divisible = False for index in range(2, number): if number % index == 0: is_divisible = True break if not is_divisible: print(number) is_prime() """ INVIRTIENDO CADENAS Crea un programa que invierta el orden de una cadena de texto sin usar funciones propias del lenguaje que lo hagan de forma automática. - Si le pasamos "Hola mundo" nos retornaría "odnum aloH" """ def reverse(text): text_len = len(text) reversed_text = "" for index in range(0, text_len): reversed_text += text[text_len - index - 1] return reversed_text print(reverse("Hola mundo")) ================================================ FILE: Intermediate/03_lambdas.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=9145 ### Lambdas ### sum_two_values = lambda first_value, second_value: first_value + second_value print(sum_two_values(2, 4)) multiply_values = lambda first_value, second_value: first_value * second_value - 3 print(multiply_values(2, 4)) def sum_three_values(value): return lambda first_value, second_value: first_value + second_value + value print(sum_three_values(5)(2, 4)) ================================================ FILE: Intermediate/04_higher_order_functions.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=10172 ### Higher Order Functions ### from functools import reduce def sum_one(value): return value + 1 def sum_five(value): return value + 5 def sum_two_values_and_add_value(first_value, second_value, f_sum): return f_sum(first_value + second_value) print(sum_two_values_and_add_value(5, 2, sum_one)) print(sum_two_values_and_add_value(5, 2, sum_five)) ### Closures ### def sum_ten(original_value): def add(value): return value + 10 + original_value return add add_closure = sum_ten(1) print(add_closure(5)) print((sum_ten(5))(1)) ### Built-in Higher Order Functions ### numbers = [2, 5, 10, 21, 3, 30] # Map def multiply_two(number): return number * 2 print(list(map(multiply_two, numbers))) print(list(map(lambda number: number * 2, numbers))) # Filter def filter_greater_than_ten(number): if number > 10: return True return False print(list(filter(filter_greater_than_ten, numbers))) print(list(filter(lambda number: number > 10, numbers))) # Reduce def sum_two_values(first_value, second_value): return first_value + second_value print(reduce(sum_two_values, numbers)) ================================================ FILE: Intermediate/05_error_types.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=12721 ### Error Types ### # SyntaxError # print "¡Hola comunidad!" # Descomentar para Error from math import pi import math print("¡Hola comunidad!") # NameError language = "Spanish" # Comentar para Error print(language) # IndexError my_list = ["Python", "Swift", "Kotlin", "Dart", "JavaScript"] print(my_list[0]) print(my_list[4]) print(my_list[-1]) # print(my_list[5]) # Descomentar para Error # ModuleNotFoundError # import maths # Descomentar para Error # AttributeError # print(math.PI) # Descomentar para Error print(math.pi) # KeyError my_dict = {"Nombre": "Brais", "Apellido": "Moure", "Edad": 35, 1: "Python"} print(my_dict["Edad"]) # print(my_dict["Apelido"]) # Descomentar para Error print(my_dict["Apellido"]) # TypeError # print(my_list["0"]) # Descomentar para Error print(my_list[0]) print(my_list[False]) # ImportError # from math import PI # Descomentar para Error print(pi) # ValueError # my_int = int("10 Años") # Descomentar para Error my_int = int("10") print(type(my_int)) # ZeroDivisionError # print(4/0) # Descomentar para Error print(4/2) ================================================ FILE: Intermediate/06_file_handling.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=15524 ### File Handling ### import xml import csv import json import os # .txt file # Leer, escribir y sobrescribir si ya existe txt_file = open("my_file.txt", "w+") txt_file.write( "Mi nombre es Brais\nMi apellido es Moure\n35 años\nY mi lenguaje preferido es Python") # Posiciona el cursor al inicio del fichero txt_file.seek(0) # Lee e imprime todo el contenido del fichero print(txt_file.read()) # Lee e imprime 10 caracteres desde el inicio del fichero txt_file.seek(0) print(txt_file.read(10)) # Lee e imprime el resto de la línea actual desde la posición 11 print(txt_file.readline()) # Lee e imprime la siguiente línea print(txt_file.readline()) # Lee e imprime las líneas restantes del fichero for line in txt_file.readlines(): print(line) # Escribe una nueva línea en el fichero txt_file.write("\nAunque también me gusta Kotlin") # Posiciona el cursor al inicio del fichero, lee e imprime todo su contenido txt_file.seek(0) print(txt_file.read()) # Cierra el fichero txt_file.close() # Agrega una nueva línea en el fichero with open("my_file.txt", "a") as my_other_file: my_other_file.write("\nY Swift") # os.remove("Intermediate/my_file.txt") # .json file json_file = open("Intermediate/my_file.json", "w+") json_test = { "name": "Brais", "surname": "Moure", "age": 35, "languages": ["Python", "Swift", "Kotlin"], "website": "https://moure.dev"} json.dump(json_test, json_file, indent=2) json_file.close() with open("Intermediate/my_file.json") as my_other_file: for line in my_other_file.readlines(): print(line) json_dict = json.load(open("Intermediate/my_file.json")) print(json_dict) print(type(json_dict)) print(json_dict["name"]) # .csv file csv_file = open("Intermediate/my_file.csv", "w+") csv_writer = csv.writer(csv_file) csv_writer.writerow(["name", "surname", "age", "language", "website"]) csv_writer.writerow(["Brais", "Moure", 35, "Python", "https://moure.dev"]) csv_writer.writerow(["Roswell", "", 2, "COBOL", ""]) csv_file.close() with open("Intermediate/my_file.csv") as my_other_file: for line in my_other_file.readlines(): print(line) # .xlsx file # import xlrd # Debe instalarse el módulo # .xml file # ¿Te atreves a practicar cómo trabajar con este tipo de ficheros? ================================================ FILE: Intermediate/07_regular_expressions.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=19762 ### Regular Expressions ### import re # match my_string = "Esta es la lección número 7: Lección llamada Expresiones Regulares" my_other_string = "Esta no es la lección número 6: Manejo de ficheros" match = re.match("Esta es la lección", my_string, re.I) print(match) start, end = match.span() print(my_string[start:end]) match = re.match("Esta no es la lección", my_other_string) # if not(match == None): # Otra forma de comprobar el None # if match != None: # Otra forma de comprobar el None if match is not None: print(match) start, end = match.span() print(my_other_string[start:end]) print(re.match("Expresiones Regulares", my_string)) # search search = re.search("lección", my_string, re.I) print(search) start, end = search.span() print(my_string[start:end]) # findall findall = re.findall("lección", my_string, re.I) print(findall) # split print(re.split(":", my_string)) # sub print(re.sub("[l|L]ección", "LECCIÓN", my_string)) print(re.sub("Expresiones Regulares", "RegEx", my_string)) ### Regular Expressions Patterns ### # Para aprender y validar expresiones regulares: https://regex101.com pattern = r"[lL]ección" print(re.findall(pattern, my_string)) pattern = r"[lL]ección|Expresiones" print(re.findall(pattern, my_string)) pattern = r"[0-9]" print(re.findall(pattern, my_string)) print(re.search(pattern, my_string)) pattern = r"\d" print(re.findall(pattern, my_string)) pattern = r"\D" print(re.findall(pattern, my_string)) pattern = r"[l].*" print(re.findall(pattern, my_string)) email = "mouredev@mouredev.com" pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z-.]+$" print(re.match(pattern, email)) print(re.search(pattern, email)) print(re.findall(pattern, email)) email = "mouredev@mouredev.com.mx" print(re.findall(pattern, email)) ================================================ FILE: Intermediate/08_python_package_manager.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=24010 ### Python Package Manager ### # PIP https://pypi.org # pip install pip # pip --version # pip install numpy import pandas from mypackage import arithmetics import requests import numpy print(numpy.version.version) numpy_array = numpy.array([35, 24, 62, 52, 30, 30, 17]) print(type(numpy_array)) print(numpy_array * 2) # pip install pandas # pip list # pip uninstall pandas # pip show numpy # pip install requests response = requests.get("https://pokeapi.co/api/v2/pokemon?limit=151") print(response) print(response.status_code) print(response.json()) # Arithmetics Package print(arithmetics.sum_two_values(1, 4)) ================================================ FILE: Intermediate/my_file.csv ================================================ name,surname,age,language,website Brais,Moure,35,Python,https://moure.dev Roswell,,2,COBOL, ================================================ FILE: Intermediate/my_file.json ================================================ { "name": "Brais", "surname": "Moure", "age": 35, "languages": [ "Python", "Swift", "Kotlin" ], "website": "https://moure.dev" } ================================================ FILE: Intermediate/my_file.txt ================================================ Mi nombre es Brais Mi apellido es Moure 35 años Y mi lenguaje preferido es Python Aunque también me gusta Kotlin Y Swift ================================================ FILE: Intermediate/mypackage/__init__.py ================================================ ================================================ FILE: Intermediate/mypackage/arithmetics.py ================================================ # Clase en vídeo: https://youtu.be/TbcEqkabAWU?t=24010 ### Arithmetics ### def sum_two_values(first_value, second_value): return first_value + second_value ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # Hello Python [![Python](https://img.shields.io/badge/Python-3.10+-yellow?style=for-the-badge&logo=python&logoColor=white&labelColor=101010)](https://python.org) [![FastAPI](https://img.shields.io/badge/FastAPI-0.88.0+-00a393?style=for-the-badge&logo=fastapi&logoColor=white&labelColor=101010)](https://fastapi.tiangolo.com) [![MongoDB](https://img.shields.io/badge/MongoDB-6.0+-00684A?style=for-the-badge&logo=mongodb&logoColor=white&labelColor=101010)](https://www.mongodb.com) [![ChatGPT](https://img.shields.io/badge/ChatGPT-GPT--4-7CF178?style=for-the-badge&logo=openai&logoColor=white&labelColor=101010)](https://platform.openai.com) [![Reflex](https://img.shields.io/badge/Reflex-0.4.6+-5646ED?style=for-the-badge&logo=reflex&logoColor=white&labelColor=101010)](https://reflex.dev) ## Curso para aprender el lenguaje de programación Python desde cero y para principiantes ![](./Images/header.jpg) ### Proyecto realizado durante emisiones en directo desde [Twitch](https://twitch.tv/mouredev) > ##### Si consideras útil el curso, apóyalo haciendo "★ Star" en el repositorio. ¡Gracias! ## Clases en vídeo ### Curso de fundamentos desde cero Curso que agrupa todas las clases en directo que hacen referencia a los fundamentos de Python. > Código: Directorio "Basic" en el proyecto - [Introducción](https://youtu.be/Kp4Mvapo5kc) - [Contexto](https://youtu.be/Kp4Mvapo5kc?t=244) - [Lección 1 - Configuración](https://youtu.be/Kp4Mvapo5kc?t=850) - [Lección 2 - Hola Mundo](https://youtu.be/Kp4Mvapo5kc?t=1518) - [Lección 3 - Variables](https://youtu.be/Kp4Mvapo5kc?t=2938) - [Lección 4 - Operadores](https://youtu.be/Kp4Mvapo5kc?t=5665) - [Lección 5 - Strings](https://youtu.be/Kp4Mvapo5kc?t=8643) - [Lección 6 - Listas](https://youtu.be/Kp4Mvapo5kc?t=10872) - [Lección 7 - Tuplas](https://youtu.be/Kp4Mvapo5kc?t=14711) - [Lección 8 - Sets](https://youtu.be/Kp4Mvapo5kc?t=16335) - [Lección 9 - Diccionarios](https://youtu.be/Kp4Mvapo5kc?t=18506) - [Lección 10 - Condicionales](https://youtu.be/Kp4Mvapo5kc?t=21442) - [Lección 11 - Bucles/Loops/Ciclos](https://youtu.be/Kp4Mvapo5kc?t=23822) - [Lección 12 - Funciones](https://youtu.be/Kp4Mvapo5kc?t=26619) - [Lección 13 - Clases](https://youtu.be/Kp4Mvapo5kc?t=29327) - [Lección 14 - Excepciones](https://youtu.be/Kp4Mvapo5kc?t=32030) - [Lección 15 - Módulos](https://youtu.be/Kp4Mvapo5kc?t=34583) - [Próximos pasos](https://youtu.be/Kp4Mvapo5kc?t=36390) ### Curso intermedio de fundamentos desde cero Curso en el que continuamos aprendiendo Python desde sus bases, siguiendo la ruta de aprendizaje desde la última lección del curso de inicial. > Código: Directorio "Intermediate" en el proyecto - [Introducción](https://youtu.be/TbcEqkabAWU) - [Lección 1 - Dates](https://youtu.be/TbcEqkabAWU?t=202) - [Lección 2 - List Comprehension](https://youtu.be/TbcEqkabAWU?t=3239) - [Lección 3 - Resolución de retos de programación](https://youtu.be/TbcEqkabAWU?t=4142) - [Lección 4 - Lambdas](https://youtu.be/TbcEqkabAWU?t=9145) - [Lección 5 - Funciones de orden superior](https://youtu.be/TbcEqkabAWU?t=10172) - [Lección 6 - Tipos de error](https://youtu.be/TbcEqkabAWU?t=12721) - [Lección 7 - Manejo de ficheros](https://youtu.be/TbcEqkabAWU?t=15524) - [Lección 8 - Expresiones regulares](https://youtu.be/TbcEqkabAWU?t=19762) - [Lección 9 - Manejo de paquetes](https://youtu.be/TbcEqkabAWU?t=24010) - [Próximos pasos](https://youtu.be/TbcEqkabAWU?t=26228) ### Backend desde cero Curso en el que aprenderemos a utilizar Python para backend e implementaremos un API REST con autenticación, base de datos y desplegaremos el proyecto en un servidor real. > Código: Directorio "Backend" en el proyecto - [Introducción](https://youtu.be/_y9qQZXE24A) - [Lección 01 - ¿Qué es un backend?](https://youtu.be/_y9qQZXE24A?t=125) - [Lección 02 - API y FastAPI](https://youtu.be/_y9qQZXE24A?t=834) - [Lección 03 - Type Hints](https://youtu.be/_y9qQZXE24A?t=1810) - [Lección 04 - Configuración FastAPI](https://youtu.be/_y9qQZXE24A?t=2629) - [Lección 05 - Hola mundo](https://youtu.be/_y9qQZXE24A?t=3504) - [Lección 06 - Operación GET](https://youtu.be/_y9qQZXE24A?t=5382) - [Lección 07 - Peticiones HTTP](https://youtu.be/_y9qQZXE24A?t=5925) - [Lección 08 - Creación API](https://youtu.be/_y9qQZXE24A?t=6099) - [Lección 09 - Path y Query](https://youtu.be/_y9qQZXE24A?t=7510) - [Lección 10 - Operaciones POST, PUT y DELETE](https://youtu.be/_y9qQZXE24A?t=8529) - [Lección 11 - HTTP status codes](https://youtu.be/_y9qQZXE24A?t=11072) - [Lección 12 - Routers](https://youtu.be/_y9qQZXE24A?t=12475) - [Lección 13 - Recursos estáticos](https://youtu.be/_y9qQZXE24A?t=13618) - [Lección 14 - Autorización OAuth2](https://youtu.be/_y9qQZXE24A?t=14094) - [Lección 15 - OAuth2 JWT](https://youtu.be/_y9qQZXE24A?t=17664) - [Lección 16 - MongoDB](https://youtu.be/_y9qQZXE24A?t=20480) - [Lección 17 - MongoDB Atlas](https://youtu.be/_y9qQZXE24A?t=25470) - [Lección 18 - Despliegue en Deta \*](https://youtu.be/_y9qQZXE24A?t=27335) - [Próximos pasos](https://youtu.be/_y9qQZXE24A?t=28484) **\*ACTUALIZACIÓN Sobre la lección 18:** Deta, el servicio utilizado para el despliegue durante el curso, ya no existe. Te recomiendo revisar la documentación oficial de FastAPI sobre [despliegue](https://fastapi.tiangolo.com/deployment/). Puedes utilizar alguno de los [proveedores gratuitos](https://fastapi.tiangolo.com/deployment/cloud/) recomendados. En mi caso, te dejo el [fichero de configuración](./Backend/FastAPI/vercel.json) y el de [dependencias](./Backend/FastAPI/requirements.txt) para hacerlo desde [Vercel](https://vercel.com/) (al crear el proyecto en la plataforma selecciona que el directorio "Backend/FastAPI" es el root). ### Frontend desde cero Cursos en los que aprenderemos a utilizar Python para desarrollo web con dos proyectos reales desplegados en producción. Tutoriales en vídeo paso a paso con 9 horas de contenido. [![Curso Python Web](https://img.shields.io/github/stars/mouredev/python-web?label=Curso%20Python%20web&style=social)](https://github.com/mouredev/python-web) [![Curso Python Web](https://img.shields.io/github/stars/mouredev/adeviento-web?label=Tutorial%20Python%20web%20extra&style=social)](https://github.com/mouredev/adeviento-web) ### Aprende a integrar ChatGPT en tu proyecto desde cero Clase de una hora de duración donde aprenderás a interactuar con ChatGPT desde tu aplicación, mantener conversaciones y establecer el contexto de la IA para potenciar tu proyecto. Con todo el código publicado [aquí](https://gist.github.com/mouredev/58abfbcef017efaf3852e8821564c011). ### Traductor de Voz con IA Aprende a desarrollar un traductor de voz a varios idiomas utilizando con IA. Creando su Web y todo en 100 líneas. Con todo el código publicado [aquí](https://gist.github.com/mouredev/0ea42112751f0187d90d5403d1f333e2). ### Introducción al Testing Taller de introducción a testing con Python creado junto a [Carlos Blé](https://www.carlosble.com) y [Miguel A. Gómez](https://softwarecrafters.io), expertos en la materia. ### Extra: 15 curiosidades sobre Python Y para finalizar... ¿Quieres saber aun más sobre él? Aquí tienes 15 curiosidades que quizás no conozcas sobre el lenguaje. ## Información importante y preguntas frecuentes Actualmente el curso está en pausa. Se han finalizados los bloques básico, intermedio y backend, y ese era el objetivo inicial del proyecto. No descarto añadir nuevas lecciones a futuro, pero creo que por el momento puede servir de base a cualquier persona que quiera empezar a aprender este lenguaje. - Recuerda que he creado en el [Discord](https://discord.gg/mouredev) un canal "🐍python" para que puedas comentar lo que quieras. - En el momento que el curso continúe, actualizaré el repositorio y avisaré en redes. ¡Muchísimas gracias por todo el apoyo mostrado! ## Enlaces de interés - [Web oficial de Python](https://www.python.org/) - [Tutorial oficial de Python en Español](https://docs.python.org/es/3/tutorial/index.html) - [Repo 30 días de Python](https://github.com/Asabeneh/30-Days-Of-Python) - [Juego Codédex para aprender Python](https://www.codedex.io/) - [Visual Studio Code](https://code.visualstudio.com/): El editor que estoy usando - [FastAPI](https://fastapi.tiangolo.com/es/): El framework para crear nuestra API Backend - [MongoDB](https://www.mongodb.com/): La base de datos que utiliza nuestro backend - [Vercel](https://vercel.com/): Para desplegar nuestra API en la nube ## Únete al campus de programación de la comunidad ![https://mouredev.pro](./Images/pro.jpg) #### Te presento [mouredev pro](https://mouredev.pro), mi proyecto más importante para ayudarte a estudiar programación y desarrollo de software de manera diferente. > **¿Buscas un extra?** Aquí encontrarás este y otros cursos editados por lecciones individuales, para avanzar a tu ritmo y guardar el progreso. También dispondrás de ejercicios y correcciones, test para validar tus conocimientos, examen y certificado público de finalización, soporte, foro de estudiantes, reunionnes grupales, cursos exclusivos y mucho más. > > Entra en **[mouredev.pro](https://mouredev.pro)** y utiliza el cupón **"PYTHON"** con un 10% de descuento en tu primera suscripción. ## ![https://mouredev.com](https://raw.githubusercontent.com/mouredev/mouredev/master/mouredev_emote.png) Hola, mi nombre es Brais Moure. ### Freelance full-stack iOS & Android engineer [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCxPD7bsocoAMq8Dj18kmGyQ?style=social)](https://youtube.com/mouredevapps?sub_confirmation=1) [![Twitch Status](https://img.shields.io/twitch/status/mouredev?style=social)](https://twitch.com/mouredev) [![Discord](https://img.shields.io/discord/729672926432985098?style=social&label=Discord&logo=discord)](https://mouredev.com/discord) [![Twitter Follow](https://img.shields.io/twitter/follow/mouredev?style=social)](https://twitter.com/mouredev) ![GitHub Followers](https://img.shields.io/github/followers/mouredev?style=social) ![GitHub Followers](https://img.shields.io/github/stars/mouredev?style=social) Soy ingeniero de software desde 2010. Desde 2018 combino mi trabajo desarrollando Apps con la creación de contenido formativo sobre programación y tecnología en diferentes redes sociales como **[@mouredev](https://moure.dev)**. Si quieres unirte a nuestra comunidad de desarrollo, aprender programación, mejorar tus habilidades y ayudar a la continuidad del proyecto, puedes encontrarnos en: [![Twitch](https://img.shields.io/badge/Twitch-Programación_en_directo-9146FF?style=for-the-badge&logo=twitch&logoColor=white&labelColor=101010)](https://twitch.tv/mouredev) [![Discord](https://img.shields.io/badge/Discord-Servidor_de_la_comunidad-5865F2?style=for-the-badge&logo=discord&logoColor=white&labelColor=101010)](https://mouredev.com/discord) [![Pro](https://img.shields.io/badge/Cursos-mouredev.pro-FF5500?style=for-the-badge&logo=gnometerminal&logoColor=white&labelColor=101010)](https://moure.dev) [![Link](https://img.shields.io/badge/Links_de_interés-moure.dev-14a1f0?style=for-the-badge&logo=Linktree&logoColor=white&labelColor=101010)](https://moure.dev) [![Web](https://img.shields.io/badge/GitHub-MoureDev-087ec4?style=for-the-badge&logo=github&logoColor=white&labelColor=101010)](https://github.com/mouredev)