How can i make argparse suparser match any string? - python-2.7

i am using
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
add_parser = subparsers.add_parser("add", help="Add parser")
add_parser.add_argument("-project", default="global")
edit_parser = subparsers.add_parser("edit", help="Edit parser")
I want to achieve smething like this:
python myprogram.py add
python myprogram.py edit
python myprogram.py "A random string"
Where in the first two usecases my program can asign the right subparser based on the keyword "add" or "edit". I am interested in the last case, where it maps to any random string that i provide.

There isn't a direct way of doing this. The use of subparsers is an extension of a positional argument with choices.
parser.add_argument('cmd', choices=['add', 'edit', ...])
It accepts a string if it is in choices. There isn't a builtin pattern matching mechanism.
I think your simplest solution would be to add one step:
custom = subparser.add_parser('custom', help='give a random string')
custom.add_argument('anystring', help='random quoted string')
python myprogram.py custom 'any random string'
I can imagine writing a custom choices class that could do both kinds of matching. It would require a custom __contains__ method (and maybe a new __iter__ to list choices in the help). But incorporating that into the _SubParsersAction class would require some serious coding.
A few more details. Your subparser object is an _SubParsersAction. Its choices attribute is an OrderedDict. When you add_parser, it creates a new ArgumentParser (the add_parser object), and enters it into the dict with the named key (plus any aliases). When parsing your input, argparse matches the strings against the keys of this dictionary. So, to implement your ideal, you'd have to change this dictionary lookup.
Another option is to look at sys.argv[1:] at the start. If one of your 'cmds' is present call the parser to get the full subparser action. Otherwise handle the inputs yourself, or call another parser that handles 'a random string' as an ordinary positional argument. Sometimes it just isn't worth the effort to twist argparse into a special shape.

Related

What is best practice for passing variables via GET?

I am passing a variable in my URL:
mydomain.com/app/?next_page=my_page
I can get this variable in a view with:
def mypage(request):
var = request.GET['next_page']
Is it best practice to also change the URL to require next_page? Something along the lines of:
path('app/?nextpage=<str>', mypage, name='my_page')
What's best practice? If so, what's the correct syntax for this (I know the example is incorrect)?
It depends on your needs.
Do not define a fixed url route; if you use the query parameters for filtering and there is more than one possible parameter
Example: "app/photos?size=100x100" and "app/photos/?color=blue"
Define a fixed url route; if it will be the same for each and every page, like details of a particular page:
Example: "app/orders/123123123" and "app/orders/123123123"
Btw, the correct syntax is:
path(app/<str:next_page>/, mypage, name="my_page")
You should take a look at path patterns. Enforcing a GET parameter in a path is not really a good practice. So if you want to require a username for example you can use:
path('bio/<username>/', views.bio, name='bio'),
You can find more patterns in Django documentation to catch strings, slugs, integers etc.
And in views you should define your function as such:
def mypage(request, username):
...code...
About GET:
Keep in mind that request.GET["value"] will raise a ValueError if that parameter does not exist. So you can catch that error to inform user that they are missing a parameter. (This will make this parameter obligatory.)
You can also use request.GET.get("value") which will return None if the key does not exist. If you want to use a default parameter you can use of course, request.GET.get("value", "default")
You can use as many parameters as you want in your link with or without path patterns. Their values will be stored in request.GET

Groovy Templates - Non Standard Parameters, with minus signs

