<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Rafnix Guzman - Python Backend | AI Engineer | Odoo Developer]]></title><description><![CDATA[Python Backend con +15 años construyendo sistemas en producción: FastAPI, Django, Odoo ERP, PostgreSQL. Infraestructura propia con Docker y Kubernetes. AI Engineering con RAG pipelines y Agentic AI.]]></description><link>https://blog.rafnixg.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/60e4a9cde9aeb8301a6a6d39/6d75eee6-28b6-4956-83f0-5e8ef2be854d.png</url><title>Rafnix Guzman - Python Backend | AI Engineer | Odoo Developer</title><link>https://blog.rafnixg.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 16 Sep 2026 15:17:08 GMT</lastBuildDate><atom:link href="https://blog.rafnixg.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Nanobot: Arquitectura y Funcionamiento del Agente IA Ultra-ligero]]></title><description><![CDATA[Introducción
nanobot es una plataforma de asistente personal de IA diseñada para ejecutarse en tu propia infraestructura, ya sea una laptop, un servidor pequeño o un contenedor en la nube (VPS). A dif]]></description><link>https://blog.rafnixg.dev/nanobot-arquitectura-y-funcionamiento-del-agente-ia-ultra-ligero</link><guid isPermaLink="true">https://blog.rafnixg.dev/nanobot-arquitectura-y-funcionamiento-del-agente-ia-ultra-ligero</guid><category><![CDATA[calwbot]]></category><category><![CDATA[openclaw]]></category><category><![CDATA[nanobot]]></category><category><![CDATA[Python]]></category><category><![CDATA[agents]]></category><category><![CDATA[spanish]]></category><category><![CDATA[español]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Sun, 29 Mar 2026 14:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60e4a9cde9aeb8301a6a6d39/f00c0989-dda3-453b-9784-c245641db520.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introducción</h2>
<p><strong>nanobot</strong> es una plataforma de asistente personal de IA diseñada para ejecutarse en tu propia infraestructura, ya sea una laptop, un <strong>servidor pequeño</strong> o un <strong>contenedor</strong> en la nube (<strong>VPS)</strong>. A diferencia de <strong>otros frameworks</strong> que se centran únicamente en el <strong>"prompt engineering"</strong>, <em><strong>nanobot</strong></em> siguiendo la filosofía de <em><strong>OpenClaw</strong></em>, trata al agente de IA como un <strong>problema de infraestructura</strong>, construyendo un <strong>entorno de ejecución</strong> estructurado que gestiona sesiones, memoria, <strong>sandboxing</strong> de herramientas y enrutamiento de mensajes. Los <strong>LLM</strong> solo proveen inteligencia y razonamiento, <em><strong>nanobot</strong></em> prepara el terreno para que el agente pueda tomar control del sistema donde es instalado y ejecutar las herramientas.</p>
<p>Inspirado en <em><strong>OpenClaw</strong></em>, su propuesta radical es ofrecer funcionalidad completa de agente con un <strong>99% menos de líneas de código</strong>. Mientras que los frameworks tradicionales suelen ser <strong>"cajas negras"</strong> complejas, nanobot mantiene un núcleo de aproximadamente <strong>4,000 líneas</strong>, facilitando que desarrolladores e investigadores entiendan, modifiquen y extiendan el sistema.</p>
<h2>Como Funciona nanobot: Visión general</h2>
<p><strong>Nanobot</strong> no es solo una interfaz para un <strong>API</strong> de modelos de lenguaje o un <em><strong>chatbot</strong></em> conectado a un <strong>LLM</strong>, es un <strong>entorno de ejecución</strong> que sigue una arquitectura limpia <strong>orientado a eventos</strong>. El sistema actúa como un puente entre <strong>múltiples interfaces de entrada</strong> (Telegram, Discord, Slack, etc.) y un <strong>núcleo</strong> de inteligencia <strong>centralizado</strong>.</p>
<p>El corazón del sistema es el <strong>Message Bus</strong>, que actúa como plano de control, desacoplando la capa de comunicación de la lógica del <strong>agente</strong>. Esto permite que una única instancia del agente sea accesible simultáneamente a través de <strong>diversos canales</strong>, manteniendo la coherencia del estado de la conversación y el acceso a herramientas en <strong>hardware local</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/60e4a9cde9aeb8301a6a6d39/07025eaa-3509-469f-b805-b81f484ce554.png" alt="Imagen que describe la arquitectura de nanobot" style="display:block;margin:0 auto" />

<h2>Componentes principales</h2>
<h3>1. Canales</h3>
<p>Cada plataforma de mensajería utiliza un adaptador dedicado que implementa la clase <code>BaseChannel</code>. Estos adaptadores normalizan la entrada y salida de datos:</p>
<ul>
<li><p><strong>Autenticación y Conexión:</strong> Utiliza diversos métodos según la plataforma, como <strong>polling</strong> para Telegram, <strong>WebSockets</strong> para Discord y Feishu, o un <strong>bridge</strong> de Node.js para WhatsApp.</p>
</li>
<li><p><strong>Normalización:</strong> Los canales extraen texto y manejan archivos multimedia (imágenes, voz) para convertirlos en un objeto estándar de entrada <code>InboundMessage</code>.</p>
</li>
<li><p><strong>Control de Acceso:</strong> Implementan listas de permitidos <code>allowFrom</code> para restringir quién puede interactuar con el bot a nivel de plataforma.</p>
</li>
</ul>
<h3>2. Interfaz de Control</h3>
<p><strong>Nanobot</strong> ofrece múltiples formas de interacción:</p>
<ul>
<li><p><strong>CLI (Línea de Comandos):</strong> Es la interfaz principal para la administración. Permite iniciar el asistente en modo interactivo <code>nanobot agent</code>, gestionar configuraciones <code>onboard</code> y autenticar canales <code>channels login</code>.</p>
</li>
<li><p><strong>Modo Gateway:</strong> Permite que el sistema funcione en segundo plano conectando todos los canales de chat configurados simultáneamente.</p>
</li>
</ul>
<h3>3. Gateway</h3>
<p>El Gateway es el <strong>punto central</strong> que coordina el estado del sistema. Sus responsabilidades incluyen:</p>
<ul>
<li><p><strong>Gestión de Conexiones:</strong> Inicia y mantiene los hilos o tareas asíncronas para cada <strong>canal</strong> de <strong>chat activo</strong>.</p>
</li>
<li><p><strong>Servicios Proactivos:</strong> Aloja el servicio de <strong>Cron</strong> para tareas programadas y el sistema de <strong>Heartbeat</strong>, que despierta al agente cada 30 minutos para ejecutar tareas autónomas definidas en el archivo <code>HEARTBEAT.md</code>.</p>
</li>
</ul>
<h3>4. Entorno de Ejecución del Agente (Agent Runtime)</h3>
<p>Representado por la clase <code>AgentLoop</code>, es donde ocurre el procesamiento de la IA. El <strong>runtime</strong> sigue un ciclo de cuatro pasos:</p>
<ol>
<li><p><strong>Resolución de Sesión:</strong> Identifica el historial de conversación específico para cada usuario o hilo de chat.</p>
</li>
<li><p><strong>Construcción de Contexto:</strong> Ensambla el prompt del sistema combinando la identidad del agente, las habilidades <code>skills</code>, la memoria persistente y el historial de la sesión.</p>
</li>
<li><p><strong>Invocación del Modelo:</strong> Interactúa con proveedores <em><strong>(OpenAI, Anthropic, Ollama, etc.)</strong></em> mediante una capa de abstracción que normaliza las <strong>APIs</strong>.</p>
</li>
<li><p><strong>Ejecución de Herramientas:</strong> Intercepta las solicitudes de llamadas a <strong>herramientas del LLM</strong> para ejecutar comandos de sistema, búsquedas web o manipulación de archivos.</p>
</li>
</ol>
<h2>Iteración y Coordinación</h2>
<p>La arquitectura de <strong>nanobot</strong> permite una coordinación fluida entre componentes:</p>
<ul>
<li><p><strong>Message Bus:</strong> Utiliza colas asíncronas para mensajes entrantes y salientes, asegurando que el sistema sea responsivo incluso durante procesos intensivos del LLM.</p>
</li>
<li><p><strong>Sistema de Habilidades (Skills):</strong> Permite inyectar capacidades específicas (como gestión de GitHub o clima) mediante archivos <strong>Markdown</strong> en la capeta <code>~/.nanobot/skills/</code>, que el agente carga dinámicamente según la necesidad.</p>
</li>
<li><p><strong>Herramientas Externas (MCP):</strong> Soporta el <strong>Model Context Protocol</strong>, lo que permite conectar servidores de herramientas externas y usarlos como si fueran capacidades nativas.</p>
</li>
</ul>
<h2>Flujo de mensaje de extremo a extremo</h2>
<p>El flujo de un mensaje desde que el usuario lo envía hasta que recibe la respuesta sigue estos pasos técnicos:</p>
<ul>
<li><p><strong>Ingesta:</strong> El <code>ChannelLayer</code> recibe el input y publica un <code>InboundMessage</code> en el <code>bus</code>. Un ejemplo podría ser recibir un mensaje de <strong>Telegram</strong>.</p>
</li>
<li><p><strong>Carga de Sesión:</strong> El <code>AgentLoop</code> extrae el mensaje y recupera el historial desde el <code>SessionManager</code>, ubicado en <code>~/.nanobot/sessions/</code> .</p>
</li>
<li><p><strong>Ensamblaje:</strong> El <code>ContextBuilder</code> construye el prompt del sistema incluyendo contexto, la memoria usando como base el <code>MEMORY.md</code> y herramientas.</p>
</li>
<li><p><strong>Bucle de Iteración:</strong></p>
<ul>
<li><p>Llama al LLM a través de un <em><strong>Provider</strong></em> (OpenRouter, Anthropic, OpenAI, etc.).</p>
</li>
<li><p>Si el modelo solicita <strong>herramientas</strong> (<em>shell, filesystem, web, etc.</em>), estas se ejecutan y los resultados se reinyecta en el contexto.</p>
</li>
</ul>
</li>
<li><p><strong>Finalización:</strong> Una vez generada la respuesta de texto, se publica un <code>OutboundMessage</code> en el bus y el canal lo entrega al usuario.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60e4a9cde9aeb8301a6a6d39/5214a339-e8c9-4da5-afd7-389ab0bd363d.svg" alt="Diagrama de secuencia" style="display:block;margin:0 auto" />

<h3>Gestión de datos y estado</h3>
<p><strong>Nanobot</strong> almacena su estado de forma sencilla y transparente <code>~/.nanobot</code>:</p>
<ul>
<li><p><strong>Configuración:</strong> Un único archivo <code>~/.nanobot/config.json</code> centraliza las claves de <strong>API</strong> y ajustes de canales.</p>
</li>
<li><p><strong>Memoria a largo plazo:</strong> Utiliza un archivo <code>MEMORY.md</code> en formato <strong>Markdown</strong> dentro del <em>workspace</em>. Esto permite que la memoria sea <strong>legible para humanos</strong> y <strong>fácil de editar</strong> manualmente.</p>
</li>
<li><p><strong>Historial de Sesión:</strong> Almacenado en archivos <strong>JSON</strong> individuales por usuario, permitiendo persistencia total entre reinicios.</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/60e4a9cde9aeb8301a6a6d39/371b4d75-b576-4652-9154-58f566628bd9.svg" alt="Diagrama de estado" style="display:block;margin:0 auto" />

<h2>Arquitectura de Seguridad</h2>
<p>La seguridad se implementa en múltiples capas:</p>
<ul>
<li><p><strong>Aislamiento del Workspace:</strong> Si se activa <code>restrictToWorkspace</code>, todas las operaciones de archivos y comandos de shell se confinan estrictamente al directorio <code>~/.nanobot/workspace/,</code> bloqueando ataques de salto de directorio <em><strong>(path traversal)</strong></em>.</p>
</li>
<li><p><strong>Control de Acceso:</strong> Las listas de permitidos <code>allowFrom</code> aseguran que solo usuarios autorizados puedan interactuar con el agente.</p>
</li>
<li><p><strong>Gestión de Claves:</strong> Las <strong>API keys</strong> se cargan como <strong>variables de entorno</strong> por solicitud y nunca se registran en los <strong>logs</strong> del sistema. Además las claves se almacenan con <strong>permisos restringidos <em>(600)</em></strong>.</p>
</li>
</ul>
<h2>Arquitecturas de despliegue</h2>
<p><strong>Nanobot</strong> soporta tres patrones principales:</p>
<ol>
<li><p><strong>Local/CLI:</strong> Ejecución directa mediante el <strong>binario</strong> para <strong>pruebas</strong> rápidas y <strong>desarrollo de herramientas</strong> simples o <strong>scripts</strong>.</p>
</li>
<li><p><strong>Servicio de Linux (Systemd):</strong> Permite que el <strong>gateway</strong> se ejecute permanentemente en <em><strong>segundo plano</strong></em>, reiniciándose automáticamente tras fallos o reinicios del servidor y <em><strong>manteniendo el contexto</strong></em> por sesión.</p>
</li>
<li><p><strong>Contenedor de Docker:</strong> Ideal para despliegues <strong>aislados</strong>, persistiendo la configuración y el <strong>workspace</strong> mediante <strong>volúmenes montados</strong>.</p>
</li>
</ol>
<h2>Conclusión</h2>
<p><em><strong>Nanobot</strong></em> demuestra que es posible construir una <strong>infraestructura de IA</strong> potente bajo una <strong>filosofía de simplicidad radical</strong> que hacen que su código no solo sea <strong>eficiente</strong> sino <strong>legible</strong>. Al separar las interfaces del <strong>runtime</strong> y mantener una base de código plana y <strong>modular</strong>, ofrece un sistema que es a la vez una herramienta de productividad diaria y una plataforma ideal para la investigación con <strong>agentes de IA</strong>.</p>
<p>Es, en esencia, la arquitectura mínima necesaria para un asistente que no solo responde, sino que actúa. No tiene el nivel de complejidad y funcionalidades que posee <em><strong>OpenClaw</strong></em> pero tampoco lo necesita, cumple con los objetivos que buscas en algo más que un agente, si <em><strong>OpenClaw</strong></em> se define como un sistema operativo para los Agentes, <em><strong>nanobot</strong></em> entonces sería un mini sistema operativo para agentes.</p>
<h2>Ejemplo de implementación de la arquitectura</h2>
<p><strong>femtobot</strong> es un agente creado para demostrar una pequeña implementación de la arquitectura bajo la cual <em><strong>nanobot</strong></em> funciona, es una buena base de <strong>inspiración y estudio</strong> para este tipo de sistema de agentes.</p>
<p><a class="embed-card" href="https://github.com/rafnixg/femtobot">https://github.com/rafnixg/femtobot</a></p>

<h2>Referencias</h2>
<p><a href="https://github.com/HKUDS/nanobot">Github oficial nanobot</a></p>
<p><a href="https://www.mintlify.com/HKUDS/nanobot/introduction">Documentación técnica nanobot</a></p>
<p><a href="https://rafnixg.github.io/femtobot/femtobot.html">Documentación femtobot</a></p>
]]></content:encoded></item><item><title><![CDATA[⚙️ Como automatizar tu librería en PyPI con GitHub Actions]]></title><description><![CDATA[Continuando con un post anterior donde publicamos nuestra librería a PyPI, vamos a ir un paso más allá en el proceso de construcción y despliegue (o, mejor dicho, build y release). En este tutorial, crearemos nuestro propio workflow en GitHub Actions...]]></description><link>https://blog.rafnixg.dev/como-automatizar-tu-libreria-en-pypi-con-github-actions</link><guid isPermaLink="true">https://blog.rafnixg.dev/como-automatizar-tu-libreria-en-pypi-con-github-actions</guid><category><![CDATA[Python]]></category><category><![CDATA[pypi]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[cicd]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Fri, 11 Apr 2025 14:00:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wX2L8L-fGeA/upload/51df522c518c36bb2f60432d04342b30.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuando con un post anterior donde publicamos nuestra librería a <strong>PyPI,</strong> vamos a ir un paso más allá en el proceso de construcción y despliegue (o, mejor dicho, <strong>build</strong> y <strong>release).</strong> En este tutorial, crearemos nuestro propio <strong>workflow</strong> en <strong>GitHub Actions</strong>, aprovechando que nuestro repositorio ya está en <strong>GitHub,</strong> para automatizar este proceso y hacerlo más eficiente y menos propenso a errores.</p>
<p>Al final de este tutorial tendremos configurado un <strong>workflow</strong> que construye y publica en <strong>PyPI</strong> de forma automática con cada nueva <strong>release</strong> que se cree en el repositorio de <strong>GitHub.</strong></p>
<p>👉 Si aún no publicaste tu librería en <strong>PyPI</strong>, te recomiendo comenzar por este tutorial previo:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.rafnixg.dev/como-publicar-tu-propia-libreria-de-python-guia-paso-a-paso">https://blog.rafnixg.dev/como-publicar-tu-propia-libreria-de-python-guia-paso-a-paso</a></div>
<p> </p>
<h2 id="heading-que-es-github-actions">⚙️ ¿Qué es GitHub Actions?</h2>
<p><strong>GitHub Actions</strong> es una plataforma de <strong>CI/CD (Integración y Entrega Continua)</strong> integrada directamente en <strong>GitHub</strong>. Permite automatizar tareas dentro del ciclo de vida de tu proyecto, como ejecutar tests, construir paquetes, y desplegar código, todo sin salir de tu repositorio.</p>
<p>La magia está en los <strong>workflows</strong>, que son conjuntos de instrucciones definidas en archivos <strong>YAML</strong>. Estos <strong>workflows</strong> se ejecutan en respuesta a eventos específicos, como hacer un push, crear un tag, abrir un pull request o crear un nuevo release.</p>
<p>En el caso de una librería de Python, esto nos permite automatizar pasos como:</p>
<ul>
<li><p>Construir los paquetes (<code>sdist</code> y <code>wheel</code>)</p>
</li>
<li><p>Publicar automáticamente en <strong>PyPI</strong> o <strong>TestPyPI</strong> cuando subimos una nueva versión</p>
</li>
</ul>
<p>Con unas pocas líneas de configuración, podemos lograr que todo esto suceda de forma automática cada vez que haces un <strong>release</strong>, reduciendo errores y ganando tiempo.</p>
<h2 id="heading-automatizando-la-publicacion-en-pypi-con-github-actions">📦 Automatizando la publicación en PyPI con GitHub Actions</h2>
<h3 id="heading-requisitos-previos">✅ Requisitos previos</h3>
<p>Antes de iniciar, asegúrate de tener:</p>
<ul>
<li><p>Un repositorio de <strong>GitHub</strong> con tu librería</p>
</li>
<li><p>Una cuenta de <a target="_blank" href="https://pypi.org/"><strong>PyPI</strong></a></p>
</li>
<li><p>Un <a target="_blank" href="https://blog.rafnixg.dev/como-publicar-tu-propia-libreria-de-python-guia-paso-a-paso#heading-creando-api-key"><strong>API Token</strong></a> generado de tu cuenta de <strong>PyPI</strong></p>
</li>
</ul>
<p>👉 Si ya seguiste el tutorial anterior, deberías tener todo esto listo. Si no, te recomiendo revisarlo antes de seguir.</p>
<h3 id="heading-agregar-tu-token-de-pypi-como-secret-en-github">🔐 Agregar tu token de PyPI como secret en GitHub</h3>
<p>Debemos configurar en nuestro repositorio un nuevo <strong>secret</strong> para usarlo en los <strong>workflows</strong>, para esto solo debemos seguir los siguientes pasos:</p>
<ol>
<li><p>Ir a tu repositorio en <strong>GitHub</strong>.</p>
</li>
<li><p>Hacer clic en <strong>Settings</strong>.</p>
</li>
<li><p>En el menú lateral, clic en <strong>Secrets and variables → Actions</strong>.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744062734086/d786bef0-ce2d-4134-af17-168dc5463672.png" alt class="image--center mx-auto" /></p>
<ol start="4">
<li><p>Clic en <strong>New repository secret</strong>.</p>
</li>
<li><p>El nombre será <code>PYPI_API_TOKEN</code> y en el valor pegá tu <strong>API key</strong> de <strong>PyPI</strong>.</p>
</li>
<li><p>Clic en <strong>Add secret.</strong></p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744062932644/10d2376a-8a74-406a-be2c-c6ce23db20a5.png" alt class="image--center mx-auto" /></p>
<p>Esto es lo que usa <strong>GitHub Actions</strong> para autenticar y publicar la librería.</p>
<h3 id="heading-estructura-de-archivos">📁 Estructura de archivos</h3>
<p>Ya con todo esto listo podemos empezar, lo primero que debemos saber es que para que nuestra <strong>Github Actions</strong> funcione los <strong>workflows</strong> deben estar en una carpeta llama <code>.github/workflows</code> en la raíz de nuestro repositorio, dentro de esta carpeta ira nuestro archivo de <strong>workflow</strong> llamado <code>python-publish.yml</code>.</p>
<p>Podemos crear todo usando los siguientes comandos:</p>
<pre><code class="lang-bash">$ mkdir -p .github/workflows
$ touch .github/workflows/python-publish.yml
</code></pre>
<p>La estructura de archivos quedaría similar a esta:</p>
<pre><code class="lang-plaintext">rafnixg-lib/
│
├── .github/
│   └── workflows/
│       └── python-publish.yml
├── src/
│   └── rafnixg/
│       ├── __init__.py
│       ├── __main__.py
│       └── rafnixg.py
│
├── LICENSE
├── README.md
└── pyproject.toml
</code></pre>
<h2 id="heading-configurando-el-workflow">🚀 Configurando el workflow</h2>
<p>Vamos a iniciar creando el contenido de nuestro archivo de <strong>workflow</strong> <code>python-publish.yml</code>.</p>
<h3 id="heading-activando-el-workflow-al-publicar-un-release">🎯Activando el workflow al publicar un release</h3>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Publicar</span> <span class="hljs-string">Paquete</span> <span class="hljs-string">a</span> <span class="hljs-string">PyPI</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">release:</span>
    <span class="hljs-attr">types:</span> [<span class="hljs-string">published</span>]
</code></pre>
<p>Esto indica el nombre que tendrá nuestro <strong>workflow</strong> y también define que solo se va a ejecutar cuando las <code>release</code> sean <code>published</code> con esto limitamos que solo estas acciones sean las que disparen nuestro <strong>workflow.</strong></p>
<h3 id="heading-definir-permisos-minimos-necesarios">🛡️Definir permisos mínimos necesarios</h3>
<pre><code class="lang-yaml"><span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
</code></pre>
<p>Acá le decimos a GitHub Actions que este workflow solo necesita <strong>leer el contenido del repositorio</strong>. Es una buena práctica limitar los permisos al mínimo necesario.</p>
<h3 id="heading-crear-el-job-y-configurar-el-entorno">🛠️Crear el job y configurar el entorno</h3>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
</code></pre>
<p>Creamos un <strong>job</strong> llamado <code>deploy</code>, que se ejecutará en un entorno virtual Ubuntu. Este <strong>job</strong> va a encargarse de construir y publicar nuestro paquete.</p>
<h3 id="heading-agregar-los-pasos-del-workflow">📋Agregar los pasos del workflow</h3>
<p>Los <strong>steps</strong> son partes del proceso que irán ejecutando de forma secuencia y serán lo que ejecutarán los pasos para publicar nuestra librería en <strong>PyPI</strong> luego de ser construida.</p>
<p>En los <strong>steps</strong> se puede hacer uso de otros <strong>actions</strong> creados por otros usuarios como si de librerías se tratase, solo debemos indicarlo con <code>uses: actions/nombre-del-actions@version</code> y tambien podemos usar comando sobre la máquina virtual donde se está ejecutando la <strong>actions</strong> con el comando <code>run: comando bash</code></p>
<pre><code class="lang-yaml"><span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Clonando</span> <span class="hljs-string">repositorio</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configurando</span> <span class="hljs-string">Python</span> <span class="hljs-number">3</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-python@v3</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">python-version:</span> <span class="hljs-string">'3.x'</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Instalando</span> <span class="hljs-string">dependencias</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|
        python -m pip install --upgrade pip
        pip install build
