TechByteByByte

Modules, Packages and Environments

Learn how to organize Python code into modules and packages, manage dependencies with pip and virtual environments, and securely handle AI API keys using .env files.

#Python#Modules#Packages#Virtual Environments#API Keys#AI#Python for AI

The problem: A one-file experiment is easy to begin but difficult to grow. A real AI project needs organized code, reusable third-party libraries, repeatable dependency versions, changeable configuration, and API keys that are not pasted into source code.

What you will learn: You will separate modules, import packages, installable distributions, virtual environments, and environment variables. You will also see why a .env file helps local development but is neither encryption nor a production secret manager.


1. Modules

As a project grows, one file becomes difficult to understand. Python lets you divide it into named pieces and explicitly connect those pieces with imports.

application
   โ”œโ”€โ”€ imports cleaning.py
   โ”œโ”€โ”€ imports retrieval.py
   โ””โ”€โ”€ imports model_client.py

virtual environment โ†’ supplies this project's installed dependencies
environment variables โ†’ supply configuration and secrets at runtime

These ideas solve different problems: modules organize your code, packages group importable code, dependency tools install distributions, and virtual environments isolate one projectโ€™s versions from another project.

One File as a Reusable Unit

A module is simply a .py file โ€” any Python file can be imported and reused by another.

Why Code Is Split into Modules

One giant file becomes unmanageable fast. Splitting code into modules lets you organize by responsibility โ€” one file for API calls, one for preprocessing, one for prompts.

Picture Modules as Labeled Toolboxes

A module is a toolbox โ€” you keep related tools in one box, and grab the box (import) whenever you need those tools elsewhere.


2. import

import math

print(math.sqrt(16))

Expected Output:

4.0

๐Ÿค– How Is This Used in AI? Virtually every AI script starts with a block of imports:

import json
import os
from anthropic import Anthropic

3. from โ€ฆ import

from math import sqrt, pi

print(sqrt(25))
print(pi)

Expected Output:

5.0
3.141592653589793

๐Ÿง  Intuition: import math brings in the whole toolbox (you access tools as math.sqrt). from math import sqrt brings in just one tool, usable directly as sqrt(...).

๐Ÿค– How Is This Used in AI? Youโ€™ll constantly see patterns like:

from openai import OpenAI
from pydantic import BaseModel

pulling out exactly the class or function you need from a larger library.


4. Creating Your Own Modules

text_utils.py

def clean_text(text):
    return text.strip().lower()

def word_count(text):
    return len(text.split())

main.py

from text_utils import clean_text, word_count

text = "   Python is Great for AI   "
cleaned = clean_text(text)
print(cleaned)
print(word_count(cleaned))

Expected Output:

python is great for ai
5

๐Ÿค– How Is This Used in AI? Real AI projects split into files like prompts.py, llm_client.py, retrieval.py, config.py โ€” each a module that the main application imports and combines.

โš ๏ธ The Circular Import Trap As you split your code across more files, you might accidentally create a circular import. This happens when module_a.py imports something from module_b.py, while module_b.py simultaneously imports something from module_a.py.

When you run the code, Python gets stuck in a loop and throws: ImportError: cannot import name ... from ...

How to fix circular imports:

  1. Move imports inside functions: If module_a only needs module_b inside a specific function, import it inside that function rather than at the top of the file.
  2. Refactor common logic: Extract the shared code that both modules need into a third, separate module (e.g. utils.py) and have both import from there.

5. Packages

What Is It?

A package is a folder of modules, typically containing an __init__.py file, that can be imported as a single unit.

my_ai_app/
    __init__.py
    llm_client.py
    retrieval.py
    prompts.py
from my_ai_app.llm_client import call_model
from my_ai_app.retrieval import search_documents

๐Ÿ’ก Professional AI Project Directory Structure

In production, a standard AI application directory structure separates source logic, tests, and configurations clearly:

my_ai_project/
โ”‚
โ”œโ”€โ”€ .env                  # local API keys (ignored by git!)
โ”œโ”€โ”€ .gitignore            # specifies files to ignore (like .env and venv/)
โ”œโ”€โ”€ README.md             # project setup instructions
โ”œโ”€โ”€ requirements.txt      # list of project library dependencies
โ”œโ”€โ”€ main.py               # entrypoint script
โ”‚
โ”œโ”€โ”€ src/                  # all source code packages
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ client.py         # custom LLM SDK wrapper
โ”‚   โ”œโ”€โ”€ prompts.py        # prompt template configurations
โ”‚   โ””โ”€โ”€ pipeline.py       # main RAG execution steps
โ”‚
โ””โ”€โ”€ tests/                # unit and integration tests (Module 15)
    โ”œโ”€โ”€ __init__.py
    โ”œโ”€โ”€ test_pipeline.py
    โ””โ”€โ”€ test_client.py

