"""
Generic utility to create commonly used ArgumentParser
options etc.
"""
from sisl.utils.ranges import strmap, strseq
[docs]def argv_negative_fix(argv):
""" Fixes the `argv` list by adding a space for input that may be float's """
rgv = []
for a in argv:
try:
strseq(complex, a)
strmap(complex, a)
except:
rgv.append(a)
else:
rgv.append(' ' + a)
return rgv
[docs]def default_namespace(*args, **kwargs):
class CustomNamespace(object):
pass
namespace = CustomNamespace()
namespace._actions_run = False
namespace._actions = []
for key in kwargs:
setattr(namespace, key, kwargs[key])
return namespace
[docs]def ensure_namespace(p, ns):
"""
Ensure a namespace passed in case it is not.
This is currently a hack for:
https://bugs.python.org/issue27859
"""
old_parse_known_args = p.parse_known_args
def parse_known_args(self, argv, namespace=None):
if namespace is None:
return old_parse_known_args(argv, ns)
return old_parse_known_args(argv, namespace)
p.parse_known_args = parse_known_args
[docs]def collect_arguments(argv, input=False,
argumentparser=None,
namespace=None):
"""
Function for returning the actual arguments depending on the input options.
This function will create a fake `ArgumentParser` which then
will pass through the input figuring out which options
that should be given to the final `ArgumentParser`.
Parameters
----------
argv : ``list`` of ``str``
the argument list that comprise the arguments
input : ``bool``, ``False``
whether or not the arguments should also gather
from the input file.
argumentparser : ``argparse.ArgumentParser``
the argument parser that should add the options that we find from
the output and input files.
namespace : ``Namespace``
the namespace for the argument parser.
"""
# First we figure out the input file, and the output file
import argparse
import sisl
import sys, os, os.path as osp
# Create the default namespace in case there is none
if namespace is None:
namespace = default_namespace()
if input:
# Grap input-file
p = argparse.ArgumentParser('Parser for input file', add_help=False)
# Now add the input and output file
p.add_argument('input_file', nargs='?', default=None)
# Retrieve the input file
# (return the remaining options)
args, argv = p.parse_known_args(argv)
input_file = args.input_file
else:
input_file = None
# Grap output-file
p = argparse.ArgumentParser('Parser for output file', add_help=False)
p.add_argument('--out', '-o', nargs=1, default=None)
# Parse the passed args to sort out the input file and
# the output file
args, _ = p.parse_known_args(argv)
if input_file is not None:
try:
obj = sisl.get_sile(input_file)
argumentparser, namespace = obj.ArgumentParser(argumentparser, namespace=namespace,
**obj._ArgumentParser_args_single())
# Be sure to add the input file
setattr(namespace, '_input_file', input_file)
except Exception as e:
print(e)
raise ValueError("File: '"+input_file+"' cannot be found. Please supply a readable file!")
if args.out is not None:
try:
obj = sisl.get_sile(args.out[0], mode='r')
obj.ArgumentParser_out(argumentparser, namespace=namespace)
except Exception as e:
pass
return argumentparser, namespace, argv
[docs]def dec_default_AP(*A_args, **A_kwargs):
"""
Decorator for routines which takes a parser as argument
and ensures that it is _not_ `None`.
"""
def default_AP(func):
# This requires that the first argument
# for the function is the parser with default=None
from argparse import ArgumentParser
def new_func(self, parser=None, *args, **kwargs):
if parser is None:
# Create the new parser and insert in the
# argument list
parser = ArgumentParser(*A_args, **A_kwargs)
return func(self, parser, *args, **kwargs)
return new_func
return default_AP
[docs]def dec_collect_action(func):
"""
Decorator for collecting actions until the namespace `_actions_run` is `True`.
Note that the `Namespace` object is the 2nd argument.
"""
def collect(self, *args, **kwargs):
if args[1]._actions_run:
return func(self, *args, **kwargs)
# Else we append the actions to be performed
args[1]._actions.append((self, args, kwargs))
return None
return collect
[docs]def dec_collect_and_run_action(func):
"""
Decorator for collecting actions and running.
Note that the `Namespace` object is the 2nd argument.
"""
def collect(self, *args, **kwargs):
if args[1]._actions_run:
return func(self, *args, **kwargs)
args[1]._actions.append((self, args, kwargs))
return func(self, *args, **kwargs)
return collect
[docs]def dec_run_actions(func):
"""
Decorator for running collected actions.
Note that the `Namespace` object is the 2nd argument.
"""
def run(self, *args, **kwargs):
args[1]._actions_run = True
# Run all so-far collected actions
for A, Aargs, Akwargs in args[1]._actions:
A(*Aargs, **Akwargs)
args[1]._actions_run = False
args[1]._actions = []
return func(self, *args, **kwargs)
return run