argparse - Define custom actions or types with additional arguments












1














I'm developing a toolbox containing several python scripts. For several of them some arguments may be numeric values. Depending of the script some may require a value v to be between -1 and 1, or 0 and 1 or 1 and 10 or ... An example could be a page width from an output diagram which should be always positive.



I can check all the time if v is in the required range. I could also for each of these range define an Action or a type using argparse. An example is given using a new type:



def positive_num(a_value):
"""Check a numeric positive."""
if not a_value > 0:
raise argparse.ArgumentTypeError("Should be positive.")
return a_value


And add it later to the parser:



parser_grp.add_argument('-pw', '--page-width',
help='Output pdf file width (e.g. 7 inches).',
type=positive_num,
default=None,
required=False)


Now, if the value is a correlation coefficient (or anything in a range) would it be possible using action or types to write something more general using:



def ranged_num(a_value, lowest=-1, highest=1):
"""Check a numeric is in expected range."""
if not (a_value >= lowest and a_value <= highest):
raise argparse.ArgumentTypeError("Not in range.")
return a_value


That could later be added like:



parser_grp.add_argument('-c', '--correlation',
help='A value for the correlation coefficient',
type=ranged_num(-1,1),
default=None,
required=False)


I have tried in several ways but whithout success.



Thank you










share|improve this question






















  • You need a higher-order function to do this, a function that returns a function. type needs to be a function that accepts a single (note: string) argument, so that's what ranged_num(-1, 1) needs to return.
    – jonrsharpe
    Nov 23 '18 at 11:28












  • Yes... That's it. I will dig into that.
    – user451460
    Nov 23 '18 at 11:32










  • The question is how will I pass the range (-1,1) to this higher-order function since the normal way is to pass a function definition and not a function call to the type argument of add_argument() method. I recall that I don't want to write a particular function for each range.
    – user451460
    Nov 23 '18 at 11:42










  • That's the point of a higher-order function; the function that returns the type function can also take parameters. You would write type=ranged_num(-1, 1), and that function would return an appropriately-configures function that accepts the string argument.
    – jonrsharpe
    Nov 23 '18 at 11:44










  • functools.partial can be used to bind the low and high of ranged_num.
    – hpaulj
    Nov 23 '18 at 16:12
















1














I'm developing a toolbox containing several python scripts. For several of them some arguments may be numeric values. Depending of the script some may require a value v to be between -1 and 1, or 0 and 1 or 1 and 10 or ... An example could be a page width from an output diagram which should be always positive.



I can check all the time if v is in the required range. I could also for each of these range define an Action or a type using argparse. An example is given using a new type:



def positive_num(a_value):
"""Check a numeric positive."""
if not a_value > 0:
raise argparse.ArgumentTypeError("Should be positive.")
return a_value


And add it later to the parser:



parser_grp.add_argument('-pw', '--page-width',
help='Output pdf file width (e.g. 7 inches).',
type=positive_num,
default=None,
required=False)


Now, if the value is a correlation coefficient (or anything in a range) would it be possible using action or types to write something more general using:



def ranged_num(a_value, lowest=-1, highest=1):
"""Check a numeric is in expected range."""
if not (a_value >= lowest and a_value <= highest):
raise argparse.ArgumentTypeError("Not in range.")
return a_value


That could later be added like:



parser_grp.add_argument('-c', '--correlation',
help='A value for the correlation coefficient',
type=ranged_num(-1,1),
default=None,
required=False)


I have tried in several ways but whithout success.



Thank you










share|improve this question






















  • You need a higher-order function to do this, a function that returns a function. type needs to be a function that accepts a single (note: string) argument, so that's what ranged_num(-1, 1) needs to return.
    – jonrsharpe
    Nov 23 '18 at 11:28












  • Yes... That's it. I will dig into that.
    – user451460
    Nov 23 '18 at 11:32










  • The question is how will I pass the range (-1,1) to this higher-order function since the normal way is to pass a function definition and not a function call to the type argument of add_argument() method. I recall that I don't want to write a particular function for each range.
    – user451460
    Nov 23 '18 at 11:42










  • That's the point of a higher-order function; the function that returns the type function can also take parameters. You would write type=ranged_num(-1, 1), and that function would return an appropriately-configures function that accepts the string argument.
    – jonrsharpe
    Nov 23 '18 at 11:44










  • functools.partial can be used to bind the low and high of ranged_num.
    – hpaulj
    Nov 23 '18 at 16:12