๐Ÿง  Intuition: If a module is one toolbox, a package is a shelf of toolboxes, organized by category.

๐Ÿค– How Is This Used in AI? Libraries like langchain, openai, and anthropic are all packages โ€” folders full of organized modules you install and import from.


6. Virtual Environments

What Is It?

An isolated, self-contained Python installation for one specific project, so its dependencies donโ€™t clash with any other projectโ€™s.

Why Does It Exist?

Project A might need openai==1.2.0; Project B might need openai==2.0.0. Without isolation, installing one breaks the other.

๐Ÿง  Intuition

A virtual environment is a separate, sealed toolbox per project โ€” what you install for one project never leaks into or conflicts with another.

Syntax

python3 -m venv venv          # create a virtual environment named "venv"
source venv/bin/activate      # activate it (Mac/Linux)
venv\Scripts\activate         # activate it (Windows)

Once activated, anything you pip install goes into this projectโ€™s isolated environment only.

โš ๏ธ Common Beginner Mistake: Installing AI packages globally (without activating a virtual environment first) โ€” this works at first, but eventually causes version conflicts between unrelated projects that are painful to debug.


7. pip

What Is It?

Pythonโ€™s package installer โ€” how you download and install other peopleโ€™s code (like openai, anthropic, pandas, numpy).

pip install anthropic
pip install pandas numpy

๐Ÿค– How Is This Used in AI? Every AI project begins with installing the SDKs and libraries it depends on โ€” this is the very first command you run before writing a single line of AI code.


8. requirements.txt

What Is It?

A plain text file listing exactly which packages (and versions) a project needs โ€” so anyone else (or you, on a new machine) can recreate the same environment.

anthropic==0.34.0
pydantic==2.7.1
python-dotenv==1.0.1
pandas==2.2.2
pip install -r requirements.txt   # installs everything listed, all at once

๐Ÿง  Intuition: requirements.txt is a recipe card โ€” anyone who follows it ends up with the exact same set of ingredients (packages) you used.

๐Ÿค– How Is This Used in AI? Essential for reproducibility โ€” an AI pipeline that works on your machine should work identically on a teammateโ€™s machine or in production, and pinned versions in requirements.txt are how you guarantee that.

๐Ÿ’ก Generating your requirements file (pip freeze)

Instead of typing every library name and version by hand, you can ask pip to automatically export all packages currently installed in your active virtual environment.

Run this command in your terminal:

pip freeze > requirements.txt

This inspects your active environment and writes the exact list of packages and versions to requirements.txt in a single second.

Why is this extremely useful?

  • Saves Time and Prevents Typos: Typing package names and version strings manually is slow and error-prone.
  • Captures Transient Dependencies: If you install anthropic, it automatically installs other helper packages (like httpx, anyio, and sniffio). pip freeze lists every package in your environment, ensuring that teammates or production deployments replicate the exact environment down to the sub-dependencies.
  • Prevents โ€œWorks on My Machineโ€ Errors: Pinned exact versions (==) mean your code wonโ€™t suddenly break when external packages are updated in the future.

9. Environment Variables

What Is It?

Values stored outside your code, in the operating systemโ€™s environment, and read into your program at runtime.

import os

model_name = os.environ.get("MODEL_NAME", "gpt-4o-mini")   # fallback default
print(model_name)

๐Ÿง  Intuition: Think of environment variables as sticky notes on the computer itself, not inside your code โ€” your program can read them, but theyโ€™re never hardcoded into a file that might get shared or committed to version control.


10. .env Files

What Is It?

A file (named exactly .env) holding key-value pairs, typically loaded into environment variables at the start of a program using the python-dotenv package.

.env

ANTHROPIC_API_KEY=your_api_key_here
MODEL_NAME=claude-sonnet-4-6
MAX_TOKENS=500

main.py

from dotenv import load_dotenv
import os

load_dotenv()   # reads .env and loads its values as environment variables

api_key = os.environ.get("ANTHROPIC_API_KEY")
model_name = os.environ.get("MODEL_NAME")

print(model_name)
print(api_key[:6] + "..." if api_key else "No API key found")

Expected Output:

claude-sonnet-4-6
your_a...

How It Works

  • load_dotenv() reads the .env file and injects its values into os.environ, as if youโ€™d set them in the operating system directly.
  • os.environ.get(...) reads them back out โ€” with a default fallback if theyโ€™re missing.

