<?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: Armand Sauzay</title>
    <description>The latest articles on DEV Community by Armand Sauzay (@armandsauzay).</description>
    <link>https://dev.to/armandsauzay</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%2F984330%2Fa7821b11-53b6-47ef-acb6-7c04b8012ff1.jpeg</url>
      <title>DEV Community: Armand Sauzay</title>
      <link>https://dev.to/armandsauzay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/armandsauzay"/>
    <language>en</language>
    <item>
      <title>How to properly setup your Python project</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Tue, 16 May 2023 21:22:03 +0000</pubDate>
      <link>https://dev.to/armandsauzay/how-to-properly-setup-your-python-project-3fng</link>
      <guid>https://dev.to/armandsauzay/how-to-properly-setup-your-python-project-3fng</guid>
      <description>&lt;p&gt;Industry best practices to kickstart your python project.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2AK94o6os3wF0iA4okKFot5A.jpeg" 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%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2AK94o6os3wF0iA4okKFot5A.jpeg" alt="How to properly setup your Python project" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo by David Clode on Unsplash&lt;/p&gt;

&lt;p&gt;As you start working on your python project, you will likely need to set it up&lt;br&gt;
in a consistent and collaboration-friendly way. In this article, I'll describe a&lt;br&gt;
setup that works great for my projects. It includes many industry best practices&lt;br&gt;
and aims at explaining how to install python, run automated checks in a GitOps&lt;br&gt;
fashion and structure your project.&lt;/p&gt;

&lt;p&gt;This article covers quite a few topics. To ease the reading, I've split each topic into two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📚 indicates the &lt;strong&gt;theory&lt;/strong&gt; part &lt;/li&gt;
&lt;li&gt;🛠️ indicates the &lt;strong&gt;practical&lt;/strong&gt; part (i.e. the commands you need to run).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes you will also see a 💡 section, indicating a tip or a trick.&lt;/p&gt;
&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install a Python version manager&lt;/li&gt;
&lt;li&gt;Choose an environment manager (poetry)&lt;/li&gt;
&lt;li&gt;Alternatively, use Docker as a Dev Environment instead&lt;/li&gt;
&lt;li&gt;Add Some Code&lt;/li&gt;
&lt;li&gt;Write Some Tests&lt;/li&gt;
&lt;li&gt;Lint your code&lt;/li&gt;
&lt;li&gt;Automate checks on local with pre-commit&lt;/li&gt;
&lt;li&gt;Automate checks on remote with GitHub Actions&lt;/li&gt;
&lt;li&gt;Automate your release with GitHub Actions&lt;/li&gt;
&lt;li&gt;Enjoy the benefits of your new code practices&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1. Install a Python version manager
&lt;/h2&gt;

&lt;p&gt;📚 The first thing you will need to do is to install a python version manager. A&lt;br&gt;
python version manager will allow you to install multiple versions of python on&lt;br&gt;
your machine and switch between them easily.&lt;/p&gt;

&lt;p&gt;To illustrate this, let's say you have a project that requires python 3.6 and&lt;br&gt;
another project that requires python 3.7. If you only have python 3.7 installed&lt;br&gt;
on your machine, you will have to uninstall it and install python 3.6 every time&lt;br&gt;
you want to work on the first project... This is where a python version manager&lt;br&gt;
comes in handy.&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://github.com/pyenv/pyenv" rel="noopener noreferrer"&gt;pyenv&lt;/a&gt; for this and follow the &lt;br&gt;
&lt;a href="https://github.com/pyenv/pyenv#installation" rel="noopener noreferrer"&gt;installation instructions&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;🛠️ At the time of writing this document, you can install pyenv by running the&lt;br&gt;
following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://pyenv.run | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want more control over the installation, on mac for instance you can run:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use brew to install pyenv&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;pyenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Depending on the shell you use, add pyenv to your PATH.&lt;/p&gt;

&lt;p&gt;💡 If you're not sure which shell you're using, you can run the following command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;For bash:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PYENV_ROOT="$HOME/.pyenv"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'command -v pyenv &amp;gt;/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'eval "$(pyenv init -)"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;For zsh:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PYENV_ROOT="$HOME/.pyenv"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'command -v pyenv &amp;gt;/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'eval "$(pyenv init -)"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Choose an environment manager (poetry)
&lt;/h2&gt;

&lt;p&gt;📚 Now that you have a python version manager, you will need to install an&lt;br&gt;
environment manager. An environment manager will allow you to create isolated&lt;br&gt;
environments for your projects. This is useful when you work on multiple&lt;br&gt;
projects that require different versions of the same package. And it is a great&lt;br&gt;
practice overall to make sure anyone can run your project. &lt;/p&gt;

&lt;p&gt;To illustrate this, let's say you have a project that requires &lt;code&gt;pandas&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;matplotlib&lt;/code&gt; to do some data analysis and another project that requires&lt;br&gt;
&lt;code&gt;tensorflow&lt;/code&gt; to do some machine learning. It is considered a good practice to&lt;br&gt;
create a separate environment for each project. This way, you can install&lt;br&gt;
only the packages you need for each project and avoid any conflicts between&lt;br&gt;
packages.&lt;/p&gt;

&lt;p&gt;There are many environment managers (pipenv, conda, virtualenv, python&lt;br&gt;
built-in venv, etc...). I personally use &lt;a href="https://python-poetry.org/" rel="noopener noreferrer"&gt;poetry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In general, your environment manager will be installed with your python version. &lt;br&gt;
For instance, if you use pyenv, you can install poetry by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyenv &lt;span class="nb"&gt;install &lt;/span&gt;3.10.6
pyenv global 3.10.6
pip &lt;span class="nb"&gt;install &lt;/span&gt;poetry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, poetry will live in your python environment. This means that&lt;br&gt;
you can have a different version of poetry for each python version you have&lt;br&gt;
installed on your machine.&lt;/p&gt;

&lt;p&gt;🛠️ Pip installing poetry in your python environment with pip is one way to do it but you can also follow the steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use the curl command to install poetry&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://install.python-poetry.org | python3 -
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Add poetry to your PATH. On MacOS, poetry is added at &lt;code&gt;~/Library/Application&lt;br&gt;
Support/pypoetry/venv/bin/poetry&lt;/code&gt;. So you can add it to your PATH by adding the&lt;br&gt;
following line to your ~/.bashrc or ~/.zshrc file:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/pypoetry/venv/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;If you are using a different shell, you can find the path to poetry by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry config &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;--local&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;virtualenvs.path
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;And then add it to your PATH.&lt;/p&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  3. Alternatively, use Docker as a Dev Environment instead
&lt;/h2&gt;

&lt;p&gt;If you don't want to install a python version manager and an environment&lt;br&gt;
manager, or want to abstract this for your team, you can use Docker instead. I&lt;br&gt;
won't go into too many details here but if you're interested, VSCode has a great&lt;br&gt;
&lt;a href="https://code.visualstudio.com/docs/devcontainers/containers" rel="noopener noreferrer"&gt;integration with&lt;br&gt;
Docker&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Add Some Code
&lt;/h2&gt;

&lt;p&gt;📚 Now that you have a python version manager and an environment manager, you&lt;br&gt;
can start working on your project. Let's write some simple functions to get&lt;br&gt;
started. For illustration purposes we'll create a simple CLI that prints "Hello&lt;br&gt;
&lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;" when you run it and give how many repositories &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; has on GitHub.&lt;/p&gt;

&lt;p&gt;💡 By default, poetry wants you to create a package with a folder named as your&lt;br&gt;
git repository (with the only difference that it wants underscores instead of dashes). So if your git&lt;br&gt;
repository is called &lt;code&gt;python-project-template&lt;/code&gt;, poetry will create a folder&lt;br&gt;
called &lt;code&gt;python_project_template&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;💡 You can find the code for this section at &lt;a href="https://github.com/armand-sauzay/hello-world-cli" rel="noopener noreferrer"&gt;armand-sauzay/hello-world-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case let's call our project &lt;code&gt;hello-world&lt;/code&gt;. So we'll create a folder&lt;br&gt;
called &lt;code&gt;hello_world&lt;/code&gt; and add a file called &lt;code&gt;__init__.py&lt;/code&gt; to it. &lt;/p&gt;

&lt;p&gt;🛠️ Use gh to create a new repository called &lt;code&gt;hello-world&lt;/code&gt; and clone it to your&lt;br&gt;
machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh repo create &amp;lt;your-github-username&amp;gt;/hello-world-cli &lt;span class="nt"&gt;--template&lt;/span&gt; armand-sauzay/python-template &lt;span class="nt"&gt;--public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To initialize your project, run the following command (it comes from the template above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./script/bootstrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the requests package to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry add requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, we ran the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyenv &lt;span class="nb"&gt;install &lt;/span&gt;3.10.6 &lt;span class="c"&gt;# install python 3.10.6&lt;/span&gt;
pyenv global 3.10.6 &lt;span class="c"&gt;# (optional) set python 3.10.6 as the default python version&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;poetry &lt;span class="c"&gt;# install poetry as a python package in your python 3.10.6 environment&lt;/span&gt;
poetry add requests &lt;span class="c"&gt;# add the requests package to your project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;hello_world_cli&lt;/code&gt; folder a file called &lt;code&gt;main.py&lt;/code&gt; and add the following code to it:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&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="n"&gt;argv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&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="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The name to greet and count repos for&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&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;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;""&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Username cannot be empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&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;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;repos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&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;https://api.github.com/users/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/repos&lt;/span&gt;&lt;span class="sh"&gt;"&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;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to fetch repos for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;repos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You have &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; repos.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# type: ignore
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a few tricks here that are worth mentioning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use &lt;code&gt;argparse&lt;/code&gt; to parse the arguments passed to our CLI. This is a built-in
python package that allows you to parse arguments passed to your CLI. &lt;/li&gt;
&lt;li&gt;We use &lt;code&gt;argv&lt;/code&gt; to pass the arguments to our main function. This is useful for
testing purposes. We can pass a list of arguments to our main function and
test it without having to run the CLI.&lt;/li&gt;
&lt;li&gt;We use &lt;code&gt;SystemExit&lt;/code&gt; to exit our program. This is a built-in python exception
that allows you to exit your program with a specific exit code (0 for success, 1 for failure).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Write Some Tests
&lt;/h2&gt;

&lt;p&gt;📚 Now that you have a few basic methods, you can start writing some tests. Tests make sure your code behaves as expected. There&lt;br&gt;
are many types of tests (unit tests, integration tests, end-to-end tests, etc...)&lt;br&gt;
but in this article, we will focus on unit tests. Unit tests are tests that&lt;br&gt;
check the smallest unit of your code (i.e. a function or a method).&lt;/p&gt;

&lt;p&gt;🛠️ Create a file called &lt;code&gt;test_main.py&lt;/code&gt; and add the following code to it:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hello_world_cli.cli&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capsys&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--name&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;test&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="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capsys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readouterr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# test is a user which does not have any contributions since 2010. 
&lt;/span&gt;    &lt;span class="c1"&gt;# Hopefully this will not change in the future and the test will not break.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello test!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;You have 5 repos.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_main_empty_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capsys&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--name&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="p"&gt;])&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;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capsys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readouterr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Username cannot be empty&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We use &lt;code&gt;capsys&lt;/code&gt; to capture the output of our CLI. This is a pytest built-in that allows you to capture the output of your CLI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Lint your code
&lt;/h2&gt;

&lt;p&gt;📚 Now that you have some tests, you can start linting your code. Linting is the&lt;br&gt;
process of checking your code for potential errors. There are many linters out&lt;br&gt;
there (pylint, flake8, black, etc...). I personally use flake8, black, isort and&lt;br&gt;
mypy. Ruff is also becoming quite popular and replaces flake8 and isort.&lt;/p&gt;

&lt;p&gt;🛠️ To install flake8, black, isort and mypy, you can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry add &lt;span class="nt"&gt;--dev&lt;/span&gt; flake8 black isort mypy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can use mypy to check your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry run mypy hello_world_cli/cli.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use flake8 to check your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry run flake8 hello_world_cli/cli.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use black to format your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry run black hello_world_cli/cli.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you would not really want to run these commands manually every time you&lt;br&gt;
change your code. This is where pre-commit comes in handy, to both make sure you&lt;br&gt;
don't commit wrongly formatted code and to not have to run these commands&lt;br&gt;
manually.&lt;/p&gt;

&lt;p&gt;Also, do note that some of these linters have small incompatible differences.&lt;br&gt;
For example, black will complain if you have a line longer than 88 characters,&lt;br&gt;
but flake8 will complain if you have a line longer than 79 characters. You need&lt;br&gt;
to configure them to work correctly together: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you should create a .flake8 file with the following content:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;flake8]
max-line-length &lt;span class="o"&gt;=&lt;/span&gt; 88
extend-ignore &lt;span class="o"&gt;=&lt;/span&gt; E203
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;you should create a .isort.cfg file with the following content:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;settings]
profile &lt;span class="o"&gt;=&lt;/span&gt; black
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;you can read more on the &lt;a href="https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html" rel="noopener noreferrer"&gt;black documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  7. Automate checks on local with pre-commit
&lt;/h2&gt;

