<?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>Forem: Inada Naoki</title>
    <description>The latest articles on Forem by Inada Naoki (@methane).</description>
    <link>https://forem.com/methane</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%2F41886%2F6ddf3e4c-8992-4d42-9edd-00a4fc9699ad.jpg</url>
      <title>Forem: Inada Naoki</title>
      <link>https://forem.com/methane</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/methane"/>
    <language>en</language>
    <item>
      <title>Python: Use the UTF-8 mode on Windows!</title>
      <dc:creator>Inada Naoki</dc:creator>
      <pubDate>Thu, 12 Dec 2019 06:59:46 +0000</pubDate>
      <link>https://forem.com/methane/python-use-utf-8-mode-on-windows-212i</link>
      <guid>https://forem.com/methane/python-use-utf-8-mode-on-windows-212i</guid>
      <description>&lt;p&gt;Summary: Set the &lt;code&gt;PYTHONUTF8=1&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;On macOS and Linux, UTF-8 is the standard encoding already.&lt;br&gt;
But Windows still uses legacy encoding (e.g. cp1252, cp932, etc...) as system encoding.&lt;/p&gt;

&lt;p&gt;Python works very well about file names and console IO (e.g. use ~W APIs).  But the legacy system encoding is used for the default encoding of text files and pipes.&lt;/p&gt;

&lt;p&gt;It is a very common mistake that omits the &lt;code&gt;encoding="utf-8"&lt;/code&gt; option.  Developers who use macOS or Linux doesn't have any trouble by the mistake.&lt;/p&gt;

&lt;p&gt;For example, even the &lt;a href="https://packaging.python.org/tutorials/packaging-projects/"&gt;packaging tutorial in the packaging.python.org&lt;/a&gt; uses this code snippet:&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;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"README.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;long_description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;README.md&lt;/code&gt; contains some non-ASCII characters (e.g. Unicode emoji),  &lt;code&gt;setup.py&lt;/code&gt; will fail on Windows.  Windows users can not install the package when wheel is not provided.  (I sent &lt;a href="https://github.com/pypa/packaging.python.org/pull/682"&gt;a pull request&lt;/a&gt; to fix this example code already.)&lt;/p&gt;

&lt;p&gt;I believe many Python programmers are suffered by this default text file encoding on Windows because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The default encoding of Python source code is UTF-8&lt;/li&gt;
&lt;li&gt;UTF-8 is the standard encoding of the Web&lt;/li&gt;
&lt;li&gt;Modern text editors like VS Code use UTF-8 by default.  And even the notepad.exe chose UTF-8 for the default encoding!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it is difficult to change the default encoding of text files because it is backward incompatible change.  It will break some legacy applications which relying on the legacy encoding.&lt;/p&gt;

&lt;p&gt;But there is good news: Python 3.7 introduced the &lt;a href="https://www.python.org/dev/peps/pep-0540/"&gt;"UTF-8 mode"&lt;/a&gt;. (thanks to Victor Stinner!!)&lt;/p&gt;

&lt;p&gt;When UTF-8 mode is enabled, Python uses UTF-8 as default encoding for text files instead of system encoding.&lt;br&gt;
You can live in the world "UTF-8 is the default.  Other legacy encodings are used only when explicitly specified." like macOS and Linux.&lt;/p&gt;

&lt;p&gt;To enable UTF-8 mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set the the environment variable &lt;code&gt;PYTHONUTF8=1&lt;/code&gt;, or&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;-Xutf8&lt;/code&gt; command line option.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>windows</category>
    </item>
    <item>
      <title>Use pip3 to install awscli</title>
      <dc:creator>Inada Naoki</dc:creator>
      <pubDate>Tue, 25 Jun 2019 15:19:42 +0000</pubDate>
      <link>https://forem.com/methane/use-pip3-to-install-awscli-44pk</link>
      <guid>https://forem.com/methane/use-pip3-to-install-awscli-44pk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;NOTE: AWS provides &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-bundle.html" rel="noopener noreferrer"&gt;bundled installer&lt;/a&gt;.  It is much better than &lt;code&gt;pip install awscli&lt;/code&gt;, especially when you are installing awscli on EC2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you know, Python 2 will be EOL at 2020-01-01.&lt;/p&gt;

&lt;p&gt;But more than 50% of downloads from PyPI are still from Python 2.7.  This graph is copied from &lt;a href="https://pypistats.org/packages/__all__" rel="noopener noreferrer"&gt;PyPI Stats&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgy9c0zcl9rwyy57hhj5o.png" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgy9c0zcl9rwyy57hhj5o.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This huge number of download from Python 2 put pressure on library authors to keep supporting Python 2.  I want to reduce this pressure by Python 2 EOL.&lt;/p&gt;

&lt;p&gt;Who uses Python 2 to &lt;code&gt;pip install&lt;/code&gt; so much?  This is a hint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5a6ukhhl2r63a3b3tg36.png" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5a6ukhhl2r63a3b3tg36.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most downloads are from Linux, although most Python users are using macOS or Windows.  We can assume most &lt;code&gt;pip install&lt;/code&gt; executions are for CI/CD/server deployment.&lt;/p&gt;

