Creating a Python Package

30 minutes
  • 4 Learning Objectives

About this Hands-on Lab

Modules are the main way we share code in Python, but modules are almost always shared as a part of a package. In this hands-on lab, we’ll create an installable package that contains a module and exposes some functions directly through the package itself. To feel comfortable completing this lab, you’ll want to know how to create and use packages (watch the “Creating and Using Packages” video from the [Certified Associate in Python Programming Certification](https://linuxacademy.com/cp/modules/view/id/470) course), as well as how to make an installable package and install packages (watch the “Distributing and Installing Packages” video from the [Certified Associate in Python Programming Certification](https://linuxacademy.com/cp/modules/view/id/470) course).

Learning Objectives

Successfully complete this lab by achieving the following learning objectives:

Create the Folder Structure for the `words` Package within the `~/packages` Directory

Before we implement the actual functionality of our package, we’re going to create the folder structure and the files we’ll need. Our code will go within a directory under the ~/packages/words/src/ directory, and we’ll also need a setup.py at the root of our higher-level words directory (the project directory).

Run the following commands to set up the folder structure and files we need to create a fully installable Python package:

mkdir -p ~/packages/words/src/words
mv ~/generator.py ~/packages/words/src/words/
touch ~/packages/words/setup.py
touch ~/packages/words/src/words/__init__.py
Write the `random_word` and `random_words` Functions within the `words.generator` Module

Our words.generator module will hold both of the useful functions we need to write and already has a little bit of code to start. Here’s what the file should look like before we begin:

~/packages/words/src/words/generator.py

from random import sample

# Do not modify or remove this
with open("/usr/share/dict/words", "r") as f:
    WORD_LIST = [w.strip("n") for w in f.readlines()]

We need to utilize the sample function from the standard libraries random module to get a random list of words, and then we can write random_word to take the first item from a list returned from a call to random_words. Here’s one way we can implement these functions:

~/packages/words/src/words/generator.py

from random import sample

# Do not modify or remove this
with open("/usr/share/dict/words", "r") as f:
    WORD_LIST = [w.strip("n") for w in f.readlines()]

def random_word():
    return random_words(1)[0]

def random_words(length):
    return sample(WORD_LIST, length)
Customize `~/packages/words/src/words/__init__.py` to Provide the `random_words` Function

The using_packages.py file uses the random_words function without explicitly importing it from the words.generator package. Instead, it has from words import *. This means we need to import the random_words function into the __init__.py for our package and, optionally, we can explicitly make that available using the __all__ variable. Here’s one way we can achieve this:

~/packages/words/src/words/init.py

__all__ = ["random_words"]

from .generator import *

Now, running from words import * when the package is installed will result in all the definitions from words.generator being loaded, but only random_words will get imported.

Write the `setup.py`, Build a Wheel, and Install the Package Using `pip`

Our package now has all the functional code it needs, but it is not installable. We need to customize our setup.py using the setup function from setuptools. We could start with a starter file like this one from the PyPA example repository, or we can write a simple one from scratch. Here’s the simplest version of this file:

~/packages/words/setup.py

from setuptools import find_packages, setup

setup(
    name="words",
    version="1.0.0",
    description="Helper library for working with random words",
    package_dir={"": "src"},
    packages=find_packages(where="src"),
)

Now we need to ensure wheel is installed and then build a wheel for our package using the bdist_wheel subcommand.

cd ~/packages/words
pip3.7 install --user --upgrade wheel
python3.7 setup.py bdist_wheel

Next, let’s install our package using pip and then run the ~/using_packages.py script:

pip3.7 install --user ~/packages/words/dist/words-1.0.0-py3-none-any.whl
python3.7 using_packages.py

Additional Resources

We have a using_packages.py script that is utilizing a package we haven't created yet. We need to create the words package that provides a generator module with a few functions:

  • random_word: Returns a single random word from the system's words file (found at /usr/share/dict/words)
  • random_words: Takes a length and returns a list of random words of that length

We've been provided a generator.py file that includes the code necessary to populate a WORD_LIST variable, but we need to move this file into a words package we'll create within the packages directory.

Logging In

There are a couple of ways to get in and work with the code. One is to use the credentials provided in the hands-on lab overview page, log in with SSH, and use a text editor in the terminal.

The other is using VS Code in the browser. If you'd like to go this route, you will need to navigate to the public IP address of the workstation server (provided in the hands-on lab overview page) on port 8080 (example: http://<PUBLIC_IP>:8080). Your password will be the same password that you'd use to connect over SSH.

What are Hands-on Labs

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Sign In
Welcome Back!

Psst…this one if you’ve been moved to ACG!

Get Started
Who’s going to be learning?