<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Flávio Filipe</title>
    <description>The latest articles on DEV Community by Flávio Filipe (@flaviofilipe).</description>
    <link>https://dev.to/flaviofilipe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F561844%2Fc12a7e02-ba47-4528-96d2-8c0000413411.jpeg</url>
      <title>DEV Community: Flávio Filipe</title>
      <link>https://dev.to/flaviofilipe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flaviofilipe"/>
    <language>en</language>
    <item>
      <title>Documentando código Python com Type Hints</title>
      <dc:creator>Flávio Filipe</dc:creator>
      <pubDate>Thu, 08 Jul 2021 13:13:21 +0000</pubDate>
      <link>https://dev.to/flaviofilipe/documentando-codigo-python-com-type-hints-3d19</link>
      <guid>https://dev.to/flaviofilipe/documentando-codigo-python-com-type-hints-3d19</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Fiquei um pouco confuso ao começar a estudar sobre a declaração explícita com Python. Ao tentar comparar com outras linguagens como Java, C++ ou Typescript a compreensão começa a ficar um pouco problemática. Para entender o que é, para que serve e quando utilizar é preciso entender o motivo da sua criação.&lt;/p&gt;

&lt;p&gt;Para começar precisamos ressaltar duas coisas importantes sobre o Python:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;É uma linguagem fortemente tipada, isto é, cada variável tem um tipo e em alguns casos é preciso convertê-las para realizar operações, por exemplo: &lt;code&gt;‘1’ + 1&lt;/code&gt; irá retornar uma exceção pois os tipos são diferentes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;É uma linguagem de tipagem dinâmica. Isso significa que podemos alterar o tipo da variável ao longo do programa, como por exemplo:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# n é do tipo inteiro
&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;teste&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt; &lt;span class="c1"&gt;# n é do tipo string
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tipo de dados
&lt;/h2&gt;

&lt;p&gt;Para conhecermos melhor os tipos em python podemos utilizar o método &lt;code&gt;type(var)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Os mais comuns são:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tipo&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;th&gt;Exemplo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str&lt;/td&gt;
&lt;td&gt;Texto&lt;/td&gt;
&lt;td&gt;'hello'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;Número Inteiro&lt;/td&gt;
&lt;td&gt;1 , 2, 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;float&lt;/td&gt;
&lt;td&gt;Número Real&lt;/td&gt;
&lt;td&gt;1.0, 2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;Lista&lt;/td&gt;
&lt;td&gt;[1,2,3]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dict&lt;/td&gt;
&lt;td&gt;Dicionário&lt;/td&gt;
&lt;td&gt;{'title': 'post 1', 'category': 1 }&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Vantagens da Tipagem Estática
&lt;/h3&gt;

&lt;p&gt;A grande vantagem de se trabalhar com linguagens de tipagem estática é que ao definir o seu tipo: garantimos que não teremos problemas em tentar somar um &lt;em&gt;inteiro&lt;/em&gt; com uma &lt;em&gt;string&lt;/em&gt; durante o desenvolvimento do código. &lt;br&gt;
Outra vantagem é poder entender os tipos de dados que uma função está esperando, apontando um erro imediato na IDE durante a escrita do código caso o parâmetro passado seja de um tipo diferente.&lt;/p&gt;

&lt;p&gt;Mas e se tratando de &lt;strong&gt;Python&lt;/strong&gt;, como podemos ganhar agilidade no desenvolvimento e evitar erros comuns com os tipos de dados e deixar claro para quem for dar manutenção no futuro os tipos de dados que esperamos trabalhar?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vamos considerar o código abaixo:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;somar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Olhando para ele fica difícil saber o real propósito da sua criação. Ele foi criado para somar números, textos ou listas? O que aconteceria se eu passasse um número no primeiro parâmetro e um texto no segundo? Precisamos deixar claro para quem precisar olhar para este código no futuro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docstring
&lt;/h2&gt;

&lt;p&gt;Na &lt;a href="https://www.python.org/dev/peps/pep-0257/" rel="noopener noreferrer"&gt;PEP-257&lt;/a&gt;, com a chegada do Docstring, é apresentada uma convenção para documentar nossas funções. Abaixo um exemplo com a tentativa de facilitar nosso entendimento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;somar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
        Retorna a soma de dois números inteiros
        Params:
            a (int)
            b (int)
    &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependendo da IDE ou editor de texto utilizado, ao chamar esta função e passar o mouse por cima, ele irá apresentar a sua documentação. Mas pensando no cenário onde teremos vários métodos e para todos eles precisaríamos criar um &lt;em&gt;docstring&lt;/em&gt; somente para informar o tipo de parâmetro e seu retorno acaba se tornando uma tarefa repetitiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoradores para Funções e Métodos
&lt;/h2&gt;

