<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Rochdi Khalid - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Rochdi Khalid - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 17:39:15 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/rochdikhalid/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use Python Generators – Explained With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ Python generators are a powerful feature that allow lazy iteration through a sequence of values. They produce items one at a time and only when needed, which makes them the best choice for working with large datasets or streams of data where it would... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-python-generators/</link>
                <guid isPermaLink="false">66c375ea63ac6ce6ab8eba8b</guid>
                
                    <category>
                        <![CDATA[ generators ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rochdi Khalid ]]>
                </dc:creator>
                <pubDate>Wed, 10 Jul 2024 19:05:55 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/SERIE-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Python generators are a powerful feature that allow lazy iteration through a sequence of values.</p>
<p>They produce items one at a time and only when needed, which makes them the best choice for working with large datasets or streams of data where it would be inefficient and impractical to load everything into memory at once.</p>
<h2 id="heading-how-to-define-and-use-generators">How to Define and Use Generators</h2>
<p>To define a generator, you can use the <code>def</code> keyword like you would with a normal function. However, instead of returning a value with <code>return</code>, we use <code>yield</code>. </p>
<p>Here, the <code>yield</code> keyword is used to produce a value and pause the execution of the generator function. When the function is resumed, it continues execution immediately after the <code>yield</code> statement.</p>
<h3 id="heading-example-simple-generator">Example: Simple Generator</h3>
<p>Here is a simple generator that yields the first <code>n</code> numbers:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">simple_generator</span>(<span class="hljs-params">n</span>):</span>
    i = <span class="hljs-number">0</span>
    <span class="hljs-keyword">while</span> i &lt; n:
        <span class="hljs-keyword">yield</span> i
        i += <span class="hljs-number">1</span>

<span class="hljs-comment"># Using the generator</span>
gen = simple_generator(<span class="hljs-number">5</span>)
<span class="hljs-keyword">for</span> number <span class="hljs-keyword">in</span> gen:
    print(number)
</code></pre>
<p>Output:</p>
<pre><code class="lang-terminal">0
1
2
3
4
</code></pre>
<p>When the <code>simple_generator()</code> function is called, it doesn't execute its code. Instead, it returns a generator object that contains an internal method named <code>__next__()</code>, which is created when the generator function is called. </p>
<p>The generator object implicitly uses this method as an iterator protocol when we iterate over the generator.</p>
<h2 id="heading-benefits-of-using-generators">Benefits of Using Generators</h2>
<p>Python generators offer several advantages that significantly enhance code efficiency and readability. By efficiently producing items on-the-fly, generators optimize memory usage and enhance performance compared to traditional iterable methods.</p>
<p>Let's explore some these benefits in detail, highlighting how generators streamline Python development and improve code quality.</p>
<h3 id="heading-memory-optimization">Memory Optimization</h3>
<p>Compared to lists that load all elements into memory at once, generators are memory usage optimizers. They produce items one at a time and only when required. </p>
<p>Here is an example that considers a scenario where we need to generate a large list of numbers:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using a list</span>
numbers = [i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1000000</span>)]

<span class="hljs-comment"># Using a generator</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">number_generator</span>():</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1000000</span>):
        <span class="hljs-keyword">yield</span> i

gen_numbers = number_generator()
</code></pre>
<p>With the list, all 1000000 numbers are stored in memory at once, but with the generator, numbers are produced one at a time, reducing memory usage.</p>
<h3 id="heading-enhanced-performance">Enhanced Performance</h3>
<p>Since generators produce items on-the-fly, they enhance performance, particularly in terms of speed and efficiency. They can start yielding results immediately without waiting to process an entire dataset. </p>
<p>In this example, let's assume that we need to process each number in a sequence:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using a list</span>
numbers = [i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1000000</span>)]
squared_numbers = [x**<span class="hljs-number">2</span> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> numbers]

<span class="hljs-comment"># Using a generator</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">number_generator</span>():</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1000000</span>):
        <span class="hljs-keyword">yield</span> i

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">squared_gen</span>(<span class="hljs-params">gen</span>):</span>
    <span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> gen:
        <span class="hljs-keyword">yield</span> num**<span class="hljs-number">2</span>

gen_numbers = number_generator()
squared_gen_numbers = squared_gen(gen_numbers)
</code></pre>
<p>When we use the list, we generated all the numbers and then process them, which takes more time. However, with the generator, each number is processed as soon as it is generated, making the process more efficient.</p>
<h3 id="heading-code-simplicity-and-readability">Code Simplicity and Readability</h3>
<p>Generators help in writing clean and readable code. They allow us to define an iterative algorithm in a simple way, without the need for boilerplate code to manage the state of the iteration. Let's consider a scenario where we need to read lines from a large file:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Using a list</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">read_large_file</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> file:
        lines = file.readlines()
    <span class="hljs-keyword">return</span> lines

lines = read_large_file(<span class="hljs-string">'large_file.txt'</span>)

