Prevent accidental publishing of a private Python package

It may occur that you have a Python package which for one reason or another is private and you don’t want someone to accidentally publish it to PyPi which is a public public repository of Python packages.

This can be achieved in many different ways. Two of the simplest ways to do that are documented bellow. Some of you might argue that those options are ugly, but they are simple and do the trick.

Option 1 - Disallowing “register” and “upload” command

This options simply prevents a user from calling setup.py with register and / or upload argument.

For example:

$ python setup.py register
Command "register" has been blacklisted, exiting...

To use it, simply put the following snippet in your setup.py before the setup function call.

    def forbid_publish():
        argv = sys.argv
        blacklist = ['register', 'upload']

        for command in blacklist:
            if command in argv:
                values = {'command': command}
                print('Command "%(command)s" has been blacklisted, exiting...' %
                      values)
                sys.exit(2)

    forbid_publish()

Option 2 - Forcing a custom PyPi repository

In some cases you don’t want to fully prevent publishing, but you only want to allow users to publish packages to your private PyPi repository.

You can do that and prevent accidental publishing to a public repository, by simply injecting --repository=<your repository name> option to the register and upload command.

Here is the code snippet which accomplishes that:

    def inject_custom_repository(repository_name):
        blacklist = ['register', 'upload']
        inject_arg = '--repository=%s' % (repository_name)

        for command in blacklist:
            try:
                index = sys.argv.index(command)
            except ValueError:
                continue

            sys.argv.insert(index + 1, inject_arg)

    inject_custom_repository('private_repository_1')

Same as above, to use it, simply put it in your setup.py file before the setup function call.

Keep in mind that you need to have an entry with key private_repository_1 in your ~/.pypirc config file for this code to work. If you don’t have it, you will receive an error similar to the one bellow:

Traceback (most recent call last):
  File "setup.py", line 58, in <module>
    'Topic :: Software Development :: Libraries :: Python Modules',
  File "/usr/lib/python2.7/distutils/core.py", line 152, in setup
    dist.run_commands()
  File "/usr/lib/python2.7/distutils/dist.py", line 953, in run_commands
    self.run_command(cmd)
  File "/usr/lib/python2.7/distutils/dist.py", line 972, in run_command
    cmd_obj.run()
  File "/usr/local/lib/python2.7/dist-packages/setuptools/command/register.py", line 9, in run
    _register.run(self)
  File "/usr/lib/python2.7/distutils/command/register.py", line 46, in run
    self._set_config()
  File "/usr/lib/python2.7/distutils/command/register.py", line 81, in _set_config
    raise ValueError('%s not found in .pypirc' % self.repository)
ValueError: private_repository_1 not found in .pypirc

You can find instructions which show how to add a new entry to your config file here.