24

I want to implement my pypy.py script on commandline, I need to work with setup tools but the console_script does not work properly as my pypy.py needs two arguments, please guide me how can I modify it properly to work on commendline.

python.py

def main(agru1, argu2):

    "do something"

 if __name__ == "__main__":
        main()

when I include it in my setup.py file, as console_script as follow

setup( 
     entry_points={
        'console_scripts': ['pypy = pypy.pypy:main'],
    }

)

And I get the following error when I run it on commandline:

Traceback (most recent call last):
File "/usr/local/bin/python", line 9, in <module>
load_entry_point('Pypy==0.1', 'console_scripts', 'pypy')()
TypeError: main() takes at least 2 arguments (0 given)
Gringo Suave
  • 29,931
  • 6
  • 88
  • 75
user3698773
  • 929
  • 2
  • 8
  • 15
  • You are meant to get the arguments from ``sys.argv``. They are not passed in. You can apply the argument parsing library to it to make it deal with options etc etc. – Graham Dumpleton Nov 23 '16 at 00:14

3 Answers3

25

The entry point must be a function that may be invoked using exactly zero arguments. If you want to pass in arguments from the command line, say you want to invoke it like:

$ pypy a1 a2

You need to read them from sys.argv instead. So your python module should contain this:

def program(arg1, arg2):
    print(arg1, arg2)

def main():
    import sys
    arg1, arg2 = sys.argv[1], sys.argv[2]
    program(arg1, arg2)

if __name__ == "__main__":
    main()

Alternatively, the main function may instead take an argv argument that defaults to sys.argv if importing sys is desirable at the top level of the module:

def main(argv=sys.argv):
    program(argv[1], argv[2])

Running that command as above should print out a1 a2 into the console. Error handling on user input is your own exercise.

metatoaster
  • 17,419
  • 5
  • 55
  • 66
  • Thanks, how should I include main(sys.argv[1], sys.argv[2]) in the setup.py ( as mentioned above) ? error still the same if I use your explanation .... ! – user3698773 Nov 28 '16 at 13:50
  • `setup.py` hooks into either `distutils` or `setuptools` and the underlying library have their own handling of `sys.argv` to process the commands, which will almost certainly clash with however you want to do this. Have you tried running my code as is? – metatoaster Nov 28 '16 at 21:48
  • Yes I have after that I responded and its the same error as mentioned above in the question. – user3698773 Nov 28 '16 at 23:40
  • 1
    Right, your setup.py calls main directly, not the _script_ directly as such; So modify the `main` method to not take anything and pass it to the actual program with the arguments. – metatoaster Nov 28 '16 at 23:54
2

Similar to the answer of metatoaster, instead of using sys.argv you can use argsparse https://docs.python.org/3/library/argparse.html, which makes the passing of argumnets a bit more user-friendly.

import argparse


if __name__ == "__main__":
  parser = argparse.ArgumentParser()
  parser.add_argument('--arg1', help='arg1 help')
  parser.add_argument('--arg2', help='arg2 help')
  args = parser.parse_args()
  print("arg1 {}, arg2 {}".format(args.arg1, args.arg2)

Call it like:

pypy --arg1 1 --arg2 2
Konstantin Grigorov
  • 1,356
  • 12
  • 20
  • 1
    While this is a clear example of using argparse it doesn't address how to use it in context of a `setup.py` using _console_script_. – matt wilkie Mar 15 '22 at 04:51
  • This should be the accepted answer if it is modified to use an entrypoint function, rather than the `if __name__ == "__main__"` method. The options here are to modify your entrypoint function to get args from sys.argv(as in the accepted answer), or argparse. Using argparse is more pythonic, and it works with console_script. – Benjamin Aug 11 '23 at 20:37
0

Recently I was facing a similar problem. The way I solved it was by calling the script directly using python -m <complete_script_path> arg1 arg2.

For example if my script file name is bar and it is present inside the package foo and the contents are as follows:

foo.py

def f1(a,b):
    return a+b
if __name__=="__main__":
   a = sys.argv[1]
   b = sys.argv[2]
   f1(a,b)

I can invoke foo as follows:

python -m foo.bar arg1 arg2

I dont have to pass it as a console_script inside setup function of setuptools.This solves problem of not being able to pass arguments to console scripts. Also I can package it inside the whl file during distribution.

MSS
  • 3,306
  • 1
  • 19
  • 50