import argparse
import logging
handlers = [logging.FileHandler('logger.log',mode='a'), logging.StreamHandler() ]
logging.basicConfig( level=logging.DEBUG,format='[%(levelname)s] %(message)s' ,handlers = handlers )
parser = argparse.ArgumentParser();
parser = argparse.ArgumentParser(description="./script.py --db <db path> --scratch <scratch path> ")
required_args = parser.add_argument_group('required arguments')
required_args.add_argument('--db' , '-d', type=str, help='db directory name. Default is release',required=True)
required_args.add_argument('--scratch', '-s', type=str, help='Scratch path where report will be written')
try:
args = parser.parse_args()
except SystemExit as se:
logging.fatal("Invalid Command line argument:" )
My code is something like the above. I want to capture invalid exception arguments into the logger at the last line where I am capturing the exception. In precise whatever the message argparse is printing on stdout for any invalid arguments, I want to redirect all of them to my logger. Can you please let me how can I do it?
Related
I want to create a script that takes two arguments that should be consumed:
directory_path,
files -- the list of files under the directory_path argument.
I've written something like that:
#!/usr/bin/python3
import argparse
import os
import argcomplete
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("directory_path",
help="a path to some directory",
nargs=1)
# conditional choices of an argument
conditional_choices = [os.listdir(parser.parse_known_args()[0].directory_path[0])]
parser.add_argument("files",
metavar="FILES",
nargs='+',
choices=conditional_choices)
argcomplete.autocomplete(parser)
args = parser.parse_args()
print("directory_path {}".format(args.directory_path))
print("files {}".format(args.files))
So the files argument depends on the directory_path argument.
Using: Python3.8
Problems
For the above snippet, the bash-completion (built from register-python-argcomplete3) for a files argument doesn't work.
If I push enter after the valid command (with path and file) then I'm getting an error
error: argument FILES: invalid choice: ...
First is worth step in argcomplete documentation based on which I created a solution
#!/usr/bin/python3
# PYTHON_ARGCOMPLETE_OK
import argparse
import os
import argcomplete
def files_names(prefix, parsed_args, **kwargs):
absolute_pat = os.path.abspath(parsed_args.directory_path[0])
files = [file for file in os.listdir(absolute_pat) if os.path.isfile(os.path.join(absolute_pat, file))]
return files
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("directory_path",
help="a path to some directory",
nargs=1)
parser.add_argument("files",
metavar="FILES",
nargs='+').completer = files_names
argcomplete.autocomplete(parser)
args = parser.parse_args()
print("directory_path {}".format(args.directory_path))
print("files {}".format(args.files))
*usesfull snippet from argcomplete test directory
To debugging the completion you can set the _ARC_DEBUG variable in your shell to enable verbose debug output
Here is the code.
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description="infomedia"
)
parser.add_argument("file", help="path to file")
parser.add_argument(
"-i",
"--info",
type=str,
default="False",
help="get information about",
)
cli_args = parser.parse_args()
worker = Worker(
cli_args.input,
cli_args.info,
)
worker._application()
When the program is running with -h / --help it shows the default values.
positional arguments:
file path to file
optional arguments:
-h, --help show this help message and exit
-i INFO, --info INFO get information about (default: False)
How to avoid printing the default values? Or is there a way to define the default values of this code in a different way?
You can create new class inheriting from argparse.ArgumentDefaultsHelpFormatter and override _get_help_string method and pass your newly created class which is MyHelpFormatter in the below example as formatter_class in ArgumentParser constructor. Here is the example code which can help you:
import argparse
class MyHelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
def _get_help_string(self, action):
return action.help
def main():
parser = argparse.ArgumentParser(
formatter_class=MyHelpFormatter,
description="infomedia",
)
parser.add_argument("file", help="path to file")
parser.add_argument(
"-i",
"--info",
type=str,
default="False",
help="get information about",
)
cli_args = parser.parse_args()
if __name__ == "__main__":
main()
I think you want more like:
parser.add_argument("--info", help="get information", action="store_true")
I'm trying to create own Logger class and then reuse it in other modules.
Logger class is:
mypackage/log_class.py:
import logging
from logging.handlers import TimedRotatingFileHandler
class MyLogger(logging.Logger):
def __init__(
self, name = "MyLoggerName2222", log_file = None,
log_format = "%(asctime)s: Line %(lineno)s: %(levelname)s: %(message)s"):
self.formatter = logging.Formatter(log_format)
self.log_file = log_file
super().__init__(name=name)
# Adding handlers
self.addHandler(self.get_stream_handler())
if log_file:
self.addHandler(self.get_file_handler(log_file))
self.propagate = True
def get_stream_handler(self):
""" Returns stream handler
"""
# Initialize stream hamdler
streamhandler = logging.StreamHandler()
# Logging level
streamhandler.setLevel(logging.DEBUG)
# Formatter
streamhandler.setFormatter(self.formatter)
return streamhandler
def get_file_handler(self, log_file):
""" Returns file handler
"""
# Initialize stream hamdler
filehandler = TimedRotatingFileHandler(filename=log_file,
when="midnight",
backupCount=5)
# Logging level
filehandler.setLevel(logging.INFO)
# Formatter
filehandler.setFormatter(self.formatter)
return filehandler
The module is:
mypackage/main.py
from log_class import MyLogger
import logging
logging.setLoggerClass(MyLogger)
logger = logging.getLogger("MyLogger", log_file="Test.log")
if __name__ == "__main__":
logger.debug("Debug message")
logger.info("Info message")
I've got the
TypeError: getLogger() got an unexpected keyword argument 'log_file'
When I remove log_file="Test.log" from the getLogger there are no errors, however no log message are shown. Neither in file nor in console.
What exactly I'm doing wrong ?
How to modify code in order to be able to provide log_file ?
Thanks in advance.
The method logging.getLogger() accepts one keyword argument: name = ''.
You specify two arguments, of which the first is a positional argument and the second is a keyword argument with a key-name log_file that is not recognized.
When you change it to:
logger = logging.getLogger(name="Test.log")
the code runs without errors.
I'm running Python 3.6.8 :: Anaconda custom (64-bit) and getting strange results from argparse. Despite the -x, the value of trainandexecute=False
def get_parameters():
startup = '-x -b'
sys.argv = startup.split(' ')
ap = argparse.ArgumentParser()
ap.add_argument('-x', '--trainandexecute', action='store_true')
ap.add_argument('-b', '--debug', action='store_true')
ap.add_argument('-d', '--rundate', action='store')
print(ap.parse_args())
return vars(ap.parse_args())
get_parameters()
This returns the following output. Notet that trainandexecute=False despite the -x flag.
Namespace(debug=True, execute=False, train=False, trainandexecute=False)
{'train': False,
'execute': False,
'trainandexecute': False,
'debug': True}
However, this test works in the next Jupyter cell and that it is not my environment:
def get_test_parameters():
startup = '-b -x'
sys.argv = startup.split(' ')
print(sys.argv)
ap = argparse.ArgumentParser()
ap.add_argument('-x', '--x', action='store_true')
ap.add_argument('-b', '--debug', action='store_true')
print(ap.parse_args())
return vars(ap.parse_args())
So the output of:
get_test_parameters()
is:
['-b', '-x'] # print(sys.argv)
Namespace(debug=False, x=True) # print(ap.parse_args())
{'x': True, 'debug': False} # return vars(ap.parse_args())
I'm bifflesnickered...
Your error is in this line:
sys.argv = startup.split(' ')
The first value in sys.argv is treated as the name of the script, not as an option. Try running ap.parse_args(startup.split()) - and you will see the right answer.
Incidentally, do not pass any parameters to split(). If you pass " " and you have more than one consecutive space, the result of the split will have empty strings.
Here's a better test framework:
def get_parameters(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument('-x', '--trainandexecute', action='store_true')
ap.add_argument('-b', '--debug', action='store_true')
ap.add_argument('-d', '--rundate', action='store')
args = ap.parse_args(argv)) # if None, parses sys.argv[1:]
print(args)
return vars(args)
get_parameters('-x -b'.split())
You can modify sys.argv[1:] instead. By passing argv through your function, you can test several ways.
I want to capture all output into variables that subprocess prints out. Here is my code:
#!/usr/bin/env python3
import subprocess # Subprocess management
import sys # System-specific parameters and functions
try:
args = ["svn", "info", "/directory/that/does/not/exist"]
output = subprocess.check_output(args).decode("utf-8")
except subprocess.CalledProcessError as e:
error = "CalledProcessError: %s" % str(e)
except:
error = "except: %s" % str(sys.exc_info()[1])
else:
pass
This script still prints this into the terminal:
svn: E155007: '/directory/that/does/not/exist' is not a working copy
How can I capture this into a variable?
check_output only captures stdout and NOT stderr (according to https://docs.python.org/3.6/library/subprocess.html#subprocess.check_output )
In order to capture stderr you should use
>>> subprocess.check_output(
... "ls non_existent_file; exit 0",
... stderr=subprocess.STDOUT, ...)
I recommend reading the docs prior to asking here by the way.