</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Construir</span> <span class="hljs-string">Paquete</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">python</span> <span class="hljs-string">-m</span> <span class="hljs-string">build</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Publicar</span> <span class="hljs-string">Paquete</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">pypa/gh-action-pypi-publish@release/v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">user:</span> <span class="hljs-string">__token__</span>
        <span class="hljs-attr">password:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.PYPI_API_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<h4 id="heading-clonando-el-repositorio">📂 Clonando el repositorio</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Clonando</span> <span class="hljs-string">repositorio</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
</code></pre>
<p>Usamos la acción oficial para <strong>clonar el código del repositorio</strong>, paso necesario para poder construir el paquete.</p>
<h4 id="heading-configurar-el-entorno-de-python">🐍 Configurar el entorno de Python</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configurando</span> <span class="hljs-string">Python</span> <span class="hljs-number">3</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-python@v3</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">python-version:</span> <span class="hljs-string">'3.x'</span>
</code></pre>
<p>Le decimos a GitHub Actions que configure un entorno de Python (versión 3.x). Esto es clave para poder instalar dependencias y ejecutar los comandos de build.</p>
<h4 id="heading-instalando-las-dependencias-necesarias">📥 Instalando las dependencias necesarias</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Instalando</span> <span class="hljs-string">dependencias</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">|
    python -m pip install --upgrade pip
    pip install build</span>
</code></pre>
<p>Actualizamos <code>pip</code> y luego instalamos el módulo <code>build</code>, que nos permite crear los archivos <code>.tar.gz</code> y <code>.whl</code> que necesita PyPI.</p>
<h4 id="heading-construir-el-paquete">🏗️Construir el paquete</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Construir</span> <span class="hljs-string">Paquete</span>
  <span class="hljs-attr">run:</span> <span class="hljs-string">python</span> <span class="hljs-string">-m</span> <span class="hljs-string">build</span>
</code></pre>
<p>Este paso ejecuta <code>python -m build</code>, que genera el paquete listo para ser publicado en la carpeta <code>dist/</code>.</p>
<h4 id="heading-publicar-el-paquete-en-pypi">📤Publicar el paquete en PyPI</h4>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Publicar</span> <span class="hljs-string">Paquete</span>
  <span class="hljs-attr">uses:</span> <span class="hljs-string">pypa/gh-action-pypi-publish@release/v1</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">user:</span> <span class="hljs-string">__token__</span>
    <span class="hljs-attr">password:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.PYPI_API_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<p>Finalmente, usamos la acción oficial para subir el paquete a <a target="_blank" href="https://pypi.org">PyPI</a>. Aquí usamos el API Key que se guarda como <strong>Secret</strong> en el repositorio de GitHub (<code>PYPI_API_TOKEN</code>), para evitar exponer credenciales.</p>
<h2 id="heading-archivo-completo-del-workflow-python-publishyml">📄 <strong>Archivo completo del workflow</strong> (<code>python-publish.yml</code>)</h2>
<p>El archivo <code>python-publish.yml</code> finalmente queda de la siguiente manera:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Publicar</span> <span class="hljs-string">Paquete</span> <span class="hljs-string">a</span> <span class="hljs-string">PyPI</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">release:</span>
    <span class="hljs-attr">types:</span> [<span class="hljs-string">published</span>]
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Clonando</span> <span class="hljs-string">repositorio</span>
          <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>

        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configurando</span> <span class="hljs-string">Python</span> <span class="hljs-number">3</span>
          <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-python@v3</span>
          <span class="hljs-attr">with:</span>
            <span class="hljs-attr">python-version:</span> <span class="hljs-string">'3.x'</span>

        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Instalando</span> <span class="hljs-string">dependencias</span>
          <span class="hljs-attr">run:</span> <span class="hljs-string">|
            python -m pip install --upgrade pip
            pip install build
</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Construir</span> <span class="hljs-string">Paquete</span>
          <span class="hljs-attr">run:</span> <span class="hljs-string">python</span> <span class="hljs-string">-m</span> <span class="hljs-string">build</span>

        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Publicar</span> <span class="hljs-string">Paquete</span>
          <span class="hljs-attr">uses:</span> <span class="hljs-string">pypa/gh-action-pypi-publish@release/v1</span>
          <span class="hljs-attr">with:</span>
            <span class="hljs-attr">user:</span> <span class="hljs-string">__token__</span>
            <span class="hljs-attr">password:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.PYPI_API_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<h2 id="heading-subiendo-los-cambios-al-repositorio">💾 Subiendo los cambios al repositorio</h2>
<p>Ya con nuestro archivo creado, solo nos resta subir un <strong>commit</strong> con los cambios que tenemos:</p>
<pre><code class="lang-bash">$ git add .github/workflows/python-publish.yml
$ git commit -m <span class="hljs-string">"Add GitHub Actions workflow for PyPI release"</span>
$ git push origin
</code></pre>
<p>Creamos un <strong>tag</strong> y lo subimos:</p>
<pre><code class="lang-bash">$ git tag v1.0.1
$ git push origin --tags
</code></pre>
<p>Revisamos nuestro repositorio de <strong>GitHub</strong> y nos aseguramos de que se subió todo correctamente, para seguir con la creación de una nueva <strong>release</strong>.</p>
<h3 id="heading-crear-una-nueva-release-en-github">🏷️ Crear una nueva release en GitHub</h3>
<p>En nuestro repositorio hacemos clic en <strong>Releases.</strong> para ingresar a la página de todas las <strong>releases</strong> que vamos a haciendo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744064075909/cb1a102c-99cf-48f6-8a2e-75921cb6a725.png" alt class="image--center mx-auto" /></p>
<p>En esta página hacemos clic en <strong>“draf a new release“</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744064165133/3071befb-dd18-4bd1-a46c-fb9bf8508299.png" alt class="image--center mx-auto" /></p>
<p>Esto nos abre el formulario para crear nuevas releases, acá debemos seleccionar el tag correspondiente con la release en <strong>“Choose a tag“</strong> y hacer clic en <strong>“Generate release notes“,</strong> esto genera una descripción usando los <strong>commits</strong> y los <strong>Pull Request.</strong></p>
<p>Por último, revisa la descripción ajusta si lo necesitas y dale clic a <strong>“Publish release“.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744064263542/5fbdee1e-64b2-405d-987a-4e96c7f2df79.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-verificar-el-resultado-de-la-publicacion">✅ Verificar el resultado de la publicación</h2>
<p>Cada vez que crees una nueva <strong>release</strong>, se publicará una nueva versión de tu paquete en <strong>PyPI</strong>. En la tab <strong>“Actions“</strong> de nuestro repositorio vamos a ver cómo se ejecuta el <strong>workflow</strong> que lo publica.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744064448660/629e622d-d515-42e0-92ed-64b5f214d844.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">🧠 <strong>Conclusión</strong></h2>
<p>Automatizar la publicación con <strong>GitHub Actions</strong> no solo te ahorra tiempo, también reduce errores y hace que todo el proceso sea mucho más limpio y profesional. Una vez configurado, solo tienes que enfocarte en mejorar tu librería y dejar que la publicación se maneje sola ✨</p>
<h2 id="heading-referencias">🔍Referencias</h2>
<h4 id="heading-documentacion-oficial-github-actions">🔗 Documentación oficial GitHub Actions</h4>
<ul>
<li><a target="_blank" href="https://docs.github.com/en/actions/about-github-actions/understanding-github-actions">https://docs.github.com/en/actions/about-github-actions/understanding-github-actions</a></li>
</ul>
<h4 id="heading-documentacion-oficial-pypi-usando-github-actions">🔗 Documentación oficial PyPI usando GitHub Actions</h4>
<ul>
<li><a target="_blank" href="https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows">https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows</a></li>
</ul>
<h4 id="heading-documentacion-del-github-actions-pypi-publish">🔗 Documentacion del GitHub Actions PyPI Publish</h4>
<ul>
<li><a target="_blank" href="https://github.com/pypa/gh-action-pypi-publish">https://github.com/pypa/gh-action-pypi-publish</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[🏗️ Cómo publicar tu propia librería de Python: Guía paso a paso]]></title><description><![CDATA[El objetivo de este tutorial es guiarte paso a paso en el proceso de creación y publicación de tu propia librería en Python. Aunque Python ofrece una biblioteca estándar muy completa, aprovechar las contribuciones de la comunidad en PyPI te permite e...]]></description><link>https://blog.rafnixg.dev/como-publicar-tu-propia-libreria-de-python-guia-paso-a-paso</link><guid isPermaLink="true">https://blog.rafnixg.dev/como-publicar-tu-propia-libreria-de-python-guia-paso-a-paso</guid><category><![CDATA[Python]]></category><category><![CDATA[pypi]]></category><category><![CDATA[package]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Fri, 04 Apr 2025 20:43:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/vb-3qEe3rg8/upload/63664bfffb704aaec45448ff9120141f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<p>El objetivo de este tutorial es guiarte paso a paso en el proceso de creación y publicación de tu propia librería en Python. Aunque Python ofrece una biblioteca estándar muy completa, aprovechar las contribuciones de la comunidad en <a target="_blank" href="https://pypi.org/">PyPI</a> te permite extender sus capacidades y crear soluciones personalizadas que se adapten a tus necesidades.</p>
<p>La motivación detrás de este proyecto es doble: por un lado, adquirir un conocimiento profundo sobre el proceso de preparación, versionado, construcción y despliegue de paquetes; y por el otro, consolidar un repositorio centralizado de herramientas que funcione como una tarjeta de presentación profesional en el mundo del desarrollo.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/rafnixg/rafnixg-lib">https://github.com/rafnixg/rafnixg-lib</a></div>
<p> </p>
<h2 id="heading-introduccion-y-primeros-pasos">🧭 Introducción y primeros pasos</h2>
<p>El primer paso es comprender el ecosistema de paquetes en Python, especialmente el rol fundamental que juega <a target="_blank" href="https://pypi.org/">PyPI</a> (Python Packaging Index). Este es el repositorio oficial de paquetes de Python, y alberga una vasta colección de librerías, desde implementaciones simples hasta complejas soluciones en áreas como ciencia de datos, inteligencia artificial y desarrollo web.</p>
<p>Al entender cómo se organizan y distribuyen los paquetes en <a target="_blank" href="https://pypi.org/">PyPI</a>, puedes orientar el desarrollo de tu librería para que cumpla con los estándares que facilitan su instalación y uso por parte de otros desarrolladores. Además, al prepararla para su publicación, te adentras en prácticas modernas como el versionado semántico y la automatización del despliegue.</p>
<p>Nuestro inicio en el mundo de las librerías lo vamos a tener en la próxima sección donde ya iniciaremos el código fuente que usaremos como base para todo el proceso de tener nuestra propia librería en <a target="_blank" href="https://pypi.org/">PyPI</a>.</p>
<p><a target="_blank" href="https://pypi.org/project/rafnixg/">https://pypi.org/project/rafnixg/</a></p>
<h2 id="heading-crear-la-base-de-tu-libreria-en-python">🏗️ Crear la base de tu librería en Python</h2>
<p>En esta sección crearemos el código base que usaremos para subir a PyPI, tú puedes usar este código como ejemplo o ser libre de usar el código de tu preferencia, y saltar a la siguiente sección.</p>
<p>Si te quedaste acá el paquete que vamos a crear se llama <code>rafnixg</code> y muestra por consola tus datos personales y por otro lado podrá ser usado en tu propio código para descargar post de tu blog de <strong><em>HashNode</em></strong> usando <strong><em>GraphQL</em></strong>. Este es básicamente mi caso de uso de ejemplo, pero tu librería puede tener las funciones que tu consideres necesarias.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743543201582/f92974d6-c2cd-4bd3-b85c-4654144a89c7.png" alt class="image--center mx-auto" /></p>
<p>Para lograr obtener este diseño de card vamos a hacer uso de la librería <code>rich</code> que nos ayuda a crear diseños de tablas para la terminal de forma fácil, los invito a revisar el potencial de <code>rich</code>, puede agregar iconos, gestionar paleta de colores, Markdown.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://pypi.org/project/rich/">https://pypi.org/project/rich/</a></div>
<p> </p>
<h3 id="heading-preparacion-del-entorno-de-desarrollo">🧪Preparación del entorno de desarrollo</h3>
<p>Para este caso hare uso de <strong>VSCode</strong> pero puedes usar el editor que prefieras, acá lo importante es crear un entorno virtual de Python para aislar las dependencias y no tener problemas en el futuro.</p>
<pre><code class="lang-powershell"><span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> venv env
<span class="hljs-variable">$</span> source env/bin/activate  <span class="hljs-comment"># Para Linux</span>
<span class="hljs-variable">$</span> env\Scripts\activate    <span class="hljs-comment"># Para Windows</span>
(env) <span class="hljs-variable">$</span> pip install rich
</code></pre>
<p>Lo segundo será crear un archivo <code>.gitignore</code> que nos ayudará a indicar que no queremos que se suba a nuestro repositorio, podemos hacer uso de la siguiente web para generar uno con la configuración para Python.</p>
<p><a target="_blank" href="https://www.toptal.com/developers/gitignore">Create Useful .gitignore Files For Your Project</a></p>
<pre><code class="lang-powershell"><span class="hljs-comment"># Created by https://www.toptal.com/developers/gitignore/api/python</span>
<span class="hljs-comment"># Edit at https://www.toptal.com/developers/gitignore?templates=python</span>

<span class="hljs-comment">### Python ###</span>
<span class="hljs-comment"># Byte-compiled / optimized / DLL files</span>
__pycache__/
*.py[<span class="hljs-type">cod</span>]
*<span class="hljs-variable">$py</span>.class

env
.env
/venv
venv

<span class="hljs-comment"># End of https://www.toptal.com/developers/gitignore/api/python</span>
</code></pre>
<blockquote>
<p>Debemos recordar que es importante evitar subir archivos con contenido sensibles como API Keys, Claves o algún tipo de información que permita acceso no autorizado.</p>
</blockquote>
<p>Luego de esto inicializamos nuestro repositorio de <code>git</code> y creamos nuestra estructura de archivos.</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> git init
</code></pre>
<h3 id="heading-estructura-del-proyecto">📁 Estructura del proyecto</h3>
<p>Toda librería de Python inicia dentro de una carpeta, así que para esto cree el directorio <code>rafnixg-lib</code> y dentro creo la siguiente estructura de archivos:</p>
<pre><code class="lang-plaintext">rafnixg-lib/
│
├── src/
│   └── rafnixg/
│       ├── __init__.py
│       ├── __main__.py
│       └── rafnixg.py
│
├── LICENSE
├── README.md
└── pyproject.toml
</code></pre>
<p>Todo el código fuente se encuentra de <code>src/</code> esto no es obligatorio, pero es una buena práctica. Si estas usando tu propio código, dentro de <code>src/</code> es donde debería ir para mantener la mejor estructura.</p>
<p>En esta sección nos enfocaremos en los archivos de Python y en las siguientes secciones veremos estos archivos especiales <code>LICENSE, README.md, pyproject.toml</code>.</p>
<h3 id="heading-crear-el-archivo-principal-srcrafnixgrafnixgpy">🧾 Crear el archivo principal src/rafnixg/rafnixg.py</h3>
<pre><code class="lang-python"><span class="hljs-string">"""src/rafnixg/rafnixg.py
RafnixG - Personal Card
"""</span>

<span class="hljs-keyword">from</span> rich.console <span class="hljs-keyword">import</span> Console
<span class="hljs-keyword">from</span> rich.table <span class="hljs-keyword">import</span> Table


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RafnixG</span>:</span>
    <span class="hljs-string">"""RafnixG - Personal Card"""</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        self.username = <span class="hljs-string">"rafnixg"</span>
        self.name = <span class="hljs-string">"Rafnix Guzmán"</span>
        self.position = <span class="hljs-string">"Python Software Developer"</span>
        self.links = <span class="hljs-string">"https://links.rafnixg.dev"</span>
        self.web = <span class="hljs-string">"https://rafnixg.dev"</span>
        self.blog = <span class="hljs-string">"https://blog.rafnixg.dev"</span>
        self.cv = <span class="hljs-string">"https://resume.rafnixg.dev"</span>
        self.github = <span class="hljs-string">"https://github.com/rafnixg"</span>
        self.twitter = <span class="hljs-string">"@rafnixg"</span>
        self.about = <span class="hljs-string">"Experienced software developer with 10+ years of expertise in designing, developing and implementing web systems across various sectors. Backend specialist skilled in Python, Linux, and Git. Passionate about continuous learning and open-source technology."</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"<span class="hljs-subst">{self.name}</span> (@<span class="hljs-subst">{self.username}</span>) - <span class="hljs-subst">{self.position}</span>"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">display</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""Display personal card"""</span>
        <span class="hljs-comment"># Crea un objeto Console para imprimir en la consola</span>
        console = Console()
        table = Table(
            show_header=<span class="hljs-literal">False</span>, <span class="hljs-comment"># No mostrar encabezados</span>
            title=str(self), <span class="hljs-comment"># Título de la tabla</span>
            highlight=<span class="hljs-literal">True</span>, <span class="hljs-comment"># Resaltar la tabla</span>
            title_style=<span class="hljs-string">"bold magenta"</span>, <span class="hljs-comment"># Estilo del título</span>
        )
        <span class="hljs-comment"># Agrega columnas a la tabla</span>
        table.add_column(<span class="hljs-string">"Attribute"</span>, style=<span class="hljs-string">"bold"</span>, width=<span class="hljs-number">16</span>)
        table.add_column(<span class="hljs-string">"Value"</span>)
        <span class="hljs-comment"># Agrega filas a la tabla con los atributos y valores de la clase</span>
        <span class="hljs-comment"># Itera sobre los atributos de la clase y los agrega a la tabla</span>
        <span class="hljs-keyword">for</span> key, value <span class="hljs-keyword">in</span> self.__dict__.items():
            <span class="hljs-keyword">if</span> isinstance(value, dict):
                <span class="hljs-keyword">for</span> sub_key, sub_value <span class="hljs-keyword">in</span> value.items():
                    table.add_row(sub_key, <span class="hljs-string">", "</span>.join(sub_value))
            <span class="hljs-keyword">elif</span> isinstance(value, list):
                table.add_row(key, <span class="hljs-string">", "</span>.join(value))
            <span class="hljs-keyword">else</span>:
                table.add_row(key, value)
        <span class="hljs-comment"># Imprime la tabla en la consola</span>
        console.print(table)
</code></pre>
<h3 id="heading-inicializar-el-paquete-con-srcrafnixginitpy">🧩 Inicializar el paquete con src/rafnixg/__init__.py</h3>
<pre><code class="lang-python"><span class="hljs-string">"""src/rafnixg/__init__.py
RafnixG - Personal Card
"""</span>
<span class="hljs-keyword">from</span> rafnixg.rafnixg <span class="hljs-keyword">import</span> RafnixG

__version__ = <span class="hljs-string">"1.0.0"</span>
</code></pre>
<h3 id="heading-ejecutar-como-modulo-con-srcrafnixgmainpy">🧩 Ejecutar como modulo con src/rafnixg/__main__.py</h3>
<pre><code class="lang-python"><span class="hljs-string">"""src/rafnixg/__main__.py
RafnixG - Personal Card
"""</span>
<span class="hljs-keyword">from</span> rafnixg <span class="hljs-keyword">import</span> RafnixG


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    <span class="hljs-string">"""Main function."""</span>
    me = RafnixG()
    me.display()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    main()
</code></pre>
<h3 id="heading-ejecutar-y-probar-tu-codigo-localmente">🖥️ Ejecutar y probar tu código localmente</h3>
<p>Para probar nuestro código debemos movernos a la carpeta <code>src/</code> y luego correr el paquete como un módulo de Python:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> <span class="hljs-built_in">cd</span> src
(env) <span class="hljs-variable">$</span> <span class="hljs-built_in">ls</span>
  rafnixg/
(env) <span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> rafnixg
</code></pre>
<p>Recuerda que si estas usando tu código aquí debes colocar el nombre la carpeta que contiene tu código fuente.</p>
<h2 id="heading-preparar-la-libreria-para-ser-publicada">📦 Preparar la librería para ser publicada</h2>
<h3 id="heading-documentando-nuestra-libreria">📘Documentando nuestra librería</h3>
<p>Un <strong>README</strong> es esencial para cualquier proyecto ya que aquí es donde otros desarrolladores y usuarios obtendrán información sobre tu librería, en este archivo no solo se explica que es y lo que hace tu proyecto, sino que también contiene información de como instalarlo, utilizarlo y contribuir. En una próxima publicación profundizaremos más sobre el <strong>README</strong> y que debería contener, por los momentos creamos el archivo <code>README.md</code> con el siguiente contenido:</p>
<pre><code class="lang-markdown"><span class="hljs-section"># Rafnix Guzmán - Personal Card (README.md)</span>

<span class="hljs-section">## Hi there 👋</span>

