Skip to content

Creating Your First Package

This tutorial walks you through creating a real-world Python application and packaging it with FlavorPack. We'll build a simple but useful CLI tool that fetches weather information.

What we'll build

A weather CLI tool that: - Accepts a city name as input - Fetches current weather data - Displays it in a formatted output - Works as a standalone executable

Step 1: Create the Application

Project Structure

Create a new directory for your project:

mkdir weather-cli
cd weather-cli

Write the Application Code

Create weather.py:

#!/usr/bin/env python3
"""
A simple weather CLI tool packaged with FlavorPack.
"""

import json
import sys
from urllib.request import urlopen
from urllib.parse import quote
from urllib.error import URLError, HTTPError


def get_weather(city: str) -> dict:
    """Fetch weather data for a given city."""
    # Using wttr.in service which doesn't require API keys
    url = f"https://wttr.in/{quote(city)}?format=j1"

    try:
        with urlopen(url) as response:
            return json.loads(response.read().decode('utf-8'))
    except HTTPError as e:
        if e.code == 404:
            print(f"❌ City '{city}' not found")
        else:
            print(f"❌ HTTP error: {e}")
        sys.exit(1)
    except URLError as e:
        print(f"❌ Network error: {e}")
        sys.exit(1)


def format_weather(data: dict, city: str) -> str:
    """Format weather data for display."""
    current = data['current_condition'][0]
    location = data['nearest_area'][0]

    output = []
    output.append("=" * 50)
    output.append(f"🌍 Weather for {location['areaName'][0]['value']}, "
                  f"{location['country'][0]['value']}")
    output.append("=" * 50)
    output.append(f"🌡️  Temperature: {current['temp_C']}°C ({current['temp_F']}°F)")
    output.append(f"🌤️  Condition: {current['weatherDesc'][0]['value']}")
    output.append(f"💨 Wind: {current['windspeedKmph']} km/h {current['winddir16Point']}")
    output.append(f"💧 Humidity: {current['humidity']}%")
    output.append(f"👁️  Visibility: {current['visibility']} km")
    output.append(f"🌡️  Feels like: {current['FeelsLikeC']}°C ({current['FeelsLikeF']}°F)")
    output.append("=" * 50)

    return "\n".join(output)


def main():
    """Main entry point for the weather CLI."""
    print("🌤️  Weather CLI - Powered by FlavorPack")
    print()

    if len(sys.argv) > 1:
        city = " ".join(sys.argv[1:])
    else:
        city = input("Enter city name: ").strip()

    if not city:
        print("❌ Please provide a city name")
        sys.exit(1)

    print(f"\nFetching weather for {city}...")

    weather_data = get_weather(city)
    print(format_weather(weather_data, city))
    print("\n✨ Packaged with FlavorPack - https://foundry.provide.io/flavorpack/")


if __name__ == "__main__":
    main()

Step 2: Create the Package Manifest

Create pyproject.toml:

[project]
name = "weather-cli"
version = "1.0.0"
description = "A simple weather CLI tool"
authors = [{name = "Your Name", email = "[email protected]"}]
requires-python = ">=3.11"
readme = "README.md"
license = {text = "MIT"}
keywords = ["weather", "cli", "tool"]
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]

# No external dependencies needed!
dependencies = []

[project.scripts]
weather = "weather:main"

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

[tool.flavor]
# FlavorPack-specific configuration
package_name = "weather-cli"
entry_point = "weather:main"

[tool.flavor.metadata]
# Additional metadata for the package
author = "Your Name"
website = "https://example.com"
support = "[email protected]"

[tool.flavor.build]
# Build configuration
include_patterns = [
    "*.py",
    "README.md",
    "LICENSE"
]
exclude_patterns = [
    "__pycache__",
    "*.pyc",
    ".git"
]

[tool.flavor.runtime]
# Runtime configuration
python_version = "3.11"
optimization_level = 2  # -OO flag for Python

Create a README

Create README.md:

# Weather CLI

A simple command-line weather tool packaged with FlavorPack.

## Usage

```bash
# Interactive mode
./weather-cli

# Direct mode
./weather-cli "New York"
./weather-cli London
./weather-cli "San Francisco"

Features

  • 🌡️ Real-time weather data
  • 🌍 Works for any city worldwide
  • 📦 Self-contained executable
  • 🔒 No API keys required

Built with FlavorPack - https://foundry.provide.io/flavorpack/

## Step 3: Build the Package

### Generate Signing Keys (Recommended)

```bash
# Generate keys for signing (one-time setup)
flavor keygen --output ./keys/

# You should see:
# ✅ Generated private key: keys/flavor-private.key
# ✅ Generated public key: keys/flavor-public.key

Create the Package

