I am starting to write a CLI using argparse library. This is my first attempt to structure a large project, usually I write single script. The CLI auto
is defined in a top
directory, helper functions are in a subfolder named project
and a main function (where I want to put the logic of my program) in sub-sub-folder named sync
.
Here is the tree-structure:
├── top/ ├── auto ├── __init__.py └── project/ ├── helper.py ├── __init__.py └── sync/ ├── __init__.py ├── sync_file.py
helper.py:
def play(device, verbose=False):
if verbose:
print device + "with verbose on"
else:
print device + "verbose off"
sync_file.py:
from .. import helper
def main(device, verbose=False):
helper.play(device,verbose)
if __name__ == '__main__':
#Test here the logic
main('omv')
main('omv',verbose=True)
auto:
#!/usr/bin/env python
import argparse
import project.sync.sync_file as logic_sync
def sync(args):
if args.verbose:
logic_sync.main(args.device,verbose=True)
else:
logic_sync.main(args.device)
parser = argparse.ArgumentParser(description='Info on my project')
subparsers = parser.add_subparsers()
sync_parser = subparsers.add_parser('sync', help='synchronize')
sync_parser.add_argument('--device', default='nas', help='specify the device name')
sync_parser.add_argument('--verbose', action='store_true', help='increase the output verbose')
sync_parser.set_defaults(func=sync) # set the default function to sync
if __name__ == '__main__':
args = parser.parse_args()
args.func(args)
After I've made the auto file executable chmode +x auto
I can use the CLI:
./auto sync
# nasverbose off
./auto sync --verbose
# naswith verbose on
I would like to keep this structure but I see a lot of repetition in propagating the verbose parameter from one file to another. Is there a better way to do it?
1 Answer 1
I would create a shared.py
module somewhere (I'll let you handle the import directory tree). It would just contain
args = None
Import it in all your modules and assign args
from argparser
directly to it.
Now shared.args
contains all the information (even device
that you did not ask for :))
Of course this is not reentrant because of the shared global structure, but if you need reentrancy, you just have to pass 1 parameter: a fake args
structure like argparse
created (see the FakeArgs
in syncfile.py
)
And when you're ready to create one single python singleton object to avoid too much parameter passing, just yell :)
in auto
code
#!/usr/bin/env python
import argparse
import shared
import project.sync.sync_file as logic_sync
def sync(args):
shared.args = args
logic_sync.main()
parser = argparse.ArgumentParser(description='Info on my project')
subparsers = parser.add_subparsers()
sync_parser = subparsers.add_parser('sync', help='synchronize')
sync_parser.add_argument('--device', default='nas', help='specify the device name')
sync_parser.add_argument('--verbose', action='store_true', help='increase the output verbose')
sync_parser.set_defaults(func=sync) # set the default function to sync
if __name__ == '__main__':
args = parser.parse_args()
args.func(args)
sync_file.py
code:
from .. import helper
import shared
def main():
helper.play()
if __name__ == '__main__':
#Test here the logic
# we don't have argparse module creating the structure
# for us ? what the heck? create a fake one
class FakeArgs:
def __init__(self):
self.verbose = False
self.device = 'omv'
shared.args = FakeArgs()
main()
shared.args.verbose = True
main()
helper.py
code:
import shared
def play():
if shared.args.verbose:
print shared.args.device + " with verbose on"
else:
print shared.args.device + " verbose off"
-
\$\begingroup\$ Thanks for your help. Your solution works quite well for me. Beside I have few questions on your comments. What do you mean with 'reentrancy'? How can I create single python singleton to avoid repetition? Can you point me in the right direction (a link to some other code for example) if you cannot give me an example here? thank you \$\endgroup\$diegus– diegus2016年10月03日 08:24:22 +00:00Commented Oct 3, 2016 at 8:24
-
\$\begingroup\$ reentrancy: means that if you're running concurrent threads you cannot modify your arguments: modifying arguments changes for all threads. But you can read the shared arguments across several threads. That's a limitation you may not be subjected to. \$\endgroup\$Jean-François Fabre– Jean-François Fabre2016年10月03日 09:11:56 +00:00Commented Oct 3, 2016 at 9:11