&lt;p&gt;Na &lt;a href="https://www.python.org/dev/peps/pep-0318/" rel="noopener noreferrer"&gt;PEP-318&lt;/a&gt;, com a chegada dos decoradores para as funções e métodos, é apresentado uma sintaxe para ser utilizada com a finalidade de definir os tipos de parâmetros e retorno, assim poderíamos simplificar nossa documentação criando uma funçao de para informar os parâmetros e retorno:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@accepts&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;somar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui temos alguns exemplos da utilização dos decorators para facilitar o entendimento deles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pythonacademy.com.br/blog/domine-decorators-em-python" rel="noopener noreferrer"&gt;https://pythonacademy.com.br/blog/domine-decorators-em-python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://realpython.com/primer-on-python-decorators/" rel="noopener noreferrer"&gt;https://realpython.com/primer-on-python-decorators/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Finalmente os &lt;em&gt;Annotations&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;No ano de 2006, com a chegada do Python 3, a &lt;a href="https://www.python.org/dev/peps/pep-3107/" rel="noopener noreferrer"&gt;PEP-3107&lt;/a&gt; nos trouxe uma outra forma de documentar nosso código com as Anotações de Função. Agora nós podemos fazer as anotações dentro do parâmetro da função e logo em seguida informar seu retorno, que basicamente fazem o uso das anotations para fazer o mapeamento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Hints
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://www.python.org/dev/peps/pep-0483/" rel="noopener noreferrer"&gt;PEP-483&lt;/a&gt; nos trás uma nova “teoria” da proposta de implementação de tipos para o Python 3.5 Segue a citação que deixa bem claro o real propósito da nova implementação sugerida:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;É importante que o usuário seja capaz de definir os tipos de uma forma que possa ser entendida por verificadores de tipo. O objetivo deste PEP é propor uma forma sistemática de definir tipos para anotações de tipo de variáveis ​​e funções usando a sintaxe &lt;a href="https://www.python.org/dev/peps/pep-3107" rel="noopener noreferrer"&gt;PEP 3107&lt;/a&gt; . Essas anotações podem ser usadas para evitar muitos tipos de bugs, para fins de documentação, ou talvez até mesmo para aumentar a velocidade de execução do programa. Aqui, nos concentramos apenas em evitar bugs usando um verificador de tipo estático.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Porém é com a &lt;a href="https://www.python.org/dev/peps/pep-0484/" rel="noopener noreferrer"&gt;PEP-484&lt;/a&gt; que isso acontece, com a chegada dos Type Hints ou Dicas de Tipo.&lt;/p&gt;

&lt;p&gt;Segue um exemplo atualizado usando a nova sintaxe e falaremos sobre ele em seguida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;somar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, de uma forma mais semântica, conseguimos documentar melhor nosso método. Fica claro os tipos de dados de entrada e saída. Agora vamos à "confusão" citada no início deste artigo quando tentei comparar com outras linguagens.&lt;/p&gt;

&lt;p&gt;Ao olharmos o histórico da implementação podemos perceber que esta funcionalidade está mais ligada a &lt;strong&gt;documentação&lt;/strong&gt; e &lt;strong&gt;legibilidade do código&lt;/strong&gt; ao invés de tornar a linguagem estática. Sendo assim, diferente de outras linguagens estáticas, ao fazer uma declaração explícita dos valores de entrada ele não nos obriga a informá-los ou proíbe a mudança de tipo ao longo do código. Isso significa que o código abaixo ainda é um código válido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;somar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;  

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;somar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 

&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ab&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso ocorre porque o intuito é &lt;strong&gt;DOCUMENTAR&lt;/strong&gt; e não obrigar os tipos de entrada e saída. A grande vantagem desta funcionalidade está no desenvolvimento se combinado com a ferramenta de terceiros para fazer a validação no código.&lt;/p&gt;

&lt;p&gt;Utilizando uma IDE ou um editor de texto configurado para o python, ao escrever o código acima seria apresentado um erro informando que os tipos de dados são incompatíveis. Outras ferramentas, como o &lt;a href="http://mypy-lang.org/" rel="noopener noreferrer"&gt;MyPy&lt;/a&gt;, podem garantir se o código segue as regras de implementação propostas. Com isso em mente, vamos explorar um pouco mais o que podemos fazer com os Types Hints.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Eu estou utilizando o PyCharm, uma IDE feita para Python. Ela tem uma ótima integração com os Type Hints fazendo as validações em tempo de desenvolvimento. Mas sintam-se a vontade para testar em outros editores. Você poderá executar o MyPy sempre que quiser testar suas implementações&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  EXEMPLOS COM TYPE HINTS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Exemplo 1: Precisamos passar uma lista de palabras para um método fazer algum tipo de validação nelas. Assim, precisamos especificar o tipo de lista que estamos esperando:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validar_palavras&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;palavras&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;teste&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;palavras&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;validate_words&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Nome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;teste&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Utilizando o &lt;code&gt;list[str]&lt;/code&gt; informamos que estamos esperando uma lista de palavras para nossa função. No método acima o &lt;code&gt;-&amp;gt; bool&lt;/code&gt; informa que o retorno é um &lt;em&gt;boleano&lt;/em&gt; (Verdadeiro ou Falso).&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo 2: Precisamos dar as boas vindas ao suário. Por isso iremos criar um método que recebe o nome e o status do usuário, se ele tiver o status ATIVO irá retornar a mensagem: &lt;code&gt;Bem vindo &amp;lt;NOME&amp;gt;!&lt;/code&gt;. Mas se ele possuir o status SUSPENSO deverá retornar a mensagem: &lt;code&gt;Usuário Suspenso!&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypedDict&lt;/span&gt;  

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;  


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  
    &lt;span class="n"&gt;ATIVO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  
    &lt;span class="n"&gt;SUSPENSO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;  


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  
    &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;  
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserStatus&lt;/span&gt;  


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;boas_vindas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;UserStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUSPENSO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Usuário Suspenso!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bem vindo &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;usuario&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  


&lt;span class="n"&gt;usuario_ativo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Usuário Ativo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ativo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="n"&gt;usuario_suspenso&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Usuário Suspenso&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUSPENSO&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;boas_vindas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario_ativo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;boas_vindas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usuario_suspenso&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para este exemplo nós criamos duas &lt;em&gt;classes&lt;/em&gt; para ser a referência de tipo de entrada para nossa função. A class &lt;code&gt;UserStatus&lt;/code&gt; será usada para definir nossos tipos padrões de status aceitos, enquanto a &lt;code&gt;UserType&lt;/code&gt; serão os tipos de dados esperados pelo usuário.&lt;/p&gt;

&lt;p&gt;Caso vc esteja utilizando o PyCharm ou algum editor configurado para reconhecer os tipos verá que poderá utilizar o autocomplete e caso passe algum parâmetro errado o próprio editor já acusa que há um erro:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FgxPc-oaNy5QMJe7lC4BfubTDxbn1_0NlyMiD6Z8DLgwNptfLORbg1GniykxD3H3Zyds9jTGDXEhqcrRl55kMnzKC_Xmr36FEvq0sp8fAAIaBWByPDZtWpiVrJhFRCEUgSAm6lJFj" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh6.googleusercontent.com%2FgxPc-oaNy5QMJe7lC4BfubTDxbn1_0NlyMiD6Z8DLgwNptfLORbg1GniykxD3H3Zyds9jTGDXEhqcrRl55kMnzKC_Xmr36FEvq0sp8fAAIaBWByPDZtWpiVrJhFRCEUgSAm6lJFj" alt="Mensagem de tipo inesperado para o status do usuário"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Você poderá usar também a opção do autocomplete apertando ctrl+espaço:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FP7Bjsifc_CddFdXRdEHHRUfOc1tJQXP1uIbZ58U64YFQ8nCh76kHNy7H5y64U8yanc9htujsmD5RLWaJk5GnRluXwkcth56EDVh-O9PFwoQf2bTlH9kepstzODAa9I7r8Sf4epHQ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh5.googleusercontent.com%2FP7Bjsifc_CddFdXRdEHHRUfOc1tJQXP1uIbZ58U64YFQ8nCh76kHNy7H5y64U8yanc9htujsmD5RLWaJk5GnRluXwkcth56EDVh-O9PFwoQf2bTlH9kepstzODAa9I7r8Sf4epHQ" alt="Sugestão de autocomplete para o usuário"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Para conhecer mais como definir os tipos com classes poderá consultar a &lt;a href="https://www.python.org/dev/peps/pep-0589/" rel="noopener noreferrer"&gt;PEP-589&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Com a declaração explicita podemos: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentar melhor nosso código&lt;/li&gt;
&lt;li&gt;Ter segurança na hora de fazer o refatoramento&lt;/li&gt;
&lt;li&gt;Aproveitar ao máximo o autocomplete&lt;/li&gt;
&lt;li&gt;Pensar melhor nos dados da nossa aplicação&lt;/li&gt;
&lt;li&gt;Deixar o código mais claro e limpo&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>[Python] Exceções - Transformando bugs em features</title>
      <dc:creator>Flávio Filipe</dc:creator>
      <pubDate>Mon, 22 Feb 2021 03:09:37 +0000</pubDate>
      <link>https://dev.to/flaviofilipe/python-excecoes-transformando-bugs-em-features-2gm3</link>
      <guid>https://dev.to/flaviofilipe/python-excecoes-transformando-bugs-em-features-2gm3</guid>
      <description>&lt;p&gt;Neste post veremos como transformar os bugs em features, em outras palavras, como lidar com "erros" ao desenvolvermos nossas regras.&lt;/p&gt;

&lt;p&gt;Sendo assim, aqui falaremos sobre como lançar exceções com o &lt;code&gt;rise&lt;/code&gt;, como tratá-las utilizando o &lt;code&gt;try/except&lt;/code&gt; e como criar exceções personalizadas para melhorar a legibilidade do nosso código.&lt;/p&gt;

&lt;p&gt;Estaremos utilizando a linguagem Python, mas os conceitos abordados servirão para qualquer linguagem de programação que siga estes princípios de tratamento e lançamento de exceções.&lt;/p&gt;

&lt;h3&gt;
  
  
  Índice
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Erros e Exceções&lt;/li&gt;
&lt;li&gt;Bug vs Exceções&lt;/li&gt;
&lt;li&gt;Tratando erros com o try/except&lt;/li&gt;
&lt;li&gt;Lançando exceções&lt;/li&gt;
&lt;li&gt;Exceções personalizadas&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;li&gt;Bônus - Pytest&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;a id="erros-excecoes"&gt;&lt;/a&gt;Erros e Exceções
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Por que lançar e tratar exceções?
&lt;/h3&gt;

