Create symlinks to python package directories
Project description
pkglink
Create symlinks to python package directories from PyPI packages or GitHub repos into your current working directory.
This package provides a unified CLI with three complementary subcommands:
pkglink link: Access resources from any Python package or GitHub repopkglink tool: Make GitHub Python projectsuvx-compatible for CLI execution inside.pkglink/pkglink sync: Read project configuration frompkglink.config.yamland process multiple pkglink operations in staged batches
⚠️ Requirements
This tool requires uv to be installed on your system.
pkglink depends entirely on the uv package
manager for all installation and authentication tasks. uv handles:
- Package installation from PyPI
- GitHub repository handling
- Authentication for private repositories
- Dependency resolution and caching
- Environment isolation via
uvx
Install uv first:
# Install uv (see https://docs.astral.sh/uv/getting-started/installation/)
curl -LsSf https://astral.sh/uv/install.sh | sh
Overview
pkglink link
pkglink is a CLI tool designed for configuration sharing and quick access to
package resources. It allows you to symlink specific directories (like
resources, configs, templates) from Python packages directly into your
current directory without having to install them globally or manually download
files.
pkglink tool
pkglink tool is designed specifically for GitHub Python repositories. It
creates a .pkglink directory structure that makes any GitHub Python project
compatible with uvx for CLI tool execution, even if the project wasn't
originally designed for it.
pkglink sync
pkglink sync lets you define multiple resources and CLI packages inside a
pkglink.config.yaml file and execute them in three deterministic phases:
download, plan, and execute. The batch process downloads every package up front
(failing fast if any fetch errors occur), generates execution plans for each
entry, and finally runs all filesystem operations and post-install setup. This
keeps logs grouped by phase and ensures a partially completed batch never writes
to disk.
Installation
Using uvx (Recommended)
Once published, you can use both tools directly with uvx without installation:
# Use pkglink link for resource linking
uvx pkglink link --from tbelt toolbelt resources
# Use pkglink tool for GitHub repo CLI access
uvx pkglink tool github:org/awesome-cli-tool
# Then run the CLI tool
uvx --from .pkglink/awesome-cli-tool some-command
Local Installation
For development or repeated use:
pip install pkglink
Usage
pkglink link - Resource Linking
Basic Examples
# Symlink the 'resources' directory from 'mypackage'
pkglink link mypackage resources
# Use --from to install one package but link from another module
pkglink link --from tbelt toolbelt resources
# Specify a custom symlink name
pkglink link --symlink-name .configs mypackage configs
# Create symlinks inside .pkglink directory (unified with pkglink tool)
pkglink link --inside-pkglink --from tbelt toolbelt resources
# Dry run to see what would happen
pkglink link --dry-run mypackage templates
# Force overwrite existing symlinks
pkglink link --force mypackage resources
Command Line Options
source: The package to install (can be PyPI package or GitHub repo)directory: The subdirectory within the package to symlink (default: "resources")--from PACKAGE: Install one package but look for the module in another--symlink-name NAME: Custom name for the symlink (default:.{source})--inside-pkglink: Create symlink inside.pkglinkdirectory instead of current directory--force: Overwrite existing symlinks/directories--dry-run: Show what would be done without making changes--verbose: Enable verbose logging--no-setup: Skip running post-install setup (pkglink.yaml)
pkglink tool - GitHub CLI Tools
Basic Examples
# Make a GitHub repo uvx-compatible (basic usage)
pkglink tool github:org/awesome-cli-tool
# Then run CLI commands
uvx --from .pkglink/awesome-cli-tool some-command
# With specific version
pkglink tool github:org/tool@v1.2.0
# Skip resource linking (CLI tools only)
pkglink tool --skip-resources github:org/pure-cli-tool
# Custom resource directory and symlink name
pkglink tool -d configs -s .my-configs github:org/config-tool
Command Line Options
source: GitHub repository specification (github:org/repo[@version])-d, --directory: Target subdirectory to link (default: "resources")-s, --symlink-name: Name for the resource symlink (default:.{repo-name})--skip-resources: Skip creating resource symlinks--verbose: Enable verbose logging
Generated Structure
pkglink tool creates a structured .pkglink directory:
.pkglink/
├── awesome-cli-tool/ # Package directory
│ ├── pyproject.toml # Generated project file
│ ├── src/ # Source code symlink
│ │ └── awesome_cli_tool/ # → symlinked to cached package
│ └── .pkglink-metadata.yaml # Metadata for version tracking
└── .awesome-cli-tool # Resource symlink (if resources exist)
Note: If the target symlink already exists, pkglink will skip the
operation and exit successfully (unless --force is used). This makes it safe
to run in setup scripts multiple times.
pkglink sync - YAML Automation
pkglink sync reads link definitions from pkglink.config.yaml and executes
each one in three stages. Each link uses the same flags available on
pkglink link or pkglink tool, so you can mix resource links and .pkglink
uvx setups in one run.
Example pkglink.config.yaml
defaults:
inside_pkglink: true
directory: resources
links:
codeguide:
source: github:hotdog-werx/codeguide@topic/updates
project_name: codeguide
symlink_name: .codeguide
toolbelt-cli:
source: github:hotdog-werx/toolbelt@v0.0.1
from: tbelt
project_name: tbelt
inside_pkglink: false
skip_resources: true
Warning: Each link must resolve to a unique
project_nameandsymlink_name. If two entries collide,pkglink syncwill exit before downloading anything and list the duplicates so you can fix them safely.
Run the batch:
pkglink sync # reads pkglink.config.yaml in the current directory
The CLI will:
- Download every package (stop immediately if any download fails)
- Generate execution plans using the cached downloads
- Apply each plan and run
pkglink.yamlpost-install setup where applicable
Use pkglink sync --dry-run to preview all plans without touching the
filesystem. You can override the configuration path with
pkglink sync --config path/to/pkglink.config.yaml.
⚠️ Important Notes & Gotchas
GitHub Repository Naming
When using GitHub repositories, pkglink automatically converts repository
names from kebab-case (hyphens) to snake_case (underscores) to match
Python module naming conventions.
# Repository: github:org/my-awesome-package
# Python module: my_awesome_package
# This works automatically:
pkglink link github:org/my-awesome-package resources
# pkglink automatically looks for module 'my_awesome_package'
# If the auto-conversion doesn't match, use --from:
pkglink link --from github:org/repo-with-hyphens actual_module_name
Why this matters:
- GitHub repositories often use kebab-case:
my-package-name - Python modules must use snake_case:
my_package_name - Without conversion,
pkglinkwould look for the wrong module name
Examples:
github:org/data-science-toolkit→ looks for moduledata_science_toolkitgithub:org/ml-models→ looks for moduleml_modelsgithub:org/project-templates→ looks for moduleproject_templates
Advanced Usage
# GitHub repositories
pkglink user/repo configs
# Specific versions
pkglink link mypackage==1.2.0 resources
# With custom names and force overwrite
pkglink link --symlink-name .my-configs --force mypackage configs
# Skip post-install setup
pkglink link --no-setup mypackage resources
Post-Install Setup
pkglink supports automatic post-install setup through pkglink.yaml
configuration files. After creating the main symlink, pkglink will look for a
pkglink.yaml file in the linked directory and automatically create additional
symlinks as specified.
Configuration Format
Create a pkglink.yaml file in your package's resources directory:
symlinks:
- source: configs/.editorconfig
target: .editorconfig
- source: configs/.gitignore
target: .gitignore
- source: configs/pyproject.toml
target: pyproject.toml
Example Usage
For a package like codeguide with this structure:
codeguide/
└── resources/
├── pkglink.yaml
└── configs/
├── .editorconfig
├── .gitignore
└── pyproject.toml
Running pkglink link codeguide will:
- Create
.codeguide/symlink to the resources directory - Read
.codeguide/pkglink.yaml - Automatically create additional symlinks:
.editorconfig→.codeguide/configs/.editorconfig.gitignore→.codeguide/configs/.gitignorepyproject.toml→.codeguide/configs/pyproject.toml
Options
- Automatic: Post-install setup runs automatically when
pkglink.yamlexists - Skip: Use
--no-setupflag to disable post-install setup - Safe: Invalid configurations are logged but don't stop the main linking process
How It Works
pkglink leverages uv's powerful package management capabilities through its
uvx tool:
1. uvx Integration
- Package Installation: Uses
uvx(part ofuv) to install packages in isolated environments - Dependency Resolution: Leverages
uv's robust dependency handling and authentication - Environment Isolation: Each package gets proper isolation via
uvx - Authentication: Inherits all
uvauthentication for private repositories
2. Intelligent Caching
- Location:
~/.cache/pkglink/{package}_{hash}/ - Persistence: Survives
uvxcleanup operations - Performance: Subsequent runs are near-instantaneous
- Hash-based: Each unique package specification gets its own cache directory
3. Package Discovery
pkglink uses multiple strategies to find the correct package directory after
installation:
- Exact Match: Direct directory name matching
- Python Package Detection: Looks for directories with
__init__.py - Resource Directory Detection: Finds directories containing a
resourcesfolder - Prefix/Suffix Matching: Flexible name matching
- Similarity Matching: Fuzzy matching for close names
- Fallback: Uses the first suitable directory
Use Cases
Configuration Sharing (pkglink)
# Share configuration templates across projects
pkglink link --symlink-name .eslintrc my-configs eslint
pkglink link --symlink-name .github my-configs github-workflows
# Unified organization with pkglink tool
pkglink link --inside-pkglink --from tbelt toolbelt resources
Resource Access (pkglink)
# Access package resources for development
pkglink link --from data-science-toolkit datasets data
pkglink link ml-models pretrained
Template Management (pkglink)
# Quick access to project templates
pkglink link project-templates react
pkglink link --symlink-name .templates cookiecutter-templates django
CLI Tool Access (pkglink tool)
# Make any GitHub Python project usable as a CLI tool
pkglink tool github:microsoft/pylint-extensions
uvx --from .pkglink/pylint-extensions pylint --load-plugins=...
# Development tools
pkglink tool github:psf/black
uvx --from .pkglink/black black --version
# Custom CLI tools
pkglink tool github:myorg/internal-tool
uvx --from .pkglink/internal-tool tool-command --help
Unified Workflow
Both tools can work together for complete project setup:
# Set up CLI tools
pkglink tool github:org/awesome-linter
pkglink tool --skip-resources github:org/code-formatter
# Set up shared resources
pkglink link --inside-pkglink --from tbelt toolbelt resources
pkglink link --inside-pkglink my-configs eslint
# Now everything is organized under .pkglink/
ls .pkglink/
# awesome-linter/ code-formatter/ .tbelt/ .my-configs/
# Use the tools
uvx --from .pkglink/awesome-linter lint-code
uvx --from .pkglink/code-formatter format-code
Benefits
pkglink link
- Fast: Leverages
uvxcaching + additional persistent caching - Reliable: Uses
uv's robust package installation with multiple fallback strategies - Flexible: Supports PyPI packages, GitHub repos, and local paths
- Safe: Dry-run mode and intelligent conflict detection
- Organized: Optional
--inside-pkglinkfor unified structure with pkglink tool - Convenient: Can be used with
uvxwithout installation - Authenticated: Inherits all
uvauthentication for private repositories
pkglink tool
- Universal: Makes any GitHub Python project uvx-compatible
- Automatic: Generates proper
pyproject.tomlfrom package metadata - Cross-platform: Uses robust symlink creation with Windows fallback
- Version-aware: Tracks and refreshes mutable references (branches)
- Resource-friendly: Optional resource directory linking
- CLI-focused: Optimized for command-line tool usage
- Standards-compliant: Creates proper Python package structure
Combined
- Unified Organization: Both tools can create symlinks in
.pkglink/directory - Comprehensive: Covers both resource access and CLI tool execution
- Consistent: Shared authentication, caching, and safety features
- Scalable: Supports everything from single configs to complex multi-tool setups
Requirements
uv(required) - Handles all package installation and authentication- Python 3.11+
uvx(part ofuv, used for package installation)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pkglink-1.0.1.tar.gz.
File metadata
- Download URL: pkglink-1.0.1.tar.gz
- Upload date:
- Size: 34.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a2c6b562420561447ada1d35595181f3a2d0e1d03b7c06756cf334186e8bd33
|
|
| MD5 |
da6f3fd7056a4cd1ac9b8390ecf83669
|
|
| BLAKE2b-256 |
3058aee65a45bdd50dee7ea822ef35ad13c60eaffb5ddc574dc9cfbb039fc4a6
|
File details
Details for the file pkglink-1.0.1-py3-none-any.whl.
File metadata
- Download URL: pkglink-1.0.1-py3-none-any.whl
- Upload date:
- Size: 44.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29180915ffc9e7849588d8d280b1d6954d58e8f34f723a44911dd830df5a2e5c
|
|
| MD5 |
37dcf38c077540652d66ae4dce299e64
|
|
| BLAKE2b-256 |
479f7ba2bc4bb51829be023f98aeea3c6baeae0a301326d09525ce7639190c98
|