&lt;p&gt;📚 Now that you have some tests and some linters, you can start automating your&lt;br&gt;
checks. The goal of automating your checks is to make sure your code is always&lt;br&gt;
in a good state. There are many tools out there that can help you automate your&lt;br&gt;
checks (pre-commit, tox, etc...). I personally use pre-commit.&lt;/p&gt;

&lt;p&gt;🛠️ To install pre-commit, you can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can run pre-commit&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pre-commit run &lt;span class="nt"&gt;--all-files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*0zUt-ahuexfeelyOa8iYOQ.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2A0zUt-ahuexfeelyOa8iYOQ.png" alt="pre-commit" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can see on the image above that pre-commit is running the checks that we
defined in the &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Note that this file is coming from the template above in 
step 4.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Automate checks on remote with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;📚 Now that you have some tests and some linters, you can start automating your&lt;br&gt;
checks on the server side. The goal of automating your checks on the server side&lt;br&gt;
is to make sure your code is always in a good state. There are many tools out&lt;br&gt;
there that can help you automate your checks (GitHub Actions, Travis CI, Circle&lt;br&gt;
CI, etc...). I personally use GitHub Actions.&lt;/p&gt;

&lt;p&gt;🛠️ To set up GitHub Actions, you can create a file called &lt;code&gt;.github/workflows/ci.yaml&lt;/code&gt; and add the following code to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;armand-sauzay/actions-python/lint@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;

  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;armand-sauzay/actions-python/test@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;test-flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this file should already be created if you used the template mentionned above (see gh command in step 4. &lt;/p&gt;

&lt;p&gt;Explanation: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you're not familiar with the syntax of GitHub Actions, you can read the &lt;a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Here we call two jobs: lint and test. Each job runs on ubuntu-latest (a Linux machine).&lt;/li&gt;
&lt;li&gt;The lint job uses the &lt;a href="https://github.com/armand-sauzay/actions-python/tree/main/lint" rel="noopener noreferrer"&gt;armand-sauzay/actions-python/lint&lt;/a&gt; action to run pre-commit.&lt;/li&gt;
&lt;li&gt;The test job uses the &lt;a href="https://github.com/armand-sauzay/actions-python/tree/main/test" rel="noopener noreferrer"&gt;armand-sauzay/actions-python/test&lt;/a&gt; action to run pytest. Here we pass a flag to pytest to just have a dummy test. You can remove this flag to run your actual tests.&lt;/li&gt;
&lt;/ul&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%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2Ahm_WdYYhhdWNDrIXb5MoFA.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%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2Ahm_WdYYhhdWNDrIXb5MoFA.png" alt="remote-checks" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Automate your release with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;📚 We have briefly talked about linting - using black, flake8, isort and mypy - and testing - using pytest. Release is an equally important concept that allows you to give versions to &lt;/p&gt;

&lt;p&gt;🛠️ To set up GitHub Actions, you can create a file called &lt;code&gt;.github/workflows/release.yaml&lt;/code&gt; and add the following code to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# enable manual release&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;armand-sauzay/actions-python/lint@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;

  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;armand-sauzay/actions-python/test@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;test-flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--version&lt;/span&gt;

  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Release&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;new-release-published&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.release.outputs.new-release-published }}&lt;/span&gt;
      &lt;span class="na"&gt;new-release-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.release.outputs.new-release-version }}&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;armand-sauzay/actions-python/release@v1&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ADMIN_TOKEN || secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*0NeO14HG1cZ3uw3vEZWSEw.png" rel="noopener noreferrer"&gt;release&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few things worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;this workflow will trigger on push on the main branch and on manual trigger (workflow_dispatch)&lt;/li&gt;
&lt;li&gt;it will run the lint and test jobs&lt;/li&gt;
&lt;li&gt;it will then run the release job which is semantically versioning your code and creating a release on GitHub. In case you don't know what semantic versioning is, you can read the &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In order to follow semantic versioning, you can follow conventional commits (this is why the commits show up as &lt;code&gt;fix: ...&lt;/code&gt; or &lt;code&gt;feat: ...&lt;/code&gt; in the release notes). You can read more on &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;conventional commits&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Sometimes you might have a protected branch, for which the default GITHUB_TOKEN wouldn't have enough permissions to create a release. In that case, you can create a personal access token called &lt;code&gt;ADMIN_TOKEN&lt;/code&gt; and give it the right permissions. You can then use this token in the workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Enjoy the benefits of your new code practices
&lt;/h2&gt;

&lt;p&gt;Now you know how to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use pyenv to install different python versions &lt;/li&gt;
&lt;li&gt;use poetry to manage your dependencies (poetry add/remove)&lt;/li&gt;
&lt;li&gt;use pytest to test your python code &lt;/li&gt;
&lt;li&gt;what linting is and how to use flake8, black, isort and mypy&lt;/li&gt;
&lt;li&gt;use pre-commit to automate your checks on your local machine&lt;/li&gt;
&lt;li&gt;use GitHub Actions to automate your checks on the server side&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy the benefits of your new code practices! 🎉&lt;/p&gt;

&lt;p&gt;As always, if you have any questions, feel free to leave a comment below or reach out to me on the different platforms:&lt;/p&gt;


&lt;p&gt;&lt;br&gt;
&lt;a href="https://github.com/armand-sauzay" rel="noopener noreferrer"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FFortAwesome%2FFont-Awesome%2F6.x%2Fsvgs%2Fbrands%2Fgithub.svg" width="496" height="512"&gt;&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FFortAwesome%2FFont-Awesome%2F6.x%2Fsvgs%2Fbrands%2Ftwitter.svg" width="512" height="512"&gt;&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/" rel="noopener noreferrer"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FFortAwesome%2FFont-Awesome%2F6.x%2Fsvgs%2Fbrands%2Flinkedin.svg" width="448" height="512"&gt;&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
&lt;a href="https://armand-sauzay.github.io/#/about" rel="noopener noreferrer"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FFortAwesome%2FFont-Awesome%2F6.x%2Fsvgs%2Fsolid%2Fglobe.svg" alt="4214976" width="512" height="512"&gt;&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/@armand-sauzay" rel="noopener noreferrer"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FFortAwesome%2FFont-Awesome%2F6.x%2Fsvgs%2Fbrands%2Fmedium.svg" alt="4214976" width="640" height="512"&gt;&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/armandsauzay"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FFortAwesome%2FFont-Awesome%2F6.x%2Fsvgs%2Fbrands%2Fdev.svg" width="448" height="512"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>softwareengineering</category>
      <category>devops</category>
      <category>cli</category>
    </item>
    <item>
      <title>How Fair Are Your Machine Learning Models?</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Tue, 07 Mar 2023 18:22:01 +0000</pubDate>
      <link>https://dev.to/armandsauzay/how-fair-are-your-machine-learning-models-3kga</link>
      <guid>https://dev.to/armandsauzay/how-fair-are-your-machine-learning-models-3kga</guid>
      <description>&lt;p&gt;A quick introduction to the topic of fairness with hands on coding. Evaluate your machine learning model fairness in just a few lines of code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uLBXYjgL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AMZWIZHRWNqGkyoC_MKT-OA.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uLBXYjgL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AMZWIZHRWNqGkyoC_MKT-OA.webp" alt="Photo by Wesley Tingey on Unsplash" width="880" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; Photo by Wesley Tingey on Unsplash &lt;/p&gt;

&lt;p&gt;Are Machine Learning models "fair"? When increasingly more decisions are backed by ML algorithms, it becomes important to understand the biases they can create.&lt;/p&gt;

&lt;p&gt;But what does "fairness" mean? This is where it gets a little political (and mathematical)… To illustrate our thoughts, we'll take the example of a machine learning model which predicts whether a salary should be higher than 50K/year based on a number of features including &lt;strong&gt;age&lt;/strong&gt; and &lt;strong&gt;gender&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And maybe you've already guessed, by looking at these two features, that fairness can have different definitions. Fair for &lt;strong&gt;gender&lt;/strong&gt; might mean that we want to have the a prediction which is independent of gender (i.e. paying the same people who only differ by their gender). Fair for &lt;strong&gt;age&lt;/strong&gt; might mean something else. We'd probably want to allow a certain correlation between the prediction and the age, as it seems fair to pay better older individuals (which usually are more experienced).&lt;/p&gt;

&lt;p&gt;One key thing to understand is that what is judged "fair" is sometimes not even respected in the data itself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How would the model learn that men and women should be paid the same at equal levels it it does not observe this in the data itself ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HdrrlQC7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AW_rBWQ-Z1Mw3sE43lDfNLw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HdrrlQC7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AW_rBWQ-Z1Mw3sE43lDfNLw.webp" alt="data biases vs model biases" width="880" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; Figure1: data biases vs model biases &lt;/p&gt;

&lt;p&gt;Now that we have a bit of context on the problem, let's get into the math (Section 1) and the code (Sections 2 and 3)to be able to evaluate and address unfairness issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; A few fairness concepts&lt;/li&gt;
&lt;li&gt;Evaluating Data Biases&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Evaluating and Correcting Model Biases with Fairlearn   &lt;/p&gt;

&lt;p&gt;a. Evaluating bias &lt;/p&gt;

&lt;p&gt;b. Correcting bias&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;All the code for this tutorial can be found on Kaggle &lt;a href="https://www.kaggle.com/code/armandsauzay/a-primer-on-fairness-with-fairlearn"&gt;here&lt;/a&gt;. Feel free to run the notebook yourself or create a copy!&lt;/p&gt;




&lt;h2&gt;
  
  
  1. A few fairness concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1. Mathematical definition of fairness
&lt;/h3&gt;

&lt;p&gt;In order to simplify things, we'll restrict the scope to binary classification (predict whether someone should be paid more than 50K/year).&lt;br&gt;
Usually, we'll call:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;X: the feature matrix&lt;/li&gt;
&lt;li&gt;Y: the target&lt;/li&gt;
&lt;li&gt;A: Sensitive feature, usually one of the columns of X&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For &lt;strong&gt;binary classification&lt;/strong&gt;, two main definition of fairness exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Demographic parity&lt;/strong&gt; (also known as statistical parity): A classifier h satisfies demographic parity under a distribution over (X,A,Y) if its prediction h(X) is statistically independent of the sensitive feature A. This is equivalent to: &lt;code&gt;E[h(X)|A=a]=E[h(X)]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Equalized odds&lt;/strong&gt;: A classifier h satisfies equalized odds under a distribution over (X,A,Y) if its prediction h(X) is conditionally independent of the sensitive feature A given the label Y. This is equivalent to: &lt;code&gt;E[h(X)|A=a,Y=y]=E[h(X)|Y=y]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: a third one exists but is more rarely used: &lt;strong&gt;equal opportunity&lt;/strong&gt; is a relaxed version of equalized odds that only considers conditional expectations with respect to positive labels.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  1.2. Fairness in words
&lt;/h3&gt;

&lt;p&gt;In "simpler words":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Demographic parity&lt;/strong&gt;: the prediction should be independent from the sensitive features (for instance independent from gender). It states that all categories from the protected feature should receive the positive outcome at the same rate (it plays on selection rate)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Equalized odds&lt;/strong&gt;: the prediction can be correlated to the sensitive feature, to the extent it is explained by the data we see&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1.3. Why does it matter?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;OK, that's interesting, but why does it matter? And how can I use those mathematical concepts?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;→ Let's take two examples of features and then explain what type of fairness we want to have for this feature. Going back to the previous example of salary prediction, let's say you are the CEO of a very big company and want to build an algorithm which would give you the salary you should give to your employees based on performance indicators. Ideally you would look for something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Demographic Parity for gender: the salary prediction should be independent from the gender&lt;/li&gt;
&lt;li&gt;Equalized Odds for Age: the salary prediction should not be independent from Age (you want to still pay more employees with more experience) but you still want to control that the salary so that you do not end up being too skewed → you don't want to end up in the situation where the algorithm exacerbates even more the inequalities (pays the youth even less and the elders even more)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without further due, let's get into the implementation details on how we can evaluate fairness and "retrain" our Machine Learning models against its biases. For this we're going to use the &lt;a href="https://archive.ics.uci.edu/ml/datasets/adult"&gt;UCI Adult Dataset&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Evaluating Data Biases
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;NOTE: once again, you can find all the associated code &lt;a href="https://www.kaggle.com/code/armandsauzay/a-primer-on-fairness-with-fairlearn"&gt;here&lt;/a&gt;.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Biases can exist in the data itself. Let's just load the data and plot the percentage of Male/Female having a salary above 50K.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ooDDayKd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1106/1%2AdMFb4gM4LjtQ5TC52fBTVA.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ooDDayKd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1106/1%2AdMFb4gM4LjtQ5TC52fBTVA.webp" width="880" height="620"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--48befrN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/896/1%2Ad5GJ2Z7Yz3uom5ANr96yGQ.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--48befrN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/896/1%2Ad5GJ2Z7Yz3uom5ANr96yGQ.webp" width="840" height="730"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt; Figure 2: gender and age impact on salary &lt;/p&gt;

&lt;p&gt;We see that the percentage of males having a salary above 50K is almost 3x the percentage of females. (!!)&lt;/p&gt;

&lt;p&gt;If the algorithm learns on this data it will definitely be biased. To counter this bias we can either: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cherry pick data so that the percentage of male &lt;/li&gt;
&lt;li&gt;use fairlearn to correct the bias after the model is trained on this unfair data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In section 3, we'll focus on the second approach.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Evaluating and Correcting Model Biases with Fairlearn
&lt;/h2&gt;
&lt;h3&gt;
  
  
  3.1. Evaluating bias
&lt;/h3&gt;

&lt;p&gt;One of the most interesting features here is probably &lt;strong&gt;selection rate&lt;/strong&gt;. It is the rate of predicting positive outcomes (in this case, whether salary is above 50K)&lt;/p&gt;

&lt;p&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bm_Bk8UP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/708/1%2AoflHCW6PPNRa2Eb0yAIjvA.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bm_Bk8UP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/708/1%2AoflHCW6PPNRa2Eb0yAIjvA.webp" width="354" height="128"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt; Figure 3: Selection Rate Definition &lt;/p&gt;

&lt;p&gt;Let's use MetricFrame from fairlearn to calculate the selection rates split by Sex.&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="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fairlearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MetricFrame&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;precision_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;recall_score&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sklearn.ensemble&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GradientBoostingClassifier&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fairlearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;selection_rate&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fairlearn.reductions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ExponentiatedGradient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DemographicParity&lt;/span&gt;
&lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GradientBoostingClassifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'accuracy'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'precision'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;precision_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'recall'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;recall_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'selection_rate'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;selection_rate&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;metric_frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MetricFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;y_true&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;sensitive_features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;metric_frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_group&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'selection_rate'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Selection Rate split by Sex'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sM0EbE0U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AILbeO5Vn4AsXPfgEZeLCiA.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sM0EbE0U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AILbeO5Vn4AsXPfgEZeLCiA.webp" alt="Selection Rate Split by Sex" width="814" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; Figure 4: Selection Rate Split by Sex &lt;/p&gt;

&lt;p&gt;We see that the percentage of males having a salary above 50K is almost 3x the percentage of females. (!!)&lt;br&gt;
Once the model is trained we see that this ratio is now 5x (!!). The model is exacerbating the bias we see in the data.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.2. Correcting bias
&lt;/h3&gt;

&lt;p&gt;Let's now correct the bias we observe by applying Demographic Parity on our classifier (we use ExponentiatedGradient from fairlearn for this). More context on how it works behind the scene can be found on the official fairlearn documentation here.&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&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;# set seed for consistent results with ExponentiatedGradient
&lt;/span&gt;
&lt;span class="n"&gt;constraint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DemographicParity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GradientBoostingClassifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mitigator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExponentiatedGradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;constraint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mitigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sensitive_features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_pred_mitigated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mitigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;sr_mitigated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MetricFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;selection_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_true&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y_pred_mitigated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sensitive_features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sr_mitigated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sr_mitigated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;metric_frame_mitigated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MetricFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;y_true&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y_pred_mitigated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;sensitive_features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;metric_frame_mitigated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;subplots&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;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Show all metrics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t9T7em7W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2A9x24g1w-4HVrLr4nNQEPvw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t9T7em7W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2A9x24g1w-4HVrLr4nNQEPvw.webp" alt="Selection rate for original model vs mitigated one" width="820" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; Figure 5: Selection rate for original model vs mitigated one &lt;/p&gt;

&lt;p&gt;By mitigating the model we introduced demographic parity (and thus equal selection rates) for our new model. Our model is now fair!!!&lt;/p&gt;




&lt;p&gt;Woohoo! You now know the basics of fairness works and how you can start using it right away in your machine learning projects!&lt;/p&gt;

&lt;p&gt;I hope you liked this article! Let me know if you have any questions or suggestions. Also feel free to contact me on LinkedIn, GitHub or Twitter, or checkout some other articles I wrote on DS/ML best practices. Happy learning!&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fairlearn.org/"&gt;https://fairlearn.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>Introduction to Cryptography: Understanding Hashing and Public-key Encryption with Code Examples</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Wed, 15 Feb 2023 22:15:59 +0000</pubDate>
      <link>https://dev.to/armandsauzay/introduction-to-cryptography-understanding-hashing-and-public-key-encryption-with-code-examples-4fdl</link>
      <guid>https://dev.to/armandsauzay/introduction-to-cryptography-understanding-hashing-and-public-key-encryption-with-code-examples-4fdl</guid>
      <description>&lt;p&gt;What's cryptography? What does hashing and public-key encryption mean? And which tool can you use to start writing cryptography code?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vb67fpys02dun7g7045.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vb67fpys02dun7g7045.jpeg" alt="Photo of cryptography computer Markus Spiske on Unsplash" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; Photo by Markus Spiske on &lt;a href="https://unsplash.com/photos/FXFz-sW0uwo" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You probably heard the name cryptography a lot recently, especially during the cryptocurrency bull market of 2021, or with the recent FTX saga. But what does it really mean? Is it useful? And how can you start using some cryptography yourself?&lt;/p&gt;

&lt;p&gt;As always, we'll go through a little bit of theory and the concepts behind before diving into some code to give a concrete example. &lt;strong&gt;As Steve Jobs once said:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The doers are the major thinkers. The people that really create the things that change this industry are both the thinker-doer in one person. And if we really go back and we examine, you know, did Leonardo have a guy off to the side that was thinking 5 years out in the future what he would paint or the technology he would use to paint it. Of course not. Leonardo was the artist, but he also mixed all his own paint. He also was a fairly good chemist, knew about pigments, knew about human anatomy. And combining all of those skills together, the art and the science, the thinking and the doing, was what resulted in the exceptional results.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;In this article, we'll cover the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cryptography 

&lt;ul&gt;
&lt;li&gt;1.1. Real world use cases&lt;/li&gt;
&lt;li&gt;1.2. Web2 vs Web3&lt;/li&gt;
&lt;li&gt;1.3. Symmetric vs asymmetric cryptography&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hashing

&lt;ul&gt;
&lt;li&gt;2.1. Core concept behind hashing&lt;/li&gt;
&lt;li&gt;2.2. Slight difference in inputs can lead to completely different outputs&lt;/li&gt;
&lt;li&gt;2.3. Why is this useful?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Public key cryptography (and ssh)

&lt;ul&gt;
&lt;li&gt;3.1. Public key vs Private key and their respective roles&lt;/li&gt;
&lt;li&gt;3.2. Digital Signature&lt;/li&gt;
&lt;li&gt;3.3. Bonus: how does ssh work?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Using gpg to create a key pair and encrypting/decrypting documents

&lt;ul&gt;
&lt;li&gt;4.1. Having a secret message/document&lt;/li&gt;
&lt;li&gt;4.2. Generating a key pair&lt;/li&gt;
&lt;li&gt;4.3. Encrypting your message with the public key&lt;/li&gt;
&lt;li&gt;4.4. Decrypting your message with your private key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Cryptography
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1. Real world use cases
&lt;/h3&gt;

&lt;p&gt;Cryptography, in short, is a set of techniques to enable secure communication through encoding and decoding messages. More generally, cryptography is about constructing and analyzing protocols that prevent third parties or the public from reading private messages. It is mainly used for the following: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;securing personal information: most web applications use cryptography to encrypt messages and the data they store, and hide their services and APIs from the general public.&lt;/li&gt;
&lt;li&gt;as the base layer of crypto/blockchain. And you don't have to go further than the second page of Satoshi Nakamoto's original paper on bitcoin (read more &lt;a href="https://bitcoin.org/bitcoin.pdf" rel="noopener noreferrer"&gt;here&lt;/a&gt;) to understand that cryptography is central in the blockchain/crypto field.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.2. Web2 vs Web3
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;So, most of the "tech" we know relies on cryptography: if you're a &lt;strong&gt;Web2&lt;/strong&gt; aficionado, you trust that companies will correctly protect your data through encrypting the "username" and "password" required to access their databases (these are usually not user and password per say but can be access keys). And if you're a &lt;strong&gt;Web3&lt;/strong&gt; aficionado you trust yourself with keeping your "username" and "password" (or public and private keys) secret to yourself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And how you keep things &lt;strong&gt;secret&lt;/strong&gt; is through cryptography:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have an input&lt;/li&gt;
&lt;li&gt;Run a function on it to encode it. &lt;/li&gt;
&lt;li&gt;Potentially run another function to then decode the encoded message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;p&gt;roughly, cryptography = encryption + decryption &lt;/p&gt;

&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3. Symmetric and asymmetric cryptography
&lt;/h3&gt;

&lt;p&gt;Popular encryption algorithm include the &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FCaesar_cipher" rel="noopener noreferrer"&gt;Caesar cipher&lt;/a&gt; (shift all the letters by one or more characters, i.e. a becomes b, b becomes c, etc.), or &lt;a href="https://en.wikipedia.org/wiki/Pig_Latin" rel="noopener noreferrer"&gt;Pig Latin&lt;/a&gt; (adding a suffix to each syllab) which you might know. It is also useful to distinguish between symmetric and asymmetric cryptography:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symmetric cryptography&lt;/strong&gt;: the same key is used to encrypt and decrypt the message. This is the most common type of cryptography and is used in most applications. The most popular symmetric cryptography algorithm is AES (Advanced Encryption Standard) which is used in most applications. &lt;strong&gt;In symmetric cryptography: encryption = decryption&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asymmetric cryptography&lt;/strong&gt;: the key used to encrypt the message is different from the key used to decrypt the message. This is the most common type of cryptography used in the blockchain/crypto field. The most popular asymmetric cryptography algorithm is RSA (Rivest–Shamir–Adleman) which is used in most applications. &lt;strong&gt;In asymmetric cryptography: encryption ≠ decryption&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article we'll only cover &lt;strong&gt;asymmetric cryptography&lt;/strong&gt; and cover two main ideas that are the foundation of most applications: (1) hashing and (2) public-key cryptography.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Hashing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1. Core concept behind hashing
&lt;/h3&gt;

&lt;p&gt;Hashing is the simplest cryptographic process: you take an input (an image, text, any data basically) and you make it go through a hashing process to create an encrypted message. One of the most used algorithm is SHA-256 (which was developed by the NSA): it will create a "random" 64 character long string from any input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwa12qd5ej47o0ehf6xja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwa12qd5ej47o0ehf6xja.png" alt="illustration of hashing (image by author)" width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; illustration of hashing (image by author) &lt;/p&gt;

&lt;h3&gt;
  
  
  2.2. A slight difference in inputs can lead to completely different outputs
&lt;/h3&gt;

&lt;p&gt;Below, you can see how the two strings "hello world" and "Hello world" are hashed with the SHA-256 algorithm. Notice the very slight difference on the first letter being capitalized or not but the huge difference in the encrypted messages… You can try it out for yourself here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Hello world → b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
hello world → 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3. Why is this useful?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Hashing is a one way function. It is easy to go from message to encrypted message but almost impossible to do the opposite.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, good. But why is this useful?&lt;/p&gt;

