Pywharf
The private PyPI server powered by flexible backends.
Install / Use
/learn @pywharf/PywharfREADME
pywharf
The private PyPI server powered by flexible backends.
</div>What is it?
pywharf allows you to deploy a PyPI server privately and keep your artifacts safe by leveraging the power (confidentiality, integrity and availability) of your storage backend. The backend mechanism is designed to be flexible so that the developer could support a new storage backend at a low cost.
Supported backends:
- GitHub. (Yes, you can now host your Python package in GitHub by using
pywharf. ) - File system.
- ... (Upcoming)
Design
<div align="center"><img width="766" alt="Screen Shot 2020-03-24 at 8 19 12 PM" src="https://user-images.githubusercontent.com/5213906/77424853-c14e0480-6e0c-11ea-9a7f-879a68ada0a0.png"></div>The pywharf server serves as an abstraction layer between Python package management tools (pip/poetry/twine) and the storage backends:
- Package management tools communicate with
pywharfserver, following PEP 503 -- Simple Repository API for searching/downloading package, and Legacy API for uploading package. pywharfserver then performs file search/download/upload operations with some specific storage backend.
Usage
Install from PyPI
pip install pywharf==0.2.3
This should bring the execuable pywharf to your environment.
$ pywharf --help
SYNOPSIS
pywharf <command> <command_flags>
SUPPORTED COMMANDS
server
update_index
github.init_pkg_repo
github.gen_gh_pages
Using the docker image (recommended)
Docker image: pywharf/pywharf:0.2.3. The image tag is the same as the package version in PyPI.
$ docker run --rm pywharf/pywharf:0.2.3 --help
SYNOPSIS
pywharf <command> <command_flags>
SUPPORTED COMMANDS
server
update_index
github.init_pkg_repo
github.gen_gh_pages
Run the server
To run the server, use the command pywharf server.
SYNOPSIS
pywharf server ROOT <flags>
POSITIONAL ARGUMENTS
ROOT (str):
Path to the root folder. This folder is for logging,
file-based lock and any other file I/O.
FLAGS
--config (Optional[str]):
Path to the package repository config (TOML),
or the file content if --config_or_admin_secret_can_be_text is set.
Default to None.
--admin_secret (Optional[str]):
Path to the admin secrets config (TOML) with read/write permission.
or the file content if --config_or_admin_secret_can_be_text is set.
This field is required for local index synchronization.
Default to None.
--config_or_admin_secret_can_be_text (Optional[bool]):
Enable passing the file content to --config or --admin_secret.
Default to False.
--auth_read_expires (int):
The expiration time (in seconds) for read authentication.
Default to 3600.
--auth_write_expires (int):
The expiration time (in seconds) for write authentication.
Default to 300.
--extra_index_url (str):
Extra index url for redirection in case package not found.
If set to empty string explicitly redirection will be suppressed.
Default to 'https://pypi.org/simple/'.
--debug (bool):
Enable debug mode.
Default to False.
--host (str):
The interface to bind to.
Default to '0.0.0.0'.
--port (int):
The port to bind to.
Default to 8888.
**waitress_options (Dict[str, Any]):
Optional arguments that `waitress.serve` takes.
Details in https://docs.pylonsproject.org/projects/waitress/en/stable/arguments.html.
Default to {}.
In short, the configuration passed to --config defines mappings from pkg_repo_name to backend-specific settings. In other words, a single server instance can be configured to connect to multiple backends.
Exampe of the configuration file passed to --config:
[pywharf-pkg-repo]
type = "github"
owner = "pywharf"
repo = "pywharf-pkg-repo"
[local-file-system]
type = "file_system"
read_secret = "foo"
write_secret = "bar"
Exampe of the admin secret file passed to --admin_secret:
[pywharf-pkg-repo]
type = "github"
raw = "<personal-access-token>"
[local-file-system]
type = "file_system"
raw = "foo"
Example run:
docker run --rm \
-v /path/to/root:/pywharf-root \
-v /path/to/config.toml:/config.toml \
-v /path/to/admin_secret.toml:/admin_secret.toml \
-p 8888:8888 \
pywharf/pywharf:0.2.3 \
server \
/pywharf-root \
--config=/config.toml \
--admin_secret=/admin_secret.toml
Server API
Authentication in shell
User must provide the pkg_repo_name and their secret in most of the API calls so that the server can find which backend to operate and determine whether the operation is permitted or not. The pkg_repo_name and the secret should be provided in basic access authentication.
Some package management tools will handle the authentication behind the screen, for example,
- Twine: to set the environment variables
TWINE_USERNAMEandTWINE_PASSWORD. ref - Poetry: Configuring credentials.
Some will not, for example,
- Pip: you need to prepend
<pkg_repo_name>:<secret>@to the hostname in the URL manually like thishttps://[username[:password]@]pypi.company.com/simple. ref
Authentication in browser
You need to visit /login page to submit pkg_repo_name and the secret, since most of the browsers today don't support prepending <username>:<password>@ to the hostname in the URL. The pkg_repo_name and the secret will be stored in the session cookies. To reset, visit /logout .
Example: http://localhost:8888/login/
PEP-503, Legacy API
The server follows PEP 503 -- Simple Repository API and Legacy API to define APIs for searching/downloading/uploading package:
GET /simple/: List all distributions.GET /simple/<distrib>/: List all packages in a distribution.GET /simple/<distrib>/<filename>: Download a package file.POST /simple/: Upload a package file.
In a nutshell, you need to set the "index url / repository url / ..." to http://<host>:<port>/simple/ for the package management tool.
Server management
GET /index_mtime
Get the last index index synchronization timestamp.
$ curl http://debug:foo@localhost:8888/index_mtime/
1584379892
POST /initialize
Submit configuration and (re-)initialize the server. User can change the package repository configuration on-the-fly with this API.
# POST the file content.
$ curl \
-d "config=${CONFIG}&admin_secret=${ADMIN_SECRET}" \
-X POST \
http://localhost:8888/initialize/
# Or, POST the file.
$ curl \
-F 'config=@/path/to/config.toml' \
-F 'admin_secret=@/path/to/admin_secret.toml' \
http://localhost:8888/initialize/
Update index
<div align="center"><img width="636" alt="Screen Shot 2020-03-25 at 5 39 19 PM" src="https://user-images.githubusercontent.com/5213906/77522697-9a043f80-6ebf-11ea-95e6-9a086db7af2e.png"></div>Index file is used to track all published packages in a specific time:
- Remote index file: the index file sotred in the backend. By design, this file is only updated by a standalone
update indexservice and will not be updated by thepywharfserver. - Local index file: the index file synchronized from the remote index file by the
pywharfserver
To update the remote index file, use the command pywharf update_index:
SYNOPSIS
pywharf update_index TYPE NAME <flags>
POSITIONAL ARGUMENTS
TYPE (str):
Backend type.
NAME (str):
Name of config.
FLAGS
--secret (Optional[str]):
The secret with write permission.
--secret_env (Optional[str]):
Instead of passing the secret through --secret,
the secret could be loaded from the environment variable.
**pkg_repo_configs (Dict[str, Any]):
Any other backend-specific configs are allowed.
Backend developer could setup an update index service by invoking pywharf update_index command.
Backend-specific commands
The backend registration mechanism will hook up the backend-specific commands to pywharf. As illustrated, commands github.init_pkg_repo and github.gen_gh_pages are registered by github backend.
$ pywharf --help
SYNOPSIS
pywharf <command> <command_flags>
SUPPORTED COMMANDS
server
update_index
github.init_pkg_repo
github.gen_gh_pages
Related Skills
node-connect
340.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.2kCommit, push, and open a PR
