Objective

In this unit, you'll learn how to manage Python projects, dependencies, and virtual environments using Poetry. By the end of this unit, you'll understand how to create a project, add dependencies, and build and publish packages.

Introduction to Dependency Management

Dependency management is the process of handling the libraries and packages that your code relies on. It ensures that the correct versions of these dependencies are used and that they are compatible with each other.

Poetry is a popular tool for managing dependencies in Python projects. It simplifies the process of adding, updating, and removing dependencies, and it helps maintain a consistent environment across different stages of development.

Installing and Configuring Poetry

Installing Poetry

To get started with Poetry, you'll need to install it. You can do this by running the following command:

curl -sSL https://install.python-poetry.org | python -

Configuring Poetry Settings

Once installed, you can configure Poetry settings, such as the default Python version or the location of virtual environments, using the poetry config command. For example, to set the default Python version, you can run:

poetry config virtualenvs.python /usr/bin/python3

Understanding the pyproject.toml File

The pyproject.toml file is a central configuration file used by Poetry to manage the project's settings and dependencies. Here's a brief overview of its main sections:

  • [tool.poetry]: This section contains metadata about the project, such as the name, version, description, authors, and more.

  • [tool.poetry.dependencies]: This section lists the project's dependencies. You can specify the required packages and their versions here.

  • [tool.poetry.dev-dependencies]: This section lists the development dependencies, which are only needed for development and testing.

  • [build-system]: This section defines the build system used by the project, typically specifying Poetry itself.

Here's an example of what a pyproject.toml file might look like:

[tool.poetry]
name = "my_project"
version = "0.1.0"
description = "A simple project"
authors = ["Your Name <youremail@example.com>"]

[tool.poetry.dependencies]
python = "^3.10"
requests = "^2.25"

[tool.poetry.dev-dependencies]
pytest = "^6.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

This file is automatically created when you initialize a new project with Poetry, and you can modify it manually or use Poetry commands like poetry add to update the dependencies.

Understanding the pyproject.toml file is key to working with Poetry, as it provides a clear and concise way to manage your project's configuration and dependencies.

Creating a New Project with Poetry

Initializing a New Project

Creating a new project with Poetry is a straightforward process. You can use the poetry new command followed by the name of your project to create a new directory with the necessary structure:

poetry new my_project

This command will create a new directory called my_project with the following structure:

my_project/
├── pyproject.toml
├── README.md
├── my_project/
│   └── __init__.py
└── tests/
    └── __init__.py

The pyproject.toml file is automatically generated and contains the basic configuration and dependencies for your project.

Adding and Managing Dependencies

Once your project is initialized, you can add dependencies using the poetry add command. For example, to add the requests library, you can run:

cd my_project
poetry add requests

This command will update the pyproject.toml file and the poetry.lock file. This file locks the versions of your dependencies, ensuring that every user of your project gets the same versions of the dependencies.

The poetry.lock file is crucial for maintaining consistency across different environments. It ensures that the exact versions of the dependencies are used every time the project is built, preventing unexpected changes or conflicts.

You can also specify development dependencies using the --dev flag. These are dependencies that are only needed during development and testing:

poetry add pytest --dev

If you want to update a specific package or all packages to their latest versions, you can use the poetry update command:

  • To update a specific package:

    poetry update requests
  • To update all packages:

    poetry update

This command will update the specified packages to their latest versions, considering the constraints defined in pyproject.toml, and update the poetry.lock file accordingly.

If you no longer need a dependency, you can remove it using the poetry remove command:

poetry remove requests

This command will remove the requests package from your project and update both the pyproject.toml and poetry.lock files.

Managing the Project

Poetry provides several other commands to help you manage your project:

  • poetry install: Installs the project's dependencies as specified in the poetry.lock file.
  • poetry build: Builds the project package.
  • poetry publish: Publishes the package to a package repository like PyPI.
  • poetry run: Executes commands in the virtual environment where the project's dependencies are installed.

By utilizing these commands, you can efficiently manage your project, ensuring that it has the correct dependencies, and build and distribute it as needed.

Semantic Versioning

When specifying dependencies, it's a good practice to use semantic versioning. This allows you to define a range of acceptable versions, giving you flexibility while maintaining compatibility.

Semantic versioning is a versioning scheme that follows a specific format: MAJOR.MINOR.PATCH. Each part has a specific meaning:

  • MAJOR: Indicates incompatible changes that require user intervention.
  • MINOR: Adds new features in a backward-compatible manner.
  • PATCH: Includes backward-compatible bug fixes.

When specifying dependencies in Poetry, you can use semantic versioning to define a range of acceptable versions. This allows you to benefit from updates without risking compatibility issues.

Here's how you can use semantic versioning in Poetry:

  • Caret Requirements (^): This allows updates that do not modify the left-most non-zero digit. For example, ^2.3.4 allows versions up to 3.0.0, but not including 3.0.0.

    [dependencies]
    requests = "^2.25"
  • Tilde Requirements (~): This allows updates that do not modify the specified digits. For example, ~2.3.4 allows versions up to 2.4.0, but not including 2.4.0.

    [dependencies]
    flask = "~1.1.2"
  • Exact Version: You can specify an exact version if you want to lock the dependency to a specific release.

    [dependencies]
    numpy = "1.20.0"
  • Wildcard Requirements (*): While it's possible to use a wildcard to accept any version, this is generally discouraged as it can lead to unexpected updates that might break your project.

Using semantic versioning in your pyproject.toml file provides flexibility in receiving updates while maintaining control over compatibility. It helps ensure that your project stays up to date with the latest features and fixes without risking unexpected behavior due to incompatible changes. By understanding and utilizing semantic versioning, you can create a more robust and maintainable project.

Working with Virtual Environments

Virtual environments are isolated environments where you can install dependencies without affecting other projects or the system's Python installation. Poetry automatically manages virtual environments for your projects, making it easier to handle dependencies and ensure that your project has exactly what it needs.

Understanding Virtual Environments

A virtual environment is like a self-contained Python installation. It allows you to install packages and dependencies that are isolated from the global Python environment. This isolation ensures that different projects on the same system do not interfere with each other, providing a consistent and controlled development environment.

Creating and Managing Virtual Environments with Poetry

When you create a new project with Poetry or add dependencies to an existing project, Poetry automatically creates a virtual environment for that project. You don't have to worry about creating or activating the virtual environment manually; Poetry takes care of it for you.

You can check the details of the virtual environment associated with your project by running:

poetry env info

This command will display information about the virtual environment, including the path and the Python version being used.

Activating and Deactivating Virtual Environments

While Poetry automatically handles the activation of virtual environments when running commands like poetry run, you may want to activate the virtual environment manually to run Python scripts or other commands within that environment.

To activate the virtual environment, you can use:

poetry shell

This command will start a new shell session with the virtual environment activated. You'll notice that your command prompt changes to include the name of the virtual environment.

To deactivate the virtual environment and return to your global Python environment, simply exit the shell session by typing exit.

Managing Multiple Virtual Environments

Poetry also allows you to manage multiple virtual environments for different Python versions or different sets of dependencies. You can list all virtual environments associated with a project by running:

poetry env list

And you can remove a virtual environment with:

poetry env remove python-version

Replace python-version with the specific Python version of the virtual environment you want to remove.

Working with virtual environments is an essential aspect of Python development, and Poetry makes this process seamless and straightforward. By automatically handling the creation and management of virtual environments, Poetry allows you to focus on your code without worrying about dependency conflicts or system-wide settings. Whether you're working on a single project or juggling multiple projects with different requirements, Poetry's virtual environment management provides a robust and flexible solution.

Poetry Best Practices

Poetry is a powerful tool for managing Python projects, and following best practices can help you make the most of it. Here are some guidelines to effectively use Poetry:

1. Keep Dependencies Up to Date

Regularly update your dependencies to benefit from bug fixes, performance improvements, and new features. Use the poetry update command to update specific packages or all packages. In addition, periodically review your project's dependencies and remove any that are no longer needed. This helps keep your project clean and reduces potential security risks.

2. Lock Dependencies with poetry.lock

Always commit the poetry.lock file to your version control system. This ensures that everyone working on the project uses the same versions of the dependencies, leading to consistent behavior across different environments.

3. Manage Development Dependencies Separately

If you have dependencies that are only needed during development (e.g., testing frameworks), add them as development dependencies using the --dev flag:

poetry add --dev pytest

4. Utilize Virtual Environments

Use Poetry's virtual environments to isolate your project's dependencies from the global Python environment. This helps prevent conflicts between different projects and makes it easier to manage dependencies.

5. Avoid Wildcard Dependencies

Avoid using wildcard (*) dependencies, as they can lead to unexpected updates that might break your project. Instead, specify a version range that you know is compatible with your project.

Project: Create a Poetry Project for Displaying Random Quotes

In this project, you'll create a Poetry project named random_quote that displays random quotes using the Turtle graphics library and the requests library to fetch quotes from an API.

Step 1: Create a New Project with Poetry

Navigate to where you want the project directory to reside and then run:

poetry new random_quote

This will create a directory structure that should look like:

random_quote/
├── pyproject.toml
├── README.md
├── random_quote/
│   └── __init__.py
└── tests/
    └── __init__.py

Change your current directory to the random_quote folder. This directory that contains the pyproject.toml file is considered your top level project directory.

Step 2: Add Dependencies

Next, add the requests library as a dependency:

poetry add requests

Step 3: Create the Python Script

The random_quote directory inside your root project folder is where all your program source code will reside. Navigate into that folder and create a new Python file named main.py that contains the following code:

import turtle
import requests

def main():
    # Make a GET request to the dummyJSON endpoint and parse out the quote and author
    response = requests.get('https://dummyjson.com/quotes/random')
    data = response.json()
    quote = data['quote']
    author = data['author']

    # Create a new turtle screen and set its background color
    screen = turtle.Screen()
    screen.bgcolor("lightyellow")

    # Initialize a turtle object
    t = turtle.Turtle()
    t.hideturtle()

    # Position the turtle and display the quote
    t.penup()
    t.goto(0, 50)  # Position the quote
    t.write(quote, align="center", font=("Arial", 16, "italic"))

    # Position the turtle and display the author
    t.goto(0, -50)  # Position the author
    t.write(f"- {author}", align="center", font=("Arial", 14, "bold"))

    # Wait until the window is closed
    turtle.done()

if __name__ == '__main__':
    main()

At this point, your directory structure should look like the following:

random_quote/
├── pyproject.toml
├── README.md
├── random_quote/
│   └── __init__.py
│   └── main.py
└── tests/
    └── __init__.py

Step 4: Configure the Project to Run with Poetry

Back in the root project folder, open the pyproject.toml file and add a [tool.poetry.scripts] section to define a custom script that runs your program:

[tool.poetry.scripts]
random_quote = 'random_quote.main:main'

The value 'random_quote.main:main' is used to define the entry point for the script. Here's what each part means:

  • random_quote: This refers to the top-level package or directory containing your Python code. In your directory structure, random_quote is the name of the folder containing the main.py file.

  • .main: This part refers to the specific Python module (file) within the package where the entry point function is defined. In this case, it's the main.py file.

  • :main: After the colon :, you specify the name of the function that will be called when the script is run. In this case, it's the main function within the main.py file.

So, the full value 'random_quote.main:main' tells Poetry to look inside the random_quote package, find the main.py module, and call the main function within that module when the script is run.

Step 5: Build and Test the Project

Build your project:

poetry install

Run your project using Poetry:

poetry run random_quote

This command will execute the random_quote script, displaying a random quote on the screen.

In this unit, you've gained some experience managing Python projects with Poetry, handling dependencies and working with virtual environments. These skills are essential for modern Python development and will help you create robust and maintainable code.

In the next unit, we'll shift back to the Turtle graphics library and explore some of its advanced functionality that will help us build our game in the final unit.