Skip to content
beginner Phase 7 · Python Packages & Projects

Python Packages & Modules

Organize code into packages with __init__.py, imports, and namespaces.

45m
0 problems
Topic Progress 0%

Package Structure

What is a Package?

A package is a directory containing Python modules and a special __init__.py file.

my_package/
├── __init__.py          # Makes directory a package
├── module1.py           # Module
├── module2.py           # Another module
└── subpackage/          # Sub-package
    ├── __init__.py
    └── module3.py

init.py

# my_package/__init__.py

# Can be empty (marks directory as package)

# Or export specific names
from .module1 import MyClass
from .module2 import my_function

# Control what 'from my_package import *' imports
__all__ = ['MyClass', 'my_function']

Relative vs Absolute Imports

# Relative imports (from same package)
from . import module1           # Same directory
from .subpackage import module3  # Sub-directory
from .. import other_package    # Parent directory

# Absolute imports (recommended)
from my_package import module1
from my_package.subpackage import module3

# Best practice: Use absolute imports
# They're clearer and less prone to errors

Package Discovery

# Find packages in project
import pkg_resources

for dist in pkg_resources.working_set:
    print(dist.key, dist.version)

# Or using importlib
import importlib
import importlib.metadata

for dist in importlib.metadata.distributions():
    print(dist.metadata['Name'], dist.version)

pip Package Manager

Installing Packages

# Basic install
pip install requests

# Specific version
pip install requests==2.28.0

# Version constraints
pip install 'requests>=2.28,<3.0'

# Install from requirements.txt
pip install -r requirements.txt

# Install in development mode
pip install -e .

Managing Packages

# List installed packages
pip list

# Show package info
pip show requests

# Check for outdated packages
pip list --outdated

# Upgrade package
pip install --upgrade requests

# Uninstall
pip uninstall requests

Requirements Files

# Generate requirements.txt
pip freeze > requirements.txt

# Or using pipreqs (more accurate)
pipreqs . --force

# Install from requirements.txt
pip install -r requirements.txt

# Development requirements
pip install -r requirements-dev.txt

requirements.txt Example

# requirements.txt
requests==2.28.0
flask>=2.0,<3.0
python-dotenv==1.0.0
pytest>=7.0  # Comment: testing

# Install with:
# pip install -r requirements.txt

Package Indices

# PyPI (default)
pip install requests

# Private index
pip install --index-url https://pypi.mycompany.com/simple/ mypackage

# Multiple indices
pip install --extra-index-url https://pypi.mycompany.com/simple/ requests

Common pip Commands

# Search (deprecated, use pypi.org)
pip search requests

# Download without installing
pip download requests -d ./packages

# Install from local file
pip install ./requests-2.28.0.tar.gz

# Install from Git
pip install git+https://github.com/user/repo.git

# Install from specific branch
pip install git+https://github.com/user/repo.git@main

Creating Packages

Package Structure

my_package/
├── src/
│   └── my_package/
│       ├── __init__.py
│       ├── core.py
│       └── utils.py
├── tests/
│   ├── __init__.py
│   └── test_core.py
├── pyproject.toml
├── README.md
└── LICENSE

pyproject.toml (Modern)

# pyproject.toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-package"
version = "0.1.0"
description = "A short description"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.8"
dependencies = [
    "requests>=2.28",
    "click>=8.0",
]

[project.optional-dependencies]
development = [
    "pytest>=7.0",
    "black>=22.0",
    "mypy>=0.900",
]

[project.scripts]
my-cli = "my_package.cli:main"

setup.py (Legacy)

# setup.py
from setuptools import setup, find_packages

setup(
    name='my-package',
    version='0.1.0',
    packages=find_packages(where='src'),
    package_dir={'': 'src'},
    install_requires=[
        'requests>=2.28',
        'click>=8.0',
    ],
    extras_require={
        'dev': ['pytest>=7.0', 'black>=22.0'],
    },
)

Building and Publishing

# Install build tools
pip install build twine

# Build package
python -m build

# Check package
twine check dist/*

# Upload to PyPI
twine upload dist/*

# Or test on TestPyPI first
twine upload --repository testpypi dist/*

Versioning

# Semantic Versioning: MAJOR.MINOR.PATCH
# 1.0.0 -> 1.0.1 (bug fix)
# 1.0.1 -> 1.1.0 (new feature)
# 1.1.0 -> 2.0.0 (breaking change)

# In pyproject.toml
[project]
version = "1.2.3"

# Or dynamic versioning
[tool.setuptools_scm]

Best Practices

# ✅ Do:
# - Use pyproject.toml (modern)
# - Pin exact versions in requirements.txt
# - Use virtual environments
# - Write tests
# - Document your package
# - Follow PEP 8

# ❌ Don't:
# - Use setup.py alone (legacy)
# - Commit .pyc files
# - Include sensitive data
# - Use wildcard imports
# - Ignore dependency conflicts