2011-07-29 03:14:09 +02:00
.. -*- mode: rst; coding: utf-8 -*-
2016-01-21 19:27:38 +01:00
.. image :: pypiserver_logo.png
:width: 300 px
:align: center
2011-07-29 03:14:09 +02:00
==============================================================================
pypiserver - minimal PyPI server for use with pip/easy_install
==============================================================================
2019-10-19 20:05:52 +02:00
|pypi-ver| |travis-status| |dependencies| |python-ver| |proj-license|
2011-07-29 03:14:09 +02:00
2020-01-12 00:23:07 +01:00
:Version: 1.3.2
:Date: 2020-01-11
2015-12-21 23:05:03 +01:00
:Source: https://github.com/pypiserver/pypiserver
2018-06-12 03:27:09 +02:00
:PyPI: https://pypi.org/project/pypiserver/
2015-12-21 23:05:03 +01:00
:Travis: https://travis-ci.org/pypiserver/pypiserver
2016-06-28 13:13:32 +02:00
:Maintainers: Kostis Anagnostopoulos <ankostis@gmail.com>,
Matthew Planchard <mplanchard@gmail.com>
2015-12-21 23:05:03 +01:00
:License: zlib/libpng + MIT
2011-07-31 23:42:37 +02:00
2019-09-11 00:35:18 +02:00
`` pypiserver `` is a minimal PyPI_ compatible server for `` pip `` or `` easy_install `` .
2016-06-17 21:44:50 +02:00
It is based on bottle_ and serves packages from regular directories.
Wheels, bdists, eggs and accompanying PGP-signatures can be uploaded
2019-09-11 00:35:18 +02:00
either with `` pip `` , `` setuptools `` , `` twine `` , `` pypi-uploader `` , or simply copied
with `` scp `` .
2011-07-31 23:42:37 +02:00
2015-02-27 23:02:07 +01:00
2016-01-21 19:27:38 +01:00
.. contents :: Table of Contents
:backlinks: top
2011-07-29 03:14:09 +02:00
2015-03-08 18:37:34 +01:00
Quickstart: Installation and Usage
==================================
2019-09-11 00:35:18 +02:00
`` pypiserver `` > 1.2.x works with Python 2.7 and 3.4+ or PyPy.
2017-12-18 12:50:19 +01:00
Older Python versions may still work, but they are not tested.
For legacy Python versions, use `` pypiserver-1.1.x `` series.
2011-07-31 23:42:37 +02:00
2016-07-02 13:46:09 +02:00
.. Tip ::
The commands below work on a unix-like operating system with a posix shell.
The `` '~' `` character expands to user's home directory.
If you're using Windows, you'll have to use their "Windows counterparts".
The same is true for the rest of this documentation.
2019-09-11 00:35:18 +02:00
1. Install `` pypiserver `` with this command::
2016-07-02 13:46:09 +02:00
2019-09-11 00:35:18 +02:00
pip install pypiserver # Or: pypiserver[passlib,watchdog]
mkdir ~/packages # Copy packages into this directory.
2015-09-11 18:40:07 +02:00
2016-07-02 13:33:23 +02:00
See also `Alternative Installation methods`_ .
2015-02-27 23:02:07 +01:00
2016-07-02 13:33:23 +02:00
2. Copy some packages into your `` ~/packages `` folder and then
2019-09-11 00:35:18 +02:00
get your `` pypiserver `` up and running::
2016-01-21 19:27:38 +01:00
2019-09-11 00:35:18 +02:00
pypi-server -p 8080 ~/packages & # Will listen to all IPs.
2011-07-29 03:14:09 +02:00
2016-07-02 13:46:09 +02:00
3. From the client computer, type this::
2016-07-02 13:33:23 +02:00
2019-09-11 00:35:18 +02:00
# Download and install hosted packages.
pip install --extra-index-url http://localhost:8080/simple/ ...
2017-03-19 21:10:01 +01:00
# or
2019-09-11 00:35:18 +02:00
pip install --extra-index-url http://localhost:8080 ...
2017-03-19 21:10:01 +01:00
2019-09-11 00:35:18 +02:00
# Search hosted packages.
2017-03-19 21:10:01 +01:00
pip search --index http://localhost:8080 ...
2019-09-11 00:35:18 +02:00
# Note that pip search does not currently work with the /simple/ endpoint.
2016-07-02 13:33:23 +02:00
See also `Client-side configurations`_ for avoiding tedious typing.
2014-01-05 01:32:34 +01:00
2016-07-02 13:46:09 +02:00
4. Enter `` pypi-server -h `` in the cmd-line to print a detailed usage message::
pypi-server [OPTIONS] [PACKAGES_DIRECTORY...]
start PyPI compatible package server serving packages from
PACKAGES_DIRECTORY. If PACKAGES_DIRECTORY is not given on the
2019-09-11 00:35:18 +02:00
command line, it uses the default ~/packages. pypiserver scans this
2016-07-02 13:46:09 +02:00
directory recursively for packages. It skips packages and
directories starting with a dot. Multiple package directories can be
specified.
pypi-server understands the following options:
-p, --port PORT
2019-09-11 00:35:18 +02:00
Listen on port PORT (default: 8080).
2016-07-02 13:46:09 +02:00
-i, --interface INTERFACE
2019-09-11 00:35:18 +02:00
Listen on interface INTERFACE (default: 0.0.0.0, any interface).
-a, --authenticate (update|download|list), ...
Comma-separated list of (case-insensitive) actions to authenticate.
Requires to have set the password (-P option).
To password-protect package downloads (in addition to uploads) while
leaving listings public, use:
-P foo/htpasswd.txt -a update,download
To allow unauthorized access, use:
-P . -a .
2016-07-02 13:46:09 +02:00
Note that when uploads are not protected, the `register` command
is not necessary, but `~/.pypirc` still need username and password fields,
even if bogus.
By default, only 'update' is password-protected.
-P, --passwords PASSWORD_FILE
2019-09-11 00:35:18 +02:00
Use apache htpasswd file PASSWORD_FILE to set usernames & passwords when
2016-07-02 13:46:09 +02:00
authenticating certain actions (see -a option).
2019-09-11 00:35:18 +02:00
To allow unauthorized access, use:
-P . -a .
2016-07-02 13:46:09 +02:00
--disable-fallback
2019-09-11 00:35:18 +02:00
Disable redirect to real PyPI index for packages not found in the
local index.
2016-07-02 13:46:09 +02:00
--fallback-url FALLBACK_URL
2019-09-11 00:35:18 +02:00
For packages not found in the local index, this URL will be used to
redirect to (default: https://pypi.org/simple/).
2016-07-02 13:46:09 +02:00
--server METHOD
2019-09-11 00:35:18 +02:00
Use METHOD to run the server. Valid values include paste,
2016-07-02 13:46:09 +02:00
cherrypy, twisted, gunicorn, gevent, wsgiref, auto. The
default is to use "auto" which chooses one of paste, cherrypy,
twisted or wsgiref.
-r, --root PACKAGES_DIRECTORY
2019-09-11 00:35:18 +02:00
[deprecated] Serve packages from PACKAGES_DIRECTORY.
2016-07-02 13:46:09 +02:00
-o, --overwrite
2019-09-11 00:35:18 +02:00
Allow overwriting existing package files.
2016-07-02 13:46:09 +02:00
--hash-algo ALGO
2019-09-11 00:35:18 +02:00
Any `hashlib` available algo used as fragments on package links.
Set one of (0, no, off, false) to disabled it (default: md5).
2016-07-02 13:46:09 +02:00
--welcome HTML_FILE
2019-09-11 00:35:18 +02:00
Uses the ASCII contents of HTML_FILE as welcome message response.
2016-07-02 13:46:09 +02:00
-v
2019-09-11 00:35:18 +02:00
Enable verbose logging; repeat for more verbosity.
2016-07-02 13:46:09 +02:00
--log-conf <FILE>
2019-09-11 00:35:18 +02:00
Read logging configuration from FILE.
2016-07-02 13:46:09 +02:00
By default, configuration is read from `log.conf` if found in server's dir.
--log-file <FILE>
2019-09-11 00:35:18 +02:00
Write logging info into this FILE.
2016-07-02 13:46:09 +02:00
--log-frmt <FILE>
2019-09-11 00:35:18 +02:00
The logging format-string (see `logging.LogRecord` class from standard python library).
2016-07-02 13:46:09 +02:00
[Default: %(asctime)s|%(name)s|%(levelname)s|%(thread)d|%(message)s]
--log-req-frmt FORMAT
2019-09-11 00:35:18 +02:00
A format-string selecting Http-Request properties to log; set to '%s' to see them all.
2016-07-02 13:46:09 +02:00
[Default: %(bottle.request)s]
--log-res-frmt FORMAT
2019-09-11 00:35:18 +02:00
A format-string selecting Http-Response properties to log; set to '%s' to see them all.
2016-07-02 13:46:09 +02:00
[Default: %(status)s]
--log-err-frmt FORMAT
2019-09-11 00:35:18 +02:00
A format-string selecting Http-Error properties to log; set to '%s' to see them all.
2016-07-02 13:46:09 +02:00
[Default: %(body)s: %(exception)s \n%(traceback)s]
2019-09-11 00:35:18 +02:00
--cache-control AGE
Add "Cache-Control: max-age=AGE, public" header to package downloads.
Pip 6+ needs this for caching.
pypi-server -h, --help
Show this help message.
2016-07-02 13:46:09 +02:00
pypi-server --version
2019-09-11 00:35:18 +02:00
Show pypi-server's version.
2016-07-02 13:46:09 +02:00
pypi-server -U [OPTIONS] [PACKAGES_DIRECTORY...]
2019-09-11 00:35:18 +02:00
Update packages in PACKAGES_DIRECTORY. This command searches
2018-06-12 03:27:09 +02:00
pypi.org for updates and shows a pip command line which
2016-07-02 13:46:09 +02:00
updates the package.
The following additional options can be specified with -U:
-x
2019-09-11 00:35:18 +02:00
Execute the pip commands instead of only showing them.
2016-07-02 13:46:09 +02:00
-d DOWNLOAD_DIRECTORY
2019-09-11 00:35:18 +02:00
Download package updates to this directory. The default is to use
2016-07-02 13:46:09 +02:00
the directory which contains the latest version of the package to
be updated.
-u
2019-09-11 00:35:18 +02:00
Allow updating to unstable version (alpha, beta, rc, dev versions).
2016-07-02 13:46:09 +02:00
Visit https://github.com/pypiserver/pypiserver for more information.
2015-09-11 18:40:07 +02:00
2015-02-27 23:02:07 +01:00
2019-09-11 00:35:18 +02:00
Client-Side Configurations
2016-07-02 13:33:23 +02:00
==========================
2019-09-11 00:35:18 +02:00
2016-07-02 13:33:23 +02:00
Always specifying the the pypi url on the command line is a bit
2019-09-11 00:35:18 +02:00
cumbersome. Since `` pypiserver `` redirects `` pip/easy_install `` to the
`` pypi.org `` index if it doesn't have a requested package, it is a
2016-07-02 13:33:23 +02:00
good idea to configure them to always use your local pypi index.
2019-09-11 00:35:18 +02:00
Configuring `` pip ``
-------------------
2016-07-02 13:33:23 +02:00
For `` pip `` command this can be done by setting the environment variable
`` PIP_EXTRA_INDEX_URL `` in your `` .bashr/.profile/.zshrc `` ::
export PIP_EXTRA_INDEX_URL=http://localhost:8080/simple/
or by adding the following lines to `` ~/.pip/pip.conf `` ::
[global]
extra-index-url = http://localhost:8080/simple/
.. Note ::
2019-09-11 00:35:18 +02:00
If you have installed `` pypiserver `` on a remote url without *https*
2016-07-02 13:33:23 +02:00
you wil receive an "untrusted" warning from *pip* , urging you to append
the `` --trusted-host `` option. You can also include this option permanently
in your configuration-files or environment variables.
2019-09-11 00:35:18 +02:00
Configuring `` easy_install ``
----------------------------
2016-07-02 13:33:23 +02:00
For `` easy_install `` command you may set the following configuration in
`` ~/.pydistutils.cfg `` ::
[easy_install]
index_url = http://localhost:8080/simple/
Uploading Packages Remotely
===========================
2019-09-11 00:35:18 +02:00
2016-07-02 13:33:23 +02:00
Instead of copying packages directly to the server's folder (i.e. with `` scp `` ),
you may use python tools for the task, e.g. `` python setup.py upload `` .
2019-09-11 00:35:18 +02:00
In that case, `` pypiserver `` is responsible for authenticating the upload-requests.
2016-07-02 13:33:23 +02:00
.. Note ::
We strongly advise to password-protected your uploads!
It is possible to disable authentication for uploads (e.g. in intranets).
To avoid lazy security decisions, read help for `` -P `` and `` -a `` options.
2019-09-11 00:35:18 +02:00
*Apache* -Like Authentication (`` htpasswd `` )
2016-07-02 13:33:23 +02:00
-------------------------------------------
2019-09-11 00:35:18 +02:00
2016-03-11 18:46:29 +01:00
#. First make sure you have the *passlib* module installed (note that
2016-06-24 19:56:09 +02:00
`` passlib>=1.6 `` is required), which is needed for parsing the Apache
*htpasswd* file specified by the `` -P `` , `` --passwords `` option
2016-03-11 18:46:29 +01:00
(see next steps)::
2015-03-08 18:37:34 +01:00
pip install passlib
2016-06-23 21:17:13 +02:00
#. Create the Apache *htpasswd* file with at least one user/password pair
2015-03-08 18:37:34 +01:00
with this command (you'll be prompted for a password)::
2016-01-17 23:26:15 +01:00
htpasswd -sc htpasswd.txt <some_username>
2015-03-08 18:37:34 +01:00
2016-06-23 21:17:13 +02:00
.. Tip :: Read this SO question for running `htpasswd` cmd
under *Windows* :
2015-09-11 18:40:07 +02:00
2016-06-23 21:17:13 +02:00
http://serverfault.com/questions/152950/how-to-create-and-edit-htaccess-and-htpasswd-locally-on-my-computer-and-then-u
2015-09-17 01:39:13 +02:00
2016-06-23 21:17:13 +02:00
or if you have bogus passwords that you don't care because they are for
an internal service (which is still "bad", from a security prespective...)
you may use this public service:
2015-09-17 01:39:13 +02:00
2016-06-23 21:17:13 +02:00
http://www.htaccesstools.com/htpasswd-generator/
2015-09-11 18:40:07 +02:00
2016-06-24 19:56:09 +02:00
.. Tip :: When accessing pypiserver via the api, alternate authentication
methods are available via the `` auther `` config flag. Any callable
returning a boolean can be passed through to the pypiserver config in
2016-06-24 22:12:29 +02:00
order to provide custom authentication. For example, to configure
pypiserver to authenticate using the `python-pam`_ ::
2015-03-08 18:37:34 +01:00
2016-06-24 19:56:09 +02:00
import pam
pypiserver.default_config(auther=pam.authenticate)
2016-06-22 16:56:15 +02:00
2016-06-28 11:18:39 +02:00
Please see `Using Ad-hoc authentication providers`_ for more information.
2016-06-24 22:12:29 +02:00
2016-06-24 19:56:09 +02:00
#. You need to restart the server with the `` -P `` option only once
(but user/password pairs can later be added or updated on the fly)::
2016-06-22 16:56:15 +02:00
2016-06-24 19:56:09 +02:00
./pypi-server -p 8080 -P htpasswd.txt ~/packages &
2016-06-22 15:49:06 +02:00
2019-09-11 00:35:18 +02:00
Upload with `` setuptools ``
--------------------------
2016-06-24 19:56:09 +02:00
#. On client-side, edit or create a `` ~/.pypirc `` file with a similar content::
2015-03-08 18:37:34 +01:00
[distutils]
index-servers =
pypi
2015-09-17 13:52:00 +02:00
local
2015-09-11 18:40:07 +02:00
2015-03-08 18:37:34 +01:00
[pypi]
username:<your_pypi_username>
password:<your_pypi_passwd>
2015-09-11 18:40:07 +02:00
2015-09-17 13:52:00 +02:00
[local]
2015-03-08 18:37:34 +01:00
repository: http://localhost:8080
username: <some_username>
password: <some_passwd>
2015-09-11 18:40:07 +02:00
#. Then from within the directory of the python-project you wish to upload,
2015-03-08 18:37:34 +01:00
issue this command::
2015-09-17 13:52:00 +02:00
python setup.py sdist upload -r local
2019-09-11 00:35:18 +02:00
Upload with `` twine ``
---------------------
2015-03-08 18:37:34 +01:00
2016-07-02 13:33:23 +02:00
To avoid storing you passwords on disk, in clear text, you may either:
2016-01-19 20:22:42 +01:00
2016-07-02 13:33:23 +02:00
- use the `` register `` *setuptools* 's command with the `` -r `` option,
like that::
2016-01-19 20:22:42 +01:00
2016-07-02 13:33:23 +02:00
python setup.py sdist register -r local upload -r local
2016-01-19 20:22:42 +01:00
2016-07-02 13:33:23 +02:00
- use `twine`_ library, which
breaks the procedure in two steps. In addition, it supports signing
your files with PGP-Signatures and uploading the generated `.asc` files
2019-09-11 00:35:18 +02:00
to `` pypiserver `` ::
2016-06-23 05:03:40 +02:00
2016-07-02 13:33:23 +02:00
twine upload -r local --sign -identity user_name ./foo-1.zip
2016-06-23 05:03:40 +02:00
2015-03-08 18:37:34 +01:00
2018-06-27 03:51:32 +02:00
Using the Docker Image
======================
2018-11-10 02:25:39 +01:00
Starting with version 1.2.5, official Docker images will be built for each
2018-06-27 03:51:32 +02:00
push to master, each dev, alpha, or beta release, and each final release.
The most recent full release will always be available under the tag `` latest `` ,
and the current master branch will always be available under the tag
2018-07-18 03:45:17 +02:00
`` unstable `` .
You can always check to see what tags are currently available at our
`Docker Repo`_ .
2018-06-27 03:51:32 +02:00
To run the most recent release of `` pypiserver `` with Docker, simply::
docker run pypiserver/pypiserver:latest
This starts `` pypiserver `` serving packages from the `` /data/packages ``
directory inside the container, listening on the container port 8080.
The container takes all the same arguments as the normal `` pypi-server ``
executable, with the exception of the internal container port (`` -p `` ),
which will always be 8080.
Of course, just running a container isn't that interesting. To map
port 80 on the host to port 8080 on the container::
docker run -p 80:8080 pypiserver/pypiserver:latest
You can now access your `` pypiserver `` at `` localhost:80 `` in a web browser.
To serve packages from a directory on the host, e.g. `` ~/packages `` ::
docker run -p 80:8080 -v ~/packages:/data/packages pypiserver/pypiserver:latest
2018-09-06 17:27:25 +02:00
To authenticate against a local `` .htpasswd `` file::
2018-06-27 03:51:32 +02:00
2018-09-06 17:27:25 +02:00
docker run -p 80:8080 -v ~/.htpasswd:/data/.htpasswd pypiserver/pypiserver:latest -P .htpasswd packages
2018-06-27 03:51:32 +02:00
You can also specify `` pypiserver `` to run as a Docker service using a
composefile. An example composefile is `provided <docker-compose.yml> `_ .
2018-07-18 03:45:17 +02:00
.. _`docker repo`: https://hub.docker.com/r/pypiserver/pypiserver/tags/
Alternative Installation Methods
2015-03-08 18:37:34 +01:00
================================
2019-09-11 00:35:18 +02:00
2015-09-11 18:40:07 +02:00
When trying the methods below, first use the following command to check whether
2019-09-11 00:35:18 +02:00
previous versions of `` pypiserver `` already exist, and (optionally) uninstall them::
2015-03-08 18:37:34 +01:00
2019-09-11 00:35:18 +02:00
# VERSION-CHECK: Fails if not installed.
2015-03-08 18:37:34 +01:00
pypi-server --version
2015-09-11 18:40:07 +02:00
2019-09-11 00:35:18 +02:00
# UNINSTALL: Invoke again untill it fails.
2015-03-08 18:37:34 +01:00
pip uninstall pypiserver
2015-09-11 18:40:07 +02:00
2019-09-11 00:35:18 +02:00
Installing the Very Latest Version
2015-03-08 18:37:34 +01:00
----------------------------------
2019-09-11 00:35:18 +02:00
2015-09-11 18:40:07 +02:00
In case the latest version in *pypi* is a pre-release, you have to use
2015-03-08 18:37:34 +01:00
*pip* 's `--pre` option. And to update an existing installation combine it
with `--ignore-installed` ::
pip install pypiserver --pre -I
2015-09-11 18:40:07 +02:00
2019-09-11 00:35:18 +02:00
You can even install the latest `` pypiserver `` directly from *github* with the
2016-07-02 13:46:09 +02:00
following command, assuming you have *git* installed on your `` PATH `` ::
2015-03-08 18:37:34 +01:00
pip install git+git://github.com/pypiserver/pypiserver.git
2019-09-11 00:35:18 +02:00
Installing It As Standalone Script
2015-03-08 18:37:34 +01:00
----------------------------------
2019-09-11 00:35:18 +02:00
2015-02-27 23:02:07 +01:00
The git repository contains a `` pypi-server-standalone.py `` script,
2015-03-08 18:37:34 +01:00
which is a single python file that can be executed without any other
2011-08-01 23:09:42 +02:00
dependencies.
2016-06-23 21:17:13 +02:00
Run the following commands to download the script with `` wget `` ::
2011-08-01 23:09:42 +02:00
2015-02-27 23:02:07 +01:00
wget https://raw.github.com/pypiserver/pypiserver/standalone/pypi-server-standalone.py
2011-08-01 23:09:42 +02:00
chmod +x pypi-server-standalone.py
2016-06-23 21:17:13 +02:00
or with `` curl `` ::
2011-08-01 23:09:42 +02:00
2015-02-27 23:02:07 +01:00
curl -O https://raw.github.com/pypiserver/pypiserver/standalone/pypi-server-standalone.py
2011-08-01 23:09:42 +02:00
chmod +x pypi-server-standalone.py
2015-03-08 18:37:34 +01:00
You can then start-up the server with::
2011-08-01 23:09:42 +02:00
./pypi-server-standalone.py
2016-06-23 21:17:13 +02:00
Feel free to rename the script and move it into your `` $PATH `` .
2011-08-01 23:09:42 +02:00
2019-09-11 00:35:18 +02:00
Running on Heroku/Dotcloud
--------------------------
2015-02-27 23:02:07 +01:00
2012-10-05 00:22:58 +02:00
https://github.com/dexterous/pypiserver-on-the-cloud contains
2019-09-11 00:35:18 +02:00
instructions on how to run `` pypiserver `` on one of the supported cloud
2012-10-05 00:22:58 +02:00
service providers.
2011-07-29 03:14:09 +02:00
2017-11-14 15:41:26 +01:00
2016-07-02 13:46:09 +02:00
Recipes
=======
2011-11-19 21:17:35 +01:00
2019-09-11 00:35:18 +02:00
Managing the Package Directory
2015-03-08 18:37:34 +01:00
------------------------------
2019-09-11 00:35:18 +02:00
2016-06-23 21:17:13 +02:00
The `` pypi-server `` command has the `` -U `` option that searches for updates of
2011-11-19 21:17:35 +01:00
available packages. It scans the package directory for available
2018-06-12 03:27:09 +02:00
packages and searches on pypi.org for updates. Without further
2015-02-27 23:02:07 +01:00
options `` pypi-server -U `` will just print a list of commands which must
2011-11-19 21:17:35 +01:00
be run in order to get the latest version of each package. Output
looks like::
2016-06-23 21:17:13 +02:00
$ ./pypi-server -U
checking 106 packages for newer version
2011-11-19 21:17:35 +01:00
2016-06-23 21:17:13 +02:00
.........u.e...........e..u.............
.....e..............................e...
..........................
2011-11-19 21:17:35 +01:00
2016-06-23 21:17:13 +02:00
no releases found on pypi for PyXML, Pymacs, mercurial, setuptools
2011-11-19 21:17:35 +01:00
2016-06-23 21:17:13 +02:00
# update raven from 1.4.3 to 1.4.4
2019-09-11 00:35:18 +02:00
pip -q install --no-deps --extra-index-url https://pypi.org/simple/ -d /home/ralf/packages/mirror raven==1.4.4
2011-11-19 21:17:35 +01:00
2016-06-23 21:17:13 +02:00
# update greenlet from 0.3.3 to 0.3.4
2019-09-11 00:35:18 +02:00
pip -q install --no-deps --extra-index-url https://pypi.org/simple/ -d /home/ralf/packages/mirror greenlet==0.3.4
2011-11-19 21:17:35 +01:00
It first prints for each package a single character after checking the
2016-06-23 21:17:13 +02:00
available versions on pypi. A dot(`.` ) means the package is up-to-date, `` 'u' ``
means the package can be updated and `` 'e' `` means the list of releases on
2015-02-27 23:02:07 +01:00
pypi is empty. After that it shows a *pip* command line which can be used
2011-11-19 21:17:35 +01:00
to update a one package. Either copy and paste that or run
2015-02-27 23:02:07 +01:00
`` pypi-server -Ux `` in order to really execute those commands. You need
to have *pip* installed for that to work however.
2011-11-19 21:17:35 +01:00
2016-06-23 21:17:13 +02:00
Specifying an additional `` -u `` option will also allow alpha, beta and
2011-11-19 21:17:35 +01:00
release candidates to be downloaded. Without this option these
releases won't be considered.
2011-08-09 23:28:14 +02:00
2019-09-11 00:35:18 +02:00
Serving Thousands of Packages
2016-01-04 23:06:49 +01:00
-----------------------------
2019-09-11 00:35:18 +02:00
By default, `` pypiserver `` scans the entire packages directory each time an
2016-01-04 23:06:49 +01:00
incoming HTTP request occurs. This isn't a problem for a small number of
2016-07-02 13:33:23 +02:00
packages, but causes noticeable slow-downs when serving thousands of packages.
2016-01-04 23:06:49 +01:00
If you run into this problem, significant speedups can be gained by enabling
pypiserver's directory caching functionality. The only requirement is to
2016-07-02 13:33:23 +02:00
install the `` watchdog `` package, or it can be installed during `` pypiserver ``
installation, by specifying the `` cache `` extras option::
2016-01-04 23:06:49 +01:00
2016-06-23 21:17:13 +02:00
pip install pypiserver[cache]
2016-01-04 23:06:49 +01:00
2019-05-05 23:47:06 +02:00
Additional speedups can be obtained by using your webserver's builtin
caching functionality. For example, if you are using `nginx` as a
reverse-proxy as described below in `Behind a reverse proxy`_ , you can
easily enable caching. For example, to allow nginx to cache up to
10 gigabytes of data for up to 1 hour::
2016-01-19 20:48:01 +01:00
2019-05-05 23:47:06 +02:00
proxy_cache_path /data/nginx/cache
levels=1:2
keys_zone=pypiserver_cache:10m
max_size=10g
inactive=60m
use_temp_path=off;
2016-01-19 20:48:01 +01:00
2019-05-05 23:47:06 +02:00
server {
# ...
location / {
proxy_cache pypiserver_cache;
proxy_pass http://localhost:8080;
}
2016-01-19 20:48:01 +01:00
}
2016-01-17 23:26:15 +01:00
2019-05-05 23:47:06 +02:00
Using webserver caching is especially helpful if you have high request
volume. Using `nginx` caching, a real-world pypiserver installation was
able to easily support over 1000 package downloads/min at peak load.
2011-08-01 01:58:04 +02:00
2016-06-23 04:41:52 +02:00
Managing Automated Startup
--------------------------
2019-09-11 00:35:18 +02:00
2016-06-23 04:41:52 +02:00
There are a variety of options for handling the automated starting of
2016-06-23 21:17:13 +02:00
pypiserver upon system startup. Two of the most common are *systemd* and
*supervisor* .
2016-06-23 04:41:52 +02:00
2019-09-11 00:35:18 +02:00
Running As a `` systemd `` Service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2016-06-23 04:41:52 +02:00
2019-09-11 00:35:18 +02:00
`` systemd `` is installed by default on most modern Linux systems and as such,
2016-06-23 21:17:13 +02:00
it is an excellent option for managing the pypiserver process. An example
config file for `` systemd `` can be seen below::
2016-06-23 04:41:52 +02:00
[Unit]
2016-06-23 21:17:13 +02:00
Description=A minimal PyPI server for use with pip/easy_install.
2016-06-23 04:41:52 +02:00
After=network.target
[Service]
Type=simple
# systemd requires absolute path here too.
2016-06-23 21:17:13 +02:00
PIDFile=/var/run/pypiserver.pid
2016-06-23 04:41:52 +02:00
User=www-data
Group=www-data
2017-01-08 06:49:35 +01:00
ExecStart=/usr/local/bin/pypi-server -p 8080 -a update,download --log-file /var/log/pypiserver.log -P /etc/nginx/.htpasswd /var/www/pypi
2016-06-23 04:41:52 +02:00
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
WorkingDirectory=/var/www/pypi
TimeoutStartSec=3
RestartSec=5
[Install]
WantedBy=multi-user.target
2016-06-23 21:17:13 +02:00
Adjusting the paths and adding this file as `` pypiserver.service `` into your
2016-06-23 04:44:46 +02:00
`` systemd/system `` directory will allow management of the pypiserver process with
2016-06-23 21:17:13 +02:00
`` systemctl `` , e.g. `` systemctl start pypiserver `` .
More useful information about *systemd* can be found at
https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
2016-06-23 04:41:52 +02:00
2019-09-11 00:35:18 +02:00
Launching through `` supervisor ``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2016-06-23 21:17:13 +02:00
`supervisor <http://supervisord.org/> `_ has the benefit of being a pure python
package and as such, it provides excellent cross-platform support for process
management. An example configuration file for `` supervisor `` is given below::
2016-06-23 04:41:52 +02:00
[program:pypi]
2018-09-06 17:27:25 +02:00
command=/home/pypi/pypi-venv/bin/pypi-server -p 7001 -P /home/pypi/.htpasswd /home/pypi/packages
2016-06-23 04:41:52 +02:00
directory=/home/pypi
user=pypi
autostart=true
autorestart=true
2016-06-23 21:17:13 +02:00
stderr_logfile=/var/log/pypiserver.err.log
stdout_logfile=/var/log/pypiserver.out.log
2016-06-23 04:41:52 +02:00
2016-06-23 04:44:46 +02:00
From there, the process can be managed via `` supervisord `` using `` supervisorctl `` .
2016-06-23 04:41:52 +02:00
2019-09-11 00:35:18 +02:00
Using a Different WSGI Server
2015-03-08 18:37:34 +01:00
-----------------------------
2019-09-11 00:35:18 +02:00
- The `` bottle `` web-server which supports many WSGI-servers, among others,
`` paste `` , `` cherrypy `` , `` twisted `` and `` wsgiref `` (part of Python); you select
2016-06-25 04:02:59 +02:00
them using the `` --server `` flag.
2012-03-26 02:22:41 +02:00
2016-06-25 04:02:59 +02:00
- You may view all supported WSGI servers using the following interactive code::
2015-02-27 23:02:07 +01:00
2016-06-25 04:02:59 +02:00
>>> from pypiserver import bottle
>>> list(bottle.server_names.keys())
['cgi', 'gunicorn', 'cherrypy', 'eventlet', 'tornado', 'geventSocketIO',
'rocket', 'diesel', 'twisted', 'wsgiref', 'fapws3', 'bjoern', 'gevent',
'meinheld', 'auto', 'aiohttp', 'flup', 'gae', 'paste', 'waitress']
2015-02-27 23:02:07 +01:00
2016-06-25 04:02:59 +02:00
- If none of the above servers matches your needs, invoke just the
`` pypiserver:app() `` method which returns the internal WSGI-app WITHOUT
2019-09-11 00:35:18 +02:00
starting-up a server - you may then send it to any WSGI server you like.
2016-07-02 13:46:09 +02:00
Read also the `Utilizing the API`_ section.
2012-03-26 02:22:41 +02:00
2016-07-03 00:58:05 +02:00
- Some examples are given below - you may find more details in `bottle
site <http://bottlepy.org/docs/dev/deployment.html#switching-the-server-backend>`_.
2012-03-26 02:22:41 +02:00
2019-09-11 00:35:18 +02:00
Apache (`` mod_wsgi `` )
2016-07-03 00:58:05 +02:00
~~~~~~~~~~~~~~~~~~~~~
2019-09-11 00:35:18 +02:00
To use your *Apache2* with `` pypiserver `` , prefer to utilize `` mod_wsgi `` as
2016-07-03 00:58:05 +02:00
explained in `bottle's documentation <http://bottlepy.org/docs/dev/deployment.html#apache-mod-wsgi> `_ .
2012-03-26 02:22:41 +02:00
2016-07-03 00:58:05 +02:00
.. Note ::
2019-09-11 00:35:18 +02:00
If you choose instead to go with `` mod_proxy `` , mind that you may bump into problems
2016-07-03 00:58:05 +02:00
with the prefix-path (see `#155 <https://github.com/pypiserver/pypiserver/issues/155> `_ ).
2012-03-26 02:22:41 +02:00
2016-07-03 00:58:05 +02:00
1. Adapt and place the following *Apache* configuration either into top-level scope,
or inside some `` <VirtualHost> `` (contributed by Thomas Waldmann)::
2012-03-26 02:22:41 +02:00
2016-07-03 00:58:05 +02:00
WSGIScriptAlias / /yoursite/wsgi/pypiserver-wsgi.py
WSGIDaemonProcess pypisrv user=pypisrv group=pypisrv umask=0007 \
processes=1 threads=5 maximum-requests=500 \
display-name=wsgi-pypisrv inactivity-timeout=300
WSGIProcessGroup pypisrv
2020-01-11 23:55:17 +01:00
WSGIPassAuthorization On # Required for authentication (https://github.com/pypiserver/pypiserver/issues/288)
2013-01-28 00:45:01 +01:00
2016-07-03 00:58:05 +02:00
<Directory /yoursite/wsgi >
Require all granted
</Directort>
2013-01-28 00:45:01 +01:00
2016-07-03 00:58:05 +02:00
or if using older `` Apache < 2.4 `` , substitute the last part with this::
2013-01-28 00:45:01 +01:00
2016-07-03 00:58:05 +02:00
<Directory /yoursite/wsgi >
Order deny,allow
Allow from all
</Directort>
2016-07-02 13:46:09 +02:00
2016-07-03 00:58:05 +02:00
2. Then create the `` /yoursite/cfg/pypiserver.wsgi `` file and make sure that
the `` user `` and `` group `` of the `` WSGIDaemonProcess `` directive
(`` pypisrv:pypisrv `` in the example) have the read permission on it::
2012-03-26 02:22:41 +02:00
2016-07-03 00:58:05 +02:00
import pypiserver
2012-03-26 02:22:41 +02:00
2016-07-03 00:58:05 +02:00
conf = pypiserver.default_config(
root = "/yoursite/packages",
password_file = "/yoursite/htpasswd", )
application = pypiserver.app(**conf)
.. Tip ::
2019-09-11 00:35:18 +02:00
If you have installed `` pypiserver `` in a virtualenv, follow `` mod_wsgi `` 's
2016-07-03 00:58:05 +02:00
`instructions <http://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html> `_
and prepend the python code above with the following::
2016-07-02 13:46:09 +02:00
2016-07-03 00:58:05 +02:00
import site
site.addsitedir('/yoursite/venv/lib/pythonX.X/site-packages')
.. Note ::
For security reasons, notice that the `` Directory `` directive grants access
2019-09-11 00:35:18 +02:00
to a directory holding the `` wsgi `` start-up script, alone; nothing else.
2020-01-12 00:23:07 +01:00
2020-01-11 23:55:17 +01:00
.. Note ::
To enable HTTPS support on Apache, configure the directive that contains the
WSGI configuration to use SSL.
2016-07-03 00:58:05 +02:00
2019-09-11 00:35:18 +02:00
`` gunicorn ``
~~~~~~~~~~~~
2016-07-03 00:58:05 +02:00
2019-09-11 00:35:18 +02:00
The following command uses `` gunicorn `` to start `` pypiserver `` ::
2016-07-03 00:58:05 +02:00
gunicorn -w4 'pypiserver:app(root="/home/ralf/packages")'
or when using multiple roots::
gunicorn -w4 'pypiserver:app(root=["/home/ralf/packages", "/home/ralf/experimental"])'
2012-03-26 02:22:41 +02:00
2019-09-11 00:35:18 +02:00
`` paste ``
~~~~~~~~~
2015-02-27 23:02:07 +01:00
2016-06-23 21:17:13 +02:00
`paste <http://pythonpaste.org/> `_ allows to run multiple WSGI applications
2019-09-11 00:35:18 +02:00
under different URL paths. Therefore it is possible to serve different set
2016-06-23 21:17:13 +02:00
of packages on different paths.
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
The following example `` paste.ini `` could be used to serve stable and
2012-04-08 00:29:14 +02:00
unstable packages on different paths::
2016-06-23 21:17:13 +02:00
[composite:main]
use = egg:Paste#urlmap
/unstable/ = unstable
/ = stable
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
[app:stable]
use = egg:pypiserver#main
root = ~/stable-packages
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
[app:unstable]
use = egg:pypiserver#main
root = ~/stable-packages
~/unstable-packages
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
[server:main]
use = egg:gunicorn#main
host = 0.0.0.0
port = 9000
workers = 5
accesslog = -
2012-04-08 00:29:14 +02:00
2015-02-27 23:02:07 +01:00
.. Note ::
2016-06-23 21:17:13 +02:00
You need to install some more dependencies for this to work, like::
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
pip install paste pastedeploy gunicorn pypiserver
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
The server can then start with::
2012-04-08 00:29:14 +02:00
2016-06-23 21:17:13 +02:00
gunicorn_paster paste.ini
2012-04-08 00:29:14 +02:00
2016-07-02 13:46:09 +02:00
2019-09-11 00:35:18 +02:00
Behind a Reverse Proxy
2016-09-06 09:42:50 +02:00
----------------------
2019-09-11 00:35:18 +02:00
You can run `` pypiserver `` behind a reverse proxy as well.
2016-09-06 09:42:50 +02:00
Nginx
~~~~~
2019-09-11 00:35:18 +02:00
2016-09-06 09:42:50 +02:00
Extend your nginx configuration::
upstream pypi {
server pypiserver.example.com:12345 fail_timeout=0;
}
server {
2019-05-05 23:47:06 +02:00
server_name myproxy.example.com;
2016-09-06 09:42:50 +02:00
location / {
proxy_set_header Host $host:$server_port;
2017-11-25 01:26:43 +01:00
proxy_set_header X-Forwarded-Proto $scheme;
2016-09-06 09:42:50 +02:00
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://pypi;
}
}
2019-05-05 23:47:06 +02:00
As of pypiserver 1.3, you may also use the `X-Forwarded-Host` header in your
reverse proxy config to enable changing the base URL. For example if you
want to host pypiserver under a particular path on your server::
upstream pypi {
server locahost:8000;
}
server {
location /pypi/ {
proxy_set_header X-Forwarded-Host $host:$server_port/pypi;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://pypi;
}
}
2019-09-11 00:35:18 +02:00
Supporting HTTPS
~~~~~~~~~~~~~~~~
2019-05-05 23:47:06 +02:00
Using a reverse proxy is the preferred way of getting pypiserver behind
2019-09-11 00:35:18 +02:00
HTTPS. For example, to put pypiserver behind HTTPS on port 443, with
2019-05-05 23:47:06 +02:00
automatic HTTP redirection, using `nginx` ::
upstream pypi {
server localhost:8000;
}
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name pypiserver.example.com;
ssl_certificate /etc/star.example.com.crt;
ssl_certificate_key /etc/star.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://pypi;
}
}
Please see `nginx's HTTPS docs for more details <http://nginx.org/en/docs/http/configuring_https_servers.html> `_ .
Getting and keeping your certificates up-to-date can be simplified using,
for example, using `certbot and letsencrypt <https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-18-04> `_ .
2020-01-20 01:30:10 +01:00
Traefik
~~~~~~~
It is also possible to use `Traefik <https://docs.traefik.io/> `_ to put pypiserver behind HTTPS on port 443, with
automatic HTTP redirection using Docker Compose. Please see the provided `<docker-compose.yml>`_ example for more information.
2016-07-02 13:46:09 +02:00
Utilizing the API
-----------------
2019-09-11 00:35:18 +02:00
2016-07-02 13:46:09 +02:00
In order to enable ad-hoc authentication-providers or to use WSGI-servers
2019-09-11 00:35:18 +02:00
not supported by *bottle* out-of-the-box, you needed to launch `` pypiserver ``
2016-07-02 13:46:09 +02:00
via its API.
2019-09-11 00:35:18 +02:00
- The main entry-point for configuring `` pypiserver `` is the `pypiserver:app()
2016-07-02 13:46:09 +02:00
<https://github.com/pypiserver/pypiserver/blob/master/pypiserver/__init__.py#L116>`_
function. This function returns the internal WSGI-app that you my then
send to any WSGI-server you like.
- To get all `` pypiserver:app() `` keywords and their explanations, read the
function `pypiserver:default_config()
<https://github.com/pypiserver/pypiserver/blob/master/pypiserver/__init__.py#L35>`_.
- Finally, to fire-up a WSGI-server with the configured app, invoke
the `` bottle:run(app, host, port, server) `` function.
2019-09-11 00:35:18 +02:00
Note that `` pypiserver `` ships with it is own copy of *bottle* ; to use it,
2016-07-02 13:46:09 +02:00
import it like that: `` from pypiserver import bottle ``
2019-09-11 00:35:18 +02:00
Using Ad-Hoc Authentication Providers
2016-07-02 13:46:09 +02:00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-09-11 00:35:18 +02:00
2016-06-25 04:02:59 +02:00
The `` auther `` keyword of `` pypiserver:app() `` function maybe set only using
the API. This can be any callable that returns a boolean when passed
the *username* and the *password* for a given request.
For example, to authenticate users based on the `` /etc/passwd `` file under Unix,
you may delegate such decisions to the `python-pam`_ library by following
these steps:
1. Ensure `` python-pam `` module is installed::
pip install python-pam
2. Create a python-script along these lines::
$ cat > pypiserver-start.py
import pypiserver
from pypiserver import bottle
import pam
2016-09-23 05:54:04 +02:00
app = pypiserver.app(root='./packages', auther=pam.authenticate)
2016-06-25 04:02:59 +02:00
bottle.run(app=app, host='0.0.0.0', port=80, server='auto')
[Ctrl+ D]
2019-09-11 00:35:18 +02:00
3. Invoke the python-script to start-up `` pypiserver `` ::
2016-06-25 04:02:59 +02:00
$ python pypiserver-start.py
.. Note ::
The `python-pam`_ module, requires *read* access to `` /etc/shadow `` file;
2019-09-11 00:35:18 +02:00
you may add the user under which `` pypiserver `` runs into the *shadow*
2016-06-25 04:02:59 +02:00
group, with a command like this: `` sudo usermod -a -G shadow pypy-user `` .
2012-04-08 00:29:14 +02:00
2015-02-27 23:02:07 +01:00
Sources
=======
2019-09-11 00:35:18 +02:00
2016-06-23 21:17:13 +02:00
To create a copy of the repository, use::
2011-08-01 23:09:42 +02:00
2016-06-23 21:17:13 +02:00
git clone https://github.com/pypiserver/pypiserver.git
cd pypiserver
2011-08-01 23:09:42 +02:00
2016-06-23 21:17:13 +02:00
To receive any later changes, in the above folder use::
2015-03-08 18:37:34 +01:00
2016-06-23 21:17:13 +02:00
git pull
2011-08-01 23:09:42 +02:00
2011-07-29 03:14:09 +02:00
2016-01-19 20:22:42 +01:00
Known Limitations
=================
2019-09-11 00:35:18 +02:00
`` pypiserver `` does not implement the full API as seen on PyPI_. It
2017-03-19 21:10:01 +01:00
implements just enough to make `` easy_install `` , `` pip install `` , and
`` search `` work.
2011-07-31 23:42:37 +02:00
The following limitations are known:
2015-12-21 11:49:14 +01:00
- Command `` pypi -U `` that compares uploaded packages with *pypi* to see if
2016-06-23 21:17:13 +02:00
they are outdated, does not respect a http-proxy environment variable
2016-07-03 00:58:05 +02:00
(see `#19 <https://github.com/pypiserver/pypiserver/issues/19> `_ ).
2015-02-27 23:02:07 +01:00
- It accepts documentation uploads but does not save them to
2016-07-03 00:58:05 +02:00
disk (see `#47 <https://github.com/pypiserver/pypiserver/issues/47> `_ for a
2014-03-05 22:53:09 +01:00
discussion)
2016-01-19 20:22:42 +01:00
- It does not handle misspelled packages as *pypi-repo* does,
2016-06-23 21:17:13 +02:00
therefore it is suggested to use it with `` --extra-index-url `` instead
2016-07-03 00:58:05 +02:00
of `` --index-url `` (see `#38 <https://github.com/pypiserver/pypiserver/issues/38> `_ ).
2015-09-11 18:40:07 +02:00
2016-06-23 21:17:13 +02:00
Please use Github's `bugtracker <https://github.com/pypiserver/pypiserver/issues> `_
2016-01-19 20:22:42 +01:00
for other bugs you find.
2011-08-01 23:09:42 +02:00
2011-07-31 23:42:37 +02:00
Similar Projects
2015-02-27 23:02:07 +01:00
================
2019-09-11 00:35:18 +02:00
2011-07-31 23:42:37 +02:00
There are lots of other projects, which allow you to run your own
2019-09-11 00:35:18 +02:00
PyPI server. If `` pypiserver `` doesn't work for you, the following are
2015-02-27 23:02:07 +01:00
among the most popular alternatives:
2011-07-31 23:42:37 +02:00
2018-06-12 03:27:09 +02:00
- `devpi-server <https://pypi.org/project/devpi/> `_ :
a reliable fast pypi.org caching server, part of
2015-09-11 18:40:07 +02:00
the comprehensive `github-style pypi index server and packaging meta tool
2018-06-12 03:27:09 +02:00
<https://pypi.org/project/devpi/>`_.
2015-03-08 17:38:35 +01:00
(version: 2.1.4, access date: 8/3/2015)
2015-09-11 18:40:07 +02:00
- `pip2pi <https://github.com/wolever/pip2pi> `_
2015-03-08 17:38:35 +01:00
a simple cmd-line tool that builds a PyPI-compatible local folder from pip requirements
(version: 0.6.7, access date: 8/3/2015)
2011-08-09 23:47:34 +02:00
2016-01-17 19:27:58 +01:00
- `flask-pypi-proxy <http://flask-pypi-proxy.readthedocs.org/> `_
A proxy for PyPI that also enables also uploading custom packages.
2016-06-23 21:17:13 +02:00
- `twine`_ :
2019-09-11 00:35:18 +02:00
A command-line utility for interacting with PyPI or `` pypiserver `` .
2016-06-23 21:17:13 +02:00
2016-06-23 05:03:40 +02:00
- `pypi-uploader`_ :
2019-09-11 00:35:18 +02:00
A command-line utility to upload packages to your `` pypiserver `` from pypi without
2016-06-23 05:03:40 +02:00
having to store them locally first.
2019-06-11 00:54:38 +02:00
- Check this SO question: `How to roll my own pypi
2016-06-23 21:17:13 +02:00
<http://stackoverflow.com/questions/1235331/how-to-roll-my-own-pypi>`_
2015-03-08 18:37:34 +01:00
2016-07-02 13:46:09 +02:00
Licensing
=========
2015-03-08 18:37:34 +01:00
2019-09-11 00:35:18 +02:00
`` pypiserver `` contains a copy of bottle_ which is available under the
MIT license, and the remaining part is distributed under the zlib/libpng license.
See the `` LICENSE.txt `` file.
2013-05-29 00:15:35 +02:00
2015-02-27 23:02:07 +01:00
2011-07-31 23:42:37 +02:00
.. _bottle: http://bottlepy.org
2018-06-12 03:27:09 +02:00
.. _PyPI: https://pypi.org
.. _twine: https://pypi.org/project/twine/
.. _pypi-uploader: https://pypi.org/project/pypi-uploader/
.. _python-pam: https://pypi.org/project/python-pam/
2019-10-19 20:05:52 +02:00
.. |travis-status| image :: https://travis-ci.org/pypiserver/pypiserver.svg
:alt: Travis build status
2015-03-08 23:21:35 +01:00
:scale: 100%
2019-10-19 20:05:52 +02:00
:target: https://travis-ci.org/pypiserver/pypiserver
2015-03-08 23:21:35 +01:00
2015-09-11 18:40:07 +02:00
.. |pypi-ver| image :: https://img.shields.io/pypi/v/pypiserver.svg
2018-06-12 03:27:09 +02:00
:target: https://pypi.org/project/pypiserver/
2015-03-08 23:21:35 +01:00
:alt: Latest Version in PyPI
2015-09-11 18:40:07 +02:00
.. |python-ver| image :: https://img.shields.io/pypi/pyversions/pypiserver.svg
2018-06-12 03:27:09 +02:00
:target: https://pypi.org/project/pypiserver/
2015-09-11 18:40:07 +02:00
:alt: Supported Python versions
2015-03-08 23:21:35 +01:00
2015-09-21 04:38:47 +02:00
.. |proj-license| image :: https://img.shields.io/badge/license-BSD%2Bzlib%2Flibpng-blue.svg
2015-09-11 18:40:07 +02:00
:target: https://raw.githubusercontent.com/pypiserver/pypiserver/master/LICENSE.txt
:alt: Project License
.. |dependencies| image :: https://img.shields.io/requires/github/pypiserver/pypiserver.svg
2016-06-28 13:42:54 +02:00
:target: https://requires.io/github/pypiserver/pypiserver/requirements/
2015-09-11 18:40:07 +02:00
:alt: Dependencies up-to-date?