1












1








1







I'm developing a toolbox containing several python scripts. For several of them some arguments may be numeric values. Depending of the script some may require a value v to be between -1 and 1, or 0 and 1 or 1 and 10 or ... An example could be a page width from an output diagram which should be always positive.



I can check all the time if v is in the required range. I could also for each of these range define an Action or a type using argparse. An example is given using a new type:



def positive_num(a_value):
"""Check a numeric positive."""
if not a_value > 0:
raise argparse.ArgumentTypeError("Should be positive.")
return a_value


And add it later to the parser:



parser_grp.add_argument('-pw', '--page-width',
help='Output pdf file width (e.g. 7 inches).',
type=positive_num,
default=None,
required=False)


Now, if the value is a correlation coefficient (or anything in a range) would it be possible using action or types to write something more general using:



def ranged_num(a_value, lowest=-1, highest=1):
"""Check a numeric is in expected range."""
if not (a_value >= lowest and a_value <= highest):
raise argparse.ArgumentTypeError("Not in range.")
return a_value


That could later be added like:



parser_grp.add_argument('-c', '--correlation',
help='A value for the correlation coefficient',
type=ranged_num(-1,1),
default=None,
required=False)


I have tried in several ways but whithout success.



Thank you










share|improve this question













I'm developing a toolbox containing several python scripts. For several of them some arguments may be numeric values. Depending of the script some may require a value v to be between -1 and 1, or 0 and 1 or 1 and 10 or ... An example could be a page width from an output diagram which should be always positive.



I can check all the time if v is in the required range. I could also for each of these range define an Action or a type using argparse. An example is given using a new type:



def positive_num(a_value):
"""Check a numeric positive."""
if not a_value > 0:
raise argparse.ArgumentTypeError("Should be positive.")
return a_value


And add it later to the parser:



parser_grp.add_argument('-pw', '--page-width',
help='Output pdf file width (e.g. 7 inches).',
type=positive_num,
default=None,
required=False)


Now, if the value is a correlation coefficient (or anything in a range) would it be possible using action or types to write something more general using:



def ranged_num(a_value, lowest=-1, highest=1):
"""Check a numeric is in expected range."""
if not (a_value >= lowest and a_value <= highest):
raise argparse.ArgumentTypeError("Not in range.")
return a_value


That could later be added like:



parser_grp.add_argument('-c', '--correlation',
help='A value for the correlation coefficient',
type=ranged_num(-1,1),
default=None,
required=False)


I have tried in several ways but whithout success.



Thank you







python argparse






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 23 '18 at 11:21









user451460

1499




1499












  • You need a higher-order function to do this, a function that returns a function. type needs to be a function that accepts a single (note: string) argument, so that's what ranged_num(-1, 1) needs to return.
    – jonrsharpe
    Nov 23 '18 at 11:28












  • Yes... That's it. I will dig into that.
    – user451460
    Nov 23 '18 at 11:32










  • The question is how will I pass the range (-1,1) to this higher-order function since the normal way is to pass a function definition and not a function call to the type argument of add_argument() method. I recall that I don't want to write a particular function for each range.
    – user451460
    Nov 23 '18 at 11:42










  • That's the point of a higher-order function; the function that returns the type function can also take parameters. You would write type=ranged_num(-1, 1), and that function would return an appropriately-configures function that accepts the string argument.
    – jonrsharpe
    Nov 23 '18 at 11:44










  • functools.partial can be used to bind the low and high of ranged_num.
    – hpaulj
    Nov 23 '18 at 16:12


















  • You need a higher-order function to do this, a function that returns a function. type needs to be a function that accepts a single (note: string) argument, so that's what ranged_num(-1, 1) needs to return.
    – jonrsharpe
    Nov 23 '18 at 11:28












  • Yes... That's it. I will dig into that.
    – user451460
    Nov 23 '18 at 11:32










  • The question is how will I pass the range (-1,1) to this higher-order function since the normal way is to pass a function definition and not a function call to the type argument of add_argument() method. I recall that I don't want to write a particular function for each range.
    – user451460
    Nov 23 '18 at 11:42










  • That's the point of a higher-order function; the function that returns the type function can also take parameters. You would write type=ranged_num(-1, 1), and that function would return an appropriately-configures function that accepts the string argument.
    – jonrsharpe
    Nov 23 '18 at 11:44










  • functools.partial can be used to bind the low and high of ranged_num.
    – hpaulj
    Nov 23 '18 at 16:12
















