Course Outline ยท Advanced Python ยท 8 Weeks ยท 32 Hours of Instruction
Course Code: PYTHON-102
Prerequisites: Python Fundamentals Level One (or equivalent knowledge โ variables, loops, functions, OOP, file handling, basic APIs)
Duration: 8 Weeks (32 Hours of Instruction)
Level: Intermediate
Target Audience: Students who have completed Level One and want to take their Python skills to the next level, building real-world applications and mastering advanced concepts.
Python Fundamentals Level Two is the next step in your Python journey. This course takes you beyond the basics and into the world of web development with Flask, data science with Pandas and NumPy, data visualization with Matplotlib, automation, advanced API integration, and professional deployment practices.
You will build real-world projects including a web application with a database, a data analysis dashboard, an automated script, and a deployable API. By the end of this course, you will be a well-rounded Python developer ready for the job market or your own projects.
By the end of this course, you will be able to:
This course is divided into 8 Core Modules, each focusing on a major area of Python development. Each module includes hands-on projects, assignments, and quizzes.
Week 1
url_for() and redirect().Build a Personal Greeting App: A Flask app that greets users by name, with a styled home page and a form.
Week 2
werkzeug.security.Build a To-Do List App with Users: A Flask app where users can register, log in, and manage their own to-do lists stored in a database.
Week 3
head(), info(), describe().dropna(), fillna()).Analyze a Real Dataset: Load a public dataset (e.g., Nigerian elections, COVID-19, or sales data), explore it, clean it, and generate summary statistics.
Week 4
plt.plot(), plt.subplots().plt.savefig()).Build a Data Dashboard: Create a dashboard with 3โ5 charts that tell a story about a dataset (e.g., sales trends, population growth, or market analysis).
Week 5
schedule and time.smtplib.argparse.Build an Automated File Organizer: A script that watches a folder and automatically organizes files into subfolders based on file type or name patterns.
Week 6
requests โ advanced usage (headers, timeouts, sessions).BeautifulSoup and Scrapy.Build a Price Tracking API: Build an API that scrapes product prices from e-commerce sites and exposes them via a RESTful endpoint.
Week 7
unittest and pytest.pdb, logging, and print debugging.flake8, black, mypy.Test and Document a Flask App: Take a previous Flask project, add comprehensive unit tests, and write clear documentation.
Week 8
gunicorn for production serving.Build a Complete Web Application: A full-stack Flask application with user authentication, a database, data visualization, and deployment. The app should solve a real-world problem (e.g., a blog, a dashboard, a booking system). Students present their projects and get feedback.
Total: 100%
Upon successful completion of this course, participants will:
Python Fundamentals Level Two is your gateway to becoming a professional Python developer. You will learn the skills that are in high demand in the tech industry โ web development, data science, automation, and more. You will also build a portfolio that showcases your abilities to employers and clients.
Whether you want to build your own apps, analyze data, automate tasks, or launch a career in tech, this course will give you the tools and confidence to succeed. We look forward to seeing you in class!
๐ Start Your Journey to Python Mastery Today! ๐
Welcome to Level Two, young coder! ๐ You have mastered the basics of Python โ variables, loops, functions, OOP, file handling, and even APIs. Now, it is time to take your skills to the next level by building web applications.
Have you ever wondered how websites like Jumia, Instagram, or your favourite blog work? They are all built using web technologies. In this module, you will learn how to build your own web applications using Flask, a lightweight Python web framework that is perfect for beginners.
Think of Flask as a magical bridge ๐ between your Python code and the web. It handles all the complex parts of web communication so you can focus on building cool features. By the end of this module, you will have built your very own web application that you can share with friends and family!
Let us begin this exciting journey into web development! ๐
By the end of this module, you will be able to:
Ada loved to learn new things. She had just finished Python Level One and was eager to build something her friends could actually use. She thought, "My friends always ask me to help them with their homework. I wish I had a website where they could just enter their questions and get answers!"
Her mentor, Mr. Obi, said, "Ada, that is a fantastic idea! You can build a web application using Flask. It is a Python framework that makes web development easy. Let us start simple โ build a greeting app where users enter their name and get a personalized welcome message."
Ada was excited. She set up Flask on her computer, created a route for the home page, and added a form where users could type their names. She learned how to render HTML templates and pass data to them. She even added some CSS to make it look beautiful.
"Now my friends can visit my website and get a greeting anytime!" Ada said. She shared the link with her friends, and they loved it. Ada had built her first web application. And now, you will build yours too! ๐
Definition: A web framework is a collection of tools and libraries that helps you build web applications more easily.
Why it is important: Building a web application from scratch is very complex. A web framework handles the common tasks โ like routing, handling requests, and managing sessions โ so you can focus on what makes your app special.
Simple explanation: Imagine you are building a house. Instead of cutting down trees and making your own bricks, you buy pre-made materials from a shop. A web framework is like those materials โ it gives you the building blocks you need.
Real-life example: Flask and Django are popular Python web frameworks. React and Angular are popular front-end frameworks.
School example: Your teacher gives you a template for your project report so you only have to fill in your content.
Home example: You use a recipe book instead of inventing your own recipes from scratch.
Nigerian example: A developer in Lagos uses Flask to build a website for a local business instead of writing everything from scratch.
Illustration:
WEB FRAMEWORK CONCEPT
+-------------------------------------------------+
| Your Python code โ Flask โ Web application |
| (You write routes, (Flask handles |
| templates, etc.) HTTP requests, |
| templating, etc.) |
+-------------------------------------------------+
Mini summary: A web framework simplifies web development by providing common tools and structures.
Definition: Flask is a lightweight web framework for Python that is easy to learn and use. It is great for small to medium-sized applications.
Why it is important: Flask gives you the power to build web apps quickly without a lot of complicated code. It is perfect for beginners and prototypes.
Simple explanation: Think of Flask as a tiny, friendly robot ๐ค that helps you turn your Python functions into web pages. You tell it what to do, and it handles all the web stuff for you.
Real-life example: Flask is used by companies like Netflix, Airbnb, and Uber for certain services.
School example: You use a simple calculator instead of doing complex math by hand โ Flask is similarly simple.
Home example: A small toolkit for fixing things around the house โ Flask gives you essential tools without extra weight.
Nigerian example: A startup in Abuja uses Flask to build its MVP (Minimum Viable Product) quickly and cheaply.
Illustration:
FLASK IS LIGHTWEIGHT
+-------------------------------------------------+
| Flask is: |
| - Easy to learn |
| - Flexible |
| - Perfect for beginners |
| - Used in many real-world projects |
| - No complicated setup required |
+-------------------------------------------------+
Mini summary: Flask is a lightweight, beginner-friendly web framework for Python. It gives you essential tools without extra complexity.
Definition: To use Flask, you need to install it and set up a project structure. This ensures your project runs correctly and is easy to manage.
Why it is important: Just like you need a kitchen to cook, you need a Python environment with Flask installed to build web apps. A virtual environment keeps your project's dependencies isolated.
Simple explanation: Imagine you are an artist. You need your own studio with all your paints and brushes organized. A virtual environment is like your studio โ it keeps everything for that project separate from your other projects.
Steps to set up:
python -m venv venvvenv\Scripts\activatesource venv/bin/activatepip install flaskapp.pyReal-life example: A chef organizes their kitchen before cooking โ ingredients, utensils, and tools all in their place.
School example: You organize your notebooks by subject before studying.
Home example: You set up your workspace before starting a project.
Nigerian example: A developer in Enugu sets up a virtual environment for each client project.
Illustration:
FLASK SETUP STEPS
+-------------------------------------------------+
| mkdir my_flask_app |
| cd my_flask_app |
| python -m venv venv |
| source venv/bin/activate (or venv\Scripts\activate) |
| pip install flask |
| touch app.py |
+-------------------------------------------------+
Mini summary: Set up a virtual environment, install
Flask, and create your app.py file to start developing.
Definition: A Flask application is a Python script that defines routes and handles HTTP requests. The simplest app returns a "Hello, World!" message.
Why it is important: This is the "Hello, World!" of web development โ it proves everything works and gives you a starting point.
Simple explanation: You write a function that returns a greeting, and Flask turns it into a web page that anyone can visit.
Code:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, World!"
if __name__ == '__main__':
app.run(debug=True)
To run it:
app.py.python app.py.http://127.0.0.1:5000.Real-life example: A restaurant menu โ the route is like a dish name, and the function is the recipe.
School example: Your teacher says "Good morning" when you enter class โ that is the response.
Home example: Your doorbell rings and you say "Hello!"
Nigerian example: A greeting app that says "Welcome" in Yoruba, Igbo, or Hausa.
Illustration:
FIRST FLASK APP
+-------------------------------------------------+
| Browser โ http://127.0.0.1:5000/ |
| โ |
| Flask matches route '/' to home() |
| โ |
| home() returns "Hello, World!" |
| โ |
| Browser displays "Hello, World!" |
+-------------------------------------------------+
Mini summary: The basic Flask app has a route for the home page and returns a simple greeting. Run it and see it in your browser!
Definition: A route is a URL pattern
(e.g., /about). A view function is the
function that runs when that URL is visited.
Why it is important: Routes define the pages of your website. Each page needs its own route and view function.
Simple explanation: Think of a restaurant menu. Each dish (route) has a recipe (view function) that tells the kitchen how to make it. When a customer orders a dish (visits a URL), the kitchen follows the recipe (view function runs).
How to add multiple routes:
@app.route('/')
def home():
return "Home Page"
@app.route('/about')
def about():
return "About Page"
@app.route('/user/<name>')
def user(name):
return f"Hello, {name}!"
Real-life example: A website with pages for Home, About, Contact, and Products.
School example: Your school has different rooms for different subjects โ each room is a route.
Home example: Different rooms in your house (kitchen, bedroom, living room).
Nigerian example: A local business website with pages for Services, Prices, Testimonials, and Contact.
Illustration:
ROUTES AND VIEW FUNCTIONS
+-------------------------------------------------+
| Route: / โ home() โ "Home Page" |
| Route: /about โ about() โ "About Page" |
| Route: /user/Ada โ user("Ada") โ "Hello, Ada!" |
+-------------------------------------------------+
Mini summary: Routes define URLs, and view functions generate the content for those URLs. Each route is like a page in your website.
Definition: Jinja2 is a templating engine used by Flask. It allows you to write HTML files with dynamic content that can be filled in by Python.
Why it is important: Instead of returning raw strings, you can return beautiful HTML pages. Templates separate design from logic, making your code cleaner and easier to maintain.
Simple explanation: Imagine you have a letter template. You fill in the name and date each time you send it. Jinja2 does that for web pages โ it fills in the blanks with data from your Python code.
How to use:
templates in your project.home.html.render_template() in your view function.Example:
from flask import render_template
@app.route('/')
def home():
return render_template('home.html')
Real-life example: A restaurant prints menus with today's specials filled in โ the menu is the template, the specials are the data.
School example: Your teacher gives you a worksheet template with blanks to fill in.
Home example: You use a greeting card template and write different messages each time.
Nigerian example: A business uses a template for invoices, filling in customer details each time.
Illustration:
TEMPLATE RENDERING
+-------------------------------------------------+
| app.py (Python) โ render_template('home.html') |
| โ |
| templates/home.html (HTML with Jinja2) |
| โ |
| Final HTML sent to browser |
| (All placeholders replaced with data) |
+-------------------------------------------------+
Mini summary: Jinja2 templates allow you to separate
HTML design from Python logic. Use render_template() to
render them.
Definition: You can pass variables from your Python
view function to the template to display dynamic content. This is done
using keyword arguments in render_template().
Why it is important: This is how you make your web pages personal and data-driven. Without this, your pages would be static and boring.
Simple explanation: You have a name tag. You write the person's name on it each time. Passing data to a template is like writing the name on the tag.
How to do it:
@app.route('/greet/<name>')
def greet(name):
return render_template('greet.html', name=name)
Template (greet.html):
<h1>Hello, {{ name }}!</h1>
You can also pass multiple variables:
@app.route('/profile')
def profile():
user = {"name": "Ada", "age": 12, "city": "Lagos"}
return render_template('profile.html', user=user)
Real-life example: A personalised email with the recipient's name and order details.
School example: A report card with the student's name and grades.
Home example: A birthday card with the person's age.
Nigerian example: A banking app shows your account balance and recent transactions when you log in.
Illustration:
PASSING DATA TO TEMPLATE
+-------------------------------------------------+
| Python: render_template('page.html', name=name) |
| โ |
| Template: <h1>Hello, {{ name }}!</h1> |
| โ |
| Output: <h1>Hello, Ada!</h1> |
+-------------------------------------------------+
Mini summary: Pass variables to templates using keyword
arguments in render_template(). Use {{ variable }}
in the template to display them.
Definition: Web forms allow users to submit data to your application. You can handle these submissions using GET (for retrieving data) or POST (for submitting data).
Why it is important: Forms are how users interact with your app โ like logging in, searching, submitting comments, or making orders.
Simple explanation: GET is like asking a question (the data is visible in the URL). POST is like handing in a form (data is hidden in the request body).
How to handle POST:
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
return f"Welcome, {username}!"
return render_template('login.html')
Real-life example: A login page where you submit your username and password.
School example: You fill in a form to register for a club or event.
Home example: You fill in a delivery address on a food delivery website.
Nigerian example: A banking app asks for your PIN using a secure form.
Illustration:
POST REQUEST HANDLING
+-------------------------------------------------+
| GET: user visits /login โ see form |
| POST: user submits form โ process data |
| request.form['username'] โ gets the value |
+-------------------------------------------------+
Mini summary: Use methods=['GET', 'POST']
to handle both. Use request.form to access submitted data
for POST requests.
Definition: Static files are files that do not change, like CSS stylesheets, images, and JavaScript files. They are served directly to the browser.
Why it is important: They make your website look beautiful and interactive. Without them, your site would be plain text.
Simple explanation: Think of a book cover โ it is static but makes the book attractive. Static files are like that for your website.
How to use:
static in your project.url_for('static', filename='style.css').Example:
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">
Real-life example: A website with a logo, custom fonts, and a beautiful colour scheme.
School example: A project report with a cover page and images.
Home example: A photo frame holding a picture.
Nigerian example: A business website with its company logo and brand colours.
Illustration:
STATIC FOLDER STRUCTURE
+-------------------------------------------------+
| project/ |
| โโโ app.py |
| โโโ templates/ |
| โ โโโ home.html |
| โโโ static/ |
| โโโ css/ |
| โ โโโ style.css |
| โโโ images/ |
| โโโ logo.png |
+-------------------------------------------------+
Mini summary: Place static files in a static
folder. Reference them using url_for('static', filename='...').
Definition: A well-organized project structure makes your code maintainable, scalable, and easy for others to understand.
Why it is important: As your project grows, good organization helps you find files quickly and avoid chaos. It also makes collaboration easier.
Simple explanation: Like having different drawers for different types of clothes โ it is easier to find what you need.
Recommended structure:
my_flask_app/
โโโ app.py
โโโ templates/
โ โโโ base.html
โ โโโ index.html
โโโ static/
โ โโโ css/
โ โ โโโ style.css
โ โโโ images/
โโโ venv/
โโโ requirements.txt
โโโ .gitignore
Best practices:
templates folder.static folder.requirements.txt for dependencies..gitignore file for Git.Real-life example: A library organizes books by genre and author for easy finding.
School example: Your folders for each subject.
Home example: Your kitchen drawers for cutlery, pots, and pans.
Nigerian example: A market where different sections sell different goods (e.g., food section, clothing section).
Illustration:
GOOD PROJECT STRUCTURE
+-------------------------------------------------+
| my_app/ |
| โโโ app.py (main logic) |
| โโโ templates/ (HTML files) |
| โโโ static/ (CSS, JS, images) |
| โโโ venv/ (virtual environment) |
| โโโ requirements.txt (dependencies) |
| โโโ .gitignore (what to ignore in Git) |
+-------------------------------------------------+
Mini summary: Organize your project with separate
folders for templates, static files, and environment. Use
requirements.txt to track dependencies.
Definition: Template inheritance allows you to create a base template that contains the common layout (like header and footer), and then extend it in other templates.
Why it is important: It avoids repetition. You write the layout once and reuse it across all pages. This makes maintenance much easier.
Simple explanation: Imagine you have a school uniform. Everyone wears the same base uniform, but each student can have their own tie or badge. The base template is like the uniform, and the child templates add the unique parts.
How to use:
Base template (base.html):
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My App{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header><h1>My App</h1></header>
<main>{% block content %}{% endblock %}</main>
<footer>© 2025 My App</footer>
</body>
</html>
Child template (home.html):
{% extends "base.html" %}
{% block title %}Home{% endblock %}
{% block content %}
<h2>Welcome to My App!</h2>
<p>This is the home page.</p>
{% endblock %}
Real-life example: A restaurant chain has a consistent layout for all its branches, but each branch has its own menu.
School example: Your school's website has the same header and footer on every page, but each page has different content.
Home example: A magazine has the same cover design but different articles inside.
Nigerian example: A business website keeps the same logo and navigation on all pages.
Illustration:
TEMPLATE INHERITANCE
+-------------------------------------------------+
| base.html (layout: header, footer) |
| โ |
| โโโโโโโโดโโโโโโโฌโโโโโโโโโโโโโโโ |
| โ โ โ |
| V V V |
| home.html about.html contact.html |
+-------------------------------------------------+
Mini summary: Use template inheritance to avoid repeating HTML code. Create a base template and extend it in other templates.
Now we will build a complete Flask application that demonstrates everything we have learned.
Scenario: A simple "Greeting App" where a user enters their name and gets a personalized greeting. We will use template inheritance, static files, and form handling.
Code (app.py):
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def home():
return render_template('home.html')
@app.route('/greet', methods=['GET', 'POST'])
def greet():
if request.method == 'POST':
name = request.form.get('name', 'Guest')
return render_template('greet.html', name=name)
return render_template('form.html')
if __name__ == '__main__':
app.run(debug=True)
templates/base.html:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Greeting App{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav><a href="/">Home</a> | <a href="/greet">Greet</a></nav>
<main>{% block content %}{% endblock %}</main>
<footer>© 2025 Greeting App</footer>
</body>
</html>
templates/home.html:
{% extends "base.html" %}
{% block title %}Home{% endblock %}
{% block content %}
<h1>Welcome to the Greeting App!</h1>
<p>Enter your name and get a personalized greeting.</p>
<a href="/greet">Go to Greeting Form</a>
{% endblock %}
templates/form.html:
{% extends "base.html" %}
{% block title %}Greeting Form{% endblock %}
{% block content %}
<h1>Enter Your Name</h1>
<form method="POST">
<label for="name">Name:</label>
<input type="text" id="name" name="name" placeholder="Enter your name">
<button type="submit">Greet Me!</button>
</form>
{% endblock %}
templates/greet.html:
{% extends "base.html" %}
{% block title %}Greeting{% endblock %}
{% block content %}
<h1>Hello, {{ name }}!</h1>
<p>Welcome to the Greeting App.</p>
<a href="/greet">Go back</a>
{% endblock %}
static/css/style.css:
body {
max-width: 600px;
margin: 0 auto;
padding: 20px;
background-}
nav {
margin-bottom: 20px;
padding: 10px;
background-border-radius: 5px;
}
nav a {
text-decoration: none;
}
form {
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
button {
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
footer {
margin-top: 20px;
text-align: center;
}
What we used:
url_for() for links and static filesIllustration:
COMPLETE APP FLOW
+-------------------------------------------------+
| Home โ / โ Shows welcome page |
| Click "Go to Greeting Form" โ /greet (GET) |
| Fill form and submit โ /greet (POST) |
| Shows personalized greeting |
+-------------------------------------------------+
Mini summary: The complete app combines routes, templates, inheritance, static files, and form handling to create a professional-looking web application.
Definition: Deployment means making your app available on the internet so others can access it.
Why it is important: Sharing your app with the world is the final exciting step. It turns your project into something real that others can use.
Simple explanation: You have cooked a delicious meal. Now you want to serve it to your friends. Deployment is like serving your web app to users.
Options for deployment (free):
Steps for PythonAnywhere:
app.py file.yourusername.pythonanywhere.com.Important steps:
requirements.txt file.Real-life example: A business puts its website online for customers to visit.
School example: You present your project to the class.
Home example: You invite friends over to see your new garden.
Nigerian example: A local store opens an online shop so customers can order from anywhere.
Illustration:
DEPLOYMENT PROCESS
+-------------------------------------------------+
| Local development โ Upload to server โ Live! |
| (Your computer) (PythonAnywhere) (Internet) |
+-------------------------------------------------+
Mini summary: Deploy your Flask app using platforms like PythonAnywhere to share it with the world. Follow the steps to upload and configure your app.
| Word | Simple Definition |
|---|---|
| Web Framework | A set of tools for building web applications. |
| Flask | A lightweight web framework for Python. |
| Route | A URL path (e.g., /about). |
| View Function | A function that runs when a route is visited. |
| Template | An HTML file with placeholders for dynamic content. |
| Jinja2 | The templating engine used by Flask. |
| GET | An HTTP method for retrieving data. |
| POST | An HTTP method for submitting data. |
| Static File | A file that does not change, like CSS or images. |
| Template Inheritance | A way to reuse common HTML layout across pages. |
| Deployment | Making your app available on the internet. |
| Virtual Environment | An isolated space for managing dependencies. |
url_for() |
A Flask function that generates URLs for routes and static files. |
render_template() |
A Flask function that renders HTML templates with data. |
url_for() is the safe way to generate
URLs in Flask.
from flask import Flask.app = Flask(__name__).@app.route() decorator with the URL path.app.run(debug=True).templates folder.render_template.render_template('filename.html', var1=value1, var2=value2).{{ var1 }} to display the data.@app.route('/path', methods=['GET', 'POST']).if request.method == 'POST':.request.form['fieldname'].base.html with the common layout.{% block content %}{% endblock %} for replaceable sections.{% extends "base.html" %}.{% block content %}...{% endblock %}.url_for() to generate URLs safely.
| Mistake | How to Avoid It |
|---|---|
| Forgetting to install Flask | Always pip install flask in your virtual
environment. |
Not putting templates in the templates folder |
Flask expects templates to be in a folder named
templates (exact spelling). |
Using render_template without importing it |
Import from flask: from flask import render_template. |
Forgetting request.form for POST data |
Use request.form['field'] or
request.form.get('field'). |
| Not handling GET and POST correctly | Use methods=['GET', 'POST'] and check
request.method. |
Not using url_for for static files |
Always use {{ url_for('static', filename='...') }}
to ensure correct paths. |
| Forgetting to activate the virtual environment | Always activate the environment before installing or running. |
Using debug=True in production |
Only use debug mode during development. Set it to
False in production. |
templates
and static folders.
url_for() for linking to routes
and static files.
debug=True during development for
easier debugging.
requirements.txt to document
dependencies.
FLASK REQUEST-RESPONSE
+-------------------------------------------------+
| Browser sends request to /page |
| โ |
| Flask matches route to view function |
| โ |
| View function runs, maybe renders template |
| โ |
| Flask sends back HTML response |
| โ |
| Browser displays the page |
+-------------------------------------------------+
PROJECT STRUCTURE
+-------------------------------------------------+
| my_flask_app/ |
| โโโ app.py |
| โโโ templates/ |
| โ โโโ base.html |
| โ โโโ home.html |
| โโโ static/ |
| โ โโโ css/ |
| โ โ โโโ style.css |
| โ โโโ images/ |
| โโโ venv/ |
| โโโ requirements.txt |
| โโโ .gitignore |
+-------------------------------------------------+
GET VS POST
+-------------------------------------------------+
| GET: |
| - Data in URL (visible) |
| - Idempotent (safe to repeat) |
| - Used for retrieving data |
| - Can be bookmarked |
+-------------------------------------------------+
| POST: |
| - Data in request body (hidden) |
| - Not idempotent (should not be repeated) |
| - Used for submitting data |
| - Cannot be bookmarked |
+-------------------------------------------------+
TEMPLATE INHERITANCE
+-------------------------------------------------+
| base.html |
| โโโ header |
| โโโ {% block content %}{% endblock %} |
| โโโ footer |
| โ |
| โโโโโโโโดโโโโโโโฌโโโโโโโโโโโโโโโ |
| โ โ โ |
| V V V |
| home.html about.html contact.html |
| (fills (fills (fills |
| content) content) content) |
+-------------------------------------------------+
APP FLOW DIAGRAM
+-------------------------------------------------+
| User visits / โ home() โ home.html |
| โ |
| User clicks "Go to Greeting Form" |
| โ |
| User visits /greet (GET) โ form.html |
| โ |
| User fills form and submits (POST) |
| โ |
| greet() processes POST โ greet.html |
| โ |
| User sees personalized greeting |
+-------------------------------------------------+
| Feature | GET | POST |
|---|---|---|
| Purpose | Retrieve data | Submit data |
| Data location | URL query string | Request body |
| Visibility | Visible in URL | Not visible |
| Bookmarkable | Yes | No |
| Idempotent | Yes | No |
| Data size | Limited (URL length) | Unlimited |
| Use case | Search, pagination | Login, form submission |
| Feature | Flask | Django |
|---|---|---|
| Scope | Micro-framework | Full-stack framework |
| Learning curve | Easy | Steeper |
| Built-in features | Minimal (add as needed) | Admin, ORM, authentication |
| Flexibility | High | Moderate |
| Project size | Small to medium | Large, complex applications |
| Database ORM | SQLAlchemy (add-on) | Built-in |
| Best for | APIs, microservices, beginners | Content-heavy sites, CMS |
Lesson 1 Summary: A web framework simplifies building web applications by providing common tools.
Lesson 2 Summary: Flask is a lightweight, beginner-friendly Python web framework.
Lesson 3 Summary: Set up a virtual environment and install Flask to start developing.
Lesson 4 Summary: The basic Flask app has a route and a view function returning a response.
Lesson 5 Summary: Routes map URLs to view functions. Each route creates a page.
Lesson 6 Summary: Use Jinja2 templates with render_template() to generate HTML.
Lesson 7 Summary: Pass variables to templates using keyword arguments in render_template().
Lesson 8 Summary: Handle GET and POST methods; use request.form for POST data.
Lesson 9 Summary: Static files go in the static folder. Use url_for() to link them.
Lesson 10 Summary: Organize your project with templates, static, and a virtual environment.
Lesson 11 Summary: Template inheritance reuses common layout across pages.
Lesson 12 Summary: The complete app combines routes, templates, inheritance, static files, and forms.
Lesson 13 Summary: Deploy your app using PythonAnywhere or similar platforms to share it online.
Congratulations! You have completed Module One of Python Fundamentals Level Two ๐. You have taken the first step into the exciting world of web development with Flask.
You learned what a web framework is and why Flask is a great choice for beginners. You set up your development environment with a virtual environment and wrote your first Flask application. You learned about routes, view functions, templates, and how to pass data to them.
You handled forms with GET and POST requests, added static files to make your pages look professional, and organized your project correctly. You mastered template inheritance to avoid repeating HTML code. You even deployed your app so others could see it!
These are the foundational skills for building any web application. In the next module, you will dive deeper into Flask โ learning about databases, user authentication, and building more complex apps.
Keep practicing by building your own projects. The more you build, the better you will become. You are now a web developer! ๐
@app.errorhandler() to define custom
error pages. You can also use try-except blocks in your view
functions.
jsonify() to return JSON data.
request.files to handle uploaded files. Make
sure to set enctype="multipart/form-data" in your form.
url_for()?render_template() returns an HTML page. (True / False)templates folder. (True / False)url_for() is used to generate URLs in Flask. (True / False)request object is used to access form data. (True / False)app.run(debug=True) starts the Flask development server. (True / False)python install flask
pip install flask
install flask
flask install
@app.route('/')?
render()
render_template()
template()
html()
request.args.get()
request.form['name']
request.data
request.body
static
templates
public
assets
@app.get()
@app.route()
@app.post()
@app.view()
dependencies.txt
requirements.txt
packages.txt
pip.txt
debug=True in app.run()?
/user/<name>
/user/{name}
/user/%name%
/user:name
static folder
templates folder
views folder
app.py
url_for()
requirements.txt
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. Flask | A. A lightweight Python web framework |
| 2. Route | B. A URL pattern |
| 3. View Function | C. A function that handles a request |
| 4. Template | D. An HTML file with placeholders |
| 5. Jinja2 | E. The templating engine used by Flask |
| 6. GET | F. An HTTP method for retrieving data |
| 7. POST | G. An HTTP method for submitting data |
| 8. Static | H. Folder for CSS, images, etc. |
| 9. Deployment | I. Making your app available online |
| 10. Template Inheritance | J. Reusing common HTML layout |
Answers: 1-A, 2-B, 3-C, 4-D, 5-E, 6-F, 7-G, 8-H, 9-I, 10-J
url_for() in Flask?Scenario 1:
Ada wants to build a simple "Name Saver" app where users can enter their name and it is stored in a list. She wants to display all saved names on a page. What routes and templates would she need? Write the code for the routes and views.
Scenario 2:
Chidi wants to add a CSS file to make his app look beautiful. He has a
file called style.css in a folder called css.
How would he link it in his base template?
Scenario 3:
Zainab wants to deploy her Flask app to PythonAnywhere. She has already created an account. What are the key steps she needs to follow to get her app live?
Activity Title: Build a Simple Calculator Web App
Instructions:
Activity Title: Build a Personal Bio Page
Instructions:
Project Title: Build a Simple To-Do List App
Description:
Create a Flask application for a to-do list. The app should:
This project will reinforce your understanding of routes, forms, and templates.
Assignment Title: Build a Temperature Converter Web App
Instructions:
Challenge Title: Build a Simple Blog with Flask and SQLite
Extend your Flask skills by building a simple blog. The blog should:
posts table (id, title,
content, created_at).This challenge combines web development with database integration. Good luck!
Fill-in-the-Blank Answers:
pip install flaskrender_templatestaticurl_for()render_template()True or False Answers:
Multiple Choice Answers:
static folder and linked using url_for().
Congratulations on completing Module One of Level Two! ๐ You have laid a strong foundation in web development with Flask. In the next module, you will learn how to:
To prepare, review the concepts from this module and practice building small Flask apps. The more you practice, the easier it will be to learn the advanced topics.
Keep coding, keep exploring, and never stop learning. See you in the next module! ๐๐
๐ End of Module One โ Python Fundamentals Level Two ๐
Welcome back, young web developer! ๐ In Module One, you built your first Flask application and learned the basics of routing, templates, and forms. But your app was missing something important โ data persistence and user accounts. In this module, you will learn how to add a database to your Flask app and create a user authentication system.
A database is like a giant, organized filing cabinet ๐ where your app can store information permanently. Without a database, your app would forget everything every time it restarts. With a database, you can save user profiles, blog posts, comments, and much more.
You will also learn how to let users register and log in to your app. This is called user authentication, and it is the foundation of almost every web application โ from social media to online banking.
By the end of this module, you will have built a fully functional web application with a database and user accounts. Let us dive in! ๐
By the end of this module, you will be able to:
werkzeug.security.Ada had built a simple blog using Flask, but anyone could add or delete posts. She wanted her friends to have their own accounts so they could write their own posts and only edit their own content. She needed a database to store user information and a way to handle login and registration.
Her mentor, Mr. Obi, said, "Ada, you need to add a database and authentication. Flask has great extensions for this. You can use Flask-SQLAlchemy to manage the database and Flask-Login to handle user sessions. And for passwords, you will use hashing to keep them secure."
Ada followed his advice. She defined a User model with
fields for username, email, and password_hash. She created routes for
registration and login, with forms to collect user input. She used
flask-login to manage the logged-in user and protect
certain pages.
"Now my blog is a real web application!" Ada said. Her friends could create accounts, log in, and write their own posts. Ada's app was now secure and user-friendly. And you will learn how to build the same system! ๐ก๏ธ
Definition: A database is a structured collection of data that can be easily accessed, managed, and updated.
Why it is important: Without a database, your application cannot remember data between sessions. A database allows you to store user information, posts, comments, and anything else permanently.
Simple explanation: Imagine you have a notebook where you write down your friends' phone numbers. If you lose the notebook, you lose the information. A database is like a safe, digital notebook that never gets lost and can be searched instantly.
Real-life example: A school stores student records in a database. A bank stores customer accounts in a database.
School example: Your teacher uses a register to track attendance โ that is a simple database.
Home example: Your family might keep a list of contacts on a phone โ that is also a database.
Nigerian example: A bank in Lagos stores customer account information in a database.
Illustration:
DATABASE CONCEPT
+-------------------------------------------------+
| Your Flask App |
| โ |
| Database (SQLite, PostgreSQL, etc.) |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
| โ Table: users โ |
| โ โโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโ โ |
| โ โ id โ username โ password โ โ |
| โ โโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโค โ |
| โ โ 1 โ ada โ hashed... โ โ |
| โ โ 2 โ chidi โ hashed... โ โ |
| โ โโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโ โ |
| โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ |
+-------------------------------------------------+
Mini summary: A database stores data permanently so your app can remember information even after it restarts.
Definition: SQLAlchemy is a Python library that provides an ORM (Object-Relational Mapper). An ORM lets you interact with a database using Python objects instead of writing raw SQL queries.
Why it is important: ORMs make database code cleaner, safer, and easier to write. You can think in Python classes instead of SQL tables.
Simple explanation: Imagine you are building a house. Instead of learning how to make bricks and cement, you use pre-made blocks. SQLAlchemy gives you pre-made blocks (Python objects) to build your database.
Real-life example: A developer defines a User
class, and SQLAlchemy automatically creates a users table
in the database.
School example: Your teacher gives you a template (class) to fill in student information; the template is like an ORM model.
Home example: You use a recipe card (class) to store different recipes; each recipe card is like an object.
Nigerian example: A developer uses SQLAlchemy to build a student management system without writing complex SQL queries.
Illustration:
ORM CONCEPT
+-------------------------------------------------+
| Python Class โ SQLAlchemy ORM โ Database |
| (User) (users table) |
| โ |
| user = User(name="Ada") |
| db.session.add(user) |
| db.session.commit() |
| โ SQL: INSERT INTO users (name) VALUES ("Ada") |
+-------------------------------------------------+
Mini summary: SQLAlchemy ORM lets you work with databases using Python classes instead of writing SQL. It makes database code simpler and safer.
Definition: Flask-SQLAlchemy is a Flask extension that adds SQLAlchemy support to Flask. It makes it easy to integrate a database into your Flask app.
Why it is important: Flask-SQLAlchemy handles the connection and session management for you, so you can focus on your models and data operations.
Simple explanation: Think of Flask-SQLAlchemy as a bridge ๐ between your Flask app and the database. It connects them smoothly.
Steps to set up:
pip install flask-sqlalchemySQLAlchemy object.Code example:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///myapp.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# Define models here...
with app.app_context():
db.create_all() # Creates tables
Real-life example: A developer configures the database connection string and initializes the ORM.
School example: You set up a new notebook for a subject and label it clearly.
Home example: You organize a shelf for your books, labeling each section.
Nigerian example: A startup in Abuja sets up a PostgreSQL database for their Flask app.
Illustration:
FLASK-SQLALCHEMY SETUP
+-------------------------------------------------+
| app = Flask(__name__) |
| app.config['SQLALCHEMY_DATABASE_URI'] = '...' |
| db = SQLAlchemy(app) |
| โ |
| db.create_all() โ Creates tables |
+-------------------------------------------------+
Mini summary: Flask-SQLAlchemy connects your Flask app to a database. Configure the URI, initialize the object, and create tables.
Definition: A model is a Python class that represents a database table. Each attribute of the class represents a column in that table.
Why it is important: Models define the structure of your data. They tell SQLAlchemy what tables to create and what columns they have.
Simple explanation: Think of a model as a blueprint for a table. It's like a form that you fill out for each record.
How to define a model:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
def __repr__(self):
return f'<User {self.username}>'
Common column types:
db.Integer โ whole numbersdb.String(length) โ text with a maximum lengthdb.Text โ long textdb.DateTime โ date and timedb.Boolean โ True/False
Real-life example: A school defines a Student
model with columns for name, class, and age.
School example: Your teacher creates a registration form with fields for name, age, and class.
Home example: You have a recipe card with fields for name, ingredients, and instructions.
Nigerian example: A bank defines a Customer
model with account_number, name, and balance.
Illustration:
MODEL TO TABLE
+-------------------------------------------------+
| class User(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| username = db.Column(db.String(80)) |
| email = db.Column(db.String(120)) |
| password_hash = db.Column(db.String(128)) |
+-------------------------------------------------+
| โ Creates table: |
| CREATE TABLE user ( |
| id INTEGER PRIMARY KEY, |
| username VARCHAR(80), |
| email VARCHAR(120), |
| password_hash VARCHAR(128) |
| ); |
+-------------------------------------------------+
Mini summary: Models are Python classes that define database tables. Each attribute is a column. Use built-in column types to specify the data type.
Definition: CRUD stands for Create, Read, Update, Delete โ the four basic operations on data.
Why it is important: These operations let you manage your data: add new records, retrieve them, change them, and remove them.
Simple explanation: Imagine you have a list of contacts. You can add a new contact (Create), see the list (Read), change a phone number (Update), or remove a contact (Delete). These are CRUD operations.
Examples in SQLAlchemy:
# CREATE
new_user = User(username='ada', email='ada@example.com')
db.session.add(new_user)
db.session.commit()
# READ (all users)
users = User.query.all()
# READ (filter by username)
user = User.query.filter_by(username='ada').first()
# UPDATE
user = User.query.get(1)
user.email = 'newemail@example.com'
db.session.commit()
# DELETE
user = User.query.get(1)
db.session.delete(user)
db.session.commit()
Real-life example: An e-commerce site adds a new product (CREATE), lists all products (READ), updates its price (UPDATE), and removes discontinued products (DELETE).
School example: Your teacher adds a new student to the register (CREATE), checks attendance (READ), changes a student's grade (UPDATE), and removes a student who left (DELETE).
Home example: You add a new recipe (CREATE), view your recipes (READ), change an ingredient (UPDATE), and remove a recipe (DELETE).
Nigerian example: A bank adds a new customer (CREATE), checks their balance (READ), updates their address (UPDATE), and closes an account (DELETE).
Illustration:
CRUD OPERATIONS
+-------------------------------------------------+
| C: db.session.add(obj) โ INSERT |
| R: Model.query.all() โ SELECT * |
| U: update attribute โ UPDATE |
| D: db.session.delete(obj) โ DELETE |
| Always commit: db.session.commit() |
+-------------------------------------------------+
Mini summary: CRUD operations are the foundation of data management. SQLAlchemy provides methods to perform them using Python objects.
Definition: User authentication is the process of verifying that a user is who they claim to be. It usually involves a username and password.
Why it is important: Authentication protects your application and its data. It ensures that only authorized users can access certain features, like writing posts, viewing personal information, or making purchases.
Simple explanation: Imagine you have a diary with a lock ๐. Only you and trusted friends have the key. Authentication is like that lock โ it keeps out unwanted visitors.
Real-life example: Online banking requires a username and password to log in. Social media platforms use authentication to protect user accounts.
School example: Your school has a gate with a security guard who checks ID cards before letting people in.
Home example: Your phone has a PIN or fingerprint lock to prevent others from using it.
Nigerian example: A POS machine requires your PIN before allowing a withdrawal.
Illustration:
AUTHENTICATION PROCESS
+-------------------------------------------------+
| User enters username and password |
| โ |
| App checks password hash against stored hash |
| โ |
| If correct โ user is logged in (session created) |
| If incorrect โ error message |
+-------------------------------------------------+
Mini summary: User authentication ensures that only authorized users can access certain parts of your app. It is essential for security and personalization.
Definition: Password hashing converts a plain-text password into a fixed-length string of characters using a mathematical algorithm. It is a one-way process โ you cannot reverse it to get the original password.
Why it is important: Storing passwords in plain text is a huge security risk. If your database is breached, attackers would get all passwords. Hashing protects passwords so even if the database is stolen, attackers cannot easily get the actual passwords.
Simple explanation: Imagine you have a secret recipe. You don't write it down in plain text; you encode it in a way that only you can decode. Hashing is like encoding a password so it cannot be easily read.
How to hash in Flask:
from werkzeug.security import generate_password_hash, check_password_hash
# Hash a password
password_hash = generate_password_hash('mypassword')
# Check a password against the hash
is_correct = check_password_hash(password_hash, 'mypassword')
Real-life example: When you create an account on a website, your password is hashed before being stored in the database.
School example: Your teacher keeps your grades in a locked cabinet, not in plain sight.
Home example: You have a secret code for your diary that only you know.
Nigerian example: A banking app stores your PIN as a hash so that even if the database is hacked, the PIN is not exposed.
Illustration:
PASSWORD HASHING
+-------------------------------------------------+
| Plain password: "mysecret" |
| โ |
| generate_password_hash() |
| โ |
| Hashed: 'scrypt:32768:8:1$...' |
| (Stored in database) |
| โ |
| When user logs in: |
| check_password_hash(hashed, input) โ True/False|
+-------------------------------------------------+
Mini summary: Always hash passwords before storing
them. Use generate_password_hash() and
check_password_hash() from werkzeug.security.
Definition: Registration is the process of creating a new user account. Login is the process of verifying the user's credentials and starting a session.
Why it is important: These routes are the entry points for users to access your application. They are the foundation of user management.
Simple explanation: Think of registration as getting a library card (creating an account). Login is presenting that card to borrow a book (accessing your account).
Example routes:
from flask import render_template, request, redirect, url_for, flash
from werkzeug.security import generate_password_hash
from models import User, db
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
email = request.form['email']
password = request.form['password']
# Check if user already exists
existing_user = User.query.filter_by(username=username).first()
if existing_user:
flash('Username already taken.', 'danger')
return redirect(url_for('register'))
# Create new user
hashed_password = generate_password_hash(password)
new_user = User(username=username, email=email, password_hash=hashed_password)
db.session.add(new_user)
db.session.commit()
flash('Account created! Please log in.', 'success')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password_hash, password):
# Log user in (we'll add session management later)
flash('Logged in successfully!', 'success')
return redirect(url_for('home'))
else:
flash('Invalid username or password.', 'danger')
return render_template('login.html')
Real-life example: A social media site has signup and login pages.
School example: You register for a club by filling out a form, then you log in to see club updates.
Home example: You create an account on a streaming service, then log in to watch movies.
Nigerian example: A fintech app has a signup page where you provide your BVN, email, and password, and a login page to access your dashboard.
Illustration:
REGISTRATION FLOW
+-------------------------------------------------+
| /register (GET) โ Show form |
| /register (POST) โ Validate, hash password, |
| create user, commit, flash |
| redirect to login |
+-------------------------------------------------+
| /login (GET) โ Show form |
| /login (POST) โ Check credentials, |
| if valid โ log in, redirect |
| else โ flash error |
+-------------------------------------------------+
Mini summary: Registration and login routes handle creating and authenticating users. Use hashing for passwords and flash messages for feedback.
Definition: Flask-Login is an extension that manages user sessions. It stores the user's ID in the session cookie and provides convenient methods to access the current user.
Why it is important: Without session management, you would have to manually check credentials on every request. Flask-Login automates this, making it easy to keep users logged in across pages.
Simple explanation: Think of a session as a temporary pass ๐ซ that your app gives to a user after they log in. The pass is valid for a certain time, and the app checks it on each page visit.
How to set up Flask-Login:
pip install flask-loginLoginManager.@login_required decorator to protected routes.login_user() and logout_user().Code example:
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login' # Redirect if not logged in
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['POST'])
def login():
# ... authenticate user ...
if user:
login_user(user)
flash('Logged in successfully.', 'success')
return redirect(url_for('dashboard'))
@app.route('/logout')
@login_required
def logout():
logout_user()
flash('Logged out.', 'info')
return redirect(url_for('home'))
@app.route('/dashboard')
@login_required
def dashboard():
return f'Hello, {current_user.username}!'
Real-life example: After you log in to a website, you stay logged in as you navigate through pages until you log out or the session expires.
School example: Your school ID card lets you enter the building and stay in until you leave.
Home example: Your phone stays unlocked until you manually lock it or it times out.
Nigerian example: A banking app keeps you logged in for a period of time until you log out or the session expires.
Illustration:
FLASK-LOGIN FLOW
+-------------------------------------------------+
| 1. User logs in โ login_user(user) |
| 2. Flask-Login stores user ID in session |
| 3. On each request, load_user() gets the user |
| 4. @login_required protects routes |
| 5. Logout โ logout_user() clears session |
+-------------------------------------------------+
Mini summary: Flask-Login simplifies session management. It provides decorators to protect routes and functions to log users in and out.
Definition: Flash messages are one-time notifications that appear on the next page after an action (like registration or login). They are used to give feedback to the user.
Why it is important: Flash messages improve user experience by informing users about the result of their actions. They are also easy to implement in Flask.
Simple explanation: Imagine you submit a form, and a message pops up saying "Success!" or "Error: check your input." That is a flash message.
How to use:
from flask import flash
flash('Account created!', 'success')
flash('Invalid username or password.', 'danger')
# In template, use:
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
Real-life example: After you reset your password, a message says "Password reset email sent."
School example: Your teacher writes "Well done!" on your test paper โ that is feedback.
Home example: A message on your phone says "Message sent successfully."
Nigerian example: After a successful transfer, your banking app shows "Transfer successful."
Illustration:
FLASH MESSAGE PROCESS
+-------------------------------------------------+
| Action (e.g., registration) โ flash('msg', 'category') |
| โ |
| Redirect to another page |
| โ |
| Next page displays the message (once) |
+-------------------------------------------------+
Mini summary: Flash messages are one-time notifications
for user feedback. Use flash() to set them and
get_flashed_messages() to display them in templates.
Definition: Flask-WTF integrates WTForms with Flask to provide form validation, CSRF protection, and easier form rendering.
Why it is important: Validating user input is crucial for security and data quality. Flask-WTF makes it easy to define form classes with built-in validators.
Simple explanation: Imagine you have a form that asks for an email address. Flask-WTF can check that the input actually looks like an email, and if not, it shows an error message.
How to use:
pip install flask-wtf
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo, Length
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=80)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Sign Up')
Real-life example: A sign-up form that checks if the email is valid and if the password is strong enough.
School example: A registration form for a club that ensures all required fields are filled.
Home example: A feedback form that validates your email address before submitting.
Nigerian example: A banking app's registration form validates that your BVN has 11 digits.
Illustration:
WTFORM VALIDATION
+-------------------------------------------------+
| Form class with validators |
| โ |
| In route: |
| form = RegistrationForm() |
| if form.validate_on_submit(): |
| # process data |
| else: |
| # show errors in template |
+-------------------------------------------------+
Mini summary: Flask-WTF provides form classes with built-in validators. It simplifies input validation and adds CSRF protection.
Now we will build a complete Flask application with database and user authentication, using all the concepts we have learned.
Scenario: A simple "User Dashboard" app where users can register, log in, and view a personalized dashboard.
Project Structure:
my_auth_app/
โโโ app.py
โโโ models.py
โโโ forms.py
โโโ templates/
โ โโโ base.html
โ โโโ home.html
โ โโโ register.html
โ โโโ login.html
โ โโโ dashboard.html
โโโ static/
โ โโโ style.css
โโโ venv/
โโโ requirements.txt
Code (app.py):
from flask import Flask, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from models import db, User
from forms import RegistrationForm, LoginForm
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
login_manager.login_message_category = 'info'
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/')
def home():
return render_template('home.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = generate_password_hash(form.password.data)
user = User(username=form.username.data, email=form.email.data, password_hash=hashed_password)
db.session.add(user)
db.session.commit()
flash('Your account has been created! You can now log in.', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and check_password_hash(user.password_hash, form.password.data):
login_user(user, remember=form.remember.data)
flash('Login successful!', 'success')
return redirect(url_for('dashboard'))
else:
flash('Login unsuccessful. Please check email and password.', 'danger')
return render_template('login.html', form=form)
@app.route('/logout')
@login_required
def logout():
logout_user()
flash('You have been logged out.', 'info')
return redirect(url_for('home'))
@app.route('/dashboard')
@login_required
def dashboard():
return render_template('dashboard.html')
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True)
models.py:
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
db = SQLAlchemy()
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
def __repr__(self):
return f'<User {self.username}>'
forms.py:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Email, Length, EqualTo
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=80)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Sign Up')
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
remember = BooleanField('Remember Me')
submit = SubmitField('Login')
Templates: (omitted for brevity, but would include
base.html with flash messages, and forms with form.hidden_tag()
and {{ form.field() }})
What we used:
Illustration:
COMPLETE APP FLOW
+-------------------------------------------------+
| Home โ / โ public page |
| Register โ /register โ create user |
| Login โ /login โ authenticate, start session |
| Dashboard โ /dashboard โ protected (requires login) |
| Logout โ /logout โ end session |
+-------------------------------------------------+
Mini summary: The complete app combines Flask-SQLAlchemy, Flask-Login, Werkzeug, and Flask-WTF to create a secure, user-friendly web application with authentication.
Definition: When deploying a Flask app with a database, you need to ensure the database is properly set up on the server and the connection string is correctly configured.
Why it is important: Your local SQLite file won't be available on the server. You need to either use a hosted database or upload the SQLite file and update the URI.
Simple explanation: It's like moving your notebook from your desk to the library. You need to make sure the notebook (database) is in the right place and the librarian (your app) knows where to find it.
Steps for PythonAnywhere:
SQLALCHEMY_DATABASE_URI to point to the server path.db.create_all() (or use a script).SECRET_KEY as an environment variable.Real-life example: A company moves its application from a development server to a production server.
School example: You submit your project to the teacher (deployment) and they run it on their computer.
Home example: You take a photo from your phone and send it to your computer.
Nigerian example: A fintech startup deploys its app to AWS and configures a PostgreSQL database.
Illustration:
DEPLOYMENT WITH DATABASE
+-------------------------------------------------+
| Local: SQLite file on your computer |
| โ |
| Upload files to server |
| โ |
| Server: Update URI path |
| โ |
| Run db.create_all() in the server's Python |
| Set environment variables for SECRET_KEY |
| App goes live! |
+-------------------------------------------------+
Mini summary: When deploying, ensure the database URI is correct and the database exists. Use environment variables for sensitive settings.
| Word | Simple Definition |
|---|---|
| Database | A structured collection of data stored permanently. |
| ORM (Object-Relational Mapper) | A tool that maps Python objects to database tables. |
| SQLAlchemy | A Python library providing ORM for databases. |
| Model | A Python class that represents a database table. |
| CRUD | Create, Read, Update, Delete โ the four basic operations. |
| Authentication | The process of verifying a user's identity. |
| Password Hashing | Converting a password into a secure, irreversible string. |
| Session | A temporary storage for user data between requests. |
| Flask-Login | An extension that manages user sessions in Flask. |
| Flash Message | A one-time notification for user feedback. |
| Form Validation | Checking user input for correctness and security. |
| CSRF | Cross-Site Request Forgery โ a security attack prevented by tokens. |
@login_required.
pip install flask-sqlalchemy.SQLAlchemy and initialize it with your app.db.Model.db.create_all() inside the app context.pip install flask-login.LoginManager.@login_required to protected routes.login_user() and logout_user().generate_password_hash() and verify with check_password_hash().pip install flask-wtf.FlaskForm.validate_on_submit().form.hidden_tag() and form.field().db.Model.
db.session.add(), db.session.commit(),
and db.session.delete().
generate_password_hash() and
check_password_hash().
login_user(), logout_user(), and
@login_required.
flash() and get_flashed_messages().
| Mistake | How to Avoid It |
|---|---|
Forgetting to import db in models and forms |
Always import db from the module where it is
defined. |
Not calling db.create_all() before running |
Run db.create_all() once to create tables. |
| Storing plain-text passwords | Always hash passwords with werkzeug.security. |
Forgetting to set the login_view on
LoginManager |
Set login_manager.login_view = 'login' to
redirect unauthenticated users. |
Not using form.hidden_tag() in templates |
Always include form.hidden_tag() for CSRF
protection. |
| Not validating input before saving to database | Always use Flask-WTF validators or manual checks. |
| Hardcoding secret key | Use environment variables for SECRET_KEY in
production. |
| Forgetting to commit after changes | Always call db.session.commit() after
modifications. |
@login_required to protect routes
that require authentication.
first()
instead of all() when you only need one record.
TABLE: users
+-------------------------------------------------+
| id | INTEGER PRIMARY KEY AUTOINCREMENT |
| username| VARCHAR(80) NOT NULL UNIQUE |
| email | VARCHAR(120) NOT NULL UNIQUE |
| password| VARCHAR(128) NOT NULL |
+-------------------------------------------------+
ORM MAPPING
+-------------------------------------------------+
| Python Class โ SQLAlchemy โ Table |
| User ORM users |
| (id, name) (id, name) |
+-------------------------------------------------+
AUTHENTICATION FLOW
+-------------------------------------------------+
| 1. User submits login form (POST /login) |
| 2. App queries database for user by email |
| 3. If user exists, check password hash |
| 4. If correct, create session (login_user) |
| 5. Redirect to dashboard |
| 6. On subsequent requests, load_user() checks |
| session and retrieves user object |
| 7. @login_required protects routes |
| 8. Logout destroys session (logout_user) |
+-------------------------------------------------+
FLASH MESSAGE CYCLE
+-------------------------------------------------+
| Route: flash('msg', 'category') |
| โ |
| Redirect to another page |
| โ |
| Template: get_flashed_messages() displays msg |
| โ |
| Message removed from session (shown only once) |
+-------------------------------------------------+
| Feature | SQLite | PostgreSQL |
|---|---|---|
| Serverless | Yes | No (client-server) |
| Setup complexity | Very simple (built-in) | More complex |
| Data size | Small to medium | Large |
| Concurrency | Limited (one writer) | High |
| Use case | Development, small apps | Production, large apps |
| Algorithm | Security | Speed | Usage |
|---|---|---|---|
| MD5 | Weak (cracked) | Fast | Not recommended |
| SHA-1 | Weak (collisions) | Fast | Not recommended |
| bcrypt | Strong | Slow | Recommended |
| scrypt | Strong | Slow | Recommended |
| PBKDF2 | Strong | Moderate | Used by werkzeug |
Lesson 1 Summary: Databases store data permanently; apps need them to remember information.
Lesson 2 Summary: SQLAlchemy ORM maps Python classes to database tables, making database code simpler.
Lesson 3 Summary: Flask-SQLAlchemy integrates SQLAlchemy into Flask. Configure the URI and create tables.
Lesson 4 Summary: Models are Python classes that define table structures. Use column types to specify data.
Lesson 5 Summary: CRUD operations are Create, Read, Update, Delete. Use db.session methods.
Lesson 6 Summary: User authentication verifies identity and protects sensitive areas.
Lesson 7 Summary: Password hashing secures passwords. Use werkzeug.security utilities.
Lesson 8 Summary: Registration and login routes handle account creation and authentication.
Lesson 9 Summary: Flask-Login manages sessions with login_user(), logout_user(), and @login_required.
Lesson 10 Summary: Flash messages give one-time feedback to users.
Lesson 11 Summary: Flask-WTF provides forms with validation and CSRF protection.
Lesson 12 Summary: Combining all components creates a secure, functional authentication app.
Lesson 13 Summary: Deployment requires updating the database URI and using environment variables.
Congratulations! You have completed Module Two of Python Fundamentals Level Two ๐. You have added two essential features to your Flask toolkit: databases and user authentication.
You learned how to use Flask-SQLAlchemy to define
models and perform CRUD operations. You now understand the importance of
password hashing and how to implement it securely with
werkzeug.security. You set up Flask-Login
to manage user sessions and protect routes. You also added
flash messages and form validation
with Flask-WTF.
You built a complete authentication app that allows users to register, log in, and access a personalized dashboard. This is the foundation of almost every web application you will ever build.
In the next module, you will learn how to extend your application with more advanced features like email confirmation, password reset, and user roles. You will also learn how to use Flask-Migrate for database schema changes.
Keep practicing by adding new features to your app. The skills you have learned here are in high demand and will serve you well in your programming career. Well done! ๐๐
current_user.is_authenticated in API routes.
User model and run a
migration (or recreate the table if in development).
db.create_all()?
db.session.commit()?werkzeug.security.
@login_required protects routes from unauthenticated users. (True / False)db.session.commit() saves changes to the database. (True / False)db.create_all() drops existing tables and recreates them. (True / False)hash_password()
generate_password_hash()
encrypt_password()
secure_password()
@login_protected
@auth_required
@login_required
@secure_route
login()
log_in_user()
login_user()
user_login()
db.session.commit()?
db.session.remove()
db.session.delete()
db.session.destroy()
db.session.clear()
db.Integer
db.String
db.Text
db.Boolean
db.Password is not a standard column type.)
db.create_all()?
@login_required do?
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. SQLAlchemy | A. Manages user sessions |
| 2. Flask-Login | B. ORM for Python |
| 3. Flask-WTF | C. Password hashing |
| 4. werkzeug.security | D. Form validation |
| 5. Flash message | E. One-time notification |
| 6. CRUD | F. Create, Read, Update, Delete |
Answers: 1-B, 2-A, 3-D, 4-C, 5-E, 6-F
db.session.add() and db.session.commit()?@login_required and how does it work?Scenario 1:
Ada wants to add a "Remember Me" checkbox to her login form so that
users stay logged in for a longer period. How would she modify her login
route and form to implement this? (Hint: use Flask-Login's
remember parameter.)
Scenario 2:
Chidi has a Post model with fields id,
title, content, user_id. He wants
to display all posts by the currently logged-in user on their dashboard.
Write the SQLAlchemy query to fetch these posts.
Scenario 3:
Zainab wants to add a profile page where users can update their email and password. She wants to use a form with validation. Write the route and form code for this feature.
Activity Title: Build a Simple Blog with User Accounts
Instructions:
Activity Title: Build a Personal Diary App
Instructions:
Entry model (id, title,
content, created_at, user_id).
Project Title: Build a User Management System
Description:
Create a Flask application that manages users with roles (admin and regular). The app should:
This project will test your ability to handle different user roles and permissions.
Assignment Title: Build a Product Review System
Instructions:
Challenge Title: Build a RESTful API with Flask and JWT Authentication
Build a RESTful API using Flask that provides endpoints for user registration, login, and a protected resource. Use JWT (JSON Web Tokens) for authentication instead of Flask-Login. The API should:
pyjwt library to generate and verify tokens.This challenge will test your ability to build an API and use token-based authentication, which is widely used in modern web applications.
Fill-in-the-Blank Answers:
generate_password_hash@login_requireddb.session.commit()login_user()logout_user()True or False Answers:
Multiple Choice Answers:
werkzeug.security.
login_user(), logout_user(), and
@login_required.
Congratulations on completing Module Two of Level Two! ๐ You have added databases and authentication to your Flask toolkit. In the next module, you will learn:
To prepare, review the concepts from this module and practice building authentication systems. The more you practice, the easier it will be to add new features.
Keep coding, keep exploring, and never stop learning. See you in the next module! ๐๐
๐ End of Module Two โ Python Fundamentals Level Two ๐
Welcome, data explorer! ๐ You have learned how to build web applications with Flask and manage databases. Now, it is time to unlock the power of data analysis. In today's world, data is everywhere โ from sales figures to social media posts. Being able to analyse and understand data is a superpower.
In this module, you will learn two of the most important Python libraries for data analysis: NumPy (Numerical Python) and Pandas (Panel Data). NumPy provides fast mathematical operations on arrays. Pandas builds on top of NumPy and gives you easy-to-use data structures like DataFrames, which are like spreadsheets in Python.
You will learn how to load data from CSV files, clean and transform it, filter and sort it, group and aggregate it, and even create basic visualizations. By the end of this module, you will be able to take a messy dataset and turn it into meaningful insights.
Think of NumPy and Pandas as your data detective tools ๐. They help you find patterns, uncover secrets, and tell stories with data. Let us begin our data adventure! ๐
By the end of this module, you will be able to:
head(), info(), describe().dropna() and fillna().groupby().apply() and map().Ada's mother ran a small grocery store in Lagos. She kept a notebook with daily sales of different products โ rice, beans, tomatoes, onions, and more. But it was hard to see which products sold best and on which days. Ada wanted to help her mother make better decisions.
"Mummy, I can use Python to analyse your sales data!" Ada said. She typed all the sales numbers into a CSV file. Then she used Pandas to load the data, clean it, and find the average sales per product. She even created a chart showing sales over the week.
"Wow!" her mother said. "Now I know that tomatoes sell most on Fridays and Saturdays. I will buy more tomatoes on those days!" Ada's analysis helped her mother earn more money and reduce waste.
Ada had discovered the power of data analysis. And you will learn how to do the same โ using Python to turn raw data into useful information. Let us dive in! ๐
Definition: NumPy is a library for numerical computing in Python. It provides fast, multidimensional arrays and mathematical functions. Pandas is a library built on top of NumPy that provides easy-to-use data structures and data analysis tools.
Why it is important: These libraries are the foundation of data science in Python. They are used by millions of people for data cleaning, analysis, and visualization.
Simple explanation: Imagine you have a big pile of numbers. NumPy is like a super-fast calculator that can do math with all those numbers at once. Pandas is like a smart spreadsheet that organizes the numbers into rows and columns and lets you slice, dice, and analyse them easily.
Real-life example: A data scientist uses Pandas to analyse sales data and NumPy for complex calculations.
School example: You use a spreadsheet (like Excel) to track your grades; Pandas is like that but in Python.
Home example: You keep a list of your expenses in a notebook; Pandas can help you find patterns.
Nigerian example: A market analyst uses Pandas to analyse vegetable prices across different markets.
Illustration:
NUMPY AND PANDAS
+-------------------------------------------------+
| NumPy: Fast numerical arrays |
| โ |
| Pandas: High-level data structures (DataFrame) |
| โ |
| Data analysis, cleaning, visualization |
+-------------------------------------------------+
Mini summary: NumPy provides fast arrays for mathematical operations; Pandas provides powerful data structures for analysis.
Definition: To use these libraries, you need to install
them using pip.
Why it is important: They are not built into Python, so you have to install them separately.
Simple explanation: Think of NumPy and Pandas as apps you download on your phone. You need to install them before you can use them.
Installation commands:
pip install numpy pandas matplotlib
Real-life example: A developer installs these libraries before starting a data analysis project.
School example: You install a calculator app on your phone before using it.
Home example: You buy a new kitchen tool before cooking a new recipe.
Nigerian example: A data analyst in Abuja installs Pandas to analyse customer data.
Illustration:
INSTALLATION
+-------------------------------------------------+
| pip install numpy pandas matplotlib |
+-------------------------------------------------+
Mini summary: Install NumPy, Pandas, and Matplotlib
using pip to get started with data analysis.
Definition: A NumPy array is a grid of values, all of the same type, that can be efficiently computed. It is like a list, but faster and more powerful.
Why it is important: NumPy arrays are the foundation of many data science operations. They make mathematical operations fast.
Simple explanation: Think of a NumPy array as a bullet train ๐ compared to a regular list (which is like a bicycle). It can handle large amounts of data much faster.
How to create an array:
import numpy as np
# From a list
arr = np.array([1, 2, 3, 4, 5])
# Zeros array
zeros = np.zeros(5) # [0., 0., 0., 0., 0.]
# Ones array # [1., 1., 1.]
# Range of numbers
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
# Random numbers
rand_arr = np.random.rand(3) # random numbers between 0 and 1
Real-life example: A scientist uses NumPy arrays to store temperature readings from sensors.
School example: You have a list of your test scores; you can convert it to a NumPy array to calculate the average.
Home example: You track your daily step count in a NumPy array.
Nigerian example: A farmer stores daily rainfall measurements in a NumPy array.
Illustration:
NUMPY ARRAY
+-------------------------------------------------+
| arr = np.array([1, 2, 3, 4, 5]) |
| arr.shape โ (5,) |
| arr[0] โ 1 |
| arr + 1 โ [2, 3, 4, 5, 6] |
+-------------------------------------------------+
Mini summary: NumPy arrays are fast, multi-dimensional
containers for data. They are created using np.array() and
other functions.
Definition: NumPy allows you to perform mathematical operations on entire arrays at once, without loops.
Why it is important: This makes NumPy much faster and more concise than using regular Python lists.
Simple explanation: It is like being able to add 5 to every number in a list in one go, instead of using a loop.
Examples:
arr = np.array([1, 2, 3, 4, 5])
# Addition
arr + 10 # [11, 12, 13, 14, 15]
# Multiplication
arr * 2 # [2, 4, 6, 8, 10]
# Square
arr ** 2 # [1, 4, 9, 16, 25]
# Sum
np.sum(arr) # 15
# Mean
np.mean(arr) # 3.0
# Max and min
np.max(arr) # 5
np.min(arr) # 1
Real-life example: A financial analyst uses NumPy to calculate daily returns on a portfolio.
School example: You calculate the average of your test
scores using np.mean().
Home example: You calculate total calories from a list of foods.
Nigerian example: A trader calculates total sales from daily sales figures using NumPy.
Illustration:
ARRAY OPERATIONS
+-------------------------------------------------+
| arr = np.array([1, 2, 3, 4, 5]) |
| arr + 1 โ [2, 3, 4, 5, 6] |
| arr * 2 โ [2, 4, 6, 8, 10] |
| np.mean(arr) โ 3.0 |
+-------------------------------------------------+
Mini summary: NumPy arrays support fast element-wise operations and aggregate functions like sum, mean, max, and min.
Definition: A Pandas Series is a one-dimensional labeled array that can hold any data type. It is like a column in a spreadsheet.
Why it is important: Series are the building blocks of DataFrames. They allow you to work with labeled data, which makes analysis easier.
Simple explanation: Imagine you have a list of names and another list of ages. A Series can combine them with labels so you can refer to each item by name.
How to create a Series:
import pandas as pd
# From a list
s = pd.Series([10, 20, 30, 40])
# With custom index (labels)
s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
# From a dictionary
s = pd.Series({'a': 10, 'b': 20, 'c': 30})
print(s['a']) # 10
Real-life example: A Series could represent the daily temperatures for a week, with days as labels.
School example: A Series of student names and their grades.
Home example: A Series of family members' ages.
Nigerian example: A Series of product prices in a market, with product names as labels.
Illustration:
PANDAS SERIES
+-------------------------------------------------+
| s = pd.Series([10, 20, 30], index=['a','b','c']) |
| a 10 |
| b 20 |
| c 30 |
| dtype: int64 |
+-------------------------------------------------+
Mini summary: A Pandas Series is a one-dimensional labeled array, useful for storing and working with data with labels.
Definition: A DataFrame is a two-dimensional labeled data structure with columns of potentially different types. It is like a spreadsheet or a SQL table.
Why it is important: DataFrames are the most common way to work with structured data in Python. They make data manipulation and analysis easy and intuitive.
Simple explanation: Think of a DataFrame as a well-organized table with rows and columns. Each column is a Series, and all columns share the same index (rows).
How to create a DataFrame:
import pandas as pd
# From a dictionary of lists
data = {
'Name': ['Ada', 'Chidi', 'Zainab'],
'Age': [12, 14, 13],
'City': ['Lagos', 'Abuja', 'Kano']
}
df = pd.DataFrame(data)
print(df)
# Name Age City
# 0 Ada 12 Lagos
# 1 Chidi 14 Abuja
# 2 Zainab 13 Kano
Real-life example: A company stores employee data in a DataFrame.
School example: Your teacher keeps student records in a spreadsheet, which is like a DataFrame.
Home example: You keep a budget in a table with columns for Date, Category, Amount.
Nigerian example: A bank stores customer information in a DataFrame.
Illustration:
DATAFRAME STRUCTURE
+-------------------------------------------------+
| Name Age City |
| Ada 12 Lagos |
| Chidi 14 Abuja |
| Zainab 13 Kano |
+-------------------------------------------------+
Mini summary: A DataFrame is a two-dimensional labeled data structure, like a spreadsheet. It is the primary data structure in Pandas.
Definition: CSV (Comma-Separated Values) is a common file format for storing tabular data. Pandas can easily read CSV files into DataFrames.
Why it is important: Most data you will work with comes from CSV files โ from spreadsheets, databases, or web downloads.
Simple explanation: Think of a CSV file as a digital table. Pandas can read that table and put it into a DataFrame so you can analyse it.
How to read a CSV:
df = pd.read_csv('data.csv')
# You can also specify options
df = pd.read_csv('data.csv', header=0, delimiter=',')
Real-life example: A data analyst downloads sales data as a CSV and loads it into Pandas.
School example: Your teacher saves class grades in a CSV file and reads it into Python.
Home example: You export your bank transactions as a CSV and analyse them in Pandas.
Nigerian example: A market researcher loads survey data from a CSV file into Pandas.
Illustration:
CSV TO DATAFRAME
+-------------------------------------------------+
| CSV file: |
| Name,Age,City |
| Ada,12,Lagos |
| Chidi,14,Abuja |
+-------------------------------------------------+
| df = pd.read_csv('file.csv') |
+-------------------------------------------------+
Mini summary: Use pd.read_csv() to load
data from CSV files into a DataFrame for analysis.
Definition: Exploring data means getting a first look at your DataFrame to understand its structure and content.
Why it is important: Before you analyse, you need to know what you are working with. Exploration helps you spot issues like missing values or unexpected data types.
Simple explanation: Imagine you have a new puzzle box. You look at the picture on the box, the number of pieces, and the shapes. That is exploring your data.
Common exploration methods:
# View first 5 rows
df.head()
# View last 5 rows
df.tail()
# Get basic info (column types, non-null count)
df.info()
# Statistical summary
df.describe()
# Shape (rows, columns)
df.shape
# Column names
df.columns
# Data types
df.dtypes
Real-life example: A business analyst checks the first few rows of sales data to see what columns exist.
School example: Your teacher previews a class list before taking attendance.
Home example: You look at your budget spreadsheet to see the categories you have.
Nigerian example: A data analyst uses describe()
to understand the distribution of product prices.
Illustration:
EXPLORING DATA
+-------------------------------------------------+
| df.head() โ first 5 rows |
| df.info() โ column types and null counts |
| df.describe() โ stats for numeric columns |
+-------------------------------------------------+
Mini summary: Use head(), info(),
describe(), and other methods to explore your DataFrame.
Definition: Selecting means choosing specific rows or columns. Filtering means choosing rows that meet a condition.
Why it is important: You often need to work with only a part of your dataโfor example, only sales in a particular region or only students with a certain grade.
Simple explanation: It is like picking apples from a basket โ you only take the ones that are ripe (filtering) or you take only the ones from the top layer (selecting).
Examples:
# Select a single column
df['Name']
# Select multiple columns
df[['Name', 'Age']]
# Select rows by index position (0-4)
df.iloc[0:5]
# Select rows by label
df.loc[0:5]
# Filter rows where Age > 12
df[df['Age'] > 12]
# Filter with multiple conditions
df[(df['Age'] > 12) & (df['City'] == 'Lagos')]
Real-life example: A store manager filters sales data to see only transactions from the Lagos branch.
School example: A teacher selects only the students who scored above 70%.
Home example: You filter your expenses to show only those for food.
Nigerian example: A market researcher filters survey responses by age group.
Illustration:
FILTERING DATA
+-------------------------------------------------+
| df[df['Age'] > 12] |
| Returns rows where Age is greater than 12 |
+-------------------------------------------------+
Mini summary: Use df[column] or
df[['col1','col2']] to select columns. Use boolean
conditions to filter rows.
Definition: Missing data are values that are not
present in your dataset. They are often represented as NaN
(Not a Number).
Why it is important: Missing data can cause problems in analysis. You need to decide how to handle them โ either remove rows with missing values or fill them with something else.
Simple explanation: Imagine you have a survey where some people did not answer a question. You cannot just ignore them; you have to decide what to do with those missing answers.
How to handle:
# Check for missing values
df.isnull().sum()
# Drop rows with any missing values
df.dropna()
# Drop rows where a specific column has missing values
df.dropna(subset=['Age'])
# Fill missing values with a specific value
df.fillna(0)
# Fill missing values with the mean of the column
df['Age'].fillna(df['Age'].mean())
Real-life example: A data analyst drops rows with missing customer information before building a model.
School example: Your teacher ignores blank answers on a test when calculating the average.
Home example: You fill in missing grocery prices with the average price from other stores.
Nigerian example: A market researcher replaces missing product ratings with the average rating.
Illustration:
MISSING DATA
+-------------------------------------------------+
| Before: |
| Name Age City |
| Ada 12 Lagos |
| Chidi NaN Abuja |
| Zainab 13 NaN |
+-------------------------------------------------+
| dropna() โ removes rows 1 and 2 |
| fillna(0) โ fills NaN with 0 |
+-------------------------------------------------+
Mini summary: Use dropna() to remove
missing values or fillna() to fill them with a value.
Definition: Grouping means splitting data into groups based on some criteria, and then applying an aggregation function (like sum, mean, count) to each group.
Why it is important: Grouping is essential for summarizing data. For example, you might want to know the average sales per city or the total spending per category.
Simple explanation: Imagine you have a list of students and their grades. You want to find the average grade for each class. Grouping lets you separate students by class and then calculate the average for each group.
How to use groupby:
# Group by City and calculate mean age
df.groupby('City')['Age'].mean()
# Group by City and get multiple aggregates
df.groupby('City').agg({'Age': ['mean', 'count']})
# Group by multiple columns
df.groupby(['City', 'Gender'])['Age'].mean()
Real-life example: A store groups sales by product category to see which category brings in the most revenue.
School example: A teacher groups students by class to calculate the average score per class.
Home example: You group your expenses by category (food, transport, entertainment) to see where you spend most.
Nigerian example: A market analyst groups product sales by region to see which region has the highest sales.
Illustration:
GROUPBY EXAMPLE
+-------------------------------------------------+
| df.groupby('City')['Age'].mean() |
| City |
| Abuja 14.0 |
| Kano 13.0 |
| Lagos 12.0 |
+-------------------------------------------------+
Mini summary: Use groupby() to split data
into groups and agg() or aggregation functions to summarize
each group.
Definition: Sometimes you need to apply a custom
function to each element, row, or column. Pandas provides apply()
and map() for this.
Why it is important: Not all transformations can be done with built-in methods. You may need to create your own logic.
Simple explanation: Imagine you have a list of temperatures in Celsius, and you want to convert them to Fahrenheit. You need to apply a conversion function to each element.
Examples:
# Apply a function to a column
def double(x):
return x * 2
df['Age_doubled'] = df['Age'].apply(double)
# Using lambda
df['Age_doubled'] = df['Age'].apply(lambda x: x * 2)
# Apply to entire row (axis=1)
df['Total'] = df[['col1', 'col2']].apply(lambda row: row[0] + row[1], axis=1)
# Map values in a column
df['City_code'] = df['City'].map({'Lagos': 'LA', 'Abuja': 'AB', 'Kano': 'KN'})
Real-life example: A data scientist applies a function to normalize data (scale it to a range).
School example: You apply a function to convert percentage grades to letter grades.
Home example: You apply a function to calculate the total cost of items including tax.
Nigerian example: A market analyst applies a function to convert prices from naira to dollars using the current exchange rate.
Illustration:
APPLY FUNCTION
+-------------------------------------------------+
| df['Age'].apply(lambda x: x * 2) |
| Applies the doubling function to each age |
+-------------------------------------------------+
Mini summary: Use apply() and
map() to apply custom functions to your data.
Definition: After analysis, you often want to save the results to a file. You can also create basic plots to visualize your data.
Why it is important: Saving allows you to share your results. Visualization helps you understand patterns and communicate insights.
How to save:
# Save to CSV
df.to_csv('output.csv', index=False)
# Save to Excel
df.to_excel('output.xlsx', index=False)
Basic plotting with Pandas and Matplotlib:
import matplotlib.pyplot as plt
# Line plot
df['Age'].plot()
plt.show()
# Bar chart
df['City'].value_counts().plot(kind='bar')
plt.show()
# Histogram
df['Age'].plot(kind='hist')
plt.show()
# Scatter plot
df.plot.scatter(x='Age', y='Score')
plt.show()
Real-life example: A business analyst creates a bar chart of sales by product category.
School example: You create a histogram of test scores to see the distribution.
Home example: You make a pie chart of your monthly expenses.
Nigerian example: A market researcher plots a bar chart of product popularity across different regions.
Illustration:
VISUALIZATION
+-------------------------------------------------+
| df['Age'].plot(kind='hist') |
| Displays a histogram of ages |
+-------------------------------------------------+
Mini summary: Save DataFrames to CSV or Excel. Use
.plot() with Matplotlib for basic visualizations.
Now we will perform a complete data analysis using Pandas and NumPy on a sample dataset.
Scenario: We have a CSV file containing student grades and demographic information. We will load, explore, clean, analyse, and visualize the data.
Code example:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Load data
df = pd.read_csv('students.csv')
# Explore
print(df.head())
print(df.info())
print(df.describe())
# Handle missing values
df = df.dropna(subset=['Grade'])
# Create a new column: Passing (Grade >= 60)
df['Pass'] = df['Grade'] >= 60
# Group by gender and calculate average grade
avg_grade = df.groupby('Gender')['Grade'].mean()
print(avg_grade)
# Group by gender and count passes
pass_count = df.groupby('Gender')['Pass'].sum()
print(pass_count)
# Visualization
df.groupby('Gender')['Grade'].plot(kind='bar')
plt.title('Average Grade by Gender')
plt.show()
# Save results
df.to_csv('cleaned_students.csv', index=False)
What we used:
Illustration:
COMPLETE ANALYSIS FLOW
+-------------------------------------------------+
| Load CSV โ Explore โ Clean โ Transform โ Analyse โ Visualize โ Save |
+-------------------------------------------------+
Mini summary: The complete analysis combines all the steps: loading, exploring, cleaning, transforming, grouping, and visualizing data to extract insights.
| Word | Simple Definition |
|---|---|
| NumPy | A library for fast numerical operations on arrays. |
| Pandas | A library for data analysis with DataFrames and Series. |
| Array | A grid of values, all of the same type, in NumPy. |
| Series | A one-dimensional labeled array in Pandas. |
| DataFrame | A two-dimensional labeled data structure, like a spreadsheet. |
| CSV | Comma-Separated Values, a common file format for tables. |
| Missing Data | Values that are not present, often represented as NaN. |
| Groupby | A method to split data into groups and apply functions. |
| Aggregation | Summarizing data with functions like sum, mean, count. |
| Visualization | Creating charts and graphs to represent data. |
import pandas as pd.pd.read_csv('filename.csv').header, delimiter, etc., if needed.df = pd.read_csv(...).df['column'] > value.df[df['column'] > value].& (and) or | (or).df.groupby('col').df.groupby('col')['value']..mean(), .sum(), .count(), etc..agg() for multiple aggregations.pd.read_excel().
df.query()
to filter data using a string expression.
pd.read_csv() to load data from CSV files.
head(), info(), and
describe().
dropna() and
fillna().
groupby().
apply().
| Mistake | How to Avoid It |
|---|---|
| Forgetting to install pandas or numpy | Always pip install pandas numpy matplotlib. |
Using df['column'] when column doesn't exist |
Check column names with df.columns. |
| Not handling missing values before analysis | Always check for nulls with df.isnull().sum(). |
Applying functions without axis parameter |
Remember axis=1 for row-wise operations. |
Modifying a slice of a DataFrame without using .copy() |
Use df_copy = df.copy() to avoid warnings. |
| Forgetting to import matplotlib | Always import import matplotlib.pyplot as plt. |
Using value_counts() on non-categorical data |
It works, but use it on categorical columns for best results. |
head(), info(), and describe().
DATAFRAME STRUCTURE
+-------------------------------------------------+
| Index | Name | Age | City |
| 0 | Ada | 12 | Lagos |
| 1 | Chidi | 14 | Abuja |
| 2 | Zainab | 13 | Kano |
+-------------------------------------------------+
DATA ANALYSIS PIPELINE
+-------------------------------------------------+
| Raw Data (CSV) |
| โ |
| Load with pd.read_csv() |
| โ |
| Explore (head, info, describe) |
| โ |
| Clean (dropna, fillna) |
| โ |
| Transform (apply, map) |
| โ |
| Group and Aggregate (groupby) |
| โ |
| Visualize (plot) |
| โ |
| Save (to_csv) |
+-------------------------------------------------+
GROUPBY OPERATION
+-------------------------------------------------+
| df.groupby('City')['Age'].mean() |
| City |
| Lagos 12.0 |
| Abuja 14.0 |
| Kano 13.0 |
+-------------------------------------------------+
MISSING DATA HANDLING
+-------------------------------------------------+
| Before: |
| Name Age City |
| Ada 12 Lagos |
| Chidi NaN Abuja |
| Zainab 13 NaN |
+-------------------------------------------------+
| dropna() โ removes rows 1 and 2 |
| fillna(0) โ fills NaN with 0 |
+-------------------------------------------------+
| Feature | NumPy Array | Python List |
|---|---|---|
| Memory | Less (fixed type) | More (arbitrary types) |
| Speed | Fast (vectorized) | Slower (loops) |
| Element-wise operations | Built-in | Need loops |
| Data types | All elements same type | Any type |
| Use case | Numerical computing | General-purpose |
| Feature | Series | DataFrame |
|---|---|---|
| Dimensions | 1D | 2D |
| Index | Yes | Yes |
| Columns | Single | Multiple |
| Use case | Column of data | Full table |
Lesson 1 Summary: NumPy provides fast numerical arrays; Pandas provides DataFrames for analysis.
Lesson 2 Summary: Install NumPy, Pandas, and Matplotlib with pip.
Lesson 3 Summary: NumPy arrays are fast, multi-dimensional containers.
Lesson 4 Summary: NumPy supports fast element-wise operations and aggregations.
Lesson 5 Summary: Pandas Series are one-dimensional labeled arrays.
Lesson 6 Summary: DataFrames are two-dimensional labeled structures like spreadsheets.
Lesson 7 Summary: Use pd.read_csv() to load data from CSV files.
Lesson 8 Summary: Explore data with head(), info(), describe().
Lesson 9 Summary: Select and filter data using column names and boolean conditions.
Lesson 10 Summary: Handle missing data with dropna() and fillna().
Lesson 11 Summary: Group and aggregate data with groupby().
Lesson 12 Summary: Apply custom functions with apply() and map().
Lesson 13 Summary: Save data to CSV/Excel and create basic plots.
Lesson 14 Summary: The complete analysis flow combines all steps.
Congratulations! You have completed Module Three ๐. You now have a solid foundation in data analysis with Python using NumPy and Pandas.
You learned how to use NumPy for fast numerical operations and Pandas for data manipulation and analysis. You can load data from CSV files, explore and clean it, filter and group it, and even create basic visualizations. You have built a complete data analysis pipeline.
These skills are in high demand across many industries โ from business and finance to healthcare and technology. With this knowledge, you can turn raw data into actionable insights.
In the next module, you will dive deeper into data visualization with Matplotlib and Seaborn, learning how to create professional and informative plots.
Keep practising by finding datasets that interest you and analysing them. The more you practice, the more confident you will become. You are now a data analyst! ๐
pd.read_excel() to read Excel
files.
loc and
iloc?
loc uses labels (index names), while
iloc uses integer positions.
& for AND and | for OR, with
parentheses around each condition.
df.plot() which is built on
Matplotlib.
apply() and
map()?
apply() works on rows or columns; map()
works element-wise on a Series.
df.to_excel('file.xlsx', index=False).
groupby()?df['Age'] > 12 returns a __________ Series.
df.head() shows the last 5 rows. (True / False)df.describe() only works on numeric columns. (True / False)None in Pandas. (True / False)dropna() removes rows with any missing value. (True / False)groupby() is used to filter data. (True / False)apply() can be used to apply a function to a column. (True / False)to_csv() saves a DataFrame to an Excel file. (True / False)df['column'] returns a Series. (True / False)fillna() replaces missing values with a specified value. (True / False)pd.load_csv()
pd.read_csv()
pd.read_file()
pd.import_csv()
df.head() do?
dropna()
fillna()
drop_na()
remove_na()
dropna()
fillna()
replace_na()
na_fill()
group()
groupby()
group_by()
by_group()
df['Age']
df.Age
df(column='Age')
apply()?
df.summary()
df.describe()
df.info()
df.stats()
df.to_csv()
df.save_csv()
df.write_csv()
df.export_csv()
df.info() display?
np.array()
np.create()
np.ndarray()
np.list()
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. NumPy | A. One-dimensional labeled array |
| 2. Pandas | B. Two-dimensional labeled data structure |
| 3. Series | C. Fast numerical arrays |
| 4. DataFrame | D. Data analysis library |
| 5. groupby | E. Splits data into groups |
| 6. dropna | F. Removes missing values |
Answers: 1-C, 2-D, 3-A, 4-B, 5-E, 6-F
describe() method?Scenario 1:
Ada has a CSV file with sales data: Date, Product,
Quantity, Price. She wants to find the total
sales per product and the average price per product. Write the Pandas
code to do this.
Scenario 2:
Chidi has a dataset with missing values in the Age column.
He wants to fill the missing ages with the median age. Write the code.
Scenario 3:
Zainab wants to create a bar chart of the top 5 products by total sales. Write the Pandas and Matplotlib code.
Activity Title: Analyse a Real Dataset
Instructions:
Activity Title: Analyse Your Personal Data
Instructions:
Project Title: Build a Data Analysis Dashboard
Description:
Create a Python script that loads a dataset, performs analysis, and generates a dashboard of charts and statistics. The dashboard should:
Use Pandas, NumPy, and Matplotlib. This project will test your ability to combine all the skills from this module.
Assignment Title: Analyse Student Performance Data
Instructions:
Student_ID,
Gender, Class, Subject,
Score.
Challenge Title: Analyse and Predict Sales
You have a dataset of daily sales for a store over one year. The dataset
includes: Date, Product_ID, Sales,
Discount. Your task is to:
This challenge will test your ability to handle a real-world dataset and extract meaningful insights. Good luck!
Fill-in-the-Blank Answers:
pd.read_csv()df.head()df.describe()NaNdropna()groupby()apply()df.to_csv()True or False Answers:
Multiple Choice Answers:
Excellent work completing Module Three! ๐ You have gained valuable skills in data analysis with Pandas and NumPy. In the next module, you will learn:
To prepare, review the plotting basics from this module and explore some datasets you would like to visualize. The more you practice, the better your visualizations will become.
Keep coding, keep exploring data, and never stop learning. See you in the next module! ๐๐
๐ End of Module Three โ Python Fundamentals Level Two ๐
Welcome, data storyteller! ๐ In Module Three, you learned how to analyse data using Pandas and NumPy. But numbers alone can be hard to understand. That is where data visualization comes in. A picture is worth a thousand words, and a chart is worth a thousand numbers!
In this module, you will learn how to create beautiful, informative charts using two powerful Python libraries: Matplotlib and Seaborn. Matplotlib is the foundation of plotting in Python โ it gives you total control over every aspect of your charts. Seaborn is built on top of Matplotlib and makes it easy to create statistical plots with beautiful default styles.
You will learn how to create line charts, bar charts, histograms, scatter plots, pie charts, and more. You will also learn how to customize your plots โ adding titles, labels, colours, and legends. By the end of this module, you will be able to create professional-looking visualizations that tell compelling stories with data.
Think of Matplotlib as your canvas ๐จ and Seaborn as your set of professional paintbrushes. Together, they let you turn raw data into beautiful art. Let us begin! ๐
By the end of this module, you will be able to:
Ada's mother ran a grocery store, and Ada had been helping her analyse sales data. But her mother found it hard to understand the tables of numbers. "Ada, I see the numbers, but I don't see the story," her mother said.
Ada knew exactly what to do. She used Matplotlib and Seaborn to turn the numbers into beautiful charts. She created a bar chart showing sales by product, a line chart showing sales over time, and a pie chart showing the percentage of each product's sales.
"Now I understand!" her mother exclaimed. "Tomatoes are our best seller, and sales are highest on Saturdays. I can use this to plan better." Ada had not only analysed the data โ she had told a story with it.
Ada's story shows that data visualization is not just about making pretty pictures. It is about making data understandable and actionable. And you will learn how to do the same! ๐จ
Definition: Data visualization is the graphical representation of information and data. It uses visual elements like charts, graphs, and maps to communicate data clearly and effectively.
Why it is important: Humans process visual information much faster than text or numbers. A good chart can reveal patterns, trends, and outliers that are hard to see in a table of numbers.
Simple explanation: Imagine you have a list of your test scores. Looking at the numbers, it is hard to see if you are improving. But if you draw a line chart, you can instantly see the trend โ are your scores going up or down?
Real-life example: Weather forecasts use maps and charts to show temperature and rainfall.
School example: Your teacher shows a bar chart of class test scores to see which subject needs more attention.
Home example: You track your pocket money spending in a pie chart to see where your money goes.
Nigerian example: A business owner uses a chart to see which products sell best in each market.
Illustration:
DATA VISUALIZATION
+-------------------------------------------------+
| Raw Data โ Visualization โ Insights |
| (Numbers) (Charts) (Decisions) |
+-------------------------------------------------+
Mini summary: Data visualization turns numbers into pictures that are easier to understand and analyse.
Definition: Matplotlib is a comprehensive library for creating static, animated, and interactive visualizations in Python.
Why it is important: Matplotlib is the foundation of plotting in Python. It gives you complete control over your charts and is used by millions of data scientists and developers.
Simple explanation: Think of Matplotlib as your paintbrush and canvas ๐จ. It gives you all the tools you need to create any kind of chart you can imagine.
How to install and import:
pip install matplotlib
import matplotlib.pyplot as plt
Real-life example: A scientist uses Matplotlib to create charts for a research paper.
School example: A student creates a chart for a science fair project.
Home example: You create a chart of your monthly expenses.
Nigerian example: A market analyst uses Matplotlib to create price trend charts.
Illustration:
MATPLOTLIB
+-------------------------------------------------+
| import matplotlib.pyplot as plt |
| plt.plot([1, 2, 3], [4, 5, 6]) |
| plt.show() |
+-------------------------------------------------+
Mini summary: Matplotlib is the main plotting library in Python. It provides the foundation for all types of charts.
Definition: A line chart displays information as a series of data points connected by line segments. It is great for showing trends over time.
Why it is important: Line charts help you see how data changes over time โ up, down, or staying flat.
Simple explanation: Imagine you are tracking your height over the years. A line chart would show your growth as an upward line.
How to create a line chart:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]
plt.plot(x, y)
plt.title('My First Line Chart')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.show()
Real-life example: A stock market chart shows price changes over time.
School example: You chart your test scores over the term to see if you are improving.
Home example: You chart your daily step count over a month.
Nigerian example: A farmer charts crop yield over different seasons.
Illustration:
LINE CHART
+-------------------------------------------------+
| plt.plot([1,2,3], [2,4,6]) |
| โ shows a line from (1,2) to (3,6) |
+-------------------------------------------------+
Mini summary: Line charts are used to show trends over
time or continuous data. Use plt.plot() to create one.
Definition: A bar chart represents categorical data with rectangular bars with heights proportional to the values they represent.
Why it is important: Bar charts are great for comparing different categories โ like sales by product, or scores by subject.
Simple explanation: Imagine you have a basket of fruits โ apples, bananas, oranges. A bar chart would show one bar for each fruit, with the height showing how many you have.
How to create a bar chart:
import matplotlib.pyplot as plt
categories = ['Apples', 'Bananas', 'Oranges']
values = [10, 15, 8]
plt.bar(categories, values)
plt.title('Fruit Count')
plt.xlabel('Fruit')
plt.ylabel('Count')
plt.show()
Real-life example: A store manager compares sales of different product categories.
School example: Your teacher shows the number of students in each class.
Home example: You compare your spending on food, transport, and entertainment.
Nigerian example: A market trader compares sales of different vegetables.
Illustration:
BAR CHART
+-------------------------------------------------+
| categories = ['A', 'B', 'C'] |
| values = [10, 15, 8] |
| plt.bar(categories, values) |
+-------------------------------------------------+
Mini summary: Bar charts compare categories. Use
plt.bar() for vertical bars or plt.barh() for
horizontal bars.
Definition: A histogram shows the distribution of a dataset. It groups data into bins and shows the frequency of each bin.
Why it is important: Histograms help you understand how your data is spread out โ where most values are, and if there are any outliers.
Simple explanation: Imagine you have the test scores of your whole class. A histogram would show how many students scored in each range (0-10, 10-20, etc.).
How to create a histogram:
import matplotlib.pyplot as plt
import numpy as np
data = np.random.randn(1000) # 1000 random numbers
plt.hist(data, bins=30)
plt.title('Histogram of Random Data')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
Real-life example: A teacher uses a histogram to see the distribution of test scores.
School example: You look at the distribution of heights in your class.
Home example: You track the distribution of your daily study hours.
Nigerian example: A market analyst examines the distribution of product prices.
Illustration:
HISTOGRAM
+-------------------------------------------------+
| data = [1,2,2,3,3,3,4,4,5] |
| plt.hist(data, bins=5) |
+-------------------------------------------------+
Mini summary: Histograms show the distribution of a
dataset. Use plt.hist() with the bins
parameter.
Definition: A scatter plot uses dots to represent the values of two different variables. It shows the relationship between them.
Why it is important: Scatter plots help you see if two variables are related โ for example, if studying more leads to higher grades.
Simple explanation: Imagine you have a list of your study hours and your test scores. A scatter plot would show each pair as a dot, so you can see if more study hours lead to higher scores.
How to create a scatter plot:
import matplotlib.pyplot as plt
import numpy as np
x = np.random.rand(50) * 10 # 50 random numbers 0-10
y = x + np.random.randn(50) * 2 # y = x + noise
plt.scatter(x, y)
plt.title('Scatter Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.show()
Real-life example: A scientist plots temperature against ice cream sales to see if they are related.
School example: You plot study hours against test scores to see if there is a relationship.
Home example: You plot distance from home against travel time.
Nigerian example: A business plots advertising spend against sales to measure effectiveness.
Illustration:
SCATTER PLOT
+-------------------------------------------------+
| x = [1,2,3,4,5] |
| y = [2,4,5,8,9] |
| plt.scatter(x, y) |
+-------------------------------------------------+
Mini summary: Scatter plots show the relationship
between two variables. Use plt.scatter() to create one.
Definition: A pie chart is a circular statistical graphic divided into slices to illustrate numerical proportion.
Why it is important: Pie charts show parts of a whole. They are great for showing percentages or proportions.
Simple explanation: Imagine a pizza ๐ cut into slices. Each slice represents a portion of the whole. A pie chart shows your data as slices of a pie.
How to create a pie chart:
import matplotlib.pyplot as plt
sizes = [30, 25, 20, 15, 10]
labels = ['Category A', 'Category B', 'Category C', 'Category D', 'Category E']
plt.pie(sizes, labels=labels, autopct='%1.1f%%')
plt.title('Pie Chart')
plt.show()
Real-life example: A budget breakdown shows what percentage of income goes to rent, food, transport, etc.
School example: A pie chart shows the percentage of students in different clubs.
Home example: You show the percentage of your expenses in different categories.
Nigerian example: A business shows the market share of different products.
Illustration:
PIE CHART
+-------------------------------------------------+
| sizes = [30, 25, 20, 15, 10] |
| labels = ['A', 'B', 'C', 'D', 'E'] |
| plt.pie(sizes, labels=labels) |
+-------------------------------------------------+
Mini summary: Pie charts show proportions of a whole.
Use plt.pie() with labels and values.
Definition: Customizing means adding information to make your chart easier to understand โ titles, axis labels, legends, and colours.
Why it is important: A well-labelled chart tells a story. Without labels, your audience may not understand what they are looking at.
Simple explanation: Imagine a map without labels. You would not know where anything is. Labels on a chart are like labels on a map โ they tell you what you are seeing.
How to customize:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y1 = [2, 4, 6, 8, 10]
y2 = [1, 3, 5, 7, 9]
plt.plot(x, y1, label='Line 1', color='blue', linestyle='-')
plt.plot(x, y2, label='Line 2', color='red', linestyle='--')
plt.title('Customized Chart')
plt.xlabel('X-axis Label')
plt.ylabel('Y-axis Label')
plt.legend()
plt.grid(True)
plt.show()
Real-life example: A sales report chart has a title, axis labels, and a legend showing different product lines.
School example: Your science project chart has a title and labeled axes.
Home example: Your budget chart has a title and labels for each category.
Nigerian example: A business dashboard has clear labels for each metric.
Illustration:
CUSTOMIZING PLOTS
+-------------------------------------------------+
| plt.title('Title') |
| plt.xlabel('X Label') |
| plt.ylabel('Y Label') |
| plt.legend() |
| plt.grid(True) |
+-------------------------------------------------+
Mini summary: Use titles, axis labels, legends, and grid lines to make your charts clear and informative.
Definition: Seaborn is a Python data visualization library based on Matplotlib. It provides a high-level interface for drawing statistical graphics.
Why it is important: Seaborn makes it easy to create beautiful, complex statistical plots with less code. It also has built-in themes and colour palettes.
Simple explanation: If Matplotlib is a basic paint set, Seaborn is a professional art kit with pre-mixed colours and advanced tools.
How to install and import:
pip install seaborn
import seaborn as sns
import matplotlib.pyplot as plt
Real-life example: A data scientist uses Seaborn to create publication-quality plots for a report.
School example: A student uses Seaborn to create a beautiful chart for a project.
Home example: You use Seaborn to create a professional budget visualization.
Nigerian example: A business analyst uses Seaborn to create sales dashboard charts.
Illustration:
SEABORN
+-------------------------------------------------+
| import seaborn as sns |
| sns.set_theme() # Apply default theme |
| sns.barplot(x='category', y='value', data=df) |
+-------------------------------------------------+
Mini summary: Seaborn builds on Matplotlib to create beautiful, statistical plots with less code.
Definition: Seaborn provides built-in themes and colour palettes that make your charts look professional with one line of code.
Why it is important: Good styling makes your charts more readable and attractive. Seaborn handles this automatically.
Simple explanation: Think of themes as filters for your chart. Just like you can apply a filter to a photo to make it look better, you can apply a theme to your chart.
How to use:
import seaborn as sns
import matplotlib.pyplot as plt
# Set the theme
sns.set_theme(style='darkgrid') # Other options: 'whitegrid', 'dark', 'white', 'ticks'
# Use a colour palette
sns.set_palette('husl') # Other options: 'viridis', 'coolwarm', 'Set2'
# Or use a specific palette in a plot
sns.barplot(data=df, palette='Blues_d')
Real-life example: A company uses Seaborn's dark theme for a professional-looking dashboard.
School example: A student uses a colour palette to make their project chart more engaging.
Home example: You choose a colour palette that matches your presentation theme.
Nigerian example: A business uses the green and white of the Nigerian flag in their charts.
Illustration:
SEABORN THEMES
+-------------------------------------------------+
| sns.set_theme(style='whitegrid') |
| sns.set_palette('viridis') |
| โ Beautiful charts with one line! |
+-------------------------------------------------+
Mini summary: Seaborn themes and colour palettes make your charts look professional with minimal effort.
Definition: Seaborn provides several statistical plot types that help you understand the distribution and relationships in your data.
Why it is important: These plots go beyond basic charts to show you more about your data โ like the median, quartiles, and outliers.
Common Seaborn plots:
sns.boxplot(x='category', y='value', data=df)
sns.violinplot(x='category', y='value', data=df)
sns.heatmap(df.corr(), annot=True)
sns.pairplot(df)
sns.countplot(x='category', data=df)
Real-life example: A business analyst uses a box plot to see the spread of sales across different regions.
School example: A teacher uses a box plot to show the distribution of test scores.
Home example: You use a pair plot to see relationships between your study hours, scores, and sleep.
Nigerian example: A market researcher uses a heatmap to see correlations between different product sales.
Illustration:
SEABORN STATISTICAL PLOTS
+-------------------------------------------------+
| Box plot: sns.boxplot() |
| Violin plot: sns.violinplot() |
| Heatmap: sns.heatmap() |
| Pair plot: sns.pairplot() |
| Count plot: sns.countplot() |
+-------------------------------------------------+
Mini summary: Seaborn provides advanced statistical plots like box plots, violin plots, heatmaps, and pair plots to help you understand your data better.
Definition: Subplots allow you to display multiple charts in a single figure, arranged in rows and columns.
Why it is important: Subplots help you compare multiple charts side by side, making it easier to see patterns and relationships.
Simple explanation: Imagine you have a wall where you can hang multiple pictures. Subplots let you arrange several charts on one canvas.
How to create subplots:
import matplotlib.pyplot as plt
import numpy as np
# Create a 2x2 grid of subplots
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# Add data to each subplot
axes[0, 0].plot([1, 2, 3], [4, 5, 6])
axes[0, 0].set_title('Line Chart')
axes[0, 1].bar(['A', 'B', 'C'], [10, 15, 8])
axes[0, 1].set_title('Bar Chart')
axes[1, 0].scatter([1, 2, 3], [4, 5, 6])
axes[1, 0].set_title('Scatter Plot')
axes[1, 1].hist(np.random.randn(100), bins=20)
axes[1, 1].set_title('Histogram')
plt.tight_layout()
plt.show()
Real-life example: A dashboard displays multiple charts on one screen.
School example: A project report includes several charts on one page.
Home example: You create a weekly report with several charts.
Nigerian example: A business dashboard shows sales, costs, and profit in one view.
Illustration:
SUBPLOTS
+-------------------------------------------------+
| fig, axes = plt.subplots(2, 2) |
| axes[0,0].plot(...) |
| axes[0,1].bar(...) |
| axes[1,0].scatter(...) |
| axes[1,1].hist(...) |
+-------------------------------------------------+
Mini summary: Subplots let you arrange multiple charts
in one figure. Use plt.subplots() to create a grid.
Definition: Saving a figure means exporting your chart as an image file (PNG, JPEG, SVG, PDF) so you can share it or use it in reports.
Why it is important: You often need to share your visualizations โ in presentations, reports, or on social media.
Simple explanation: It is like taking a photo of your chart so you can show it to others even when you are not at your computer.
How to save:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [4, 5, 6])
plt.title('My Chart')
plt.xlabel('X')
plt.ylabel('Y')
# Save as PNG
plt.savefig('my_chart.png', dpi=300, bbox_inches='tight')
plt.savefig('my_chart.pdf') # Also supports PDF, SVG, etc.
plt.show() # Still displays if you want
Real-life example: A data scientist saves charts to include in a PowerPoint presentation.
School example: A student saves a chart to include in a project report.
Home example: You save a chart of your budget to share with your family.
Nigerian example: A business owner saves a sales chart to send to investors.
Illustration:
SAVING FIGURES
+-------------------------------------------------+
| plt.savefig('filename.png', dpi=300) |
| Saves as PNG with high quality |
| plt.savefig('filename.pdf') |
| Saves as PDF for printing |
+-------------------------------------------------+
Mini summary: Use plt.savefig() to save
your charts as image files for sharing and reports.
Now we will build a complete data visualization dashboard using Matplotlib and Seaborn.
Scenario: We have a dataset of student information (grades, study hours, gender, etc.). We will create multiple charts to explore and present the data.
Code example:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
# Create sample data
np.random.seed(42)
n = 200
data = {
'Gender': np.random.choice(['Male', 'Female'], n),
'Study_Hours': np.random.normal(5, 2, n),
'Grade': np.random.normal(70, 15, n),
'Subject': np.random.choice(['Math', 'Science', 'English', 'History'], n)
}
df = pd.DataFrame(data)
df['Study_Hours'] = df['Study_Hours'].clip(0, 10)
df['Grade'] = df['Grade'].clip(0, 100)
# Set Seaborn theme
sns.set_theme(style='whitegrid')
# Create subplots
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. Histogram of grades
axes[0, 0].hist(df['Grade'], bins=20, color='skyblue', edgecolor='black')
axes[0, 0].set_title('Grade Distribution')
axes[0, 0].set_xlabel('Grade')
axes[0, 0].set_ylabel('Frequency')
# 2. Box plot of grades by gender
sns.boxplot(x='Gender', y='Grade', data=df, ax=axes[0, 1])
axes[0, 1].set_title('Grades by Gender')
# 3. Scatter plot of study hours vs grade
axes[1, 0].scatter(df['Study_Hours'], df['Grade'], alpha=0.6)
axes[1, 0].set_title('Study Hours vs Grade')
axes[1, 0].set_xlabel('Study Hours')
axes[1, 0].set_ylabel('Grade')
# 4. Bar chart of average grade by subject
avg_by_subject = df.groupby('Subject')['Grade'].mean().sort_values()
axes[1, 1].bar(avg_by_subject.index, avg_by_subject.values, color='lightgreen')
axes[1, 1].set_title('Average Grade by Subject')
axes[1, 1].set_xlabel('Subject')
axes[1, 1].set_ylabel('Average Grade')
plt.tight_layout()
plt.savefig('student_dashboard.png', dpi=300, bbox_inches='tight')
plt.show()
What we used:
Illustration:
DASHBOARD FLOW
+-------------------------------------------------+
| Load data โ Explore โ Create multiple charts |
| โ |
| Arrange in subplots โ Customize โ Save โ Share |
+-------------------------------------------------+
Mini summary: The complete dashboard combines multiple chart types and libraries to create a comprehensive data visualization report.
| Word | Simple Definition |
|---|---|
| Data Visualization | Representing data through charts and graphs. |
| Matplotlib | The foundational plotting library for Python. |
| Seaborn | A high-level library for statistical plots. |
| Line Chart | Shows trends over time with connected points. |
| Bar Chart | Compares categories with rectangular bars. |
| Histogram | Shows the distribution of a dataset. |
| Scatter Plot | Shows the relationship between two variables. |
| Pie Chart | Shows parts of a whole. |
| Box Plot | Shows the spread of data using quartiles. |
| Heatmap | Shows correlations with colour intensity. |
| Subplot | Multiple charts in one figure. |
| Theme | A predefined style for charts. |
| Palette | A set of colours used in a chart. |
import matplotlib.pyplot as plt.plt.bar(categories, values).plt.title(), plt.xlabel(), plt.ylabel().plt.show() to display.import seaborn as sns.sns.set_theme(style='whitegrid').sns.boxplot(x='column1', y='column2', data=df).plt.show() to display.fig, axes = plt.subplots(rows, cols, figsize=(width, height)).axes[row, col].plt.tight_layout() to adjust spacing.plt.show() to display.plt.style module
provides ready-to-use styles like 'ggplot', 'fivethirtyeight', and
'seaborn' (which are now integrated).
plt.subplots()
to create a grid of plots with shared axes.
plt.savefig().
| Mistake | How to Avoid It |
|---|---|
Forgetting to import matplotlib.pyplot |
Always import: import matplotlib.pyplot as plt. |
Not calling plt.show() |
Always call plt.show() to display your chart. |
| Using the wrong chart type for the data | Think about what you want to show: trends, comparisons, distribution, etc. |
| Not adding labels or titles | Always add a title and axis labels to make your chart understandable. |
| Using too many colours | Stick to a consistent colour palette (use Seaborn palettes). |
| Not adjusting figure size | Use figsize parameter to make charts bigger or smaller. |
| Overlapping subplots | Use plt.tight_layout() to adjust spacing. |
| Forgetting to import seaborn after setting theme | Seaborn themes only work after importing seaborn. |
dpi=300)
for printing.
CHART TYPES
+-------------------------------------------------+
| Line Chart โ Trends over time |
| Bar Chart โ Comparing categories |
| Histogram โ Data distribution |
| Scatter Plot โ Relationship between variables |
| Pie Chart โ Parts of a whole |
| Box Plot โ Quartiles and outliers |
| Heatmap โ Correlation matrix |
+-------------------------------------------------+
MATPLOTLIB VS SEABORN
+-------------------------------------------------+
| Matplotlib: |
| - More control |
| - More code |
| - Foundation library |
+-------------------------------------------------+
| Seaborn: |
| - Beautiful defaults |
| - Less code |
| - Built on Matplotlib |
+-------------------------------------------------+
SUBPLOT GRID (2x2)
+-------------------------------------------------+
| axes[0,0] | axes[0,1] |
| Line Chart | Bar Chart |
+-------------+-----------------------------------+
| axes[1,0] | axes[1,1] |
| Scatter | Histogram |
+-------------+-----------------------------------+
| Feature | Matplotlib | Seaborn |
|---|---|---|
| Ease of use | More control, more code | Less code, beautiful defaults |
| Statistical plots | Basic | Advanced (box, violin, heatmap) |
| Themes | Manual | Built-in themes |
| Integration with Pandas | Works, but manual | Native support |
| Learning curve | Steeper | Gentler |
| Chart Type | Best For | When to Use |
|---|---|---|
| Line Chart | Trends over time | When you have continuous data (time series) |
| Bar Chart | Comparing categories | When you have categorical data |
| Histogram | Distribution | When you want to see how data is spread out |
| Scatter Plot | Relationship between two variables | When you want to see if two things are related |
| Pie Chart | Parts of a whole | When you want to show proportions |
| Box Plot | Summary of distribution | When you want to show quartiles and outliers |
| Heatmap | Correlation matrix | When you want to see relationships between multiple variables |
Lesson 1 Summary: Data visualization turns numbers into pictures that are easier to understand.
Lesson 2 Summary: Matplotlib is the foundational plotting library in Python.
Lesson 3 Summary: Line charts show trends over time using plt.plot().
Lesson 4 Summary: Bar charts compare categories using plt.bar().
Lesson 5 Summary: Histograms show data distribution using plt.hist().
Lesson 6 Summary: Scatter plots show relationships using plt.scatter().
Lesson 7 Summary: Pie charts show parts of a whole using plt.pie().
Lesson 8 Summary: Customize plots with titles, labels, legends, and grid lines.
Lesson 9 Summary: Seaborn builds on Matplotlib for beautiful statistical plots.
Lesson 10 Summary: Seaborn themes and palettes make charts look professional instantly.
Lesson 11 Summary: Seaborn provides box plots, violin plots, heatmaps, and pair plots.
Lesson 12 Summary: Subplots display multiple charts in one figure.
Lesson 13 Summary: Save figures with plt.savefig().
Lesson 14 Summary: Combining everything creates a complete data dashboard.
Congratulations! You have completed Module Four ๐. You have learned how to turn raw data into beautiful, informative visualizations using Matplotlib and Seaborn.
You learned the basics of Matplotlib โ line charts, bar charts, histograms, scatter plots, and pie charts. You learned how to customize your charts with titles, labels, legends, and colours. You discovered Seaborn and its powerful statistical plots like box plots, violin plots, heatmaps, and pair plots.
You also learned how to create subplots to combine multiple charts in one view, and how to save your figures for sharing. You built a complete data dashboard that showcases your skills.
Data visualization is an essential skill in today's data-driven world. Whether you are presenting to a client, writing a report, or exploring data for yourself, the ability to create clear, compelling charts will make you stand out.
In the next module, you will learn about Automation and Scripting โ how to automate repetitive tasks with Python, making you even more productive.
Keep practising by creating charts with different datasets. The more you practice, the more intuitive visualization will become. You are now a data visualization expert! ๐
plt.figure(figsize=(width, height)) before
plotting, or figsize in subplots().
plt.savefig('file.png', dpi=300).
plt.text(x, y, 'text') or
plt.annotate().
plt.plot()
plt.bar()
plt.hist()
plt.scatter()
plt.plot()
plt.bar()
plt.hist()
plt.scatter()
plt.title()
plt.xlabel()
plt.ylabel()
plt.legend()
plt.savefig()
plt.save()
plt.export()
plt.write()
plt.legend()?
sns.heatmap()
sns.boxplot()
sns.violinplot()
sns.pairplot()
plt.subplot()
plt.subplots()
plt.grid()
plt.figure()
sns.theme()
sns.set_theme()
sns.style()
sns.palette()
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. Matplotlib | A. Statistical plots with beautiful defaults |
| 2. Seaborn | B. Foundation plotting library |
| 3. Line Chart | C. Compares categories |
| 4. Bar Chart | D. Shows trends over time |
| 5. Histogram | E. Shows data distribution |
| 6. Scatter Plot | F. Shows relationship between two variables |
| 7. Pie Chart | G. Shows parts of a whole |
| 8. Box Plot | H. Shows quartiles and outliers |
| 9. Heatmap | I. Shows correlations |
| 10. Subplot | J. Multiple charts in one figure |
Answers: 1-B, 2-A, 3-D, 4-C, 5-E, 6-F, 7-G, 8-H, 9-I, 10-J
Scenario 1:
Ada has a dataset of daily sales for a month. She wants to show the sales trend and the distribution of daily sales. What charts should she create? Write the code.
Scenario 2:
Chidi wants to compare the average test scores of students in different classes. He also wants to see how scores are spread out in each class. What charts should he use? Write the code.
Scenario 3:
Zainab wants to create a dashboard with four charts: a line chart of sales trends, a bar chart of sales by category, a pie chart of market share, and a scatter plot of advertising vs sales. Write the code using subplots.
Activity Title: Create a Data Visualization Dashboard
Instructions:
Activity Title: Visualize Your Personal Data
Instructions:
Project Title: Build a Sales Dashboard
Description:
Create a complete sales dashboard using Matplotlib and Seaborn. The dashboard should:
This project will test your ability to combine all the skills from this module.
Assignment Title: Visualize Student Performance Data
Instructions:
Challenge Title: Build a Data Storytelling Dashboard
Choose a dataset that tells a story about a real-world issue (e.g., climate change, education inequality, poverty). Create a dashboard that:
This challenge will test your ability to use visualization to communicate real insights. Good luck!
Fill-in-the-Blank Answers:
plt.title()plt.legend()plt.savefig()set_theme()True or False Answers:
Multiple Choice Answers:
Excellent work completing Module Four! ๐ You have learned how to create beautiful, informative visualizations with Matplotlib and Seaborn. In the next module, you will learn:
To prepare, review the concepts from this module and practice creating visualizations with different datasets. The more you practice, the more intuitive visualization will become.
Keep coding, keep exploring, and never stop learning. See you in the next module! ๐๐
๐ End of Module Four โ Python Fundamentals Level Two ๐
Welcome, future automation engineer! ๐ You have learned so much in this course โ from building web apps with Flask to analysing data with Pandas and creating beautiful visualizations. Now, it is time to learn one of the most powerful and practical uses of Python: automation and scripting.
Imagine you have a task that you do every day โ renaming files, sending emails, downloading data, or even filling out forms. Wouldn't it be amazing if a computer could do it for you? That is exactly what automation is all about: teaching computers to do repetitive tasks so you can focus on more important things.
In this module, you will learn how to write Python scripts that automate everyday tasks. You will learn how to work with files and folders, schedule tasks to run automatically, send emails with Python, control web browsers with Selenium, and build your own command-line tools. By the end of this module, you will be able to save hours of time every week by automating boring, repetitive work.
Think of this module as giving you a magic helper ๐ค that does all the boring stuff for you. Let us begin our automation adventure! ๐
By the end of this module, you will be able to:
os and shutil modules.schedule library.smtplib.subprocess module.argparse.Ada was a busy student who also helped her mother run the family store. Every day, she had to do the same boring tasks: check inventory, update prices, send sales reports to her mother, and organize receipts into folders. It took hours each week!
One day, Ada thought, "Why can't a computer do all this for me?" She remembered learning about automation in Python. She decided to write a script that would do everything automatically.
She wrote a script that used the os module to organize
receipts into monthly folders. She used the schedule library
to run the script every night. She used smtplib to send an
automatic email to her mother with a daily sales summary. She even used
Selenium to download the latest price list from the supplier's website.
"Amazing!" her mother said. "Now you have more time to study and play." Ada had built her own automated assistant. And now, you will learn how to build yours! ๐ค
Definition: Automation is the process of using technology to perform tasks with minimal human intervention.
Why it is important: Automation saves time, reduces errors, and allows you to focus on more creative and important work.
Simple explanation: Imagine you have to water your plants every day. If you set up an automatic watering system, the plants get watered without you having to remember. That is automation!
Real-life example: A factory uses robots to assemble cars automatically.
School example: You set a reminder on your phone to study at the same time every day.
Home example: A smart thermostat adjusts the temperature automatically.
Nigerian example: A POS machine automatically deducts money from your account when you buy something.
Illustration:
AUTOMATION CONCEPT
+-------------------------------------------------+
| Human task โ Automated script โ Done! |
| (Boring, (Computer does (No more |
| repetitive) it for you) boring work) |
+-------------------------------------------------+
Mini summary: Automation uses computers to do repetitive tasks so you do not have to.
Definition: The os module provides
functions for interacting with the operating system โ working with files,
folders, and system paths.
Why it is important: Many automation tasks involve
organizing, renaming, or moving files. The os module makes
this easy.
Simple explanation: Imagine you have a messy desk with
papers everywhere. The os module is like your hands ๐ that
can pick up papers, move them, and put them in folders.
Common functions:
import os
# Get current working directory
current_dir = os.getcwd()
print(current_dir)
# List files in a directory
files = os.listdir('.')
print(files)
# Create a new folder
os.mkdir('new_folder')
# Check if a file or folder exists
exists = os.path.exists('file.txt')
# Rename a file
os.rename('old.txt', 'new.txt')
# Remove a file
os.remove('file.txt')
# Remove an empty folder
os.rmdir('empty_folder')
# Join paths (works on any operating system)
path = os.path.join('folder', 'subfolder', 'file.txt')
Real-life example: A script that organizes downloaded files into folders by type.
School example: You organize your class notes into subject folders.
Home example: You sort your photos into folders by year.
Nigerian example: A business automatically backs up daily sales records to a dated folder.
Illustration:
OS MODULE FUNCTIONS
+-------------------------------------------------+
| os.getcwd() โ get current folder |
| os.listdir() โ list all files/folders |
| os.mkdir() โ create a new folder |
| os.rename() โ rename a file or folder |
| os.remove() โ delete a file |
+-------------------------------------------------+
Mini summary: The os module lets you
interact with the file system โ create, rename, delete, and check files
and folders.
Definition: The shutil module provides
high-level operations on files and collections of files, like copying
and moving.
Why it is important: Copying and moving files are common tasks in automation (e.g., backing up files, organizing data).
Simple explanation: If os is your hands,
shutil is like having a forklift ๐๏ธ โ it can handle larger
operations like copying entire folders.
Common functions:
import shutil
# Copy a file
shutil.copy('source.txt', 'destination.txt')
# Copy a file to a different folder (keeps filename)
shutil.copy('source.txt', 'backup/')
# Copy an entire folder
shutil.copytree('original_folder', 'backup_folder')
# Move a file or folder
shutil.move('file.txt', 'new_location/')
# Remove an entire folder (dangerous!)
shutil.rmtree('folder_to_delete')
Real-life example: A script that copies all PDFs from your downloads folder to a "Documents" folder.
School example: You copy a project folder to a USB drive as a backup.
Home example: You move photos from your phone to your computer.
Nigerian example: A business copies daily sales data to a backup drive.
Illustration:
SHUTIL MODULE FUNCTIONS
+-------------------------------------------------+
| shutil.copy() โ copy a file |
| shutil.copytree() โ copy a whole folder |
| shutil.move() โ move a file or folder |
| shutil.rmtree() โ delete a folder (careful!) |
+-------------------------------------------------+
Mini summary: shutil lets you copy, move,
and delete files and folders at a higher level than os.
Definition: os.walk() is a function that
generates the file names in a directory tree by walking either top-down
or bottom-up. It is used to go through every folder and file inside a
directory.
Why it is important: Many automation tasks require you to process all files in a folder and its subfolders โ for example, organizing all images in a messy directory.
Simple explanation: Imagine you are exploring a huge
building with many rooms (folders) and each room has items (files).
os.walk() helps you visit every room and see every item.
How to use os.walk:
import os
# Walk through all folders and files
for root, dirs, files in os.walk('.'):
print(f"Folder: {root}")
print(f" Subfolders: {dirs}")
print(f" Files: {files}")
# Process each file
for filename in files:
filepath = os.path.join(root, filename)
print(f" Processing: {filepath}")
Real-life example: A script that finds all image files in a folder and all its subfolders.
School example: You search for all PDFs in your schoolwork folder.
Home example: You find all photos on your computer and organize them by date.
Nigerian example: A business scans all folders for receipts and moves them to an archive.
Illustration:
OS.WALK STRUCTURE
+-------------------------------------------------+
| root/ |
| โโโ folder1/ |
| โ โโโ file1.txt |
| โ โโโ subfolder/ |
| โ โโโ file2.txt |
| โโโ folder2/ |
| โโโ file3.txt |
+-------------------------------------------------+
| os.walk() visits every folder and file |
+-------------------------------------------------+
Mini summary: os.walk() lets you visit
every folder and file in a directory tree, making it easy to process all
files.
Definition: The schedule library lets you
run Python functions at specific times or intervals, like every day at
8 AM or every 10 minutes.
Why it is important: Many automation tasks need to run regularly โ daily backups, weekly reports, hourly checks. Scheduling makes this automatic.
Simple explanation: Think of schedule as
an alarm clock โฐ for your Python scripts. You tell it when to run your
code, and it reminds you (or just runs it).
How to install and use:
pip install schedule
import schedule
import time
def my_task():
print("Task is running!")
# Schedule the task
schedule.every(10).minutes.do(my_task)
schedule.every().hour.do(my_task)
schedule.every().day.at("08:00").do(my_task)
schedule.every().monday.do(my_task)
# Keep the script running
while True:
schedule.run_pending()
time.sleep(1)
Real-life example: A script that backs up a folder every night at 2 AM.
School example: A reminder to study at the same time every day.
Home example: A script that turns off your computer at a certain time.
Nigerian example: A business runs a sales report every day at 6 PM.
Illustration:
SCHEDULE LIBRARY
+-------------------------------------------------+
| schedule.every().day.at("08:00").do(task) |
| โ Runs task every day at 8:00 AM |
| schedule.every(10).minutes.do(task) |
| โ Runs task every 10 minutes |
+-------------------------------------------------+
Mini summary: The schedule library lets
you run Python functions automatically at specified times or intervals.
Definition: smtplib is a Python library
that allows you to send emails using the SMTP (Simple Mail Transfer
Protocol) protocol.
Why it is important: Sending automated emails is a common automation task โ for reports, notifications, alerts, and more.
Simple explanation: Imagine you are a secretary โ๏ธ who
sends letters for your boss. smtplib is like a robot
secretary that sends emails automatically.
How to send an email:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# Email details
sender = "your_email@gmail.com"
password = "your_app_password" # Use App Password for Gmail
receiver = "friend@example.com"
subject = "Automated Email"
body = "This email was sent automatically by a Python script!"
# Create message
msg = MIMEMultipart()
msg['From'] = sender
msg['To'] = receiver
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain'))
# Send email
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(sender, password)
server.send_message(msg)
server.quit()
print("Email sent successfully!")
except Exception as e:
print(f"Error: {e}")
Real-life example: A script that sends a daily sales report to the manager.
School example: A script that sends a reminder email before a deadline.
Home example: A script that emails your family the weekly shopping list.
Nigerian example: A business sends automated invoices to customers.
Illustration:
SENDING EMAILS
+-------------------------------------------------+
| smtplib โ connect to email server |
| โ |
| Login with your email and password |
| โ |
| Compose the email (subject, body, recipient) |
| โ |
| Send the email |
+-------------------------------------------------+
Mini summary: smtplib lets you send
automated emails from your Python scripts. You need an email account and
server settings.
Definition: Selenium is a tool that automates web browsers. It can click buttons, fill forms, and extract data from websites just like a human would.
Why it is important: Some websites do not provide APIs (like we learned in earlier modules). Selenium lets you interact with websites that require clicking, logging in, or JavaScript.
Simple explanation: Imagine you have a robot ๐ค that can use a web browser just like you โ clicking, typing, and reading. That is Selenium.
How to install and use Selenium:
pip install selenium
# Download the Chrome WebDriver from chromedriver.chromium.org
# and put it in your PATH.
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
# Launch browser
driver = webdriver.Chrome()
# Go to a website
driver.get("https://example.com")
# Find an element by ID, class, or tag
element = driver.find_element(By.ID, "search-box")
element.send_keys("Python automation")
# Click a button
button = driver.find_element(By.CLASS_NAME, "search-button")
button.click()
# Wait for page to load
time.sleep(2)
# Get page title
title = driver.title
print(title)
# Close the browser
driver.quit()
Real-life example: A script that automatically logs in to a website and downloads a report.
School example: A script that checks your school portal for new grades and notifies you.
Home example: A script that checks if a product is in stock on a shopping website.
Nigerian example: A script that checks JAMB admission status automatically.
Illustration:
SELENIUM WORKFLOW
+-------------------------------------------------+
| Launch browser |
| โ |
| Go to website |
| โ |
| Find elements (by ID, class, etc.) |
| โ |
| Interact (type text, click, etc.) |
| โ |
| Extract data or take screenshot |
| โ |
| Close browser |
+-------------------------------------------------+
Mini summary: Selenium automates web browsers. It can click, type, and extract data from websites that need human interaction.
Definition: The subprocess module lets you
run system commands from Python โ like dir on Windows,
ls on Linux, or any program you can run from the terminal.
Why it is important: Sometimes you need to run external programs from your Python script โ compressing files, converting images, or using command-line tools.
Simple explanation: Imagine you are a conductor ๐ถ who
tells other instruments (programs) what to play. subprocess
lets you conduct other programs from your Python script.
How to use subprocess:
import subprocess
# Run a command and get the output
result = subprocess.run(['ls', '-la'], capture_output=True, text=True)
print(result.stdout)
# Run a command (simple)
subprocess.run(['mkdir', 'new_folder'])
# Run a command and check if it succeeded
result = subprocess.run(['ping', '-c', '4', 'google.com'], capture_output=True, text=True)
if result.returncode == 0:
print("Ping successful!")
else:
print("Ping failed.")
Real-life example: A script that compresses files using
zip command after processing.
School example: A script that runs a program to convert documents to PDF.
Home example: A script that backs up files using the
rsync command.
Nigerian example: A script that runs a database backup command.
Illustration:
SUBPROCESS WORKFLOW
+-------------------------------------------------+
| Python script |
| โ |
| subprocess.run(['command', 'arg1', 'arg2']) |
| โ |
| System runs the command |
| โ |
| Results are returned to Python |
+-------------------------------------------------+
Mini summary: subprocess lets you run
system commands from Python, giving you access to any program on your
computer.
Definition: argparse is a module that
helps you build command-line interfaces for your Python scripts. It
handles arguments, options, and help messages.
Why it is important: Command-line tools are powerful
and user-friendly. They let users interact with your script by typing
commands like python script.py --input file.txt --output result.csv.
Simple explanation: Imagine you have a magic wand ๐ช
that works differently depending on what you say. argparse
is like the instruction manual that tells people how to use your magic
wand (your script).
How to use argparse:
import argparse
# Create a parser
parser = argparse.ArgumentParser(description='A simple file processor.')
# Add arguments
parser.add_argument('input_file', help='The input file to process')
parser.add_argument('-o', '--output', help='Output file name', default='output.txt')
parser.add_argument('-v', '--verbose', action='store_true', help='Print verbose output')
parser.add_argument('--count', type=int, default=1, help='Number of times to process')
# Parse arguments
args = parser.parse_args()
# Use the arguments
print(f"Processing: {args.input_file}")
print(f"Output file: {args.output}")
if args.verbose:
print(f"Verbose mode is ON")
print(f"Count: {args.count}")
# Main logic here...
Running the script:
python script.py data.txt -o results.csv -v --count 5
Real-life example: A data processing script that takes input file, output format, and processing options.
School example: A script that analyses test scores and takes a file name and options for output.
Home example: A script that organises photos with options for destination folder and date filter.
Nigerian example: A currency converter script that takes amount and currencies as arguments.
Illustration:
ARGPARSE USAGE
+-------------------------------------------------+
| python script.py --help |
| โ shows help message |
| python script.py input.csv -o output.json |
| โ processes input.csv and saves output.json |
+-------------------------------------------------+
Mini summary: argparse helps you build
professional command-line tools with arguments, options, and help
messages.
Now we will build a complete automation application that combines all the skills we have learned.
Scenario: We will build a "Daily Report Generator" that:
Code (simplified):
import os
import pandas as pd
import matplotlib.pyplot as plt
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
import schedule
import time
import argparse
def process_data(folder):
"""Find the latest data file and process it."""
files = os.listdir(folder)
csv_files = [f for f in files if f.endswith('.csv')]
if not csv_files:
print("No CSV files found.")
return None
latest = max(csv_files, key=lambda f: os.path.getmtime(os.path.join(folder, f)))
df = pd.read_csv(os.path.join(folder, latest))
return df
def create_chart(df, output_file):
"""Create a chart from the data."""
plt.figure(figsize=(10, 6))
df.plot(kind='bar')
plt.title('Daily Report')
plt.tight_layout()
plt.savefig(output_file)
plt.close()
def send_report(email, password, recipient, subject, body, chart_file):
"""Send an email with the report and chart."""
msg = MIMEMultipart()
msg['From'] = email
msg['To'] = recipient
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain'))
with open(chart_file, 'rb') as f:
img = MIMEImage(f.read())
img.add_header('Content-Disposition', 'attachment', filename=chart_file)
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(email, password)
server.send_message(msg)
server.quit()
print("Report sent!")
def run_daily_report(folder, email, password, recipient):
"""Run the complete daily report process."""
print("Generating daily report...")
df = process_data(folder)
if df is None:
return
chart_file = 'daily_report.png'
create_chart(df, chart_file)
send_report(email, password, recipient, 'Daily Report', 'Please find the daily report attached.', chart_file)
print("Daily report complete.")
def main():
parser = argparse.ArgumentParser(description='Daily Report Generator')
parser.add_argument('folder', help='Folder containing data files')
parser.add_argument('--email', required=True, help='Sender email')
parser.add_argument('--password', required=True, help='Email password')
parser.add_argument('--recipient', required=True, help='Recipient email')
args = parser.parse_args()
# Schedule the report every day at 8 AM
schedule.every().day.at("08:00").do(run_daily_report, args.folder, args.email, args.password, args.recipient)
print("Report generator started. Running daily at 8 AM.")
while True:
schedule.run_pending()
time.sleep(60)
if __name__ == "__main__":
main()
What we used:
os module for file operationssmtplib for sending emailsschedule for schedulingargparse for command-line argumentsIllustration:
DAILY REPORT GENERATOR FLOW
+-------------------------------------------------+
| 1. Scan folder for CSV files |
| 2. Process data with Pandas |
| 3. Create chart with Matplotlib |
| 4. Send email with chart attached |
| 5. Schedule to run daily at 8 AM |
+-------------------------------------------------+
Mini summary: The complete automation app combines file operations, data processing, visualization, email, scheduling, and command-line arguments into a powerful, automated tool.
| Word | Simple Definition |
|---|---|
| Automation | Using computers to do repetitive tasks for you. |
| Script | A program written to automate a specific task. |
| os Module | A Python module for working with files and folders. |
| shutil Module | A Python module for copying and moving files. |
| os.walk() | A function that visits every folder and file in a directory. |
| schedule | A library for scheduling tasks to run at specific times. |
| smtplib | A library for sending emails from Python. |
| Selenium | A tool for automating web browsers. |
| subprocess | A module for running system commands from Python. |
| argparse | A module for building command-line tools. |
os.listdir() to get all files in a folder.os.mkdir()).shutil.move() to move files to the right folder.os.walk() if you need to go into subfolders.pip install schedule.schedule.every().schedule.run_pending().time.sleep() to avoid using too much CPU.argparse.argparse.ArgumentParser().add_argument().parser.parse_args().shutil.rmtree() and deleting files accidentally.
schedule library can
handle timezones using the pytz module.
subprocess
to run other Python scripts from your script.
smtplib and
email.mime.
os.walk() can be used to
find and delete duplicate files.
| Mistake | How to Avoid It |
|---|---|
| Deleting the wrong file or folder | Always test on copies first. Use os.path.exists() to check. |
Using shutil.rmtree() without checking |
Double-check the path before deleting. |
Forgetting to add schedule.run_pending() in the loop |
Always include the infinite loop with schedule.run_pending(). |
| Hardcoding email passwords in scripts | Use environment variables or a config file. |
| Not handling exceptions in Selenium | Use try-except to handle element not found errors. |
Using subprocess.run() without capture_output=True |
Use capture_output=True to capture output and errors. |
Not using text=True with subprocess |
Use text=True to get string output instead of bytes. |
argparse to make your scripts
user-friendly.
FILE ORGANIZATION FLOW
+-------------------------------------------------+
| Start |
| โ |
| List files in folder |
| โ |
| For each file, check extension |
| โ |
| Move to appropriate subfolder |
| โ |
| Done! |
+-------------------------------------------------+
SCHEDULING FLOW
+-------------------------------------------------+
| schedule task |
| โ |
| While True: |
| โ |
| Check pending tasks |
| โ |
| If task is due, run it |
| โ |
| Wait 1 second |
+-------------------------------------------------+
DAILY REPORT GENERATOR
+-------------------------------------------------+
| 1. Scan folder for latest CSV |
| 2. Process data with Pandas |
| 3. Create chart |
| 4. Send email with attachment |
| 5. Schedule for next day |
+-------------------------------------------------+
SELENIUM FLOW
+-------------------------------------------------+
| Launch browser |
| โ |
| Navigate to URL |
| โ |
| Find elements (ID, class, XPath) |
| โ |
| Interact (click, type, submit) |
| โ |
| Extract data / take screenshot |
| โ |
| Close browser |
+-------------------------------------------------+
| Feature | os Module | shutil Module |
|---|---|---|
| Rename files | Yes (os.rename()) |
No |
| Copy files | No | Yes (shutil.copy()) |
| Move files | Yes (os.rename()) |
Yes (shutil.move()) |
| Copy entire folders | No | Yes (shutil.copytree()) |
| Delete files | Yes (os.remove()) |
No |
| Delete folders | Yes (os.rmdir() empty only) |
Yes (shutil.rmtree() full) |
| Feature | requests | Selenium |
|---|---|---|
| Speed | Fast (raw HTTP) | Slower (browser automation) |
| JavaScript execution | No | Yes |
| Interactions (click, type) | No | Yes |
| Resources | Low | High (browser overhead) |
| Use case | APIs, static pages | Dynamic pages, user interactions |
Lesson 1 Summary: Automation uses computers to do repetitive tasks for you.
Lesson 2 Summary: The os module works with files and folders (rename, delete, check existence).
Lesson 3 Summary: shutil copies and moves files and whole folders.
Lesson 4 Summary: os.walk() visits every folder and file in a directory tree.
Lesson 5 Summary: The schedule library runs functions at specific times.
Lesson 6 Summary: smtplib sends automated emails.
Lesson 7 Summary: Selenium automates web browsers (click, type, extract).
Lesson 8 Summary: subprocess runs system commands from Python.
Lesson 9 Summary: argparse builds command-line tools with arguments and options.
Lesson 10 Summary: Combining all tools creates powerful automation systems.
Congratulations! You have completed Module Five ๐. You have learned how to automate tasks with Python, making you more productive and efficient.
You learned how to work with files and folders using the os and shutil modules. You discovered how to schedule tasks to run automatically with the schedule library. You learned how to send automated emails with smtplib, and how to control web browsers with Selenium.
You also learned how to run system commands with subprocess and build professional command-line tools with argparse. You built a complete daily report generator that combines all these skills.
Automation is a superpower. It allows you to save hours of time and eliminate boring, repetitive work. These skills are highly valued in the workplace and can make you a much more effective developer.
In the next module, you will learn about Building RESTful APIs โ how to create your own web services that other programs can use.
Keep automating, keep exploring, and never stop learning. You are now an automation engineer! ๐ค
schedule library works on all platforms.
You can also use system-specific schedulers like Task Scheduler or
cron.
print() statements to see what the
script would do before actually doing it.
pyautogui to control the mouse and
keyboard, or win32com to automate Microsoft Office.
os.rename()
and shutil.move()?
os.rename() can only rename or move within the same
file system. shutil.move() can move across file systems
and is more flexible.
os and shutil modules?os.walk() do?argparse module?os.remove() and shutil.rmtree()?os module can copy files. (True / False)shutil.move() can move files and folders. (True / False)os.walk() only visits the top-level folder. (True / False)schedule library runs tasks at specific times. (True / False)smtplib is used for web automation. (True / False)subprocess can run system commands. (True / False)argparse is used for scheduling tasks. (True / False)sys
os
subprocess
argparse
os
shutil
sys
subprocess
os.walk() do?
time
schedule
datetime
calendar
email
smtplib
sendmail
mail
os
shutil
subprocess
sys
sys
argparse
getopt
optparse
shutil.move()
shutil.copy()
shutil.copyfile()
shutil.copytree()
os.remove()
os.rmdir()
shutil.rmtree()
shutil.delete()
os.exists()
os.path.exists()
os.check()
os.file_exists()
argparse?
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. os module | A. Copies and moves files |
| 2. shutil module | B. Sends emails |
| 3. os.walk() | C. Works with files and folders |
| 4. schedule | D. Visits every folder and file |
| 5. smtplib | E. Schedules tasks |
| 6. Selenium | F. Runs system commands |
| 7. subprocess | G. Automates web browsers |
| 8. argparse | H. Builds command-line tools |
Answers: 1-C, 2-A, 3-D, 4-E, 5-B, 6-G, 7-F, 8-H
os and shutil modules?argparse?os.remove() and shutil.rmtree()?Scenario 1:
Ada downloads many files from the internet every day. They all go to her Downloads folder, which becomes messy. She wants to automatically organize files into folders based on their file extension (images, documents, PDFs, etc.) every hour. Write the Python script for this.
Scenario 2:
Chidi wants to send an automated email to his team every Monday morning with a summary of the previous week's tasks. He has a list of tasks in a CSV file. Write the script that reads the CSV and sends the email.
Scenario 3:
Zainab wants to create a command-line tool that takes a folder path and
an optional output file, then lists all files in that folder and saves
the list to the output file. Write the script using argparse.
Activity Title: Build an Automated File Organizer
Instructions:
os and shutil modules.argparse for command-line options.Activity Title: Build a Personal Automation Script
Instructions:
os,
shutil, schedule, smtplib,
Selenium, subprocess, or argparse.
Project Title: Build an Automated Email Report System
Description:
Create a complete automated email report system that:
smtplib.schedule library.argparse to accept configuration options.This project will test your ability to combine automation, data analysis, and email into a single system.
Assignment Title: Build a File Backup System
Instructions:
shutil).argparse for command-line arguments.schedule
library.
Challenge Title: Build a Comprehensive Automation System
Build a comprehensive automation system that monitors a folder, processes new files, and sends notifications. The system should:
watchdog library).This challenge combines file monitoring, processing, email, and logging into a complete automation solution. Good luck!
Fill-in-the-Blank Answers:
osshutilos.walk()schedulesmtplibsubprocessargparseTrue or False Answers:
Multiple Choice Answers:
Excellent work completing Module Five! ๐ You have learned how to automate tasks with Python, making you a more productive and efficient developer. In the next module, you will learn:
To prepare, review the Flask basics from Level One and the database concepts from earlier. The more you practice, the easier it will be to build powerful APIs.
Keep coding, keep automating, and never stop learning. See you in the next module! ๐๐ค
๐ End of Module Five โ Python Fundamentals Level Two ๐
Welcome, future API developer! ๐ You have learned so much in this course โ from web development with Flask to data analysis, visualization, and automation. Now, it is time to learn one of the most important skills in modern software development: building APIs.
API stands for Application Programming Interface. It is like a waiter ๐ฝ๏ธ in a restaurant. You (the client) tell the waiter what you want, and the waiter brings it to you from the kitchen (the server). In the same way, an API allows different applications to talk to each other and exchange data.
In this module, you will learn how to build RESTful APIs using Flask. You will learn how to create endpoints that respond with JSON data, perform CRUD operations, add authentication, and even deploy your API to the cloud. By the end of this module, you will be able to build your own web services that other developers can use.
Think of this module as giving you the power to create your own data services ๐๏ธ. Whether you are building a mobile app backend, a microservice, or a public API, the skills you learn here will be invaluable. Let us begin! ๐
By the end of this module, you will be able to:
jsonify function to return JSON responses.Ada had a collection of books that she wanted to share with her friends. She wanted them to be able to see her books, add new ones, and mark which ones they had read. But her friends lived in different cities, so they could not use her computer directly.
"I need a way for my friends to access my book data from anywhere," Ada thought. Then she remembered APIs! She could build a web service that her friends could connect to from anywhere in the world.
Ada built a RESTful API using Flask. She created endpoints for listing books, adding a new book, updating a book's status, and deleting a book. Her friends could send requests to her API from their own programs or even from their browsers. She also added authentication so only her friends could access the API.
"Now my friends can access my book collection anytime, anywhere!" Ada said. She had built her first API. And now, you will learn how to build yours! ๐
Definition: An API (Application Programming Interface) is a set of rules that allows different software applications to communicate with each other.
Why it is important: APIs are the backbone of modern software. They allow apps to share data and functionality โ like a weather app getting data from a weather service, or a payment app processing transactions.
Simple explanation: Imagine you are at a restaurant. You (the client) give your order to the waiter (the API). The waiter takes your order to the kitchen (the server) and brings you your food. The API is the waiter โ it connects you to the kitchen.
Real-life example: When you use a weather app, it uses an API to get weather data from a weather service.
School example: You ask your teacher a question (request), and the teacher gives you an answer (response).
Home example: You ask your parent for permission to go out, and they say yes or no.
Nigerian example: A fintech app uses an API to check exchange rates from the Central Bank.
Illustration:
API CONCEPT
+-------------------------------------------------+
| Client (App/User) โ API โ Server (Data) |
| (Asks for data) (Waiter) (Gives data) |
+-------------------------------------------------+
Mini summary: An API is a set of rules that lets different applications talk to each other. It is like a waiter in a restaurant.
Definition: REST (Representational State Transfer) is a set of architectural principles for building APIs. A RESTful API uses HTTP methods (GET, POST, PUT, DELETE) to perform operations on resources.
Why it is important: REST is the most common way to build APIs. Understanding REST helps you design clean, predictable APIs.
Simple explanation: Think of a RESTful API as a library ๐. You can look at a book (GET), add a new book (POST), update a book (PUT), or remove a book (DELETE). Each action corresponds to an HTTP method.
HTTP methods:
Real-life example: An e-commerce API uses GET to view products, POST to add to cart, PUT to update quantity, and DELETE to remove from cart.
School example: Your school library lets you borrow books (GET), add new books (POST), renew books (PUT), and return books (DELETE).
Home example: Your grocery list โ you read it (GET), add items (POST), change quantities (PUT), and remove items (DELETE).
Nigerian example: A banking API lets you view balance (GET), deposit money (POST), update account details (PUT), and close account (DELETE).
Illustration:
REST METHODS
+-------------------------------------------------+
| GET โ Read data (retrieve) |
| POST โ Create new data |
| PUT โ Update existing data |
| DELETE โ Remove data |
+-------------------------------------------------+
Mini summary: REST is a set of rules for building APIs. It uses HTTP methods (GET, POST, PUT, DELETE) to perform actions on resources.
Definition: Flask can be used to build APIs, not just websites. Instead of returning HTML templates, you return JSON data.
Why it is important: Flask is lightweight and flexible, making it perfect for building APIs. You already know Flask, so you are halfway there!
Simple explanation: You have been building websites with Flask. Now, instead of sending HTML pages, you will send data in a format called JSON. It is like switching from sending letters to sending digital messages.
How to set up:
pip install flask flask-sqlalchemy flask-migrate
Basic Flask API app:
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return jsonify({"message": "Welcome to the API!"})
if __name__ == '__main__':
app.run(debug=True)
Real-life example: A developer builds a weather API that returns temperature data in JSON format.
School example: You build an API for a school project that returns student data.
Home example: You build an API for your personal budget tracker.
Nigerian example: A startup builds an API to serve product data to their mobile app.
Illustration:
FLASK API SETUP
+-------------------------------------------------+
| pip install flask flask-sqlalchemy |
| from flask import Flask, jsonify |
| app = Flask(__name__) |
| @app.route('/') |
| def home(): |
| return jsonify({"message": "Hello"}) |
+-------------------------------------------------+
Mini summary: Use Flask with jsonify() to
return JSON responses. The setup is similar to a regular Flask app, but
you return data instead of HTML.
Definition: jsonify() is a Flask function
that converts Python dictionaries and lists into JSON format and sets the
correct content type for the response.
Why it is important: JSON is the standard format for
APIs. jsonify() makes it easy to return JSON responses from
your Flask routes.
Simple explanation: Imagine you have a letter written
in English. jsonify() translates that letter into a
language that computers understand (JSON).
How to use jsonify:
from flask import jsonify
@app.route('/user')
def user():
data = {
"name": "Ada",
"age": 12,
"city": "Lagos"
}
return jsonify(data)
# Returns: {"name": "Ada", "age": 12, "city": "Lagos"}
Real-life example: A social media API returns user
profiles as JSON using jsonify().
School example: You return a student's grades as JSON.
Home example: You return your budget data as JSON.
Nigerian example: A bank API returns account information as JSON.
Illustration:
JSONIFY EXAMPLE
+-------------------------------------------------+
| data = {"name": "Ada", "age": 12} |
| return jsonify(data) |
| โ {"name": "Ada", "age": 12} |
+-------------------------------------------------+
Mini summary: jsonify() converts Python
data to JSON format for API responses. It is the standard way to return
data from Flask APIs.
Definition: A GET endpoint is a URL that responds to HTTP GET requests and returns data. It is used to retrieve information.
Why it is important: GET is the most commonly used HTTP method. It is how clients get data from your API.
Simple explanation: Think of a GET endpoint as a vending machine ๐ฅค. You press a button (make a GET request), and the machine gives you a drink (returns data).
How to create a GET endpoint:
# List all books (GET /books)
@app.route('/books', methods=['GET'])
def get_books():
return jsonify(books)
# Get a single book by ID (GET /books/1)
@app.route('/books/<int:id>', methods=['GET'])
def get_book(id):
book = next((b for b in books if b['id'] == id), None)
if book:
return jsonify(book)
return jsonify({"error": "Book not found"}), 404
Real-life example: A weather API's GET endpoint returns the current temperature for a city.
School example: An endpoint that returns a list of students in a class.
Home example: An endpoint that returns your grocery list.
Nigerian example: An endpoint that returns exchange rates from the Central Bank.
Illustration:
GET ENDPOINT
+-------------------------------------------------+
| GET /books โ returns list of books |
| GET /books/1 โ returns book with ID 1 |
| Status code 200 โ OK |
| Status code 404 โ Not found |
+-------------------------------------------------+
Mini summary: GET endpoints retrieve data. Use
@app.route() with methods=['GET'] and return
jsonify(data).
Definition: A POST endpoint is a URL that responds to HTTP POST requests and creates new data. It is used to add new records.
Why it is important: POST is how clients send data to your API to create new resources.
Simple explanation: Think of a POST endpoint as a form ๐. You fill in the form (send data), and the API processes it and creates something new.
How to create a POST endpoint:
from flask import request
@app.route('/books', methods=['POST'])
def add_book():
# Get JSON data from request body
data = request.get_json()
# Validate the data
if not data or 'title' not in data or 'author' not in data:
return jsonify({"error": "Title and author are required"}), 400
# Create a new book
new_book = {
"id": len(books) + 1,
"title": data['title'],
"author": data['author']
}
books.append(new_book)
return jsonify(new_book), 201
Real-life example: A blog API uses POST to create a new blog post.
School example: An endpoint that adds a new student to the database.
Home example: An endpoint that adds a new item to your grocery list.
Nigerian example: A banking API uses POST to create a new account.
Illustration:
POST ENDPOINT
+-------------------------------------------------+
| POST /books |
| Body: {"title": "Python", "author": "Ada"} |
| โ Creates new book, returns 201 Created |
+-------------------------------------------------+
Mini summary: POST endpoints create new data. Use
request.get_json() to access the request body, validate the
data, and return a 201 status code on success.
Definition: A PUT endpoint responds to HTTP PUT requests and updates existing data. It is used to modify existing records.
Why it is important: PUT allows clients to update existing resources, like changing a user's name or a product's price.
Simple explanation: Think of a PUT endpoint as an eraser โ๏ธ. You use it to change something that already exists.
How to create a PUT endpoint:
@app.route('/books/<int:id>', methods=['PUT'])
def update_book(id):
data = request.get_json()
book = next((b for b in books if b['id'] == id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
# Update fields
if 'title' in data:
book['title'] = data['title']
if 'author' in data:
book['author'] = data['author']
return jsonify(book)
Real-life example: A user updates their profile information.
School example: You update a student's grade.
Home example: You change the quantity of an item in your grocery list.
Nigerian example: You update your account details in a banking app.
Illustration:
PUT ENDPOINT
+-------------------------------------------------+
| PUT /books/1 |
| Body: {"title": "Advanced Python"} |
| โ Updates book with ID 1, returns updated book |
+-------------------------------------------------+
Mini summary: PUT endpoints update existing data. Find the record by ID, update the fields, and return the updated data.
Definition: A DELETE endpoint responds to HTTP DELETE requests and removes data. It is used to delete existing records.
Why it is important: DELETE allows clients to remove resources they no longer need, like deleting a user account or removing a product.
Simple explanation: Think of a DELETE endpoint as a trash bin ๐๏ธ. You throw something away, and it is gone.
How to create a DELETE endpoint:
@app.route('/books/<int:id>', methods=['DELETE'])
def delete_book(id):
global books
book = next((b for b in books if b['id'] == id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
books = [b for b in books if b['id'] != id]
return jsonify({"message": "Book deleted successfully"})
Real-life example: You delete a product from your shopping cart.
School example: You remove a student from the class list.
Home example: You delete an item from your grocery list.
Nigerian example: You close a bank account (delete).
Illustration:
DELETE ENDPOINT
+-------------------------------------------------+
| DELETE /books/1 โ removes book with ID 1 |
| Returns 200 OK with success message |
| Returns 404 if book not found |
+-------------------------------------------------+
Mini summary: DELETE endpoints remove data. Find the record by ID, remove it, and return a success message.
Definition: HTTP status codes are three-digit numbers that indicate the result of an HTTP request. Error handling means returning appropriate status codes and messages when something goes wrong.
Why it is important: Status codes tell clients what happened โ success, error, or something else. Good error handling makes your API user-friendly.
Simple explanation: Imagine you ask a question, and the person says "I don't understand" (error) or "Yes, here is the answer" (success). Status codes are like that โ they tell the client what happened.
Common status codes:
How to return status codes:
# Return with status code
return jsonify({"error": "Book not found"}), 404
# Return with success code
return jsonify(new_book), 201
# Return with validation error
if not data or 'title' not in data:
return jsonify({"error": "Title is required"}), 400
Real-life example: A login API returns 401 Unauthorized if the password is wrong.
School example: A student search API returns 404 if the student is not found.
Home example: A grocery API returns 400 if you try to add an item without a name.
Nigerian example: A banking API returns 403 Forbidden if you try to access someone else's account.
Illustration:
STATUS CODES
+-------------------------------------------------+
| 200 OK โ Success |
| 201 Created โ Resource created |
| 400 Bad Request โ Invalid input |
| 404 Not Found โ Resource missing |
| 500 Internal Server Error โ Server problem |
+-------------------------------------------------+
Mini summary: Status codes tell clients the result of their request. Always return appropriate codes and error messages.
Definition: JWT (JSON Web Token) is a standard for securely transmitting information between parties. It is commonly used for API authentication.
Why it is important: Authentication ensures that only authorized users can access your API. JWT is a popular, secure way to implement authentication.
Simple explanation: Imagine a club with a bouncer ๐ช. You show your ID (the token), the bouncer checks it, and if it is valid, you get in. JWT works like that ID.
How to use JWT in Flask:
pip install pyjwt
import jwt
import datetime
from functools import wraps
SECRET_KEY = "your-secret-key"
# Create a token
def create_token(user_id):
payload = {
'user_id': user_id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
return jwt.encode(payload, SECRET_KEY, algorithm='HS256')
# Decode a token
def decode_token(token):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
return payload['user_id']
except jwt.ExpiredSignatureError:
return None
except jwt.InvalidTokenError:
return None
# Decorator to protect routes
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token:
return jsonify({"error": "Token is missing"}), 401
user_id = decode_token(token)
if not user_id:
return jsonify({"error": "Invalid or expired token"}), 401
return f(*args, **kwargs)
return decorated
Real-life example: A social media API uses JWT to authenticate users.
School example: A school portal uses JWT to keep students logged in.
Home example: A smart home system uses JWT to authenticate devices.
Nigerian example: A fintech app uses JWT to keep users authenticated for a session.
Illustration:
JWT AUTHENTICATION FLOW
+-------------------------------------------------+
| 1. User logs in โ server creates JWT token |
| 2. Token sent back to client |
| 3. Client includes token in request header |
| 4. Server verifies token โ if valid, grant access |
+-------------------------------------------------+
Mini summary: JWT is a secure way to authenticate API
users. Use pyjwt to create, encode, and decode tokens.
Definition: Postman is a tool that allows you to test APIs by sending HTTP requests and viewing responses.
Why it is important: Testing is essential to ensure your API works correctly. Postman makes it easy to test all your endpoints without writing a frontend.
Simple explanation: Imagine you are a detective ๐ต๏ธ testing a new phone. You call different numbers to see if the phone works. Postman lets you call your API endpoints to test them.
How to test with Postman:
http://localhost:5000/books).Real-life example: A developer tests a new API endpoint before integrating it into the frontend.
School example: You test your school project API to make sure all endpoints work.
Home example: You test your personal budget API to ensure it returns the right data.
Nigerian example: A developer tests a banking API before deploying it.
Illustration:
POSTMAN WORKFLOW
+-------------------------------------------------+
| Enter URL โ Select method โ Add body โ Send |
| โ |
| View response (status code, body) |
+-------------------------------------------------+
Mini summary: Postman is a powerful tool for testing APIs. It lets you send requests and inspect responses easily.
Definition: Swagger/OpenAPI is a specification for documenting APIs. It provides a standard way to describe your API's endpoints, parameters, and responses.
Why it is important: Good documentation makes your API easier to use. Other developers can quickly understand how to interact with your API.
Simple explanation: Think of Swagger as a user manual ๐ for your API. It tells people what your API does, how to use it, and what to expect.
How to add Swagger to Flask:
pip install flask-swagger-ui
from flask_swagger_ui import get_swaggerui_blueprint
SWAGGER_URL = '/api/docs'
API_URL = '/static/swagger.json'
swaggerui_blueprint = get_swaggerui_blueprint(
SWAGGER_URL,
API_URL,
config={'app_name': "Book API"}
)
app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)
Real-life example: A public API like Twitter's API has extensive Swagger documentation.
School example: You document your school project API for your teacher.
Home example: You document your personal API so you can remember how it works later.
Nigerian example: A fintech startup documents their API for partner developers.
Illustration:
SWAGGER DOCUMENTATION
+-------------------------------------------------+
| GET /books โ Returns list of books |
| POST /books โ Creates a new book |
| PUT /books/{id} โ Updates a book |
| DELETE /books/{id} โ Deletes a book |
+-------------------------------------------------+
Mini summary: Swagger/OpenAPI provides a standard way
to document your API. Use flask-swagger-ui to add a
beautiful documentation UI to your Flask app.
Definition: Deploying means making your API available on the internet so others can access it.
Why it is important: An API is only useful if others can reach it. Deployment is the final step in making your API live.
Simple explanation: You have cooked a delicious meal ๐ฒ. Now you need to serve it to your guests. Deployment is like serving your API to the world.
Options for deployment:
Steps for Render (example):
pip install -r requirements.txt.gunicorn app:app.Real-life example: A company deploys their API to AWS for production use.
School example: You deploy your school project API so your teacher can test it.
Home example: You deploy your personal budget API to access it from anywhere.
Nigerian example: A startup deploys their API to Render to serve their mobile app.
Illustration:
DEPLOYMENT PROCESS
+-------------------------------------------------+
| Local development โ Push to Git โ Deploy to |
| Render/PythonAnywhere โ API goes live! |
+-------------------------------------------------+
Mini summary: Deploy your API using platforms like Render, PythonAnywhere, or Heroku. Set the build and start commands, and your API will be live.
Now we will build a complete RESTful API with all the features we have learned.
Scenario: A book management API with CRUD operations, authentication, and documentation.
Complete code:
from flask import Flask, jsonify, request
import jwt
import datetime
from functools import wraps
from flask_swagger_ui import get_swaggerui_blueprint
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'
# Sample data
books = [
{"id": 1, "title": "Python Basics", "author": "Ada"},
{"id": 2, "title": "Flask in Action", "author": "Chidi"}
]
users = [
{"id": 1, "username": "admin", "password": "admin123"}
]
# JWT functions
def create_token(user_id):
payload = {
'user_id': user_id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
return jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')
def decode_token(token):
try:
payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
return payload['user_id']
except:
return None
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token:
return jsonify({"error": "Token is missing"}), 401
user_id = decode_token(token)
if not user_id:
return jsonify({"error": "Invalid or expired token"}), 401
return f(*args, **kwargs)
return decorated
# Swagger setup
SWAGGER_URL = '/api/docs'
API_URL = '/static/swagger.json'
# Routes
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
username = data.get('username')
password = data.get('password')
user = next((u for u in users if u['username'] == username and u['password'] == password), None)
if not user:
return jsonify({"error": "Invalid credentials"}), 401
token = create_token(user['id'])
return jsonify({"token": token})
@app.route('/books', methods=['GET'])
@token_required
def get_books():
return jsonify(books)
@app.route('/books/<int:id>', methods=['GET'])
@token_required
def get_book(id):
book = next((b for b in books if b['id'] == id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
return jsonify(book)
@app.route('/books', methods=['POST'])
@token_required
def add_book():
data = request.get_json()
if not data or 'title' not in data or 'author' not in data:
return jsonify({"error": "Title and author required"}), 400
new_book = {
"id": len(books) + 1,
"title": data['title'],
"author": data['author']
}
books.append(new_book)
return jsonify(new_book), 201
@app.route('/books/<int:id>', methods=['PUT'])
@token_required
def update_book(id):
data = request.get_json()
book = next((b for b in books if b['id'] == id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
if 'title' in data:
book['title'] = data['title']
if 'author' in data:
book['author'] = data['author']
return jsonify(book)
@app.route('/books/<int:id>', methods=['DELETE'])
@token_required
def delete_book(id):
global books
book = next((b for b in books if b['id'] == id), None)
if not book:
return jsonify({"error": "Book not found"}), 404
books = [b for b in books if b['id'] != id]
return jsonify({"message": "Book deleted"})
@app.route('/')
def home():
return jsonify({"message": "Welcome to the Book API", "docs": "/api/docs"})
if __name__ == '__main__':
app.run(debug=True)
What we used:
jsonify() for JSON responsesIllustration:
COMPLETE API FLOW
+-------------------------------------------------+
| 1. User logs in โ gets JWT token |
| 2. User includes token in requests |
| 3. GET /books โ returns all books |
| 4. POST /books โ creates a book |
| 5. PUT /books/1 โ updates book 1 |
| 6. DELETE /books/1 โ deletes book 1 |
+-------------------------------------------------+
Mini summary: The complete API combines authentication, CRUD operations, error handling, and documentation into a professional, production-ready service.
| Word | Simple Definition |
|---|---|
| API | A set of rules for applications to communicate. |
| REST | An architectural style for building APIs. |
| Endpoint | A specific URL that handles API requests. |
| JSON | A data format used for API communication. |
| GET | HTTP method to retrieve data. |
| POST | HTTP method to create data. |
| PUT | HTTP method to update data. |
| DELETE | HTTP method to remove data. |
| JWT | JSON Web Token โ used for authentication. |
| Status Code | A number indicating the result of a request. |
| Swagger | A tool for documenting APIs. |
| Deployment | Making your API available online. |
from flask import Flask, jsonify.app = Flask(__name__).@app.route('/path', methods=['GET']).jsonify(data).app.run(debug=True).pyjwt.@token_required) to protect routes.http://localhost:5000/books).Authorization: Bearer token).| Mistake | How to Avoid It |
|---|---|
Forgetting to use jsonify() for JSON responses |
Always use jsonify() to return JSON data from Flask. |
| Hardcoding secret keys | Use environment variables for SECRET_KEY. |
| Not validating input data | Always check if required fields are present before processing. |
| Returning the wrong status code | Use appropriate codes: 200 for success, 201 for created, 400 for bad request, 404 for not found, 500 for server error. |
| Forgetting to check for token expiration | Always check jwt.ExpiredSignatureError when decoding. |
Not handling request.get_json() errors |
Use try-except or check if data is None. |
| Exposing sensitive data in error messages | Return generic error messages, not detailed stack traces. |
/api/v1/books).
/books not /book).
API FLOW
+-------------------------------------------------+
| Client sends request to /books |
| โ |
| Flask routes to the correct endpoint |
| โ |
| Endpoint processes request |
| โ |
| JSON response sent back to client |
+-------------------------------------------------+
CRUD OPERATIONS
+-------------------------------------------------+
| Create โ POST /books |
| Read โ GET /books, GET /books/1 |
| Update โ PUT /books/1 |
| Delete โ DELETE /books/1 |
+-------------------------------------------------+
JWT AUTHENTICATION FLOW
+-------------------------------------------------+
| 1. Client sends login request |
| 2. Server validates credentials |
| 3. Server creates and returns JWT token |
| 4. Client stores token |
| 5. Client includes token in future requests |
| 6. Server validates token before processing |
+-------------------------------------------------+
API STRUCTURE
+-------------------------------------------------+
| app.py |
| โโโ Login route (/login) |
| โโโ Books routes |
| โ โโโ GET /books |
| โ โโโ GET /books/{id} |
| โ โโโ POST /books |
| โ โโโ PUT /books/{id} |
| โ โโโ DELETE /books/{id} |
| โโโ JWT authentication |
| โโโ Swagger documentation |
+-------------------------------------------------+
| Method | Action | CRUD | Example |
|---|---|---|---|
| GET | Retrieve data | Read | GET /books |
| POST | Create new data | Create | POST /books |
| PUT | Update existing data | Update | PUT /books/1 |
| DELETE | Remove data | Delete | DELETE /books/1 |
| Method | How it works | Pros | Cons |
|---|---|---|---|
| JWT | Token-based, stateless | Scalable, no server-side session storage | Tokens can expire, need secure storage |
| Session (Cookie) | Server-side sessions | Easy to implement | Not stateless, requires server storage |
| Basic Auth | Username:password in header | Simple | Not secure unless over HTTPS |
| API Keys | Unique key per user | Simple to use | Can be leaked, hard to manage |
Lesson 1 Summary: An API lets different applications communicate.
Lesson 2 Summary: REST uses HTTP methods for CRUD operations.
Lesson 3 Summary: Flask is a great framework for building APIs.
Lesson 4 Summary: jsonify() converts data to JSON format.
Lesson 5 Summary: GET endpoints retrieve data.
Lesson 6 Summary: POST endpoints create data.
Lesson 7 Summary: PUT endpoints update data.
Lesson 8 Summary: DELETE endpoints remove data.
Lesson 9 Summary: Status codes and error handling are crucial for API usability.
Lesson 10 Summary: JWT provides secure API authentication.
Lesson 11 Summary: Postman is used for testing APIs.
Lesson 12 Summary: Swagger/OpenAPI documents APIs.
Lesson 13 Summary: Deploy your API to make it accessible online.
Lesson 14 Summary: A complete API combines all these features.
Congratulations! You have completed Module Six ๐. You have learned how to build professional RESTful APIs using Flask.
You now understand what APIs are and why they are important. You know
the REST principles and how to use HTTP methods (GET, POST, PUT, DELETE)
to perform CRUD operations. You can create API endpoints that return JSON
data using jsonify().
You learned how to add JWT authentication to secure your API, how to test your API with Postman, and how to document it using Swagger/OpenAPI. You also learned how to deploy your API so others can use it.
You built a complete book management API that combines all these features. This is the kind of API you would build for a real-world application โ a mobile app backend, a microservice, or a public API.
In the next module, you will learn about Testing and Debugging โ how to ensure your code is reliable and how to find and fix bugs efficiently.
Keep coding, keep building APIs, and never stop learning. You are now an API developer! ๐
request.files in Flask and save the file to disk
or cloud storage.
jsonify() in Flask?jsonify() converts data to XML format. (True / False)json.dumps()
jsonify()
to_json()
json_parse()
request.args
request.form
request.get_json()
request.data
@token_required decorator do?
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. GET | A. Creates new data |
| 2. POST | B. Retrieves data |
| 3. PUT | C. Removes data |
| 4. DELETE | D. Updates data |
| 5. JWT | E. API documentation |
| 6. Swagger | F. Authentication token |
| 7. jsonify | G. API testing tool |
| 8. Postman | H. Returns JSON data |
Answers: 1-B, 2-A, 3-D, 4-C, 5-F, 6-E, 7-H, 8-G
jsonify() in Flask?Scenario 1:
Ada wants to build an API to manage her music playlist. She needs to be able to list songs, add a new song, update a song's name, and delete a song. Write the Flask code for this API with JWT authentication.
Scenario 2:
Chidi has built his API and wants to test it. He has Postman installed. He needs to test the GET, POST, PUT, and DELETE endpoints. What steps should he follow for each?
Scenario 3:
Zainab wants to document her API so other developers can use it. She has chosen Swagger. What should she include in her documentation and how does she set it up in Flask?
Activity Title: Build a Product API
Instructions:
Activity Title: Build a Task Management API
Instructions:
Project Title: Build a Complete Blog API
Description:
Create a complete blog API with the following features:
This project will test your ability to build a complete, production-ready API. Good luck!
Assignment Title: Build an API for a Library
Instructions:
Challenge Title: Build an E-commerce API
Build a complete e-commerce API with the following features:
This challenge will test your ability to build a complex, multi-feature API. Good luck!
Fill-in-the-Blank Answers:
jsonify()True or False Answers:
Multiple Choice Answers:
Excellent work completing Module Six! ๐ You have learned how to build professional RESTful APIs with Flask. In the next module, you will learn:
unittest and pytest.pdb,
logging, and print debugging.To prepare, review the concepts from this module and practice building APIs. The more you practice, the easier it will be to test and debug them.
Keep coding, keep building APIs, and never stop learning. See you in the next module! ๐๐
๐ End of Module Six โ Python Fundamentals Level Two ๐
Welcome, code quality champion! ๐ You have built amazing things โ web apps, APIs, data analysis pipelines, and automation scripts. But how do you know your code actually works? How do you find bugs when things go wrong? In this module, you will learn the essential skills of testing and debugging.
Testing is like checking your homework before submitting it ๐. You write small programs (tests) that check if your code does what it should. If all tests pass, you can be confident your code works. Debugging is like being a detective ๐ต๏ธ โ when something breaks, you need to find out why and fix it.
You will learn how to write unit tests using unittest and
pytest, how to test Flask applications, how to use mocking
to isolate code, and how to debug effectively with print statements,
logging, and the Python debugger (pdb). You will also learn
about code quality tools that help you write cleaner, more reliable code.
By the end of this module, you will be able to write tests for your own code, find and fix bugs efficiently, and ensure your programs are robust and maintainable. Let us dive in! ๐
By the end of this module, you will be able to:
unittest module.pytest (a more modern testing framework).pytest.pdb).flake8, black, and mypy.Ada had built a beautiful Flask API for her book collection. Her friends loved it, but sometimes it would crash with strange errors. One friend said, "Ada, when I try to add a book with a very long title, it breaks!" Another said, "The search function doesn't find books with uppercase letters."
Ada realized she needed to test her code properly. She started writing
unit tests to check every part of her API. She used
unittest to test her functions, and she added
mocking to isolate the database. She also used
debugging tools to track down tricky bugs.
"Now I can catch bugs before my friends do!" Ada said. She also set up continuous integration so every time she made a change, all her tests would run automatically. Her API became much more reliable, and her friends were happier. Ada had become a testing and debugging expert. And now, you will become one too! ๐
Definition: Testing is the process of checking that your code works as expected. A test is a small program that verifies a piece of your code.
Why it is important: Testing catches bugs before users do. It gives you confidence that your code works. When you make changes, tests tell you if you broke anything.
Simple explanation: Imagine you are baking a cake. You taste the batter to see if it is sweet enough. That is testing! You are checking if the cake will be good before you serve it.
Real-life example: A car manufacturer crash-tests cars to make sure they are safe.
School example: Your teacher gives you a practice test before the real exam.
Home example: You try on clothes before buying them to see if they fit.
Nigerian example: A market woman tastes a little bit of her stew to check the seasoning.
Illustration:
TESTING PROCESS
+-------------------------------------------------+
| Write code โ Write tests โ Run tests |
| If tests pass โ Code is good |
| If tests fail โ Fix code and retest |
+-------------------------------------------------+
Mini summary: Testing is checking your code to make sure it works. It saves time and prevents bugs.
Definition: unittest is a built-in Python
module for writing and running tests. It is based on the xUnit testing
framework.
Why it is important: unittest provides a
structured way to write tests, with setup, teardown, and assertion
methods.
Simple explanation: Think of unittest as a
testing kit ๐งช. It gives you tools (assertions) to check if your code
produces the right results.
How to write a unit test:
import unittest
def add(a, b):
return a + b
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(0, 0), 0)
if __name__ == '__main__':
unittest.main()
Common assertions:
assertEqual(a, b) โ checks that a == bassertTrue(x) โ checks that x is TrueassertFalse(x) โ checks that x is FalseassertIn(a, b) โ checks that a is in bassertRaises(Exception, func, *args) โ checks that an exception is raisedReal-life example: A bank tests that its transfer function correctly deducts money.
School example: A teacher checks if a student's answer is correct.
Home example: You test a recipe by tasting a small sample.
Nigerian example: A trader weighs a product to make sure it is the right amount.
Illustration:
UNITTEST EXAMPLE
+-------------------------------------------------+
| import unittest |
| class TestAdd(unittest.TestCase): |
| def test_add(self): |
| self.assertEqual(add(2,3), 5) |
| self.assertEqual(add(-1,1), 0) |
+-------------------------------------------------+
Mini summary: unittest provides a
framework for writing tests with assertions. It is built into Python.
Definition: Testable code is code that is easy to test. It is modular, has clear inputs and outputs, and avoids side effects.
Why it is important: Testable code is easier to understand, maintain, and debug. It also makes testing much simpler.
Simple explanation: Imagine a machine with many buttons and levers. If it is designed well, you can easily test each function. If it is a mess, testing is hard.
Principles of testable code:
Real-life example: A well-organized kitchen makes it easy to find ingredients and tools.
School example: Organizing your notes by subject makes studying easier.
Home example: Having a clean workspace helps you work faster.
Nigerian example: A market woman organizes her goods by type, making it easier to find what customers want.
Illustration:
TESTABLE CODE
+-------------------------------------------------+
| Good: |
| def calculate_total(prices): |
| return sum(prices) |
| (Pure function, easy to test) |
+-------------------------------------------------+
| Bad: |
| def process_order(): |
| data = read_from_db() |
| total = sum(data) |
| send_email(total) |
| (Mixed concerns, hard to test) |
+-------------------------------------------------+
Mini summary: Write code that is modular, with clear inputs and outputs. Avoid side effects to make testing easier.
Definition: pytest is a popular testing
framework for Python that is more modern and easier to use than
unittest. It allows you to write tests as simple functions.
Why it is important: pytest is widely used
in the Python community. It has powerful features like fixtures,
parameterized tests, and plugins.
Simple explanation: If unittest is a
traditional tool, pytest is like a smart, modern tool that
does the same job with less effort.
How to install and use pytest:
pip install pytest
Writing a test:
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
Running tests:
pytest test_example.py
Real-life example: A developer uses pytest to test a web application.
School example: You write a test to check your math function.
Home example: You test a recipe by following it step by step.
Nigerian example: A market woman checks her scales to ensure they are accurate.
Illustration:
PYTEST EXAMPLE
+-------------------------------------------------+
| def test_add(): |
| assert add(2, 3) == 5 |
| assert add(-1, 1) == 0 |
| Run: pytest test_file.py |
+-------------------------------------------------+
Mini summary: pytest is a modern testing
framework. It is easy to write and run tests with simple functions and
assertions.
Definition: Fixtures are functions that provide a fixed baseline for tests. They are used to set up data or resources that multiple tests need.
Why it is important: Fixtures help you avoid repeating setup code. They make your tests cleaner and more maintainable.
Simple explanation: Imagine you are baking many cakes. Instead of preparing the batter for each cake separately, you make one big batch and use it for all. Fixtures are like that batch.
How to use fixtures:
import pytest
@pytest.fixture
def sample_data():
return {"name": "Ada", "age": 12}
def test_name(sample_data):
assert sample_data["name"] == "Ada"
def test_age(sample_data):
assert sample_data["age"] == 12
Real-life example: A database connection is set up once and used in multiple tests.
School example: You have a set of sample test questions that you use for different practice tests.
Home example: You prepare a common base for different dishes (like a stock).
Nigerian example: A trader uses the same pricing list for different customers.
Illustration:
FIXTURES IN PYTEST
+-------------------------------------------------+
| @pytest.fixture |
| def data(): |
| return {"name": "Ada", "age": 12} |
| def test_name(data): |
| assert data["name"] == "Ada" |
+-------------------------------------------------+
Mini summary: Fixtures provide reusable test data or resources. They make tests cleaner and avoid duplication.
Definition: Mocking is the practice of replacing a real object with a fake one that simulates its behaviour. Patching is used to replace objects during testing.
Why it is important: Mocking allows you to test code that depends on external services (like databases or APIs) without actually calling them. This makes tests faster and more reliable.
Simple explanation: Imagine you are testing a remote control. Instead of testing it with a real TV, you use a dummy TV that behaves like a real one. That is mocking.
How to use mocking with unittest:
from unittest.mock import Mock, patch
# Create a mock object
mock_db = Mock()
mock_db.get.return_value = {"name": "Ada"}
# Patch an external dependency
@patch('module.external_function')
def test_something(mock_external):
mock_external.return_value = 10
# Now external_function will return 10 in the test
Real-life example: Testing a payment system without actually charging a credit card.
School example: Practicing with a sample exam paper instead of the real one.
Home example: Using a dummy phone to test a phone app.
Nigerian example: A bank tests its ATM software with a mock network before going live.
Illustration:
MOCKING EXAMPLE
+-------------------------------------------------+
| from unittest.mock import Mock |
| mock_weather = Mock() |
| mock_weather.get_temperature.return_value = 25 |
| # Now using mock_weather in tests |
+-------------------------------------------------+
Mini summary: Mocking replaces real objects with fake ones to isolate the code being tested. It is essential for testing code that interacts with external services.
Definition: Testing Flask applications involves sending
test requests to the app and checking the responses. You can use
pytest and Flask's test client.
Why it is important: You need to ensure your web app works correctly โ routes, forms, and API endpoints all need to be tested.
Simple explanation: It is like sending a robot ๐ค to visit your website and check that every page works correctly.
How to test a Flask app:
import pytest
from app import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_home(client):
response = client.get('/')
assert response.status_code == 200
assert b'Welcome' in response.data
Real-life example: An e-commerce site tests its checkout process before releasing.
School example: You test your school project website by clicking all links.
Home example: You try out a new recipe by following the instructions.
Nigerian example: A business tests its online store's payment page before launching.
Illustration:
FLASK TESTING
+-------------------------------------------------+
| client = app.test_client() |
| response = client.get('/') |
| assert response.status_code == 200 |
+-------------------------------------------------+
Mini summary: Use Flask's test client to simulate requests and check responses. This ensures your web app works correctly.
Definition: Using print() to show the
values of variables at different points in your code to understand what
is happening.
Why it is important: Print debugging is the simplest and most common way to find bugs. It is quick and easy.
Simple explanation: It is like putting sticky notes ๐ on your code to remember what values are at each step.
How to use:
def calculate_average(numbers):
total = 0
for num in numbers:
total += num
print(f"Current total: {total}") # Debug print
avg = total / len(numbers)
print(f"Average: {avg}") # Debug print
return avg
Real-life example: A chef tastes the soup at each stage to adjust seasoning.
School example: You check your answers step by step while solving a math problem.
Home example: You try a piece of the cake before it is fully baked.
Nigerian example: A trader counts money twice to be sure of the amount.
Illustration:
PRINT DEBUGGING
+-------------------------------------------------+
| print(f"Variable x = {x}") |
| print(f"Function returned: {result}") |
| โ Check output to see what is happening |
+-------------------------------------------------+
Mini summary: Print debugging is a simple but effective technique to see what your code is doing at runtime.
Definition: The logging module provides a
flexible way to record messages from your program, with different levels
(DEBUG, INFO, WARNING, ERROR, CRITICAL).
Why it is important: Logging is more powerful than print debugging. You can control the verbosity, log to files, and keep a record of what happened.
Simple explanation: It is like keeping a diary ๐ of what your program does. You can look back later to see what happened.
How to use logging:
import logging
logging.basicConfig(level=logging.DEBUG)
def divide(a, b):
logging.debug(f"Dividing {a} by {b}")
if b == 0:
logging.error("Division by zero attempted!")
return None
return a / b
Real-life example: A flight recorder (black box) logs data during a flight.
School example: You keep a study journal to track your progress.
Home example: You keep a record of your expenses.
Nigerian example: A business keeps a sales log for tax purposes.
Illustration:
LOGGING EXAMPLE
+-------------------------------------------------+
| import logging |
| logging.basicConfig(level=logging.DEBUG) |
| logging.debug("This is a debug message") |
| logging.info("Info message") |
| logging.error("Error message") |
+-------------------------------------------------+
Mini summary: The logging module provides
flexible, configurable logging for debugging and monitoring.
Definition: pdb is the Python debugger. It
allows you to step through your code line by line, inspect variables,
and control execution.
Why it is important: pdb is a powerful
tool for understanding complex bugs. You can see exactly what is
happening at each step.
Simple explanation: Think of pdb as a
remote control for your code ๐บ. You can pause, step forward, and look
at the state of your program at any point.
How to use pdb:
import pdb
def buggy_function(x, y):
result = x + y
pdb.set_trace() # Execution pauses here
result = result * 2
return result
buggy_function(2, 3)
Common pdb commands:
n (next) โ execute the current line and go to the nextc (continue) โ continue execution until the next breakpointp variable โ print the value of a variableq (quit) โ exit the debuggers (step) โ step into a function callReal-life example: A mechanic uses a diagnostic tool to find engine problems.
School example: You use a ruler to measure each step of a geometry construction.
Home example: You follow a recipe step by step, checking each ingredient.
Nigerian example: An electrician uses a multimeter to check each wire.
Illustration:
PDB DEBUGGING
+-------------------------------------------------+
| import pdb |
| pdb.set_trace() # Breakpoint |
| (Pdb) n โ next line |
| (Pdb) p x โ print x |
| (Pdb) c โ continue |
+-------------------------------------------------+
Mini summary: pdb lets you step through
your code line by line, inspect variables, and find bugs interactively.
Definition: Code quality tools help you write cleaner,
more consistent code. flake8 checks for style and errors,
black formats your code automatically, and mypy
checks type hints.
Why it is important: Good code is easy to read and maintain. These tools automate the process of finding issues and enforcing standards.
Simple explanation: Think of them as teachers ๐ฉโ๐ซ who check your homework for mistakes and suggest improvements.
How to use:
pip install flake8 black mypy
# Check style
flake8 my_script.py
# Auto-format
black my_script.py
# Type check
mypy my_script.py
Real-life example: A publishing house uses editors to check books for errors.
School example: Your teacher corrects your grammar and spelling.
Home example: You use a measuring tape to make sure furniture fits in a room.
Nigerian example: A contractor uses a level to make sure a wall is straight.
Illustration:
CODE QUALITY TOOLS
+-------------------------------------------------+
| flake8: finds style issues and bugs |
| black: auto-formats code |
| mypy: checks type hints |
+-------------------------------------------------+
Mini summary: Code quality tools automate checking and fixing of code style, potential errors, and type consistency.
Definition: Continuous Integration (CI) is the practice of automatically running tests whenever code is pushed to a repository. It helps catch bugs early.
Why it is important: CI gives you confidence that your code still works after changes. It also helps teams collaborate.
Simple explanation: Imagine you are building a Lego structure. Every time you add a new piece, you shake the table to see if it falls apart. CI is like that โ it checks if your code still stands after each change.
Popular CI services:
Example workflow (GitHub Actions):
name: Python tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest
Real-life example: A car factory tests every car before it leaves the assembly line.
School example: Your school has a policy that every project must be checked by a teacher before submission.
Home example: You test your phone after installing a new app.
Nigerian example: A market woman weighs her goods before selling to ensure correct quantity.
Illustration:
CI PIPELINE
+-------------------------------------------------+
| Code pushed to GitHub |
| โ |
| CI server runs tests automatically |
| โ |
| If tests pass โ code is safe |
| If tests fail โ developer is notified |
+-------------------------------------------------+
Mini summary: CI automatically runs tests on every code change, ensuring your code stays reliable.
Now we will build a simple Flask app with comprehensive tests, demonstrating all the concepts we have learned.
Scenario: A simple "Todo" API with a test suite.
app.py:
from flask import Flask, jsonify, request
app = Flask(__name__)
todos = []
@app.route('/todos', methods=['GET'])
def get_todos():
return jsonify(todos)
@app.route('/todos', methods=['POST'])
def add_todo():
data = request.get_json()
if not data or 'task' not in data:
return jsonify({"error": "Task required"}), 400
todo = {"id": len(todos) + 1, "task": data['task'], "done": False}
todos.append(todo)
return jsonify(todo), 201
@app.route('/todos/<int:id>', methods=['PUT'])
def update_todo(id):
todo = next((t for t in todos if t['id'] == id), None)
if not todo:
return jsonify({"error": "Todo not found"}), 404
data = request.get_json()
if 'done' in data:
todo['done'] = data['done']
if 'task' in data:
todo['task'] = data['task']
return jsonify(todo)
@app.route('/todos/<int:id>', methods=['DELETE'])
def delete_todo(id):
global todos
todo = next((t for t in todos if t['id'] == id), None)
if not todo:
return jsonify({"error": "Todo not found"}), 404
todos = [t for t in todos if t['id'] != id]
return jsonify({"message": "Todo deleted"})
if __name__ == '__main__':
app.run(debug=True)
test_app.py (using pytest):
import pytest
from app import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
# Clear todos before each test
app.todos.clear()
yield client
def test_get_empty_todos(client):
response = client.get('/todos')
assert response.status_code == 200
assert response.json == []
def test_add_todo(client):
response = client.post('/todos', json={"task": "Learn testing"})
assert response.status_code == 201
data = response.json
assert data['task'] == "Learn testing"
assert data['done'] == False
# Check that it was added
get_response = client.get('/todos')
assert len(get_response.json) == 1
def test_update_todo(client):
# First add a todo
add_resp = client.post('/todos', json={"task": "Learn Python"})
todo_id = add_resp.json['id']
# Update it
update_resp = client.put(f'/todos/{todo_id}', json={"done": True})
assert update_resp.status_code == 200
assert update_resp.json['done'] == True
def test_delete_todo(client):
add_resp = client.post('/todos', json={"task": "Delete me"})
todo_id = add_resp.json['id']
delete_resp = client.delete(f'/todos/{todo_id}')
assert delete_resp.status_code == 200
# Verify it's gone
get_resp = client.get('/todos')
assert len(get_resp.json) == 0
def test_add_todo_missing_task(client):
response = client.post('/todos', json={})
assert response.status_code == 400
assert 'error' in response.json
What we used:
Illustration:
TESTED APP FLOW
+-------------------------------------------------+
| Write app.py โ Write test_app.py |
| Run pytest โ Tests pass โ App is reliable |
| If tests fail โ Fix and retest |
+-------------------------------------------------+
Mini summary: A well-tested Flask app with unit tests for each endpoint ensures reliability and catches bugs early.
| Word | Simple Definition |
|---|---|
| Unit Test | A test that checks a small piece of code. |
| unittest | A built-in Python testing framework. |
| pytest | A popular, modern testing framework. |
| Fixture | A setup function that provides data or resources for tests. |
| Mock | A fake object that simulates a real object. |
| Patch | Replacing an object during testing. |
| Assertion | A check that verifies a condition is true. |
| Debugging | Finding and fixing errors in code. |
| Logging | Recording messages to track program behaviour. |
| pdb | The Python debugger for interactive debugging. |
| flake8 | A code quality tool for style and errors. |
| black | A code formatter that enforces consistent style. |
| mypy | A type checker for Python. |
| CI | Continuous Integration โ automated testing on code changes. |
pytest is more
modern and preferred.
pdb.
unittest.unittest.TestCase.test_.self.assertEqual().unittest.main().@pytest.fixture.import pdb; pdb.set_trace() at the point you want to debug.n to execute the next line.p variable to print the value of a variable.c to continue execution.pytest framework was created in 2010 and has become
one of the most popular testing tools for Python.
pdb was inspired by the GDB
debugger for C.
pytest to
run unittest tests without modifying them.
logging module is
thread-safe and can be used in multi-threaded applications.
flake8 combines
pyflakes, pycodestyle, and McCabe
complexity checking.
black is opinionated and
formats code consistently, making it popular in many open-source
projects.
pdb.
| Mistake | How to Avoid It |
|---|---|
| Not writing tests at all | Always write tests for your code, even small ones. |
| Writing tests that depend on each other | Each test should be independent. Use fixtures to reset state. |
| Testing too much in one test | Each test should test a single behaviour. |
| Not handling exceptions in tests | Use assertRaises or pytest.raises to test exceptions. |
| Hardcoding values in tests | Use fixtures or constants for test data. |
| Ignoring code quality tools | Integrate flake8, black, and mypy into your workflow. |
| Not using logging for debugging | Use logging instead of print for better control. |
| Forgetting to reset state between tests | Use setup/teardown methods or fixtures to reset. |
test_addition_with_negative_numbers.
TESTING CYCLE
+-------------------------------------------------+
| Write code โ Write tests โ Run tests |
| If tests fail โ Fix code โ Run tests again |
| If tests pass โ Code is ready |
+-------------------------------------------------+
UNITTEST VS PYTEST
+-------------------------------------------------+
| unittest: |
| class TestAdd(unittest.TestCase): |
| def test_add(self): |
| self.assertEqual(add(2,3), 5) |
+-------------------------------------------------+
| pytest: |
| def test_add(): |
| assert add(2,3) == 5 |
+-------------------------------------------------+
MOCKING FLOW
+-------------------------------------------------+
| Code under test calls external service |
| โ |
| Test replaces it with a mock |
| โ |
| Mock returns controlled data |
+-------------------------------------------------+
CI PIPELINE
+-------------------------------------------------+
| Code pushed to GitHub |
| โ |
| CI server picks up the change |
| โ |
| Install dependencies |
| โ |
| Run tests |
| โ |
| If tests pass โ merge allowed |
| If tests fail โ notify developer |
+-------------------------------------------------+
| Feature | unittest | pytest |
|---|---|---|
| Built-in | Yes | No (requires install) |
| Test syntax | Class-based | Function-based |
| Assertions | self.assertEqual() |
assert |
| Fixtures | setUp(), tearDown() |
@pytest.fixture |
| Verbosity | Less descriptive | More descriptive |
| Plugins | Limited | Rich ecosystem |
| Technique | When to use | Pros | Cons |
|---|---|---|---|
| Simple, quick checks | Easy, immediate | Clutters output, not persistent | |
| Logging | Long-running apps, production | Persistent, configurable, levels | Requires setup |
| pdb | Complex bugs, interactive debugging | Step-through, inspect variables | Requires interactive environment |
Lesson 1 Summary: Testing is checking your code to ensure it works.
Lesson 2 Summary: unittest is Python's built-in testing framework.
Lesson 3 Summary: Write testable code by making it modular and pure.
Lesson 4 Summary: pytest is a modern, easy-to-use testing framework.
Lesson 5 Summary: Fixtures provide reusable setup data for tests.
Lesson 6 Summary: Mocking replaces real objects with fakes to isolate code.
Lesson 7 Summary: Use Flask's test client to test web applications.
Lesson 8 Summary: Print debugging is quick and simple for finding bugs.
Lesson 9 Summary: Logging provides flexible, persistent debugging output.
Lesson 10 Summary: pdb allows interactive step-by-step debugging.
Lesson 11 Summary: Code quality tools like flake8, black, and mypy improve code.
Lesson 12 Summary: CI automates testing on every code change.
Lesson 13 Summary: A tested Flask app includes unit tests for all endpoints.
Congratulations! You have completed Module Seven ๐. You have learned essential skills for writing reliable, maintainable code: testing and debugging.
You now know how to write unit tests using unittest and
pytest. You can use fixtures to set up test data, and
mocking to isolate your code from external dependencies. You have
learned how to test Flask applications and ensure your web apps work
correctly.
You also learned debugging techniques โ from simple print statements to
advanced logging and the interactive Python debugger (pdb).
You discovered code quality tools that help you write cleaner,
more consistent code, and you learned about Continuous Integration to
automate testing.
These skills are crucial for any professional developer. They will save you countless hours of frustration and make your code more reliable and easier to maintain. You are now ready to build software that you can truly trust.
In the next module, you will learn about Deployment and DevOps โ how to deploy your applications to the cloud and manage them in production.
Keep testing, keep debugging, and never stop learning. You are now a quality-focused developer! ๐๐
pytest is more modern, easier to use, and has more
features. Start with pytest if you can.
pdb set_trace() inside routes.
logging is more powerful โ you can set log levels,
write to files, and control output.
black filename.py to format it
automatically.
unittest and pytest?pdb to debug?flake8 do?black do?mypy do?assert statement in pytest?unittest requires classes to write tests. (True / False)pytest uses the assert statement. (True / False)unittest. (True / False)pdb is used for interactive debugging. (True / False)flake8 checks for type errors. (True / False)black formats code automatically. (True / False)mypy checks for syntax errors. (True / False)test
unittest
pytest
testing
assert statement for tests?
unittest
pytest
pdb
pdb
flake8
print
logging
sys
debug
black
flake8
mypy
pytest
flake8
black
mypy
pytest
flake8
black
mypy
pytest
assertRaises or
pytest.raises?
flake8
black
pdb
mypy
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. unittest | A. Modern testing framework |
| 2. pytest | B. Built-in testing framework |
| 3. Fixture | C. Replaces real objects |
| 4. Mock | D. Setup data for tests |
| 5. flask test client | E. Interactive debugger |
| 6. pdb | F. Tests Flask apps |
| 7. logging | G. Formats code |
| 8. black | H. Flexible debugging output |
| 9. flake8 | I. Type checker |
| 10. mypy | J. Style and error checker |
Answers: 1-B, 2-A, 3-D, 4-C, 5-F, 6-E, 7-H, 8-G, 9-J, 10-I
unittest and pytest?pdb to debug a Python script?flake8, black, and mypy?Scenario 1:
Ada has a function that calculates the average of a list of numbers. She
wants to write tests for it. Write the pytest tests for this
function, including edge cases (empty list, negative numbers).
Scenario 2:
Chidi's Flask app has a route that gets a user by ID from a database. He wants to test it without actually hitting the database. How can he use mocking to test this route? Write the test.
Scenario 3:
Zainab is debugging a complex function and it keeps crashing. She wants to step through it line by line. What tool should she use and how? Write the steps.
Activity Title: Test a Flask API
Instructions:
pytest.Activity Title: Test Your Own Code
Instructions:
pytest.
Project Title: Test a Complete Flask Blog API
Description:
Create a complete test suite for a blog API (similar to the one built in Module Six). The API should have:
Your test suite should:
pytest.This project will test your ability to write comprehensive tests for a real-world API. Good luck!
Assignment Title: Add Tests to an Existing Project
Instructions:
pytest.
Challenge Title: Implement Test-Driven Development (TDD)
Write a new Python module (e.g., a calculator) using Test-Driven Development. That is:
Your module should have functions for addition, subtraction, multiplication, and division. Write tests for:
Submit your test file, your implementation file, and a log of your TDD process (what you wrote at each step). This challenge will test your ability to design code around tests.
Fill-in-the-Blank Answers:
unittestpytestpdbloggingflake8blackmypypytest.raisesTrue or False Answers:
Multiple Choice Answers:
pytest is modern and
preferred.
pdb for interactive debugging.
Excellent work completing Module Seven! ๐ You have learned how to test and debug your Python code effectively. In the next module, you will learn:
To prepare, review the Flask applications you have built and think about how you would deploy them. The more you practice, the easier it will be to deploy your projects.
Keep testing, keep debugging, and never stop learning. See you in the next module! ๐๐
๐ End of Module Seven โ Python Fundamentals Level Two ๐
Welcome, future DevOps engineer! ๐ You have built amazing applications โ Flask web apps, RESTful APIs, data analysis pipelines, and automation scripts. But there is one final step: deployment. Deployment is the process of making your application available to the world so others can use it.
Think of deployment like opening a restaurant ๐ฝ๏ธ. You have done all the cooking (coding) and testing. Now you need to set up the tables, turn on the lights, and open the doors so customers can come in. That is what deployment does for your code.
In this module, you will learn how to deploy your Python applications to the cloud using platforms like PythonAnywhere, Render, and Heroku. You will learn about environment variables, Docker, CI/CD pipelines, and monitoring. By the end of this module, you will be able to take any Python project from your computer to the internet, where anyone can use it.
This is the final module of Level Two. You are about to become a full-fledged Python developer who can build, test, and deploy real-world applications. Let us begin! ๐
By the end of this module, you will be able to:
requirements.txt file for dependencies.Ada had built an amazing book recommendation app that her friends loved. But she was tired of running it on her laptop and having to keep it running all the time. She wanted her friends to be able to access it anytime, from anywhere.
"I need to deploy my app to the internet," Ada said. She learned about PythonAnywhere and deployed her app there. It was live! Her friends could visit her app from their phones, tablets, and computers.
But then she wanted to make changes without interrupting the live app. She learned about environment variables to keep secrets safe, and Docker to package her app consistently. She even set up a CI/CD pipeline so that every time she pushed code to GitHub, her tests ran and the app was automatically deployed.
"My app is now professional and reliable!" Ada said. She had mastered the art of deployment. And now, you will learn how to do the same! ๐
Definition: Deployment is the process of making your application available to users on the internet.
Why it is important: Without deployment, your app is only on your computer. Deployment allows the world to use your creation.
Simple explanation: Imagine you have written a book ๐. It is only a draft on your computer. Publishing it (deployment) makes it available for everyone to read.
Real-life example: A company launches its new website so customers can visit it.
School example: You submit your project to the teacher for grading โ that is like deployment.
Home example: You share a photo with your family by posting it online.
Nigerian example: A business opens a new shop so customers can visit.
Illustration:
DEPLOYMENT CONCEPT
+-------------------------------------------------+
| Local machine (development) โ Server (production) |
| (Your computer) (Internet) |
+-------------------------------------------------+
Mini summary: Deployment makes your application available to users on the internet.
Definition: Deployment platforms are services that host your application on the internet. They provide the servers and infrastructure.
Why it is important: You cannot host an app on your laptop forever. Deployment platforms provide reliable, always-on servers.
Simple explanation: Think of a deployment platform as a stage ๐ญ where your app performs. The stage is always set up and ready for an audience.
Popular platforms:
Real-life example: A business uses AWS to host its e-commerce website.
School example: You use Google Sites to host a school project website.
Home example: You use a free blog platform to share your writing.
Nigerian example: A startup uses Render to deploy their mobile app backend.
Illustration:
DEPLOYMENT PLATFORMS
+-------------------------------------------------+
| PythonAnywhere โ Easy, free for beginners |
| Render โ Git-based, free tier |
| Heroku โ Popular, simple |
| AWS โ Powerful, complex |
+-------------------------------------------------+
Mini summary: Deployment platforms host your app on the internet. Choose one based on your needs and experience.
Definition: PythonAnywhere is a platform that makes it easy to host Python web applications. It has a free tier perfect for learning.
Why it is important: PythonAnywhere is beginner-friendly and does not require complex setup. It is a great place to start.
Simple explanation: Think of PythonAnywhere as a friendly hotel ๐จ for your Python app. You bring your app, and they give it a room on the internet.
Steps to deploy:
yourusername.pythonanywhere.com.Important:
requirements.txt is uploaded.app.py or configured
in WSGI.debug=False in production.Real-life example: A developer deploys their personal blog to PythonAnywhere.
School example: You deploy your school project to PythonAnywhere so your teacher can see it.
Home example: You deploy a family recipe website.
Nigerian example: A small business deploys their website to PythonAnywhere.
Illustration:
PYTHONANYWHERE DEPLOYMENT
+-------------------------------------------------+
| 1. Create account |
| 2. Add web app โ choose Flask |
| 3. Upload files (Git or via Files tab) |
| 4. Configure WSGI file |
| 5. App goes live! |
+-------------------------------------------------+
Mini summary: PythonAnywhere is a beginner-friendly platform for deploying Flask apps. Follow the steps to get your app online.
Definition: Render is a cloud platform that offers free hosting for web applications with Git-based deployment.
Why it is important: Render is more flexible than PythonAnywhere and supports a wider range of applications. It is a great next step.
Simple explanation: Render is like a modern apartment building ๐ข for your app. It is more advanced but still easy to use.
Steps to deploy:
pip install -r requirements.txt.gunicorn app:app.your-app.onrender.com.Important:
requirements.txt file.app.py and have
app = Flask(__name__).Real-life example: A startup deploys its API to Render.
School example: You deploy your group project to Render so everyone can test it.
Home example: You deploy a personal dashboard.
Nigerian example: A fintech startup uses Render for their API.
Illustration:
RENDER DEPLOYMENT
+-------------------------------------------------+
| 1. Push code to GitHub |
| 2. Connect GitHub to Render |
| 3. Set build and start commands |
| 4. Choose free plan |
| 5. Deploy! |
+-------------------------------------------------+
Mini summary: Render offers Git-based deployment for Flask apps. It is a modern, flexible platform with a free tier.
Definition: Environment variables are key-value pairs that store configuration settings outside your code. They are used for sensitive data like secret keys, API keys, and database URLs.
Why it is important: Hardcoding secrets in your code is dangerous. Environment variables keep them safe and make your app flexible.
Simple explanation: Imagine you have a secret password for your diary. You would not write it on the cover. Environment variables are like keeping the password in a locked drawer, not on the cover.
How to use environment variables:
import os
SECRET_KEY = os.environ.get('SECRET_KEY', 'fallback-key')
DATABASE_URL = os.environ.get('DATABASE_URL', 'sqlite:///app.db')
app.config['SECRET_KEY'] = SECRET_KEY
app.config['SQLALCHEMY_DATABASE_URI'] = DATABASE_URL
Setting environment variables:
.env file with
python-dotenv.
heroku config:set.
Real-life example: A banking app uses environment variables to store API keys for payment gateways.
School example: You store your project's secret key in
a .env file.
Home example: You keep your Wi-Fi password in a safe place, not written on the router.
Nigerian example: A fintech startup stores its API keys in environment variables, not in the code.
Illustration:
ENVIRONMENT VARIABLES
+-------------------------------------------------+
| SECRET_KEY = os.environ.get('SECRET_KEY') |
| DATABASE_URL = os.environ.get('DATABASE_URL') |
| Set in: |
| - Local: .env file |
| - PythonAnywhere: Web tab |
| - Render: Environment variables |
+-------------------------------------------------+
Mini summary: Environment variables keep sensitive configuration outside your code. They are essential for security and flexibility.
Definition: A requirements.txt file lists
all the Python packages your application needs. It is used by deployment
platforms to install dependencies.
Why it is important: Without a requirements file, your app will not work on the server because the dependencies are missing.
Simple explanation: Imagine you are moving to a new house. You make a list of all your furniture so you do not forget anything. A requirements file is like that list for your code's dependencies.
How to create a requirements file:
pip freeze > requirements.txt
Example requirements.txt:
flask==2.3.2
flask-sqlalchemy==3.0.5
flask-login==0.6.2
flask-wtf==1.1.1
werkzeug==2.3.6
gunicorn==21.2.0
python-dotenv==1.0.0
Real-life example: A developer creates a requirements.txt before deploying to ensure all dependencies are installed.
School example: You make a list of materials for a science project.
Home example: You write a shopping list before going to the market.
Nigerian example: A developer uses a requirements.txt to deploy a Flask app to a server.
Illustration:
REQUIREMENTS.TXT
+-------------------------------------------------+
| pip freeze > requirements.txt |
| Contents: |
| flask==2.3.2 |
| flask-sqlalchemy==3.0.5 |
| ... |
+-------------------------------------------------+
Mini summary: A requirements.txt file
lists all dependencies. It ensures your app runs correctly on any
server.
Definition: Docker is a tool that packages applications into containers. A container is like a lightweight, isolated environment that has everything your app needs to run.
Why it is important: Docker ensures your app runs the same way anywhere โ on your computer, on a server, or in the cloud. It solves the "it works on my machine" problem.
Simple explanation: Imagine you are going on a trip. You pack your suitcase with everything you need โ clothes, toiletries, snacks. Docker is like a suitcase for your app. It contains everything your app needs to run.
Key Docker concepts:
Example Dockerfile:
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
Real-life example: A company uses Docker to ensure its app runs the same on development, testing, and production servers.
School example: You use a container for your project so your teacher can run it without installing anything.
Home example: You use a pre-packed lunch box for work โ everything you need is inside.
Nigerian example: A startup uses Docker to deploy its app consistently across different servers.
Illustration:
DOCKER CONCEPT
+-------------------------------------------------+
| Dockerfile โ Build โ Image โ Run โ Container |
| (Instructions) (Snapshot) (Running instance) |
+-------------------------------------------------+
Mini summary: Docker packages your app and its dependencies into a container, ensuring it runs consistently anywhere.
Definition: Building a Docker image creates a snapshot of your application and its environment. You can then run containers from this image.
Why it is important: Once you have an image, you can run it anywhere Docker is installed, without worrying about setup.
Simple explanation: It is like taking a photograph of your entire setup โ code, libraries, and all โ so you can recreate it anywhere.
Steps to build and run:
Dockerfile in your project folder.docker build -t my-app .
docker run -p 5000:5000 my-app
Real-life example: A developer builds a Docker image of their app and shares it with the team.
School example: You create a portable version of your project that anyone can run.
Home example: You pack a travel bag with everything you need, so you are ready to go anywhere.
Nigerian example: A developer builds a Docker image of their API for deployment to a cloud server.
Illustration:
BUILDING A DOCKER IMAGE
+-------------------------------------------------+
| docker build -t my-app . |
| โ |
| Docker reads Dockerfile |
| โ |
| Docker creates an image |
| โ |
| docker run -p 5000:5000 my-app |
| โ |
| Your app is running in a container! |
+-------------------------------------------------+
Mini summary: Build a Docker image using a Dockerfile, then run it as a container. This makes your app portable and consistent.
Definition: CI/CD stands for Continuous Integration and Continuous Deployment. It is the practice of automatically building, testing, and deploying your code whenever you make changes.
Why it is important: CI/CD automates the process of getting code from development to production. It reduces errors and speeds up delivery.
Simple explanation: Imagine you have a factory assembling cars. Every time a new part (code change) arrives, the factory automatically puts it together (builds), checks it (tests), and delivers it to the showroom (deploys). That is CI/CD.
CI/CD stages:
Example with GitHub Actions:
name: CI/CD Pipeline
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest
- name: Deploy to Render
run: |
curl -X POST https://api.render.com/deploy/...
Real-life example: A tech company uses CI/CD to deploy updates to its app multiple times a day.
School example: You set up a system that automatically checks your homework and submits it.
Home example: You have a robot that automatically waters your plants when they need it.
Nigerian example: A startup uses CI/CD to deploy new features to their app quickly and reliably.
Illustration:
CI/CD PIPELINE
+-------------------------------------------------+
| Code push โ Build โ Test โ Deploy |
| (Git) (install (run (deploy to |
| deps) tests) server) |
+-------------------------------------------------+
Mini summary: CI/CD automates building, testing, and deploying your code. It speeds up development and reduces errors.
Definition: Monitoring is the process of tracking the health and performance of your application. Logging is recording events that happen in your application.
Why it is important: Once your app is deployed, you need to know if it is working correctly and what is happening when things go wrong.
Simple explanation: Imagine you are a pilot โ๏ธ. You have instruments (monitoring) that tell you if everything is okay, and you keep a logbook (logging) of all flights.
Monitoring tools:
Logging in your Flask app:
import logging
logging.basicConfig(level=logging.INFO)
@app.route('/')
def home():
app.logger.info('Home page accessed')
return "Hello, World!"
Real-life example: A website monitors its uptime and logs errors to fix them quickly.
School example: You check your grades regularly (monitoring) and keep a study log (logging).
Home example: You check your refrigerator temperature (monitoring) and keep a record of food expiry dates (logging).
Nigerian example: A business monitors its website uptime to ensure customers can always access it.
Illustration:
MONITORING AND LOGGING
+-------------------------------------------------+
| Monitoring: Checks if app is up and fast |
| Logging: Records what the app does |
| Together: Help you keep your app healthy |
+-------------------------------------------------+
Mini summary: Monitoring tracks your app's health, and logging records events. Both are essential for production applications.
Now we will combine everything you have learned in Level Two to build and deploy a complete application.
Scenario: A complete Task Management Application with:
Project Structure:
task_manager/
โโโ app.py
โโโ models.py
โโโ forms.py
โโโ templates/
โโโ static/
โโโ tests/
โโโ requirements.txt
โโโ Dockerfile
โโโ .github/workflows/ci.yml
โโโ .env.example
Key files:
app.py (simplified):
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-key')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///app.db')
db = SQLAlchemy(app)
login_manager = LoginManager(app)
# ... routes and models ...
Dockerfile:
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:5000"]
GitHub Actions workflow (.github/workflows/ci.yml):
name: CI/CD Pipeline
on:
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to Render
run: |
curl -X POST https://api.render.com/deploy/...
What we used:
Illustration:
FINAL PROJECT ARCHITECTURE
+-------------------------------------------------+
| Code โ GitHub โ CI/CD โ Docker โ Deploy |
| (Local) (Push) (Test) (Container) (Render) |
+-------------------------------------------------+
Mini summary: The final project combines all Level Two skills: Flask, APIs, databases, testing, Docker, CI/CD, and deployment. It is a complete, production-ready application.
| Word | Simple Definition |
|---|---|
| Deployment | Making your app available on the internet. |
| PythonAnywhere | A beginner-friendly hosting platform for Python apps. |
| Render | A modern cloud platform with free hosting. |
| Heroku | A popular cloud platform for web applications. |
| Environment Variables | Configuration values stored outside your code. |
| requirements.txt | A list of Python package dependencies. |
| Docker | A tool for packaging apps into containers. |
| Container | An isolated environment for running an application. |
| CI/CD | Continuous Integration and Continuous Deployment โ automated pipelines. |
| GitHub Actions | A CI/CD tool built into GitHub. |
| Monitoring | Tracking the health of your application. |
| Logging | Recording events that happen in your app. |
pip install -r requirements.txt).gunicorn app:app).your-app.onrender.com.FROM python:3.9-slim.WORKDIR /app.COPY requirements.txt ..RUN pip install -r requirements.txt.COPY . ..EXPOSE 5000.CMD ["python", "app.py"].| Mistake | How to Avoid It |
|---|---|
Forgetting to include requirements.txt |
Always generate and include a requirements file. |
| Hardcoding secret keys in code | Use environment variables for secrets. |
Not setting debug=False in production |
Set debug=False on the server. |
| Using a different Python version on server | Match your local Python version with the server version. |
| Not updating the database URL on deployment | Use environment variables for database URLs. |
| Forgetting to set environment variables on the platform | Set all required variables in the platform dashboard. |
| Not testing after deployment | Always test your deployed app to ensure it works. |
| Ignoring logs when things go wrong | Check server logs to debug deployment issues. |
requirements.txt file.
debug=False in production.
DEPLOYMENT FLOW
+-------------------------------------------------+
| Local Development โ Push to Git โ Deploy to |
| (Your computer) (GitHub) (PythonAnywhere, |
| Render, Heroku) |
+-------------------------------------------------+
ENVIRONMENT VARIABLES
+-------------------------------------------------+
| In your code: |
| SECRET_KEY = os.environ.get('SECRET_KEY') |
| In the platform: |
| SECRET_KEY = "your-secret-value" |
+-------------------------------------------------+
CI/CD PIPELINE
+-------------------------------------------------+
| Code Push โ Build โ Test โ Deploy |
| (GitHub) (Install (Run (Render/Heroku) |
| deps) tests) |
+-------------------------------------------------+
DOCKER CONTAINER
+-------------------------------------------------+
| Dockerfile โ Build โ Image โ Run โ Container |
| (Instructions) (Snapshot) (App running) |
+-------------------------------------------------+
FINAL PROJECT ARCHITECTURE
+-------------------------------------------------+
| Flask App โ Docker โ CI/CD โ Render |
| (Backend) (Container) (Automated) (Hosted) |
+-------------------------------------------------+
| Platform | Ease of Use | Free Tier | Best For |
|---|---|---|---|
| PythonAnywhere | Very Easy | Yes | Beginners, Flask apps |
| Render | Easy | Yes | Git-based deployment |
| Heroku | Easy | Yes (limited) | General web apps |
| AWS | Complex | Limited | Enterprise applications |
| Method | Advantages | Disadvantages |
|---|---|---|
| Manual Upload | Simple, full control | Time-consuming, error-prone |
| Git-based | Automated, versioned | Requires Git setup |
| Docker | Consistent, portable | Learning curve |
| CI/CD | Fully automated, reliable | Complex to set up |
Lesson 1 Summary: Deployment makes your app available on the internet.
Lesson 2 Summary: Platforms like PythonAnywhere and Render host your app.
Lesson 3 Summary: PythonAnywhere is beginner-friendly for Flask apps.
Lesson 4 Summary: Render offers Git-based deployment with a free tier.
Lesson 5 Summary: Environment variables keep secrets safe and make apps configurable.
Lesson 6 Summary: requirements.txt lists all dependencies.
Lesson 7 Summary: Docker packages apps into portable containers.
Lesson 8 Summary: Build a Docker image with a Dockerfile and run it.
Lesson 9 Summary: CI/CD automates build, test, and deploy.
Lesson 10 Summary: Monitoring and logging keep apps healthy in production.
Lesson 11 Summary: The final project combines all Level Two skills.
Congratulations! You have completed Module Eight โ the final module of Python Fundamentals Level Two ๐. You have learned how to take your applications from your computer to the world.
You now know how to deploy Flask apps to PythonAnywhere and Render. You use environment variables to keep your configuration safe, and requirements.txt to manage dependencies. You have learned the basics of Docker to package your apps into containers, and you understand the power of CI/CD pipelines to automate testing and deployment.
You also learned about monitoring and logging to keep your applications healthy in production. The final project brought together every skill you have learned in Level Two โ from building web apps and APIs to testing, containerization, and deployment.
You have completed the entire Python Fundamentals Level Two course. You are now a well-rounded Python developer who can build, test, and deploy real-world applications. This is a huge achievement. Be proud of yourself!
Where to go next? You can explore specialized areas like:
Keep building, keep deploying, and never stop learning. You have come so far. We are incredibly proud of you! ๐๐๐
requirements.txt file?
requirements.txt file?debug= __________.
requirements.txt file is optional. (True / False)environment.yml
requirements.txt
dependencies.txt
packages.txt
docker build
docker run
docker create
docker image
docker build
docker run
docker start
docker container
.env file?
Match the term on the left with its description on the right:
| Term | Description |
|---|---|
| 1. Deployment | A. Keeping secrets safe |
| 2. PythonAnywhere | B. Containerization tool |
| 3. Environment Variables | C. Lists dependencies |
| 4. requirements.txt | D. Beginner-friendly hosting |
| 5. Docker | E. Automates testing and deployment |
| 6. CI/CD | F. Making app available online |
| 7. Render | G. Modern hosting with free tier |
| 8. Monitoring | H. Tracks app health |
| 9. Logging | I. Records events |
Answers: 1-F, 2-D, 3-A, 4-C, 5-B, 6-E, 7-G, 8-H, 9-I
Scenario 1:
Ada has built a Flask app and wants to deploy it for free. She wants to use a platform that supports environment variables and Git-based deployment. Which platform should she use? Write the steps she should follow.
Scenario 2:
Chidi is deploying his app to Render, but it keeps crashing. He checks the logs and sees "ModuleNotFoundError: No module named 'flask'." What is the problem and how can he fix it?
Scenario 3:
Zainab wants to use GitHub Actions to test her code automatically whenever she pushes to the main branch. Write the GitHub Actions workflow YAML file for this.
Activity Title: Deploy a Group Project
Instructions:
requirements.txt file.Activity Title: Deploy Your Own App
Instructions:
requirements.txt file..env.example file showing required variables.Project Title: Deploy a Complete Web Application
Description:
Build and deploy a complete web application of your choice. The application should:
This project is the culmination of everything you have learned in Level Two. Build something you are proud of!
Assignment Title: Deploy an API with Docker and CI/CD
Instructions:
Dockerfile for the API.
Challenge Title: Deploy a Full-Stack Application with GitHub Actions
Build and deploy a full-stack application (Flask backend + React frontend) with a complete CI/CD pipeline. The application should:
This is a major challenge that combines everything you have learned in Level One and Level Two. It will test your ability to build, test, and deploy a complete, modern web application. Good luck!
Fill-in-the-Blank Answers:
requirements.txtTrue or False Answers:
Multiple Choice Answers:
Congratulations on completing Python Fundamentals Level Two! ๐ You have achieved a huge milestone. You are now a Python developer with a wide range of skills.
Here are some paths you can explore next:
No matter which path you choose, the skills you have learned in Level One and Level Two will serve as a strong foundation. Keep coding, keep building, and keep learning. The Python community is huge and welcoming.
We are incredibly proud of you. You have come so far. Now go out there and build something amazing! ๐๐๐
๐ End of Module Eight โ End of Python Fundamentals Level Two ๐