&lt;p&gt;Then which packages are most downloaded?  This is ranking from PyPI Stats:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc3vxl7yjo2dtbaww7hyh.png" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc3vxl7yjo2dtbaww7hyh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All packages in the top 20 are pip, awscli, and those dependencies!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj5ntq7jalzr6k7vc91et.png" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj5ntq7jalzr6k7vc91et.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And 80% of &lt;code&gt;pip install awscli&lt;/code&gt; are using Python 2!&lt;/p&gt;

&lt;p&gt;If you know some document or template uses Python 2 to install awscli, please suggest using Python 3 to the author.&lt;/p&gt;

&lt;p&gt;May Python 2 rest in peace.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>Don't omit __init__.py</title>
      <dc:creator>Inada Naoki</dc:creator>
      <pubDate>Fri, 17 May 2019 05:50:54 +0000</pubDate>
      <link>https://forem.com/methane/don-t-omit-init-py-3hga</link>
      <guid>https://forem.com/methane/don-t-omit-init-py-3hga</guid>
      <description>&lt;p&gt;I saw some people think Python 3 allow package without &lt;code&gt;__init__.py&lt;/code&gt; on Stackoverflow or mailing lists.&lt;/p&gt;

&lt;p&gt;This is misunderstanding.  Package directory without &lt;code&gt;__init__.py&lt;/code&gt; is "namespace package", not a regular package.  See &lt;a href="https://www.python.org/dev/peps/pep-0420/"&gt;PEP 420&lt;/a&gt; for reference.&lt;/p&gt;

&lt;p&gt;Namespace package is special package for people creating complex "distribution package" ("package" which can be registered on PyPI).  There is &lt;a href="https://packaging.python.org/guides/packaging-namespace-packages/"&gt;guide for namespace package&lt;/a&gt; in "Python Packaging User guide".&lt;/p&gt;

&lt;p&gt;There are some difference between namespace package and regular package.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;unittest&lt;/code&gt; module in standard library doesn't search into directory without &lt;code&gt;__init__.py&lt;/code&gt;.  If they do, they may take dozen seconds to search tests in &lt;code&gt;node_modules&lt;/code&gt; which contains millions of files and subdirectories.&lt;/p&gt;

&lt;p&gt;You should not omit &lt;code&gt;__init__.py&lt;/code&gt; in your project unless you are 100% sure about what "namespace package" is.  Use "regular package" with &lt;code&gt;__init__.py&lt;/code&gt; instead.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>How to speed up Python application startup time</title>
      <dc:creator>Inada Naoki</dc:creator>
      <pubDate>Fri, 19 Jan 2018 08:48:47 +0000</pubDate>
      <link>https://forem.com/methane/how-to-speed-up-python-application-startup-time-nkf</link>
      <guid>https://forem.com/methane/how-to-speed-up-python-application-startup-time-nkf</guid>
      <description>&lt;p&gt;I hear &lt;a href="https://pypi.python.org/pypi/pipenv" rel="noopener noreferrer"&gt;pipenv&lt;/a&gt; 9.0.2 is released with major startup time improvement.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-953294094029262849-987" src="https://platform.twitter.com/embed/Tweet.html?id=953294094029262849"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-953294094029262849-987');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=953294094029262849&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I tried it soon and I didn't feel it's fast.  So I investigated it with Python 3.7's new feature.&lt;/p&gt;

&lt;p&gt;In this article, I introduce the feature and how to use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Startup time ≒ import time
&lt;/h2&gt;

&lt;p&gt;For example, execution time of &lt;code&gt;pipenv -h&lt;/code&gt; is much larger than time to show help message.&lt;/p&gt;

&lt;p&gt;Generally speaking, when application starts, there are some startup process like loading environment variables or config files.&lt;/p&gt;

&lt;p&gt;In case of Python application, importing module takes most of startup time.  For example, &lt;code&gt;pipenv --version&lt;/code&gt; took about 800ms and &lt;code&gt;import pipenv&lt;/code&gt; took 700ms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ time local/py37/bin/python3 -c 'import pipenv'

real    0m0.696s
user    0m0.648s
sys     0m0.048s

$ time local/py37/bin/pipenv --version
pipenv, version 9.0.3

real    0m0.812s
user    0m0.761s
sys     0m0.052s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Show import time for modules
&lt;/h2&gt;

&lt;p&gt;Python 3.7 has new feature to show time for importing modules.&lt;/p&gt;

&lt;p&gt;This feature is enabled with &lt;code&gt;-X importtime&lt;/code&gt; option or &lt;code&gt;PYTHONPROFILEIMPORTTIME&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;For example, you can profile import time of pipenv by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.7 -X importtime -c 'import pipenv' 2&amp;gt; pipenv-imports
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PYTHONPROFILEIMPORTTIME=1 pipenv --version 2&amp;gt;pipenv-imports
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://paste.ubuntu.com/26409167/" rel="noopener noreferrer"&gt;Here is example output of &lt;code&gt;pipenv --version&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigating import time
&lt;/h2&gt;

