Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
342: Continuous Integration for a Python Test Suite
Up until now, you've been running your tests manually. You write a feature, run pytest, see the green dots, and push to your repository. That works fine for a solo project, but the moment you collaborate with anyone else—or even just move between a laptop and a desktop—you'll realize that "it worked on my machine" is a dangerous phrase. That's where Continuous Integration (CI) comes in. It's basically a robot that runs your tests every single time you push code, ensuring you didn't accidentally break something in the process.
Our Target: A Simple Currency Converter
To keep this concrete, let's imagine we're building a small library called fx_calc that handles currency conversions. I've already got a basic function that takes an amount and a rate, and a corresponding test suite. Here is the structure of the project I'm working with:
fx_calc/
├── fx_calc/
│ └── converter.py
├── tests/
│ └── test_converter.py
└── requirements.txt
The converter.py file is simple, but the test_converter.py file is where the magic happens. I'm using pytest because it's the industry standard for a reason—it's less boilerplate than unittest. Now, I want to make sure that whenever I push a change to GitHub, these tests run automatically.
Automating the Boring Stuff with GitHub Actions
I'm using GitHub Actions for this because it's integrated right into the repo. To get started, I need to create a specific directory structure: .github/workflows/. Inside that, I'll create a file called ci.yml. This YAML file is essentially a recipe that tells GitHub, "Here is the environment I need, and here are the commands I want you to run."
Here is my first attempt at the configuration:
name: Python CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytest
Wait, Why Did the Build Fail?
I pushed the code, felt confident, and then... a red "X". The build failed. I checked the logs, and I saw a classic ImportError: No module named 'fx_calc'.
Here's what happened: I told the CI robot to install the dependencies listed in requirements.txt (which includes pytest), but I forgot that the fx_calc code itself isn't a "dependency" in that file—it's the project I'm currently building. When pytest runs in the GitHub environment, it doesn't automatically know that the root folder is a package it should be looking at.
I've made this mistake a dozen times. I was thinking about the environment in terms of "what libraries do I need?" rather than "how does Python find my local code?".
Getting the Green Checkmark
To fix this, I have two choices: I could mess around with PYTHONPATH, or I could do it the professional way and install my current project in "editable" mode. By adding pip install -e . to my installation step, I tell Python to treat the current directory as an installed package.
I updated the "Install dependencies" section of my ci.yml to look like this:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e .
I pushed the change, waited about 40 seconds, and there it was: the beautiful green checkmark. Now, if I accidentally change a formula in converter.py that breaks my tests, GitHub will scream at me before that code ever makes it into the main branch. That's the peace of mind CI provides.
📋 Practical Task
Implementing a CI Pipeline for a Markdown-to-HTML Parser
You have been handed a small project called md_parse. It contains a function that converts basic Markdown strings to HTML. The project structure is as follows:
md_parse/
├── md_parse/
│ └── parser.py
├── tests/
│ └── test_parser.py
└── requirements.txt
The requirements.txt file already contains pytest. Your task is to create a GitHub Actions workflow file (.github/workflows/ci.yml) that:
- Triggers on every
pushandpull_request. - Uses
ubuntu-latestas the runner. - Sets up Python version
3.11. - Installs the dependencies from
requirements.txt. - Installs the
md_parseproject itself so that the tests can import it. - Executes the test suite using
pytest.
Write the complete YAML configuration for this workflow.
There are no comments for now.