I want to give my program a path to a file but it doesnot like it if there is a / included. How can I convince python that my path is only 1 argument
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser(description='Change the option prefix characters',prefix_chars='-+/',)
parser.add_argument('-f', action='store', dest='PathtoFile',help='PathtoFile')
print parser.parse_args()
it works without /
argsparse.py -f banana -> Namespace(PathtoFile='banana')
Any of those result in expect one argument
argsparse.py -f /home/user/banana
argsparse.py -f '/home/user/banana'
argsparse.py -f '//home//user//banana'
argsparse.py -f "/home/user/banana"
argsparse.py -f "//home//user//banana"
->
usage: argsparse.py [-h] [-f PATHTOFILE]
argsparse.py: error: argument -f: expected one argument
UPDATE: Thanks match I forgot I added / as a prefix
Change
parser = argparse.ArgumentParser(description='Change the option prefix characters',prefix_chars='-+/',)
to
parser = argparse.ArgumentParser(description='Change the option prefix characters',prefix_chars='-+',)
The problem is that you're using prefix_chars='-+/' - this tells argparse that those characters are what mark out the command flags.
So your code is seeing / as equivalent to - and reading it as if you'd typed:
argsparse.py -f -home/user/banana
This means that -f has not been given an argument. Remove the prefix_chars and it should work properly.
Related
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-f", "--filepath", help="Input the file path")
group.add_argument("-d", "--dirpath", help="Input the directory path")
For Example if I use both options -f and -d,I'm getting the following error,which is generated by python:
error: argument -d/--dirpath: expected one argument
But I want to customise the error and it should be defined by me.
2140:~/mypy$ python3 stack50552334.py
Namespace(dirpath=None, filepath=None)
These are all produced when there's a mismatch between the Action nargs and available strings. While message format is the same, it is customized to the argument's name:
2140:~/mypy$ python3 stack50552334.py -f
usage: stack50552334.py [-h] [-f FILEPATH | -d DIRPATH]
stack50552334.py: error: argument -f/--filepath: expected one argument
2140:~/mypy$ python3 stack50552334.py -d
usage: stack50552334.py [-h] [-f FILEPATH | -d DIRPATH]
stack50552334.py: error: argument -d/--dirpath: expected one argument
2140:~/mypy$ python3 stack50552334.py -f -d
usage: stack50552334.py [-h] [-f FILEPATH | -d DIRPATH]
stack50552334.py: error: argument -f/--filepath: expected one argument
2141:~/mypy$ python3 stack50552334.py -f foo -d
usage: stack50552334.py [-h] [-f FILEPATH | -d DIRPATH]
stack50552334.py: error: argument -d/--dirpath: expected one argument
But when both flags are provided with the expected arguments, then the mutually_exclusive_group test comes into play, and raises its own error.
2141:~/mypy$ python3 stack50552334.py -f foo -d dir
usage: stack50552334.py [-h] [-f FILEPATH | -d DIRPATH]
stack50552334.py: error: argument -d/--dirpath: not allowed with argument -f/--filepath
The first class of message is produced in:
def _match_argument(self, action, arg_strings_pattern):
# match the pattern for this action to the arg strings
nargs_pattern = self._get_nargs_pattern(action)
match = _re.match(nargs_pattern, arg_strings_pattern)
# raise an exception if we weren't able to find a match
if match is None:
nargs_errors = {
None: _('expected one argument'),
OPTIONAL: _('expected at most one argument'),
ONE_OR_MORE: _('expected at least one argument'),
}
default = ngettext('expected %s argument',
'expected %s arguments',
action.nargs) % action.nargs
msg = nargs_errors.get(action.nargs, default)
raise ArgumentError(action, msg)
# return the number of arguments matched
return len(match.group(1))
The _ is alias for gettext.gettext. So there is a possibility of customizing the messages with this mechanism. https://docs.python.org/3/library/gettext.html
from gettext import gettext as _, ngettext
I don't have any experience with this multlingual localization.
The mutually_exclusive error is raised in:
def take_action(action, argument_strings, option_string=None):
...
# error if this argument is not allowed with other previously
# seen arguments, assuming that actions that use the default
# value don't really count as "present"
if argument_values is not action.default:
seen_non_default_actions.add(action)
for conflict_action in action_conflicts.get(action, []):
if conflict_action in seen_non_default_actions:
msg = _('not allowed with argument %s')
action_name = _get_action_name(conflict_action)
raise ArgumentError(action, msg % action_name)
Again, there is the possibility of gettext customization.
custom argparse.py
Of course there's nothing preventing you from modifying a copy of argparse.py file, and placing in your own directory so it is loaded instead of the default one.
post parsing testing
If the wording of the mutually_exclusive error is bothering you (as opposed to the expected one argument errors, you could omit that group from the parser, and do your own tests after parsing. If the user provides non-default values for both args.filepath and args.dirpath call parser.error('your own message'), or raise your own error.
Is there any way to do required argument for crystal program?
For example
./myprog ~/Music -r
Instead of
./myprog -d ~/Music -r
So my program wont run if there's no [directory] argument. Right now using "option_parser" and can only do -arguments.
There is no way to create required arguments using option_parser, but you can parse arguments and throw an error or exit if there is no argument passed you expect:
require "option_parser"
directory = nil
parser = OptionParser.new
parser.on("-d DIR", "Directory [required]") do |d|
directory = d
end
parser.parse ARGV
if directory.nil?
# directory argument was not set
# print help and exit
puts parser
exit 1
else
# ...
end
This is the query I am trying to use in order to connect to elasticsearch, which is in (172.21.150.230) in order to pull out information in a csv format:
es2csv -u http://xxx.xx.xxx.xxx:5601/ -f _all -d doc -i test2 -r -q '{"query": {"match": {"NAME": "xxx"}}}' -o database.csv
However, I get SyntaxError: invalid syntax
Thanks
Which version are you using?
This error raised when your json query is not valid or when you forget to add -r argument.
I am trying to set up two different environments (development and test) on a single machine where I am using fetchmail/procmail. How would I specify a procmail script other than .procmailrc?
You can optionally specify an alternate rcfile on the command line (or even multiple files).
$ procmail -h 2>&1 | head -n 4
Usage: procmail [-vptoY] [-f fromwhom] [parameter=value | rcfile] ...
Or: procmail [-toY] [-f fromwhom] [-a argument] ... -d recipient ...
Or: procmail [-ptY] [-f fromwhom] -m [parameter=value] ... rcfile [arg] ...
Or: procmail [-toY] [-a argument] ... -z
See the ARGUMENTS section of the manual page for precise details.
With the -m option, the rcfile argument is mandatory. It might be a good idea to use in your scenario, as it disables some defaults which make more sense when running as your default LDA.
I have a directory with folder structure as follows:
-- DATA -- ABD 1231345 -- 01-08-12 // date in mm-dd-yy format
-- 03-09-12
-- 06-11-12
-- DEF 4859480 -- 02-10-12
-- 05-10-12
-- 07-10-12
I would like to batch rename this DATA folder as follows
-- DATA -- ABD 1231345 -- 2012_01_08 // date in yyyy_mm_dd format with underscore
-- 2012_03_09
-- 2012_06_11
-- DEF 4859480 -- 2012_02_10
-- 2012_05_10
-- 2012_07_10
Do you have a suggestion on how to accomplish using command line on Mac OSX / unix?
You could use a for loop and awk, parsing each file-name into your specified format and then mv to rename the original to the new name:
for dir in DATA/*; do \
pushd "$dir"; # change directory \
for file in *; do \
path=`echo $file | awk -F- '{print "20"$3"_"$1"_"$2}'`; \
mv $file $path; # "rename" the file \
done; \
popd; # restore original directory \
done;
This can be executed in folder above DATA. If you want to execute it directly in DATA, update the first loop to read for dir in *; do instead of DATA/*. It tells awk to use the - as the delimiter (instead of whitespace), and then reconstructs a string from "mm-dd-yy" to "20yy_mm_dd".
Using pushd and popd will enable the script to change the current directory to each subdirectory inside DATA (pushd) and then, after moving all necessary files will change back to the original (popd). Doing this will save you a lot of parsing-effort trying to save directory paths / etc.
You could use string manipulations and arrays to do that with bash only.
Something like:
for f in * ; do
parts=(${f//-/ })
mv "$f" "20${parts[2]}_${parts[1]}_${parts[0]}"
done
Search this site for various options to recurse into directories e.g.:
Shell script to traverse directories
Use the date command to convert the file name:
$ date -j -f %m-%d-%y 01-08-12 +%Y_%m_%d
2012_01_08
Getting to the files is a little tricker. We'll just switch directories to avoid dealing with long file paths.
for d in DATA; do
pushd "$d"
for f in *; do
new_f=$(date -j -f %m-%d-%y $f +%Y_%m_%d)
mv "$f" "$new_f"
done
popd
done
This site gives a good snippet
for i in *.avi; do j=`echo $i | sed 's/(\d{2})-(\d{2})-(\d{2})/20\3_\1_\2/g'`; mv "$i" "$j"; done