Skip to main content
Latest Version Documentation Status https://travis-ci.org/mattsb42/pypi-parker.svg?branch=master

pypi-parker lets you easily park package names on PyPI to protect users of your packages from typosquatting.

Typosquatting is a problem: in general, but also on PyPI. There are efforts being taken by pypa to protect core library names, but this does not (and really cannot and probably should not attempt to) help individual package owners. For example, reqeusts rather than requests, or crytpography rather than cryptography. Because of the self-serve nature of PyPI, individual package owners are left to their own devices to protect their users. This is not inherently a problem: in my opinion this is a reasonable balance to keep the barrier to entry for publishing PyPI package low. However, tooling should exist to make it easy for package owners to protect their users. That is what pypi-parker sets out to do.

Objectives

  • Self-serve is a good thing. Let’s not try and get rid of that. Work with it instead.

  • Package owners should be able to easily protect users of their packages from malicious typosquatting.

  • It should be easy for package owners to introduce pypi-parker into their existing package builds.

  • Parked packages should:

    • fail fast and not do anything else

    • be self documenting, both in metadata and in source

    • contain functionally complete setup.py files to allow whitelisted external validators to work

      • The readme_renderer validator is run on each generated package before building.

What does it do?

pypi-parker provides a custom distutils command park that interprets a provided config file to generate empty Python package source distributables. These packages will always throw an ImportError when someone tries to install them. You can customize the ImportError message to help guide users to the correct package.

Using the Config File

pypi-parker uses a configparser config file to determine what packages to generate and what metadata to include with each.

There are two special sections: names and DEFAULT.

  • DEFAULT : Values in DEFAULT are used if that key is not present in a package-specific section.

  • names : Keys in names are interpretted as package names that should all use only the values in DEFAULT.

Unless otherwise indicated, all key/value pairs loaded for each package are loaded directly into the setup call for that generated package.

Special Packages

If you want to specify custom values for specific packages, you can add additional sections for those packages. For any sections found aside from DEFAULT and names, the section name is used as the package name.

Special Section Keys

  • description_keys : This line-delimited value is used with str.format to build the final description value.

  • classifiers : If multiple lines are provided for this value, and each line will be treated as a separate entry.

  • description :

    • This value cannot contain multiple lines.

    • This value is also used for the ImportError message in the generated setup.py.

Default Values

  • config file name : park.cfg

  • classifiers : Development Status :: 7 - Inactive

  • description : parked using pypi-parker

  • long_description :

    This package has been parked either for future use or to protect against typo misdirection.
    If you believe that it has been parked in error, please contact the package owner.

Example

park.cfg

[DEFAULT]
author: mattsb42

[my-package-name]
url: https://github.com/mattsb42/my-package-name
description: This package is parked by {author}. See {url} for more information.
description_keys:
    author
    url
classifiers:
    Development Status :: 7 - Inactive
    Operating System :: OS Independent
    Topic :: Utilities

Generated setup.py

from setuptools import setup

args = ' '.join(sys.argv).strip()
if not any(args.endswith(suffix) for suffix in ['setup.py sdist', 'setup.py check -r -s']):
    raise ImportError('This package is parked by mattsb42. See https://github.com/mattsb42/my-package-name for more information.')

setup(
    author='mattsb42',
    url='https://github.com/mattsb42/my-package-name',
    description='This package is parked by mattsb42. See https://github.com/mattsb42/my-package-name for more information.',
    classifiers=[
        'Development Status :: 7 - Inactive',
        'Operating System :: OS Independent',
        'Topic :: Utilities'
    ]
)

Install attempt

$ pip install my-package-name
Processing my-package-name
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-oma2zoy6-build/setup.py", line 6, in <module>
        raise ImportError('This package is parked by mattsb42. See https://github.com/mattsb42/my-package-name for more information.',)
    ImportError: This package is parked by mattsb42. See https://github.com/mattsb42/my-package-name for more information.

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-oma2zoy6-build/

Ok, how do I use it?

  1. Install pypi-parker wherever you will be running your builds.

pip install pypi-parker
  1. Define the package names you want to target in your config file.

  2. Call setup.py with the park command.

python setup.py park
  • If you want to use a custom config file, specify it with the park-config argument.

    python setup.py park --park-config={filename}
  1. Upload the resulting contents of dist to your package index of choice.

Example tox configuration

[testenv:park]
basepython = python3.6
deps =
    setuptools
    pypi-parker
commands = python setup.py park

Metadata

Release files for pypi-parker 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pypi-parker 0.1.2
File Size Uploaded
pypi-parker-0.1.2.tar.gz 11.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pypi-parker 0.1.2
File Interpreter ABI Platform
pypi_parker-0.1.2-py2.py3-none-any.whl Python 2, Python 3 none any Details

Total release size: 30.2 kB

Release files / pypi-parker-0.1.2.tar.gz

Download URL pypi-parker-0.1.2.tar.gz
Size 11.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ddda596ea3f9e0a6a5da911dfe2dfe1a5cefca0c6920b17c1c93068db2c28955
BLAKE2b-256 checksum
How to use checksums
b061af2176d7dd54be657b0e91a869ce30337978ecf8ac5f071a2157bef2200a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release files / pypi_parker-0.1.2-py2.py3-none-any.whl

Download URL pypi_parker-0.1.2-py2.py3-none-any.whl
Size 18.3 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
6da5ce5bcf3618ab3a86e3ae8310348a0fe75e88438f4f9bfbf0abf8fb7491ec
BLAKE2b-256 checksum
How to use checksums
d587950f91d500dcde81da51d2a7abbdcd606406dfc7e00f62a11c543958dd0b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page