This is my personal card [<span class="hljs-string">rafnixg.dev</span>](<span class="hljs-link">https://rafnixg.dev</span>)

![<span class="hljs-string">image</span>](<span class="hljs-link">https://github.com/user-attachments/assets/4c1c368b-83ca-4ff7-89d0-c131efe60c9f</span>)


<span class="hljs-section">## How to use it? 🤔</span>

Install using pip:

<span class="hljs-code">```bash
pip install rafnixg
```</span>

Then run it:

<span class="hljs-code">```bash
rafnixg
```</span>
</code></pre>
<h3 id="heading-configurar-el-sistema-de-construccion-build-system">🛠️Configurar el sistema de construcción (build system)</h3>
<p>Para preparar nuestra librería para ser publicada en <strong><em>PyPI</em></strong> necesitamos configurar algunas secciones en el archivo <code>pyproject.toml</code> primero debemos indicar el <strong>build system</strong> que es la parte responsable de crear los archivos que se suben a PyPI, usualmente se usa el formato <strong>wheel</strong> o <strong>sdist</strong>.</p>
<p>Nosotros usaremos el <a target="_blank" href="https://setuptools.pypa.io/">setuptools</a> como <strong>build system.</strong></p>
<pre><code class="lang-ini"><span class="hljs-comment"># pyproject.toml</span>

<span class="hljs-section">[build-system]</span>
<span class="hljs-attr">requires</span> = [<span class="hljs-string">"setuptools&gt;=61.0.0"</span>, <span class="hljs-string">"wheel"</span>]
<span class="hljs-attr">build-backend</span> = <span class="hljs-string">"setuptools.build_meta"</span>
</code></pre>
<h3 id="heading-organizar-el-archivo-pyprojecttoml">🗂️ Organizar el archivo <code>pyproject.toml</code></h3>
<p>Ahora agregaremos una sección para configurar información del proyecto, acá es donde indicaremos el nombre de nuestro paquete, recordemos que debemos verificar que el nombre no este usado por ningún otro paquete dentro del ecosistema <strong><em>PyPI</em></strong>.</p>
<pre><code class="lang-ini"><span class="hljs-comment"># pyproject.toml</span>
...

<span class="hljs-section">[project]</span>
<span class="hljs-attr">name</span> = <span class="hljs-string">"rafnixg"</span>
<span class="hljs-attr">version</span> = <span class="hljs-string">"1.0.0"</span>
<span class="hljs-attr">description</span> = <span class="hljs-string">"Rafnix Guzman Personal Card"</span>
<span class="hljs-attr">readme</span> = <span class="hljs-string">"README.md"</span>
<span class="hljs-attr">authors</span> = [{ name = <span class="hljs-string">"Rafnix Guzman"</span>, email = <span class="hljs-string">"rafnixg@gmail.com"</span> }]
<span class="hljs-attr">license</span> = { file = <span class="hljs-string">"LICENSE"</span> }
<span class="hljs-attr">classifiers</span> = [
    <span class="hljs-string">"License :: OSI Approved :: MIT License"</span>,
    <span class="hljs-string">"Programming Language :: Python"</span>,
    <span class="hljs-string">"Programming Language :: Python :: 3"</span>,
]
<span class="hljs-attr">keywords</span> = [<span class="hljs-string">"personal card"</span>, <span class="hljs-string">"console"</span>]
<span class="hljs-attr">dependencies</span> = [
    <span class="hljs-string">"rich"</span>,
]
<span class="hljs-attr">requires-python</span> = <span class="hljs-string">"&gt;=3.9"</span>

<span class="hljs-section">[project.optional-dependencies]</span>
<span class="hljs-attr">dev</span> = [<span class="hljs-string">"black"</span>, <span class="hljs-string">"bumpver"</span>, <span class="hljs-string">"isort"</span>, <span class="hljs-string">"pip-tools"</span>, <span class="hljs-string">"pytest"</span>]

<span class="hljs-section">[project.urls]</span>
<span class="hljs-attr">Homepage</span> = <span class="hljs-string">"https://github.com/rafnixg/rafnixg-lib"</span>

<span class="hljs-section">[project.scripts]</span>
<span class="hljs-attr">rafnixg</span> = <span class="hljs-string">"rafnixg.__main__:main"</span>
</code></pre>
<blockquote>
<p>No toda esta información es obligatoria, pero es importante dar la mayor cantidad de información posible sobre nuestra librería, la información mínima que podemos ingresar es <code>name</code> y <code>version</code> .</p>
</blockquote>
<p>Las siguientes secciones son importantes por la información que le proporcionan a PyPI:</p>
<ul>
<li><p><code>classifiers</code>: Lista de <a target="_blank" href="https://pypi.org/classifiers/">classifiers</a> de <strong><em>PyPI</em></strong> que ayudan a la búsqueda.</p>
</li>
<li><p><code>keywords</code>: Lista de etiquetas que seran usadas para identicar y categorizar la libreria.</p>
</li>
<li><p><code>dependencies</code>: Lista de dependencias que tu librería necesita, en nuestro caso <strong>rich.</strong></p>
</li>
<li><p><code>project.optional-dependencies</code>: Lista de las dependencias de desarrollo.</p>
</li>
<li><p><code>project.urls</code>: Links que relacione a tu proyecto en github o alguna página web.</p>
</li>
<li><p><code>project.scripts</code>: Punto de entrada para tu librería. en este caso el comando será <code>rafnixg</code> y el punto de entrada será <code>rafnixg.__main__:main</code></p>
</li>
</ul>
<p>Toda esta información hace que en <strong><em>PyPI</em></strong> tu librería se vea mucho mejor y cuando se haga una búsqueda también sea más fácil de encontrar. acá un ejemplo de la información que se muestra en <strong><em>PyPI</em></strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743546709575/1b54dd48-9bb9-434e-aa6f-4b27c783be9b.png" alt class="image--center mx-auto" /></p>
<p>Vemos como también usa el archivo <code>README.md</code> para mostrar del lado derecho la documentación de la librería en <strong><em>PyPI</em></strong>, y los datos del archivo <code>pyproject.toml</code> también se muestran a la izquierda.</p>
<p>Para saber más sobre este archivo de configuración acá esta la <a target="_blank" href="https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html">documentación</a>.</p>
<h3 id="heading-usar-versionamiento-semantico">🔢 Usar versionamiento semántico</h3>
<p>Toda librería debe tener un versionamiento para poder tener un control de lo que se publica, existen diferentes esquemas de versionamiento, en nuestro caso usaremos <a target="_blank" href="https://semver.org/">Semantic Versioning</a> que es una forma simple de gestionar el versionamiento formado por 3 grupo de números, ejemplo: <strong>MAJOR.MINOR.PATCH</strong> las recomendaciones para cambiar estos números son:</p>
<ul>
<li><p><strong>MAJOR</strong>: Cuando tus cambios son tan grandes que rompen tu API anterior.</p>
</li>
<li><p><strong>MINOR</strong>: Cuando agregas nuevas funciones y todo se mantiene compatible, Vuelve a 0 cuando MAJOR cambia.</p>
</li>
<li><p><strong>PATCH</strong>: Cuando agregas bug fixes, vuelve a 0 cuando MINOR cambia.</p>
</li>
</ul>
<p>Para gestionar esto en Python haremos uso de una librería llamada <code>bumpver</code> esto modifica directamente los archivos y así mantiene sincronizado en todos lados la versión.</p>
<pre><code class="lang-powershell">(venv) <span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> pip install bumpver
(venv) <span class="hljs-variable">$</span> bumpver init
WARNING - Couldn<span class="hljs-string">'t parse pyproject.toml: Missing version_pattern
Updated pyproject.toml</span>
</code></pre>
<p>Este comando inicializa en <code>pyproject.toml</code> la gestión de las versiones, si vemos agrego una nueva sección:</p>
<pre><code class="lang-ini"><span class="hljs-section">[tool.bumpver]</span>
<span class="hljs-attr">current_version</span> = <span class="hljs-string">"1.0.0"</span>
<span class="hljs-attr">version_pattern</span> = <span class="hljs-string">"MAJOR.MINOR.PATCH"</span>
<span class="hljs-attr">commit_message</span> = <span class="hljs-string">"bump version {old_version} -&gt; {new_version}"</span>
<span class="hljs-attr">commit</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">tag</span> = <span class="hljs-literal">true</span>
<span class="hljs-attr">push</span> = <span class="hljs-literal">false</span>

<span class="hljs-section">[tool.bumpver.file_patterns]</span>
<span class="hljs-attr">"pyproject.toml"</span> = [
    <span class="hljs-string">'current_version = "{version}"'</span>,
    <span class="hljs-string">'version = "{version}"'</span>
]
<span class="hljs-attr">"src/rafnixg/__init__.py"</span> = [<span class="hljs-string">"{version}"</span>]
</code></pre>
<p>Si no se parece a esta ajustar el <code>version_pattern</code> para que sean iguales, después de configurar esto, tú puedes cambiar la versión usando los comandos de <code>bumpver</code>:</p>
<pre><code class="lang-powershell">(venv) <span class="hljs-variable">$</span> bumpver update -<span class="hljs-literal">-minor</span>
INFO    - Old Version: <span class="hljs-number">1.0</span>.<span class="hljs-number">0</span>
INFO    - New Version: <span class="hljs-number">1.1</span>.<span class="hljs-number">0</span>
INFO    - git commit -<span class="hljs-literal">-message</span> <span class="hljs-string">'bump version 1.0.0 -&gt; 1.1.0'</span>
INFO    - git tag -<span class="hljs-literal">-annotate</span> <span class="hljs-number">1.1</span>.<span class="hljs-number">0</span> -<span class="hljs-literal">-message</span> <span class="hljs-string">'1.1.0'</span>
</code></pre>
<h3 id="heading-elegir-una-licencia-adecuada">📜 Elegir una licencia adecuada</h3>
<p>Cuando creamos una librería debemos elegir que permisos queremos que los demás tengan sobre nuestro código, así se podrá saber qué es lo que quiere que se haga o no con tu librería. Una licencia muy usada para compartir código es la <a target="_blank" href="https://mit-license.org/">Licencia MIT</a> con esta licencia simple y bastante permisiva.</p>
<p>Lo que debemos hacer es crear un archivo de texto llamado <code>LICENSE</code> que contenga el texto de nuestra licencia, si no sabes que licencia escoger existe esta web que permite ver cuál es la más conveniente según tus necesidades: <a target="_blank" href="https://choosealicense.com/">Choose an open source license</a></p>
<h3 id="heading-instalar-tu-libreria-localmente">📥 Instalar tu librería localmente</h3>
<p>Para este punto ya tenemos nuestra librería lista para ser publicada, ahora lo que vamos a necesitar hacer es probar nuestra librería instalándola directamente en nuestro entorno virtual, para esto haremos uso de los siguientes comandos:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> pip install <span class="hljs-literal">-e</span> .
</code></pre>
<p>Con el flag <code>-e</code> se instala tu librería en modo editable y con <code>.</code> indicamos donde se encuentra el archivo <code>pyproject.toml</code> esto ya deja disponible nuestro comando <code>rafnixg</code> que está definido en la sección <code>project.scripts</code> indicando el punto de entrada.</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> rafnixg
                            Rafnix Guzmán Garcia (@rafnixg) - Python Software Developer                             
┌──────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────┐
│ username         │ rafnixg                                                                                       │
│ name             │ Rafnix Guzmán Garcia                                                                          │
│ position         │ Python Software Developer                                                                     │
│ links            │ https://links.rafnixg.dev                                                                     │
│ web              │ https://rafnixg.dev                                                                           │
│ blog             │ https://blog.rafnixg.dev                                                                      │
│ cv               │ https://resume.rafnixg.dev                                                                    │
│ github           │ https://github.com/rafnixg                                                                    │
│ twitter          │ @rafnixg                                                                                      │
│ about            │ Experienced software developer with <span class="hljs-number">10</span>+ years of expertise <span class="hljs-keyword">in</span> designing, developing and       │
│                  │ implementing web systems across various sectors. Backend specialist skilled <span class="hljs-keyword">in</span> Python, Linux, │
│                  │ and Git. Passionate about continuous learning and <span class="hljs-built_in">open-source</span> technology.                     │
└──────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────┘
</code></pre>
<h2 id="heading-publica-tu-libreria-a-pypi">🚀 Publica tu librería a PyPI</h2>
<p>Ya nuestra librería se encuentra lista y a la espera de conocer el mundo, en esta sección haremos el empaquetado y despliegue a <strong>PyPI.</strong></p>
<h3 id="heading-crear-cuentas-en-pypi-y-testpypi">🧑‍💻 Crear cuentas en PyPI y TestPyPI</h3>
<p>Lo primero que debemos tener es una cuenta en <strong><em>PyPI</em></strong>, así que si no la tienes este es tu momento de registrarte: <a target="_blank" href="https://pypi.org/account/register/">https://pypi.org/account/register/</a></p>
<p>También deberíamos crear una cuenta en el ambiente de pruebas de <strong><em>PyPI</em></strong>, así siempre podemos verificar que todo va bien antes de lanzar algo a producción: <a target="_blank" href="https://test.pypi.org/account/register/">https://test.pypi.org/account/register/</a></p>
<p>Recuerden crear sus <code>API Key</code> porque en el proceso de publicación mas adelante serán necesarias.</p>
<h3 id="heading-generar-una-api-key">🔐 Generar una API Key</h3>
<p>Para esto ingresamos a <a target="_blank" href="https://pypi.org/manage/account/">Configuracion de la cuenta</a> bajamos y buscamos la opción <strong>Fichas de API</strong>, hacemos clic en el botón <code>Añadir ficha de API</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743792251750/e6005144-893b-4ebd-9ace-3ffe2dff784a.png" alt class="image--center mx-auto" /></p>
<p>Luego le ponen algún nombre descriptivo a esta <strong>Key</strong>, seleccionamos el <strong>Alcance</strong> y por último clic al botón <code>Create Token</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743792355464/0d294b80-640d-4b6b-8434-4965cb2ca50b.png" alt class="image--center mx-auto" /></p>
<p>Con esto nos mostrara nuestra API Key que siempre empieza por <code>pypy-</code> como se muestra en la imagen de abajo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743793988095/52016b85-72c6-4375-ab7f-0a53ab09d0a2.png" alt class="image--center mx-auto" /></p>
<p>Hacemos clic en Copiar Ficha y guardamos nuestra <code>API Key</code> en algún lugar seguro**.** Siempre van a tener la posibilidad de borrar la key y generar otra si es necesario la pierden.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🚩</div>
<div data-node-type="callout-text">Nunca debemos compartir la API Key o agregarla directamente a un archivo que pueda estar trackeado en <strong>GIT.</strong></div>
</div>

<p>Luego de todo esto debemos instalar 2 librerías que nos ayudaran a construir y publicar nuestro paquete:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> pip install build twine
</code></pre>
<h3 id="heading-construir-el-paquete-con-build">🛠️ Construir el paquete con <code>build</code></h3>
<p>Ahora que tenemos nuestra librería lista, ya podemos hacer la distribución del código a <strong>PyPI</strong>, para esto primero debemos empaquetar nuestra librería en formato <strong>wheels</strong>, un formato que consiste en empaquetar en un archivo <code>tar</code> todo el código fuente de la librería. Para crear este archivo haremos uso de la librería <code>build</code>:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> build
[<span class="hljs-type">...</span>]
Successfully built rafnixg<span class="hljs-literal">-1</span>.<span class="hljs-number">0.0</span>.tar.gz and rafnixg<span class="hljs-literal">-1</span>.<span class="hljs-number">0.0</span><span class="hljs-literal">-py3</span><span class="hljs-literal">-none</span><span class="hljs-literal">-any</span>.whl
</code></pre>
<p>Esto nos crea una nueva carpeta llamada <code>dist/</code> que contiene el archivo <code>.tar.gz</code> con el código de nuestra librería y el archivo <code>.whl</code> que es nuestro archivo <strong>wheels</strong>, esto es todo lo que necesitamos para subir a <strong>PyPI</strong>.</p>
<h3 id="heading-verificar-el-paquete-con-twine-check">✅ Verificar el paquete con <code>twine check</code></h3>
<p>Para validar que todo fue empaquetado correctamente podemos usar <code>twine</code>:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> twine check dist/*
Checking dist/rafnixg<span class="hljs-literal">-1</span>.<span class="hljs-number">0.0</span><span class="hljs-literal">-py3</span><span class="hljs-literal">-none</span><span class="hljs-literal">-any</span>.whl: PASSED
Checking dist/rafnixg<span class="hljs-literal">-1</span>.<span class="hljs-number">0.0</span>.tar.gz: PASSED
</code></pre>
<h3 id="heading-subir-el-paquete-a-pypi">☁️ Subir el paquete a PyPI</h3>
<p>Ahora que tenemos todo listo y verificado, podemos subir a <strong><em>TestPyPI</em></strong> para ver que todo va con normalidad y no tenemos ningún error en nuestra librería:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> twine upload <span class="hljs-literal">-r</span> testpypi dist/*
</code></pre>
<p>Nos pedirá nuestra <code>API Key</code>. Ya con esto podemos probar nuestra librería usando el siguiente comando:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> pip install <span class="hljs-literal">-i</span> https://test.pypi.org/simple/ rafnixg
</code></pre>
<p>Si todo salió con normalidad, podemos subir a él repositorio principal de <strong><em>PyPI</em></strong>:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> twine upload dist/*
</code></pre>
<p>Con esto tendríamos nuestro proyecto ya disponible para usar con <code>pip</code>, podemos a <strong><em>PyPI</em></strong> y buscar nuestra librería.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://pypi.org/project/rafnixg">https://pypi.org/project/rafnixg</a></div>
<p> </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743790696920/9726f027-4b6f-438b-bb66-09421f8c08e0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-instalar-tu-paquete-desde-pypi">📥 Instalar tu paquete desde PyPI</h3>
<p>Ya con nuestra librería publicada en <strong><em>PyPI</em></strong> podemos usarla con el siguiente comando:</p>
<pre><code class="lang-powershell">(env) <span class="hljs-variable">$</span> python <span class="hljs-literal">-m</span> pip install rafnixg
(env) <span class="hljs-variable">$</span> rafnixg
</code></pre>
<h2 id="heading-conclusiones">🧠 Conclusiones</h2>
<p>Crear y publicar tu propio paquete en Python es una experiencia enriquecedora que va más allá de compartir código: es una oportunidad para aprender sobre la estructuración de proyectos, el versionado semántico y las buenas prácticas de la comunidad. A lo largo de este tutorial, hemos recorrido desde la configuración del entorno de desarrollo hasta la publicación en <strong><em>PyPI</em></strong>, enfatizando la importancia de una documentación clara y una estructura ordenada. Con estos conocimientos, no solo mejoras tus habilidades técnicas, sino que también das un paso significativo hacia la consolidación de tu perfil profesional en el mundo del desarrollo. ¡Atrévete a experimentar, optimizar tu paquete y contribuir al ecosistema <strong>open source</strong>!</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">📰</div>
<div data-node-type="callout-text">En una próxima publicación veremos cómo podemos crear un flujo de <strong>CI/CD</strong> con <strong>Github Actions</strong> para automatizar la publicación de nuestra librería, también como documentarla y publicar con <strong>Github Pages</strong> esta documentación. Cualquier duda o consulta déjalo en la sección de comentarios.</div>
</div>]]></content:encoded></item><item><title><![CDATA[Shell de Odoo: Domina Operaciones Avanzadas, Integración de Librerías y Automatización de Tareas]]></title><description><![CDATA[En un post anterior, exploramos los conceptos básicos de la shell de la CLI de Odoo y cómo configurar IPython como REPL para mejorar nuestra experiencia de desarrollo. Ahora, profundizaremos en el uso de la shell de Odoo, abordando temas más avanzado...]]></description><link>https://blog.rafnixg.dev/shell-de-odoo-domina-operaciones-avanzadas-integracion-de-librerias-y-automatizacion-de-tareas</link><guid isPermaLink="true">https://blog.rafnixg.dev/shell-de-odoo-domina-operaciones-avanzadas-integracion-de-librerias-y-automatizacion-de-tareas</guid><category><![CDATA[Odoo]]></category><category><![CDATA[shell]]></category><category><![CDATA[shell odoo]]></category><category><![CDATA[Python]]></category><category><![CDATA[español]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Mon, 10 Apr 2023 21:24:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/xbEVM6oJ1Fs/upload/c61979ca790e36478ccfd07e09317664.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En un post anterior, exploramos los conceptos básicos de la shell de la <a target="_blank" href="https://hashnode.com/post/clfv2dvp4014vmvnvgeie8rtc">CLI de Odoo y cómo configurar IPython como REPL</a> para mejorar nuestra experiencia de desarrollo. Ahora, profundizaremos en el uso de la shell de Odoo, abordando temas más avanzados y descubriendo cómo sacarle el máximo provecho a esta poderosa herramienta.</p>
<p>El propósito de este post es proporcionar una guía completa para los desarrolladores de Odoo que deseen llevar sus habilidades al siguiente nivel y dominar el uso de la shell en sus proyectos. A lo largo del artículo, cubriremos temas como acceso avanzado, operaciones avanzadas, integración de librerías externas, automatización de tareas y seguridad en la shell de Odoo.</p>
<h2 id="heading-acceso-avanzado-a-la-shell-de-odoo"><strong>Acceso avanzado a la shell de Odoo</strong></h2>
<p>La shell de Odoo es una herramienta poderosa que nos permite interactuar con el sistema Odoo y ejecutar tareas de desarrollo y administración. En esta sección, profundizaremos en algunas técnicas avanzadas para acceder y utilizar la shell de Odoo de manera más efectiva.</p>
<h3 id="heading-uso-de-diferentes-archivos-de-configuracion"><strong>Uso de diferentes archivos de configuración</strong></h3>
<p>En ocasiones, puede ser útil tener diferentes archivos de configuración para distintos entornos o propósitos. Por ejemplo, podrías querer tener un archivo de configuración específico para trabajar con la shell de Odoo, que incluya parámetros ajustados para este propósito, como el número de workers, los límites de memoria y los puertos XML-RPC y Longpolling.</p>
<p>Para utilizar un archivo de configuración específico al acceder a la shell de Odoo, simplemente especifica la ruta del archivo con el parámetro <code>-c</code> al ejecutar el comando <code>odoo-bin shell</code>. Por ejemplo:</p>
<pre><code class="lang-bash">./odoo-bin shell -c /path/to/your/custom/odoo.conf
</code></pre>
<p>Asegúrate de que tu archivo de configuración personalizado incluye todos los parámetros necesarios para que la shell de Odoo funcione correctamente.</p>
<h3 id="heading-acceso-remoto-a-la-shell-de-odoo"><strong>Acceso remoto a la shell de Odoo</strong></h3>
<p>En algunos casos, es posible que desees acceder a la shell de Odoo en un servidor remoto, en lugar de ejecutarla localmente. Para hacer esto, puedes utilizar una herramienta como <code>ssh</code> para establecer una conexión segura con el servidor remoto y acceder a la shell de Odoo desde allí.</p>
<p>Primero, asegúrate de tener <code>ssh</code> instalado en tu máquina local y que tienes acceso al servidor remoto con las credenciales adecuadas. Luego, ejecuta el siguiente comando para establecer una conexión <code>ssh</code> con el servidor remoto:</p>
<pre><code class="lang-bash">ssh user@remote-server-ip
</code></pre>
<p>Una vez que hayas iniciado sesión en el servidor remoto, navega hasta el directorio de instalación de Odoo y sigue los pasos habituales para acceder a la shell de Odoo utilizando el comando <code>odoo-bin shell</code> y el archivo de configuración deseado.</p>
<p>Al utilizar el acceso remoto a la shell de Odoo, ten en cuenta las implicaciones de seguridad y sigue las mejores prácticas para proteger tus datos y evitar accesos no autorizados.</p>
<h2 id="heading-operaciones-avanzadas-en-la-shell-de-odoo"><strong>Operaciones avanzadas en la shell de Odoo</strong></h2>
<p>La shell de Odoo ofrece muchas posibilidades para realizar tareas de desarrollo y administración de manera eficiente. En esta sección, abordaremos algunas operaciones avanzadas que puedes realizar en la shell de Odoo, lo que te permitirá aprovechar aún más esta herramienta.</p>
<h3 id="heading-actualizacion-de-modulos-desde-la-shell"><strong>Actualización de módulos desde la shell</strong></h3>
<p>Es posible actualizar módulos directamente desde la shell de Odoo. Para actualizar un módulo existente, utiliza el método <code>button_upgrade()</code> en el módulo que deseas actualizar:</p>
<pre><code class="lang-bash">module = env[<span class="hljs-string">'ir.module.module'</span>].search([(<span class="hljs-string">'name'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'my_module'</span>)])
module.button_upgrade()
</code></pre>
<p>Donde <code>'my_module'</code> es el nombre del modulo que deseo actualizar.</p>
<h3 id="heading-importacion-y-exportacion-de-datos-en-formatos-csv"><strong>Importación y exportación de datos en formatos CSV</strong></h3>
<p>La shell de Odoo también facilita la importación y exportación de datos en formatos CSV y XML. Para importar datos desde un archivo CSV, sigue estos pasos:</p>
<ol>
<li><p>Instala la librería <code>csv</code> en tu entorno de Odoo.</p>
</li>
<li><p>Utiliza la siguiente estructura para leer y procesar el archivo CSV:</p>
</li>
</ol>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'data.csv'</span>, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> csvfile:
    reader = csv.DictReader(csvfile)
    <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> reader:
        <span class="hljs-comment"># Procesa cada fila del archivo CSV</span>
</code></pre>
<p>Para exportar datos a un archivo CSV, puedes utilizar un enfoque similar:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv

<span class="hljs-keyword">with</span> open(<span class="hljs-string">'data.csv'</span>, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> csvfile:
    fieldnames = [<span class="hljs-string">'field1'</span>, <span class="hljs-string">'field2'</span>, <span class="hljs-string">'field3'</span>]
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    <span class="hljs-keyword">for</span> record <span class="hljs-keyword">in</span> records:
        <span class="hljs-comment"># Escribe cada registro en el archivo CSV</span>
</code></pre>
<p>Para trabajar con datos en formato XML, puedes utilizar librerías como <code>lxml</code> o <code>xml.etree.ElementTree</code>.</p>
<h3 id="heading-trabajo-con-registros-y-campos-relacionales"><strong>Trabajo con registros y campos relacionales</strong></h3>
<p>La shell de Odoo facilita el trabajo con registros y campos relacionales. Para acceder a un campo relacional (por ejemplo, un campo Many2one), simplemente utiliza la notación de punto:</p>
<pre><code class="lang-python">record = env[<span class="hljs-string">'res.partner'</span>].browse(<span class="hljs-number">1</span>)
print(record.parent_id)
print(record.company_id.name)
</code></pre>
<p>Para acceder a campos relacionales inversos (por ejemplo, campos One2many o Many2many), utiliza la misma notación de punto:</p>
<pre><code class="lang-python">record = env[<span class="hljs-string">'res.partner'</span>].browse(<span class="hljs-number">1</span>)
print(record.child_ids)
<span class="hljs-keyword">for</span> child <span class="hljs-keyword">in</span> record.child_ids:
    print(child.id)
</code></pre>
<h3 id="heading-busqueda-y-manipulacion-de-registros-con-filtros-y-operadores-avanzados"><strong>Búsqueda y manipulación de registros con filtros y operadores avanzados</strong></h3>
<p>La shell de Odoo te permite buscar y manipular registros utilizando filtros y operadores avanzados usando la notacion de domains de Odoo. Por ejemplo, puedes utilizar el operador <code>like</code> para buscar registros que coincidan con un patrón específico:</p>
<pre><code class="lang-python">records = env[<span class="hljs-string">'res.partner'</span>].search([(<span class="hljs-string">'name'</span>, <span class="hljs-string">'like'</span>, <span class="hljs-string">'R%'</span>)])
</code></pre>
<p>También puedes combinar múltiples criterios de búsqueda utilizando operadores lógicos como <code>&amp;</code> (AND) y <code>|</code> (OR):</p>
<pre><code class="lang-python">records = env[<span class="hljs-string">'res.partner'</span>].search([<span class="hljs-string">'&amp;'</span>, (<span class="hljs-string">'name'</span>, <span class="hljs-string">'like'</span>, <span class="hljs-string">'R%'</span>), (<span class="hljs-string">'country_id.code'</span>, <span class="hljs-string">'='</span>, <span class="hljs-string">'PE'</span>)])
</code></pre>
<h3 id="heading-uso-de-contextos"><strong>Uso de contextos</strong></h3>
<p>Los contextos en Odoo son una herramienta útil para personalizar el comportamiento de las operaciones en función de ciertos parámetros, como el idioma o el usuario. Puedes utilizar contextos para realizar consultas en diferentes idiomas o para aplicar filtros específicos a nivel de usuario.</p>
<p>Por ejemplo, para buscar registros en un idioma específico, puedes pasar el código de idioma en el contexto:</p>
<pre><code class="lang-python">records = env[<span class="hljs-string">'res.partner'</span>].with_context(lang=<span class="hljs-string">'es_ES'</span>).search([])
</code></pre>
<p>Esto retornará los registros traducidos al idioma especificado en el contexto (en este caso, español).</p>
<p>También puedes utilizar contextos para aplicar filtros específicos a nivel de usuario. Por ejemplo, si deseas buscar registros que solo sean visibles para un usuario específico, puedes hacer lo siguiente:</p>
<pre><code class="lang-python">user_id = <span class="hljs-number">2</span>  <span class="hljs-comment"># ID del usuario específico</span>
user = env[<span class="hljs-string">'res.users'</span>].browse(user_id)
records = env[<span class="hljs-string">'res.partner'</span>].with_context(user=user).search([])
</code></pre>
<p>Esto retornará los registros de socios comerciales que solo son visibles para el usuario con ID 2.</p>
<h2 id="heading-integracion-de-librerias-externas-en-la-shell-de-odoo"><strong>Integración de librerías externas en la shell de Odoo</strong></h2>
<p>La shell de Odoo es un entorno interactivo de Python, lo que significa que puedes importar y utilizar librerías externas de Python para mejorar y ampliar la funcionalidad de la shell. En esta sección, exploraremos cómo utilizar algunas librerías útiles para el análisis y tratamiento de datos y también mencionaremos otras librerías que podrían resultar de interés.</p>
<h3 id="heading-uso-de-pandas-para-el-analisis-y-tratamiento-de-datos">Uso de Pandas para el análisis y tratamiento de datos</h3>
<p>Pandas es una biblioteca de Python popular y poderosa que ofrece estructuras de datos y herramientas de análisis de datos. Su integración en la shell de Odoo puede ser útil para realizar análisis de datos y para trabajar con grandes conjuntos de registros.</p>
<p>Para utilizar Pandas en la shell de Odoo, primero debes instalarla en tu entorno de Python:</p>
<pre><code class="lang-bash">pip install pandas
</code></pre>
<p>Una vez instalada, puedes importar Pandas en la shell de Odoo y empezar a utilizar sus funciones. Por ejemplo, puedes utilizar la función <code>DataFrame</code> de Pandas para convertir un conjunto de registros de Odoo en un DataFrame de Pandas:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd

partners = env[<span class="hljs-string">'res.partner'</span>].search([])
data = []

<span class="hljs-keyword">for</span> partner <span class="hljs-keyword">in</span> partners:
    data.append({
        <span class="hljs-string">'id'</span>: partner.id,
        <span class="hljs-string">'name'</span>: partner.name,
        <span class="hljs-string">'email'</span>: partner.email,
        <span class="hljs-string">'country'</span>: partner.country_id.name,
    })

df = pd.DataFrame(data)
</code></pre>
<p>Ahora que tienes un DataFrame de Pandas, puedes utilizar todas las funciones y herramientas de análisis de datos que ofrece Pandas. Por ejemplo, puedes realizar agrupaciones, filtrados, ordenamientos y mucho más.</p>
<h3 id="heading-otras-librerias-utiles-para-mejorar-el-trabajo-en-la-shell">Otras librerías útiles para mejorar el trabajo en la shell</h3>
<p>Además de Pandas, hay muchas otras librerías de Python que pueden ser útiles en la shell de Odoo. A continuación, se mencionan algunas de ellas:</p>
<ol>
<li><p><strong>NumPy</strong>: Esta biblioteca es muy útil para realizar cálculos matemáticos y estadísticos en conjuntos de datos. Puedes utilizar NumPy junto con Pandas para llevar a cabo análisis avanzados en tus datos de Odoo.</p>
</li>
<li><p><strong>Requests</strong>: Requests es una biblioteca popular para realizar solicitudes HTTP en Python. Puedes utilizarla en la shell de Odoo para interactuar con servicios web y APIs externas.</p>
</li>
<li><p><strong>OpenPyXL</strong>: OpenPyXL es una biblioteca de Python para leer y escribir archivos Excel. Puedes utilizarla en la shell de Odoo para importar y exportar datos en formato Excel.</p>
</li>
</ol>
<p>Estas son solo algunas de las muchas librerías disponibles para Python que pueden mejorar tu experiencia de trabajo en la shell de Odoo. No dudes en explorar otras librerías y adaptarlas a tus necesidades específicas.</p>
<h2 id="heading-automatizacion-de-tareas-con-la-shell-de-odoo"><strong>Automatización de tareas con la shell de Odoo</strong></h2>
<p>Una de las ventajas de trabajar con la shell de Odoo es la posibilidad de automatizar tareas y procesos. En esta sección, exploraremos cómo ejecutar scripts y comandos desde archivos externos y cómo programar tareas automatizadas y cron jobs desde la shell.</p>
<h3 id="heading-ejecucion-de-scripts-y-comandos-desde-archivos-externos">Ejecución de scripts y comandos desde archivos externos</h3>
<p>En lugar de ejecutar comandos individualmente en la shell de Odoo, puedes crear un archivo de script de Python que contenga una serie de comandos y ejecutar ese archivo. Esto facilita la automatización y la reutilización de código.</p>
<p>Para ejecutar un script de Python usando el entorno de Odoo, debemos crear primero un script wrapper que nos permita ejecutar nuestros scripts inyectando el entorno de odoo. sigue estos pasos:</p>
<ol>
<li><p>Crea un archivo llamado <code>odoo_wrapper.py</code> con el siguiente contenido:</p>
<p> <a target="_blank" href="https://gist.github.com/rafnixg/8be94e4b5226b19a465f5a36935828c7">https://gist.github.com/rafnixg/8be94e4b5226b19a465f5a36935828c7</a></p>
</li>
<li><div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="8be94e4b5226b19a465f5a36935828c7"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/rafnixg/8be94e4b5226b19a465f5a36935828c7" class="embed-card">https://gist.github.com/rafnixg/8be94e4b5226b19a465f5a36935828c7</a></div><p> </p>
</li>
<li><p>Crea un archivo de script de Python (por ejemplo, <code>mi_script.py</code>) con una función llamada <code>run</code> que reciba un argumento <code>env</code>:</p>
</li>
</ol>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run</span>(<span class="hljs-params">env</span>):</span>
    <span class="hljs-comment"># Tus comandos aqui, utilizando la variable 'env' para acceder a la API de Odoo</span>
    <span class="hljs-comment"># Este archivo puede ser todo lo complejo que tu quieras</span>
    <span class="hljs-comment"># Para probar usemos esto de ejemplo:</span>
    partners = env[<span class="hljs-string">'res.partner'</span>].search([])
    print(<span class="hljs-string">"Numero de contactos:"</span>, len(partners))
</code></pre>
<ol>
<li><p>Desde la línea de comandos, navega hasta el directorio donde se encuentra el archivo <code>odoo_wrapper.py</code>.</p>
</li>
<li><p>Ejecuta el siguiente comando para ejecutar el archivo <code>odoo_wrapper.py</code> y que a su vez ejecute tu archivo <code>mi_script.py</code>:</p>
</li>
</ol>
<pre><code class="lang-bash">python3 odoo_wrapper.py /path/to/mi_script.py
</code></pre>
<p>El archivo <code>odoo_wrapper.py</code> se encargará de ejecutar el archivo <code>mi_script.py</code> utilizando la API de Odoo y la base de datos especificada en el archivo de configuración. La función <code>run</code> en tu archivo <code>mi_script.py</code> se ejecutará con el entorno de Odoo proporcionado.</p>
<h3 id="heading-programacion-de-tareas-automatizadas-y-cron-jobs-desde-la-shell">Programación de tareas automatizadas y cron jobs desde la shell</h3>
<p>La shell de Odoo también te permite programar tareas automatizadas y cron jobs directamente desde la shell. Estas tareas se ejecutarán en intervalos específicos y pueden ser útiles para automatizar procesos como copias de seguridad, actualizaciones, sincronizaciones y más.</p>
<p>Para programar una tarea automatizada o un cron job desde la shell de Odoo, sigue estos pasos:</p>
<ol>
<li><p>En la shell de Odoo, accede al modelo <code>ir.cron</code>:</p>
<pre><code class="lang-python"> ir_cron = env[<span class="hljs-string">'ir.cron'</span>]
</code></pre>
</li>
<li><p>Crea un nuevo registro de cron job utilizando el método <code>create()</code> y proporciona los detalles necesarios, como el nombre, el modelo, el método y el intervalo de tiempo:</p>
</li>
</ol>
<pre><code class="lang-python">ir_cron.create({
    <span class="hljs-string">'name'</span>: <span class="hljs-string">'Mi Cron Job'</span>,
    <span class="hljs-string">'model_id'</span>: env.ref(<span class="hljs-string">'base.model_res_partner'</span>).id,
    <span class="hljs-string">'state'</span>: <span class="hljs-string">'code'</span>,
    <span class="hljs-string">'code'</span>: <span class="hljs-string">"model.my_custom_method()"</span>,
    <span class="hljs-string">'interval_number'</span>: <span class="hljs-number">1</span>,
    <span class="hljs-string">'interval_type'</span>: <span class="hljs-string">'days'</span>,
    <span class="hljs-string">'numbercall'</span>: <span class="hljs-number">-1</span>,
    <span class="hljs-string">'doall'</span>: <span class="hljs-literal">False</span>,
    <span class="hljs-string">'active'</span>: <span class="hljs-literal">True</span>,
})
</code></pre>
<p>En este ejemplo, hemos creado un cron job que ejecutará el método <code>my_custom_method()</code> en el modelo <code>res.partner</code> cada día. Puedes personalizar los parámetros según tus necesidades.</p>
<p>Una vez creada la tarea, se ejecutará automáticamente según el intervalo de tiempo especificado. Puedes verificar y administrar las tareas automatizadas y los cron jobs en la interfaz web de Odoo, bajo Configuración &gt; Técnico &gt; Automatización &gt; Tareas programadas.</p>
<h2 id="heading-seguridad-y-buenas-practicas-en-el-uso-de-la-shell-de-odoo"><strong>Seguridad y buenas prácticas en el uso de la shell de Odoo</strong></h2>
<h3 id="heading-recomendaciones-para-proteger-la-informacion-y-evitar-accesos-no-autorizados"><strong>Recomendaciones para proteger la información y evitar accesos no autorizados</strong></h3>
<p>Cuando trabajamos con la shell de Odoo, es importante tener en cuenta la seguridad y garantizar que la información y los datos estén protegidos. A continuación, se presentan algunas recomendaciones para proteger la información y evitar accesos no autorizados:</p>
<ol>
<li><p><strong>Controlar el acceso a la shell de Odoo</strong>: Limita el acceso a la shell de Odoo a los usuarios que realmente necesitan usarla. Asegúrate de que las credenciales de inicio de sesión y los permisos estén configurados correctamente para restringir el acceso solo a los usuarios autorizados.</p>
</li>
<li><p><strong>Proteger el archivo de configuración</strong>: El archivo de configuración de Odoo puede contener información sensible, como contraseñas de base de datos y otros datos de configuración. Asegúrate de proteger este archivo mediante permisos de lectura y escritura adecuados y almacenarlo en una ubicación segura.</p>
</li>
<li><p><strong>Hacer copias de seguridad de los datos</strong>: Realiza copias de seguridad periódicas de la base de datos de Odoo y almacena estas copias de seguridad en un lugar seguro y protegido. Esto te permitirá restaurar los datos en caso de un problema de seguridad o una pérdida de datos accidental.</p>
</li>
</ol>
<h3 id="heading-uso-responsable-de-la-shell-en-entornos-de-produccion"><strong>Uso responsable de la shell en entornos de producción</strong></h3>
<p>Es importante utilizar la shell de Odoo de manera responsable en entornos de producción para evitar problemas y garantizar la estabilidad del sistema. Aquí hay algunas pautas para usar la shell de Odoo de manera responsable:</p>
<ol>
<li><p><strong>Evitar cambios en tiempo real en entornos de producción</strong>: Aunque la shell de Odoo permite realizar cambios en tiempo real en la base de datos y el sistema, estos cambios pueden tener consecuencias imprevistas. Siempre es mejor realizar cambios en un entorno de desarrollo o prueba antes de aplicarlos en un entorno de producción.</p>
</li>
<li><p><strong>Limitar el uso de la shell en entornos de producción</strong>: Utiliza la shell de Odoo en entornos de producción solo cuando sea necesario y por el tiempo estrictamente necesario. Evita dejar sesiones de shell abiertas innecesariamente.</p>
</li>
<li><p><strong>Registrar y auditar el uso de la shell</strong>: Mantén un registro de quién accede a la shell de Odoo y qué acciones se realizan en la shell. Estos registros pueden ser útiles para identificar problemas de seguridad y realizar auditorías.</p>
</li>
<li><p><strong>Seguir las mejores prácticas de desarrollo</strong>: Al utilizar la shell de Odoo para desarrollar módulos y realizar cambios en la plataforma, sigue las mejores prácticas de desarrollo de Odoo para garantizar un código seguro, eficiente y fácil de mantener.</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>Conclusión</strong></h2>
<p>En este artículo, se profundizado en el uso y la configuración de la shell de Odoo para aprovechar su potencial y mejorar nuestras habilidades en el desarrollo y la gestión de Odoo. Hemos cubierto temas esenciales como el acceso avanzado a la shell, la realización de operaciones avanzadas, la integración de librerías externas, la automatización de tareas y la implementación de medidas de seguridad y buenas prácticas.</p>
<p>Espero que este artículo te haya proporcionado una comprensión más profunda del potencial de la shell de Odoo y te haya equipado con el conocimiento necesario para aprovechar sus capacidades en tus proyectos. Te invitos a aplicar y experimentar con lo aprendido, y a compartir tus experiencias y conocimientos con otros miembros de la comunidad Odoo.</p>
<div class="hn-embed-widget" id="plausible"></div>]]></content:encoded></item><item><title><![CDATA[Explorando Odoo a fondo: Cómo trabajar con la shell de la CLI y configurar IPython como REPL]]></title><description><![CDATA[¡Hola a todos! Hoy vamos a explorar un tema esencial para todos los programadores de Odoo que deseen profundizar en el desarrollo y uso del ORM de Odoo: la shell de la CLI de Odoo. La CLI (Command Line Interface) de Odoo es la forma en que se ejecuta...]]></description><link>https://blog.rafnixg.dev/explorando-odoo-a-fondo-como-trabajar-con-la-shell-de-la-cli-y-configurar-ipython-como-repl</link><guid isPermaLink="true">https://blog.rafnixg.dev/explorando-odoo-a-fondo-como-trabajar-con-la-shell-de-la-cli-y-configurar-ipython-como-repl</guid><category><![CDATA[Odoo]]></category><category><![CDATA[Python]]></category><category><![CDATA[cli]]></category><category><![CDATA[shell odoo]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Thu, 30 Mar 2023 12:00:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/a4X1cdC1QAc/upload/0907fbada7fd37c284884a528569e522.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola a todos! Hoy vamos a explorar un tema esencial para todos los programadores de Odoo que deseen profundizar en el desarrollo y uso del ORM de Odoo: la shell de la CLI de Odoo. La CLI (Command Line Interface) de Odoo es la forma en que se ejecuta Odoo en la mayoría de los casos, ya sea en modo de desarrollo o en producción. Conocer cómo funciona la CLI y cómo usarla de manera efectiva nos permitirá aprovechar al máximo las herramientas y funciones de Odoo y mejorar la eficiencia de nuestro trabajo.</p>
<p>En este post, te guiaré a través de cómo acceder a la shell de Odoo y cómo configurarla para trabajar con IPython.</p>
<h2 id="heading-como-ejecutar-una-shell-usando-la-cli-de-odoo"><strong>Cómo ejecutar una shell usando la CLI de Odoo</strong></h2>
<p>Para acceder a la shell de Odoo, primero debemos asegurarnos de que Odoo esté instalado en nuestro sistema. Si aún no lo has hecho, te recomiendo seguir los pasos de instalación de Odoo para tu sistema operativo o <a target="_blank" href="https://blog.rafnixg.dev/creando-un-entorno-de-desarrollo-para-odoo-140-con-vscode-en-ubuntu-2204">Creando un entorno de desarrollo para Odoo 14.0 con VSCode</a>. Una vez instalado, sigue estos pasos para acceder a la shell de Odoo:</p>
<ol>
<li><p>Abre la línea de comandos o terminal.</p>
</li>
<li><p>Navega hasta el directorio de instalación de Odoo. Normalmente, esto se encuentra en "/usr/lib/odoo" o "/opt/odoo".</p>
</li>
<li><p>Ejecuta el siguiente comando si tienes una instalacion desde codigo fuente:</p>
</li>
</ol>
<pre><code class="lang-bash">./odoo-bin shell -c /path/to/odoo.conf --xmlrpc-port 8888 --longpolling-port 8899
</code></pre>
<p>Si es desde una instalcion usando los paquetes del sistema operativo</p>
<pre><code class="lang-bash">odoo shell -c /path/to/odoo.conf --xmlrpc-port 8888 --longpolling-port 8899
</code></pre>
<ul>
<li><p><code>-c /path/to/odoo.conf</code>: especifica la ruta al archivo de configuración de Odoo que deseas utilizar.</p>
</li>
<li><p><code>--xmlrpc-port 8888</code>: establece el puerto XML-RPC que utiliza Odoo para comunicarse con otras aplicaciones.</p>
</li>
<li><p><code>--longpolling-port 8899</code>: establece el puerto de long polling que utiliza Odoo para notificaciones en tiempo real.</p>
</li>
</ul>
<p>Cambiamos los puertos para que no choque con los puertos de nuestra instancia de Odoo que se esta ejecutando.</p>
<p>Si todo funciona correctamente, deberías ver la siguiente línea en la terminal:</p>
<pre><code class="lang-bash">env: &lt;odoo.api.Environment object at 0x7efc89670ef0&gt;
odoo: &lt;module <span class="hljs-string">'odoo'</span> from <span class="hljs-string">'/usr/lib/python3/dist-packages/odoo/__init__.py'</span>&gt;
openerp: &lt;module <span class="hljs-string">'odoo'</span> from <span class="hljs-string">'/usr/lib/python3/dist-packages/odoo/__init__.py'</span>&gt;
self: res.users(1,)
Python 3.x.x (default, MMM DD YYYY, HH:MM:SS)
</code></pre>
<p>Ahora estás en la shell de Odoo. Puedes empezar a ejecutar comandos de Odoo y explorar la plataforma ERP. Por ejemplo, puedes ejecutar el siguiente comando para el usuario que se ejecuta en esta shell Odoo:</p>
<pre><code class="lang-python">print(self.name)
</code></pre>
<p>También puedes interactuar con la base de datos de Odoo utilizando la sintaxis de ORM de Odoo. Por ejemplo, el siguiente comando cuenta todos los modelos de datos que tiene esta instancia de Odoo:</p>
<pre><code class="lang-javascript">print(env[<span class="hljs-string">'ir.model'</span>].search_count([]))
</code></pre>
<h2 id="heading-como-configurar-la-interfaz-de-la-shell-para-usar-ipython-como-repl"><strong>Cómo configurar la interfaz de la shell para usar IPython como REPL</strong></h2>
<p>IPython es un shell interactivo de Python que proporciona funciones avanzadas como autocompletado, resaltado de sintaxis, historial de comandos y más. Utilizar IPython como REPL (Read-Eval-Print Loop) en lugar del shell estándar de Python puede mejorar nuestra experiencia de programación en Odoo.</p>
<p>Para configurar la shell de Odoo para usar IPython como REPL, sigue estos pasos:</p>
<ol>
<li>Instala IPython en tu sistema. En la mayoría de los sistemas operativos, puedes instalarlo ejecutando el siguiente comando:</li>
</ol>
<pre><code class="lang-bash">pip install ipython
</code></pre>
<ol>
<li>Ahora que IPython está instalado, debes modificar el comando que usamos anteriormente para acceder a la shell de Odoo, incluyendo la opción <code>--shell-interface ipython</code>. El comando modificado se verá así:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># Desde codigo fuente</span>
./odoo-bin shell -c /path/to/odoo.conf --xmlrpc-port 8888 --longpolling-port 8899 --shell-interface ipython
</code></pre>
<pre><code class="lang-bash"><span class="hljs-comment"># Binario instalado</span>
odoo shell -c /path/to/odoo.conf --xmlrpc-port 8888 --longpolling-port 8899 --shell-interface ipython
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1680142682619/4e5967a9-664c-4b2e-a86c-d2d044b443f4.png" alt class="image--center mx-auto" /></p>
<p>Al ejecutar este comando, accederás a la shell de Odoo con IPython como REPL,como vemos en la imagen, lo que te permitirá aprovechar sus funciones avanzadas mientras trabajas con Odoo, para salir del modo shell con IPython debes usar <code>ctrl+D</code></p>
<h2 id="heading-recomendaciones-para-el-uso-de-la-shell-de-odoo"><strong>Recomendaciones para el uso de la shell de Odoo</strong></h2>
<h3 id="heading-configuracion-separada-para-la-shell-de-odoo"><strong>Configuración separada para la shell de Odoo</strong></h3>
<p>Es altamente recomendable tener un archivo de configuración separado para la shell de Odoo. Esto nos permite ajustar los parámetros específicos para la shell sin afectar la configuración de nuestra instancia de Odoo en producción o desarrollo. Algunos de los parámetros que podrías considerar ajustar en este archivo de configuración separado incluyen:</p>
<ul>
<li><p><code>--xmlrpc-port 8888</code>: Establecer un puerto XML-RPC diferente para evitar conflictos con la instancia principal de Odoo.</p>
</li>
<li><p><code>--longpolling-port 8899</code>: Establecer un puerto de Long Polling diferente para evitar conflictos con la instancia principal de Odoo.</p>
</li>
<li><p>Cambiar los valores de límite de memoria (soft y hard memory limit) para asignar más o menos recursos a la shell.</p>
</li>
<li><p>Ajustar el número de workers para adaptarlo a tus necesidades específicas.</p>
</li>
</ul>
<p>Para crear un archivo de configuración separado, simplemente copia tu archivo de configuración principal y modifica los parámetros mencionados anteriormente. Luego, al ejecutar la shell de Odoo, usa la opción <code>-c</code> para especificar la ruta a este nuevo archivo de configuración. Por ejemplo:</p>
<pre><code class="lang-bash">./odoo-bin shell -c /path/to/shell-odoo.conf --shell-interface ipython
</code></pre>
<pre><code class="lang-bash">odoo- shell -c /path/to/shell-odoo.conf --shell-interface ipython
</code></pre>
<h3 id="heading-uso-de-librerias-externas"><strong>Uso de librerías externas</strong></h3>
<p>Al trabajar con la shell de Odoo, no estás limitado a utilizar solo las funcionalidades integradas en Odoo. Puedes aprovechar también las ventajas de librerías externas de Python para mejorar tu productividad y facilitar el análisis y procesamiento de datos. Una de estas librerías es Pandas, una herramienta popular y potente para el análisis y manipulación de datos en Python.</p>
<p>Puedes importar Pandas en la shell de Odoo e interactuar con los datos utilizando sus estructuras de datos como DataFrames y Series. Por ejemplo, puedes convertir los registros de un modelo de Odoo en un DataFrame de Pandas y luego realizar análisis y manipulación de datos avanzados. Esto puede ser especialmente útil cuando necesitas generar informes o analizar datos de forma rápida y eficiente.</p>
<p>Recuerda que al usar librerías externas como Pandas, es importante garantizar que estén correctamente instaladas y configuradas en tu entorno de desarrollo y, si es necesario, en el entorno de producción.</p>
<h2 id="heading-conclusion"><strong>Conclusión</strong></h2>
<p>En resumen, la shell de la CLI de Odoo es una herramienta muy útil para los desarrolladores de Odoo que desean profundizar en la programación del ERP. A través de la CLI, podemos interactuar con Odoo de una manera más avanzada y personalizada. Además, al configurar la interfaz de la shell para usar IPython como REPL, podemos aprovechar las funciones avanzadas de IPython y mejorar nuestra experiencia de programación en Odoo.</p>
<p>Espero que este post te haya sido útil y te haya brindado una mejor comprensión de cómo trabajar con la shell de Odoo y configurarla con IPython. Si te ha gustado este post y crees que puede ser útil para otros desarrolladores de Odoo, no dudes en compartirlo en tus redes sociales. Nos vemos en un proximo post donde profundizaremos en el uso de la shell de Odoo.</p>
<p>Si quieren saber mas sobre IPython y la CLI de Odoo, aca les dejo los enlaces a su documentación.</p>
<ul>
<li><p><a target="_blank" href="https://ipython.readthedocs.io/en/stable/">Documentación Oficial de IPython</a></p>
</li>
<li><p><a target="_blank" href="https://www.odoo.com/documentation/master/developer/reference/cli.html">Documentación Oficial de Odoo CLI</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Crea tu propio chatbot con la API de OpenAI y Gradio en Python]]></title><description><![CDATA[Hoy vamos a aprender a crear una aplicación en Python utilizando la API de OpenAI y Gradio. Esta publicación será útil para las personas que quieren aprender a utilizar la API de OpenAI y crear una aplicación con una interfaz de usuario interactiva d...]]></description><link>https://blog.rafnixg.dev/crea-tu-propio-chatbot-con-la-api-de-openai-y-gradio-en-python</link><guid isPermaLink="true">https://blog.rafnixg.dev/crea-tu-propio-chatbot-con-la-api-de-openai-y-gradio-en-python</guid><category><![CDATA[openai]]></category><category><![CDATA[gradio]]></category><category><![CDATA[Python]]></category><category><![CDATA[chatgpt]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Wed, 22 Mar 2023 19:05:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/hZkOZGtlA5w/upload/b8b7ca97aff3fe83363c9b90c6177dd9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hoy vamos a aprender a crear una aplicación en Python utilizando la API de OpenAI y Gradio. Esta publicación será útil para las personas que quieren aprender a utilizar la API de OpenAI y crear una aplicación con una interfaz de usuario interactiva de forma rapida y sin necesidad de usar HTML, CSS y Javscript.</p>
<h2 id="heading-introduccion">Introducción</h2>
<p>Antes de empezar, debemos entender qué es la API de OpenAI y Gradio.</p>
<p><a target="_blank" href="https://openai.com/">OpenAI</a> es una organización de investigación en inteligencia artificial. Ofrecen una API que permite acceder a modelos de inteligencia artificial avanzados para realizar diversas tareas, como responder preguntas, traducir oraciones, resumir noticias y más.</p>
<p>Por otro lado, <a target="_blank" href="https://gradio.app/">Gradio</a> es una herramienta de código abierto para crear interfaces de usuario interactivas para modelos de inteligencia artificial. Ofrece una manera fácil y rápida de crear una interfaz de usuario para cualquier modelo de aprendizaje automático.</p>
<p>Ahora que tenemos una comprensión básica de ambas herramientas, comencemos con el tutorial.</p>
<h2 id="heading-conectando-a-la-api-de-openai"><strong>Conectando a la API de OpenAI</strong></h2>
<p>Para usar la API de OpenAI, necesitamos generar una clave API. Siga estos pasos para obtener su clave API:</p>
<ol>
<li><p>Visite el sitio web de <a target="_blank" href="https://platform.openai.com/signup">OpenAI</a> y regístrese para obtener una cuenta gratuita.</p>
</li>
<li><p>Inicie sesión en su cuenta y vaya a la página de la <a target="_blank" href="https://platform.openai.com/account/api-keys">API</a>.</p>
</li>
<li><p>Cree una nueva clave API y cópiela porque la usaremos mas adelante.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679435437209/e6cc242a-0f2c-40c8-9759-7711c29f276b.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h2 id="heading-instalacion-de-dependencias">Instalación de dependencias</h2>
<p>En este tutorial, crearemos una aplicación de Chatbot utilizando la API de OpenAI y Gradio. Para empezar, necesitamos ubicarnos en la carpeta donde vamos a trabajar nuestro proyecto e instalar ambos paquetes en nuestra máquina. Como un paso previo a la instalación de las dependecias se puede crear un entorno virtual de python para que las librerias no tengan colision con las del sistema:</p>
<pre><code class="lang-bash">python3 -m venv venv
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<p>Luego de activar el entorno virtual, procedemos a instalar las dependencias:</p>
<pre><code class="lang-bash">pip install openai
pip install gradio
</code></pre>
<h2 id="heading-configuracion-de-la-clave-api-de-openai">Configuración de la clave API de OpenAI</h2>
<p>Una vez que tengamos ambos paquetes instalados, podemos comenzar a escribir nuestro código.</p>
<p>Primero, debemos configurar la API de OpenAI para poder acceder a sus servicios. Una vez que tengamos la clave API, podemos configurarla en nuestro código de Python creando un archivo llamado <code>chatbot.py</code> utilizando el siguiente código.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> openai
<span class="hljs-keyword">import</span> os

<span class="hljs-comment"># Obtener la clave API de OpenAI de la variable de entorno</span>
openai.api_key = os.environ.get(<span class="hljs-string">"OPENAI_API_KEY"</span>, <span class="hljs-literal">None</span>)
</code></pre>
<p>Asegúrate de configurar la variable de entorno <code>OPENAI_API_KEY</code> con tu clave API real antes de ejecutar el código, sino en la ultima sección te explico como hacerlo.</p>
<p>Ahora que tenemos la clave API configurada, podemos comenzar a interactuar con la API de OpenAI. En este tutorial, crearemos un chatbot que puede responder a las preguntas de los usuarios.</p>
<h2 id="heading-configuracion-del-mensaje-por-defecto">Configuración del mensaje por defecto</h2>
<p>Para crear un chatbot utilizando la API de OpenAI, necesitamos proporcionar una serie de mensajes como entrada a la API. Cada mensaje es una cadena de texto que representa el mensaje enviado por un usuario o el chatbot. Usaremos un mensaje por defecto para configurar y condicionar las respuesta GPT:</p>
<pre><code class="lang-python">messages = [
    {
        <span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>,
        <span class="hljs-string">"content"</span>: <span class="hljs-string">"Act like a personal assistant. You can respond to questions, translate sentences, summarize news, and give recommendations."</span>
    }
]
</code></pre>
<p>En este ejemplo, el chatbot comienza presentándose como un asistente personal y proporcionando una lista de tareas que puede realizar.</p>
<h2 id="heading-funcion-de-llamada-a-la-api-de-openai">Función de llamada a la API de OpenAI</h2>
<p>Una vez que tenemos los mensajes de entrada preparados, podemos enviarlos a la API de OpenAI para generar una respuesta utilizando el siguiente código.</p>
<pre><code class="lang-python">
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">openai_process_message</span>(<span class="hljs-params">user_message</span>):</span>
    <span class="hljs-comment"># Set the prompt for OpenAI Api</span>
    messages = [
        {
            <span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>,
            <span class="hljs-string">"content"</span>: <span class="hljs-string">"Act like a personal assistant. You can respond to questions, translate sentences, summarize news, and give recommendations."</span>
        }
    ]
    messages.append({<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: user_message})
    <span class="hljs-comment"># Call the OpenAI Api to process our prompt</span>
    openai_response = openai.ChatCompletion.create(model=<span class="hljs-string">"gpt-3.5-turbo"</span>, messages=messages, max_tokens=<span class="hljs-number">2000</span>)
    <span class="hljs-comment"># Parse the response to get the response text for our prompt</span>
    response_text = openai_response.choices[<span class="hljs-number">0</span>].message.content
    <span class="hljs-keyword">return</span> response_text
</code></pre>
<p>La función <code>openai_process_message</code> toma como entrada el mensaje del usuario y lo agrega a la lista de mensajes como un mensaje de usuario. A continuación, llama a la API de OpenAI para procesar los mensajes y generar una respuesta. Por último, la función devuelve la respuesta generada por la API de OpenAI.</p>
<h2 id="heading-creacion-de-la-ui-con-gradio">Creación de la UI con Gradio</h2>
<p>A continuación, crearemos una lista de ejemplos que se utilizarán para mostrar ejemplos en la interfaz de usuario. En este caso, utilizaremos preguntas sobre la inteligencia artificial.</p>
<pre><code class="lang-python">examples = [
    <span class="hljs-string">"Que es la IA?"</span>,
    <span class="hljs-string">"Como funciona una red neuronal?"</span>,
    <span class="hljs-string">"pueden las maquinas aprender?"</span>,
]
</code></pre>
<p>Luego, creamos una instancia de la clase <code>Interface</code> de Gradio y le pasamos la función <code>openai_process_message()</code> como argumento. A continuación, definimos el tipo de entrada y salida que deseamos para nuestra interfaz. En este caso, utilizaremos una caja de texto para la entrada del usuario y otra para mostrar la respuesta del chatbot.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create a Gradio interface instance</span>
demo = gr.Interface(
    fn=openai_process_message,
    inputs=gr.Textbox(lines=<span class="hljs-number">5</span>, label=<span class="hljs-string">'Pregunta'</span>,    placeholder=<span class="hljs-string">'Escribe tu pregunta aquí...'</span>),
    outputs=gr.Textbox(label=<span class="hljs-string">'Respuesta'</span>),
    examples=examples,
    title=<span class="hljs-string">"Chatbot OpenAI API"</span>,
)
</code></pre>
<p>Finalmente, lanzamos la interfaz de usuario utilizando el método <code>launch()</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    demo.launch()
</code></pre>
<h2 id="heading-corriendo-nuestra-aplicacion">Corriendo nuestra aplicación</h2>
<p>Recuerda que antes de lanzar la aplicación, debes configurar la variable de entorno "OPENAI_API_KEY" con tu clave de API de OpenAI. Puedes hacerlo de la siguiente manera en tu terminal:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> OPENAI_API_KEY=&lt;tu_clave_de_api&gt;
</code></pre>
<p>Donde &lt;tu_clave_de_api&gt; debe ser reemplazada con tu clave de API real de OpenAI.</p>
<p>Para lanzar la aplicación, puedes simplemente ejecutar el archivo Python en tu terminal o IDE de Python:</p>
<pre><code class="lang-bash">python chatbot.py
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679438402612/e8a57a90-5afd-4d5e-9dfa-a6ef90d6bd3e.png" alt class="image--center mx-auto" /></p>
<p>Con esto ya tenemos nuestra app corriendo sobre https://127.0.0.1:7860 y con la siguiente UI de forma facil y rapida:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679438572766/7cba6334-d1b2-43bb-b34c-4c60369c4151.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusiones">Conclusiones</h2>
<p>Ahora tenemos una aplicación completa de preguntas y respuestas que utiliza la API de OpenAI para generar respuestas a cualquier pregunta que el usuario pueda tener. Esta aplicación es solo un ejemplo de lo que se puede hacer con la API de OpenAI y la biblioteca Gradio. Hay muchas otras aplicaciones de inteligencia artificial que se pueden crear utilizando estas herramientas.</p>
<p>En un proximo post voy a implementar otra UI usando el componente Chatbot de Gradio para darle un diseño mas acoorde al un chatbot y algunos otros tips a la hora de usar Gradio, por el momento es un buen punto de partida para practicar y probar estas tecnologias.</p>
<h2 id="heading-codigo-fuente">Código Fuente</h2>
<p>Todo el codigo y los pasos para instalar la aplicación estan en mi cuenta de GitHub</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/rafnixg/chatbot_openai_gradio">https://github.com/rafnixg/chatbot_openai_gradio</a></div>
]]></content:encoded></item><item><title><![CDATA[Los servicios que uso en mi HomeLab server: virtualización, contenedores y más.]]></title><description><![CDATA[¡Hola nuevamente! hoy quiero profundizar en cada uno de los servicios y aplicaciones que tengo en mi homelab server y compartirlas contigo.
Introducción
En mi camino como desarrollador y entusiasta de la tecnología, he construido un homelab server en...]]></description><link>https://blog.rafnixg.dev/los-servicios-que-uso-en-mi-homelab-server-virtualizacion-contenedores-y-mas</link><guid isPermaLink="true">https://blog.rafnixg.dev/los-servicios-que-uso-en-mi-homelab-server-virtualizacion-contenedores-y-mas</guid><category><![CDATA[proxmox]]></category><category><![CDATA[self-hosted]]></category><category><![CDATA[cloudflare]]></category><category><![CDATA[Homelab]]></category><category><![CDATA[nginx]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Mon, 20 Mar 2023 23:42:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/EJe6LqEjHpA/upload/769f355c1142c6c1634c19b941d72ddf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¡Hola nuevamente! hoy quiero profundizar en cada uno de los servicios y aplicaciones que tengo en mi homelab server y compartirlas contigo.</p>
<h2 id="heading-introduccion">Introducción</h2>
<p>En mi camino como desarrollador y entusiasta de la tecnología, he construido un homelab server en mi casa para experimentar con nuevas tecnologías y aprender de forma autodidacta. Es un servidor casero donde puedo ejecutar diferentes servicios y herramientas en un ambiente controlado.</p>
<p>En este artículo, compartiré con ustedes los servicios que actualmente estoy corriendo en mi homelab server. Estos servicios incluyen virtualización con Proxmox, contenedores con LXC y Docker, una plataforma como servicio (PaaS) llamada Coolify, un backend as a service (BaaS) llamado Appwrite, Pi-hole para bloquear anuncios y rastreadores, Plausible para analizar las métricas de mi sitio, y mucho más. Si estás interesado en crear tu propio homelab server o simplemente deseas conocer qué servicios estoy usando, sigue leyendo para conocer más.</p>
<h2 id="heading-proxmox-ve"><strong>Proxmox VE</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679354595439/a606ff2f-6af1-497c-9a35-71f59a74bc02.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://www.proxmox.com/">Proxmox VE</a> es una plataforma de virtualización de código abierto que utilizo para virtualizar y administrar mis servidores. Proxmox me permite crear y gestionar contenedores Linux (LXC) y máquinas virtuales (VM), lo que me brinda una gran flexibilidad y ahorro de recursos en mi homelab server.</p>
<p>Los contenedores LXC son una forma ligera y eficiente de virtualización que me permiten ejecutar múltiples servicios en mi homelab server de manera aislada y segura. Por otro lado, las máquinas virtuales son una forma más tradicional de virtualización que me permiten ejecutar sistemas operativos completos en mi homelab server, lo que es útil para probar diferentes configuraciones y experimentar con nuevas tecnologías.</p>
<p>Proxmox tiene una interfaz web fácil de usar que me permite crear y gestionar mis contenedores LXC y máquinas virtuales de manera sencilla. También cuenta con una comunidad activa y una amplia documentación que me ha sido de gran ayuda a lo largo del tiempo.</p>
<h2 id="heading-coolify"><strong>Coolify</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679354733424/3149397a-9f00-444b-844d-2d918f1d7a94.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://coolify.io/">Coolify</a> es una plataforma como servicio (PaaS) que utilizo para alojar mi sitio web. Es una alternativa a Heroku, pero self-hosted, lo que me brinda más control y flexibilidad. Dentro de Coolify, tengo desplegado mi sitio <a target="_blank" href="https://rafnixg.dev">web</a>. Además, utilizo Appwrite, un Backend as a Service (BaaS) del que hablare mas adelante y algunas aplicaciones desplegadas usando docker.</p>
<h2 id="heading-appwrite"><strong>Appwrite</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679354761054/c8fd9ad7-b7a9-44e1-8a5a-0cb47d698f52.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://appwrite.io/">Appwrite</a> es un Backend as a Service (BaaS) que utilizo para gestionar mi sitio web. Me ayuda a manejar fácilmente usuarios, bases de datos y autenticación en mi sitio web, lo que me ahorra mucho tiempo y esfuerzo. Appwrite es muy fácil de integrar con Coolify, y tiene una interfaz de usuario web muy intuitiva.</p>
<h2 id="heading-plausible"><strong>Plausible</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679354407326/3617b113-832c-4f33-bd2f-ba2709e781c8.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://plausible.io/">Plausible</a> es una herramienta de análisis web de código abierto que utilizo para analizar las métricas de mi sitio web. Es una alternativa a Google Analytics, pero más centrada en la privacidad. Plausible utiliza una arquitectura simple y ligera que no rastrea a los usuarios y no recopila información personal. Plausible me brinda información detallada sobre el tráfico de mi sitio web, como la cantidad de visitas, la ubicación geográfica de los visitantes y el tiempo promedio en el sitio.</p>
<h2 id="heading-portainer"><strong>Portainer</strong></h2>
<p><img src="https://www.portainer.io/hubfs/Edge%20Aug22/edge-mockup.png" alt="Portainer User Interface - Multiple endpoints" /></p>
<p><a target="_blank" href="https://www.portainer.io/">Portainer</a> es una herramienta de gestión de contenedores de Docker que utilizo para administrar y supervisar mis contenedores. Portainer tiene una interfaz de usuario web que me permite ver fácilmente el estado de mis contenedores, administrar imágenes y supervisar logs. Utilizo Portainer para gestionar Pi-Hole y otros servicios como el speedtracker en mi homelab server.</p>
<h2 id="heading-pi-hole"><strong>Pi-Hole</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679354884844/267bfbbc-b436-43b2-8fbf-6e749f0df02b.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://pi-hole.net/">Pi-hole</a> es una aplicación de bloqueo de anuncios y rastreadores en Internet que utilizo para proteger mi navegación web y reducir la cantidad de anuncios. Pi-Hole utiliza una lista de bloqueo de anuncios actualizada regularmente para bloquear anuncios en todos mis dispositivos de red. Pi-hole funciona bloqueando las solicitudes de DNS de anuncios y rastreadores, lo que significa que la mayoría de los anuncios y rastreadores simplemente no se cargan.</p>
<p>En mi homelab server, utilizo Pi-hole como mi servidor de DNS local y bloqueador de anuncios y rastreadores. Pi-hole es fácil de configurar y puedo personalizar las listas de bloqueo de anuncios y rastreadores según mis necesidades. También puedo ver estadísticas detalladas sobre los dominios bloqueados y la cantidad de solicitudes de DNS procesadas por Pi-hole. Es una herramienta útil para mantener la privacidad y seguridad en mi red doméstica.</p>
<h2 id="heading-speedtest-tracker"><strong>Speedtest Tracker</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679354922703/afb58053-71c3-4ce7-801d-6c62a6ad0355.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://docs.speedtest-tracker.dev/">Speedtest Tracker</a> es una herramienta de monitoreo de velocidad de internet que utilizo para supervisar la velocidad de mi conexión a internet. Speedtest Tracker se ejecuta en un contenedor de Docker y utiliza Speedtest CLI para realizar pruebas de velocidad en intervalos regulares. Speedtest Tracker me brinda información detallada sobre la velocidad de mi conexión a internet, como la velocidad de descarga, la velocidad de carga y la latencia. También puedo ver gráficas de tendencias y estadísticas de velocidad a lo largo del tiempo.</p>
<h2 id="heading-cloudflare-tunnels"><strong>Cloudflare Tunnels</strong></h2>
<p>Cloudflare Tunnels es un servicio que utilizo para conectar mis contenedores y mi dominio. Con Cloudflare Tunnels, puedo acceder a mis servicios de forma segura desde cualquier lugar, sin tener que preocuparme por abrir puertos en mi firewall. Cloudflare Tunnels también me ayuda a ocultar la dirección IP de mi servidor, lo que aumenta mi privacidad y seguridad. Si quieres conocer más acerca de Cloudflare Tunnels, puedes visitar <a target="_blank" href="https://developers.cloudflare.com/cloudflare-one/tutorials/share-localhost-on-the-internet"><strong>su sitio web</strong></a>.</p>
<h2 id="heading-nginx-proxy-manager"><strong>Nginx Proxy Manager</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679355046298/fb56717b-721d-422f-bf9c-6c140bfbe487.png" alt class="image--center mx-auto" /></p>
<p>Nginx Proxy Manager es una herramienta de gestión de proxies que utilizo para gestionar la redirección en dominios locales junto con Pi-Hole. Nginx Proxy Manager tiene una interfaz de usuario web sencilla que me permite configurar fácilmente proxies y redirecciones para mis servicios en contenedores. Además, Nginx Proxy Manager me ayuda a asegurar mis servicios al permitirme configurar SSL/TLS para mis dominios. Si estás interesado en conocer más sobre Nginx Proxy Manager, puedes visitar <a target="_blank" href="https://nginxproxymanager.com/"><strong>su sitio web</strong></a>.</p>
<h2 id="heading-resumen">Resumen</h2>
<p>En mi homelab server, tengo configurados varios servicios para llevar a cabo diversas tareas. Proxmox me permite virtualizar y administrar mis servidores, y utilizo tanto contenedores LXC como máquinas virtuales para ejecutar diferentes servicios y experimentar con nuevas tecnologías.</p>
<p>Coolify es una plataforma como servicio que utilizo para alojar mi sitio web, con un backend as a service llamado Appwrite para manejar usuarios y bases de datos. Para analizar las métricas de mi sitio, utilizo Plausible, y para bloquear anuncios y rastreadores en mi red, utilizo Pi-hole.</p>
<p>Además, utilizo Cloudflare Tunnels para conectar mis contenedores dentro de mi servidor y mi dominio de forma segura, y Nginx Proxy Manager para gestionar la redirección en dominios locales junto con Pi-hole.</p>
<p>En resumen, estos son los servicios que tengo en mi homelab server y que me permiten experimentar con diferentes tecnologías y aplicaciones en un entorno seguro y controlado. Si estás interesado en crear tu propio homelab server, te recomiendo comenzar con algunos de estos servicios y experimentar para encontrar lo que mejor se adapte a tus necesidades. ¡Que disfrutes la creación de tu homelab server!</p>
]]></content:encoded></item><item><title><![CDATA[Creando un entorno de desarrollo para Odoo 14.0 con VSCode en Ubuntu 22.04]]></title><description><![CDATA[En este artículo aprenderás a configurar un entorno de desarrollo para Odoo 14.0 en Ubuntu 22.04. Si estás leyendo esto, probablemente ya sabes que Odoo es un ERP basado en Python, PostgreSQL y XML que permite a las empresas gestionar sus procesos em...]]></description><link>https://blog.rafnixg.dev/creando-un-entorno-de-desarrollo-para-odoo-140-con-vscode-en-ubuntu-2204</link><guid isPermaLink="true">https://blog.rafnixg.dev/creando-un-entorno-de-desarrollo-para-odoo-140-con-vscode-en-ubuntu-2204</guid><category><![CDATA[Odoo]]></category><category><![CDATA[vscode]]></category><category><![CDATA[Python]]></category><category><![CDATA[odoo developer]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Tue, 14 Mar 2023 13:00:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/f77Bh3inUpE/upload/bf647ff9837c4d4b1c50314394b07e63.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En este artículo aprenderás a configurar un entorno de desarrollo para Odoo 14.0 en Ubuntu 22.04. Si estás leyendo esto, probablemente ya sabes que Odoo es un ERP basado en Python, PostgreSQL y XML que permite a las empresas gestionar sus procesos empresariales de manera integrada.</p>
<p>Antes de empezar con la configuración del entorno de desarrollo, asegúrate de tener instalado los siguientes requisitos previos: Python 3, Git, PostgreSQL y VSCode. Si aún no los tienes, puedes seguir los siguientes enlaces para instalarlos:</p>
<ul>
<li><p>Python 3: <a target="_blank" href="https://www.python.org/downloads/"><strong>https://www.python.org/downloads/</strong></a></p>
</li>
<li><p>Git: <a target="_blank" href="https://git-scm.com/downloads"><strong>https://git-scm.com/downloads</strong></a></p>
</li>
<li><p>PostgreSQL: <a target="_blank" href="https://www.postgresql.org/download/"><strong>https://www.postgresql.org/download/</strong></a></p>
</li>
<li><p>VSCode: <a target="_blank" href="https://code.visualstudio.com/download"><strong>https://code.visualstudio.com/download</strong></a></p>
</li>
</ul>
<p>Una vez que tengas estos requisitos previos instalados, estás listo para empezar a configurar tu entorno de desarrollo de Odoo. En este post, te enseñare cómo crear una estructura de carpetas adecuada para trabajar con Odoo y cómo configurar VSCode para poder debuggear el código.</p>
<h2 id="heading-instalacion-de-postgresql">Instalación de PostgreSQL</h2>
<p>Para trabajar con Odoo, necesitarás tener instalado PostgreSQL. PostgreSQL es un sistema de gestión de bases de datos relacional de código abierto. Para instalar PostgreSQL en Ubuntu/Debian, puede seguir los siguientes pasos en la terminal:</p>
<pre><code class="lang-bash">sudo apt update
sudo apt upgrade
sudo apt install postgresql postgresql-client
sudo -u postgres createuser -s <span class="hljs-variable">$USER</span>
createdb odoo-dev-14.0
</code></pre>
<ul>
<li><p><code>sudo apt update</code>: Este comando se utiliza para actualizar la lista de paquetes disponibles en los repositorios de Ubuntu/Debian. Es importante ejecutar este comando antes de instalar cualquier software nuevo en Ubuntu para asegurarse de que se están utilizando las versiones más recientes de los paquetes disponibles.</p>
</li>
<li><p><code>sudo apt upgrade</code>: Este comando se utiliza para actualizar los paquetes existentes en el sistema operativo. Al ejecutar este comando, se descargarán e instalarán las actualizaciones disponibles para todos los paquetes instalados en el sistema.</p>
</li>
<li><p><code>sudo apt install postgresql postgresql-client</code>: Estos comandos se utilizan para instalar PostgreSQL y su cliente en el sistema operativo. PostgreSQL es un sistema de gestión de bases de datos relacionales que se utiliza comúnmente como base de datos para Odoo.</p>
</li>
<li><p><code>sudo -u postgres createuser -s $USER</code>: Este comando se utiliza para crear un usuario en PostgreSQL con todos los privilegios necesarios para trabajar con Odoo. El comando se ejecuta como el usuario "postgres", que es el usuario por defecto de PostgreSQL. <code>$USER</code> es una variable de entorno que contiene el nombre de usuario actual.</p>
</li>
<li><p><code>createdb odoo-dev-14.0</code>: Este comando se utiliza para crear una nueva base de datos en PostgreSQL llamada "odoo-dev-14.0". Esta será la base de datos que se utilizará para desarrollar y probar Odoo en este entorno de desarrollo.</p>
</li>
</ul>
<p>Es importante destacar que después de la instalación, es necesario realizar algunas configuraciones de seguridad adicionales para garantizar la protección de los datos de la empresa. Sin embargo, para fines de este tutorial y dado que nos encontramos en un ambiente de desarrollo, no profundizaremos en este aspecto</p>
<h2 id="heading-instalacion-de-dependencias">Instalación de dependencias</h2>
<p>Antes de empezar a trabajar con Odoo, necesitamos instalar algunas dependencias en nuestro sistema operativo. Para hacerlo, podemos seguir las instrucciones <a target="_blank" href="https://www.odoo.com/documentation/14.0/es/administration/install/install.html#id14">oficiales</a> que recomiendan utilizar los siguientes comandos en la terminal:</p>
<pre><code class="lang-bash">sudo apt update
sudo apt upgrade
sudo apt install python3-dev python3-pip python3-venv libxml2-dev \
libxslt1-dev libldap2-dev libsasl2-dev libtiff5-dev \
libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev \
liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev libxcb1-dev libpq-dev
</code></pre>
<p>Estos comandos nos permitirán instalar todas las dependencias necesarias para trabajar con Odoo en nuestro sistema Ubuntu 22.04. Es importante asegurarse de que todas las dependencias se instalen correctamente antes de continuar con la configuración de nuestro entorno de desarrollo.</p>
<h2 id="heading-creacion-de-la-estructura-de-carpetas">Creación de la estructura de carpetas</h2>
<p>Una vez instalado PostgreSQL y las dependencias necesarias, es hora de crear una estructura de carpetas para trabajar con Odoo. Para ello, ejecuta en la terminal el siguiente comando:</p>
<pre><code class="lang-bash">mkdir -p ~/Odoo/{src,workspaces,instances,instances/odoo-dev-14.0}
</code></pre>
<p>Esta una forma abreviada de crear varias carpetas a la vez utilizando llaves y una lista de nombres de carpeta separados por comas.</p>
<p>En este caso, el comando crea una estructura de carpetas dentro de la carpeta principal del usuario (representado por el símbolo "~" que se refiere al directorio de inicio del usuario) con los siguientes nombres de carpeta:</p>
<ul>
<li><p>src</p>
</li>
<li><p>workspaces</p>
</li>
<li><p>instances</p>
</li>
<li><p>instances/odoo-dev-14.0</p>
</li>
</ul>
<p>La opción "-p" indica que se crearán todas las carpetas necesarias en la ruta, incluso si algunas de ellas ya existen. De esta manera, se crea una estructura de carpetas adecuada para trabajar con Odoo y se asegura de que todas las carpetas necesarias estén disponibles en el directorio de inicio del usuario.</p>
<h2 id="heading-instalacion-de-odoo-140">Instalación de Odoo 14.0</h2>
<p>Ahora que hemos instalado PostgreSQL, Python y las dependencias necesarias, podemos proceder a instalar Odoo.</p>
<h3 id="heading-descargar-el-codigo-fuente-de-odoo-140">Descargar el código fuente de Odoo 14.0</h3>
<p>Para descargar el código fuente de Odoo 14.0, ejecuta en la terminal el siguiente comando:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/odoo/odoo.git --single-branch --depth 1 --branch 14.0 ~/Odoo/src/14.0
</code></pre>
<p>Este comando descargará el código fuente de Odoo 14.0 en la carpeta <code>~/Odoo/src/14.0</code>.</p>
<p>El parámetro --single-branch indica que solo se clonará la rama especificada en lugar de todas las ramas del repositorio. El parámetro --depth 1 indica que solo se clonará el historial más reciente del repositorio, lo que reduce el tiempo y espacio necesarios para la descarga.</p>
<h3 id="heading-crear-un-entorno-virtual">Crear un entorno virtual</h3>
<p>Para crear un entorno virtual de Python para Odoo, ejecute el siguiente comando:</p>
<pre><code class="lang-bash">python3 -m venv ~/Odoo/instances/odoo-dev-14.0/venv
</code></pre>
<p>Este comando creará un entorno virtual para Odoo en la carpeta <code>~/Odoo/instances/odoo-dev-14.0/venv</code>.</p>
<h3 id="heading-instalar-las-dependencias-de-odoo">Instalar las dependencias de Odoo</h3>
<p>Para instalar las dependencias de python para Odoo, ejecute los siguientes comandos:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> ~/Odoo/instances/odoo-dev-14.0/venv/bin/activate
pip3 install setuptools wheel inotify psycopg2-binary
pip3 install -r ~/Odoo/src/14.0/requirements.txt
deactivate
</code></pre>
<p>Estos comandos activarán el entorno virtual de Odoo, instalarán las dependencias necesarias y desactivarán el entorno virtual.</p>
<ol>
<li><p><code>source ~/Odoo/instances/odoo-dev-14.0/venv/bin/activate</code>: este comando activa el entorno virtual de Odoo para que puedas instalar las dependencias necesarias sin afectar al sistema operativo.</p>
</li>
<li><p><code>pip3 install setuptools wheel inotify psycopg2-binary</code>: estos son paquetes de Python necesarios para ejecutar Odoo. <code>setuptools</code> y <code>wheel</code> son herramientas de construcción de paquetes, <code>inotify</code> es una biblioteca para monitorear cambios en archivos y directorios, y <code>psycopg2-binary</code> es un controlador de base de datos PostgreSQL para Python.</p>
</li>
<li><p><code>pip3 install -r ~/Odoo/src/14.0/requirements.txt</code>: este comando instala todas las dependencias adicionales requeridas por Odoo, que están enumeradas en el archivo <code>requirements.txt</code>. El prefijo <code>-r</code> significa "de un archivo de requisitos".</p>
</li>
<li><p><code>deactivate</code>: este comando desactiva el entorno virtual de Odoo, lo que significa que ya no se están utilizando las dependencias instaladas en dicho entorno.</p>
</li>
</ol>
<p>Con estos pasos, hemos instalado Odoo 14.0 en nuestro entorno de desarrollo de Ubuntu 22.04. Ahora podemos empezar a trabajar con Odoo y personalizarlo según nuestras necesidades.</p>
<h3 id="heading-crear-el-archivo-de-configuracion-de-odoo">Crear el archivo de configuración de Odoo</h3>
<p>Después de haber creado el entorno virtual de Python y haber instalado las dependencias necesarias, el siguiente paso es configurar Odoo para que se ejecute correctamente en el entorno virtual. Para esto, es necesario crear un archivo de configuración específico para su instancia de Odoo.</p>
<p>Para crear el archivo de configuración, ejecute los siguientes comandos:</p>
<pre><code class="lang-bash">cp ~/Odoo/src/14.0/debian/odoo.conf ~/Odoo/instances/odoo-dev-14.0 
sed -i <span class="hljs-string">'s/db_user = odoo/db_user = '</span><span class="hljs-variable">$USER</span><span class="hljs-string">'/'</span> ~/Odoo/instances/odoo-dev-14.0/odoo.conf
</code></pre>
<p>El primer comando copia el archivo de configuración predeterminado de Odoo a la carpeta de su instancia de Odoo. El segundo comando utiliza el comando "sed" para reemplazar el usuario de la base de datos predeterminado de "odoo" por el usuario actual. Esto es necesario para que Odoo pueda acceder a la base de datos en el entorno virtual.</p>
<p>Una vez que haya creado el archivo de configuración de Odoo, podrá personalizarlo para adaptarlo a sus necesidades específicas. Puede configurar la dirección IP, el puerto, la base de datos y otras opciones para su instancia de Odoo si ya tenia una instalación de PostgreSQL.</p>
<h2 id="heading-inicializar-la-base-de-datos-de-odoo"><strong>Inicializar la base de datos de Odoo</strong></h2>
<p>Una vez que se han instalado las dependencias de Odoo y se ha creado el archivo de configuración, el siguiente paso es inicializar la base de datos de Odoo. Para hacer esto, se utilizará el comando:</p>
<pre><code class="lang-bash">~/Odoo/instances/odoo-dev-14.0/venv/bin/python3 ~/Odoo/src/14.0/odoo-bin -c ~/Odoo/instances/odoo-dev-14.0/odoo.conf -d odoo-dev-14.0 -i base --stop-after-init
</code></pre>
<p>Este comando ejecuta el archivo <code>odoo-bin</code> que se encuentra en la carpeta <code>src/14.0</code> del directorio raíz de Odoo. El parámetro <code>-c</code> especifica la ruta del archivo de configuración de Odoo que se creó anteriormente. El parámetro <code>-d</code> especifica el nombre de la base de datos que se creará e inicializará. En este caso, se está utilizando <code>odoo-dev-14.0</code>.</p>
<p>El parámetro <code>-i</code> indica los módulos de Odoo que se instalarán. En este caso, solo se está instalando el módulo base de Odoo. Sin embargo, es posible agregar más módulos separándolos por comas.</p>
<p>Finalmente, el parámetro <code>--stop-after-init</code> detiene el servidor de Odoo después de inicializar la base de datos. Esto es útil si solo se desea inicializar la base de datos y no ejecutar el servidor completo de Odoo.</p>
<p>Una vez que se ejecuta este comando, se creará y se inicializará la base de datos de Odoo. Este proceso puede tardar unos minutos, dependiendo de la velocidad de su computadora.</p>
<h2 id="heading-configuracion-del-debugger-de-vscode-para-odoo-140">Configuración del debugger de VSCode para Odoo 14.0</h2>
<p>Una herramienta útil para desarrollar en Odoo es el debugger de Visual Studio Code (VSCode), que permite depurar código en tiempo real. A continuación, se muestra cómo configurar el debugger de VSCode para trabajar con Odoo 14.0.</p>
<ol>
<li><p>Abre Visual Studio Code en la carpta de la instancia <code>~/Odoo/instances/odoo-dev-14.0/</code> y haz clic en la pestaña "Debug" en la barra lateral izquierda.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678753259740/c30934dc-32b9-44ee-8952-84074af4430d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Haz clic en el botón "cree un archivo <code>launch.json</code>" en la parte inferior de la pestaña "Debug".</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1678753416525/8f98379f-5b41-45e3-aec4-ca3634d20082.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Copia y pega el siguiente código en el archivo "launch.json" que se ha creado:</p>
</li>
</ol>
<pre><code class="lang-json">{
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.2.0"</span>,
    <span class="hljs-attr">"configurations"</span>: [
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"odoo-dev-14.0"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"python"</span>,
            <span class="hljs-attr">"request"</span>: <span class="hljs-string">"launch"</span>,
            <span class="hljs-attr">"program"</span>: <span class="hljs-string">"~/Odoo/src/14.0/odoo-bin"</span>,
            <span class="hljs-attr">"console"</span>: <span class="hljs-string">"integratedTerminal"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"-c"</span>,<span class="hljs-string">"~/Odoo/instances/odoo-dev-14.0/odoo.conf"</span>,
                <span class="hljs-string">"--limit-time-real"</span>, <span class="hljs-string">"99999"</span>,
                <span class="hljs-string">"-d"</span>, <span class="hljs-string">"odoo-dev-14.0"</span>
            ]
        },
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"odoo-dev-14.0-install-addons"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"python"</span>,
            <span class="hljs-attr">"request"</span>: <span class="hljs-string">"launch"</span>,
            <span class="hljs-attr">"program"</span>: <span class="hljs-string">"~/Odoo/src/14.0/odoo-bin"</span>,
            <span class="hljs-attr">"console"</span>: <span class="hljs-string">"integratedTerminal"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"-c"</span>,<span class="hljs-string">"~/Odoo/instances/odoo-dev-14.0/odoo.conf"</span>,
                <span class="hljs-string">"--limit-time-real"</span>, <span class="hljs-string">"99999"</span>,
                <span class="hljs-string">"-d"</span>, <span class="hljs-string">"odoo-dev-14.0"</span>,
                <span class="hljs-string">"-i"</span>,<span class="hljs-string">""</span>,
                <span class="hljs-string">"--stop-after-init"</span>
            ]
        },
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"odoo-dev-14.0-update-addons"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"python"</span>,
            <span class="hljs-attr">"request"</span>: <span class="hljs-string">"launch"</span>,
            <span class="hljs-attr">"program"</span>: <span class="hljs-string">"~/Odoo/src/14.0/odoo-bin"</span>,
            <span class="hljs-attr">"console"</span>: <span class="hljs-string">"integratedTerminal"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"-c"</span>,<span class="hljs-string">"~/Odoo/instances/odoo-dev-14.0/odoo.conf"</span>,
                <span class="hljs-string">"--limit-time-real"</span>, <span class="hljs-string">"99999"</span>,
                <span class="hljs-string">"-d"</span>, <span class="hljs-string">"odoo-dev-14.0"</span>,
                <span class="hljs-string">"-u"</span>,<span class="hljs-string">""</span>,
                <span class="hljs-string">"--stop-after-init"</span>
            ]
        },
        {
            <span class="hljs-attr">"name"</span>: <span class="hljs-string">"odoo-dev-14.0-repl"</span>,
            <span class="hljs-attr">"type"</span>: <span class="hljs-string">"python"</span>,
            <span class="hljs-attr">"request"</span>: <span class="hljs-string">"launch"</span>,
            <span class="hljs-attr">"program"</span>: <span class="hljs-string">"~/Odoo/src/14.0/odoo-bin"</span>,
            <span class="hljs-attr">"console"</span>: <span class="hljs-string">"integratedTerminal"</span>,
            <span class="hljs-attr">"args"</span>: [
                <span class="hljs-string">"shell"</span>,
                <span class="hljs-string">"-c"</span>,<span class="hljs-string">"~/Odoo/instances/odoo-dev-14.0/odoo.conf"</span>,
                <span class="hljs-string">"--limit-time-real"</span>, <span class="hljs-string">"99999"</span>,
                <span class="hljs-string">"--xmlrpc-port"</span>,<span class="hljs-string">"8888"</span>,
                <span class="hljs-string">"--longpolling-port"</span>,<span class="hljs-string">"8899"</span>,
                <span class="hljs-string">"-d"</span>, <span class="hljs-string">"odoo-dev-14.0"</span>,
                <span class="hljs-string">"--shell-interface"</span>, <span class="hljs-string">"ipython"</span>
            ]
        }
    ]
}
</code></pre>
<ol>
<li>Ahora, puedes elegir una de las siguientes opciones de configuración del debugger:</li>
</ol>
<ul>
<li><p>odoo-dev-14.0: esta opción inicia Odoo en modo de desarrollo con la base de datos "odoo-dev-14.0".</p>
</li>
<li><p>odoo-dev-14.0-install-addons: esta opción instala los módulos de Odoo que agregemos al parametro "-i", en la base de datos "odoo-dev-14.0".</p>
</li>
<li><p>odoo-dev-14.0-update-addons: esta opción actualiza los módulos de Odoo que agregemos al parametro "-u", en la base de datos "odoo-dev-14.0".</p>
</li>
<li><p>odoo-dev-14.0-repl: esta opcion inicia Odoo en modo de consola interactiva (REPL) donde puedes ejecutar comandos del ORM</p>
</li>
</ul>
<p>El parametro "--limit-time-real" establece el tiempo máximo permitido para la ejecución de una solicitud de servidor en Odoo, con un valor de "99999" establece este límite en un tiempo muy alto, prácticamente ilimitado. Esto es útil durante el desarrollo, ya que nos permite depurar el código sin interrupciones debido a la expiración del tiempo límite de Odoo</p>
<p>Con la configuración adecuada, podemos utilizar el debugger de VSCode para solucionar problemas en el código de Odoo y mejorar la calidad del software. Además, al tener un debugger integrado en su entorno de desarrollo, pueden ahorrar tiempo y mejorar la eficiencia de su trabajo.</p>
<p>Espero que este tutorial haya sido útil para aquellos que buscan configurar el debugger de VSCode para trabajar con Odoo 14.0. Si tienes alguna pregunta o comentario, no dudes en escribirme.</p>
]]></content:encoded></item><item><title><![CDATA[Creando tu primer HomeLab Server: Consideraciones clave para empezar]]></title><description><![CDATA[¿Estás interesado en crear tu propio homelab server pero no sabes por dónde empezar? Aquí te presentamos algunas consideraciones clave que debes tener en cuenta para planificar y armar tu homelab.
Por qué tener un homelab es importante
Un homelab es ...]]></description><link>https://blog.rafnixg.dev/creando-tu-primer-homelab-server-consideraciones-clave-para-empezar</link><guid isPermaLink="true">https://blog.rafnixg.dev/creando-tu-primer-homelab-server-consideraciones-clave-para-empezar</guid><category><![CDATA[Homelab]]></category><category><![CDATA[self-hosted]]></category><category><![CDATA[spanish]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Fri, 10 Mar 2023 00:15:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9wWX_jwDHeM/upload/93d501946d16f0753fb178d4394d8c21.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>¿Estás interesado en crear tu propio homelab server pero no sabes por dónde empezar? Aquí te presentamos algunas consideraciones clave que debes tener en cuenta para planificar y armar tu homelab.</p>
<h2 id="heading-por-que-tener-un-homelab-es-importante">Por qué tener un homelab es importante</h2>
<p>Un homelab es una infraestructura de tecnología personal que te permite experimentar y aprender de una manera práctica cómo funcionan diferentes sistemas operativos, aplicaciones y servicios. Además, tener tu propio homelab te da la libertad de tener el control total sobre tus aplicaciones, datos y recursos. También te permite realizar pruebas en un ambiente controlado y seguro sin afectar los sistemas de producción en una empresa.</p>
<h2 id="heading-no-es-necesario-hardware-empresarial">No es necesario hardware empresarial</h2>
<p>A menudo, la gente piensa que es necesario tener hardware empresarial costoso para crear un homelab server. Sin embargo, esto no es cierto. Para proyectos personales o pequeñas empresas, no es necesario tener un servidor costoso y de alta gama. Un equipo de escritorio potente puede ser suficiente para comenzar, siempre y cuando se planifique cuidadosamente la configuración de hardware.</p>
<h2 id="heading-como-planificar-el-armado-de-tu-homelab-server">Cómo planificar el armado de tu homelab server</h2>
<p>Antes de planificar la configuración de hardware para tu homelab server, debes tener claro el objetivo de tu homelab y los proyectos que deseas ejecutar. Esto te permitirá determinar los requerimientos de hardware que vas a necesitar. A continuación, algunos factores clave que debes considerar:</p>
<h3 id="heading-procesador">Procesador</h3>
<p>El procesador es uno de los componentes más importantes de cualquier servidor. Se recomienda tener al menos un procesador de multiples nucleos, minimo 2. Para un mejor rendimiento, se recomienda optar por procesadores de la serie i7 de Intel o la serie Ryzen 7 de AMD estos proporcionará suficiente potencia de procesamiento para ejecutar varias aplicaciones y servicios simultáneamente.</p>
<h3 id="heading-ram">RAM</h3>
<p>La memoria RAM es otro componente crítico en la construcción de un homelab server, especialmente si planeas ejecutar varias máquinas virtuales al mismo tiempo. Se recomienda tener al menos 16 GB o 32 GB de RAM para asegurar un rendimiento óptimo. Si tienes un presupuesto ajustado, puedes empezar con 8 GB de RAM y luego actualizar a medida que sea necesario.</p>
<h3 id="heading-almacenamiento">Almacenamiento</h3>
<p>En cuanto al almacenamiento, hay varias opciones disponibles. Aunque los SSD son más rápidos y fiables que los discos duros tradicionales (HDD), también son más caros. Para proyectos personales o pequeñas empresas, un disco duro HDD de alta capacidad puede ser una opción más económica. Un disco duro de 1 TB o más es suficiente para la mayoría de las necesidades de almacenamiento.</p>
<h3 id="heading-conexion-a-red">Conexión a red</h3>
<p>La conexión a red es crucial para el rendimiento del servidor. Asegúrate de tener una tarjeta de red Gigabit Ethernet para un rendimiento óptimo. Si planeas configurar tu servidor como un router o firewall, considera utilizar una tarjeta de red con múltiples puertos.</p>
<h2 id="heading-equipos-pre-armados-de-bajo-consumo">Equipos pre-armados de bajo consumo</h2>
<p>Existen diversas opciones de equipos pre-armados de poco consumo que pueden ser utilizados como servidores para proyectos personales o pequeñas empresas:</p>
<ul>
<li><p>Raspberry Pi: La Raspberry Pi es una pequeña computadora de bajo costo que consume muy poca energía. Es perfecta para ejecutar aplicaciones de servidor livianas.</p>
</li>
<li><p>Odroid: Odroid es otra pequeña computadora similar a la Raspberry Pi. También consume muy poca energía y es capaz de ejecutar aplicaciones de servidor.</p>
</li>
</ul>
<p>Crear tu propio servidor homelab puede ser una experiencia emocionante y valiosa. Te permite aprender y experimentar en un entorno controlado, lo que te ayuda a desarrollar habilidades útiles en el mundo de la tecnología e informática.</p>
]]></content:encoded></item><item><title><![CDATA[Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 3]]></title><description><![CDATA[Si aun no has leído las otras dos partes te invito a que las revises:

Crear nuestro README en GitHub

Escribir un script en python para crear nuestro README dinámico


En esta tercera entrega vamos a automatizar mediante GitHub Actions la generación...]]></description><link>https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-3</link><guid isPermaLink="true">https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-3</guid><category><![CDATA[Python]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[README]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Sun, 09 Aug 2020 00:59:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/MAYEkmn7G6E/upload/d6bf961a729b1007baf04287606f07d0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Si aun no has leído las otras dos partes te invito a que las revises:</p>
<ul>
<li><p><a target="_blank" href="https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-1">Crear nuestro README en GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-2">Escribir un script en python para crear nuestro README dinámico</a></p>
</li>
</ul>
<p>En esta tercera entrega vamos a automatizar mediante GitHub Actions la generación de nuestro archivo README.md ejecutando de forma programada nuestro script de Python que creamos en la publicación anterior.</p>
<p>GitHub Actions es una funcionalidad de GitHub que nos permite automatizar flujos de desarrollo directamente en nuestro repositorio de código, lo que nos da la ventaja de poder crear nuestros propios flujos y trabajos a ejecutar.</p>
<p>Al estar integrado con nuestro repositorio de código, tenemos la ventaja de poder crear nuestros flujos de trabajo de CI/CD, en esta publicación no profundizaremos en este tipo de implementaciones, pero si haremos uso de GitGub Actions para ejecutar nuestro propio flujo que consiste en ejecutar un script de Python y realizar un <strong>PUSH</strong> a nuestro repositorio de datos cuando exista un cambio en el archivo README.md.</p>
<h2 id="heading-creando-nuestro-primer-github-actions">Creando nuestro primer GitHub Actions</h2>
<p>Para poder activar esta funcionalidad solo debemos crear un directorio en la raíz de nuestro proyecto llamado <em>.github</em> dentro de este directorio creamos otro directorio llamado <strong><em>workflows</em></strong>*.*</p>
<pre><code class="lang-bash">mkdir .github 
<span class="hljs-built_in">cd</span> .github 
mkdir workflows
</code></pre>
<p>Ya con esto podemos comenzara crear nuestro <strong>workflow</strong> usando un archivo YAML, para este caso mi archivo se va a llamar <a target="_blank" href="https://github.com/rafnixg/rafnixg/blob/master/.github/workflows/python-app.yml"><em>python-app.yml</em></a> pero puede tener el nombre que ustedes quieran.</p>
<p>Si hacemos un push al repositorio y revisamos el tab de "Actions" veremos nuestro <strong>workflow</strong> y estará en un estado de falla ya que aun no hemos agregado ningún trabajo ni los pasos a seguir.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Raíz del proyecto </span>
git add .github/workflows/python-app.yml 
git commit -m <span class="hljs-string">"[ADD] new workflow for GitHub Actions"</span> 
git push origin master
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625600269425/37-YsGPMGv.png" alt="GitHub Actions tab" /></p>
<p>Para editar nuestro archivo lo haremos directamente desde GitHub para aprovechar el auto completado y otras herramientas que tiene GitHub para la creación de Actions, al abrir nuestro archivo escribimos lo siguiente:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625600271286/ryIhk_9kI.png" alt="Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 3" /></p>
<p>Acá podemos ver del lado derecho un panel que nos puede ayudar a buscar Actions creadas por la comunidad y también nos muestra la documentación de GitHub Actions.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Python</span> <span class="hljs-string">workflow</span> <span class="hljs-comment"># Nombre del workflow</span>
<span class="hljs-attr">on:</span> <span class="hljs-comment"># llave que indica que se realizara una acción sobre algun evento </span>
  <span class="hljs-attr">schedule:</span> <span class="hljs-comment"># El evento que ejecutara la acción</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">"0 */6 * * *"</span> <span class="hljs-comment"># configuración del intervalo de ejecución</span>
</code></pre>
<p>Pudimos haber hecho que esta acción se ejecutara con otros eventos como un push o un pull request, pero de esto hablare en una siguiente publicación, para profundizar les recomiendo estas dos lecturas:</p>
<p><a target="_blank" href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onschedule">https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onschedule</a></p>
<p><a target="_blank" href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events">https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events</a></p>
<p>Hasta este momento solo hemos indicado, el nombre de nuestro <strong>workflow</strong> y que sera una acción que se ejecutara de forma programada cada 6 horas, pero aun no hemos definido el <strong>job</strong> y la secuencia de pasos que se van a ejecutar, para esto debemos editar nuestro archivo y nos debe quedar de la siguiente manera:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Python</span> <span class="hljs-string">workflow</span> <span class="hljs-comment"># Nombre del workflow</span>
<span class="hljs-attr">on:</span> <span class="hljs-comment"># llave que indica que se realizara una acción sobre algun evento </span>
  <span class="hljs-attr">schedule:</span> <span class="hljs-comment"># El evento que ejecutara la acción</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">"0 */6 * * *"</span> <span class="hljs-comment"># configuración del intervalo de ejecución</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>

    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Python</span> <span class="hljs-number">3.8</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-python@v2</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">python-version:</span> <span class="hljs-number">3.8</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          python -m pip install --upgrade pip
          pip install -r requirements.txt
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">script</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          python app.py
          git config user.name rafnixg
          git config user.email rafnixg@gmail.com
          git add README.md
          git diff --quiet &amp;&amp; git diff --staged --quiet || git commit -m "[BOT] Update README with latest info"
          git push origin master</span>
</code></pre>
<p><a target="_blank" href="https://github.com/rafnixg/rafnixg/blob/master/.github/workflows/python-app.yml">https://github.com/rafnixg/rafnixg/blob/master/.github/workflows/python-app.yml</a></p>
<p>Al guardar los cambios en nuestro archivo tenemos ya definido un <strong>job</strong> de nombre <strong><em>build</em></strong> con el key <strong><em>run-on</em></strong> donde indicamos que el sistema operativo que va a correr es un ubuntu-latest, si han trabajado con este tipo de archivos YAML en docker, se les hará fácil comprender este archivo, sino no hay problema acá explico que hace nuestro archivo.</p>
<p>Después de la definición del jobs tenemos que definir los <strong>steps,</strong> que son esos pasos que va a seguir nuestro job, aqui usamos dos actions que están disponibles en el marketplace, esta creo es una de las cosas mas interesantes de GitHub Actions, ya que podemos crear actions y compartirlas con la comunidad para que otras personas las puedan implementar, yo estaré usando en esta oportunidad "action/checkout@v2" que nos ayuda a configurar git en nuestro <strong>workspace</strong> y poder tener acceso desde el <strong>Workflow</strong> que estamos definiendo hacia nuestro repositorio y "action/setup-python@v2" que nos ayuda a configurar python en el workspace para poder correr nuestro script.</p>
<p>Lo siguiente sera actualizar pip e instalar las dependencias de nuestro script y ejecutar nuestro script, ya en este punto tenemos nuestro archivo READM.md actualizado en nuestro <strong>workspace</strong>, solo nos resta crear un commit con este cambio y hacer push a nuestro repositorio.</p>
<p>Con este push ya tenemos nuestro README.md actualizado en nuestro repositorio, ahora cada 6 horas va a correr este Workflow en donde definimos un jobs que se encarga de correr nuestro script y hacer un commit cuando exista un cambio en el archivo README.md</p>
<p>En próximas publicaciones hablara un poco mas sobre las GitHubs Actions y de como crear nuestras propias actions y publicarlas para que puedan ser reutilizadas, si te gusto el contenido espero tu comentario.</p>
<p>Sígueme en twitter <a target="_blank" href="https://twitter.com/rafnixg">@rafnixg</a></p>
]]></content:encoded></item><item><title><![CDATA[Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 2]]></title><description><![CDATA[La idea principal es poder generar un archivo README.md con una lista de los últimos 5 post de este Blog, pero en esencia este código con muy poco o hasta nula modificacion en algunos casos puede servir para otros servicios como dev.to, Medium o hash...]]></description><link>https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-2</link><guid isPermaLink="true">https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-2</guid><category><![CDATA[Python]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[README]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Wed, 29 Jul 2020 19:24:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/MAYEkmn7G6E/upload/d6bf961a729b1007baf04287606f07d0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>La idea principal es poder generar un archivo README.md con una lista de los últimos 5 post de este Blog, pero en esencia este código con muy poco o hasta nula modificacion en algunos casos puede servir para otros servicios como <a target="_blank" href="https://dev.to/">dev.to</a>, <a target="_blank" href="https://medium.com/">Medium</a> o <a target="_blank" href="https://hashnode.com/">hashnode.com</a>.</p>
<p>Ya teniendo nuestro archivo README.md creado en el post <a target="_blank" href="http://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-1">Actualiza tu perfil de GitHub con README y Github Actions - Parte 1</a> , nos ubicamos en la carpeta de nuestro proyecto y empezaremos creamos una copia de nuestro archivo pero con extensión <strong>.template</strong>, quedándonos algo como esto: README.md.template, este sera el archivo que usaremos como base para generar nuestro README.md</p>
<p>Luego editamos la sección de "Latest post (Spanish)" sustituyendo nuestros post estáticos con este código en Jinja2, que nos ayuda a iterar sobre una lista de post.</p>
<pre><code class="lang-markdown"><span class="hljs-section">## Latest Posts (Spanish)</span>

{% for post in latest<span class="hljs-emphasis">_post %} - {{post.title}} {% endfor %}</span>
</code></pre>
<p>En esta plantilla indico que le voy a pasar <em>latest_post</em> y que debo recorrer sus post e imprimirlos dentro de un link en markdown.</p>
<p>Ahora necesitamos el endpoint a el que consultaremos para obtener nuestras lista de posts, para esto haré uso de las <a target="_blank" href="https://es.wikipedia.org/wiki/RSS">RSS</a> que tiene mi blog y con el siguiente servicio lo convertiré de XML a JSON</p>
<p><a target="_blank" href="https://rss2json.com">https://rss2json.com</a></p>
<p>Acá pudimos haberlo hecho de muchas maneras distintas, se pudo haber hecho el cambio de XML a JSON usando Python, mi idea era hacerlo lo mas simple posible, si tienes una idea mejor la espero en los comentarios o un Pull Request, ya con esto aclarado podemos continuar xD.</p>
<p>Teniendo nuestro endpoint listo procederemos a crear nuestro script en Python, por lo que primero debemos preparar, es nuestro entorno virtual que nos ayude a aislar nuestras dependencias para este proyecto, podemos hacer uso de Pipenv del cual tengo un tutorial por acá (<a target="_blank" href="https://blog.rafnixg.dev/entornos-virtuales-en-python-usando-pipenv">Entornos virtuales en python usando Pipenv</a>), pero en este caso lo haremos de la siguiente manera ya que es la mas comun.</p>
<pre><code class="lang-bash">python3 -m venv env 
<span class="hljs-built_in">source</span> env/bin/activate 
touch app.py
</code></pre>
<p>Lo que creara una carpeta <em>env</em> en el <em>root</em> de nuestro proyecto, activara nuestro entorno virtual y crea nuestro archivo <strong>app.py</strong></p>
<p>Para poder usar nuestras librerías debemos instalarlas, en este caso haré uso de PIP que es nuestro gestor de paquetes en python y las librería a instalar son:</p>
<ul>
<li><p><strong>urllib3</strong>: Para realizar las consultas HTTP</p>
</li>
<li><p><strong>json</strong>: para parsear la información recibida en la respuesta HTTP</p>
</li>
<li><p><strong>jinja2</strong>: para renderizar nuestro archivo README con la potencia de esta librería de plantillas</p>
</li>
</ul>
<pre><code class="lang-bash">pip install urllib3 json jinja2 
pip freeze &gt; requirements.txt
</code></pre>
<p>Ya tenemos nuestras dependencias instaladas nuestras dependencias, así que procederemos a crear nuestro script, quedándonos algo como esto:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> urllib3
<span class="hljs-keyword">from</span> jinja2 <span class="hljs-keyword">import</span> Environment, FileSystemLoader

<span class="hljs-comment"># Cantidad maxima de posts a mostrar</span>
MAX_POSTS = <span class="hljs-number">5</span>

<span class="hljs-comment"># Setup</span>
env = Environment(loader=FileSystemLoader(<span class="hljs-string">'.'</span>))
http = urllib3.PoolManager()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_latest_posts</span>(<span class="hljs-params">max_posts=<span class="hljs-number">5</span></span>):</span>
    r = http.request(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'https://api.rss2json.com/v1/api.json?rss_url=https://blog.rafnixg.dev/rss.xml'</span>)
    data = json.loads(r.data.decode(<span class="hljs-string">'utf-8'</span>))[<span class="hljs-string">'items'</span>]
    <span class="hljs-keyword">return</span> data[<span class="hljs-number">0</span>:max_posts]

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">render_readme</span>(<span class="hljs-params">data</span>):</span>
    template = env.get_template(<span class="hljs-string">'README.template'</span>)
    render = template.render(**data)
    <span class="hljs-keyword">with</span> open(<span class="hljs-string">"README.md"</span>, <span class="hljs-string">"w"</span>) <span class="hljs-keyword">as</span> f:
        f.write(render)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>

    latest_posts = get_latest_posts(MAX_POSTS)
    data = {
        <span class="hljs-string">'latest_post'</span>: latest_posts
    }
    render_readme(data)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">" __main__"</span>:
    main()
</code></pre>
<p>Las primeras 3 lineas de nuestro código son básicamente la importación de las librerías y utilidades que vamos a usar, luego definimos una constante para el numero máximo de post que vamos a escribir en nuestro archivo README.</p>
<p>El setup es donde indicamos a jinja en que fichero debe buscar los templates y creamos una instancia que llamaremos http para nuestras consultas HTTP</p>
<p>Como ven en la función <em>get_latest_posts()</em> es un simple petición GET a el enpoint, como parámetro le podemos limitar el numero de items que retornara</p>
<p>En la función <em>render_readme()</em> indicamos el archivo a usar como template, cargamos la data obtenida de los últimos post y lo renderizamos en nuestro template para luego escribirlo en el archivo final README.md</p>
<p>Con esto ya podemos correr nuestro script y ver como nos genera de forma dinámica nuestro archivo README.md</p>
<pre><code class="lang-bash">ptyhon3 app.py
</code></pre>
<p>Nuestro script ya genere de forma dinámica nuestro archivo README.md, con este mismo enfoque se pueden agregar muchísimas mas funciones consultando a diferentes servicios y editar desde el template como se va a renderizar esta información.</p>
<p>En la tercera y ultima parte veremos como automatizar la ejecución de nuestro script y actualizar README.md en nuestro repositorio de GitHub, gracias a las GitHub Actions.</p>
<p>Gracias por leerme, los espero por twitter <a target="_blank" href="https://twitter.com/rafnixg">@rafnixg</a> y por mi GitHub <a target="_blank" href="https://github.com/rafnixg/rafnixg">rafnixg</a></p>
<p>Siguiente publicación de esta serie: <a target="_blank" href="https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-3">Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 3</a></p>
]]></content:encoded></item><item><title><![CDATA[Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 1]]></title><description><![CDATA[Esta sera una serie de 3 Post:

Crear nuestro README en GitHub

Escribir un script en python para crear nuestro README dinámico

Implementar GitHub Actions para automatizar nuestro README


Acá te dejo una mirada de como quedo mi perfil, espero me de...]]></description><link>https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-1</link><guid isPermaLink="true">https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-1</guid><category><![CDATA[Python]]></category><category><![CDATA[GitHub Actions]]></category><category><![CDATA[README]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Tue, 28 Jul 2020 21:35:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/MAYEkmn7G6E/upload/d6bf961a729b1007baf04287606f07d0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Esta sera una serie de 3 Post:</p>
<ul>
<li><p><a target="_blank" href="http://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-1">Crear nuestro README en GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-2">Escribir un script en python para crear nuestro README dinámico</a></p>
</li>
<li><p><a target="_blank" href="https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-3">Implementar GitHub Actions para automatizar nuestro README</a></p>
</li>
</ul>
<p>Acá te dejo una mirada de como quedo <a target="_blank" href="https://github.com/rafnixg">mi perfil</a>, espero me dejes una estrella :D</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625600297367/qIgriV0bP.png" alt="Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 1" /></p>
<h2 id="heading-preparando-nuestro-repositorio">Preparando nuestro repositorio</h2>
<p>Para iniciar, debemos crear un repositorio en GitHub con nuestro nombre de usuario, en mi caso "rafnixg", tiene que ser publico y estar inicializado con un archivo README.</p>
<p>Ingresando a <a target="_blank" href="https://github.com/new">https://github.com/new</a> podemos crear nuestro repositorio</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625600299615/ZGBEIU-y7.png" alt="Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 1" /></p>
<p>En mi caso ya me indica que tengo este repositorio creado, pero ademas se ve un mensaje que nos indica que activamos esta funcionalidad "secreta"</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625600301793/LW4AZUI3I.png" alt="Actualiza tu perfil de GitHub con README y GitHub Actions - Parte 1" /></p>
<h2 id="heading-creando-nuestro-readme">Creando nuestro README</h2>
<p>En esta parte del proceso tendremos que empezar clonando nuestro repositorio y editar nuestro archivo README con la información que quisiéramos mostrar, para esto usaremos el siguiente comando de Git:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/tu_username/tu_username.git
</code></pre>
<p>Luego de clonar nuestro repositorio procedemos a crear nuestro archivo README usando Markdown, yo en esta parte del proceso use varias referencias para tomar ideas y armar algo que me gustara, les dejo por acá los enlaces para que las visiten y tomen ideas.</p>
<ul>
<li><p><a target="_blank" href="https://github.com/kautukkundan/Awesome-Profile-README-templates">https://github.com/kautukkundan/Awesome-Profile-README-templates</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/abhisheknaiidu/awesome-github-profile-readme">https://github.com/abhisheknaiidu/awesome-github-profile-readme</a></p>
</li>
</ul>
<p>Ya con una idea de lo que queremos hacer, escribimos nuestro archivo y subimos estos cambios a GitHub</p>
<pre><code class="lang-bash">git add README.md
git commit -m <span class="hljs-string">"[IMP] Mejora de nuestro README"</span>
git push -u origin master
</code></pre>
<p>Con esto ya tendremos nuestro archivo README desplegado en nuestro perfil de GitHub.</p>
<p>En la segunda entrega veremos como poder obtener datos de un RSS de servicios como Ghost, Dev.to o <a target="_blank" href="https://hashnode.com/">https://hashnode.com/</a> y actualizar nuestro archivo README usando Python.</p>
<p>Siguiente de esta serie: <a target="_blank" href="https://blog.rafnixg.dev/actualiza-tu-perfil-de-github-con-readme-y-github-actions-parte-2">Escribir un script en python para crear nuestro README dinámico</a></p>
<p>Gracias por leerme! los espero por mi twitter <a target="_blank" href="https://rafnixg@gmail.com">@rafnixg</a></p>
]]></content:encoded></item><item><title><![CDATA[Crea tu blog con Python usando GitHub Pages y Pelican]]></title><description><![CDATA[Cuando comencé a darle vuelta a la idea de empezar un blog de nuevo me vinieron muchas ideas de como hacerlo a la mente, como el de usar el famoso Wordpress, teniendo en cuenta que el blog lo quería hacer para hablar un poco de python y las tecnologí...]]></description><link>https://blog.rafnixg.dev/crea-tu-blog-con-python-usando-github-pages-y-pelican</link><guid isPermaLink="true">https://blog.rafnixg.dev/crea-tu-blog-con-python-usando-github-pages-y-pelican</guid><category><![CDATA[Python]]></category><category><![CDATA[pelican]]></category><category><![CDATA[GitHubPages]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Sat, 18 May 2019 19:06:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/xG8IQMqMITM/upload/31f1eeceb26639f0f17a965f76ce52f3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Cuando comencé a darle vuelta a la idea de empezar un blog de nuevo me vinieron muchas ideas de como hacerlo a la mente, como el de usar el famoso <a target="_blank" href="https://wordpress.org">Wordpress</a>, teniendo en cuenta que el blog lo quería hacer para hablar un poco de python y las tecnologías que iba a ir conociendo y aprendiendo decidí mejor usar Pelican ya que esta desarrollado en Python.</p>
<h2 id="heading-que-es-pelican">¿Qué es Pelican?</h2>
<p><a target="_blank" href="https://blog.getpelican.com/">Pelican</a> es un generador de sitios estáticos desarrollado en python que nos permite escribir los post en archivos escritos en reStructuredText, Markdown, o AsciiDoc, y estos serán luego procesados para generar un sitio web estático como este blog, por lo que no necesitaremos una base de datos ni un servidor web que soporte un lenguaje de Backend como lo es GitHub Pages.</p>
<h2 id="heading-que-es-github-pages">¿Qué es GitHub Pages?</h2>
<p><a target="_blank" href="https://pages.github.com/">GitHub Pages</a> es un hosting de sitios estáticos y como su pagina web lo indica, esta diseñado para hostear directamente en un repositorio de GitHub la pagina web de nuestros proyecto, paginas personales o de organizaciones, ademas de ser un servicio gratuito.</p>
<p>Gracias a estas características, podemos fácilmente crear nuestros sitios estáticos y subirlos a un repositorio de GitHub que debe tener la siguiente estructura <code>username.github.io</code> mas adelante indicare como crear y configurar el repositorio para que pueda servir nuestro sitio web.</p>
<p>GitHub recomienda el uso de <a target="_blank" href="https://jekyllrb.com/">Jekyll</a> para generar nuestros sitios estáticos, pero este esta hecho en Ruby, lo que no es un problema si usas Ruby pero yo al ser un #PythonLover decidí usar Pelican que esta desarrollado en Python.</p>
<h2 id="heading-creando-nuestro-repositorio-en-github">Creando nuestro repositorio en GitHub</h2>
<p>Esta parte es la mas sencilla de post, ya que solo debemos entrar a nuestra cuenta de GitHub y crear un nuevo repositorio publico, que tenga el siguiente nombre.</p>
<p><code>tu_username.github.io</code>, en mi caso el repositorio donde se aloja este blog se llama <a target="_blank" href="https://rafnixg.github.io">rafnixg.github.io</a></p>
<p>Solo con esto ya tendremos nuestro Github Pages listo para comenzar a subir nuestro contenido estático.</p>
<h2 id="heading-instalando-y-configurando-pelican">Instalando y configurando Pelican</h2>
<p>Instalar y tener Pelican funcionando es super sencillo. Pero si les quiero recomendar que toda la instalación se haga en un entorno virtual usando Pipenv, para mantener separado esta instalación de los demás paquetes de Python que tengan instalados en sus sistema, si no saben como usar Pipenv acá les dejo un post que tengo sobre este tema, Entornos virtuales en Python usando Pipenv.</p>
<p>Antes de iniciar con la instalación de pelican, debemos clonar nuestro repositorio donde esta hosteada nuestro blog, para esto solo debemos ubicarnos sonde queramos tener nuestro proyecto, en este caso yo lo haré en la raíz de mi sistema.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~
git <span class="hljs-built_in">clone</span> https://github.com/tu_username/tu_username.github.io.git
<span class="hljs-built_in">cd</span> tu_username.github.io
</code></pre>
<p>Luego de esto, procedemos a instalar nuestro Pelican, lo primero que debemos hacer es crear un nuevo branch llamado <code>source</code> donde ira todo nuestro código fuente y librerías, ya que para GitHub todo lo que este en la rama <code>master</code> es lo que sera servido, para nuestro interés solo debemos subir a <code>master</code> lo que pelican genera en su carpeta output, pero mas adelante nos preocuparemos de esto.</p>
<pre><code class="lang-bash">git checkout -b <span class="hljs-built_in">source</span>
pipenv shell
</code></pre>
<p>Con esto ya tendremos nuestro entorno virtual para nuestra instalación de pelican, ahora procedemos a instalar <code>pelican</code> que es nuestro generador de sitios estáticos, <code>markdown</code> que nos ayudara para escribir nuestros post usando este lenguaje y <code>ghp-import</code> que nos ayuda a publicar nuestro sitio a GitHub.</p>
<pre><code class="lang-bash">pipenv install pelican markdown ghp-import
Installing pelican… Adding pelican to Pipfile<span class="hljs-string">'s [packages]… 
✔ Installation Succeeded Installing markdown… 
Adding markdown to Pipfile'</span>s [packages]… 
✔ Installation Succeeded Installing ghp-import… 
Adding ghp-import to Pipfile<span class="hljs-string">'s [packages]… 
✔ Installation Succeeded Pipfile.lock not found, creating… 
Locking [dev-packages] dependencies… 
Locking [packages] dependencies… 
✔ Success! Updated Pipfile.lock (b0c318)! 
Installing dependencies from Pipfile.lock (b0c318)… 
🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 13/13 —</span>
</code></pre>
<p>Ya con esto tenemos todo listo para empezar a usar Pelican así que creemos nuestro primer blog usándolo.</p>
<pre><code class="lang-bash">pelican-quickstart
Welcome to pelican-quickstart v4.0.1.
This script will <span class="hljs-built_in">help</span> you create a new Pelican-based website.
Please answer the following questions so this script can generate the files needed by Pelican.
Using project associated with current virtual environment.Will save to: /home/username/blog/pelican
&gt; What will be the title of this web site? prueba pelican 
&gt; Who will be the author of this web site? rafnix guzman 
&gt; What will be the default language of this web site? [es] es 
&gt; Do you want to specify a URL prefix? e.g., https://example.com (Y/n) n 
&gt; Do you want to <span class="hljs-built_in">enable</span> article pagination? (Y/n) y 
&gt; How many articles per page <span class="hljs-keyword">do</span> you want? [10] 
&gt; What is your time zone? [Europe/Paris] America/Lima 
&gt; Do you want to generate a tasks.py/Makefile to automate generation and publishing? (Y/n) Y <span class="hljs-comment"># Responder Y, esto nos ayuda mucho! </span>
&gt; Do you want to upload your website using FTP? (y/N) n 
&gt; Do you want to upload your website using SSH? (y/N) n 
&gt; Do you want to upload your website using Dropbox? (y/N) n 
&gt; Do you want to upload your website using S3? (y/N) n 
&gt; Do you want to upload your website using Rackspace Cloud Files? (y/N) n 
&gt; Do you want to upload your website using GitHub Pages? (y/N) y 
&gt; Is this your personal page (username.github.io)? (y/N) y 
Done. Your new project is available at /home/username/blog/pelican
</code></pre>
<p>Si tienen alguna duda respecto a la zona horaria acá les dejo una lista con todas las <a target="_blank" href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">zonas horarias</a></p>
<pre><code class="lang-bash">&gt; Do you want to generate a tasks.py/Makefile to automate generation and publishing? (Y/n)
</code></pre>
<p>A esta pregunta deben responder (Y), ya que este Makefile nos ayudara a generar nuestro sitio de forma mas fácil, como podemos ver ya con esto se nos ha generado nuestro proyecto de pelican con el que podemos empezar a trabajar.</p>
<h2 id="heading-escribiendo-nuestro-primer-post">Escribiendo nuestro primer post</h2>
<p>Vamos a crear nuestro primer post, para esto nos debemos ubicar en la carpeta <code>content</code> y con nuestro editor de texto favorito procedemos a crear un archivo llamado hola-mundo.md (si, lo se, la imaginación esta a la orden del día), este archivo luego puede ser borrado es solo para pruebas.</p>
<pre><code class="lang-markdown">Title: Hola Mundo 
Date: 2019-05-18 10:30 
Modified: 2019-05-18 11:30 
Category: blog Tags: principal, otros 
Slug: hola-mundo Authors: Rafnix Guzmán 
Summary: Mi primer post usando Pelican y GitHub Pages