I'm trying to render a map that has keys containing minus signs (e.g. first-name). Here is an exemplary template I'm trying to render:
String text = "Dear \"$first-name $lastname\",\nSo nice to meet you";
When I render it with Groovy template engine (can be either SimpleTemplateEngine or MarkupTemplateEngine) it complains and throws an exception. When I remove the '-' from the variable name, it works OK.
Is there anyway to escape these variables in the Groovy template text?
BTW - the reason I'm doing it this way is to render a JSON blob from a 3rd party API.
There is at least one way to do it. It doesn't work in your case for the same reasons you can't use - character in variable name. When you define an expression like:
${first-name}
Groovy sees it as:
${first.minus(name)}
and that is why it throws exception like:
Caught: groovy.lang.MissingPropertyException: No such property: first for class: SimpleTemplateScript1
groovy.lang.MissingPropertyException: No such property: first for class: SimpleTemplateScript1
at SimpleTemplateScript1.run(SimpleTemplateScript1.groovy:1)
You can keep keys like first-name in your bindings, but you would have to put them in a map, so you can access first-name value using Map.get(key) function. Consider following example:
import groovy.text.SimpleTemplateEngine
def engine = new SimpleTemplateEngine()
def bindings = [
'first-name': 'Test',
'lastname': 'qwe'
]
String text = 'Dear "${map["first-name"]} ${map["lastname"]}",\nSo nice to meet you'
println engine.createTemplate(text).make([map: bindings])
In this example I put bindings into a map with a key map. When I do so I can access my bindings as map['first-name'] and map['lastname']. Running this example produces expected output:
Dear "Test qwe",
So nice to meet you
Hope it helps.

Use ConfigParser with different variable types in Python

I am trying to use ConfigParser in the following situation. I am running some code after which i have an object with several attributes. I pick out some of these attributes and write them to a .ini file with configparser. This works fine and my .ini file looks something like this.
[Section]
path = "D:\\"
number = 10.0
boolean = False
Then with some other script I want to read the file and add the items as attributes to another object (self) using.
parser.read('file.ini')
self.__dict__.update(dict(parser.items("Section")))
This fails because all values are read as strings by configparser and now all attributes are strings. parser.items("Section") looks like this:
[('path', '"D:\\"'), ('number', '10.0'), ('boolean', 'False')]
Now I could go and specify the floats, integers, and booleans by their keys and use the corresponding methods parser.getfloat, getint, and getboolean to get the right python types out. However, that means making an extra list of keys and a loop to get them for each data type, which i don't want. Furthermore, even the path is now double quoted and i need to start removing quotes.
This behavior makes ConfigParser almost completely worthless to me and I am doubting if I am using it correctly an if ConfigParser is the best option for my goal, which is simply to write object attributes to a file and at a later time read the file and add the parameters to a new object as attributes. Can I use ConfigParser for this effectively? Or should I start looking for a different method?
INI is not JSON. There are no data types. There are sections and key/value pairs. Stuff before the = is the key, stuff after it is the value. Everything is text.
There are no "strings", which means there is no need to double quote anything. The same goes for "escaped" backslashes. The concept of escaping does not exist in the INI file format.
So, first off, your file should be looking like this:
[Section]
path = D:\
number = 10.0
boolean = False
Next, I consider this a dangerous operation
parser.read('file.ini')
self.__dict__.update(dict(parser.items("Section")))
because it potentially trashes your class instance with arbitrary values from a text file that might contain garbage, but when you can swear that the file will always be fine, well, do it if you must.
I would write a more explicit way of reading and validating config data. I sense your reason not to do that is laziness or a false sense of simplicity; both of these reasons are not very good.
If you want a semi-automated way of type conversion, tag the keys with a data type.
[Section]
s_path = D:\
f_number = 10.0
b_boolean = False
and write a function that knows how to handle them and throws when something is not right.
def type_convert(items):
result = []
for (key, value) in items:
type_tag = key[:2]
if type_tag == "s_":
result.append((key[2:], value))
elif type_tag == "f_":
result.append((key[2:], float(value)))
elif type_tag == "b_":
result.append((key[2:], bool(value)))
else:
raise ValueError('Invalid type tag "%s" found in ini file.' % type_tag)
# alternatively: "everything else defaults to string"
return result
which you can use to make the operation somewhat more convenient:
self.__dict__.update(dict(type_convert(parser.items("Section"))))
Of course you still run the risk of trashing your class instance by overriding keys that should not be overridden.

using regex in searching for a field using get_field_by_name

