# Pipwatch

[![PyPI version](https://badge.fury.io/py/pipwatch.svg)](https://badge.fury.io/py/pipwatch)
[![CI](https://github.com/Felixdiamond/pipwatch/workflows/CI/badge.svg)](https://github.com/Felixdiamond/pipwatch/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

Detect import statements in Python files and install the corresponding PyPI packages.

Pipwatch parses your Python files for imports, filters out standard library modules, maps import names to PyPI package names where they differ (e.g. `PIL` to `pillow`, `cv2` to `opencv-python`), and installs whatever is missing.

## Features

### Import Detection
- Parses import statements using the AST module and filters out standard library modules
- Also detects `# pip install` comments and version specifiers in your code
- Maps import names to correct PyPI package names (e.g. `sklearn` -> `scikit-learn`)
- Skips packages that are already installed

### Mapping Registry
- Package mappings hosted on GitHub and fetched at runtime
- Local cache with 24-hour TTL so it doesn't hit the network on every run
- Falls back to bundled `mappings.json` when offline
- New mappings can be added via pull request

### CLI Flags
- `--dry-run` - Preview what would be installed without installing anything
- `--generate` - Generate a `requirements.txt` file from detected dependencies
- `--verbose` - Enable detailed debug logging
- `--yes` - Auto-confirm installations (useful for CI)
- `--output` - Specify custom output path for generated requirements files
- `--update-mappings` - Fetch latest mappings from GitHub
- `--clear-cache` - Clear cached mappings
- `--show-mappings` - Show mapping statistics

## Installation

```bash
pip install pipwatch
```

For development:
```bash
pip install pipwatch[dev]
```

## Usage

### Basic Usage

Analyze and install dependencies:
```bash
pipwatch script.py
```

### Dry Run (Preview Only)

See what would be installed without installing:
```bash
pipwatch script.py --dry-run
```

Example output:
```
INFO: Analyzing script.py...
INFO: Found the following dependencies from import statements:
INFO:   • bs4 → beautifulsoup4
INFO:   • numpy
INFO:   • pandas

[DRY RUN] Would install the following packages:
  • beautifulsoup4
  • numpy
  • pandas
```

### Generate Requirements File

Create a `requirements.txt` from your code:
```bash
pipwatch script.py --generate
```

Or with a custom output path:
```bash
pipwatch script.py --generate --output my-requirements.txt
```

### Auto-Install (No Prompts)

For automation and CI:
```bash
pipwatch script.py --yes
```

### Verbose Mode

Get detailed debug information:
```bash
pipwatch script.py --verbose
```

### Manage Mappings

Update mappings from GitHub:
```bash
pipwatch --update-mappings
```

Show mapping statistics:
```bash
pipwatch --show-mappings
```

Clear cached mappings:
```bash
pipwatch --clear-cache
```

## Package Name Mappings

Pipwatch includes 50+ mappings for cases where the import name differs from the PyPI package name:

| Import Name | Package Name |
|------------|--------------|
| `PIL` | `pillow` |
| `cv2` | `opencv-python` |
| `sklearn` | `scikit-learn` |
| `bs4` | `beautifulsoup4` |
| `yaml` | `pyyaml` |
| `Crypto` | `pycryptodome` |
| `jwt` | `PyJWT` |
| And more... | |

## How It Works

1. **Parse** - Parses your Python file using the AST module
2. **Filter** - Removes standard library imports
3. **Analyze** - Scans for `# pip install` comments and version specifiers
4. **Map** - Maps import names to PyPI package names
5. **Check** - Checks which packages are already installed
6. **Install/Generate** - Installs missing packages or generates `requirements.txt`

### Mapping Resolution

The mapping system loads from three sources, trying each in order:

```
┌─────────────────┐
│  mappings.json  │ (GitHub)
│   (Remote)      │
└────────┬────────┘
         │ Fetch (once per day)
         ▼
┌─────────────────┐
│  Local Cache    │ (~/.pipwatch/)
│  (24hr TTL)     │
└────────┬────────┘
         │ Fallback
         ▼
┌─────────────────┐
│  Bundled File   │ (Offline support)
│  (Built-in)     │
└─────────────────┘
```

### Contributing Mappings

Found a missing mapping? See [docs/CONTRIBUTING_MAPPINGS.md](docs/CONTRIBUTING_MAPPINGS.md) for how to add one.

## Development

### Setup

```bash
git clone https://github.com/Felixdiamond/pipwatch.git
cd pipwatch
pip install -e ".[dev]"
```

### Run Tests

```bash
pytest tests/
```

With coverage:
```bash
pytest tests/ --cov=src/pipwatch --cov-report=term-missing
```

### Code Formatting

```bash
black src/ tests/
isort src/ tests/
ruff check src/ tests/ --fix
```

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## License

[MIT License](LICENSE)

---

Created by [Felix Dawodu](https://github.com/Felixdiamond)