<span class="hljs-comment"># Using a generator</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">read_large_file</span>(<span class="hljs-params">file_name</span>):</span>
    <span class="hljs-keyword">with</span> open(file_name, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> file:
        <span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> file:
            <span class="hljs-keyword">yield</span> line

lines_gen = read_large_file(<span class="hljs-string">'large_file.txt'</span>)
</code></pre>
<p>With the list approach, we read all lines into memory at once. With the generator, we read and yielded one line at a time, which makes the code simpler and more readable while contributing to saving memory.</p>
<h2 id="heading-practical-use-cases">Practical Use Cases</h2>
<p>This section explores some practical use cases where Python generators excel, discovering how generators simplify complex tasks while optimizing performance and memory usage.</p>
<h3 id="heading-stream-processing">Stream Processing</h3>
<p>Generators are excellent at handling continuous streams of data, like real-time sensor data, log streams, or live feeds from APIs. They provide efficient processing of data as it becomes available, without the need to store large amounts of data in memory.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> time

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">data_stream</span>():</span>
    <span class="hljs-string">"""Simulate a data stream."""</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
        time.sleep(<span class="hljs-number">1</span>) <span class="hljs-comment"># Simulate data arriving every second</span>
        <span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stream_processor</span>(<span class="hljs-params">data_stream</span>):</span>
    <span class="hljs-string">"""Process data from the stream."""</span>
    <span class="hljs-keyword">for</span> data <span class="hljs-keyword">in</span> data_stream:
        processed_data = data * <span class="hljs-number">2</span> <span class="hljs-comment"># Example processing step</span>
        <span class="hljs-keyword">yield</span> processed_data


<span class="hljs-comment"># Usage</span>
stream = data_stream()
processed_stream = stream_processor(stream)
<span class="hljs-keyword">for</span> data <span class="hljs-keyword">in</span> processed_stream:
    print(data)
</code></pre>
<p>In this example, the <code>data_stream()</code> method generates data at intervals, simulating a continuous data stream. The  <code>stream_processor()</code> processes each piece of data as it arrives, demonstrating how generators can handle streaming data efficiently without the need to load all data into memory at once.</p>
<h3 id="heading-iterative-algorithms">Iterative Algorithms</h3>
<p>Generators provide a straightforward way to define and execute iterative algorithms that involve repetitive calculations and simulations. They allow us to maintain the state of the iteration without manually managing loop variables, which can enhance code clarity and maintainability.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fibonacci_generator</span>():</span>
    a, b = <span class="hljs-number">0</span>, <span class="hljs-number">1</span>
    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        <span class="hljs-keyword">yield</span> a
        a, b = b, a + b


<span class="hljs-comment"># Usage</span>
fib_gen = fibonacci_generator()
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
    print(next(fib_gen))
</code></pre>
<p>In the example above, the <code>fibonacci_generator()</code> method defines a generator that produces Fibonacci numbers indefinitely. It returns each Fibonacci number one at a time, starting from 0 and 1. </p>
<p>Here, the <code>for</code> loop iterates 10 times to print the first 10 Fibonacci numbers, demonstrating how generators can efficiently generate and manage sequences without preloading them into memory.</p>
<h3 id="heading-real-time-simulator">Real-Time Simulator</h3>
<p>In this example, we will simulate real-time updates of a stock price. The generator will produce a new stock price at each step, based on the previous price and some random fluctuation.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> random
<span class="hljs-keyword">import</span> time

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stock_price_generator</span>(<span class="hljs-params">initial_price, volatility, steps</span>):</span>
    <span class="hljs-string">"""Generates stock prices starting from initial_price with given volatility."""</span>

    price = initial_price
    <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(steps):
        <span class="hljs-comment"># Simulate price change</span>
        change_percent = random.uniform(-volatility, volatility)
        price += price * change_percent
        <span class="hljs-keyword">yield</span> price
        time.sleep(<span class="hljs-number">1</span>) <span class="hljs-comment"># Simulate real-time delay</span>

<span class="hljs-comment"># Create the stock price generator</span>
initial_price = <span class="hljs-number">100.0</span> <span class="hljs-comment"># Starting stock price</span>
volatility = <span class="hljs-number">0.02</span> <span class="hljs-comment"># Volatility as a percentage</span>
steps = <span class="hljs-number">10</span> <span class="hljs-comment"># Number of steps (updates) to simulate</span>

stock_prices = stock_price_generator(initial_price, volatility, steps)

<span class="hljs-comment"># Simulate recieving and processing real-time stock prices</span>
<span class="hljs-keyword">for</span> price <span class="hljs-keyword">in</span> stock_prices:
    print(<span class="hljs-string">f"New stock price: <span class="hljs-subst">{price:<span class="hljs-number">.2</span>f}</span>"</span>)
</code></pre>
<p>This example generates each stock price on-the-fly based on the previous price and doesn't store all generated prices in memory, making it efficient for long-running simulations. </p>
<p>The generator provides a new stock price at each step with minimal computation. The <code>time.sleep(1)</code> simulates a real-time delay, allowing the system to handle other tasks concurrently if needed.</p>
<h2 id="heading-summary">Summary</h2>
<p>In summary, Python generators offer efficient memory management and enhanced performance, simplifying code while tackling diverse tasks like stream processing, iterative algorithms, and real-time simulation. </p>
<p>Their ability to optimize resources makes them a valuable tool for modern Python developers seeking elegant and scalable solutions.</p>
<p>Hopefully, this exploration of Python generators provides you with the insights needed to leverage their full potential. If you have any questions or want to discuss further, feel free to reach out to me on <a target="_blank" href="https://www.linkedin.com/in/rochdi-khalid/">LinkedIn</a>. Additionally, you can subscribe to <a target="_blank" href="https://www.youtube.com/channel/UCF8iZXSsjgc8kE8hITp5rdQ">my YouTube channel</a> where I share videos on coding techniques and projects I'm working on.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Python Path – How to Use the Pathlib Module with Examples ]]>
                </title>
                <description>
                    <![CDATA[ Each operating system has different rules for constructing file paths. For example, Linux uses forward slashes for paths, while Windows uses backslashes.  This small difference can cause issues if you are working on a project and you want other devel... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-pathlib-module-in-python/</link>
                <guid isPermaLink="false">66c375e840438b5931fe0a06</guid>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rochdi Khalid ]]>
                </dc:creator>
                <pubDate>Tue, 10 May 2022 13:59:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/05/pathlib-cover-freecodecamp.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Each operating system has different rules for constructing file paths. For example, Linux uses forward slashes for paths, while Windows uses backslashes. </p>
<p>This small difference can cause issues if you are working on a project and you want other developers who come from different operating systems to expand your code. </p>
<p>Fortunately, if you're coding in Python, the Pathlib module does the heavy lifting by letting you make sure that your file paths work the same in different operating systems. Also, it provides functionalities and operations to help you save time while handling and manipulating paths.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Pathlib comes as default with Python &gt;= 3.4. However, if you are using a version of Python lower than 3.4, you won't have access to this module.</p>
<h2 id="heading-how-does-pathlib-work">How Does Pathlib Work?</h2>
<p>To understand how you can construct a basic path using Pathlib, let's create a new Python file called <code>example.py</code> and put it inside a particular directory.</p>
<p>Open the file, and type the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pathlib

p = pathlib.Path(__file__)
print(p)
</code></pre>
<p>In this example, we import the Pathlib module. Then, we create a new variable called <code>p</code> to store the path. Here, we use the Path object from Pathlib with a built-in variable in Python called <strong><strong>file</strong></strong> to refer to the file path we are currently writing in it <code>example.py</code>.</p>
<p>If we print <code>p</code>, we will get the path to the file we are currently in:</p>
<pre><code>/home/rochdikhalid/dev/src/package/example.py
</code></pre><p>As shown above, Pathlib creates a path to this file by putting this particular script in a Path object. Pathlib contains many objects such as <code>PosixPath()</code> and <code>PurePath()</code>, which we will learn more about in the following sections.</p>
<p>Before we jump into this, Pathlib divides the filesystem paths into two different classes that represent two types of path objects: <strong>Pure Path</strong> and <strong>Concrete Path</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/04/pathlib-diagram.png" alt="Image" width="600" height="400" loading="lazy">
<em>PurePath() classes</em></p>
<p>The pure path provides utilities to handle and manipulate your file path without making writing operations, while the concrete path allows you to manipulate and do writing operations on your file path. </p>
<p>In other words, a concrete path is a subclass of a Pure path. It inherits manipulation from the parent class and adds input/output operations that do system calls.</p>
<h2 id="heading-pure-paths-in-python">Pure paths in Python</h2>
<p>Pure paths manipulate a file path on your machine even if it belongs to a different operating system. </p>
<p>For example, let's say you are on Linux and you want to use a Windows file path. Here, Pure path class objects will help you get the path working on your machine with some basic operations like creating child paths or accessing individual parts of a path. </p>
<p>But pure paths won't be able to mimic some other operations like creating a directory or a file because you are not actually in that operating system.</p>
<h3 id="heading-how-to-use-pure-paths">How to use pure paths</h3>
<p>As you can see in the diagram above, pure paths consist of three classes that handle any file system path on your machine:</p>
<p><strong>PurePath()</strong> is the root node that provides handling operations to every path object in Pathlib. </p>
<p>When you instantiate <code>PurePath()</code>, it creates two classes to handle Windows paths and non-Windows paths. <code>PurePath()</code> creates a generic path object "agnostic path", regardless of the operating system you are running on.</p>
<pre><code class="lang-python">In [*]: pathlib.PurePath(<span class="hljs-string">'setup.py'</span>)                                            
Out[*]: PurePosixPath(<span class="hljs-string">'setup.py'</span>)
</code></pre>
<p>PurePath() in the example above creates a <code>PurePosixPath()</code> because we assumed we are running on a Linux machine. But if you instantiate it on Windows you will get something like <code>PureWindowsPath('setup.py')</code>.</p>
<p><strong>PurePosixPath()</strong> is the child node of PurePath() implemented for non-Windows file system paths.</p>
<pre><code class="lang-python">In [*]: pathlib.PurePosixPath(<span class="hljs-string">'setup.py'</span>)                                            
Out[*]: PurePosixPath(<span class="hljs-string">'setup.py'</span>)
</code></pre>
<p>You will not get any error if you instantiate <code>PurePosixPath()</code> on Windows because too simply this class doesn't make system calls.</p>
<p><strong>PureWindowsPath()</strong> is the child node of PurePath() implemented for Windows file system paths.</p>
<pre><code class="lang-python">In [*]: pathlib.PureWindowsPath(<span class="hljs-string">'setup.py'</span>)                                     
Out[*]: PureWindowsPath(<span class="hljs-string">'setup.py'</span>)
</code></pre>
<p>The same applies to <code>PureWindowsPath()</code> since this class doesn't provide system calls, so instantiating it will not raise any error for other operating systems.</p>
<h3 id="heading-pure-path-properties">Pure path properties</h3>
<p>Each subclass in <strong><code>PurePath()</code></strong> provides the following properties:</p>
<p><strong>PurePath().parent</strong> outputs the parent of the path:</p>
<pre><code class="lang-python">In [*]: pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>).parent                     
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts'</span>)
</code></pre>
<p>In the example above, we are using the <code>.parent</code> property to get the path of the logical parent of <code>**main.py**</code>.</p>
<p><strong>PurePath().parents[]</strong> outputs the ancestors of the path:</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.parents[<span class="hljs-number">0</span>]               
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts'</span>)

