Dependency Management

PPM revolutionizes dependency management for polyglot projects by providing a unified interface for JavaScript and Python packages while maintaining the full power and compatibility of each ecosystem.

Core Concepts

Unified Configuration

Instead of managing separate package.json and requirements.txt files, PPM uses a single project.toml file:
[dependencies.js]
react = "^18.2.0"
axios = "^1.6.0"

[dependencies.python]
flask = "^3.0.0"
numpy = "^1.24.0"

Ecosystem Isolation

PPM maintains proper isolation between language ecosystems:
  • JavaScript packagesnode_modules/ directory
  • Python packages → Virtual environment (.venv/ or custom location)
  • No cross-contamination between package managers

Smart Resolution

PPM intelligently resolves dependencies:
  1. Analyzes your project structure
  2. Detects language-specific files (package.json, requirements.txt)
  3. Merges configurations when importing existing projects
  4. Maintains compatibility with existing toolchains

Installation Process

How ppm install Works

1

Environment Detection

PPM scans your project to understand the structure:
  • Checks for existing package.json or requirements.txt
  • Identifies language-specific directories
  • Detects Node.js and Python versions
2

Environment Setup

For JavaScript:
  • Uses existing node_modules/ or creates new one
  • Respects .nvmrc or Node.js version constraints
For Python:
  • Creates virtual environment (.venv/ by default)
  • Uses specified Python version or system default
  • Activates environment for all Python operations
3

Dependency Installation

Parallel Installation:
  • JavaScript packages installed via npm/yarn/pnpm
  • Python packages installed via pip
  • Both processes run simultaneously for speed
4

Lock File Generation

  • Generates ppm.lock with exact dependency tree
  • Includes both JavaScript and Python package versions
  • Ensures reproducible builds across environments

JavaScript Dependencies

Package Manager Support

PPM supports all major JavaScript package managers:
Package ManagerDetectionUsage
npmpackage-lock.jsonDefault choice
Yarnyarn.lockAutomatic detection
pnpmpnpm-lock.yamlAutomatic detection

Version Specifications

PPM supports standard npm semantic versioning:
[dependencies.js]
# Exact version
react = "18.2.0"

# Caret range (compatible within major)
vue = "^3.3.0"

# Tilde range (compatible within minor)
lodash = "~4.17.21"

# Version ranges
typescript = ">=4.5.0 <6.0.0"

# Latest version
axios = "latest"

# Git repositories
my-private-lib = "git+https://github.com/user/repo.git"

# Local file paths
local-utils = "file:../shared-utils"

Scoped Packages

Handle scoped packages with proper quoting:
[dependencies.js]
"@types/node" = "^20.0.0"
"@mui/material" = "^5.14.0"
"@testing-library/react" = "^13.0.0"

Development Dependencies

Separate production and development dependencies:
[dependencies.js]
react = "^18.2.0"
axios = "^1.6.0"

[dev-dependencies.js]
typescript = "^5.0.0"
vite = "^5.0.0"
"@types/react" = "^18.2.0"
eslint = "^8.50.0"
prettier = "^3.0.0"

Python Dependencies

Version Constraints

PPM supports PEP 440 version specifiers:
[dependencies.python]
# Exact version
django = "4.2.5"

# Compatible release (tilde operator)
requests = "~=2.31.0"

# Minimum version
numpy = ">=1.24.0"

# Version exclusion
pillow = ">=9.0.0,!=9.1.0"

# Caret-style (PPM extension for familiarity)
flask = "^3.0.0"  # Equivalent to ">=3.0.0,<4.0.0"

Package Extras

Include optional dependencies with extras:
[dependencies.python]
# Simple extras
requests = { version = "^2.31.0", extras = ["security"] }

# Multiple extras
django = { version = "^4.2.0", extras = ["bcrypt", "argon2"] }

# Complex specifications
sqlalchemy = { 
  version = "^2.0.0", 
  extras = ["postgresql", "asyncio"],
  markers = "python_version >= '3.8'"
}

Development Dependencies

[dependencies.python]
flask = "^3.0.0"
pandas = "^2.0.0"

[dev-dependencies.python]
pytest = "^7.4.0"
black = "^23.0.0"
mypy = "^1.5.0"
flake8 = "^6.0.0"
pytest-cov = "^4.1.0"

Virtual Environment Management

PPM automatically manages Python virtual environments:
[python]
version = "3.11"              # Prefer specific Python version
venv_dir = ".venv"           # Virtual environment directory
requirements_file = "requirements.txt"  # Legacy requirements file

Dependency Resolution

Conflict Resolution

When conflicts arise, PPM provides intelligent resolution:
PPM uses npm’s resolution algorithm:
[dependencies.js]
react = "^18.2.0"
some-lib = "^1.0.0"  # Requires react@^17.0.0
Resolution:
  • PPM installs React 18.2.x as primary dependency
  • some-lib gets React 17.x in its own dependency tree
  • No conflict due to npm’s nested dependency structure
