- Advanced Python Programs
- Advanced Python Programs - Home
Python Basics
- Introduction and Setup
- Create a system info collector CLI using platform, sys, and psutil.
- Build a virtual environment manager using venv and subprocess.
- Script to generate a project folder with auto README, .gitignore, and starter script.
- Python version compatibility checker for scripts (uses ast, tokenize).
- Auto-install missing modules when ImportError is detected.
- Create a startup script that logs Python path, version, and user info.
- Build a tool to compare two Python environments (pip freeze diff).
- Script to automate code linting, formatting (using black, flake8, isort).
- Develop a python --info clone that shows detailed interpreter config.
- Set up and test a pyproject.toml file for a sample module.
- Package a module and publish it to TestPyPI.
- Script to check environment memory usage while loading modules.
- Write a Python script that upgrades all installed packages safely.
- Program to back up and restore .py and .ipynb files in a directory.
- Use argparse to build a multi-command CLI utility tool.
- Compare CPython vs PyPy performance on a benchmark task.
- Automate logging and error capturing for all first-time scripts.
- Build a script to run code snippets interactively with audit logging.
- Create a "Getting Started Wizard" for first-time learners.
- Write a Python sandbox that runs code with restricted permissions.
- Variables and Data Types
- Implement dynamic type conversion using regex rules on string inputs.
- Auto-detect and correct mistyped literals (e.g., "5.0O" → "500").
- Create a type-tracer that logs type transitions across operations.
- Build a system to simulate memory-efficient representations (bitfields).
- Write a program that deep-checks nested data structure types.
- Simulate real-time data stream type validation using decorators.
- Create a tool that visualizes Python object memory layout.
- Build a mini schema validator for data (like JSON schema).
- Explore data coercion rules (like float+int, str*int) with examples.
- Type-safe expression evaluator (add type checks to an eval function).
- Program to convert mixed-type lists to homogeneous types.
- Create custom class TypeEnforcer to reject illegal type assignments.
- Dynamic variable inspector CLI using locals() and globals().
- Use mypy and typing to enforce type hints and generate reports.
- Build a program that tracks how often each data type is used.
- Create a symbolic type system to simulate type inference.
- Program to clean and standardize inconsistent data types in a CSV.
- Visualize type distributions in a dataset using a pie chart.
- Parse and evaluate expressions based on runtime-detected types.
- Use metaclasses to auto-type-check class properties.
- Operators
- Create a visual operator precedence tester with expressions.
- Implement a full infix → postfix → result evaluator using stack.
- Write a symbolic math engine using operator overloading.
- Build a spreadsheet-style formula evaluator supporting cells.
- Implement a binary expression tree from math strings.
- Create a vector class that supports all mathematical operators.
- Overload operators to simulate a Matrix class (with +, *, etc.).
- Build a simulator for circuit logic (AND, OR, NOT using bitwise ops).
- Create a filter expression parser (e.g., "age>30 and score<=80").
- Build a secure math expression evaluator (no eval()).
- Compare expression results across float/int/bool for precision.
- Implement a mini-language interpreter using custom operators.
- Develop a program to visualize operator evaluation order.
- Create a complex number calculator using class and operator overloading.
- Simulate a search engine filter logic using boolean operators.
- Build a finance calculator for tax slabs (tiered with conditions).
- Use bitwise operators to encode/decode permissions (Unix-style).
- Test short-circuit evaluation with custom objects and logs.
- Build a CLI tool that runs operator tests on user input.
- Create a GUI-based calculator supporting all operator types.
- Input and Output (Advanced)
- Build a CLI form handler that saves data in JSON/XML/CSV.
- Real-time data logger from user input to rotating file logs.
- Input validator that uses regex, length, type, and range checks.
- Password input tool with masking and strength meter.
- Create a reusable interactive menu system.
- Build a resume-builder CLI that outputs to Markdown and PDF.
- Implement a chatbot-like input collector with context.
- Save formatted user input into Excel using openpyxl.
- Use input() to take dynamic Python code and safely evaluate.
- Read and parse structured data input (YAML, XML).
- Create a console wizard that guides users through data entry.
- CLI survey that outputs charts of responses using matplotlib.
- Create a tool to validate and clean bulk data from user entries.
- Prompt user for input and send it via POST request to an API.
- Record input sessions and save as log with timestamps.
- Create a pseudo form validator with input loop + correction.
- Build a terminal app that accepts file paths and processes them.
- Develop a custom input prompt framework with templates.
- Validate and enrich contact details entered by the user (name/email).
- Build a script that generates a config file based on user inputs.
Module 2: Control Structures
- Conditional Statements
- Custom Grading System – Assign letter grades with optional GPA scale.
- Tax Calculator – Slab-based income tax with deductions and surcharges.
- Loan Eligibility Checker – Based on salary, credit score, age.
- Nested Condition Analyzer – Debug tool to visualize if-elif-else flow.
- Advanced BMI Categorizer – Classify health risk using BMI + age + gender.
- Eligibility Checker for Competitive Exams – Uses multiple nested conditions.
- Age-based Access Control System – Assign privileges by age groups.
- Custom Rule Engine – Accepts user-defined conditions and evaluates.
- Dynamic If-Else Generator – Take user conditions and generate Python code.
- Compare 3 or More Objects (Scores, Distances) – With tie-break logic.
- Medical Diagnosis Rule Checker – Use conditions to suggest possible symptoms.
- Electricity Bill Estimator – Different rates for tiers of usage.
- Scholarship Eligibility Calculator – Uses multi-param criteria.
- Compare Dates or Time Intervals – Determine recency, time left, etc.
- Smart Calculator with Conditional Error Checks – e.g., divide-by-zero, invalid op.
- Credit Card Approval Simulator – Based on income, age, history.
- Multi-Language Greeting System – Based on input locale.
- Dynamic Pricing Model – Based on season, demand, location.
- Insurance Premium Estimator – Based on driver’s profile.
- Hotel Room Assignment Logic – Based on group size and preferences.
- Looping Statements - (for, while)
- Pattern Generator Engine – Choose shape, size, and symbol.
- Sudoku Grid Validator – Iterate through rows, cols, and subgrids.
- Prime Number Counter with Stats – Count, sum, mean of all primes in range.
- Progress Bar Animation in Terminal – Simulated loading loop.
- Calendar Renderer – Print calendar view using nested loops.
- Reverse Multiplication Table Generator – From N to 1 in rows.
- Factorial Table Generator – Show factorials of first N numbers.
- User Login System with Retry Limit – Allow 3 attempts.
- Simulate Bank ATM Menu – Loop with transaction types.
- Loop-Based Art Generator (ASCII) – Complex figures using logic.
- Iterate Over Nested JSON – Parse and print key-value tree.
- Custom Loop Breaker – Use input to break or continue dynamically.
- Dynamic Loop Builder from Text Input – Convert plain rules to loops.
- Pyramid Pattern with Alphabets or Numbers – Custom alignment.
- User Polling System – Loop to take repeated survey inputs.
- Fibonacci Sequence Analyzer – Find nth term, sum, average.
- Interactive Flashcards in a Loop – Present until mastery.
- Simulation: Car Fuel Consumption Until Empty – Break loop at 0.
- Calculate Compound Interest Year by Year – Show yearly breakdown.
- Time Tracker: Display Clock Every 1 Sec – Stop after N seconds.
- Loop Control Statements (break, continue, pass)
- Password Validator with Break on Success – Retry until valid input.
- Loop Skipping Specific Conditions – e.g., skip weekends in date loop.
- Data Cleaning with Continue – Skip invalid rows in list of dicts.
- Game Menu Loop with Break to Exit – Continue looping until “exit”.
- Log Scanner: Stop at First Error Entry – Demonstrate break.
- Prime Finder with Pass Placeholder for Future Optimizations.
- Custom Retry Mechanism with Break and Counter.
- Loop Through Sensor Data – Continue if Reading < Threshold.
- Shopping Cart Simulator – Exit loop when budget exhausted.
- Pass as Empty Handler in Function Loops.
- Email List Parser – Skip Invalid Emails using Continue.
- For-Else Loop Example – Search for Item, Confirm if Not Found.
- Simulate Elevator Stops – Skip Out-of-Order Floors.
- Simulate Turn-Based Game – Use Continue for Skipped Turn.
- Log Parser with Multiple Exit Conditions.
- Interactive Quiz – Break After 3 Wrong Answers.
- Random Number Generator – Pass if Even, Stop on Divisible by 7.
- Skip Comments While Reading a File.
- Fast Search in Dataset – Break on First Match, Pass on Errors.
- Infinite Menu Loop with Controlled Break.
Module 3: Functions and Recursion
- Defining and Calling Functions
- Function to Auto-Format Report Cards – Accepts data and prints styled output.
- Keyword-Only Argument Enforcer – Prevents positional usage.
- Function to Summarize Dataset – Mean, median, mode, range with *args.
- Create a Function Registry – Dynamically register callable functions.
- Function that Returns Multiple Statistical Results – e.g., mean, std, var.
- Decorator-Free Memoization with Function Wrapping.
- Factory Function That Returns Specialized Functions.
- Function Call Logger with Timestamps (using datetime).
- Function that Accepts Another Function and Logs Its Output.
- Multiple Argument Handling with Type Enforcement.
- Build a Secure Eval Function That Limits Scope.
- Dynamic Function Calling from a String (using globals()).
- Function to Perform Chained Transformations on Text.
- Higher-Order Function: Accepts Sorting Rule as Function.
- Create a Timer Wrapper for Any Callable.
- Function to Recursively Flatten Nested Lists.
- Function that Builds Markdown Tables from Nested Lists.
- Function to Convert Dictionary to Query String.
- Function with Dynamic Default Value Generator.
- Function Comparison Tool (compares logic by AST).
- Arguments and Parameters
- Function to Accept Unlimited Named Arguments and Return JSON.
- Create a Flexible Currency Converter Using **kwargs.
- Dynamic Calculator Function Using *args.
- Logger Function That Accepts Log Type and Metadata as kwargs.
- Function That Accepts Rules and Applies to List (like filter).
- Build Function Dispatcher with Argument Inspection.
- Convert Flat Args into Nested Dictionary Structure.
- Type Annotated Function With Runtime Type Checking.
- Argument Handler for CLI Tools Using argparse.
- Simulate API Call Signature with Optional/Required Parameters.
- Build Template Renderer Using Named Placeholders.
- Create Default Parameter Based on Other Inputs.
- Use inspect to Analyze Function Parameters.
- Function that Accepts Inputs from YAML File and Executes Task.
- Dynamic Field Validator Function With Rules Passed as kwargs.
- Named Parameter Resolver With Defaults and Fallbacks.
- Function With Error Reporting for Each Argument.
- Parameter Flattening Utility Function.
- Function Overloader That Chooses by Argument Count.
- Smart Validator With Switchable Rules via kwargs.
- Lambda, map, filter, reduce
- Use map to Clean, Normalize, and Standardize CSV Data.
- Use filter to Remove Incomplete or Corrupt Records.
- Use reduce to Perform Cumulative Summation of Dataset.
- Use Lambda for Dynamic Sorting Rules (length, frequency, etc.).
- Lambda for Generating Fibonacci Sequence in List Comprehension.
- Custom Lambda-Based Encryption for Strings.
- Pipeline System Using map → filter → reduce on JSON Records.
- Lambda to Validate Form Fields Based on Type Rules.
- Chained Lambdas for Text Cleanup: Lowercase → Strip → Replace.
- Use map to Apply Markdown Formatting to a List of Strings.
- Use reduce to Calculate GCD/LCM of List of Integers.
- Use filter to Extract Users Over Age X with Score > Y.
- Lambda to Simulate Expression Evaluator (a op b).
- Create a Decorator That Replaces Function With a Lambda Dynamically.
- Create Nested Lambda for Polynomial Functions.
- Sort List of Dicts Using Lambda Keys with Fallbacks.
- Use map to Reformat Date Strings in Data.
- Build a Text Summarizer Using Lambda to Reduce Sentences.
- Lambda-Based Unit Converter Factory.
- Function to Create Lambda Chains Dynamically from Configs.
- Recursion
- Recursive Directory Scanner – Walks file system like os.walk().
- Recursive Tree Printer – For nested dictionaries or JSON structures.
- Recursively Flatten Any Nested List/Dict Structure.
- Solve Tower of Hanoi Problem and Print Steps.
- Find All Subsets (Power Set) of a Given List.
- Generate All Permutations of a String Recursively.
- Recursively Reverse a Linked List (or simulate with list).
- Solve a Maze Path Using Recursion and Backtracking.
- Binary Search Implementation (Recursive).
- Parse Nested Mathematical Expression (e.g., "3(2+1)").*
- Recursive Fibonacci with Memoization.
- Sudoku Solver Using Recursive Backtracking.
- Recursively Evaluate a JSON Rule Engine.
- Generate Pascal’s Triangle Recursively.
- Simulate File Copying with Nested Folders Recursively.
- Count Leaf Nodes in a Tree Represented with Nested Lists.
- Solve N-Queens Problem Using Recursion.
- Recursive Web Crawler (Limit by Depth).
- Expression Tree Evaluation Recursively.
- Recursive Palindrome Checker with Substring Reduction.
Advanced Python Programs
![]() Share with a Friend |
Introduction and Setup
Package a module and publish it to TestPyPI - Advanced Python Program
Prereqs: Python 3.10+,
pip install psutil black flake8 isort twine build rich
(some scripts also use colorama or tomllib on <3.11).
The program below is a complete, safe, and practical Python script that:
- Creates a sample package (module) with a pyproject.toml using PEP 621,
- Builds sdist and wheel using python -m build,
- Uploads the artifacts to TestPyPI using python -m twine upload (supports environment credentials or interactive prompt),
- Optionally verifies the upload by creating a temporary venv and installing the package from TestPyPI and importing it.
I include the full script, example outputs (what you’ll see), and a detailed step-by-step explanation of what each part does and why.
Important: This script does not publish anything without your explicit approval (you must provide credentials or allow the tool to prompt). Use TestPyPI for testing — it’s separate from the real PyPI. Do not put real production credentials here.
File Name: package_and_publish_testpypi.py
File Name : package_and_publish_testpypi.py
#!/usr/bin/env python3
"""
package_and_publish_testpypi.py
Create a sample package (pyproject.toml + module), build distributions, upload to TestPyPI,
and optionally verify installation from TestPyPI.
Usage examples:
# Create project and build artifacts only (no upload)
python package_and_publish_testpypi.py create MyPkg --version 0.1.0 --no-upload
# Create, build and upload to TestPyPI (will prompt for credentials if none in env)
python package_and_publish_testpypi.py create MyPkg --version 0.1.0
# Create with unique timestamped version, upload, and verify install
python package_and_publish_testpypi.py create MyPkg --unique --upload --verify
Notes:
- Requires `build` and `twine` installed (pip install build twine).
- For uploading via an API token set:
TWINE_USERNAME="__token__"
TWINE_PASSWORD="<pypi-AgENd...>" (the API token value)
Or the script will prompt you for username & password.
"""
from __future__ import annotations
import argparse
import getpass
import os
import subprocess
import sys
import tempfile
import time
from datetime import datetime
from pathlib import Path
from typing import Optional, Tuple
# ----------------------------
# Templates for the sample package
# ----------------------------
PYPROJECT_TPL = """[build-system]
requires = ["setuptools>=61", "wheel", "build"]
build-backend = "setuptools.build_meta"
[project]
name = "{name}"
version = "{version}"
description = "{description}"
readme = "README.md"
authors = [{{name = "{author}", email = "{email}"}}]
requires-python = ">=3.8"
license = {{text = "MIT"}}
keywords = ["sample", "test", "example"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
]
"""
INIT_PY_TPL = '''"""
{pkg} — a tiny example package created by package_and_publish_testpypi.py
"""
__all__ = ["hello"]
__version__ = "{version}"
def hello(name: str) -> str:
"""Return a friendly greeting"""
return f"Hello, {name}!"
'''
README_TPL = "# {name}\n\n{description}\n\nInstall from TestPyPI for verification."
GITIGNORE = """# Python caches
__pycache__/
*.py[cod]
# build artifacts
dist/
build/
*.egg-info/
# virtualenv
.venv/
"""
LICENSE_TPL = """MIT License
Copyright (c) {year} {author}
Permission is hereby granted, free of charge, to any person obtaining a copy...
"""
# ----------------------------
# Helpers
# ----------------------------
def run(cmd: list, cwd: Optional[Path] = None, capture: bool = False) -> Tuple[int, str]:
"""Run a command; return (rc, stdout+stderr)."""
try:
if capture:
out = subprocess.check_output(cmd, cwd=str(cwd) if cwd else None, stderr=subprocess.STDOUT, text=True)
return 0, out
else:
subprocess.check_call(cmd, cwd=str(cwd) if cwd else None)
return 0, ""
except subprocess.CalledProcessError as e:
return e.returncode, (e.output or "")
except FileNotFoundError as e:
return 127, str(e)
def ensure_tool_available(module_name: str, human_cmd_description: str) -> None:
"""
Ensure 'python -m module_name --version' succeeds. If not, prompt user to install it into current env.
"""
rc, out = run([sys.executable, "-m", module_name, "--version"], capture=True)
if rc != 0:
print(f"[!] Tool '{module_name}' is required ({human_cmd_description}).")
yn = input(f"Install '{module_name}' into the current interpreter now? [y/N]: ").strip().lower()
if yn not in ("y", "yes"):
print("[!] Aborting. Install the tool manually and re-run.")
sys.exit(1)
print(f"[*] Installing {module_name}...")
rc2, out2 = run([sys.executable, "-m", "pip", "install", module_name], capture=True)
if rc2 != 0:
print("[!] Failed to install", module_name)
print(out2)
sys.exit(rc2)
print(f"[+] Installed {module_name}.")
def write_sample_project(root: Path, name: str, version: str, description: str, author: str, email: str) -> None:
"""Create project skeleton and small module under root."""
root.mkdir(parents=True, exist_ok=True)
(root / "pyproject.toml").write_text(PYPROJECT_TPL.format(name=name, version=version, description=description, author=author, email=email), encoding="utf-8")
(root / "README.md").write_text(README_TPL.format(name=name, description=description), encoding="utf-8")
(root / ".gitignore").write_text(GITIGNORE, encoding="utf-8")
(root / "LICENSE").write_text(LICENSE_TPL.format(year=datetime.utcnow().year, author=author), encoding="utf-8")
pkg_dir = root / name
pkg_dir.mkdir(exist_ok=True)
(pkg_dir / "__init__.py").write_text(INIT_PY_TPL.format(pkg=name, version=version), encoding="utf-8")
print(f"[+] Created project skeleton at {root.resolve()}")
print(" files: pyproject.toml, README.md, LICENSE, .gitignore, package directory")
def build_distributions(project_dir: Path) -> None:
"""Run python -m build to create sdist & wheel in dist/"""
print("[*] Building distributions with 'python -m build' ...")
rc, out = run([sys.executable, "-m", "build", "--sdist", "--wheel"], cwd=project_dir, capture=True)
if rc != 0:
print("[!] Build failed:")
print(out)
sys.exit(rc)
print(out)
print("[+] Build completed. Check the 'dist/' directory.")
def upload_to_testpypi(project_dir: Path, username: Optional[str], password: Optional[str], repository_url: str = "https://test.pypi.org/legacy/") -> None:
"""
Upload all files in dist/ to TestPyPI using twine. Credentials may be provided via args or environment.
Environment variables TWINE_USERNAME/TWINE_PASSWORD take precedence if set.
"""
env_user = os.environ.get("TWINE_USERNAME")
env_pass = os.environ.get("TWINE_PASSWORD")
if env_user:
print("[i] Using TWINE_USERNAME from environment.")
username = env_user
if env_pass:
password = env_pass
if not username:
username = input("TestPyPI username (or '__token__' if using API token): ").strip()
if not password:
password = getpass.getpass("TestPyPI password or API token: ")
# Use python -m twine upload --repository-url <url> dist/*
cmd = [sys.executable, "-m", "twine", "upload", "--repository-url", repository_url, "dist/*"]
print("[*] Uploading to TestPyPI (this will prompt Twine for credentials unless provided via env)...")
# Provide credentials as TWINE_USERNAME/TWINE_PASSWORD env for the subprocess
env = os.environ.copy()
env["TWINE_USERNAME"] = username
env["TWINE_PASSWORD"] = password
# Run twine as subprocess with env
try:
subprocess.check_call(cmd, cwd=str(project_dir), env=env)
except subprocess.CalledProcessError as e:
print("[!] Twine upload failed with exit code", e.returncode)
sys.exit(e.returncode)
print("[+] Upload to TestPyPI complete.")
def verify_install_from_testpypi(package_name: str, version: str) -> None:
"""
Create a temporary venv, pip install the package from TestPyPI, and try to import it.
This helps confirm your package is available and importable.
"""
print("[*] Verifying installation from TestPyPI in a temporary venv...")
tmpdir = Path(tempfile.mkdtemp(prefix="tpypi-verify-"))
venv_dir = tmpdir / "venv"
# create venv
subprocess.check_call([sys.executable, "-m", "venv", str(venv_dir)])
# determine python path
if os.name == "nt":
py = venv_dir / "Scripts" / "python.exe"
else:
py = venv_dir / "bin" / "python"
py = str(py)
# install from TestPyPI (no deps) to ensure we pull exactly the uploaded artifact:
index_url = "https://test.pypi.org/simple/"
pkg_spec = f"{package_name}=={version}"
cmd_install = [py, "-m", "pip", "install", "--index-url", index_url, "--no-deps", pkg_spec]
print(f"[*] Installing {pkg_spec} from TestPyPI into {venv_dir} ...")
rc, out = run(cmd_install, capture=True)
if rc != 0:
print("[!] pip install from TestPyPI failed:")
print(out)
print("You may need to wait a minute for TestPyPI to index the package, or check that the upload succeeded.")
sys.exit(rc)
print(out)
# try importing and calling hello()
cmd_run = [py, "-c", f"import {package_name}; print('IMPORT_OK:', {package_name}.hello('Tester'))"]
rc2, out2 = run(cmd_run, capture=True)
if rc2 != 0:
print("[!] Import test failed:")
print(out2)
sys.exit(rc2)
print(out2.strip())
print("[+] Verification SUCCEEDED. Temporary venv at:", venv_dir)
print("[i] Remove it when done:", tmpdir)
# ----------------------------
# CLI
# ----------------------------
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(description="Create a sample package, build, and publish to TestPyPI")
p.add_argument("action", choices=["create"], help="Action to perform (create builds and optionally uploads)")
p.add_argument("name", help="Package name (must be a valid distribution name, e.g. mypkg)")
p.add_argument("--version", default="0.1.0", help="Initial version (default: 0.1.0)")
p.add_argument("--description", default="A sample test package", help="Short description")
p.add_argument("--author", default=getpass.getuser() or "You", help="Author name")
p.add_argument("--email", default="", help="Author email")
p.add_argument("--unique", action="store_true", help="Append timestamp to version to ensure uniqueness (useful for repeated TestPyPI uploads)")
p.add_argument("--no-upload", dest="upload", action="store_false", help="Do not upload to TestPyPI (just build)")
p.add_argument("--upload", dest="upload", action="store_true", help="Upload to TestPyPI after building (default)")
p.add_argument("--verify", action="store_true", help="After upload, attempt to pip install from TestPyPI and import")
p.add_argument("--skip-tool-check", action="store_true", help="Skip checking for build/twine and skip auto-install prompt")
return p
def main(argv: Optional[list] = None) -> None:
args = build_parser().parse_args(argv)
if args.action != "create":
print("[!] Only 'create' action is supported in this script.")
sys.exit(1)
name = args.name.strip()
version = args.version.strip()
if args.unique:
version = f"{version}.post{int(time.time())}"
project_dir = Path(name)
if project_dir.exists():
print(f"[!] Directory '{project_dir}' already exists. Remove it or choose another name.")
sys.exit(1)
# 1) Create skeleton
write_sample_project(project_dir, name, version, args.description, args.author, args.email)
# 2) Ensure build & twine are available (unless skipped)
if not args.skip_tool_check:
ensure_tool_available("build", "create source & wheel distributions ('python -m build')")
ensure_tool_available("twine", "upload distributions ('python -m twine upload')")
# 3) Build distributions
build_distributions(project_dir)
# 4) Optionally upload to TestPyPI
if args.upload:
# Credentials may be provided via env; user will be prompted if not present
upload_to_testpypi(project_dir, username=None, password=None)
# 5) Optionally verify installation
if args.upload and args.verify:
# Wait a moment for TestPyPI to process the upload (small sleep helps typical cases)
print("[i] Waiting a few seconds to allow TestPyPI to index the package...")
time.sleep(3)
verify_install_from_testpypi(name, version)
print("[+] All done. Project dir:", project_dir.resolve())
if __name__ == "__main__":
main()
What the script does — short summary
- Create a minimal project folder with:
- pyproject.toml (PEP 621 metadata),
- a package folder mypkg/__init__.py with a hello() function,
- README.md, .gitignore, LICENSE.
- Ensure build and twine are available (optionally installing them if the user agrees).
- Build wheel and sdist: runs python -m build --sdist --wheel and writes artifacts to dist/.
- Upload to TestPyPI: runs python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*, using credentials from TWINE_USERNAME/TWINE_PASSWORD or prompting.
- Verify (optional): creates a temp venv, installs the just-uploaded package from TestPyPI and imports it, executing hello() to confirm.
Example run (expected console output)
These outputs are illustrative — your local build / twine text may vary.
Build only (no upload)
$ python package_and_publish_testpypi.py create samplepkg --version 0.1.0 --no-upload
[+] Created project skeleton at /home/alice/samplepkg
files: pyproject.toml, README.md, LICENSE, .gitignore, package directory
[*] Building distributions with 'python -m build' ...
* Creating venv isolated environment
* Building sdist
* Building wheel
Successfully built samplepkg-0.1.0-py3-none-any.whl
[+] Build completed. Check the 'dist/' directory.
[+] All done. Project dir: /home/alice/samplepkg
Build + upload to TestPyPI (interactive credential prompt)
$ python package_and_publish_testpypi.py create samplepkg --unique
[+] Created project skeleton at /home/alice/samplepkg
files: ...
[*] Installing build (if missing)... # if it was missing and user allowed install
[*] Building distributions with 'python -m build' ...
... build output ...
[+] Build completed. Check the 'dist/' directory.
[i] Using TWINE_USERNAME from environment. # if TWINE_USERNAME set
[*] Uploading to TestPyPI (this will prompt Twine for credentials unless provided via env)...
Uploading distributions to https://test.pypi.org/legacy/
Uploading samplepkg-0.1.0.post1630000000.tar.gz
100% 5.00k/5.00k [00:01<00:00, 4.20kB/s]
Uploading samplepkg-0.1.0.post1630000000-py3-none-any.whl
100% 10.0k/10.0k [00:01<00:00, 9.50kB/s]
View at https://test.pypi.org/project/samplepkg/0.1.0.post1630000000/
[+] Upload to TestPyPI complete.
[+] All done. Project dir: /home/alice/samplepkg
Upload + verify install
$ python package_and_publish_testpypi.py create samplepkg --unique --verify ... build output ... [*] Uploading to TestPyPI ... ... twine output ... [+] Upload to TestPyPI complete. [i] Waiting a few seconds to allow TestPyPI to index the package... [*] Verifying installation from TestPyPI in a temporary venv... [*] Installing samplepkg==0.1.0.post1630000000 from TestPyPI into /tmp/tpypi-verify-xxxxx ... Collecting samplepkg==0.1.0.post1630000000 Downloading samplepkg-0.1.0.post1630000000-py3-none-any.whl (10 kB) Successfully installed samplepkg-0.1.0.post1630000000 IMPORT_OK: Hello, Tester! [+] Verification SUCCEEDED. Temporary venv at: /tmp/tpypi-verify-xxxxx [+] All done. Project dir: /home/alice/samplepkg
Security & practical notes
- Use TestPyPI for testing — it's separate from real PyPI.
- Credentials:
- Best practice: create an API token in TestPyPI and set TWINE_USERNAME="__token__" and TWINE_PASSWORD="<token value>" in your environment. This avoids entering your account password.
- Do not paste secrets into shared consoles or commit them to code.
- Unique versions: If you upload the same version twice to TestPyPI, it will be rejected. Use --unique to append a timestamp to the version (handy for repeated tests).
- Delay for indexing: sometimes TestPyPI takes a short moment to index uploaded files — if verify fails, wait a minute and try again.
- Permissions: If you run pip install or python -m build in system Python and you don't have write access, use virtualenv or run in a venv.
- Reality check: This script runs tools (build, twine) as subprocesses, so it relies on those tools' behavior. The script checks tools and offers to install them into the current interpreter if missing.
Step-by-step code explanation
I'll explain the main logical parts of the script in order:
1) Templates & project layout
- PYPROJECT_TPL — PEP 621 toml with build-system declaring build and setuptools & wheel, and project metadata (name, version, description, author).
- INIT_PY_TPL — the package py containing hello() and __version__.
- README_TPL, .gitignore, LICENSE — small supportive files.
2) run() helper
- Runs arbitrary shell commands (subprocess) and returns (rc, output); capture=True returns combined stdout+stderr; otherwise it streams output to terminal.
3) ensure_tool_available()
- Checks python -m <module> --version; if not found or failing, prompts user to install it into the current interpreter using pip install <module>. This helps avoid manual setup friction. The check can be skipped via --skip-tool-check.
4) write_sample_project()
- Creates the folder structure and writes the files. This ensures the project is buildable with python -m build.
5) build_distributions()
- Runs python -m build --sdist --wheel in the project dir. This produces dist/ with .tar.gz and .whl.
6) upload_to_testpypi()
- Reads credentials from environment (TWINE_USERNAME, TWINE_PASSWORD) if present, otherwise prompts the user. It then runs python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/* with those credentials set in the subprocess environment. This avoids exposing the password in command-line arguments.
Note: for token uploads, set TWINE_USERNAME="__token__" and TWINE_PASSWORD="<actual-token-value>".
7) verify_install_from_testpypi()
- Creates a temporary venv, installs the just-uploaded package from TestPyPI using pip with --index-url https://test.pypi.org/simple/ --no-deps and then imports the package inside that venv and calls the hello() function to confirm the package installs and works.
8) CLI wiring (argparse) and flow (main)
- Parses options: create name, --version, --unique, --no-upload, --verify, etc.
- Ensures project folder does not already exist to avoid overwriting.
- Writes the skeleton, ensures tools exist (unless skipped), builds, optionally uploads and verifies.
Final tips before you run
1. Install helper tools first (recommended):
pip install build twine
2. Create a TestPyPI account and optionally an API token: https://test.pypi.org/account/token/ Then export credentials (safer than interactive prompt):
export TWINE_USERNAME="__token__" export TWINE_PASSWORD="pypi-AgENd...your-token-here..."
3. Run the script:
python package_and_publish_testpypi.py create mysample --unique --upload --verify
