{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[comment]: <> (los titulares se generan en el siguiente link: https://docs.google.com/drawings/d/1TLM83sTn9w2Jmq0l0Jy1ivIeLRVO_rKBCamm5Tq11Yo/edit?usp=sharing)\n",
    "\n",
    "![](../img/titulos_errores_excepciones.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Contenido\n",
    "\n",
    "* [Errores](#Errores)\n",
    "    * [Manejando excepciones](#Manejando-excepciones)\n",
    "    * [Definiendo acciones de limpieza](#Definiendo-acciones-de-limpieza)\n",
    "* [Configuracion de Python avanzada](#Configuracion-de-Python-avanzada)\n",
    "    * [Administrador de paquetes](#Administrador-de-paquetes)\n",
    "    * [Librerías](#Librerías)\n",
    "    * [Entornos virtuales](Entornos-virtuales)\n",
    "    * [IDE](#IDE)   \n",
    "* [Referencias usadas en el notebook](#Referencias-usadas-en-el-notebook)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Objetivos del notebook\n",
    "\n",
    "* Trabajar con excepciones y control de errores.\n",
    "* Configuración avanzada de Python.\n",
    "* Manejo de entornos virtuales.\n",
    "* Instalar y configurar un IDE."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Errores"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hay (al menos) dos tipos diferentes de errores: **errores de sintaxis** y **excepciones**. \n",
    "Los errores de sintaxis, también conocidos como errores de interpretación, son quizás el tipo de erorres más comunes cuando se arranca con Python. Por ejemplo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "while True print('Hola mundo')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La pequeña **flecha** señala el primer lugar donde se detectó un error. En este caso, señala a la función `print()`, ya que faltan dos puntos (`:`) antes de la misma."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Excepciones"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Incluso si la declaración o expresión es sintácticamente correcta, puede generar un error cuando se intenta ejecutarla. Los errores detectados durante la ejecución se llaman **excepciones**. Las excepciones surgen por diferentes tipos de errores al ejecutar código Python. Por ejemplo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "10 * 1/0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "1 + 'e'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "4 + potencia(3,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La lista de excepciones es muy extensa, Python cuenta con [excepciones integradas](https://docs.python.org/3/library/exceptions.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Manejando excepciones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "while True:\n",
    "    try:\n",
    "        x = int(input(\"Por favor ingrese un número: \"))\n",
    "        break\n",
    "    except ValueError:\n",
    "        print(\"Oops! No era válido. Intente nuevamente...\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La declaración `try` funciona de la siguiente manera:\n",
    "* Primero, se ejecuta el bloque `try` (el código entre las declaración `try` y `except`).\n",
    "* **Si no ocurre ninguna excepción**, el bloque `except` se saltea y termina la ejecución de la declaración `try`.\n",
    "* **Si ocurre una excepción** durante la ejecución del bloque `try`, el resto del bloque se saltea. Luego, **si su tipo coincide con la excepción nombrada** luego de la palabra reservada `except`, se ejecuta el bloque `except`, y la ejecución continúa luego de la declaración `try`.\n",
    "* **Si ocurre una excepción que no coincide con la excepción nombrada** en el `except`, esta se pasa a declaraciones `try` de más afuera; si no se encuentra nada que la maneje, es una excepción no manejada, y la ejecución se frena con un mensaje como los mostrados arriba."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las declaraciones `try`,`except` tienen un bloque `else` opcional, el cual, cuando está presente, debe seguir a los `except`. Es útil para aquel código que debe ejecutarse si el bloque `try` no genera una excepción. \n",
    "Veamos una aplicación del uso de exepciones. \n",
    "Primero forcemos los errores: *ZeroDivisionError* y *ValueError*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Dame dos números y yo los dividiré.\")\n",
    "print(\"Ingrese una q, para salir\")\n",
    "\n",
    "while True:\n",
    "    first_number = input(\"\\nPrimer número: \")\n",
    "    if first_number == 'q':\n",
    "        break\n",
    "    second_number = input(\"Segundo numero: \")\n",
    "    if second_number == 'q':\n",
    "        break    \n",
    "    answer = int(first_number) / int(second_number)\n",
    "    print(answer)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Si ahora contemplamos las excepciones y trabajamos sobre ellas:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Dame dos números y yo los dividiré.\")\n",
    "print(\"Ingrese una q, para salir\")\n",
    "\n",
    "while True:\n",
    "    first_number = input(\"\\nPrimer número: \")\n",
    "    if first_number == 'q':\n",
    "        break\n",
    "    second_number = input(\"Segundo numero: \")\n",
    "    try:\n",
    "        answer = int(first_number) / int(second_number)\n",
    "    except ZeroDivisionError:\n",
    "        print(\"No se puede dividir por cero.\")\n",
    "    except ValueError:\n",
    "        print(\"Valores ingresados incorrectos\")\n",
    "    else:\n",
    "        print(answer)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El uso de `else` es mejor que agregar código adicional en el try porque evita capturar accidentalmente una excepción que no fue generada por el código que está protegido por la declaración `try`, `except`.\n",
    "\n",
    "Cuando se usa con un ciclo, el `else` tiene más en común con el `else` de una declaración `try` que con el de un `if`: el `else` de un `try` se ejecuta cuando no se genera ninguna excepción, y el `else` de un ciclo se ejecuta cuando no hay ningún `break`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Definiendo acciones de limpieza\n",
    "\n",
    "La declaración `try` tiene otra cláusula opcional que intenta definir acciones de limpieza, por ejemplo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def dividir(x, y):\n",
    "    try:\n",
    "        result = x / y\n",
    "    except ZeroDivisionError:\n",
    "        print(\"¡división por cero!\")\n",
    "    else:\n",
    "        print(\"el resultado es\", result)\n",
    "    finally:\n",
    "        print(\"ejecutando la clausula finally\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Una cláusula `finally` **siempre es ejecutada antes de salir de la declaración** `try`, ya sea que una excepción haya ocurrido o no. Cuando ocurre una excepción en la cláusula `try` y no fue manejada por una cláusula `except` (o ocurrió en una cláusula `except` o `else`), es relanzada luego de que se ejecuta la cláusula `finally`. El `finally` es también ejecutado “a la salida” cuando cualquier otra cláusula de la declaración `try` es dejada via `break`, `continue` or `return`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dividir(2, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dividir(2, 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "divide(\"2\", \"1\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Como podés ver, la cláusula `finally` es **ejecutada siempre**. La excepción *TypeError* lanzada al dividir dos cadenas de texto no es manejado por la cláusula `except` y por lo tanto es relanzada luego de que se ejecuta la cláusula `finally`.\n",
    "\n",
    "> **Nota :** En aplicaciones reales, la cláusula `finally` es útil para liberar recursos externos (como archivos o conexiones de red), sin importar si el uso del recurso fue exitoso."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Configuracion de Python avanzada\n",
    "\n",
    "Hasta acá llegamos con los temas propiamente del lenguaje, con lo visto y practicado se está en condiciones de encarar proyectos más ambiciosos, en este sentido recomendamos fuertemente seguir los proyectos del siguiente libro:\n",
    "\n",
    "> Matthes, Eric. Python crash course: a hands-on, project-based introduction to programming. No Starch Press, 2015.\n",
    "\n",
    "Pero antes de encarar algún proyecto más amplio algunas recomendaciones respecto a la configuración. En la clase [100_instalacion.ipynb](100_instalacion.ipynb), mostramos como instalar **Python** usando [Miniconda](https://docs.conda.io/en/latest/miniconda.html). **En una instancia inicial es el mejor camino para evitar confusiones y adentrarse en aprender el lenguaje**. Pero si llegaste hasta aca siguiendo los notebooks en orden y respetando la dinamica propuesta por los autores, de seguro te estar preguntando como continuar o incluso como tener más control sobre nuestra version de Python y/o paquetes instalados. Por tal motivo a continuacion se presentan algunos aspectos más avanzados de la configuración.\n",
    "\n",
    "Para comenzar a trabajar con Python (como ya habiamos visto), nuestro sistema operativo deberá tener acceso a su intérprete. Para lo cual:\n",
    "\n",
    "* Descargarlo desde la página oficial [Python Software Foundation](https://www.python.org/) para el sistema operativo que se desee y ejecutarlo.\n",
    "\n",
    "#### Linux\n",
    "\n",
    "En el caso de los sistemas Linux, éstos están diseñados para la programación, por lo que Python ya está instalado en la mayoría de las distribuciones del dicho sistema operativo. Abriendo una ventana de terminal (en Ubuntu, presionar `ctrl+alt+T`) ingresar `python` y debería abrir el intérprete en consola, donde en las primeras líneas figura la versión del mismo (para salir `ctrl+D` o ingresar `exit()`). \n",
    "\n",
    "#### OS X\n",
    "\n",
    "Al igual que en los sistema Linux, Python ya está instalado en la mayoría de los sistemas OS X. Abrir una ventana de terminal e ingresar `python` y debería abrir el intérprete en consola, donde en las primeras líneas figura la versión del mismo (para salir `ctrl+D` o ingresar `exit()`). \n",
    "\n",
    "#### Windows\n",
    "\n",
    "Por lo general Windows no viene con Python, por lo que probablemente se deba descargar e instalar. Primero verificar si Python está instalado en el sistema. Abrir una ventana de terminal e ingresar `python`, si se abre el intérprete, Python está instalado en el sistema. Sin embargo, probablemente arroje un mensaje de error que indica que Python no es un comando reconocido.\n",
    "Por lo tanto, descargar desde la página oficial [Python Software Foundation](https://www.python.org/) el instalador para Windows e instalar, es importante asegurarse de marcar la opción **Agregar Python a PATH**, lo que facilitará la configuración.\n",
    "\n",
    "> Si no seleccionamos la opción de **Agregar Python a PATH**, el intérprete no podrá ser llamado desde cualquier instancia del terminal de Windows. En tal caso proceder como recomienda la siguiente [publicación](https://medium.com/@hektorprofe/tutorial-windows-10-agregar-el-python-de-anaconda-al-path-para-utilizarlo-en-la-cmd-y-powershell-72acf22901a), para agregar el intérprete a las variables de entorno del sistema operativo.\n",
    "\n",
    "Por otra parte en el libro [*Python crash course: a hands-on, project-based introduction to programming*](https://www.amazon.es/Python-Crash-Course-Hands-Project-Based/dp/1593276036) de Matthes Eric presenta una detallada descripción de cómo proceder para cada sistema operativo, el mismo se encuentra en el capítulo 1, página 5.\n",
    "\n",
    "O se pueden seguir los pasos recomendados en la siguiente guía de [*Real Python*](https://realpython.com/installing-python/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Administrador de paquetes\n",
    "\n",
    "O **package manager** en inglés, es un sistema de gestión de paquetes utilizado para instalar y administrar paquetes de software escritos en Python, en particular. Los administradores más conocidos son dos:\n",
    "\n",
    "* [PyPi (Python Package Index)](https://pypi.org/) (Incorporado por defecto)\n",
    "* [Conda](https://docs.conda.io/projects/conda/en/latest/index.html) (Incorporado si se instala alguna version de Anaconda)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Librerias\n",
    "\n",
    "![](https://www.researchgate.net/publication/332799309/figure/fig1/AS:753947908272130@1556766597837/Schematic-view-of-the-Python-scientific-software-ecosystem-Figure-taken-from-Jake.png)\n",
    "\n",
    "Las librerías son elementos programados en Python (incluso optimizados en más bajo nivel) que amplían el abanico de herramientas para desarrollar. Es buena práctica antes de comenzar un proyecto de desarrollo ver las librerías disponibles. En este sentido [PyPi](https://pypi.org/) tiene un buscador en la web, como en el caso de [conda](https://anaconda.org/anaconda/repo) o por consola:\n",
    "\n",
    "**Conda**\n",
    "``` bash\n",
    "conda search <package>\n",
    "```\n",
    "\n",
    "**Pip**\n",
    "``` bash\n",
    "pip search <package>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Entornos virtuales\n",
    "\n",
    "Python, como la mayoría de los otros lenguajes de programación modernos, tiene su propia forma única de descargar, almacenar y administrar paquetes (o módulos). Hay algunas ubicaciones diferentes donde estos paquetes se pueden instalar en su sistema. Por ejemplo, la mayoría de los paquetes del sistema se almacenan en un directorio secundario de la ruta almacenada en sys.prefix.\n",
    "\n",
    "Entonces, ¿por qué importan todos estos pequeños detalles?\n",
    "\n",
    "Es importante saber esto porque, de manera predeterminada, cada proyecto en su sistema utilizará estos mismos directorios para almacenar y recuperar paquetes del sitio (bibliotecas de terceros). A primera vista, esto puede no parecer un gran problema, pero consideremos el siguiente escenario en el que se tiene dos proyectos: ProjectA y ProjectB, los cuales dependen de la misma biblioteca, ProjectC. El problema se hace evidente cuando comenzamos a requerir diferentes versiones de ProjectC. Tal vez ProjectA necesita v1.0.0, mientras que ProjectB requiere la v2.0.0 más reciente, por ejemplo.Dado que los proyectos se almacenan solo por su nombre, no hay diferenciación entre versiones. Por lo tanto, ambos proyectos, el Proyecto A y el Proyecto B, tendrían que usar la misma versión, lo cual es inaceptable en muchos casos.\n",
    "\n",
    "Aquí es donde entran en juego los entornos virtuales.\n",
    "\n",
    "[Conda](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html) también es un administrador de entornos virtuales. **Los entornos virtuales son un ambiente creado con el objetivo de aislar recursos como librerías y entornos de ejecución del sistema principal o de otros entornos virtuales. Esto significa que en el mismo sistema, computadora, es posible tener instaladas múltiples versiones de una misma librería sin crear ningún tipo de conflicto.** También podemos exportar una lista de paquetes en un archivo con todas las dependencias de nuestro proyecto. \n",
    "\n",
    "Otro gestor de entornos muy usado es [virtualenv](https://virtualenv.pypa.io/en/stable/).\n",
    "\n",
    "Para más información una excelente nota sobre este tema en [Real Python](https://realpython.com/python-virtual-environments-a-primer/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### IDE\n",
    "\n",
    "Un entorno de desarrollo integrado o entorno de desarrollo interactivo, en inglés **Integrated Development Environment (IDE)**, es una aplicación informática que proporciona servicios integrales para facilitarle al desarrollador o programador el desarrollo de software. Hay un gran número de ellos, muy diversos, especificos, cubriendo la mayoría de las necesidades. Mencionamos algunos de los más utilizandos con Python:\n",
    "\n",
    "* [Geany](https://www.geany.org/).\n",
    "* [IDLE](https://docs.python.org/3/library/idle.html).\n",
    "* [Sublime Text](https://www.sublimetext.com/). \n",
    "* [Atom](https://atom.io/).\n",
    "* [Spyder](https://www.spyder-ide.org/).\n",
    "* [Jupyter Lab](https://jupyterlab.readthedocs.io/en/stable/index.html). "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Referencias usadas en el notebook\n",
    "\n",
    "* G. Van Rossum. El tutorial de Python. PyAr http://docs.python.org.ar/tutorial/\n",
    "* Matthes, Eric. *Python crash course: a hands-on, project-based introduction to programming*. No Starch Press, 2015."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Licencia\n",
    "\n",
    "<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\"><img alt=\"Licencia de Creative Commons\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-sa/4.0/88x31.png\" /></a><br />Este documento se destribuye con una <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\">licencia Atribución CompartirIgual 4.0 Internacional de Creative Commons</a>.\n",
    "\n",
    "© 2020. Infiniem Labs Acústica. infiniemlab.dsp@gmail.com (CC BY-SA 4.0))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}