&lt;p&gt;At last of the output, you can see these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time: self [us] | cumulative | imported package
...
import time:      3246 |     578972 |   pipenv.cli
import time:       507 |     579479 | pipenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In last line, 579479 means &lt;code&gt;import pipenv&lt;/code&gt; took 579 479us.&lt;/p&gt;

&lt;p&gt;While importing pipenv, many other modules are imported.  From above example, you can see &lt;code&gt;pipenv&lt;/code&gt; imports &lt;code&gt;pipenv.cli&lt;/code&gt;.  Subimports are indented with 2 spaces.&lt;/p&gt;

&lt;p&gt;See last line again. 507 means only 507us was took when running pipenv module. 579 479 - 507 = 578 972us is used for subimports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding slow part
&lt;/h2&gt;

&lt;p&gt;Let's find slow subtree from the output.  I selected some lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time: self [us] | cumulative | imported package
...
import time:     86500 |     179327 | pkg_resources
...
import time:       385 |     236655 |             IPython
import time:        22 |     236677 |           IPython.core
import time:        26 |     236703 |         IPython.core.magic
import time:       978 |     237680 |       dotenv.ipython
import time:       199 |     239032 |     dotenv
...
...
import time:      3246 |     578972 |   pipenv.cli
import time:       507 |     579479 | pipenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  pkg_resources
&lt;/h3&gt;

&lt;p&gt;As you can see, importing &lt;code&gt;pkg_resources&lt;/code&gt; is slow.&lt;br&gt;
And surprisingly, &lt;code&gt;pkg_resources&lt;/code&gt; is not indented; it's not subimport of &lt;code&gt;pipenv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It means &lt;code&gt;pkg_resources&lt;/code&gt; is imported by &lt;code&gt;pipenv&lt;/code&gt; script, not module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat local/py37/bin/pipenv
#!/home/inada-n/local/py37/bin/python3.7
# EASY-INSTALL-ENTRY-SCRIPT: 'pipenv==9.0.3','console_scripts','pipenv'
__requires__ = 'pipenv==9.0.3'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(
        load_entry_point('pipenv==9.0.3', 'console_scripts', 'pipenv')()
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bad news: Importing &lt;code&gt;pkg_resources&lt;/code&gt; is slow.  It's known issue and it's difficult to fix without breaking backward compatibility.&lt;/p&gt;

&lt;p&gt;Good news: you can avoid importing pkg_resources!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ local/py37/bin/pip install wheel
$ local/py37/bin/pip install -U --force-reinstall pipenv
$ time local/py37/bin/pipenv --version
pipenv, version 9.0.3

real    0m0.704s
user    0m0.653s
sys     0m0.052s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When wheel is installed, pip builds wheel and install from it.&lt;/p&gt;

&lt;p&gt;Installing from wheel (.whl) and from source package (.tar.gz) are different process.&lt;br&gt;
When installing from wheel, pkg_resources is not used in script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat local/py37/bin/pipenv
#!/home/inada-n/local/py37/bin/python3.7

# -*- coding: utf-8 -*-
import re
import sys

from pipenv import cli

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(cli())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  IPython
&lt;/h3&gt;

&lt;p&gt;See next part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time:       385 |     236655 |             IPython
import time:        22 |     236677 |           IPython.core
import time:        26 |     236703 |         IPython.core.magic
import time:       978 |     237680 |       dotenv.ipython
import time:       199 |     239032 |     dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pipenv&lt;/code&gt; imports &lt;code&gt;dotenv&lt;/code&gt;, &lt;code&gt;dotenv&lt;/code&gt; imports &lt;code&gt;dotenv.ipython&lt;/code&gt;, and it imports &lt;code&gt;IPython&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's why &lt;code&gt;pipenv&lt;/code&gt; starts slow on my environment; I have IPython installed.&lt;/p&gt;

&lt;p&gt;But why IPython is imported?  I read dotenv source and I found it's for IPython's extension.&lt;/p&gt;

&lt;p&gt;Surely, pipenv and many dotenv users don't use IPython extension.&lt;br&gt;
I made &lt;a href="https://github.com/theskumar/python-dotenv/pull/84" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; to dotenv which make importing IPython on demand.&lt;/p&gt;

&lt;p&gt;And since pipenv has own copy of dotenv, I made &lt;a href="https://github.com/pypa/pipenv/pull/1326" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; to pipenv which removes &lt;code&gt;dotenv.ipython&lt;/code&gt; completely.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I can reduce time for &lt;code&gt;pipenv --version&lt;/code&gt; from 800ms to 500ms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ time local/py37/bin/pipenv --version
pipenv, version 9.0.3

real    0m0.503s
user    0m0.463s
sys     0m0.040s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import time profiling is very nice way to investigating and optimize application startup time.&lt;/p&gt;

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