0

I'm pretty much a complete newbie when it comes to Python, and googling this leads to a lot of information about parameters... but not this specific question.

But here's the question: Is there an easy way to make a Python script require a variable when called from outside the script (e.g. Bash)? I realize I can just test on sys.argv, but it really seems like a clunky solution.

For example, could I construct this script so sys.argv[1] has to be passed to use the script without doing tests on it here?:

#!/usr/bin/env python
import string
import random
import sys

def RandomString(length=6):
    x=''.join(random.choice(string.ascii_uppercase) for i in range(length))
    return x

random.seed(sys.argv[1])
y=RandomString()
print y
user2875994
  • 195
  • 4
  • 13
  • You do realize that your question is "Can I write a script that requires a certain variable to exist without writing any code that actually ensures that the variable exists?" right? – Etan Reisner Sep 17 '14 at 23:15
  • If I understand what you're saying, you want the requirement to somehow be checked before your script is run. This is therefore not a Python question, but a shell question. – jscs Sep 17 '14 at 23:16
  • How would arguments be nonoptional other than by the code erroring when the argument is missing? – khelwood Sep 17 '14 at 23:16
  • @Etan Reisner It seems like a functionality which would make sense if it already exists in the language. If it doesn't, then I'll create it, but if it does it'd be great, hence the question. – user2875994 Sep 17 '14 at 23:17
  • ah, the good old days of DCL... – isedev Sep 17 '14 at 23:19
  • 1
    possible duplicate of [What's the best way to grab/parse command line arguments passed to a Python script?](http://stackoverflow.com/questions/20063/whats-the-best-way-to-grab-parse-command-line-arguments-passed-to-a-python-scri) See also [Argument parsing in Python: required vs. optional](http://stackoverflow.com/q/24833054) – jscs Sep 17 '14 at 23:25
  • Certainly, it is entirely possible for a language to have a built-in assertion system for arguments handled by the language runtime. Powershell does this for example. I just wanted to make sure you (and other readers) understood the tl;dr (if you will) of the question. – Etan Reisner Sep 17 '14 at 23:25
  • 1
    How does your script run if you don't give it that argument? It raises an error, right? Isn't that what any 'requirement' would do - raise an error if you don't give it the right arguments? So the real question is: `what kind of error message do you want?`. – hpaulj Sep 18 '14 at 00:09
  • Maybe I just don't understand the question, or why explicit testing of argv is clunky. Explicit testing of argv is better than implicit magic. (Of course, I agree that using a module to parse args in a fancy command line is superior than doing it by directly messing with argv). FWIW, for simple scripts that take a single arg to pass to `random.seed()`, I tend to do something like: `random.seed(argv[1] if len(argv)>1 else None)`, so I get the system time seed if I don't pass one explicitly... but I guess this is violating 'Explicit is better than implicit'. :) – PM 2Ring Sep 18 '14 at 09:54

4 Answers4

2

Use the argparse module. You can define positional arguments that are required, and it will return an error if that argument is not included.

parser = argparse.ArgumentParser()
parser.add_argument('RandomSeed')
args = parser.parse_args()

random.seed(args.RandomSeed)

Usage of the above to lines from bash would be something like:

python main.py thisisarandomstring

Argparse is a nice way to parse your arguments for a command line application(and is a preferred, or good avenue to take when you make a command line app). It automatically generates you some help pages and other documentation, and generates appropriate errors without you having to do all the overehead yourself.

Check out this link for a pretty nice tutorial.