I am trying to get a uvm register field by name in systemverilog. I want to use regex, so that I can use a pattern for the field name. Here is my register fields:
YY_XXX_2_N
ZZ_BBB_3_N
UU_AAA_8_N
MM_CCC_4_N
YY_WWW_9_N
as you can see all register fields are ending with _N, I used the following code to get register field:
field=env.my_regmap.get_field_by_name("_N$");
so I want this code to get A register field matching the provided pattern. with the code above, I am getting the following error:
reporter [RegModel] Unable to locate field '_N$' in block 'my_regmap'
I wonder if there is a way to use regex in this situation.
Thanks!
get_field_by_name() needs an exact match to return a single handle to a field. What you need to do is use get_fields() to build the list of fields, and then use the SV find()
uvm_field_reg all_fields[$], selected_fields[$];
all_fields = get_fields();
selected_fields = all_fields.find(item) with (uvm_re_match("*_N",item.get_name));
SystemVerilog does not allow to use regex directly, but UVM provides a DPI function uvm_re_match that allows you to use regexec function from regex.h library. You can read more about this here.
You cannot use this function as an argument to get_field_by_name but you can get all fields from register by calling get_fields and then check each field with uvm_re_match.

Passing an argument to main that calls a function in python

I'm trying to pass arguments to my python script using argparse and consequently call functions. Any ideas where I might be going wrong?
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('-d','--d', dest='action', action='store_const',const=do_comparison,
help="Diff the current and most recent map file memory information)")
options = parser.parse_args()
return options
def do_comparison(parsed_args):
# do things
def main(args):
options = parse_args()
if __name__ == '__main__':
sys.exit(main())
In my comment I missed the fact that you are using store_const and const=do_comparison. So you are trying some sort of callback.
options from parse_args is a argparse.Namespace object. This is a simple object, similar to a dictionary. In fact vars(options) returns a dictionary.
When main is run (with -d), options.action will be set to the const, a function. But remember, in Python, functions are first class objects, and can be set to variables, etc just like numbers and strings. To be used the function has to be 'called'.
options.action()
should end up calling do_comparison. Actually since that function requires an argument, you should use
options.action(options)
or some other way of providing a varible or object to the function.
Of course you'll have to be careful about the case where you don't specify -d. Then options.action will have the default value (e.g. None). If the default isn't a callable, then this call will produce an error.
The argparse documentation illustrates this kind of action in the section dealing with subparsers (subcommands). I vaguely recall a tutorial that set an argument value to functions like add and multiply, creating a simple arithmetic expression evaluator.
Usually the values in the Namespace are strings, or numbers, and to use them you test for string equality. e.g.
if options.action is None:
# default action
elif options.action == 'print':
print(options)
else:
do some other backup or error
A callback kind of action is possible, and may be convenient in some cases, but it isn't the usual arrangement.
You asked about using successfully store a string following the -d, to be used as the function arg with:
parser.add_argument('-d','--d', dest='action', dest='function_input', action='store_const', const=diff_map)
A 'store_const' action does not take an argument (in effect nargs=0). It's more like store_true. In fact store_true is just a store_const with has default=False and const=True.
What you need is another argument, whick could occur either before or after the -d. argparse tries to be order flexible.
Here's a simple script with a callable argument, and flexible positional argument.
import argparse
def action1(*args):
print 'action1',args
def action0(*args):
print 'action0',args
parser = argparse.ArgumentParser()
parser.add_argument('-d', dest='action', action='store_const', const=action1, default=action0)
parser.add_argument('args', nargs='*')
args = parser.parse_args()
args.action(args.args)
resulting runs
1238:~/mypy$ python stack32214076.py
action0 ([],)
1238:~/mypy$ python stack32214076.py one two three
action0 (['one', 'two', 'three'],)
1238:~/mypy$ python stack32214076.py one two three -d
action1 (['one', 'two', 'three'],)
1239:~/mypy$ python stack32214076.py -d one two three
action1 (['one', 'two', 'three'],)
1239:~/mypy$ python stack32214076.py -d
action1 ([],)
TO make -d value perform some action on value, try:
parser.add_argument('-d','--action')
The default action type stores one value (e.g. action='store', nargs=None)
args = parser.parse_args()
if args.action: # or is not None
do_comparison(args.action)
If -d is not given args.action will have default None value, and nothing happens here.
If -d astr is given acts.action will have the string value 'astr'. This if just calls the do_comparison function with this value. It's the present of this (nondefault) value that triggers the function call.
This is a rather straight forward use of a parser and an argument.