You need a higher-order function to do this, a function that returns a function. type needs to be a function that accepts a single (note: string) argument, so that's what ranged_num(-1, 1) needs to return.
– jonrsharpe
Nov 23 '18 at 11:28






You need a higher-order function to do this, a function that returns a function. type needs to be a function that accepts a single (note: string) argument, so that's what ranged_num(-1, 1) needs to return.
– jonrsharpe
Nov 23 '18 at 11:28














Yes... That's it. I will dig into that.
– user451460
Nov 23 '18 at 11:32




Yes... That's it. I will dig into that.
– user451460
Nov 23 '18 at 11:32












The question is how will I pass the range (-1,1) to this higher-order function since the normal way is to pass a function definition and not a function call to the type argument of add_argument() method. I recall that I don't want to write a particular function for each range.
– user451460
Nov 23 '18 at 11:42




The question is how will I pass the range (-1,1) to this higher-order function since the normal way is to pass a function definition and not a function call to the type argument of add_argument() method. I recall that I don't want to write a particular function for each range.
– user451460
Nov 23 '18 at 11:42












That's the point of a higher-order function; the function that returns the type function can also take parameters. You would write type=ranged_num(-1, 1), and that function would return an appropriately-configures function that accepts the string argument.
– jonrsharpe
Nov 23 '18 at 11:44




That's the point of a higher-order function; the function that returns the type function can also take parameters. You would write type=ranged_num(-1, 1), and that function would return an appropriately-configures function that accepts the string argument.
– jonrsharpe
Nov 23 '18 at 11:44












functools.partial can be used to bind the low and high of ranged_num.
– hpaulj
Nov 23 '18 at 16:12




functools.partial can be used to bind the low and high of ranged_num.
– hpaulj
Nov 23 '18 at 16:12












1 Answer
1






active

oldest

votes


















2














Per the documentation:




type= can take any callable that takes a single string argument and
returns the converted value




Therefore, to use it like type=ranged_num(-1,1), your ranged_num function must return a function itself. A function that returns a function (or accepts a function as an argument, or both) is often referred to as a "higher-order function".



Here's a minimal example:



def ranged_num(lowest=-1, highest=1):
"""Check a numeric is in expected range."""
def type_func(a_value):
a_value = int(a_value) # or "float"; you could also have error handling here
if not (a_value >= lowest and a_value <= highest): # I'd rewrite this to an "or"
raise argparse.ArgumentTypeError("Not in range.")
return a_value
return type_func


Now ranged_num creates and returns a function, type_func, that is responsible for handling the string coming from the command line.






share|improve this answer





















  • I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
    – user451460
    Nov 23 '18 at 12:16










  • @user451460 no worries; if you want more information on that, it's referred to as a "closure"
    – jonrsharpe
    Nov 23 '18 at 12:17










  • This is also nicer with a or... Thanks.
    – user451460
    Nov 23 '18 at 12:22











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53445769%2fargparse-define-custom-actions-or-types-with-additional-arguments%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














Per the documentation:




type= can take any callable that takes a single string argument and
returns the converted value




Therefore, to use it like type=ranged_num(-1,1), your ranged_num function must return a function itself. A function that returns a function (or accepts a function as an argument, or both) is often referred to as a "higher-order function".



Here's a minimal example:



def ranged_num(lowest=-1, highest=1):
"""Check a numeric is in expected range."""
def type_func(a_value):
a_value = int(a_value) # or "float"; you could also have error handling here
if not (a_value >= lowest and a_value <= highest): # I'd rewrite this to an "or"
raise argparse.ArgumentTypeError("Not in range.")
return a_value
return type_func


Now ranged_num creates and returns a function, type_func, that is responsible for handling the string coming from the command line.