KDEx
  • 3,505
  • 4
  • 31
  • 39
  • @user2875994 tried to make it a little more clear if this is all new – KDEx Sep 18 '14 at 01:50
  • @user2875994: beware, if the argument looks like an option (starts with `-` then [`argparse` won't recognize it as `randomseed` argument](http://ideone.com/H7qNV3)) – jfs Sep 18 '14 at 03:35
  • You could call the script with `python main.py -- -randomstring`, although I won't argue that's an ideal solution. – chepner Sep 18 '14 at 03:52
  • @chepner can you hop on the python chat? I don't understand the edit you made, perhaps you can teach me? I don't see anything about RandomSeed on the docs – KDEx Sep 18 '14 at 03:53
  • Where in the code does it connect the argument "RandomSeed" to argv[1]? Is it add_argument()? If so, if I add multiple arguments, will the first one I add be argv[1], second one argv[2], etc.? Also, this might be a stupid question, but what does it mean to parse an argument? Thanks. – user2875994 Sep 18 '14 at 10:54
1
  • Argparser is not safe. "Argparse has built-in magic behavior to guess if something is an argument or an option." "Argparse currently does not support disabling of interspearsed arguments." Ref: http://click.pocoo.org/3/why/
  • You should always check argv because that is what is going to be used in your later code. Avoiding it seems nonsensical.

An answer without running "tests" on argv the best I know how to. At least here we are not looking at argv[1]:


#!/usr/bin/env python
import sys

if len(sys.argv) == 1:
    print 'not read in...exiting'
    exit()
print 'read in no problem'
PhysicalChemist
  • 540
  • 4
  • 14
  • I'm not entirely sure what is magical about "does the argument start with `-` (or a character in the parser's `prefix_chars` keyword argument)?". – chepner Sep 18 '14 at 03:12
  • 1
    @chepner: if OP wants to accept *any* first command-line parameter as a random seed then [`argparse`'s behaviour to recognize options won't be helpful here.](http://stackoverflow.com/questions/25901786/making-parameters-from-bash-nonoptional-in-python#comment40544373_25902841) – jfs Sep 18 '14 at 03:41
0

Here's one possible solution with argparse, that will allow any string as a first argument. It's got two serious problems though: you can't define any optional arguments, which leads to the need to disable the -h/--help option. The technique for disabling options is a bit of a hack. Looking at the source, it's not enough to set prefix_chars to an empty string, but a tuple whose first element is an empty string. or maybe just an empty sequence. There might be some other issues as well.

from argparse import ArgumentParser
p = ArgumentParser(add_help=False, prefix_chars=("",))
p.add_argument("randomseed")

args = p.parse_args()

random.seed(args.randomseed)

Then a call like

python main.py -foo

would set args.randomseed to the string -foo.

Given all this, I think you will just have to accept you'll have to verify in-script that sys.argv has at least one command-line argument, since there is no better way to have bash check for you.

try:
    randomseed = sys.argv[1]
except IndexError:
    # Do something here; I suggest just using a value that 
    # lets random.seed() invoke its default, no-argument behavior
    randomseed = None
chepner
  • 497,756
  • 71
  • 530
  • 681
-1

This an extremely rich resource you should read about this: https://stackoverflow.com/a/4118133/3767980

For below, I am just checking to see if the string has anything in it. If it is empty (not read in) it will print to the terminal and exit.

#!/usr/bin/env python
import string
import random
import sys

# testing argv[1]

if 'argv[1]' in locals():
    print 'read in, no problem'
else:
    print 'not read in...exiting'
    exit()
fi

References:

Community
  • 1
  • 1
PhysicalChemist
  • 540
  • 4
  • 14
  • Unless I misunderstood your post, this seems to be exactly what I asked if you could avoid - running tests on the argv. I'm looking into KDEx's posted answer at the moment. – user2875994 Sep 18 '14 at 01:46
  • Sorry, I misunderstood what you meant. See below. – PhysicalChemist Sep 18 '14 at 02:01
  • 1
    The string `argv[1]` is not going to appear as a key in the dictionary returned by `locals()`. – chepner Sep 18 '14 at 03:27
  • Not even `argv` is going to be in locals() unless you change the `import` statement to `from sys import argv`, but the existence (or not) of `argv` only demonstrates that you've imported it, which is not very useful in this context. – rici Sep 18 '14 at 04:52
  • I realized this was not the best solution so I submitted a new answer. But I figured it was still useful to leave this up. But yes, I agree with you. – PhysicalChemist Sep 18 '14 at 05:31