In [*]: p.parents[<span class="hljs-number">1</span>]                
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo'</span>)
</code></pre>
<p>You should always specify the ancestor index in the square brackets as seen above. In Python 3.10 and above, you can use slices and negative index values.</p>
<p><strong>PurePath().name</strong> provides the name of the last component of your path:</p>
<pre><code class="lang-python">In [*]: pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>).name                      
Out[*]: <span class="hljs-string">'main.py'</span>
</code></pre>
<p>In this example, the final path component is <code>main.py</code>. So, the <code>.name</code> property outputs the name of the file <code>main.py</code> which is <strong>main</strong> with its suffix <strong>.py</strong>.</p>
<p>On the other hand, <strong>PurePath().suffix</strong> provides the file extension of the last component of your path:</p>
<pre><code class="lang-python">In [*]: pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>).suffix                    
Out[*]: <span class="hljs-string">'.py'</span>
</code></pre>
<p>Compared to the <code>.name</code> property, the <code>.suffix</code> property outputs the file extension and excludes the file name.</p>
<p><strong>PurePath().stem</strong> outputs only the name of the final component of your path without the suffix:</p>
<pre><code class="lang-python">In [*]: pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>).stem                      
Out[*]: <span class="hljs-string">'main'</span>
</code></pre>
<p>As seen above, the <code>.stem</code> property excludes the suffix of the final component <code>main.py</code> and provides only the name of the file.</p>
<h3 id="heading-pure-path-methods">Pure path methods</h3>
<p>Each subclass of <code>PurePath()</code> provides the following methods:</p>
<p><strong>PurePath().is_absolute()</strong> checks whether your path is absolute or not:</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.is_absolute()

Out[*]: <span class="hljs-literal">True</span>

In [*]: o = pathlib.PurePath(<span class="hljs-string">'scripts/main.py'</span>)
        o.is_absolute()

Out[*]: <span class="hljs-literal">False</span>
</code></pre>
<p>Note that the absolute path consists of a root and drive name. In this case, <code>PurePath()</code> doesn't allow us to know the drive's name. </p>
<p>If you use <code>PureWindowsPath()</code>, you can represent an absolute path that contains a drive name like <code>PureWindowsPath('c:/Program Files')</code>.</p>
<p><strong>PurePath().is_relative()</strong> checks whether the path belongs to the other given path or not:</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.is_relative_to(<span class="hljs-string">'/src'</span>)

Out[*]: <span class="hljs-literal">True</span>

In [*]: p.is_relative_to(<span class="hljs-string">'/data'</span>)

Out[*]: <span class="hljs-literal">False</span>
</code></pre>
<p>In this example, the given path <code>/src</code> is a part of or belongs to the path <code>p</code>, while the other given path <code>/data</code> raises <code>False</code> because it has no relative relationship with the path <code>p</code>.</p>
<p><strong>PurePath().joinpath()</strong> concatenates the path with the given arguments (child paths):</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo'</span>)
        p.joinpath(<span class="hljs-string">'scripts'</span>, <span class="hljs-string">'main.py'</span>)

Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
</code></pre>
<p>Note that there is no need to add slashes in your given arguments, as the <code>.joinpath()</code> method handles this for you.</p>
<p><strong>PurePath().match()</strong> checks whether the path matches a given pattern:</p>
<pre><code class="lang-python">In [*]: pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>).match(<span class="hljs-string">'*.py'</span>)
Out[*]: <span class="hljs-literal">True</span>

In [*]: pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>).match(<span class="hljs-string">'goo/*.py'</span>)
Out[*]: <span class="hljs-literal">True</span>

In [*]: pathlib.PurePath(<span class="hljs-string">'src/goo/scripts/main.py'</span>).match(<span class="hljs-string">'/*.py'</span>)
Out[*]: <span class="hljs-literal">False</span>
</code></pre>
<p>Based on the examples above, the pattern should match the path. If the given pattern is absolute, the path must be absolute too.</p>
<p><strong>PurePath().with_name()</strong> changes the name of the final component with its suffix:</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.with_name(<span class="hljs-string">'app.js'</span>)
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/app.js'</span>)

In [*]: p
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
</code></pre>
<p>The <code>.with_name()</code> method doesn't change the name of the last component permanently. Also, if the given path doesn't contain a name, an error occurs as mentioned in the <a target="_blank" href="https://docs.python.org/3/library/pathlib.html#methods-and-properties">official documentation</a>.</p>
<p><strong>PurePath().with_stem()</strong> changes only the name of the final component of the path:</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.with_stem(<span class="hljs-string">'app.py'</span>)
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/app.py'</span>)