Aca pueden empezar a escribir todo lo que quieran pueden agregar todas las sintaxis de Markdown que deseen.

<span class="hljs-section">## Título </span>
<span class="hljs-section">### Subtítulo </span>
Este es un ejemplo de texto que da entrada a una lista genérica de elementos:
<span class="hljs-bullet">-</span> Elemento 1 
<span class="hljs-bullet">-</span> Elemento 2 
<span class="hljs-bullet">-</span> Elemento 3
Este es un ejemplo de texto que da entrada a una lista numerada:
<span class="hljs-bullet">1.</span> Elemento 1 
<span class="hljs-bullet">2.</span> Elemento 2 
<span class="hljs-bullet">3.</span> Elemento 3
Al texto en Markdown puedes añadirle formato como negrita o cursiva de una manera muy sencilla.

Todo esto fue extraído de este [<span class="hljs-string">Post sobre markdown</span>](<span class="hljs-link">https://markdown.es/sintaxis-markdown/</span>)
</code></pre>
<h2 id="heading-probando-nuestro-blog-en-local">Probando nuestro blog en local</h2>
<p>Luego de escribir y guardar su primer post, procedemos a generar un servidor de pruebas para ver nuestro resultado antes de subir nuestra web a GitHub, estando en la raíz de nuestro proyecto ejecutamos el siguiente comando.</p>
<pre><code class="lang-bash">make devserver pelican \
-lr /home/username/blog/pelican/content \
-o /home/username/blog/pelican/output \
-s /home/username/blog/pelican/pelicanconf.py

-&gt; Modified: content, theme, settings. re-generating... 
Done: Processed 1 article, 0 drafts, 0 pages, 0 hidden pages and 0 draft pages <span class="hljs-keyword">in</span> 0.15 seconds.
</code></pre>
<p><em>Se usa "\" para indicar que el comando tiene varias lineas</em></p>
<p>Para entrar a nuestro servidor local de pruebas debemos ingresar a la siguiente URL <a target="_blank" href="http://localhost:8000">http://localhost:8000</a> con nuestro explorador favorito/</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625600309775/aOk6bSn3b.jpeg" alt="Crea tu blog con python usando GitHub Pages y Pelican" /></p>
<p>Hola mundo pelican</p>
<h2 id="heading-subir-nuestro-blog-a-github-pages">Subir nuestro blog a GitHub Pages</h2>
<p>Ya con esto procederemos a preparar todo para subir lo a github, este primer comando sube nuestro código fuente.</p>
<pre><code class="lang-bash">git add -A &amp;&amp; git commit -a -m <span class="hljs-string">'post hola-mundo.md'</span> &amp;&amp; git push --all
</code></pre>
<p>Ahora subimos todo a la rama <code>master</code>, recuerdan que les dije que no se preocuparan por esto, es debido a que este comando hace toda esta preparación de subir todo lo que se encuentra en la carpeta <code>output</code> a nuestra rama <code>master</code></p>
<pre><code class="lang-bash">make github
</code></pre>
<p>Acá se les preguntaran sus credenciales de github, para poder subir a su repositorio todo el sitio estático ya generado, con esto su blog estará funcionando en https://su_username.github.io/</p>
<p>Para el próximo post veremos como configurar un <code>Thema</code> y algunos <code>Plugins</code> para potenciar el funcionamiento de Pelican, ademas de unas configuraciones extra que nos ayudaran a tener mejor SEO.</p>
<p>Nos vemos en el proximo post, muchas gracias por leerme y cualquier duda, comentario, o lo que sea, lo pueden dejar por aca o por mi cuenta de Twitter <a target="_blank" href="https://twitter.com/rafnixg">@rafnixg</a>.</p>
]]></content:encoded></item><item><title><![CDATA[🐍 Entornos virtuales en Python usando Pipenv]]></title><description><![CDATA[Cuando iniciamos en el desarrollo con Python muchas veces no nos damos cuenta del dolor de cabeza que es mantener varios proyectos con diferentes versiones de dependencias en nuestra entorno de desarrollo local, a medida que vamos evolucionando vamos...]]></description><link>https://blog.rafnixg.dev/entornos-virtuales-en-python-usando-pipenv</link><guid isPermaLink="true">https://blog.rafnixg.dev/entornos-virtuales-en-python-usando-pipenv</guid><category><![CDATA[Python]]></category><category><![CDATA[pipenv]]></category><category><![CDATA[virtual environment]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Sun, 12 May 2019 00:39:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5uU8HSpfwkI/upload/0acf143138e277fd30eb5845a2ee200b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Cuando iniciamos en el desarrollo con Python muchas veces no nos damos cuenta del dolor de cabeza que es mantener varios proyectos con diferentes versiones de dependencias en nuestra entorno de desarrollo local, a medida que vamos evolucionando vamos adquiriendo nuevas herramientas que mejoren nuestro flujo de trabajo, como el uso de entornos virtuales o manejadores de paquetes, entre otras, Pipenv es una de estas herramientas que nos ayudan mucho a integrar y mejorar nuestros flujos en Python, tanto es así que su eslogan por así decirlo es <code>"Python Development Workflow for Humans".</code></p>
<p>Esta herramienta básicamente nos ayuda a optimizar nuestro flujo de desarrollo unificando <em>pip</em> y <em>virtualenv</em> en una sola herramienta que funciona por linea de comandos <em>(Terminal)</em>, lo que nos daria un entorno aislado en el cual instalar nuestras dependencia y luego replicar este mismo entorno en otra maquina gracias a el archivo que se genera <a target="_blank" href="https://github.com/pypa/pipfile"><strong>Pipfile</strong></a>, que viene a ser el sustituto del archivo que genera pip <strong>requirements.txt</strong></p>
<h2 id="heading-instalando-pipenv">Instalando Pipenv</h2>
<p>El proceso de instalación de Pipenv es muy sencillo, en esta ocasión voy a detallar 2 formas de instalar usando lo indicado en la <a target="_blank" href="https://pipenv-es.readthedocs.io/es/latest/">documentación oficial</a>.</p>
<p>Si estas usando Ubuntu 16.04:</p>
<pre><code class="lang-bash">sudo apt install software-properties-common python-software-properties
sudo add-apt-repository ppa:pypa/ppa
sudo apt update
sudo apt install pipenv
</code></pre>
<p>Esta otra opción es por si ya tienes instalado pip:</p>
<pre><code class="lang-bash">pip install pipenv
</code></pre>
<p>Como acabamos de ver la instalación es muy sencilla, de igual manera si tienen algún problema con la instalación me pueden escribir.</p>
<h2 id="heading-usando-pipenv">Usando Pipenv</h2>
<p>Para efectos de este ejemplo vamos a generar una aplicación sencilla usando <code>Flask</code> y haremos el típico <em>Hola Mundo</em>, ya que este post no se trata de desarrollo de apps usando <code>Flask</code></p>
<p>Primero creamos nuestro entorno virtual para aislar nuestra aplicación:</p>
<pre><code class="lang-bash">pipenv shell