11. Managing API Keys Securely

๐Ÿค– The AI-Specific Reason This Module Matters

Every LLM API call requires an API key โ€” a secret string that authenticates your requests and is tied to your (or your companyโ€™s) billing. If it leaks (e.g., committed to a public GitHub repo), someone else can rack up charges on your account, or worse.

The standard, safe pattern:

  1. Store real secrets only in a local .env file โ€” never in your actual .py code.
  2. Add .env to a .gitignore file so itโ€™s never committed to version control:
# .gitignore
.env
  1. Load it with load_dotenv() at the start of your program.
  2. Commit a .env.example file instead โ€” showing the shape without real values:
# .env.example
ANTHROPIC_API_KEY=your_api_key_here
MODEL_NAME=claude-sonnet-4-6
from dotenv import load_dotenv
from anthropic import Anthropic
import os

load_dotenv()
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
# client is now ready โ€” the real key never appeared anywhere in the code

โš ๏ธ Common Beginner Mistake:

client = Anthropic(api_key="sk-ant-abc123realkey...")   # NEVER do this

Hardcoding a real key means itโ€™s now permanently in your file history โ€” even if you delete the line later, it can often still be recovered from version control history. Always load secrets from the environment.

โœ… Key Takeaway: Code should describe behavior; secrets belong in the environment, never in the source code itself.

[!WARNING] Production Key Protection: Secret Scanning and Recovery Major code platforms (like GitHub and GitLab) run automated secret scanning crawlers that scan every commit the moment you push it. If you accidentally commit an API key (like an OpenAI, Anthropic, or Hugging Face key), it will be detected and usually disabled (revoked) by the platform within seconds to protect your billing.

If you do accidentally commit a secret, simply deleting it in a new commit does not remove it from your Git history. Anyone can look at your historical commits and find it. You must:

  1. Revoke the key immediately in the providerโ€™s developer console (e.g. OpenAI dashboard) and generate a new key.
  2. Use specialized Git purging tools (like git-filter-repo or BFG Repo-Cleaner) to completely wipe the secret from all historic commits in your repository.

Always double-check your .gitignore configuration contains .env before pushing your first commit!


Module, Package, and Distribution Are Different

  • A module is importable Python code, often one .py file.
  • An import package is a namespace that can contain modules and subpackages.
  • A distribution package is the installable project downloaded by a tool such as pip. Its install name and import name can differ; for example, a distribution can expose one or several import packages.

Use python -m pip install ... after activating the intended environment. This runs pip through that exact Python interpreter and reduces โ€œinstalled it, but Python cannot find itโ€ confusion.

Modern Project Metadata with pyproject.toml

Modern Python projects usually describe their build and direct dependencies in pyproject.toml:

[project]
name = "answer-checker"
version = "0.1.0"
dependencies = [
  "httpx>=0.27,<1",
  "pydantic>=2,<3",
]

[dependency-groups]
dev = ["pytest>=8,<9"]

Direct dependencies describe what the project needs. A lock file or a fully pinned environment snapshot records exact resolved versions for repeatable installation. pip freeze captures everything currently installed, including indirect packages, so it is not always the clearest hand-written dependency list.

A .env file is convenient for local development, but it is not encryption. Keep it out of version control. Deployed systems should normally receive secrets from the hosting platform or a secret manager, and leaked keys should be revoked and replaced immediately.

Module Summary

You can now split code across files and packages, isolate project dependencies with virtual environments, install and pin dependencies with pip and requirements.txt, and โ€” critically โ€” manage API keys and configuration securely using environment variables and .env files instead of hardcoding secrets into your code.

AI Connection

Every real AI project you build or work on will follow this exact structure: a virtual environment, a requirements.txt pinning your SDKs (anthropic, openai, pydantic, python-dotenvโ€ฆ), a .env file holding your real API key locally, and code that reads that key from the environment rather than containing it directly. This is the professional baseline every AI codebase is built on top of.

Mini Practice

  1. Create a small module prompt_utils.py with a build_prompt(context, question) function, then import and use it from a separate script.
  2. Write a .env.example file for a project that needs an API key, a model name, and a max token limit.
  3. Write code that loads a .env file and safely prints a masked version of an API key (first 4 and last 4 characters only).
  4. Write a requirements.txt for a project using anthropic, python-dotenv, and pydantic, with made-up but realistic version numbers.
  5. Explain, in your own words, why .env should be listed in .gitignore and what could go wrong if it isnโ€™t.

Next: Module 9 โ€” Python for Data and AI โ€” just enough NumPy and Pandas to work with embeddings and datasets.

Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed