Reputation: 3
I have been developing a python package recently and found that I need to access command line arguments many scripts removed from my main script. To maintain easy access to the original command line arguments, I have been using argparse to process the command line and then saving the dictionary of command line arguments using
import argparse
import json
parser = argparse.ArgumentParser()
# parser.add_argument() stuff here
args = parser.parse_args()
with open('commandLineArgs.json','w') as outfile:
json.dump(args.__dict__,outfile)
Then, the file "commandLineArgs.json" is available to any script that I add later and I don't have to pass arguments from file to file.
I feel like there is a more Pythonic way to do this (or even a way in argparse I didn't find). Does anyone know of a better (i.e., more Pythonic) way to do this?
=========
For reference, my python package is loosely structured as (and other users now are adding suboptionX.py files):
/main.py
/option1.py # based on command line arguments
/sub_option1.py # based on command line arguments for option1
/sub_option2.py
/option2.py, etc.
Upvotes: 0
Views: 1877
Reputation: 16580
Command-line arguments were made to be used in a top-down approach: the arguments are supplied to an entry point function (usually called main), which process the arguments, and then calls the subfunctions by supplying them the required arguments.
In your case, it seems you want your scripts to work the other way around: each module being independent from the parent module, and each needing access to the required arguments without being centralized by the parent module. In this case, a configuration file is the advisable way to go, so that any submodule or subscript can access the entire set of parameters without modifying the main() entry point. This is also more readable and manageable in the long run if your submodules use very different sets of arguments, as relevant parameters will be directly managed by the relevant submodule, instead of being managed by the top module containing the main().
From your description, it seems you are just basically creating a configuration file from the command-line arguments, which seems a bit redundant. You could just move all your command-line arguments to the json parser instead and invite your users to setup the config file themselves. Then, the only required command-line argument would be the location of the configuration file.
This is what I did when a had a similar need (many submodules must access different, possibly all, arguments) by creating a ConfigParser class to manage the loading from a configuration file, and I made all my submodules inherit the configuration file by subclassing the parent class which loads the ConfigParser. See:
ConfigParser class: https://github.com/lrq3000/author-detector/blob/master/authordetector/configparser.py
Base class which loads ConfigParser and is inherited by all children in submodules: https://github.com/lrq3000/author-detector/blob/master/authordetector/base.py
Using this scheme, by inheriting from the Base class, all subclasses also get access to all configuration arguments, without any explicit manipulation and without any memory overhead (since it's just a reference, the configuration isn't duplicated for each subclass). For example, if your module complex_math_func
requires a parameter called sigma
, you can just write this inside the definition of your module:
sigma = self.config.get("sigma")
This will automatically load the variable sigma from the configuration file, and if it doesn't exist, it will just return None so that you can set a default value. The submodule doesn't have to do any more user input/arguments processing, since it's automagically managed by the ConfigParser + Base classes.
Upvotes: 3