Creating a virtualenv <span class="hljs-keyword">for</span> this project… Pipfile: /home/usuario/nombre_del_proyecto/Pipfile Using /usr/bin/python3 (3.6.7) to create virtualenv…
</code></pre>
<p>Con la ejecución de este comando se crea un entorno virtual si no existe, ademas de crear 2 archivos: <code>Pipfile</code> y <code>Pipfile.lock</code>.</p>
<p>Si se instala en un proyecto preexistente Pipenv convierte tu archivo <em>requirements.txt</em> en <em>Pipfile</em>.</p>
<p>Para este proyecto se ha creado un entorno con una versión de python 3, si necesitas instalar una versión de python 2 solo debes agregar el argumento --two, también funciona para python 3 el argumento --three.</p>
<pre><code class="lang-bash">pipenv shell --two <span class="hljs-comment">#Genera entorno en Python2</span>
pipenv shell --three <span class="hljs-comment">#Genera entorno en Python3</span>
</code></pre>
<p>Ahora procedemos a instalar los paquetes que necesitamos, en nuestro caso Flask, pero supondremos que necesitamos una versión especifica para este ejemplo usaremos la versión 1.0, para el momento de escribir este post la versión latest de Flask es la 1.0.2</p>
<pre><code class="lang-bash">pipenv install flask==1.0
Installing flask==1.0… Adding flask to Pipfile<span class="hljs-string">'s [packages]… 
✔ Installation Succeeded Pipfile.lock not found, creating… 
Locking [dev-packages] dependencies… 
Locking [packages] dependencies… 
✔ Success! 
Updated Pipfile.lock (db0e09)! 
Installing dependencies from Pipfile.lock (db0e09)… 
🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 6/6 —</span>
</code></pre>
<p>Con esto ya tendremos Flask instalado en nuestro entorno virtual, y procedemos a realizar nuestro desarrollo.</p>
<p>Crean un archivo llamado <code>apps.py</code> con este contenido dentro:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask app = Flask(name)

<span class="hljs-meta">@app.route("/")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello World!"</span>
</code></pre>
<p>Por ultimo iniciamos nuestro servidor Flask</p>
<pre><code class="lang-bash">FLASK_APP=apps.py flask run

* Serving Flask app <span class="hljs-string">"apps.py"</span> * Environment: production WARNING: Do not use the development server <span class="hljs-keyword">in</span> a production environment. Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
</code></pre>
<p>Con esto tendremos nuestro server Flask corriendo nuestro archivo <code>apps.py</code>.</p>
<h2 id="heading-consideraciones-finales">Consideraciones finales</h2>
<p>A lo largo de este post hemos visto como el flujo de trabajo se puede optimizar con el uso de esta herramienta, ya que no debemos generar los entornos virtuales por separado usando algo como <code>virtualenv</code> con el que como yo muchas personas no han estado conformes, también hemos visto como instalar paquetes usando pipenv tan fácil como si usáramos <code>pip</code>, queda de parte de cada quien darle una probada a esta herramienta y ver si le ayuda a optimizar su flujo de desarrollo y mantener un poco más homogéneo los ambientes de desarrollo.</p>
<p>Si deseas que siga publicando contenido sobre entornos virtuales, pip, o explique más a fondo los ficheros <code>Pipfile</code>o <code>Pipfile.lock</code>, que otros comandos puede ejecutar Pipenv, solo házmelo saber en un comentario o a través de mi cuenta twitter <a target="_blank" href="https://twitter.com/rafnixg">@rafnixg</a></p>
<h3 id="heading-referencias"><strong>Referencias</strong></h3>
<h3 id="heading-ia"> </h3>
<p><a target="_blank" href="https://pipenv-es.readthedocs.io/es/latest/">Documentación Pipenv</a></p>
]]></content:encoded></item><item><title><![CDATA[Deploy usando GIT-FTP]]></title><description><![CDATA[Es muy común que cuando nos estamos iniciando en el mundo del desarrollo web y no tenemos dinero para costearnos un buen servicio, optemos por comprar espacio en un ‘Shared host’ o utilizar un hosting gratuito que básicamente funcional igual.
Introdu...]]></description><link>https://blog.rafnixg.dev/deploy-usando-git-ftp</link><guid isPermaLink="true">https://blog.rafnixg.dev/deploy-usando-git-ftp</guid><category><![CDATA[Git]]></category><category><![CDATA[ftp]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Tue, 26 Jun 2018 18:57:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/2kH-6T6x_0I/upload/5576b8e4331eae994bc98b40c2d4e7e6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Es muy común que cuando nos estamos iniciando en el mundo del desarrollo web y no tenemos dinero para costearnos un buen servicio, optemos por comprar espacio en un ‘Shared host’ o utilizar un hosting gratuito que básicamente funcional igual.</p>
<h2 id="heading-introduccion"><strong>Introducción</strong></h2>
<p>Cuando queremos desplegar nuestros proyectos webs en estos servicios de bajo costo o gratuitos, nos encontramos con una limitante de que no tenemos acceso por SSH, sino que nos colocan a disposición una cuenta FTP.</p>
<p>Para muchos que no han usado o trabajado con el control de versiones esto no es un problema, pero si queremos mantener un buen flujo de trabajo y llevar el seguimiento de nuestro proyecto usar git es tarea fundamental y a la hora del despliegue es una herramienta que nos facilita la vida, a diferencia de FTP que hace el proceso de despliegue muy tedioso y con mucha perdida de tiempo, ya que debemos saber que archivos fueron modificados para subir al servidor.</p>
<h2 id="heading-git-ftp"><strong>Git-FTP</strong></h2>
<p>Esa herramienta nos viene a solucionar ese problema de no subir todos los archivos o seleccionar de forma manual los archivos que deseamos subir al servidor, sino que el se encarga de revisar que archivos fueron modificados desde la ultima actualización y solo sube estos archivos.</p>
<p>Que belleza y que hermosura fue lo que yo pensé cuando di con esta herramienta, ya que obviamente hace que nuestro flujo de trabajo sea mas optimo que usando solamente FTP, pero no todo es así de bello existe una limitación al usar este cliente FTP y es que las modificaciones hechas directamente sobre el servidor no serán vista desde nuestra área local, por lo que aconsejo mantener esto en cuenta.</p>
<h2 id="heading-instalacion-de-git-ftp"><strong>Instalacion de Git-FTP</strong></h2>
<p>La instalación es muy sencilla para los que usamos GNU/Linux yo en especial uso Debian es muy sencillo de instalar usando la terminal, para los que usen otro sistema operativo acá les dejo el <a target="_blank" href="https://github.com/git-ftp/git-ftp/blob/master/INSTALL.md">Manual de Instalación Oficial</a> donde encontraran la instalación para los siguientes Sistemas operativos:</p>
<ul>
<li><p>Linux/Unix usando make</p>
</li>
<li><p>Debian, Ubuntu y otros usando apt</p>
</li>
<li><p>ArchLinux</p>
</li>
<li><p>Mac OS X</p>
</li>
<li><p>Windows</p>
</li>
</ul>
<p>Para los que usamos Debian o Ubuntu solo debemos teclear esto en la terminal</p>
<pre><code class="lang-bash">sudo apt-get install git-ftp
</code></pre>
<p>Con esto ya tendríamos Git-FTP instalado</p>
<h2 id="heading-configuracion"><strong>Configuración</strong></h2>
<p>La configuración es muy sencilla desde nuestro terminal usamos los siguientes comandos:</p>
<pre><code class="lang-bash">git config git-ftp.url ftp.example.net
git config git-ftp.user ftp-user
git config git-ftp.password secr3t
</code></pre>
<p>Ya con esto tendríamos configurada la conexión a nuestro servidor por FTP, solo resta ubicarnos en la carpeta de nuestro proyecto y dependiendo las siguientes 2 opciones ejecutar el comando que sea conveniente:</p>
<ul>
<li><p>Subir todos los archivos (inicializacion)<br />  <code>git ftp init</code></p>
</li>
<li><p>Indicar que los archivos ya se encuentran en el servidor.<br />  <code>git ftp catchup</code></p>
</li>
</ul>
<h2 id="heading-haciendo-deploy"><strong>Haciendo Deploy</strong></h2>
<p>Para hacer deploy seguimos nuestro flujo de trabajo normal usando git, en el momento que necesitemos subir los archivos modificados al servidor solo debemos ejecutar este comando en la terminal:</p>
<pre><code class="lang-bash">git ftp push
</code></pre>
<p>Con esto ya tendremos nuestros archivos en el servidor.</p>
<h2 id="heading-recomendacion"><strong>Recomendación</strong></h2>
<blockquote>
<p>Mantener siempre el mismo flujo de trabajo y no modificar archivos directamente al servidor.</p>
<p>Leer la documentación Oficial de Git-FTP - <a target="_blank" href="https://git-ftp.github.io/">Pagina Oficial de Git-FTP</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Ejecutar Código JavaScript en Sublime Text]]></title><description><![CDATA[Cuando estamos iniciando en el desarrollo con JavaScript uno de los flujos de trabajos menos óptimos para no decir los mas fastidiosos, son tener que escribir el código en nuestro editor de código favorito y tener que ir a la consola del explorador a...]]></description><link>https://blog.rafnixg.dev/ejecutar-codigo-javascript-en-sublime-text</link><guid isPermaLink="true">https://blog.rafnixg.dev/ejecutar-codigo-javascript-en-sublime-text</guid><category><![CDATA[Sublime Text]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Rafnix Guzman]]></dc:creator><pubDate>Wed, 28 Jun 2017 18:48:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_SgRNwAVNKw/upload/7d8d6f0cddfc178056b2e83a56d528db.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Cuando estamos iniciando en el desarrollo con JavaScript uno de los flujos de trabajos menos óptimos para no decir los mas fastidiosos, son tener que escribir el código en nuestro editor de código favorito y tener que ir a la consola del explorador a probarlo.</p>
<p>Para resolver este problema existen muchos camino, el que yo propongo aquí es el que mas se adapto a mis necesidades y espero que pueda ayudar en las suyas, para todos esos que usan <strong><em>Sublime Text</em></strong> y mantiene este flujo de trabajo de crear código en sublime y luego pasarlo a un explorador y depurar en la consola del explorador doy este pequeño pero para mi poderoso tip.</p>
<p>Inicialmente debemos tener instalado <strong><em>Sublime Text</em>,</strong> es muy sencillo de instalar y en su sitio web existe mucha documentación al respecto, y lo segundo que tendremos que tener instalado es <strong><em>Node.js</em></strong>,</p>
<p>Si aun no tienes instalado <em>Node.js</em> acá te dejo la documentación oficial donde encontrás la guiá de como instalarlo en cualquier sistema operativo que uses, <a target="_blank" href="https://nodejs.org/es/download/package-manager/">Manual de Instalación</a></p>
<h2 id="heading-configurando-sublime">Configurando Sublime</h2>
<p>Luego de tener Sublime Text y Node.js instalados y funcionando, vamos a proceder a hacer una pequeña configuración en sublime Text, para esto debemos ingresar en <code>“Tools &gt; Build System &gt; New Build System”</code>, se abrirá un documento nuevo con el siguiente contenido:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"cmd"</span>: [<span class="hljs-string">"make"</span>]
}
</code></pre>
<p>Este contenido debe ser sustituido por el siguiente:</p>
<pre><code class="lang-json">{
<span class="hljs-attr">"cmd"</span>: [<span class="hljs-string">"node"</span>, <span class="hljs-string">"$file"</span>],
<span class="hljs-attr">"selector"</span>: <span class="hljs-string">"source.js"</span>
}
</code></pre>
<p>Hecho esto procedemos a guardar el archivo en la ruta sugerida por Sublime Text, para poder probar que esta funcionando solo debemos crear un nuevo archivo JS con el código JavaScript que deseen, recomiendo solo a modo de prueba el siguiente:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"JavaScript funcionando desde Sublime Text"</span>)
</code></pre>
<p>Guardan el archivo nuevo con el nombre que deseen en mi caso <code>“prueba.js”</code> y para poder ejecutarlo deben ir a <code>“Tools &gt; Build”</code> o ejecutando la siguiente combinación de teclas <code>“Control + B”</code>.</p>
<h2 id="heading-recomendaciones">Recomendaciones</h2>
<p>Para los que se están iniciando en el mundo de JavaScript los recomiendo leer un poco sobre Node.js y lo potente que puede llegar a ser, ya que en este post no se aprecia la potencia de este.</p>
<p>Instalar Snippets y verificadores de código para Sublime Text, para aumentar su productividad y saber donde puedan tener posibles errores.</p>
]]></content:encoded></item></channel></rss>