Using a private pypi repository with pypiserver (and alternatives)
Some options:
- Create your own PyPi server
- Use Dumb PyPi to generate and farm out the context to a simple web server.
- Some other options such as PyPiCloud which falls in between the two above.
Using PyPiServer
Depending on your workflow, and how frequently and many packages are updated, PyPi server may be the most suitable, it does require an application server (python/bottle) to function, but does not require the whole thing to be rebuilt and pushed as the static version, and can handle authentication for actions (configurable).
For this case, to make things even easier, we will use the PyPiServer docker image to get going even faster, if you do not use Docker then the full installation can be achieved, or use of the static solutions mentioned.
Installation
On your Docker host extract or checkout the docker project for PyPiServer.
$ mkdir /srv/pypi
$ printf "USER:$(openssl passwd -crypt PASSWORD)\n" >> .htpasswd
$ docker run -t -i --rm \
-h pypi.mydomain.com \
-v /srv/pypi:/srv/pypi:rw \
-p <some_external_port>:80 \
--name pypi \
codekoala/pypi
You should now have a pypi server accessible on localhost:pypi.mydomain.com
.
Uploading to your server
The standard layour for any package to upload to PyPi looks like:
README.md
my_package
__init__.py
some_utility.py
setup.cfg
setup.py
The setup.cfg file is rather simple and looks like so:
[metadata]
description-file = README.md
As for setup.py, it will look like:
from distutils.core import setup
setup(
name = 'my_package',
packages = ['my_package'], # this must be the same as the name above
install_requires=[], # list any dependencies that must be installed to use this
version = '0.0.1',
description = 'My useful python library',
author = 'Your Name Here',
author_email = '[email protected]',
url = 'https://gitlab.com/your_name/your_repo', # Where the repo is
download_url = 'https://gitlab.com/your_name/your_repo/some_archive.tar.gz', # Archive you can curl
keywords = ['utilities'], # any useful keywords
classifiers = []
)
Obviously __init__.py
will expose the classes like:
from some_utility import Widget
Also, that is assuming some_utility.py looks like :
class Widget:
def __init__(self):
pass
One more thing, edit your ~/.pypirc :::ini [server-login] repository: https://pypi.mydomain.com username: USER password: PASSWORD
Now we can upload!
$ python3 setup.py sdist upload -r https://pypi.mydomain.com
Using pip to install
There are a couple of ways to do this:
Command line options
When you invoke pip, you can specify the private server as per below:
$ pip3 install my_package--trusted-host pypi.mydomain.com --index-url https://pypi.mydomain.com
Profile
Edit your ~/.bashrc
or ~/.zshrc
etc
export PIP_EXTRA_INDEX_URL=http://pypi.mydomain.com/simple/
PIP config
Edit ~/.pip/pip.conf
[global]
extra-index-url = http://pypi.mydomain.com/simple/
That's it, fire it up and you should see it go. You can also install packages that are on the regular pypi even if you have specified your private server, however I imagine conflicting names would install first from the private repo.
Using Dumb PyPi, etc
I could not get Dumb PyPi to work due to an import error with pip.wheel (not sure if a versioning issue, so I will not cover it in detail.
The layout of the python package is the same as the above when using the PyPiServer, as well as the client side installation using pip.
So the generation of the static html and upload to a webserver (and subsequent location of web content) will be what is different, depending on your needs.
Conclusion
Using a custom/private PyPi to distribute your python packages is fairly straight forward. It is cleaner and more elegant than using things such as git submodules and allows the packages to be delivered to almost any python installation.