# Build the package with signing
flavor pack \
  --manifest pyproject.toml \
  --output weather-cli.psp \
  --private-key keys/flavor-private.key \
  --public-key keys/flavor-public.key

# For development (without signing)
flavor pack \
  --manifest pyproject.toml \
  --output weather-cli.psp \
  --key-seed development

You'll see output like:

🔍 Analyzing project: weather-cli
📦 Collecting dependencies...
🐍 Packaging Python runtime (3.11.9)...
📝 Creating package manifest...
🔨 Building PSPF package with rust-launcher...
🔐 Signing package...
✅ Package created successfully!

Package: weather-cli.psp
Size: 42.7 MB
Format: PSPF/2025
Launcher: rust-launcher-darwin_arm64
Slots: 2 (runtime + application)

Step 4: Test Your Package

Make It Executable

# On Unix-like systems
chmod +x weather-cli.psp

Run Your Package

# Test with different cities
./weather-cli.psp London

# Output:
# 🌤️  Weather CLI - Powered by FlavorPack
#
# Fetching weather for London...
# ==================================================
# 🌍 Weather for London, United Kingdom
# ==================================================
# 🌡️  Temperature: 15°C (59°F)
# 🌤️  Condition: Partly cloudy
# 💨 Wind: 10 km/h W
# 💧 Humidity: 72%
# 👁️  Visibility: 10 km
# 🌡️  Feels like: 14°C (57°F)
# ==================================================
#
# ✨ Packaged with FlavorPack - https://foundry.provide.io/flavorpack/

Try more examples:

./weather-cli.psp "New York"
./weather-cli.psp Tokyo
./weather-cli.psp "Rio de Janeiro"

Step 5: Distribute Your Package

Your weather-cli.psp file is now a completely self-contained executable that can be distributed to users.

Distribution Options

Upload to your website or file hosting:

# Users download and run
wget https://example.com/weather-cli.psp
chmod +x weather-cli.psp
./weather-cli.psp

Add to GitHub releases:

gh release create v1.0.0 weather-cli.psp \
  --title "Weather CLI v1.0.0" \
  --notes "First release of Weather CLI"

Future support planned for: - Homebrew (macOS/Linux) - Scoop (Windows) - Snap (Linux)

Verification

Users can verify package integrity:

# Verify the package is valid and signed
flavor verify weather-cli.psp --public-key keys/flavor-public.key

# Output:
# ✅ Package format valid
# ✅ Signature verified with provided key
# ✅ All checksums match
# ✅ Package integrity confirmed

Understanding What Happened

Package Contents

Your package contains:

  1. Native Launcher (~2 MB)
  2. Platform-specific executable
  3. Handles extraction and execution
  4. Performs signature verification

  5. Python Runtime (~35 MB)

  6. Complete Python 3.11 interpreter
  7. Standard library
  8. No system Python needed!

  9. Your Application (~5 MB)

  10. Your weather.py code
  11. Configuration files
  12. Any dependencies (none in this case)

How It Works

graph LR
    A[User runs weather-cli.psp] --> B[Native launcher starts]
    B --> C[Verify signature]
    C --> D[Extract to cache]
    D --> E[Setup Python environment]
    E --> F[Execute weather.py]
    F --> G[Display weather data]

Cache Management

FlavorPack uses smart caching:

# First run: Extracts to cache
./weather-cli.psp London  # ~500ms (extraction + execution)

# Subsequent runs: Uses cache
./weather-cli.psp Paris   # ~100ms (execution only)

# Cache location
~/.cache/flavor/workenv/weather-cli_1.0.0/

Next Steps

Enhance Your Package

Try these improvements:

  1. Add Dependencies

    dependencies = [
        "rich",  # For colored output
        "click", # For better CLI interface
    ]
    

  2. Add More Features

  3. Weather forecasts
  4. Multiple cities
  5. Export to JSON/CSV

  6. Optimize Size

    # Exclude unnecessary files
    flavor pack --exclude "tests/**" --exclude "docs/**"
    

Learn More

Troubleshooting

Package is too large
  • Use --exclude to skip unnecessary files
  • Consider using --compression for better compression
  • Use flavor inspect to see what's taking space
Network error when fetching weather
  • Ensure internet connection is available
  • Check if wttr.in service is accessible
  • Some corporate networks may block the service
Permission denied when running
  • Ensure the file has execute permissions: chmod +x weather-cli.psp
  • On macOS, you may need to remove quarantine: xattr -d com.apple.quarantine weather-cli.psp

Summary

Congratulations! You've successfully:

✅ Created a real-world Python application
✅ Configured it for FlavorPack packaging
✅ Built a self-contained executable
✅ Tested and verified the package
✅ Learned distribution strategies

Your weather CLI tool is now ready to share with the world - no installation required! 🎉