&lt;p&gt;É muito comum encontrar códigos como este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def diga_ola(nome):
    if len(nome) &amp;lt; 5:
        return false
    elif len(nome) &amp;gt; 100:
        return false
    elif name.isnumeric():
        return false
    else:
        return f'ola {nome}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bom, claramente essas verificações estará relacionada com nossa regra de negócio. Sendo assim, para entender seu funcionamento teremos que ler e interpretar o que está acontecendo e em qual ordem.&lt;/p&gt;

&lt;p&gt;O problema é quando executamos a função e ela retorna um &lt;code&gt;false&lt;/code&gt; na nossa cara. Mas e aí?! Onde falhou?? Em qual parte da regra ela não passou?? E é nessas horas que fazemos o velho &lt;code&gt;print('aqui 1')&lt;/code&gt;, &lt;code&gt;print('aqui 2')&lt;/code&gt;, &lt;code&gt;print('aqui N')&lt;/code&gt; para saber até onde o código está chegando. &lt;/p&gt;

&lt;p&gt;Na tentativa de "melhorar" ainda fazemos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'''
Função para dizer olá
'''
def diga_ola(nome):
   // Verifica se o nome é menor que 5
    if len(nome) &amp;lt; 5:
        return false
    // Verifica se o nome é maior que 100
    elif len(nome) &amp;gt; 100:
        return false
    // Verifica se o nome é um número
    elif name.isnumeric():
        return false
    // Retornao nome formatado: Olá + nome
    else:
        return f'ola {nome}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se antes já estava ruim, agora que piorou. Nada &lt;em&gt;pythonico&lt;/em&gt;!&lt;br&gt;
Vamos ver formas melhores de organizar este código.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;a id="bug-exception"&gt;&lt;/a&gt;Bug vs Exceções
&lt;/h4&gt;

&lt;p&gt;Resumidamente&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exceções são erros esperados, previsíveis e conhecidos de alguma situação. Ex: Divisão entre dois números &lt;code&gt;x / y&lt;/code&gt;. Já é esperado que ocorra um erro caso o valor &lt;code&gt;y == 0&lt;/code&gt;, logo podemos criar formas de tratar antes que trave o sistema.&lt;/li&gt;
&lt;li&gt;Já o bug é um erro desconhecido, algo que não estava sendo esperado em uma funcionalidade. Ex: Exibir um alerta no navegador do usuário. Poderá acontecer N situações, como tamanhos de telas diferentes, navegadores diferentes, erro de conexão com a internet, desabilitar a execução de scripts no navegador, etc. Apesar de imarginarmos e tentar tratar algum deles, em algum momento essa "exceção não prevista" poderá travar o funcionamento de uma página.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Um bug conhecido poderá ser uma exceção tratada!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Caso queira se aprofundar nas terminologias poderá pesquisar sobre o padrão &lt;em&gt;IEEE nº 610.12-1990&lt;/em&gt; ou neste artigo da Dev Media &lt;a href="https://www.devmedia.com.br/gestao-de-defeitos-ferramentas-open-source-e-melhores-praticas-na-gestao-de-defeitos/8036"&gt;Gestão de defeitos&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;a id="try-except"&gt;&lt;/a&gt;Tratando erros com o try/except
&lt;/h3&gt;

