pythonpackagepython-wheelpython-click

Python package "click" causes "Error: Got unexpected extra arguments (sdist bdist_wheel)" when used in new package


I am attempting to create a Python package that can be used as a terminal command. My setup.py file looks like

import setuptools

# If the package is being updated (and not installed for the first time),
# save user-defined data.
try:
    import checklist
    update = True
except ModuleNotFoundError:
    update = False

if update:
    import os
    import pickle
    dir = os.path.join(os.path.dirname(checklist.__file__), 'user_settings')
    files = {}
    for file in os.listdir(dir):
        files[file] = pickle.load(open(os.path.join(dir, file), "rb"))

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="SampleName",
    version="0.2.0",
    author="Author1, Author2",
    author_email="email@email.com",
    description="words words words.",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/samplesample/sample1",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
        "Operating System :: OS Independent",
    ],
    entry_points='''
        [console_scripts]
        checklist=checklist.checklist:cli
    ''',
    python_requires='>=3.7',
    package_data={"checklist":["user_settings/*.pkl"]},
    include_package_data=True,
)

if update:
    for key in files:
        pickle.dump(files[key], open(os.path.join(dir, key), "wb"))

When I attempt to create the checklist package with the command

python setup.py sdist bdist_wheel

I get the message

Error: Got unexpected extra arguments (sdist bdist_wheel)

When I remove click from my environment, the wheel is created without a problem. This seems strange because my code uses click.

import os
import sys
import csv
import click
import datetime as dt
from datetime import datetime
from contextlib import suppress
import pickle


class UI:

    def __init__(self):
        <set variables>...

    <some methods>...

# noinspection SpellCheckingInspection
class Checklist(UI):

    def __init__(self):
        <set variables>...

        # start the process...
        while self.step_index < len(self.to_do):
            with suppress(ExitException):
                self.step()

    def step(self):
        self.__getattribute__(self.to_do[self.step_index])()
        self.step_index += 1
        self.overwrite = False

    <some methods>...


@click.command()
def cli():
    Checklist()

cli()

What could be causing this? How do I fix it?


Solution

  • It's amazing how a few small deviations from the best practice are chained together producing a major problem. :-)

    The problem with click is the following. If click is installed your setup.py imports the module you shown us above. And the module when imported runs cli(), said cli() calls @click.command() and that parses the command line (intended for setup.py, not for click) and produces the error.

    If click is NOT installed your setup.py tries import checklist and failed with ModuleNotFoundError. The exception is caught and ignored in setup.py and setup continues.

    To fix the problem make checklist a module that can be both run (to call cli()) and imported without calling cli():

    def main():
        cli()
    
    if __name__ == '__main__':
        main()