share|improve this answer





















  • I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
    – user451460
    Nov 23 '18 at 12:16










  • @user451460 no worries; if you want more information on that, it's referred to as a "closure"
    – jonrsharpe
    Nov 23 '18 at 12:17










  • This is also nicer with a or... Thanks.
    – user451460
    Nov 23 '18 at 12:22
















2














Per the documentation:




type= can take any callable that takes a single string argument and
returns the converted value




Therefore, to use it like type=ranged_num(-1,1), your ranged_num function must return a function itself. A function that returns a function (or accepts a function as an argument, or both) is often referred to as a "higher-order function".



Here's a minimal example:



def ranged_num(lowest=-1, highest=1):
"""Check a numeric is in expected range."""
def type_func(a_value):
a_value = int(a_value) # or "float"; you could also have error handling here
if not (a_value >= lowest and a_value <= highest): # I'd rewrite this to an "or"
raise argparse.ArgumentTypeError("Not in range.")
return a_value
return type_func


Now ranged_num creates and returns a function, type_func, that is responsible for handling the string coming from the command line.






share|improve this answer





















  • I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
    – user451460
    Nov 23 '18 at 12:16










  • @user451460 no worries; if you want more information on that, it's referred to as a "closure"
    – jonrsharpe
    Nov 23 '18 at 12:17










  • This is also nicer with a or... Thanks.
    – user451460
    Nov 23 '18 at 12:22














2












2








2






Per the documentation:




type= can take any callable that takes a single string argument and
returns the converted value




Therefore, to use it like type=ranged_num(-1,1), your ranged_num function must return a function itself. A function that returns a function (or accepts a function as an argument, or both) is often referred to as a "higher-order function".



Here's a minimal example:



def ranged_num(lowest=-1, highest=1):
"""Check a numeric is in expected range."""
def type_func(a_value):
a_value = int(a_value) # or "float"; you could also have error handling here
if not (a_value >= lowest and a_value <= highest): # I'd rewrite this to an "or"
raise argparse.ArgumentTypeError("Not in range.")
return a_value
return type_func


Now ranged_num creates and returns a function, type_func, that is responsible for handling the string coming from the command line.






share|improve this answer












Per the documentation:




type= can take any callable that takes a single string argument and
returns the converted value




Therefore, to use it like type=ranged_num(-1,1), your ranged_num function must return a function itself. A function that returns a function (or accepts a function as an argument, or both) is often referred to as a "higher-order function".



Here's a minimal example:



def ranged_num(lowest=-1, highest=1):
"""Check a numeric is in expected range."""
def type_func(a_value):
a_value = int(a_value) # or "float"; you could also have error handling here
if not (a_value >= lowest and a_value <= highest): # I'd rewrite this to an "or"
raise argparse.ArgumentTypeError("Not in range.")
return a_value
return type_func


Now ranged_num creates and returns a function, type_func, that is responsible for handling the string coming from the command line.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 23 '18 at 11:49









jonrsharpe

76.7k11101208




76.7k11101208












  • I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
    – user451460
    Nov 23 '18 at 12:16










  • @user451460 no worries; if you want more information on that, it's referred to as a "closure"
    – jonrsharpe
    Nov 23 '18 at 12:17










  • This is also nicer with a or... Thanks.
    – user451460
    Nov 23 '18 at 12:22


















  • I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
    – user451460
    Nov 23 '18 at 12:16










  • @user451460 no worries; if you want more information on that, it's referred to as a "closure"
    – jonrsharpe
    Nov 23 '18 at 12:17










  • This is also nicer with a or... Thanks.
    – user451460
    Nov 23 '18 at 12:22
















I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
– user451460
Nov 23 '18 at 12:16




I was on the way.Did not think about the fact that lowest and highest where visible inside type_func... Thanks a lot for this short lesson. Best
– user451460
Nov 23 '18 at 12:16












@user451460 no worries; if you want more information on that, it's referred to as a "closure"
– jonrsharpe
Nov 23 '18 at 12:17




@user451460 no worries; if you want more information on that, it's referred to as a "closure"
– jonrsharpe
Nov 23 '18 at 12:17












This is also nicer with a or... Thanks.
– user451460
Nov 23 '18 at 12:22




This is also nicer with a or... Thanks.
– user451460
Nov 23 '18 at 12:22


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53445769%2fargparse-define-custom-actions-or-types-with-additional-arguments%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)