<?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: Srijan Saurav</title>
    <description>The latest articles on DEV Community by Srijan Saurav (@sauravsrijan).</description>
    <link>https://dev.to/sauravsrijan</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%2F185748%2Fdba24200-9f23-4400-9ee8-4e34bb4a6869.jpg</url>
      <title>DEV Community: Srijan Saurav</title>
      <link>https://dev.to/sauravsrijan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sauravsrijan"/>
    <language>en</language>
    <item>
      <title>Python gotchas to look out for</title>
      <dc:creator>Srijan Saurav</dc:creator>
      <pubDate>Wed, 22 Apr 2020 07:21:25 +0000</pubDate>
      <link>https://dev.to/deepsource/python-gotchas-to-look-out-for-3ch6</link>
      <guid>https://dev.to/deepsource/python-gotchas-to-look-out-for-3ch6</guid>
      <description>&lt;h2&gt;
  
  
  1. Changes in &lt;code&gt;yield&lt;/code&gt; in Python 3.8
&lt;/h2&gt;

&lt;p&gt;With the release of Python 3.8, there were some major additions and breaking changes made to the language. There is a change in behavior while using &lt;code&gt;yield&lt;/code&gt; within  generator expressions and comprehensions.&lt;/p&gt;

&lt;p&gt;Take this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MAGIC_NUMBERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SECRET_NUMBERS&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;can_amaze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This was permitted till Python 3.7 (although it would still have thrown a &lt;code&gt;DeprecationWarning&lt;/code&gt;) — and became a &lt;code&gt;SyntaxError&lt;/code&gt; in Python 3.8.&lt;/p&gt;

&lt;p&gt;There are some more inconsistencies to watch out for when using &lt;code&gt;yield&lt;/code&gt;. In Python 2.7, for instance, this won't throw any errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Using `yield` in a generator expression:
&lt;/span&gt;&lt;span class="n"&gt;even_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&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;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Using ‘yield` in a set comprehension:
&lt;/span&gt;&lt;span class="n"&gt;odd&lt;/span&gt; &lt;span class="n"&gt;_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&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;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But, if &lt;code&gt;yield&lt;/code&gt; is used in a list comprehension like this, Python 2.7 throws a &lt;code&gt;SyntaxError&lt;/code&gt; saying &lt;code&gt;'yield' outside function&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;odd&lt;/span&gt; &lt;span class="n"&gt;_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&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;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In Python 3.x (till Python 3.7), all of the above mentioned operations were allowed. From Python 3.8 onwards, this has become illegal. To read more about this issue check out this &lt;a href="https://bugs.python.org/issue10544"&gt;bug report&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Raising another exception when &lt;code&gt;assert&lt;/code&gt; fails is ineffective
&lt;/h2&gt;

&lt;p&gt;When an &lt;code&gt;assert&lt;/code&gt; condition is not satisfied, it always raises an &lt;code&gt;AssertionError&lt;/code&gt;. Even if another built-in exception is explicitly raised, it will be ineffective.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_channels&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;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;'Number of image channels needs to be an integer'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, when assert fails, the user would be expecting a &lt;code&gt;ValueError&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ValueError: Number of image channels needs to be an integer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But instead, the above code will throw an &lt;code&gt;AssertionError&lt;/code&gt; when the condition fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AssertionError: Number of image channels needs to be an integer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Using the &lt;code&gt;sqrt&lt;/code&gt; method for Pythagorean calculations
&lt;/h2&gt;

&lt;p&gt;Calculating the length of the hypotenuse using the standard formula &lt;code&gt;sqrt(a**2 + b**2)&lt;/code&gt; may lead to an &lt;code&gt;OverflowError&lt;/code&gt; if  either of &lt;code&gt;a&lt;/code&gt; or &lt;code&gt;b&lt;/code&gt; or both are very large.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;get_hypotenuse&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;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;get_hypotenuse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2e154&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1e154&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running this gives the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OverflowError: (34, 'Numerical result out of range')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To avoid this, use the &lt;code&gt;hypot&lt;/code&gt; method from the &lt;code&gt;math&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;hypotenuse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hypot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2e154&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1e514&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Gives the desired output without overflowing
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Even if one (or both) side provided to the &lt;code&gt;hypot&lt;/code&gt; method is too big to be stored (say &lt;code&gt;2e308&lt;/code&gt; and &lt;code&gt;1e154&lt;/code&gt;), there won't be any runtime error and the return value would be &lt;code&gt;inf&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Empty modules
&lt;/h2&gt;

&lt;p&gt;Having empty modules lying around is never a good idea, as it populates the project unnecessarily. If the file is necessary for some reason, the file should be documented explaining why it is there.&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;Readability counts&lt;/strong&gt; ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Flask app running with &lt;code&gt;debug&lt;/code&gt; as &lt;code&gt;True&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Debuggers are meant to be used locally, and should never be enabled in production.&lt;/p&gt;

&lt;p&gt;When a flask app is run with its debug mode enabled, an attacker can gain access to the service running the application if the application uses an interactive debugger like &lt;code&gt;werkzeug&lt;/code&gt;. In such case, the application becomes vulnerable to remote code execution as any arbitrary code can be run through the interactive debugger.&lt;/p&gt;

&lt;p&gt;Here's an example of the vulnerability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/crash'&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;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The recommended way is to remove the statement enabling the debugger or to set the environment variable to disable this in the production environment. &lt;a href="https://labs.detectify.com/2015/10/02/how-patreon-got-hacked-publicly-exposed-werkzeug-debugger/"&gt;Here&lt;/a&gt; is an article about how Patreon got hacked because of this vulnerability.&lt;/p&gt;

&lt;p&gt;Find the original post &lt;a href="https://deepsource.io/blog/python-gotchas-to-look-out-for/"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>antipattern</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