&lt;p&gt;Tente executar o cód a baixo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print(1/0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado será uma mensagem de erro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
    ...
ZeroDivisionError: division by zero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos melhorar esta mensagem tratando a exceção e isolando-a numa função&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def  divide_numeros(dividendo, divisor):
    try:
        print(dividendo/divisor)
    except:
        print ('O divisor não pode ser 0.')

divide_numeros(1, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado será: &lt;code&gt;O divisor não pode ser 0.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Mas o que acontece se executarmos: &lt;code&gt;divide_numeros(1, 'teste')&lt;/code&gt; ?&lt;br&gt;
O resultado será exatamente a mesma mensagem! Portanto, precisamos tratar as exceções individualmente e exibir a mensagem adequada.&lt;br&gt;
Podemos reescrever assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def  divide_numeros(dividendo, divisor):
    try:
        print(dividendo/divisor)
    except  ZeroDivisionError:
        print ('O divisor não pode ser 0.')
    except  TypeError:
        print('Insira apenas números')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;a id="rise"&gt;&lt;/a&gt;Lançando exceções
&lt;/h1&gt;

&lt;p&gt;Vamos falar agora de exceções relacionados a nossa regra de negócio.&lt;br&gt;
Vamos rever o cenário onde nosso sistema terá uma mensagem de saudação para um usuário. Porém teremos algumas regras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O nome não poderá ser números;&lt;/li&gt;
&lt;li&gt;O nome deverá ter menos que 100 caracteres&lt;/li&gt;
&lt;li&gt;O nome deverá ter mais que 5 caracteres&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como já vimos antes, encher o código de &lt;em&gt;if&lt;/em&gt; e &lt;em&gt;else&lt;/em&gt; não é legal. Por isso faremos um código com tratamento de exceções. Começaremos criando nossa função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def  diga_ola(name: str) -&amp;gt; str:
    return f'Olá {nome}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O método acima recebe uma string por parâmetro e retorna uma string como resposta. Então poderíamos executar da seguinte maneira: &lt;code&gt;diga_ola('Flávio')&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Como estamos especificando que o parâmetro recebido deverá ser uma string, ao tentar passar um número teremos um erro: &lt;code&gt;diga_ola(123)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AttributeError: 'int' object has no attribute 'isnumeric'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sendo assim, já podemos capturar nossa primeira exceção&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try:
    print(diga_ola(123))
except  AttributeError:
    print('Insira apenas texto')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para deixarmos dinâmico, vamos pedir através de um input para que o nome seja inserido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try:
    name = input('Insira seu nome: ')
    print(diga_ola(name))
except  AttributeError:
    print('Insira apenas texto')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Faça o seguinte teste:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute seu código&lt;/li&gt;
&lt;li&gt;Insira um o número &lt;code&gt;123&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;O resultado será: &lt;code&gt;Olá 123&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como assim? Acabamos de tratar este erro...&lt;br&gt;
O problema é que quando se trata de um &lt;strong&gt;input&lt;/strong&gt; todo dado é uma string, logo atende ao nosso requesido. Por isso, precisaremos tratar dentro de nosso método e "lançar" uma nova exceção.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lançando uma exceção
&lt;/h2&gt;

&lt;p&gt;Para &lt;em&gt;lançar&lt;/em&gt; uma nova exceção utilizaremos a palavra reservada &lt;code&gt;rise&lt;/code&gt; e dizer qual é seu tipo e a mensagem. Vamos modificar nosso método:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def  diga_ola(name: str) -&amp;gt; str:
    if name.isnumeric():
        raise  TypeError('Apenas letras')
    return f'Olá {nome}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No trecho &lt;code&gt;raise  TypeError('Apenas letras')&lt;/code&gt; estamos lançando um exceção do tipo &lt;code&gt;TypeError&lt;/code&gt; e passando por parâmetro a mensagem que será exibido.&lt;/p&gt;

&lt;p&gt;Conheça a lista de exceções padrões que poderá ser lançada que são nativas da linguagem Python na &lt;a href="https://docs.python.org/3/library/exceptions.html"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Já seguindo este curso, vamos implementar as outras regras:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def  diga_ola(name: str) -&amp;gt; str:
    if  name.isnumeric():
        raise  TypeError('Apenas letras.')  

    if  len(name) &amp;gt; 100:
        raise  OverflowError('Nome muito grante.')

    if  len(name) &amp;lt; 5:
        raise  ValueError('Nome pequeno.')

    return  f'Olá {name}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E podemos chamá-lo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try:
    name = input('Insira seu nome: ')
    print(diga_ola(name))
except  AttributeError:
    print('Insira apenas texto')
except  ValueError  as  error:
    print(error)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Está bem melhor de entender, mas ainda podemos melhorar.&lt;br&gt;
Ao verificar se o parâmetro é menor que 5, nós lançamos uma função genérica e exibindo sua mensagem. Será que poderíamos criar "Exceções Personalizadas" e tratá-las da maneira ideal e não de forma genérica?&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a id="excecoes-personalizadas"&gt;&lt;/a&gt;Exceções personalizadas
&lt;/h2&gt;

&lt;p&gt;Criar exceções personalizadas nos ajudará a deixar nosso código mais organizado e legível.&lt;br&gt;
Vamos criar  um arquivo chamado &lt;code&gt;exceptions.py&lt;/code&gt; com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class  NomePequenoException(ValueError):
    pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui nós estamos criando uma classe que estende a classe &lt;code&gt;ValueError&lt;/code&gt;. Apesar de não executar nada, nos será muito útil na leitura do código. Veja nosso código final completo, onde faremos a importação da exceção e tratamos de forma individual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import  Exceptions
def  diga_ola(name: str) -&amp;gt; str:
    if  name.isnumeric():
        raise  ValueError('Apenas letras.')  

    if  len(name) &amp;gt; 100:
        raise  OverflowError('Nome muito grante.')

    if  len(name) &amp;lt; 5:
        raise  Exceptions.NomePequenoException('Nome pequeno.')

    return  f'Olá {name}'

def  main():
    try:
        name = input('Insira seu nome: ')
        print(diga_ola(name))
    except  AttributeError:
        print('Insira apenas texto')
    except  Exceptions.NomePequenoException:
        print('Insira nomes com 5 ou mais letras')
    except  ValueError  as  error:
        print(error)

if  __name__ == '__main__':
    main()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;a id="conclusao"&gt;&lt;/a&gt; Conclusão
&lt;/h1&gt;

&lt;p&gt;Desenvolver um bom código não é só "o que funciona", mas também é se preocupar com a organização e legibilidade para facilitar a manutenção. Boa parte do tempo de desenvolvimento é encontrando falhas. Por isso, organizar as exceções ao desenvolver novas features nos ajudará a rastrear o erro e facilitará no processo de teste.&lt;/p&gt;

&lt;p&gt;No exemplo que criamos  temos o caso onde a função será chamada em apenas um lugar. Mas em um sistema maior, onde será chamado em vários lugares, por várias pessoas, poderemos ter formas diferentes de tratar estas exceções: fazendo um print, registrando um log, retornando a mensagem para um dashboard em um frontend, etc. Por isso, é uma boa prática deixar a cargo de quem executa o método decidir o que fazer quando houver a exceção.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dica: Ficamos presos em criar o menor número de linhas, a menor quantidade de arquivos, os nomes mais compactos de variáveis e métodos. Mas hoje, com a grande capacidade computacional e diversas ferramentas para compactar nosso código, a quantidades de bytes em um arquivo é o menor dos problemas. Sendo assim, não exite em criar arquivos de exceções, testes e escrever nomes coerentes para seus componentes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  &lt;a id="bonus"&gt;&lt;/a&gt;  Bônus: pytest
&lt;/h1&gt;

&lt;p&gt;Deixo aqui minha sugestão &lt;em&gt;off topic&lt;/em&gt; para o estudo de testes automatizados. A baixo terá as instruções para executar os testes aplicados a nosso exemplo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando ambiente
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://docs.python.org/3/library/venv.html"&gt;venv&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;python3 -m venv venv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Caso esteja no Windows e tenha erro ao encontrar o Python, tente executar assim ou consulte a &lt;a href="https://docs.python.org/3/library/venv.html"&gt;documentação&lt;/a&gt;:&lt;br&gt;
&lt;code&gt;py -m venv venv&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Ative o ambiente
&lt;/h3&gt;

&lt;p&gt;Linux: &lt;code&gt;source venv/bin/activate&lt;/code&gt;&lt;br&gt;
Windows: &lt;code&gt;venv/scripts/activate&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Instalando o pytest
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pip install pytest&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Arquivo te testes
&lt;/h3&gt;

&lt;p&gt;Crie o arquivo &lt;code&gt;test_exceptions.py&lt;/code&gt; (todos os testes deverão começar com &lt;strong&gt;test_&lt;/strong&gt;*)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import  pytest
import  random
import  Exceptions
from  main  import  diga_ola


def  test_quando_o_nome_for_composto_maior_que_5_letras():
    assert  diga_ola('Flávio Filipe') == 'Olá Flávio Filipe'


def test_quando_o_nome_for_menor_que_5_letras_nao_deve_permitir():
    with  pytest.raises(Exceptions.NomePequenoException):
        diga_ola('abc')


def teste_quando_inserir_numero_nao_deve_permitir():
    with  pytest.raises(TypeError):
        diga_ola('123')
def  test_nome_maior_que_100_letras():
    with  pytest.raises(OverflowError):
        nome = 'a'*100+'a'

diga_ola(nome)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Os trechos com &lt;code&gt;with pytest.raises(...):&lt;/code&gt; irá verificar se o retorno do contexto analisado será o erro especificado por parâmetro.&lt;/p&gt;
&lt;h3&gt;
  
  
  Executando os testes
&lt;/h3&gt;

&lt;p&gt;Execute na raiz do projeto:&lt;br&gt;
&lt;code&gt;pytest&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>python</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Bot para Twitter com Node.JS (Erros e acertos)</title>
      <dc:creator>Flávio Filipe</dc:creator>
      <pubDate>Mon, 18 Jan 2021 04:30:31 +0000</pubDate>
      <link>https://dev.to/flaviofilipe/bot-para-twitter-com-node-js-erros-e-acertos-1keb</link>
      <guid>https://dev.to/flaviofilipe/bot-para-twitter-com-node-js-erros-e-acertos-1keb</guid>
      <description>&lt;h1&gt;
  
  
  Resumo
&lt;/h1&gt;

&lt;p&gt;Este artigo tem o intuito de apresentar o meu processo de desenvolvimento do &lt;a href="https://github.com/flaviofilipe/surta-nao-bot/"&gt;Surta Não Bot&lt;/a&gt;, apresentando tanto a criação quanto os problemas enfrentados.&lt;br&gt;
A biblioteca utilizada para fazer a conexão com twitter foi a &lt;a href="https://github.com/ttezel/twit"&gt;Twit&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Motivação
&lt;/h1&gt;

&lt;p&gt;Após o lançamento da música de um amigo tive a ideia de criar um bot para o Twitter para divuga-lo. A proposta seria monitorar algumas hashtags específicas e comentar uma chamada para a música. O mesmo comportamento seria aplicado para quando o perfil fosse mencionado nos comentários.&lt;/p&gt;
&lt;h1&gt;
  
  
  Problema
&lt;/h1&gt;

&lt;p&gt;Após feito, testado e enviado para o servidor de "produção" não levou muito tempo para que a conta fosse suspensa e marcada como span. Isso aconteceu por não ter lido as &lt;a href="https://help.twitter.com/pt/rules-and-policies/twitter-reach-limited#spam"&gt;Regras e políticas do twitter&lt;/a&gt;.&lt;br&gt;
Em uma de suas clausulas é alertado que será considerado span &lt;em&gt;"se uma conta estiver tweetando para não seguidores de forma repetida e não solicitada ou se estiver envolvida em padrões de comportamento abusivo"&lt;/em&gt;.&lt;br&gt;
Abaixo apresento as etapas de criação do bot.&lt;/p&gt;
&lt;h1&gt;
  
  
  Etapa 1 - Credenciais no Twitter
&lt;/h1&gt;
&lt;h3&gt;
  
  
  Twitter Developers
&lt;/h3&gt;

&lt;p&gt;Após criar um novo perfil no twitter (ou utilizar um existente) é necessário criar um novo app no &lt;a href="https://developer.twitter.com/en/apps"&gt;Twitter Developers&lt;/a&gt;.&lt;br&gt;
Nesta etapa será preciso informar o intuito do bot e fazer a descrição em inglês. Caso tenha dificuldade com o idioma, recorra ao bom e velho Google Tradutor.&lt;/p&gt;
&lt;h1&gt;
  
  
  Etapa 2 - Criação do projeto
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Criei uma pasta chamada &lt;em&gt;surta-nao-bot&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Foi necessário baixar duas bibliotecas: Twit e dotenv. A primeira será utilizada para conectar a API do Twitter e a segunda para carregar as variáveis de ambiente do arquivo .env. Segue o comando para instalar ambas:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i twit
npm i dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Neste primeiro momento será necessário criar três arquivos: &lt;strong&gt;bot.js&lt;/strong&gt;, &lt;strong&gt;config.js&lt;/strong&gt; e &lt;strong&gt;.env&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  .env
&lt;/h3&gt;

&lt;p&gt;Dentro deste arquivo insira os códigos de acesso gerado no Twitter Developers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;consumer_key=
consumer_secret=
access_token=
access_token_secret=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  config.js
&lt;/h3&gt;

&lt;p&gt;Aqui será carregado as chaves de acesso criadas anteriormente para ser utilizada no projeto&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('dotenv').config();

module.exports = {
    consumer_key:process.env.consumer_key,
    consumer_secret:process.env.consumer_secret,
    access_token:process.env.access_token,
    access_token_secret:process.env.access_token_secret
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  bot.js
&lt;/h3&gt;

&lt;p&gt;Este é o arquivo onde terá o core do nosso bot. Para testar vamos criar um código simples onde será pesquisado no twitter posts com a hastag &lt;em&gt;"javascript"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config = require('./config');
const twit = require('twit')
const Twit = twit(config);

function searchTweets(params){

    Twit.get('search/tweets', params, (err, data, response) =&amp;gt; {
        let tweets = data.statuses;
        if(!err) {
            for(let dat of tweets){
                let retweetId = dat.id_str;
                console.log(retweetId);
            }
        }else{
            console.log(err);
        }
    })
}

console.log('Aqui!')
searchTweets({q: '#javascript'}) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute o arquivo &lt;strong&gt;bot.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node bot.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso tudo ocorra bem até aqui, podemos prosseguir para a próxima etapa.&lt;br&gt;
Caso dê algum erro confira as mensagens que serão exibidas no console. Um dos principais motivos poderá ser as chaves de acesso do Twitter.&lt;/p&gt;
&lt;h1&gt;
  
  
  Etapa 3 - Respondendo Tweets quando mencionado
&lt;/h1&gt;

&lt;p&gt;Seguindo a documentação do &lt;a href="https://github.com/ttezel/twit"&gt;Twit&lt;/a&gt;, usaremos o &lt;code&gt;Twit.stream&lt;/code&gt; para "escutar" um filtro. Neste caso, será feito um filtro no @ da conta, para quando for mecionado possa responder o tweet. Veja o código a baixo do arquivo &lt;a href="https://github.com/flaviofilipe/surta-nao-bot/blob/13597fa404075e74a652c6f81bf292af06ba3d08/bot.js"&gt;&lt;em&gt;bot.js&lt;/em&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config = require('./config');
const twit = require('twit')
const Twit = twit(config);

//Setting up a user stream
var stream = Twit.stream('statuses/filter', { track: '@surtanao_bb' });

stream.on('tweet', tweetEvent);

function tweetEvent(tweet) {
    // console.log(tweet)
    var reply_to = tweet.in_reply_to_screen_name;
    var text = tweet.text;
    var from = tweet.user.screen_name;
    var nameID = tweet.id_str;
    // params just to see what is going on with the tweets
    var params = { reply_to, text, from, nameID };
    console.log(params);

    let new_tweet = "It's me!!";
    if (from !== 'surtanao_bb') {
        new_tweet = 'Surta não @'+from+'!!! Ouça agora a nova música de Wander Luiz: https://bit.ly/SurtaNao';
    }

    var tweet = {
        status: new_tweet,
        in_reply_to_status_id: nameID
    }

    Twit.post('statuses/update', tweet, (err) =&amp;gt; {
        if (err) {
            console.log("Something went wrong!", err);
        } else {
            console.log("It worked!");
        }
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código a cima nós declaramos na variável &lt;code&gt;stream&lt;/code&gt; com o filtro que queremos fazer, neste caso com o perfil &lt;em&gt;@surtanao_bb&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Logo a baixo no trecho &lt;code&gt;stream.on('tweet', tweetEvent);&lt;/code&gt; é onde as coisas acontecem. A varíavel &lt;code&gt;stream&lt;/code&gt; agora é uma instancia do Twit Stream, por isso possui o método &lt;em&gt;on&lt;/em&gt; que recebe o evento que será "escutado" no primeiro parâmetro e a função que será executada no segundo, que recebe cada tweet encontrado.&lt;/p&gt;

&lt;p&gt;O método &lt;code&gt;tweetEvent&lt;/code&gt; recebe por parâmetero um objeto com os dados do tweet e logo no inicio colhe algumas informações, como o usuário que fez a postagem, o texto e o ID. Um pouco mais a baixo é motado a mensagem de resposta para enfim fazer a postagem utilizando o método post do Twit. Caso ocorra algum erro será exibido no console, se não, será impressa a mensagem "It worked!".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Para que funcione é necessário conceder permissão ao app, dentro do Twitter Developers, para ler e escrever mensagens. Eu apliquei a última opção &lt;em&gt;"Read + Write + Direct Messages"&lt;/em&gt;. Basta acessar seu app, na tela inicial acessar a opção &lt;em&gt;"App permissions"&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bom, até este momento o bot deverá executar com sucesso!&lt;br&gt;
Após este passo decidi inserir as opções de monitorar &lt;em&gt;hashtags&lt;/em&gt; específicas para responder automaticamente, o que não deu muito certo, pois pouco tempo depois a conta foi identificada como span. Confira o &lt;a href="https://github.com/flaviofilipe/surta-nao-bot/commit/f123a87b11a29358462be8f7397701844d03e825"&gt;commit&lt;/a&gt; da atualização caso queira ver o resultado.&lt;/p&gt;
&lt;h3&gt;
  
  
  Etapa 4 - Deploy na &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Para fazer o deploy será necessário ter uma conta na Heroku e criar um &lt;a href="https://dashboard.heroku.com/apps"&gt;novo app&lt;/a&gt; e ter instalado o &lt;a href="https://devcenter.heroku.com/articles/heroku-cli"&gt;heroku-cli&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Após configurado, dentro da pasta &lt;em&gt;surta-nao-bot&lt;/em&gt; será necessário adicionar um novo remote para o heroku, isso permitirá fazer o deploy utilizando o git.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;heroku git:remote -a nome-do-app-heroku
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Ao exececutar o comando a cima será criado um novo origin do repositório. Você poderá conferir com o comando a baixo:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para que o Heroku consiga executar a aplicação será necessário criar o arquivo &lt;code&gt;Procfile&lt;/code&gt; na raiz do projeto. A principio criei este arquivo com o código a baixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;worker: node bot.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Além disso fiz a alteração no arquivo &lt;code&gt;package.json&lt;/code&gt; para executar o comando &lt;code&gt;npm start&lt;/code&gt; no arquivo &lt;code&gt;bot.js&lt;/code&gt;. Segue o trecho de dentro do arquivo &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
"scripts": {
    "start": "node bot.js"
  },
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E fiz o deploy utilizando o git&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Antes de enviar para o servidor da Heroku já havia enviado para o github, por isso foi necessário criar o arquivo &lt;code&gt;.gitignore&lt;/code&gt; para que não fosse enviado o arquivo &lt;code&gt;.env&lt;/code&gt; com as credenciais de acesso. Por isso, ao fazer o push na heroku será necessário criar as variáveis de ambiente dentro da própria plataforma. Segue a baixo o código do .gitignore.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.env
node_modules
.vscode
package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Variáveis de ambiente na Heroku
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Acesse o app e abra as configurações no menu &lt;em&gt;settings&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Dentro da sessão &lt;em&gt;Config Vars&lt;/em&gt; crie as variáveis que estão no arquivo &lt;code&gt;.env&lt;/code&gt; do projeto, sendo a key o nome da variável e o value as chave de acesso.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Problema 2
&lt;/h3&gt;

&lt;p&gt;Até aí tudo bem, o código executou na heroku e o bot já estava funcionado. Porém ao acompanhar o arquivo de logs da Heroku com o comando &lt;code&gt;heroku logs -a&lt;/code&gt; percebi que após 60seg o bot era finalizado. Pensei que fosse a opção gratuita da plataforma até encontrar a solução.&lt;br&gt;
Em vários tutoriais os passos executados a cima pareciam funcionar, porém para que este tivesse sucesso eu precisei adicionar uma nova linha ao &lt;code&gt;Procfile&lt;/code&gt; informando a &lt;em&gt;web&lt;/em&gt;. Aparentemente todo app da heroku precisa ter algo do tipo, foi o que funcionou para mim. Segue o código do arquivo &lt;em&gt;Procfile&lt;/em&gt; final:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web: echo "whatever"
worker: node bot.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto! Agora sim o bot estará funcionando na heroku sem parar. Para fazer o deploy faça o push:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testando
&lt;/h3&gt;

&lt;p&gt;Para fazer o teste utilize uma outra conta e faça uma postagem mencionando o perfil do seu bot. Acompanhe os logs do servidor com &lt;code&gt;heroku logs --tail&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Melhorias
&lt;/h3&gt;

&lt;p&gt;Algumas melhorias foram feitas, como criar mensagens aleatórias para que seja exibidas nas respostas e a remoção da pesquisa pelas tags.&lt;/p&gt;

&lt;p&gt;Coisas como likes e retweets poderão ser exploradas dentro da documentação do &lt;a href="https://github.com/ttezel/twit"&gt;Twit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para acompanhar as atualizações do bot confira o &lt;a href="https://github.com/flaviofilipe/surta-nao-bot"&gt;repositório no Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>twitter</category>
      <category>heroku</category>
    </item>
  </channel>
</rss>