Python uses flat dependency resolution:
[dependencies.python]
package-a = "^1.0.0"  # Requires numpy>=1.20.0
package-b = "^2.0.0"  # Requires numpy>=1.24.0
Resolution:
  • PPM installs numpy 1.24.x (satisfies both requirements)
  • Reports successful resolution
  • Warns if no compatible version exists
Some packages exist in both ecosystems:
[dependencies.js]
moment = "^2.29.0"

[dependencies.python]
moment = "^0.12.0"  # Different package!
Resolution:
  • Each package manager handles its own namespace
  • No conflicts between different ecosystems
  • PPM tracks versions separately

Dependency Updates

Keep dependencies up to date:
# Check for outdated packages
ppm outdated

# Update all dependencies
ppm update

# Update specific packages
ppm update react flask

# Update to latest versions
ppm update --latest

Lock Files and Reproducibility

Lock File Format

PPM generates a comprehensive lock file:
# ppm.lock
[metadata]
version = "1.0.0"
generated_at = "2024-01-15T10:30:00Z"

[javascript]
package_manager = "npm"
node_version = "18.17.0"

[javascript.packages]
react = { version = "18.2.0", resolved = "https://registry.npmjs.org/react/-/react-18.2.0.tgz" }
axios = { version = "1.6.0", resolved = "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz" }

[python]
python_version = "3.11.5"
pip_version = "23.2.1"

[python.packages]
flask = { version = "3.0.0", hash = "sha256:abc123..." }
numpy = { version = "1.24.4", hash = "sha256:def456..." }

Reproducible Builds

Ensure identical environments across systems:
# Install exact versions from lock file
ppm install --frozen

# Verify environment matches lock file
ppm verify

# Update lock file without installing
ppm lock --update

Advanced Features

Custom Package Sources

Configure private registries:
[sources]
[sources.js]
registry = "https://npm.internal.company.com/"
token = "${NPM_TOKEN}"  # Environment variable

[sources.python]
index_url = "https://pypi.internal.company.com/simple/"
extra_index_urls = [
  "https://pypi.org/simple/",
  "https://download.pytorch.org/whl/cpu"
]

Environment-Specific Dependencies

Different dependencies for different environments:
[environments.development]
[environments.development.dependencies.js]
react = "^18.2.0"
"@hot-loader/react-dom" = "^17.0.0"

[environments.development.dependencies.python]
flask = "^3.0.0"
flask-debugtoolbar = "^0.13.0"

[environments.production]
[environments.production.dependencies.js]
react = "18.2.37"  # Exact versions in production

[environments.production.dependencies.python]
flask = "3.0.0"
gunicorn = "^21.0.0"

Dependency Analysis

Analyze your dependency tree:
# Show dependency tree
ppm tree

# Find duplicate packages
ppm duplicates

# Analyze bundle size (JavaScript)
ppm analyze --js

# Security audit
ppm audit

# License compliance
ppm licenses

Migration Strategies

From Existing Projects

Import from existing dependency files:
# Import from package.json
ppm import --from package.json

# Import from requirements.txt
ppm import --from requirements.txt

# Import from both
ppm import --from package.json --from requirements.txt

# Merge with existing project.toml
ppm import --merge

Gradual Migration

Migrate large projects incrementally:
1

Start with PPM

ppm init --force
ppm import --from package.json --from requirements.txt
2

Verify Compatibility

ppm install
ppm run test  # Ensure everything works
3

Update Workflows

Replace existing scripts with PPM commands:
[scripts]
install = "ppm install"
dev = "ppm run dev"
test = "ppm run test"
build = "ppm run build"
4

Clean Up

# Remove old files (backup first!)
mv package.json package.json.bak
mv requirements.txt requirements.txt.bak

Best Practices

Dependency Organization

  1. Group related packages together with comments:
    [dependencies.js]
    # Core framework
    react = "^18.2.0"
    react-dom = "^18.2.0"
    
    # Routing and state management
    react-router-dom = "^6.15.0"
    "@tanstack/react-query" = "^4.35.0"
    
    # UI components
    "@mui/material" = "^5.14.0"
    
  2. Pin exact versions in production environments
  3. Use ranges for development to catch compatibility issues early
  4. Regular dependency updates with proper testing
  5. Security scanning as part of CI/CD pipeline

Performance Optimization

  1. Parallel installation (PPM does this automatically)
  2. Dependency caching in CI/CD systems
  3. Selective installation for specific environments
  4. Bundle analysis for JavaScript applications

PPM’s dependency management eliminates the complexity of polyglot projects while maintaining full compatibility with existing package managers and workflows. The unified approach saves time, reduces errors, and improves team productivity.