Package: pypi-parker
pypi-parkerlets you easily park package names on PyPI to protect users of your packages
from typosquatting.Typosquattingis a problem: in general, but also on PyPI. There are efforts being taken
by pypa toprotect core library names, but this does not (and really cannot and probably
should not attempt to) help individual package owners. For example,reqeustsrather thanrequests, orcrytpographyrather thancryptography. 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 whatpypi-parkersets out to do.ObjectivesSelf-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 introducepypi-parkerinto their existing package builds.Parked packages should:fail fast and notdo anything elsebe self documenting, both in metadata and in sourcecontain functionally completesetup.pyfiles to allow whitelisted external validators to workThereadme_renderervalidator is run on each generated package before building.What does it do?pypi-parkerprovides a custom distutils commandparkthat 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 Filepypi-parkeruses aconfigparserconfig file to determine what packages to generate and what metadata
to include with each.There are two special sections:namesandDEFAULT.DEFAULT: Values inDEFAULTare used if that key is not present in a package-specific section.names: Keys innamesare interpretted as package names that should all use only the values inDEFAULT.Unless otherwise indicated, all key/value pairs loaded for each package are loaded directly
into thesetupcall for that generated package.Special PackagesIf you want to specify custom values for specific packages, you can add additional sections
for those packages. For any sections found aside fromDEFAULTandnames, the section
name is used as the package name.Special Section Keysdescription_keys: This line-delimited value is used withstr.formatto build the
finaldescriptionvalue.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 theImportErrormessage in the generatedsetup.py.Default Valuesconfig file name:park.cfgclassifiers:Development Status :: 7 - Inactivedescription:parked usingpypi-parkerlong_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.Examplepark.cfg[DEFAULT]author:mattsb42[my-package-name]url:https://github.com/mattsb42/my-package-namedescription:This package is parked by {author}. See {url} for more information.description_keys:authorurlclassifiers:Development Status:: 7 - InactiveOperating System:: OS IndependentTopic:: UtilitiesGenerated setup.pyfromsetuptoolsimportsetupargs=' '.join(sys.argv).strip()ifnotany(args.endswith(suffix)forsuffixin['setup.py sdist','setup.py check -r -s']):raiseImportError('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$pipinstallmy-package-nameProcessingmy-package-nameCompleteoutputfromcommandpythonsetup.pyegg_info:Traceback(mostrecentcalllast):File"<string>",line1,in<module>File"/tmp/pip-oma2zoy6-build/setup.py",line6,in<module>raiseImportError('This package is parked by mattsb42. See https://github.com/mattsb42/my-package-name for more information.',)ImportError:Thispackageisparkedbymattsb42.Seehttps://github.com/mattsb42/my-package-nameformoreinformation.----------------------------------------Command"python setup.py egg_info"failedwitherrorcode1in/tmp/pip-oma2zoy6-build/Ok, how do I use it?Installpypi-parkerwherever you will be running your builds.pipinstallpypi-parkerDefine the package names you want to target in your config file.Callsetup.pywith theparkcommand.pythonsetup.pyparkIf you want to use a custom config file, specify it with thepark-configargument.pythonsetup.pypark--park-config={filename}Upload the resulting contents ofdistto your package index of choice.Example tox configuration[testenv:park]basepython=python3.6deps=setuptoolspypi-parkercommands=python setup.py park