0 to Infinity Lesson

Publish Your Python Module on PyPI

A complete practical lesson made from our real packaging journey: checking the name learnwithchampak, creating the project, building the wheel, uploading to TestPyPI, fixing token mistakes, and preparing for real PyPI.

Final learner goal
pip install learnwithchampak
python
>>> from learnwithchampak import hello
>>> print(hello("Champak"))
0. Big Picture1. Project Structure2. Code Files3. Build4. TestPyPI5. Real PyPI6. Screenshot Walkthrough

0. What is PyPI?

PyPI means Python Package Index. It is the public package library used by pip. TestPyPI is a separate practice server where you can safely test uploads before publishing the final package.

Checkpoint: At the end, your package should install using pip install learnwithchampak from real PyPI. During practice it installs from TestPyPI.

1. Create the project

In our example, the folder is D:\champak-ai-ml\learnwithchampak.

cd D:\champak-ai-ml
pip index versions learnwithchampak
md learnwithchampak
cd learnwithchampak

If pip index versions says no matching distribution was found, the name is probably free. For the first real release, PyPI may still apply extra name rules.

mkdir src
mkdir src\learnwithchampak
mkdir tests

Expected structure

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

2. Write the package code

Create the empty files:

type nul > pyproject.toml
type nul > README.md
type nul > LICENSE
type nul > src\learnwithchampak\__init__.py
type nul > src\learnwithchampak\core.py
type nul > tests	est_core.py
code .

core.py

def hello(name: str = "World") -> str:
    return f"Hello, {name}! Welcome to Learn With Champak."

__init__.py

from .core import hello

__version__ = "0.1.0"

pyproject.toml

[build-system]
requires = ["setuptools>=69", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "learnwithchampak"
version = "0.1.0"
description = "Python learning utilities by Champak Roy."
readme = "README.md"
requires-python = ">=3.8"
license = { text = "MIT" }
authors = [
  { name = "Champak Roy" }
]
keywords = ["python", "education", "learning", "programming"]
classifiers = [
  "Development Status :: 3 - Alpha",
  "Intended Audience :: Education",
  "Programming Language :: Python :: 3",
  "License :: OSI Approved :: MIT License",
  "Operating System :: OS Independent"
]

[project.urls]
Homepage = "https://learnwithchampak.live"
Repository = "https://github.com/programmer-s-picnic/learnwithchampak"

[tool.setuptools.packages.find]
where = ["src"]

3. Test locally and build

python -m venv .venv
.venv\Scriptsctivate
pip install -e .
python
from learnwithchampak import hello
print(hello("Champak"))
Checkpoint: You should see Hello, Champak! Welcome to Learn With Champak.
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*

The build should create:

dist/learnwithchampak-0.1.0.tar.gz
dist/learnwithchampak-0.1.0-py3-none-any.whl

4. Upload to TestPyPI

TestPyPI and PyPI are separate. A real PyPI token will not work on TestPyPI.

  1. Create a TestPyPI account.
  2. Enable two-factor authentication.
  3. Create an API token.
  4. For the first upload, choose Entire account scope.
python -m twine upload --repository-url https://test.pypi.org/legacy/ -u __token__ -p "PASTE_TESTPYPI_TOKEN" dist/*
Security warning: Do not paste real tokens in screenshots, chat messages, or public code. If a token is exposed, revoke it immediately and create a new one.

Common 403 Forbidden causes

ProblemFix
Used real PyPI token on TestPyPICreate token from test.pypi.org
Typed token as usernameUsername must be __token__
Used project-scoped token before project existsUse entire-account token for first upload
Copied only part of tokenCopy full token beginning with pypi-

5. Install from TestPyPI, then publish to real PyPI

pip uninstall learnwithchampak
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple learnwithchampak
python
>>> from learnwithchampak import hello
>>> print(hello("Champak"))

After TestPyPI works, create a token on the real PyPI site and upload:

python -m twine upload --repository-url https://upload.pypi.org/legacy/ -u __token__ -p "PASTE_REAL_PYPI_TOKEN" dist/*
Final checkpoint: After real upload succeeds, anyone can run pip install learnwithchampak.

6. Screenshot walkthrough

These screenshots show the real journey. Sensitive tokens and recovery code files were not included in the lesson package.

Screenshot 0

Check whether the package name is available

We use pip index versions learnwithchampak. If no matching distribution is found, the name is probably free, though PyPI can still block reserved or conflicting names.

Check whether the package name is available screenshot
Screenshot 1

Create the project folder

The project name is learnwithchampak. On PyPI the install name and Python import name can be the same when the package name has no hyphen.

Create the project folder screenshot
Screenshot 2

Enter the folder

Work from inside the root folder so every file is created in the correct place.

Enter the folder screenshot
Screenshot 3

Create src and tests folders

The src layout prevents accidental imports from the project root and is now a clean packaging habit.

Create src and tests folders screenshot
Screenshot 4

Verify the folder in Explorer

A visual check is useful for beginners: src and tests should exist beside pyproject.toml and README.md.

Verify the folder in Explorer screenshot
Screenshot 5

Prepare package files

Inside src/learnwithchampak, create __init__.py and core.py. These make the actual importable package.

Prepare package files screenshot
Screenshot 6

Create top-level files

pyproject.toml, README.md, LICENSE and test files are created from the terminal.

Create top-level files screenshot
Screenshot 7

Return to the prompt

After files are created, the project is ready to open in Visual Studio Code or another editor.

Return to the prompt screenshot
Screenshot 8

Open the project in Visual Studio Code

Use code . to edit the package files, README, and build configuration comfortably.

Open the project in Visual Studio Code screenshot
Screenshot 9

Install build and twine

Build creates distribution files. Twine checks and uploads those files to TestPyPI or PyPI.

Install build and twine screenshot
Screenshot 10

Build the package

python -m build creates a source distribution and wheel inside the dist folder.

Build the package screenshot
Screenshot 11

Check the package

twine check dist/* verifies that the package metadata and README rendering are acceptable.

Check the package screenshot
Screenshot 12

Upload to TestPyPI and fix authentication problems

403 errors usually mean wrong token, real PyPI token used on TestPyPI, missing __token__ username, or project-scoped token before the project exists. The final upload in this screenshot succeeds. Token text has been redacted.

Upload to TestPyPI and fix authentication problems screenshot
Screenshot 13

Install from TestPyPI

After successful upload, install from TestPyPI and test the function from a clean environment.

Install from TestPyPI screenshot

7. Version updates: 0 to Infinity habit

Every time you improve the module, increase the version number in pyproject.toml and __init__.py, delete old build files, rebuild, check, and upload.

rmdir /s /q dist build src\learnwithchampak.egg-info
python -m build
python -m twine check dist/*
python -m twine upload dist/*