In [*]: p
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
</code></pre>
<p>This is similar to the <code>.with_name()</code> method. The <code>.with_stem()</code> changes the name of the last component temporarily. Also, if the given path doesn't contain a name, an error will occur.</p>
<p><strong>PurePath().with_suffix()</strong> temporarily changes the suffix or the extension of the final component of your path:   </p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.with_suffix(<span class="hljs-string">'.js'</span>)
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/main.js'</span>)
</code></pre>
<p>If the name of the given path contains no suffix, the <code>.with_suffix()</code> method adds the suffix for you:</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main'</span>)
        p.with_suffix(<span class="hljs-string">'.py'</span>)
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
</code></pre>
<p>But, if we don't include the suffix and we keep the argument empty <code>''</code>, the current suffix will be removed.</p>
<pre><code class="lang-python">In [*]: p = pathlib.PurePath(<span class="hljs-string">'/src/goo/scripts/main'</span>)
        p.with_suffix(<span class="hljs-string">''</span>)
Out[*]: PurePosixPath(<span class="hljs-string">'/src/goo/scripts/main'</span>)
</code></pre>
<p>Some methods like <code>.with_stem()</code>, and <code>.is_relative_to()</code> have been added recently to Python 3.9 and above. So, if you call these methods using Python 3.8 or lower, an attribute error is raised.</p>
<h2 id="heading-concrete-paths-in-python">Concrete Paths in Python</h2>
<p>Concrete Paths allows you to handle, manipulate, and do writing operations on different filesystem paths. </p>
<p>In the other words, this type of path object helps you to create for example a new file, a new directory, and do other input/output operations while not being in that operating system.</p>
<h3 id="heading-how-to-use-concrete-paths">How to use concrete paths</h3>
<p>Concrete paths handle any file system path and make system calls on your machine. Those path objects are the child paths of the pure paths and consist of three subclasses like the pure ones:</p>
<p><strong>Path()</strong> is the child node of <code>PurePath()</code>, it provides handling operations with the ability to do writing operations on your path. </p>
<p>When you instantiate <code>Path()</code>, it creates two classes to handle Windows paths and non-Windows paths. Like <code>PurePath()</code>, <code>Path()</code> also creates a generic path object "agnostic path", regardless of the operating system you are running on.</p>
<pre><code class="lang-python">In [*]: pathlib.Path(<span class="hljs-string">'setup.py'</span>)                                            
Out[*]: PosixPath(<span class="hljs-string">'setup.py'</span>)
</code></pre>
<p><code>Path()</code> in the example above creates a <code>PosixPath()</code> because we assume we are running on a Linux machine. But if you instantiate it on Windows you will get something like <code>WindowsPath('setup.py')</code></p>
<p><strong>PosixPath()</strong> is the child node of <code>Path()</code> and <code>PurePosixPath()</code>, implemented to handle and manipulate non-Windows file system paths.</p>
<pre><code class="lang-python">In [*]: pathlib.PosixPath(<span class="hljs-string">'setup.py'</span>)                                            
Out[*]: PosixPath(<span class="hljs-string">'setup.py'</span>)
</code></pre>
<p>You will get an error if you instantiate <code>PosixPath()</code> on a Windows machine because you cannot make system calls while running on a different operating system.</p>
<p><strong>WindowsPath()</strong> is the child node of <code>Path()</code> and <code>PureWindowsPath()</code> implemented for Windows file system paths.</p>
<pre><code class="lang-python">In [*]: pathlib.WindowsPath(<span class="hljs-string">'setup.py'</span>)                                     
Out[*]: WindowsPath(<span class="hljs-string">'setup.py'</span>)
</code></pre>
<p>The same applies to <code>WindowsPath()</code> since you are running on a different operating system – so instantiating it will raise an error.</p>
<h3 id="heading-properties-of-concrete-paths">Properties of concrete paths</h3>
<p>Since the concrete path is the subclass of the pure path, you can do everything with concrete paths using the <code>PurePath()</code> properties. This means that we can use, for example, the <code>.with_suffix</code> property  to add a suffix to a concrete path:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'/src/goo/scripts/main'</span>)
        p.with_suffix(<span class="hljs-string">'.py'</span>)
Out[*]: PosixPath(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
</code></pre>
<p>Or, you can check if a given path is relative to the original path:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'/src/goo/scripts/main.py'</span>)
        p.is_relative_to(<span class="hljs-string">'/src'</span>)

Out[*]: <span class="hljs-literal">True</span>
</code></pre>
<p>Always remember that concrete paths inherit handling operations from the pure paths and add writing operations that do system calls and input/output configurations.</p>
<h3 id="heading-methods-of-concrete-path">Methods of concrete path</h3>
<p>Each subclass of <code>Path()</code> provides the following methods to handle paths and do system calls:</p>
<p><strong>Path().iterdir()</strong> returns the content of a directory. Let's say we have the following folder that contains the following files:</p>
<pre><code>data
    population.json
    density.json
    temperature.yml
    stats.md
    details.txt
</code></pre><p>To return the content of <code>/data</code> directory, you can use <code>.iterdir()</code> method here:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'/data'</span>)

        <span class="hljs-keyword">for</span> child <span class="hljs-keyword">in</span> p.iterdir():
            print(child)

Out[*]: PosixPath(<span class="hljs-string">'/data/population.json'</span>)
         PosixPath(<span class="hljs-string">'/data/density.json'</span>)
         PosixPath(<span class="hljs-string">'/data/temprature.yml'</span>)
         PosixPath(<span class="hljs-string">'/data/stats.md'</span>)
         PosixPath(<span class="hljs-string">'/data/details.txt'</span>)
</code></pre>
<p>The <code>.iterdir()</code> method creates an iterator that lists the files randomly.</p>
<p><strong>Path().exists()</strong> checks whether the file/directory exists in a current path. Let's use the directory of the previous example (our current directory is <code>/data</code>):</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'density.json'</span>).exists()
        p
Out[*]: <span class="hljs-literal">True</span>
</code></pre>
<p>The <strong>.exists()</strong> method returns <code>True</code> because the given file exists in the <code>data</code> directory. The method returns <code>False</code> if the file doesn't exist.</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'aliens.py'</span>).exists()
        p
Out[*]: <span class="hljs-literal">False</span>
</code></pre>
<p>The same applies to directories, the method returns <code>True</code> if the given directory exists and returns <code>False</code> if it does not.</p>
<p><strong>Path().mkdir()</strong> creates a new directory at a given path:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'data'</span>)
        directory = pathlib.Path(<span class="hljs-string">'data/secrets'</span>)
        directory.exists()
Out[*]: <span class="hljs-literal">False</span>

In [*]: directory.mkdir(parents = <span class="hljs-literal">False</span>, exist_ok = <span class="hljs-literal">False</span>)
        directory.exists()
Out[*]: <span class="hljs-literal">True</span>
</code></pre>
<p>According to the official documentation, the <code>.mkdir()</code> method takes three arguments. We will focus only at the moment on <code>parents</code> and <code>exist_ok</code>. </p>
<p>Both arguments are set to <code>False</code> as default. The <code>parent</code> raises a FileNotFound error in case of a missing parent, while the <code>exist_ok</code> raises a FileExists error if the given directory already exists.</p>
<p>In the example above, you can set the arguments to <code>True</code> to ignore the mentioned errors and update the directory.</p>
<p>We can also create a new file at a given path using the <code>Path().touch()</code> method:</p>
<pre><code class="lang-python">In [*]: file = pathlib.Path(<span class="hljs-string">'data/secrets/secret_one.md'</span>)
        file.exists()
Out[*]: <span class="hljs-literal">False</span>

In [*]: file.touch(exist_ok = <span class="hljs-literal">False</span>)
        file.exists()
Out[*]: <span class="hljs-literal">True</span>
</code></pre>
<p>The same logic applies to the <code>.touch()</code> method. Here, the <code>exist_ok</code> can be set to <code>True</code> to ignore the FileExists error and update the file.</p>
<p><strong>Path().rename()</strong> renames the file/directory at a given path. Let's take an example using our directory <code>/data</code>:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'density.json'</span>)
        n = pathlib.Path(<span class="hljs-string">'density_2100.json'</span>)
        p.rename(n)
Out[*]: PosixPath(<span class="hljs-string">'density_2100.json'</span>)
</code></pre>
<p>If you assign a non existing file to the method, it raises a FileNotFound error. The same applies to directories.</p>
<p><strong>Path().read_text()</strong> returns the content of a file in string format:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'info.txt'</span>)
        p.read_text()

Out[*]: <span class="hljs-string">'some text added'</span>
</code></pre>
<p>Also, you can use the <code>**write_text()**</code> method to write a content in a file:</p>
<pre><code class="lang-python">In [*]: p = pathlib.Path(<span class="hljs-string">'file.txt'</span>)
        p.write_text(<span class="hljs-string">'we are building an empire'</span>)