&lt;p&gt;→ Let's say you have a website and you are storing all the passwords of all your users. You wouldn't want to store them plainly in a datafile (assuming you're a little concerned about those passwords getting leaked…), right? So you could probably hash them with a specific algorithm. When someone signs up on your website, you'll hash their password and store the hashed password. And if that same someone tries to log in with their password, you hash the their login password input and compare it to the original hash of their password when they signed up. If the 2 hashes match (the hash from the original password and the hash from the login input) , you let the user in. And if someone gains access to the database with all the hashed passwords of all the users, you'll be safe because they would not be able to log in with that information!&lt;br&gt;
But sometimes it would be nice to also be able to decode right? Let's say you're sending a hashed love letter to your lover (with SHA-256 once again)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;I love you → c33084feaa65adbbbebd0c9bf292a26ffc6dea97b170d88e501ab4865591aafd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your lover wouldn't really know what to do with &lt;code&gt;c33084feaa65adbbbebd0c9bf292a26ffc6dea97b170d88e501ab4865591aafd&lt;/code&gt; would they?&lt;/p&gt;

&lt;p&gt;This is where public-key cryptography can be useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Public-key cryptography
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1. Public key vs Private key and their respective roles
&lt;/h3&gt;

&lt;p&gt;In public-key cryptography, there is a set of keys consisting of two keys: a public key and a private key. Both of these keys are one-way functions meaning that they are not interchangeable: the public key is used to encrypt and the private key is used to decrypt. And the security of the process is guaranteed as long as the private key is kept secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwhwbf0zac95xtwlqu0wu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwhwbf0zac95xtwlqu0wu.png" alt="illustration of public-key encryption (image by author)" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; illustration of public-key encryption (image by author) &lt;/p&gt;

&lt;p&gt;This is a powerful concept: only those with the private key would be able to decrypt messages encoded with the public key. This opens up the door for many possible applications. I can create a key pair, send the public key to everyone and keep the private key to myself. People could encrypt the messages they want to send me with the public key and publish it somewhere (in a journal, on social media, whatever). And I will be the only one to be able to decrypt the encoded message.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2. Digital Signature
&lt;/h3&gt;

&lt;p&gt;Another very central concept in cryptography is &lt;strong&gt;digital signature&lt;/strong&gt;, which is basically proving that you own the private key associated with a public key without sharing the private key. For example, let's say that you have shared a public key (with which anyone can can encrypt a message with). Someone encrypts a message with your public key and sends the encrypted message to you. If you can decrypt the encrypted message they sent, you have proved that you own the private key associated with the public one. This is how digital signature work. You now know the base layer of Bitcoin for instance since showing that you own the private key associated with your public Bitcoin address is a process very similar to what we just described.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3. Bonus: ssh
&lt;/h3&gt;

&lt;p&gt;SSH (Secure Shell) keys are a way to authenticate a user's access to a remote server. They allow users to log in to a remote server without the need to enter a password.&lt;/p&gt;

&lt;p&gt;SSH keys consist of a public key and a private key. The public key is used to encrypt data that is sent from the client to the server, and the private key is used to decrypt the data.&lt;br&gt;
To use an SSH key for authentication, the user generates a key pair on their local machine and then adds the public key to the authorized_keys file on the remote server. When the user attempts to log in to the server, the server sends a challenge message to the client, which the client encrypts using the private key and sends back to the server. If the server can decrypt the message using the public key, the user is authenticated and granted access to the server.&lt;/p&gt;

&lt;p&gt;SSH keys are a secure and convenient way to authenticate access to a remote server, as they do not rely on the user remembering a password and they can be revoked or replaced easily if necessary.&lt;/p&gt;

&lt;p&gt;The concept is nice, right? &lt;em&gt;But how can you apply the theory and start using it in code?&lt;/em&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  4. Using gpg to create a key pair and encrypting/decrypting documents
&lt;/h2&gt;

&lt;p&gt;One of the nice tools for playing around with public and private keys is gnupg with the gpg CLI (you can read more &lt;a href="https://gnupg.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The goal is not to give an extensive overview of gpg but let's see a simple example to realize typical steps (key pair creation and encrypting/decrypting).&lt;/p&gt;

&lt;p&gt;As always you can check out the associated code on GitHub and follow along if you want. This basically consists in three steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating a key pair.&lt;/li&gt;
&lt;li&gt;encoding the document with the public key.&lt;/li&gt;
&lt;li&gt;decrypting the encoded document with the private key.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4.1. Having a secret message/document
&lt;/h3&gt;

&lt;p&gt;Let's say you have a private message in a document like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#secret_message.txt
The Navy UFO videos weren't supposed to be released.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2. Generating a key pair
&lt;/h3&gt;

&lt;p&gt;You could begin by generating a key pair and storing the public and private key as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"What is your key name? "&lt;/span&gt; KEY_NAME 
gpg &lt;span class="nt"&gt;--full-generate-key&lt;/span&gt; &lt;span class="c"&gt;#then follow the prompts&lt;/span&gt;
gpg &lt;span class="nt"&gt;--export&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nv"&gt;$KEY_NAME&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KEY_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.public.key
gpg &lt;span class="nt"&gt;--export-secret-key&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nv"&gt;$KEY_NAME&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KEY_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.private.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3. Encrypting your message with the public key
&lt;/h3&gt;

&lt;p&gt;Then, using gpg --encrypt you could encrypt your message using the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"What is your key name? "&lt;/span&gt; KEY_NAME
gpg &lt;span class="nt"&gt;--import&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KEY_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.public.key
gpg &lt;span class="nt"&gt;--encrypt&lt;/span&gt; secret_message.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4. Decrypting your message with your private key
&lt;/h3&gt;

&lt;p&gt;Finally, using gpg --decrypt you can use the private key to decrypt the message that you just encoded to verify that the encryption/decryption worked well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--decrypt&lt;/span&gt; secret_message.txt.gpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Tadaa! You've created a key pair, encrypted and then decrypted your message. You're now a crypto expert!&lt;/p&gt;




&lt;p&gt;I hope you liked this article! Feel free to contact me on LinkedIn, GitHub or Twitter if you have any questions or suggestions or just want to chat, or checkout other articles I wrote on medium and leave feedback. Happy learning!&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay" rel="noopener noreferrer"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Machine Learning interpretability and feature selection made easy with SHAP.</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Tue, 14 Feb 2023 18:22:15 +0000</pubDate>
      <link>https://dev.to/armandsauzay/machine-learning-interpretability-and-feature-selection-made-easy-with-shap-450c</link>
      <guid>https://dev.to/armandsauzay/machine-learning-interpretability-and-feature-selection-made-easy-with-shap-450c</guid>
      <description>&lt;p&gt;Machine learning interpretability with hands on code with SHAP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdtpsly76v7a1s52j11x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdtpsly76v7a1s52j11x.jpeg" alt="Photo by Edu Grande on Unsplash" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo by Edu Grande on Unsplash&lt;/p&gt;

&lt;p&gt;Machine Learning interpretability is becoming increasingly important, especially as ML algorithms are getting more complex.&lt;/p&gt;

&lt;p&gt;How good is your Machine Learning algorithm if it cant be explained? Less performant but explainable models (like linear regression) are sometimes preferred over more performant but black box models (like XGBoost or Neural Networks). This is why research around machine learning explainability (aka eXplainable AI or XAI) has recently been a growing field with amazing projects like SHAP emerging.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Would you feel confident using a machine learning model if you can't explain what it does?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where SHAP can be of great help: it can explain &lt;strong&gt;any ML model&lt;/strong&gt; by giving the influence of each of the features on the target. But this is not all that SHAP can do. &lt;/p&gt;

&lt;p&gt;Build a simple model (sklearn/xgboost/keras) and use SHAP: you now have a feature selection process by looking at features which have the biggest impact on the prediction.&lt;br&gt;
But how does SHAP work under the hood? And how can you start using it?&lt;/p&gt;

&lt;p&gt;In this article we'll first get our hands on some python code to see how you can start using SHAP and how it can help you both for explainability and feature selection. &lt;/p&gt;

&lt;p&gt;Then, for those of you who want to get into the details of SHAP, we'll go through the theory behind popular XAI tools like SHAP and LIME.&lt;/p&gt;



&lt;p&gt;All the code for this tutorial can be found on Kaggle &lt;a href="https://www.kaggle.com/code/armandsauzay/shap-interpret-any-ml-model-feature-selection?scriptVersionId=99746743" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Feel free to run the notebook yourself or create a copy!&lt;/p&gt;


&lt;h2&gt;
  
  
  1. How can you start using SHAP?
&lt;/h2&gt;

&lt;p&gt;Here, we'll go through a simple example with Shap values using the competition Kaggle competition "House Prices - Advanced Regression Techniques" to illustrate SHAP. If you are interested or you have never been on Kaggle before, feel free to read more about the data and the competition itself here.&lt;/p&gt;

&lt;p&gt;The process to use shap is quite straightforward: we need to build a model and then use the shap library to explain it.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0iwk7o96otz3jwltpnz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0iwk7o96otz3jwltpnz.png" alt="Explanation of how to use SHAP in your Machine Learning Project" width="760" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;understand the output of your modelHere, our machine learning model tries to predict the house prices from the data that is given (number of square feet, quality, number of floors etc).&lt;/p&gt;

&lt;p&gt;The usual workflow in terms of code looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create an estimator. For instance GradientBoostingRegressor from sklearn.ensemble:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;estimator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GradientBoostingRegressor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Train your estimator:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;estimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;use shap library to calculate the SHAP values. For instance, using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;explainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Explainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;estimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;shap_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;explainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;See what is the impact of each feature using shap.summary_plot:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;shap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary_plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shap_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_display&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;shap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary_plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shap_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_display&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxv76l15gji1basr3tcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxv76l15gji1basr3tcw.png" alt="Summary plot of feature importance" width="800" height="774"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For instance, you can see here that OverallQual is the feature that has the most impact on the model output. High values (colored in red on the graph above) of OverallQual can increase a property's price by ~60,000 and low values can decrease a price by ~20,000. Interesting to know if you're in real estate, isn't it?&lt;/p&gt;

&lt;p&gt;But this is not all of what SHAP can do! SHAP can also explain a single prediction.&lt;/p&gt;

&lt;p&gt;For example, using shap.plots.waterfall for a single element in the dataset, you can have the following:&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="n"&gt;shap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waterfall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shap_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sample_index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;max_display&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjgd128zzqvivgmjltj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjgd128zzqvivgmjltj8.png" alt="Waterfall plot of feature importance for a single example" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this specific example, the predicted price was 166k (vs 174k on average). And we can understand why the algorithm predicted such: for instance OverallQual which is high (7) drives the value up but YearBuilt (1925) drives the value down.&lt;/p&gt;

&lt;p&gt;You can now understand the dynamics behind your model, both overall and on specific datapoints. With SHAP, you can more easily see if something is wrong (or does not make sense for your sharpened data science mind) so you can correct it! This is what observability is about.&lt;/p&gt;

&lt;p&gt;And since SHAP allows you to understand the feature importance of your model, you can also use this for feature selection. For instance&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="n"&gt;shap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary_plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shap_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_display&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plot_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bar&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m2095rw8hg0irzcfabc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m2095rw8hg0irzcfabc.png" alt="Barplot of feature importance" width="800" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you can see which features do not have a lot of impact on the output of the model. The features usually are noise for your machine learning model and do not bring a lot of predictive value. So removing them from your training set will generally improve the performance, and allow you to tune correctly the hyper parameters without overfitting on noisy data.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuoocsd2s8chw8m6tb8zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuoocsd2s8chw8m6tb8zh.png" alt="Worfklow for feature selection in your machine learning project" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; How SHAP can be used for feature selection &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Quick overview: How does SHAP work under the hood?
&lt;/h2&gt;

&lt;p&gt;If you have a bit of time, feel free to read the original paper that describes the different approaches for model explainability and goes through the advantages of SHAP.&lt;/p&gt;

&lt;p&gt;But let's try to explain in short what SHAP is doing and the concepts behind without getting too deep into the mathematical equations.&lt;/p&gt;

&lt;p&gt;Explainable Machine Learning (aka eXplainable AI or XAI) aims at understanding why the output of a machine learning model is such. To do so, you could theoretically take the definition of your model, for example a tree based model like Random Forest, and then see why your output is such. But this is not so straightforward, and of course, it gets even more complex for Deep Learning models…&lt;/p&gt;

&lt;p&gt;Instead of going through the winding path of understanding what happens inside your model (forward and backward propagation for deep learning models, which splits are the most used in your RF algo etc). But once you have your trained model, could you not instead use it to see how it reacts when you change a feature?&lt;/p&gt;

&lt;p&gt;This is the core concept behind popular XAI algorithm (SHAP, LIME etc): use your existing model, approximate it using an explainable model and you now have an explainable model. The complexity is now on how to approximate a ML model around a given prediction, and then around most predictions.&lt;/p&gt;

&lt;p&gt;If you are interested in this and want to learn more, let me know and I'll write a follow up article on the mathematical concepts behind SHAP, how it is related to the classic Shapley values, how you can compute SHAP values and how we are able to approximate it for specific use cases, which makes the computation easier.&lt;/p&gt;




&lt;p&gt;Woohoo! You now know the basics on how SHAP works and how you can start using it right away in your machine learning projects!&lt;/p&gt;




&lt;p&gt;I hope you liked this article! Let me know if you have any questions or suggestions. Also feel free to contact me on LinkedIn, GitHub or Twitter, or checkout some other tutorials I wrote on DS/ML best practices. Happy learning!&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://shap.readthedocs.io/en/latest/index.html" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://proceedings.neurips.cc/paper/2017/file/8a20a8621978632d76c43dfd28b67767-Paper.pdf" rel="noopener noreferrer"&gt;original paper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay" rel="noopener noreferrer"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>5 tools I wish I knew when I started writing Machine Learning code</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Tue, 31 Jan 2023 17:24:25 +0000</pubDate>
      <link>https://dev.to/armandsauzay/5-tools-i-wish-i-knew-when-i-started-writing-machine-learning-code-575f</link>
      <guid>https://dev.to/armandsauzay/5-tools-i-wish-i-knew-when-i-started-writing-machine-learning-code-575f</guid>
      <description>&lt;p&gt;A few tools that will get you on the right track for your Machine Learning projects using python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CIuUR2ea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/v2/resize:fit:1400/format:webp/1%2AdbOgJi1lNK72h_NjKh7OdQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CIuUR2ea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/v2/resize:fit:1400/format:webp/1%2AdbOgJi1lNK72h_NjKh7OdQ.jpeg" alt="Photo by ray rui on Unsplash" width="880" height="586"&gt;&lt;/a&gt;&lt;br&gt;
Photo by ray rui on Unsplash&lt;/p&gt;

&lt;p&gt;A few years back, I first learnt how to write machine learning code as I took my first ML class while pursuing my graduate studies in Applied Mathematics. &lt;/p&gt;

&lt;p&gt;I learnt about the Math behind classic ML algorithms, got my hands on popular python libraries for like scikit-learn, PyTorch and Tensorflow, and participated in my first Kaggle competition on the Titanic dataset.&lt;/p&gt;

&lt;p&gt;Fast forward a few years, after a pursuing my graduate studies in Machine Learning at UC Berkeley, I now work on developing machine learning models that end up being used in production and at scale.&lt;/p&gt;

&lt;p&gt;And, of course, the code I now write is very different from the Python Notebooks I used to write when I originally started. &lt;/p&gt;

&lt;p&gt;Even though I still use notebooks for the exploration part, my final code is structured using only python files, often containerized, and integrated using CI/CD and triggered by workflow management tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment management tool like conda or poetry
&lt;/h2&gt;

&lt;p&gt;The first thing to consider when you write code is to create an environment for you code to live in.&lt;/p&gt;

&lt;p&gt;For Data Science / Machine learning, the best tool around for environments is probably Conda at first. Then for production it's probably more poetry. But let's keep this discussion for another article and talk a bit about conda.&lt;/p&gt;

&lt;p&gt;Conda has the benefits of being a version manager and a package manager, it allows you to easily define environments, make sure the package versions are compatible with each other and has some cool perks like being able to define environment variables. If you want to learn more about this tool or if you want a quick refresher, you can go through the article I wrote on that subject:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/using-conda-environments-for-python-all-you-need-to-know-2eb36e224d1c"&gt;Using Conda environments for Python, all you need to know&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration tools like hydra
&lt;/h2&gt;

&lt;p&gt;Another thing is that Data Science / Machine Learning code often comes with a lot of parameters (hyper parameters, where to log artifacts, preprocessing steps etc..).&lt;/p&gt;

&lt;p&gt;For configuration, one of the nicest tool around is Hydra. From the hydra documentation itself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The key feature is the ability to dynamically create a hierarchical configuration by composition and override it through config files and the command line. The name Hydra comes from its ability to run multiple similar jobs - much like a Hydra with multiple heads.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hydra makes it easy to set up your config parameters, create config groups, and even instantiate objects from your config. If you want to learn more about this tool, and want to have a code tutorial to get up to speed on it, feel free to check out the article I wrote about it: &lt;a href="https://medium.com/@armand-sauzay/hydra-the-most-efficient-config-handling-library-for-your-python-ml-code-9178d491523c"&gt;Hydra, the most efficient config handling library for your Python/ML code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the terminal (best way to navigate through files)
&lt;/h2&gt;

&lt;p&gt;Something that can be a bit of a pain when starting to write code but that will make your life 10x easier once you get used to it is to use the terminal / command line interface to navigate through files and perform actions.&lt;/p&gt;

&lt;p&gt;If you want a quick overview of the basic actions you can perform with the terminal, feel free to check out the article I wrote: &lt;a href="https://medium.com/@armand-sauzay/a-simple-guide-to-using-the-command-line-aka-terminal-e030dbf18afe"&gt;Command Line 101: a Basic Guide to Using the Terminal&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MLFlow (ML artifact handling tool)
&lt;/h2&gt;

&lt;p&gt;A lot of tools exist to help with the machine learning lifecycle: for ML experiments, for Model Registry, for packaging your ML code or putting your models in production. MLFlow has all of these capabilities.&lt;/p&gt;

&lt;p&gt;But you might agree with me, production machine learning is kind of a niche use case and unless you work for a big marketplace company or FAANG you might not need to deploy your models in production…&lt;/p&gt;

&lt;p&gt;However, in general, you might want to have a place to store all your ML experiments results and know which validation score was obtained with which hyper parameters etc. This is exactly what MLFlow Tracking has to offer.&lt;br&gt;
In short, in seconds, you can simply log your artifacts and, by typing mlflow ui in your terminal, you will instantly start a mlflow server on &lt;code&gt;http://127.0.0.1:5000/&lt;/code&gt; that will read from your &lt;code&gt;mlruns&lt;/code&gt; folder. You can then easily navigate through your experiments and see all the metrics, parameters and artifacts you logged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Github Actions (or another CI/CD tool)
&lt;/h2&gt;

&lt;p&gt;Once you work in a context where your ML models need to be retrained or integrated to some architecture or even write daily ETLs you will quickly realize that a lot of actions can be automated with a CI/CD tool like Jenkins or GitHub actions (for ETLs Airlfow is considered a better pick but that's another subject). From the GitHub documentation: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples of CI/CD include build/push-ing docker images, pre-commit checks, automated testing and much more. If you want more details, let me know and I'll write a quick tutorial on how GitHub Actions can be used for ML code.&lt;/p&gt;




&lt;p&gt;Of course there are many more tools that are absolutely amazing and that I use on a daily basis such as cloud platforms like AWS or GCP, Docker or Visual Studio Code to mention but a few. If you'd like more details about how industry standards for these tools, feel free to reach out!&lt;/p&gt;




&lt;p&gt;Hope you liked this article! Don't hesitate if you have any question, or suggestions, in comments, or feel free to connect on LinkedIn, GitHub or Twitter.&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>tooling</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>Hydra, the most efficient config handling library for your Python/ML code</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Tue, 10 Jan 2023 18:08:56 +0000</pubDate>
      <link>https://dev.to/armandsauzay/hydra-the-most-efficient-config-handling-library-for-your-pythonml-code-fch</link>
      <guid>https://dev.to/armandsauzay/hydra-the-most-efficient-config-handling-library-for-your-pythonml-code-fch</guid>
      <description>&lt;p&gt;Improve your python code by using hydra for configuration.&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%2Fmiro.medium.com%2Fmax%2F1400%2F1%2APoU6CMaYh6uNWgYn0AX7bg.webp" 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%2Fmiro.medium.com%2Fmax%2F1400%2F1%2APoU6CMaYh6uNWgYn0AX7bg.webp" alt="Photo by Ferenc Almasi on Unsplash"&gt;&lt;/a&gt;&lt;br&gt;
Photo by Ferenc Almasi on Unsplash&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll go through some available options that you might encounter for config handling, then explain why hydra is my favorite pick, and finally go through some code examples to highlight the key functionalities of Hydra.&lt;/p&gt;
&lt;h2&gt;
  
  
  Context and available options
&lt;/h2&gt;

&lt;p&gt;As one works on a Python project, especially for machine learning, the number of parameters rapidly increases. Soon comes the question: what is the ideal way to store my parameters?&lt;/p&gt;

&lt;p&gt;Let’s go through a few options you might have encountered.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;hardcoding&lt;/strong&gt;: Should I hardcode them in some random places in my code? Probably not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;yaml/json&lt;/strong&gt;: Should I create a simple YAML file? Or json file? And import with json.load? Doesn’t seem very pythonic, does it?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;config.py&lt;/strong&gt;: Should I create a config.py file where I put all my parameters? That’s nice, but lets say I want to run 10 experiments, would I want to go back to my config.py file and change the values 1 by 1 before re-running. Once again, probably not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;dotenv&lt;/strong&gt;: Should I use something like dotenv? Same as config.py, it does not seem ideal if we play with a lot of parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;other tools&lt;/strong&gt;: I also tried other tools like dynaconf, or docopt or configparser (the python native configuration parser). But nothing comes close to hydra, which is an amazing tool for configuring python code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hydra notably allows for a clear yaml-format configuration, the ability to instantiate objects, running multiple tasks and many other features that you’ll probably love or found missing in other libraries. As described in the hydra official documentation:&lt;/p&gt;

&lt;p&gt;The key feature is the ability to dynamically create a hierarchical configuration by composition and override it through config files and the command line. The name Hydra comes from its ability to run multiple similar jobs — much like a Hydra with multiple heads.&lt;/p&gt;



&lt;p&gt;Without further due, let’s get right into the code and understand why hydra is the clear winner for configuration file a handling.&lt;/p&gt;



&lt;p&gt;All of the code for this tutorial can be found &lt;a href="https://github.com/armand-sauzay/blog-posts/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You can clone the repo to easily navigate through the different sections in this tutorial.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;having Conda (miniconda) installed and a basic understanding of Conda environment. If you’re not familiar with this, check out the article I wrote on that subject &lt;a href="https://medium.com/dev-genius/using-conda-environments-for-python-all-you-need-to-know-2eb36e224d1c" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;having a basic understanding of the command line / terminal. If you’re not familiar with this, check out the article I wrote on that subject &lt;a href="https://medium.com/@armand-sauzay/a-simple-guide-to-using-the-command-line-aka-terminal-e030dbf18afe" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Basic example (folder 1_basic_example on the GitHub repo)
&lt;/h3&gt;

&lt;p&gt;In this example, we’re going to go though the basic of hydra. There are two files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config.yaml&lt;/span&gt;
&lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
  &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# my_app.py 
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hydra&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;omegaconf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DictConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OmegaConf&lt;/span&gt;
&lt;span class="nd"&gt;@hydra.main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config&lt;/span&gt;&lt;span class="sh"&gt;"&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;my_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DictConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&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="n"&gt;OmegaConf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_yaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reading data with username &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;my_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the terminal, navigate to &lt;code&gt;1_basic&lt;/code&gt; and run &lt;code&gt;python my_app.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You see that in the file &lt;code&gt;my_app.py&lt;/code&gt;, the function my_app has been decorated with &lt;code&gt;@hydra.main()&lt;/code&gt; with 2 parameters &lt;code&gt;config_path&lt;/code&gt; and &lt;code&gt;config_name&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;config_path=”.”&lt;/code&gt; → looking for a config file in the same folder as the script&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;config_name=”config’&lt;/code&gt; → looking for a config file named config(.yaml is implicit) in the config_path, which means the current folder.
This decoration will load the config file in cfg. And you can then access it in your code. If we want to access the value of user from the db section of the config file, we just have to write cfg.db.user. As easy as this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s try a nice added functionality of hydra, the multirun. Lets say we want to run this job with 2 different parameters (for example db.table). For this you can simply run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python my_app.py -m db.table=bar,foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ this will launch 2 jobs (-m stands for multirun): one with db.table=bar and one with db.table=foo&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Config groups (folder 2_config_groups on the GitHub repo)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#my_app.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hydra&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;omegaconf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DictConfig&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&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="nd"&gt;@hydra.main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;configs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config&lt;/span&gt;&lt;span class="sh"&gt;"&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;my_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DictConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Info level message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Debug level message&lt;/span&gt;&lt;span class="sh"&gt;"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;driver=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, timeout=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;my_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config.yaml&lt;/span&gt;
&lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;dataloader&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;_self_&lt;/span&gt;
&lt;span class="na"&gt;dataloader&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea is to simplify the main config file and be able to create groups in the yaml to make it even more configurable. Here, the decorator indicates that we are in a folder called configs and that the main config file is named config (.yaml is implicit).&lt;/p&gt;

&lt;p&gt;Then, in &lt;code&gt;configs/config.yaml&lt;/code&gt;, the defaults: argument indicates that there exists a subfolder called dataloader, in which there are multiple configurations for dataloader.&lt;/p&gt;

&lt;p&gt;Finally, in &lt;code&gt;configs/config.yaml&lt;/code&gt;, the argument &lt;code&gt;_self_&lt;/code&gt; is required and indicates the precedence. In this case, &lt;code&gt;_self_&lt;/code&gt; is the last line, so it indicates that the defaults will be overwritten by values hardcoded outside of the default yaml. If &lt;code&gt;_self_&lt;/code&gt; is at the beginning, the value from the defaults is used.&lt;/p&gt;

&lt;p&gt;Now if you want to try the multi-run approach of hydra you can run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python my_app.py -m dataloader=local,redshift
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ this will launch 2 jobs (&lt;code&gt;-m&lt;/code&gt; stands for multirun): one with &lt;code&gt;dataloader=local&lt;/code&gt; and one with &lt;code&gt;dataloader=redshift&lt;/code&gt;. Of course, this is very useful for hyper parameter tuning.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Instantiation (folder 3_instantiation on the GitHub repo)
&lt;/h3&gt;

&lt;p&gt;What happens when you want to pass python objects as part of your config. For instance, let’s say you want to test different ML algorithms in a simple Sklearn project and you want to try a XGBoost model and a Logistic Regression. Hydra allows you to do that!!&lt;/p&gt;

&lt;p&gt;Let’s go through this example which has 2 files&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="c1"&gt;#my_app.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hydra&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sklearn.ensemble&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hydra.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;instantiate&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;omegaconf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DictConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OmegaConf&lt;/span&gt;
&lt;span class="nd"&gt;@hydra.main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config&lt;/span&gt;&lt;span class="sh"&gt;"&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;my_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&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="n"&gt;OmegaConf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_yaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feature_extractor&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="n"&gt;model&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;my_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#config.yaml&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;feature_extractor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;_target_&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sklearn.ensemble.GradientBoostingClassifier&lt;/span&gt;
    &lt;span class="na"&gt;random_state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="na"&gt;n_estimators&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;
    &lt;span class="na"&gt;learning_rate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.01&lt;/span&gt;
    &lt;span class="na"&gt;max_depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;bar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${bar.a}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the yaml, you need to pass a &lt;code&gt;_target_&lt;/code&gt; (note that this name is a convention so dont modify it or you wont be able to instantiate your object) as the first line of the object we want to instantiate. Following lines are parameters for the object we wish to instantiate. For instance, here, &lt;code&gt;instantiate(cfg.model.feature_extractor)&lt;/code&gt; will lead to &lt;code&gt;sklearn.ensemble.GradientBoostingClassifier(random_state=0, n_estimators=500, learning_rate=0.0, max_depth=2)&lt;/code&gt;. Pretty cool right?&lt;/p&gt;




&lt;p&gt;Woohoo! You now know how to use hydra for config, creating config groups, instantiating objects. Feel free to checkout on the repo the 4th section on the popular plugin Optuna for bayesian optimization.&lt;/p&gt;

&lt;p&gt;Hope you liked this article! Don’t hesitate if you have any question, or suggestions, in comments, or feel free to contact me on LinkedIn, GitHub or Twitter, or checkout some other tutorials I wrote on DS/ML best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay" rel="noopener noreferrer"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Use pre-commit checks to format your files and commit messages</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Fri, 06 Jan 2023 18:05:30 +0000</pubDate>
      <link>https://dev.to/armandsauzay/pre-commit-checks-to-format-your-files-and-commit-messages-27p4</link>
      <guid>https://dev.to/armandsauzay/pre-commit-checks-to-format-your-files-and-commit-messages-27p4</guid>
      <description>&lt;p&gt;Stop committing wrongly formatted code and start using pre-commit checks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwme8nn9tq3s18iel087v.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwme8nn9tq3s18iel087v.webp" alt="Photo by Roman Synkevych 🇺🇦 on Unsplash" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt; Photo by Roman Synkevych 🇺🇦 on Unsplash &lt;/center&gt; 



&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;How many times have you seen a commit message like 'test' or 'modif' or 'reran notebook'?&lt;/p&gt;

&lt;p&gt;Commit messages can be very useful and their format can help get the relevant information in a simple look. This is what conventional commits is trying to achieve: standardize the commit format to be able to navigate through commits easily and understand what code update they were associated to. But how could we make sure all commits followed this format?&lt;/p&gt;

&lt;p&gt;File formatting can also be quite challenging when more than one person works on a GitHub repository. How could we make sure that all the files committed to a repository have the same format? Or that you do have the extra empty line at the end of your file that some system require to successfully run?&lt;/p&gt;

&lt;p&gt;This is where standardization makes our life easier, especially when enforced before the commits: black formatting for python, getting rid of trailing whitespaces, etc.&lt;/p&gt;

&lt;p&gt;Long story short, all the formatting issues that you might had to deal with or that created useless commits could be avoided by using pre-commit checks.&lt;/p&gt;

&lt;p&gt;Without further due, let's see how we can implement these concepts to an actual GitHub repository (if you need more context on conventional commits feel free to skip to the appendix and come back here after).&lt;/p&gt;




&lt;center&gt;

All of the code for this tutorial can be found [here](https://github.com/armand-sauzay/blog-posts/pre-commit-checks-to-format-your-files-and-commit-messages)
&lt;/center&gt;




&lt;h2&gt;
  
  
  Get started with pre-commit checks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Install pre-commit
&lt;/h3&gt;

&lt;p&gt;To install pre-commit, simply run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install pre-commit on your machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add pre-commit checks to your repo
&lt;/h3&gt;

&lt;p&gt;To be able to add pre-commit checks that make sure your files and commit messages are correctly formatted, you simply need to add &lt;strong&gt;2 files&lt;/strong&gt; at the root of your repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;.pre-commit-config.yaml&lt;/strong&gt;: defines the checks you want to run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.commitlintrc.yaml&lt;/strong&gt;: defines the npm package you use for pre commits.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .commitlintrc.yaml&lt;/span&gt;
&lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@open-turo/commitlint-config-conventional"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .pre-commit-config.yaml&lt;/span&gt;
&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/pre-commit/pre-commit-hooks&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v2.3.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;   &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;check-yaml&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;   &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;end-of-file-fixer&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;   &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trailing-whitespace&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/alessandrojcm/commitlint-pre-commit-hook&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v8.0.0&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;commitlint&lt;/span&gt;
        &lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;commit-msg&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;additional_dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@open-turo/commitlint-config-conventional"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you added those files, you can try adding a commit, the pre commit checks defined will make sure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;yaml files are correctly formatted&lt;/li&gt;
&lt;li&gt;files have an extra empty line at the end (this is considered best practice as some systems fail when this condition is not met)&lt;/li&gt;
&lt;li&gt;get rid of trailing whitespaces&lt;/li&gt;
&lt;li&gt;make sure that the commits follow the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;conventional commits&lt;/a&gt; format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To see if this worked, try to commit those files to your repo with some commit message like&lt;br&gt;
git commit -m 'feat: enabled pre-commit checks'&lt;/p&gt;



&lt;p&gt;Woohoo! You now know how to add pre commit checks to your own repository to make sure your file format are consistent and your commit messages too!&lt;/p&gt;


&lt;h2&gt;
  
  
  Apendix
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Appendix 1&lt;/strong&gt;: A word on Conventional Commits&lt;br&gt;
With conventional commits, the commit message should be structured as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;type&amp;gt;[optional scope]: &amp;lt;description&amp;gt;
[optional body]
[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example (from commit conventional docs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Appendix 2&lt;/strong&gt;: adding a python code formatter to pre-commit checks&lt;br&gt;
Additional content: if you want to add a python code formatter, like black, you can append to the end of .pre-commit-config.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/psf/black&lt;/span&gt;
    &lt;span class="s"&gt;rev&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;21.12b0&lt;/span&gt;
    &lt;span class="s"&gt;hooks&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;black&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay" rel="noopener noreferrer"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>Command Line 101: a Basic Guide to Using the Terminal</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Mon, 19 Dec 2022 12:52:23 +0000</pubDate>
      <link>https://dev.to/armandsauzay/command-line-101-a-basic-guide-to-using-the-terminal-4alo</link>
      <guid>https://dev.to/armandsauzay/command-line-101-a-basic-guide-to-using-the-terminal-4alo</guid>
      <description>&lt;h1&gt;
  
  
  Command Line 101
&lt;/h1&gt;

&lt;p&gt;Get started using your terminal and get one step closer to being an experienced developer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxriuidm5qrd4bf1kznh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxriuidm5qrd4bf1kznh.jpeg" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
Photo by Max Duzij from Unsplash&lt;/p&gt;

&lt;p&gt;All of the code for this tutorial can be found &lt;a href="https://github.com/armand-sauzay/blog-posts/tree/main/using-conda-environments-for-python-all-you-need-to-know/code" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;Developers use the command line to navigate through file and perform operations. &lt;/p&gt;

&lt;p&gt;Once you get used to it, it is definitely the most efficient and reproducible way to access files and perform operations. Also, when you start virtual machines on the cloud, it becomes the only way of easily communicating with your instance. &lt;/p&gt;

&lt;p&gt;So, without further due, let's learn about the terminal and basic commands to get started!&lt;/p&gt;

&lt;p&gt;In this article, we'll cover what is the command line, which commands we can use and we'll go through a simple tutorial to put those commands in practice.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;First, what is the command line?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is a plain and simple text interface for your computer. It takes commands which are then passed to the OS to run.&lt;br&gt;
And which commands can we use?&lt;br&gt;
The usual commands are given in the table below.&lt;/p&gt;

&lt;p&gt;Let's now go through a small example on how to use those commands. We'll first explain commands 1 by 1 and then put them all together in a shell script that you can run.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step-by-step commands
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Let's see where our terminal currently is:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Navigate to the folder where you usually put your code (I usually have mine in a folder called &lt;code&gt;code&lt;/code&gt; in your my folder)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;path/to/your/folder/of/code
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;In my case for instance, I have got a &lt;code&gt;code&lt;/code&gt; folder under &lt;code&gt;/Users/myusername&lt;/code&gt; so I can do the following&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd
cd &lt;/span&gt;code
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;br&gt;
    - &lt;code&gt;cd&lt;/code&gt;: brings me back to my root folder&lt;br&gt;
    - &lt;code&gt;cd code&lt;/code&gt;: changes my working directory to code&lt;br&gt;
    - An equivalent of this would be cd &lt;code&gt;~/code&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to/create a folder named command_line_tutorial and enter it&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Create a folder named command_line_tutorial and go to it"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial folder exists, entering it"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial folder does not exist, creating it"&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;echo&lt;/code&gt;: prints the string in the terminal&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;if [[ -d "command_line_tutorial" ]]; then&lt;/code&gt;: if the folder command_line_tutorial exists, then enter it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;else&lt;/code&gt;: otherwise create it and enter it&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Create a file called myfile.txt&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;myfile.txt
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;touch&lt;/code&gt;: creates a file&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Write 'Hello World!' in the above created file&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hello World!'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; myfile.txt
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;: appends the string to the file&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Add a line to the above created file&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'This is added to the file because of &amp;gt;&amp;gt;, otherwise &amp;gt; overwrites'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; myfile.txt
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;: appends the string to the file&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Create 100 files named myfile1.txt, myfile2.txt, myfile3.txt, etc. and write a line in each of them&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..100&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is file number &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; myfile&lt;span class="nv"&gt;$i&lt;/span&gt;.txt&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;for i in {1..100}; do&lt;/code&gt;: for each number between 1 and 100, do the following&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;echo "This is file number $i" &amp;gt; myfile$i.txt;&lt;/code&gt;: create a file named myfile1.txt, myfile2.txt, myfile3.txt, etc. and write a line in each of them&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Count the number of files in the folder&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ls&lt;/code&gt;: list all files in the current folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt;: pipe the output of the previous command to the next command&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wc -l&lt;/code&gt;: count the number of lines in the output of the previous command&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;grep all files that are in 90-100 range&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"myfile[9][0-9].txt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ls&lt;/code&gt;: list all files in the current folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;|&lt;/code&gt;: pipe the output of the previous command to the next command&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep "myfile[9][0-9].txt"&lt;/code&gt;: grep all files that are in 90-100 range&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;copy myfile.txt into a file named myfilecopy.txt&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;myfile.txt myfilecopy.txt
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cp&lt;/code&gt;: copy the file myfile.txt into myfilecopy.txt&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;remove all files that start with myfile&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm &lt;/span&gt;myfile&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rm&lt;/code&gt;: remove the file myfile.txt&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;go to folder parent&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cd ..&lt;/code&gt;: go to the parent folder&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;remove folder created for this tutorial&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rmdir &lt;/span&gt;command_line_tutorial
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rmdir&lt;/code&gt;: remove the folder command_line_tutorial&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Let's put all these commands in a shell script
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;you can delete command_line_tutorial and re run the following in order:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#print working directory&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Print working directory"&lt;/span&gt;
&lt;span class="nb"&gt;pwd&lt;/span&gt;

&lt;span class="c"&gt;#go to root folder&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Go to root folder"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;

&lt;span class="c"&gt;# code to code folder or create it if it does not exist&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Potentially run mkdir code if it does not exist"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"code folder exists, entering it"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;#list files in folder&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"List files in folder"&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt;

&lt;span class="c"&gt;#create a folder named code and go to it&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Create a folder named code and go to it"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"code folder exists, entering it"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"code"&lt;/span&gt;

&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;#create a folder named command_line_tutorial and go to it&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Create a folder named command_line_tutorial and go to it"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial folder exists, entering it"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial folder does not exist, creating it"&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"command_line_tutorial"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;#create a file called myfile.txt&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Create a file called myfile.txt"&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="s2"&gt;"myfile.txt"&lt;/span&gt;

&lt;span class="c"&gt;# create 100 files named myfile1.txt, myfile2.txt, myfile3.txt, etc. and write a line in each of them&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Create 100 files named myfile1.txt, myfile2.txt, myfile3.txt, etc. and write a line in each of them"&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..100&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This is file number &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; myfile&lt;span class="nv"&gt;$i&lt;/span&gt;.txt&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;#write 'Hello World!' in myfile.txt&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Write 'Hello World!' in myfile.txt"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hello World!'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; myfile.txt


&lt;span class="c"&gt;#Add a line to the above created file&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Add a line to the above created file"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'This is added to the file because of &amp;gt;&amp;gt;, otherwise &amp;gt; overwrites'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; myfile.txt

&lt;span class="c"&gt;#count the number of files in the folder&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Count the number of files in the folder"&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

&lt;span class="c"&gt;# grep all files that are in 90-100 range&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Grep all files that are in 90-100 range"&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"myfile[9][0-9].txt"&lt;/span&gt;

&lt;span class="c"&gt;#copy myfile.txt into a file named myfilecopy.txt&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copy myfile.txt into a file named myfilecopy.txt"&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;myfile.txt myfilecopy.txt

&lt;span class="c"&gt;#remove all files that start with myfile&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Remove all files that start with myfile"&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;myfile&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;#go to folder parent &lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Go to folder parent"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="c"&gt;#remove folder created for this tutorial&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Remove folder created for this tutorial"&lt;/span&gt;
&lt;span class="nb"&gt;rmdir &lt;/span&gt;command_line_tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this was helpful. You now are a bash expert and can start using your terminal for automating your tasks going forward! &lt;/p&gt;

&lt;h2&gt;
  
  
  About me
&lt;/h2&gt;

&lt;p&gt;Hey! 👋 I'm Armand Sauzay (&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;armandsauzay&lt;/a&gt;). You can find, follow or contact me on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/armand-sauzay" rel="noopener noreferrer"&gt;Github&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/armandsauzay" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@armand-sauzay" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/armandsauzay"&gt;Dev.to&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>watercooler</category>
      <category>offers</category>
    </item>
    <item>
      <title>Using Conda environments for Python, all you need to know</title>
      <dc:creator>Armand Sauzay</dc:creator>
      <pubDate>Wed, 07 Dec 2022 03:34:29 +0000</pubDate>
      <link>https://dev.to/armandsauzay/using-conda-environments-for-python-all-you-need-to-know-2n5p</link>
      <guid>https://dev.to/armandsauzay/using-conda-environments-for-python-all-you-need-to-know-2n5p</guid>
      <description>&lt;p&gt;&lt;strong&gt;Conda environments and environment variables made simple for your python projects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FMVWpsAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ebjp5mlvub55g6pr3st7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FMVWpsAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ebjp5mlvub55g6pr3st7.png" alt="Photo by Kristijan Arsov on Unsplash" width="880" height="561"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;All of the code for this tutorial can be found &lt;a href="https://github.com/armand-sauzay/best-practices/tree/main/tutorials/conda_environment"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Python code is great, but being able to reproduce the code is even better! This is why all python projects should come with something that defines the packages and versions to be able to run that exact same code: an environment.&lt;/p&gt;

&lt;p&gt;Then comes the question: how can I create my code environment?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many possibilities. &lt;/p&gt;

&lt;p&gt;First, I am sure all of you have used the following: &lt;code&gt;pip install &amp;lt;package&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But how do we then keep track of the packages we installed and their version? &lt;/p&gt;

&lt;p&gt;This is where virtualenv (native Python environment manager) could come handy. But what happens when you have projects in different python versions? You'd need to use pyenv (native Python version manager) to make sure you use the right version of python. And then virtualenv to make sure you use the right package version…&lt;/p&gt;

&lt;p&gt;It would be great if a tool could do all of this, wouldn't it? &lt;strong&gt;This is why conda exists&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In short, in most cases (except for work that will end in production), conda covers all of what you would need, does some magic behind the scene so you don't have to worry about environments, and has some great added benefits, like allowing you to define environment variables.&lt;/p&gt;

&lt;p&gt;Without further due, let's learn more about conda!&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll cover the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Basic conda commands: create, list, activate and deactivate&lt;/li&gt;
&lt;li&gt;environment.yaml and its use&lt;/li&gt;
&lt;li&gt;Defining environment variables through conda&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  1. Basic conda commands: create, list, activate and deactivate
&lt;/h3&gt;

&lt;p&gt;If you haven't installed conda, you can start by installing &lt;a href="https://docs.conda.io/en/latest/miniconda.html"&gt;miniconda&lt;/a&gt;. If you are not sure, open a terminal and run &lt;code&gt;conda list&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Once the installation is complete, run &lt;code&gt;conda list&lt;/code&gt; to make sure you have conda installed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The following commands are bash commands&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  a. create your environment:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;conda create --name conda-tutorial python=3.8&lt;/code&gt;&lt;br&gt;
→ here we create an environment called conda-tutorial with python 3.8 installed. → NOTE: if it asks whether to proceed, type y and enter&lt;/p&gt;
&lt;h4&gt;
  
  
  b. list existing environments
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;conda env list&lt;/code&gt;&lt;br&gt;
→ you should be able to see the newly created environment&lt;/p&gt;
&lt;h4&gt;
  
  
  c. activate your environment
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;conda activate conda-tutorial&lt;/code&gt;&lt;br&gt;
→ you're now in your conda virtual environment. So the python code you execute should find its python version and the packages currently installed through this environment.&lt;br&gt;
→ to check this, you can type in terminal: which python.&lt;br&gt;
→ also you can install package by typing conda install &lt;br&gt;
→ we'll see later how we can use an environment.yaml to not have manual installs&lt;/p&gt;
&lt;h4&gt;
  
  
  d. deactivate your environment
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;conda deactivate&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  e. Lastly, if you want, remove your environment
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;conda env remove --name &amp;lt;your_environment_name&amp;gt;&lt;/code&gt;&lt;br&gt;
→ note that you need to first deactivate your current environment if you wish to remove it&lt;/p&gt;



&lt;p&gt;Nice! You can now create an environment in which to run your code which can greatly help for reproducibility! You can also bookmark the conda cheat sheet for your future use cases&lt;br&gt;
But, let's be honest, running a lot of conda install  is not that great for reproducibility. So let's see hwo we can use environment.yaml files.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. environment.yaml and its use
&lt;/h3&gt;

&lt;p&gt;Let's create an environment file with pandas installed and test it. For this we need two files&lt;/p&gt;
&lt;h4&gt;
  
  
  1. A simple python file named &lt;code&gt;conda_tutorial_pandas.py&lt;/code&gt; which imports pandas and prints its version.
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### conda_tutorial_pandas.py file
import pandas as pd
if __name__ == "__main__":    
    print(pd.__version__)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  2. A file called environment_pandas.yaml and paste the following in it:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### environment_pandas.yaml file
name: conda-tutorial
channels:
  - conda-forge
  - defaults
dependencies:
    - python=3.8
    - pandas=1.4.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;→ This file will create an environment named conda-tutorial with python 3.8 and pandas 1.4.2.&lt;br&gt;
If you don't have an environment named conda-tutorial, you can run&lt;br&gt;
&lt;code&gt;conda env create --file environment_pandas.yaml&lt;/code&gt;&lt;br&gt;
If you do have an environment named conda-tutorial, you can run&lt;br&gt;
&lt;code&gt;conda env update --file environment_pandas.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, you can activate the environment conda-tutorial and from terminal, run &lt;code&gt;python conda_tutorial_pandas.py&lt;/code&gt;. It should print out: 1.4.2.&lt;/p&gt;



&lt;p&gt;Let's now go a step further and let's create environment variable so you don't have to worry about credentials being leaked for instance.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Environment variables
&lt;/h3&gt;
&lt;h4&gt;
  
  
  a. Create the shell scripts that will activate and deactivate your environment variables.
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd $CONDA_PREFIX 
mkdir -p ./etc/conda/activate.d 
mkdir -p ./etc/conda/deactivate.d 
touch ./etc/conda/activate.d/env_vars.sh 
touch ./etc/conda/deactivate.d/env_vars.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  b. add the following to export your environment variables when you activate your environment
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;nano $CONDA_PREFIX/etc/conda/activate.d/env_vars.sh&lt;/code&gt;&lt;br&gt;
then paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export MY_KEY='secret-key-value' 
export MY_FILE=/path/to/my/file/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then click ctrl+o and then ctrl+x. If you don't want to use nano, you can also manually create this file with its content.&lt;/p&gt;

&lt;h4&gt;
  
  
  c. to unset your environment variables when you deactivate your environment
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;nano $CONDA_PREFIX/etc/conda/deactivate.d/env_vars.sh&lt;/code&gt;&lt;br&gt;
Then paste the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unset MY_KEY 
unset MY_FILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then click ctrl+o and then ctrl+x. If you don't want to use nano, you can manually create this file with its content.&lt;/p&gt;

&lt;p&gt;Now let's create a python file named &lt;code&gt;conda_tutorial_environment_variables.py&lt;/code&gt; which will print out these environment variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### conda_tutorial_environment_variables.py file
import os
if __name__ == "__main__": 
    print(os.getenv("MY_KEY")) 
    print(os.getenv("MY_FILE"))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, activate your conda environment by running &lt;code&gt;conda activate &amp;lt;my_env&amp;gt;&lt;/code&gt; first and then:&lt;br&gt;
&lt;code&gt;python conda_tutorial_environment_variables.py&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;Woohoo! You now know how to create and manage a conda environment and create environment variables in your environment so you don't have to worry about hardcoding credentials in your code!!&lt;/p&gt;




&lt;p&gt;Hope you liked this article! Don't hesitate if you have any question, or suggestions, in comments, or feel free to contact me on LinkedIn, GitHub or Twitter, or checkout some other tutorials I wrote on DS/ML best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  About me
&lt;/h3&gt;

&lt;p&gt;You can follow me, contact me, or see what I do on the following platforms:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/armand-sauzay"&gt;GitHub: armand-sauzay&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/armandsauzay"&gt;Twitter: @armandsauzay&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/armand-sauzay-80a70b160/"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/@armand-sauzay"&gt;Medium: armand-sauzay&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
