1

arguments.py

import argparse

args = None
local_host = None


def pass_arguments():
    global args, local_host
    parser = argparse.ArgumentParser()
    parser.add_argument("host", help="Host URL", type=str, default="https://example.com")
    args = parser.parse_args()
    local_host = args.host

main.py

from arguments import *

pass_arguments()
print args.host
print local_host  # defined variable to simplify access

This results an error

    print args.host
AttributeError: 'NoneType' object has no attribute 'host'

Alternatively, I could use main.py

import arguments

arguments.pass_arguments()
print arguments.args.host
print arguments.local_host  # defined variable to simplify access

What is the best practice here?

Gayan Pathirage
  • 1,979
  • 1
  • 24
  • 21
  • 4
    Have `pass_arguments` return the `args` variable and avoid global variables:` args = arguments.pass_arguments()`. If you are seeking advice on how to structure your program, more information on your goals is needed. If you want to pass around the arguments, see also [this SO answer](https://stackoverflow.com/questions/44734858/python-calling-a-module-that-uses-argparser) – Pierre de Buyl Sep 14 '17 at 13:01
  • @PierredeBuyl Thanks but returning args also does not help since I wanted to use the same access method in multiple modules – Gayan Pathirage Sep 15 '17 at 11:01
  • You can call `pass_arguments` several times if needed. All it does is parse the `sys.argv` variables repeatedly. – Pierre de Buyl Sep 15 '17 at 14:38
  • @PierredeBuyl Thanks, I also learned the same. But seems like an overkill, since I only wanted to share already parsed. As a workaround, I used a class. – Gayan Pathirage Sep 22 '17 at 05:53

1 Answers1

0

I wondered the same thing... and thought "singleton", but given you are intending to share arguments across modules... it makes sense if your create a base_argparse module to share a singleton via base_argparse.ArgumentParser, this can then be used as a drop in replacement for argparse.ArgumentParser.

I did try Creating a singleton in Python but it seemed like overkill. (esp. if you want to share inter module)

Do let me know if you found a better way...

File: base_argparse.py

import argparse

_singleton=None
_description=""

def ArgumentParser(description=None, *arg_l, **arg_d): 
  global _singleton, _description
  if description: 
    if _description: _description+=" & "+description
    else: _description=description
  if _singleton is None: _singleton=argparse.ArgumentParser(description=_description, *arg_l, **arg_d)
  return _singleton

File: module_x.py

import sys
import base_argparse

parser = base_argparse.ArgumentParser(description='Module_X Arguments')

parser.add_argument('-x', action="store_true", default=False)

if __name__=="__main__":
  opt_ns=parser.parse_args(sys.argv[1:])
  print opt_ns,opt_ns.x

File: module_y.py

import sys
import base_argparse

parser = base_argparse.ArgumentParser(description='Module_Y Arguments')

parser.add_argument('-y', action="store", dest="y")

if __name__=="__main__":
  opt_ns=parser.parse_args(sys.argv[1:])
  print opt_ns,opt_ns.y

File: module_z.py

import sys
import base_argparse

parser = base_argparse.ArgumentParser(description='Module_Z Arguments')

parser.add_argument('-z', action="store", dest="z", type=int)

if __name__=="__main__":
  opt_ns=parser.parse_args(sys.argv[1:])
  print opt_ns,opt_ns.z

File: test_argparse.py

import sys
import base_argparse

# in main ...
parser = base_argparse.ArgumentParser(description='Test Arguments')

# then the matching load modules
import module_x,module_y,module_z

if __name__=="__main__":

  parser.add_argument('-a', action="store_true", default=False)
  parser.add_argument('-b', action="store", dest="b")
  parser.add_argument('-c', action="store", dest="c", type=int)

  opt_ns=parser.parse_args(sys.argv[1:])
  print opt_ns,opt_ns.a,opt_ns.b,opt_ns.c,opt_ns.x,opt_ns.y,opt_ns.z

Test cases:

$ python test_argparse.py

Namespace(a=False, b=None, c=None, x=False, y=None, z=None) False None None False None None

$ python module_x.py -x

Namespace(x=True) True

$ python module_x.py -a -b 2 -c 3 -x -y 25 -z 26

usage: module_x.py [-h] [-x]
module_x.py: error: unrecognized arguments: -a -b 2 -c 3 -y 25 -z 26

$ python test_argparse.py -a -b 2 -c 3

Namespace(a=True, b='2', c=3, x=False, y=None, z=None) True 2 3 False None None

$ python test_argparse.py -x -y 25 -z 26

Namespace(a=False, b=None, c=None, x=True, y='25', z=26) False None None True 25 26

$ python test_argparse.py -a -b 2 -c 3 -x -y 25 -z 26

Namespace(a=True, b='2', c=3, x=True, y='25', z=26) True 2 3 True 25 26
NevilleDNZ
  • 1,269
  • 12
  • 31