Out[*]: <span class="hljs-string">'we are building an empire'</span>
</code></pre>
<p>Note that the <strong><code>.write_text()</code></strong> method has been added to Python 3.5 and was updated recently in Python 3.10 to have some additional parameters.</p>
<h2 id="heading-important-note">Important note</h2>
<p>You might ask yourself why you need to use Windows file system paths – because every package should be compatible with other operating systems, not Windows only. </p>
<p>You're right if the goal is to make an OS-agnostic path. But, sometimes we can't do this due to some settings that are unique to Windows or Posix systems. That's why those objects are available to help developers deal with those use cases. </p>
<p>Some packages target problems only present in the Windows ecosystem, and Python accommodates those use cases in this library.</p>
<h2 id="heading-what-next">What next?</h2>
<p>Hopefully, this tutorial helps you learn how and why to use Pathlib and how it is useful to handle and manipulate filesystem paths. </p>
<p>It would be great to play around with what you learned and turn things into a real project. If you have any questions, feel free to connect and hit me up at any time on <a target="_blank" href="https://www.linkedin.com/in/rochdi-khalid/">LinkedIn</a>. </p>
<p>Also, you can take a look at my channel on <a target="_blank" href="https://www.youtube.com/channel/UCF8iZXSsjgc8kE8hITp5rdQ">YouTube</a> where I share videos on what I'm learning and building with code.</p>
<p>See you in the next tutorial, and keep moving forward!</p>
<h3 id="heading-references">References</h3>
<p>There is a lot to know. In this blog post, I covered the basics you need to use Pathlib in your project. </p>
<p>The official documentation highlights more methods and properties that you can apply to your filesystem paths:</p>
<ul>
<li><a target="_blank" href="https://docs.python.org/3/library/pathlib.html">Pathlib — Object-oriented filesystem paths</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create and Upload Your First Python Package to PyPI ]]>
                </title>
                <description>
                    <![CDATA[ A few weeks ago, I wanted to learn how to build my first Python package, and I was trying to figure out where to start.  Well, I got confused and a bit stressed trying to find a simple and easy tutorial I could use to get started. For this ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-and-upload-your-first-python-package-to-pypi/</link>
                <guid isPermaLink="false">66c375e463ac6ce6ab8eba89</guid>
                
                    <category>
                        <![CDATA[ package ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rochdi Khalid ]]>
                </dc:creator>
                <pubDate>Mon, 11 Apr 2022 15:40:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/cover-image-python-packaging-blog-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A few weeks ago, I wanted to learn how to build my first Python package, and I was trying to figure out where to start. </p>
<p>Well, I got confused and a bit stressed trying to find a simple and easy tutorial I could use to get started. For this reason, I decided to write this tutorial documenting how I built my first Python package.</p>
<h2 id="heading-what-is-a-package-in-python">What is a package in Python?</h2>
<p>Before we get started, we should know a package means in Python.</p>
<p>A Python package is a directory that contains a bunch of modules with a dependency file called <code>__init__.py</code>. This file can be completely empty and you use it to mark the directory on a disk as a Python package. </p>
<p>The following shows an example of a package directory:</p>
<pre><code>package
    __init__.py
    module_a.py
    module_b.py
    module_c.py
</code></pre><p>The <code>__init__.py</code> is a dependency file that helps Python look for the available modules in our package directory. If we remove this file, Python will fail to import our modules.</p>
<h2 id="heading-packages-vs-modules-in-python">Packages vs modules in Python</h2>
<p>You should now understand that Python packages create a structured directory with several modules, but what about modules? Let's make sure we understand the difference between a package and a module:</p>
<p>A <strong>Module</strong> always corresponds to a single Python file <em>turtle.py</em>. It contains logic like classes, functions, and constants.</p>
<p>A <strong>Package</strong> is basically a module that could contain many modules or sub-packages.</p>
<h2 id="heading-package-structure">Package structure</h2>
<p>Packages don't only contain modules, though. They consist of top-level scripts, documentation, and tests, as well. The following example shows how a basic Python package can be structured:</p>
<pre><code>package_name/
    docs/
    scripts/
    src/
        package_a
            __init__.py
            module_a.py
        package_b
            __init__.py
            module_b.py
    tests/
        __init__.py
        test_module_a.py
        test_module_b.py
    LICENSE.txt
    CHANGES.txt
    MANIFEST.in
    README.txt
    pyproject.toml
    setup.py
    setup.cfg
</code></pre><p>Let's understand what each file in the tree above is used for:</p>
<ul>
<li><strong>package_name</strong>: represents the main package.</li>
<li><strong>docs</strong>: includes documentation files on how to use the package.</li>
<li><strong>scripts/</strong>: your top-level scripts.</li>
<li><strong>src</strong>: where your code goes. It contains packages, modules, sub-packages, and so on.</li>
<li><strong>tests</strong>: where you can put unit tests.</li>
<li><strong>LICENSE.txt</strong>: contains the text of the license (for example, MIT).</li>
<li><strong>CHANGES.txt</strong>: reports the changes of each release.</li>
<li><strong>MANIFEST.in</strong>: where you put instructions on what extra files you want to include (non-code files).</li>
<li><strong>README.txt</strong>: contains the package description (markdown format).</li>
<li><strong>pyproject.toml</strong>: to register your build tools.</li>
<li><strong>setup.py</strong>: contains the build script for your build tools.</li>
<li><strong>setup.cfg</strong>: the configuration file of your build tools.</li>
</ul>
<p>Note that there are two options for how to include our test files in our main package. We can keep it at the top level as we did above or put it inside the package like the following:</p>
<pre><code>package_name/
      __init__.py
      module_a.py
      module_b.py
      test/
          __init__.py
          test_module_a.py
          test_module_b.py
</code></pre><p>In my opinion, I think keeping tests at the top level can help a lot especially when our tests require reading and writing other external files.</p>
<h2 id="heading-should-you-use-setupcfg-or-setuppy">Should you use setup.cfg or setup.py?</h2>
<p>The <strong>setup.py</strong> and <strong>setup.cfg</strong> are the default packaging tools within PyPI, setuptools, pip, and the standard python library. </p>
<p>Here, they represent the configuration and build scripts for setuptools. They both tell the setuptools how the package can be built and installed. </p>
<p>The mentioned file contains information like the version, packages, and files to include, along with any requirements.</p>
<p>The following shows an example of <code>setup.py</code> that uses some <code>setup()</code> arguments. You can find more arguments <a target="_blank" href="https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#setup-args">here</a>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> setuptools

<span class="hljs-keyword">with</span> open(<span class="hljs-string">"README.md"</span>, <span class="hljs-string">"r"</span>, encoding = <span class="hljs-string">"utf-8"</span>) <span class="hljs-keyword">as</span> fh:
    long_description = fh.read()

setuptools.setup(
    name = <span class="hljs-string">"package-name"</span>,
    version = <span class="hljs-string">"0.0.1"</span>,
    author = <span class="hljs-string">"author"</span>,
    author_email = <span class="hljs-string">"author@example.com"</span>,
    description = <span class="hljs-string">"short package description"</span>,
    long_description = long_description,
    long_description_content_type = <span class="hljs-string">"text/markdown"</span>,
    url = <span class="hljs-string">"package URL"</span>,
    project_urls = {
        <span class="hljs-string">"Bug Tracker"</span>: <span class="hljs-string">"package issues URL"</span>,
    },
    classifiers = [
        <span class="hljs-string">"Programming Language :: Python :: 3"</span>,
        <span class="hljs-string">"License :: OSI Approved :: MIT License"</span>,
        <span class="hljs-string">"Operating System :: OS Independent"</span>,
    ],
    package_dir = {<span class="hljs-string">""</span>: <span class="hljs-string">"src"</span>},
    packages = setuptools.find_packages(where=<span class="hljs-string">"src"</span>),
    python_requires = <span class="hljs-string">"&gt;=3.6"</span>
)
</code></pre>
<p>The <code>setup.cfg</code> is written in a different format compared to <code>setup.py</code>, and contains basically two essential keys, <code>command</code> and <code>options</code>. </p>
<p>The <code>command</code> key represents one of the <strong>distutils</strong> commands, while the <code>options</code> key defines the options the command can support.</p>
<pre><code>[command]
option = value
</code></pre><p>The following shows an example of <code>setup.cfg</code> that uses some metadata and options. You can find a variety of metadata and options <a target="_blank" href="https://setuptools.pypa.io/en/latest/userguide/declarative_config.html">here</a>:</p>
<pre><code>[metadata]
name = package-name
version = <span class="hljs-number">0.0</span><span class="hljs-number">.1</span>
author = name <span class="hljs-keyword">of</span> the author
author_email = author@example.com
description = short package description
long_description = file: README.md
long_description_content_type = text/markdown
url = package url
project_urls =
    Bug Tracker = package issues url
classifiers =
    Programming Language :: Python :: <span class="hljs-number">3</span>
    <span class="hljs-attr">License</span> :: OSI Approved :: MIT License
    Operating System :: OS Independent

[options]
package_dir =
    = src
packages = find:
python_requires = &gt;=<span class="hljs-number">3.6</span>

[options.packages.find]
where = src
</code></pre><p>The <code>setup.py</code> and <code>setup.cfg</code> are both specific to setuptools. Also, the <code>setup.cfg</code> can safely be moved to <code>pyproject.toml</code>. </p>
<p>Here, the idea is that maybe one day we'll want to switch to other build systems like <strong>flit</strong> or <strong>poetry</strong>. In that case, all we'll need to do is change the build-system entry (setuptools for example) in <code>pyproject.toml</code> to something like flit or poetry rather than starting over from scratch. </p>
<p><a target="_blank" href="https://packaging.python.org/en/latest/key_projects/#build">Here</a> you can find information about other tools that build and distribute Python packages.</p>
<p>No matter which configuration file we chose, we are "locked-in" to maintaining that particular configuration file, either pyproject.toml, setup.cfg, or setup.py.</p>
<p>According to the <a target="_blank" href="https://packaging.python.org/en/latest/">Python Packaging User Guide</a>, <code>setup.cfg</code> is preferred because it's static, clean, easier to read, and avoids encoding errors.</p>
<h2 id="heading-how-to-build-your-first-python-package">How to build your first Python package</h2>
<p>Now, it's time to start building a simple Python package. We will use setuptools as a build system and we will configure our project using <code>setup.cfg</code> and <code>pyproject.toml</code>.</p>
<h3 id="heading-set-up-the-package-files">Set up the package files</h3>
<p>For this simple package, we need to structure our directory by adding the dependency files needed to get the package ready for distribution. This is how to structure our package:</p>
<pre><code>basicpkg/
    src/
        divide
            __init__.py
            divide_by_three.py
        multiply
            __init__.py
            multiply_by_three.py
    tests/
        __init__.py
        test_divide_by_three.py
        test_multiply_by_three.py
    LICENSE.txt
    README.txt
    pyproject.toml
    setup.cfg
</code></pre><p>Our main package consists of two packages: the first one to divide numbers by three, and the other to multiply numbers by three. </p>
<p>Also, we ignore some files like <code>CONTEXT.txt</code>, <code>MANIFEST.in</code>, and the <code>docs/</code> directory to keep things simple at the moment. But we need the <code>test/</code> directory to include our unit tests to test the package's behaviors.</p>
<h3 id="heading-add-some-logic-to-our-modules">Add some logic to our modules</h3>
<p>As always, we will keep the <code>__init__.py</code> empty. Then, we need to put some logic in our modules to perform our operations. </p>
<p>For the divide package, let's add the following content into <code>divide_by_three.py</code> to divide any number by three:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">divide_by_three</span>(<span class="hljs-params">num</span>):</span>
    <span class="hljs-keyword">return</span> num / <span class="hljs-number">3</span>
</code></pre>
<p>The same logic applies to <code>multiply_by_three.py</code> inside the multiply package. But, this time is to multiply any number by three:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">multiply_by_three</span>(<span class="hljs-params">num</span>):</span>
    <span class="hljs-keyword">return</span> num * <span class="hljs-number">3</span>
</code></pre>
<p>Feel free to add more packages and modules to perform other kinds of operations. For example, you can add packages to do addition and subtraction tasks.</p>
<h3 id="heading-test-our-modules">Test our modules</h3>
<p>It's good to practice adding automated tests to any program we create. We will use <code>unittest</code> to test our modules and the package's behavior. </p>
<p>Inside the <code>test/</code> directory, let's add the following code to <code>test_divide_by_three.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest
<span class="hljs-keyword">from</span> divide.by_three <span class="hljs-keyword">import</span> divide_by_three 

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestDivideByThree</span>(<span class="hljs-params">unittest.TestCase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_divide_by_three</span>(<span class="hljs-params">self</span>):</span>
        self.assertEqual(divide_by_three(<span class="hljs-number">12</span>), <span class="hljs-number">4</span>)

unittest.main()
</code></pre>
<p>We imported TestCase from <code>unittest</code> to perform our automated testing. Then, we imported our division method <code>divide_by_three()</code> from <code>by_three</code> module that is located inside the divide package. </p>
<p>If we remove the <code>__init__.py</code> here, Python will no longer be able to find our modules. </p>
<p>The <code>.assertEqual()</code> is used to check the equality of the two values above (divide_by_three(12) and 4). The <code>unittest.main()</code> is instantiated to run all our tests.</p>
<p>The same logic applies to <code>test_multiply_by_three.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest
<span class="hljs-keyword">from</span> multiply.by_three <span class="hljs-keyword">import</span> multiply_by_three

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestMultiplyByThree</span>(<span class="hljs-params">unittest.TestCase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_multiply_by_three</span>(<span class="hljs-params">self</span>):</span>
        self.assertEqual(multiply_by_three(<span class="hljs-number">3</span>), <span class="hljs-number">9</span>)

unittest.main()
</code></pre>
<p>To run the tests, type the following in your terminal/command:</p>
<p>For Linux:</p>
<pre><code>python3 tests/test_divide_by_three.py
</code></pre><p>For Windows:</p>
<pre><code>py tests/test_divide_by_three.py
</code></pre><p>Do the same to test the multiply module. If our tests run successfully, you should get the following:</p>
<pre><code>.
----------------------------------------------------------------------
Ran <span class="hljs-number">1</span> test <span class="hljs-keyword">in</span> <span class="hljs-number">0.000</span>s

OK
</code></pre><p>If you add extra packages and modules, try to add some <code>unittest</code> methods to them. This is going to be a good challenge for you.</p>
<h3 id="heading-configure-metadata-using-setupcfg">Configure metadata using setup.cfg</h3>
<p>Next, we need to add a configuration file for setuptools. As mentioned before, this config file will tell setuptools how our package can be built and installed. </p>
<p>So, we need to add the following metadata and options to our <code>setup.cfg</code>. Then, don't forget to choose a different name because I already uploaded this package with the name below to <a target="_blank" href="https://test.pypi.org/project/basicpkg/">TestPyPi</a>. Also, change other information like author, email, and project URLs to distribute the package with your info.</p>
<pre><code>[metadata]
name = basicpkg
version = <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
author = your name
author_email = your email
description = A simple Python package
long_description = file: README.md, LICENSE.txt
long_description_content_type = text/markdown
url = https:<span class="hljs-comment">//gitlab.com/codasteroid/basicpkg</span>
project_urls =
    Bug Tracker = https:<span class="hljs-comment">//gitlab.com/codasteroid/basicpkg/-/issues</span>
    repository = https:<span class="hljs-comment">//gitlab.com/codasteroid/basicpkg</span>
classifiers =
    Programming Language :: Python :: <span class="hljs-number">3</span>
    <span class="hljs-attr">License</span> :: OSI Approved :: MIT License
    Operating System :: OS Independent

[options]
package_dir =
    = src
packages = find:
python_requires = &gt;=<span class="hljs-number">3.6</span>

[options.packages.find]
where = src
</code></pre><p>You should just keep everything as default in the options category. The package_dir locates the root package where your packages, modules, and all your Python source files are located. </p>
<p>In the packages key, we can list our packages manually like this <code>[divide, multiply]</code>. But if we want to get all the packages, we can use <code>find:</code> and specify where we need to find these packages by using <code>[options.packages.find]</code> with the <code>where</code> key assigned to the name of the root package.</p>
<p>Always make sure to include the <code>classifiers</code> key in your configuration file to add some important information like the version of Python and the operating system our package is suitable for. You can find the complete list of classifiers <a target="_blank" href="https://pypi.org/classifiers/">here</a>.</p>
<h3 id="heading-create-pyprojecttoml">Create pyproject.toml</h3>
<p>We will be using setuptools as a build system. To tell <code>pip</code> or other build tools about our build system, we need two variables, as seen below. </p>
<p>We use <code>build-system.require</code> to include what we need to build our package, while <code>build-system.build-back-end</code> defines the object that will perform the build. </p>
<p>So, let's enter the following content in <code>pyproject.toml</code>:</p>
<pre><code>[build-system]
requires = [<span class="hljs-string">'setuptools&gt;=42'</span>]
build-backend = <span class="hljs-string">'setuptools.build_meta'</span>
</code></pre><p>Note that you can safely move all configuration settings in <code>setup.cfg</code> to <code>pyproject.toml</code> if you decide to change the build system to flit or poetry, for example. This will save you time.</p>
<h3 id="heading-create-the-readmemd">Create the README.md</h3>
<p>Creating a good <code>README.md</code> is important. Let's add a description to our package, and include some instructions on how to install it:</p>
<pre><code class="lang-markdown"><span class="hljs-section"># `basicpkg`</span>

The <span class="hljs-code">`basicpkg`</span> is a simple testing example to understand the basics of developing your first Python package.
</code></pre>
<p>We can also add how to use our package like this:</p>
<pre><code class="lang-markdown">from multiply.by<span class="hljs-emphasis">_three import multiply_</span>by<span class="hljs-emphasis">_three
from divide.by_</span>three import divide<span class="hljs-emphasis">_by_</span>three

multiply<span class="hljs-emphasis">_by_</span>three(9)
divide<span class="hljs-emphasis">_by_</span>three(21)
</code></pre>
<p>Feel free to add any information that can help other devs understand what your package is used for and some instructions on how to install it and work properly with it. </p>
<p>Note that our configuration file will load the <code>README.md</code> and will be included when we distribute our package.</p>
<h3 id="heading-add-a-license">Add a license</h3>
<p>It's very important to add a LICENSE to your project to let users know how they can use your code. Let's choose an MIT license for our Python package and add the following content to <code>LICENSE.txt</code>:</p>
<pre><code>MIT License

Copyright (c) [year] [fullname]

Permission is hereby granted, free <span class="hljs-keyword">of</span> charge, to any person obtaining a copy <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span> software and associated documentation files (the <span class="hljs-string">"Software"</span>), to deal <span class="hljs-keyword">in</span> the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies <span class="hljs-keyword">of</span> the Software, and to permit persons to whom the Software is furnished to <span class="hljs-keyword">do</span> so, subject to the following conditions:

The above copyright notice and <span class="hljs-built_in">this</span> permission notice shall be included <span class="hljs-keyword">in</span> all copies or substantial portions <span class="hljs-keyword">of</span> the Software.

THE SOFTWARE IS PROVIDED <span class="hljs-string">"AS IS"</span>, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</code></pre><p>Don't forget to replace [year] with the current year and [full name] with your name or the names of the copyright holders.</p>
<h3 id="heading-generate-the-distribution-archives">Generate the distribution archives</h3>
<p>One more step left to get our package ready for distribution: generating the distribution archives for our Python package. To do so, first we need to update our PyPA's build and then generate the source and built archives.</p>
<p>In the terminal/cmd, run the following commands from the same directory where the <code>pyproject.toml</code> file is located:</p>
<p>For Linux:</p>
<pre><code>python3 -m pip install --upgrade build
python3 -m build
</code></pre><p>For Windows:</p>
<pre><code>py -m pip install --upgrade build
py -m build
</code></pre><p>Once the process above is completed, a new directory is generated called <code>dist/</code> with two files in it. The <code>.tag.tz</code> file is the source archive and the <code>.whl*</code> file is the built archive. These files represent the distribution archives of our Python package which will be uploaded to the Python Package Index and installed by <code>pip</code> in the following sections.</p>
<h2 id="heading-how-to-upload-a-package-in-python">How to upload a package in Python</h2>
<p>Python Package Index is where we should upload our project. Since our Python package is in test and we might add other functionalities to experiment with it, we should use a separate instance of PyPI called TestPyPI. This instance is specifically implemented for testing and experimentation. Then, once your package is ready and meets your expectations, you can upload it to PyPI as a real package.</p>
<p>Let's follow the instructions below to get our TestPyPI ready to upload our package:</p>
<ol>
<li>Go to <a target="_blank" href="https://test.pypi.org/">TestPyPI</a> and create an account.</li>
<li>Verify your email address so you can upload packages.</li>
<li>Update your profile settings (add your picture and so on).</li>
<li>Go to <a target="_blank" href="https://test.pypi.org/manage/account/#api-tokens">api-tokens</a> and create your API token to securely upload your packages.</li>
<li>On the same page, set the scope to "entire account".</li>
<li>Copy and save your token in a safe place on your disk.</li>
</ol>
<p>Next, we need to upload our distribution archives. To do so, we have to use an upload tool to upload our package. The official PyPI upload tool is <strong>twine</strong>, so let's install twine and upload our distribution archives under the <code>dist/</code> directory.</p>
<p>In the terminal/cmd, run the following commands from the same directory where the <code>pyproject.toml</code> file is located:</p>
<p>For Linux:</p>
<pre><code>python3 -m pip install --upgrade twine
python3 -m twine upload --repository testpypi dist<span class="hljs-comment">/*</span>
</code></pre><p>For Windows:</p>
<pre><code>py -m pip install --upgrade twine
py -m twine upload --repository testpypi dist<span class="hljs-comment">/*</span>
</code></pre><p>Then, enter <code>__token__</code>. as username, and the token (pypi- prefix included) you saved as a password. Press Enter to upload the distributions.</p>
<h2 id="heading-how-to-install-the-uploaded-python-package">How to install the uploaded Python package</h2>
<p>Now, it's time to install our package. You can create a new virtual environment and use <code>pip</code> to install it from TestPyPI:</p>
<p>For Linux:</p>
<pre><code>python3 -m venv env
source env/bin/activate
(env) python3 -m pip install --index-url https:<span class="hljs-comment">//test.pypi.org/simple/ --no-deps basicpkg</span>
</code></pre><p>For Windows:</p>
<pre><code>py -m venv env
.\env\Scripts\activate
(env) py -m pip install --index-url https:<span class="hljs-comment">//test.pypi.org/simple/ --no-deps basicpkg</span>
</code></pre><p>Make sure your virtual environment is activated before you verify if our package works properly. </p>
<p>In the terminal/command, run <code>python3</code> for Linux users or run <code>py</code> for Windows users. Then, type the following code to make sure that the multiply and divide packages work as expected:</p>
<pre><code><span class="hljs-keyword">from</span> multiply.by_three <span class="hljs-keyword">import</span> multiply_by_three
<span class="hljs-keyword">from</span> divide.by_three <span class="hljs-keyword">import</span> divide_by_three

multiply_by_three(<span class="hljs-number">9</span>)
divide_by_three(<span class="hljs-number">21</span>)

# Output: <span class="hljs-number">27</span>
# Output: <span class="hljs-number">7</span>
</code></pre><p>Remember that we need to import the methods from our modules that we need to perform the desired operations, as we did above.</p>
<p>Hooray! Our package works as expected.</p>
<p>So, once you test and experiment with your package, follow the instructions below to upload your package to the real PyPI:</p>
<ol>
<li>Go to <a target="_blank" href="https://pypi.org/">PyPI</a> and create an account.</li>
<li>Run <code>twine upload dist/*</code> in the terminal/command line.</li>
<li>Enter the account credentials you registered for on the actual PyPI.</li>
<li>Then, run <code>pip install [package_name]</code> to install your package.</li>
</ol>
<p>Congratulations! Your package was installed from the real PyPI.</p>
<h2 id="heading-whats-next">What's next?</h2>
<p>It would be great if you come up with a simple idea and build with it your first real Python package. In this blog post, I focused only on the basics you need to get started, but there is a lot to learn in the world of packaging. </p>
<p>Hopefully, my first experience with developing Python packages helps you learn what you need to get building. If you have any questions, feel free to connect and hit me up at any time on <a target="_blank" href="https://www.linkedin.com/in/rochdi-khalid/">LinkedIn</a>. Also, you can subscribe to my <a target="_blank" href="https://www.youtube.com/channel/UCF8iZXSsjgc8kE8hITp5rdQ">channel</a> on YouTube where I share videos on what I'm learning and building with code.</p>
<p>See you in the next post and keep moving forward!</p>
<h3 id="heading-references">References</h3>
<p>Here are some references that helped me develop my first Python package:</p>
<ul>
<li><a target="_blank" href="https://packaging.python.org/en/latest/tutorials/packaging-projects/">Packaging Python Projects</a></li>
<li><a target="_blank" href="https://packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata">Configuring metadata</a></li>
<li><a target="_blank" href="https://peps.python.org/pep-0621/#example">PEP 621 – Storing project metadata in pyproject.toml</a></li>
<li><a target="_blank" href="https://packaging.python.org/en/latest/glossary/#term-Source-Archive">Glossary - Python Packaging User Guide</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
