python argparse ignore other options when a specific option is used











up vote
0
down vote

favorite












I am writing a python program that I want to have a command line interface that behaves in a particular way



The command line interface should accept the following invocations:



my_prog test.svg foo
my_prog --font=Sans test.svg foo


(it will generate an svg with the word foo written in the specified or default font)



Now I want to be able to also have this command accept the following invocation...



my_prog --list-fonts


which will list all of the valid options to --font as determined by the fonts available on the system.



I am using argparse, and I have something like this:



parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', action='store_true')

args = parser.parse_args()


however this does not make the --list-fonts option behave as I would like as the two positional arguments are still required.



I have also tried using subparsers, but these still need a workaround to prevent the other options being required every time.



How do I get the desired behaviour with argparse.










share|improve this question






















  • If you had one positional with nargs='*' it should accept all the alternatives. After parsing you could check whether the positional has the right number of strings or not, and raise an error as necessary (or ignore unneeded values). Otherwise I think you have to go the custom Action route.
    – hpaulj
    Nov 22 at 19:36















up vote
0
down vote

favorite












I am writing a python program that I want to have a command line interface that behaves in a particular way



The command line interface should accept the following invocations:



my_prog test.svg foo
my_prog --font=Sans test.svg foo


(it will generate an svg with the word foo written in the specified or default font)



Now I want to be able to also have this command accept the following invocation...



my_prog --list-fonts


which will list all of the valid options to --font as determined by the fonts available on the system.



I am using argparse, and I have something like this:



parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', action='store_true')

args = parser.parse_args()


however this does not make the --list-fonts option behave as I would like as the two positional arguments are still required.



I have also tried using subparsers, but these still need a workaround to prevent the other options being required every time.



How do I get the desired behaviour with argparse.










share|improve this question






















  • If you had one positional with nargs='*' it should accept all the alternatives. After parsing you could check whether the positional has the right number of strings or not, and raise an error as necessary (or ignore unneeded values). Otherwise I think you have to go the custom Action route.
    – hpaulj
    Nov 22 at 19:36













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I am writing a python program that I want to have a command line interface that behaves in a particular way



The command line interface should accept the following invocations:



my_prog test.svg foo
my_prog --font=Sans test.svg foo


(it will generate an svg with the word foo written in the specified or default font)



Now I want to be able to also have this command accept the following invocation...



my_prog --list-fonts


which will list all of the valid options to --font as determined by the fonts available on the system.



I am using argparse, and I have something like this:



parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', action='store_true')

args = parser.parse_args()


however this does not make the --list-fonts option behave as I would like as the two positional arguments are still required.



I have also tried using subparsers, but these still need a workaround to prevent the other options being required every time.



How do I get the desired behaviour with argparse.










share|improve this question













I am writing a python program that I want to have a command line interface that behaves in a particular way



The command line interface should accept the following invocations:



my_prog test.svg foo
my_prog --font=Sans test.svg foo


(it will generate an svg with the word foo written in the specified or default font)



Now I want to be able to also have this command accept the following invocation...



my_prog --list-fonts


which will list all of the valid options to --font as determined by the fonts available on the system.



I am using argparse, and I have something like this:



parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', action='store_true')

args = parser.parse_args()


however this does not make the --list-fonts option behave as I would like as the two positional arguments are still required.



I have also tried using subparsers, but these still need a workaround to prevent the other options being required every time.



How do I get the desired behaviour with argparse.







python-3.x argparse






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 22 at 15:50









DanJAB

406619




406619












  • If you had one positional with nargs='*' it should accept all the alternatives. After parsing you could check whether the positional has the right number of strings or not, and raise an error as necessary (or ignore unneeded values). Otherwise I think you have to go the custom Action route.
    – hpaulj
    Nov 22 at 19:36


















  • If you had one positional with nargs='*' it should accept all the alternatives. After parsing you could check whether the positional has the right number of strings or not, and raise an error as necessary (or ignore unneeded values). Otherwise I think you have to go the custom Action route.
    – hpaulj
    Nov 22 at 19:36
















If you had one positional with nargs='*' it should accept all the alternatives. After parsing you could check whether the positional has the right number of strings or not, and raise an error as necessary (or ignore unneeded values). Otherwise I think you have to go the custom Action route.
– hpaulj
Nov 22 at 19:36




If you had one positional with nargs='*' it should accept all the alternatives. After parsing you could check whether the positional has the right number of strings or not, and raise an error as necessary (or ignore unneeded values). Otherwise I think you have to go the custom Action route.
– hpaulj
Nov 22 at 19:36












1 Answer
1






active

oldest

votes

















up vote
0
down vote



accepted










argparse allows you to define arbitrary actions to take when encountering an argument, based on the action keyword argument to add_argument (see the docs)



You can define an action to list your fonts and then abort argument parsing, which will avoid checking for the other required arguments.



this could look like this:



class ListFonts(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
print("list of fonts here")
parser.exit() # exits the program with no more arg parsing and checking


Then you can add it to your argument like so:



parser.add_argument('--list-fonts', nargs=0, action=ListFonts)


Note nargs=0 has been added so that this argument doesn't require a value (the code in the question achieved this with action='store_true')



This solution has a side-effect of enabling the invocations like the following to also list the fonts and exits without running the main program:



my_prog --font Sans test.svg text --list-fonts


This is likely not a problem as it's not a typical use case, especially if the help text explains this behaviour.



If defining a new class for each such option feels too heavyweight, or perhaps you have more than one option that has this behaviour, then you could consider having a function that implements the desired action for each argument and then have a kind of factory function that returns a class that wraps the function. A complete example of this is shown below.



def list_fonts():
print("list of fonts here")

def override(func):
""" returns an argparse action that stops parsing and calls a function
whenever a particular argument is encountered. The program is then exited """
class OverrideAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
func()
parser.exit()
return OverrideAction

parser = argparse.ArgumentParser()

parser.add_argument('output_file')
parser.add_argument('text')
parser.add_argument('--font', help='list options with --list-fonts')
parser.add_argument('--list-fonts', nargs=0, action=override(list_fonts),
help='list the font options then stop, don't generate output')
args = parser.parse_args()





share|improve this answer





















    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%2f53434478%2fpython-argparse-ignore-other-options-when-a-specific-option-is-used%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








    up vote
    0
    down vote



    accepted










    argparse allows you to define arbitrary actions to take when encountering an argument, based on the action keyword argument to add_argument (see the docs)



    You can define an action to list your fonts and then abort argument parsing, which will avoid checking for the other required arguments.



    this could look like this:



    class ListFonts(argparse.Action):
    def __call__(self, parser, namespace, values, option_string):
    print("list of fonts here")
    parser.exit() # exits the program with no more arg parsing and checking


    Then you can add it to your argument like so:



    parser.add_argument('--list-fonts', nargs=0, action=ListFonts)


    Note nargs=0 has been added so that this argument doesn't require a value (the code in the question achieved this with action='store_true')



    This solution has a side-effect of enabling the invocations like the following to also list the fonts and exits without running the main program:



    my_prog --font Sans test.svg text --list-fonts


    This is likely not a problem as it's not a typical use case, especially if the help text explains this behaviour.



    If defining a new class for each such option feels too heavyweight, or perhaps you have more than one option that has this behaviour, then you could consider having a function that implements the desired action for each argument and then have a kind of factory function that returns a class that wraps the function. A complete example of this is shown below.



    def list_fonts():
    print("list of fonts here")

    def override(func):
    """ returns an argparse action that stops parsing and calls a function
    whenever a particular argument is encountered. The program is then exited """
    class OverrideAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string):
    func()
    parser.exit()
    return OverrideAction

    parser = argparse.ArgumentParser()

    parser.add_argument('output_file')
    parser.add_argument('text')
    parser.add_argument('--font', help='list options with --list-fonts')
    parser.add_argument('--list-fonts', nargs=0, action=override(list_fonts),
    help='list the font options then stop, don't generate output')
    args = parser.parse_args()





    share|improve this answer

























      up vote
      0
      down vote



      accepted










      argparse allows you to define arbitrary actions to take when encountering an argument, based on the action keyword argument to add_argument (see the docs)



      You can define an action to list your fonts and then abort argument parsing, which will avoid checking for the other required arguments.



      this could look like this:



      class ListFonts(argparse.Action):
      def __call__(self, parser, namespace, values, option_string):
      print("list of fonts here")
      parser.exit() # exits the program with no more arg parsing and checking


      Then you can add it to your argument like so:



      parser.add_argument('--list-fonts', nargs=0, action=ListFonts)


      Note nargs=0 has been added so that this argument doesn't require a value (the code in the question achieved this with action='store_true')



      This solution has a side-effect of enabling the invocations like the following to also list the fonts and exits without running the main program:



      my_prog --font Sans test.svg text --list-fonts


      This is likely not a problem as it's not a typical use case, especially if the help text explains this behaviour.



      If defining a new class for each such option feels too heavyweight, or perhaps you have more than one option that has this behaviour, then you could consider having a function that implements the desired action for each argument and then have a kind of factory function that returns a class that wraps the function. A complete example of this is shown below.



      def list_fonts():
      print("list of fonts here")

      def override(func):
      """ returns an argparse action that stops parsing and calls a function
      whenever a particular argument is encountered. The program is then exited """
      class OverrideAction(argparse.Action):
      def __call__(self, parser, namespace, values, option_string):
      func()
      parser.exit()
      return OverrideAction

      parser = argparse.ArgumentParser()

      parser.add_argument('output_file')
      parser.add_argument('text')
      parser.add_argument('--font', help='list options with --list-fonts')
      parser.add_argument('--list-fonts', nargs=0, action=override(list_fonts),
      help='list the font options then stop, don't generate output')
      args = parser.parse_args()





      share|improve this answer























        up vote
        0
        down vote



        accepted







        up vote
        0
        down vote



        accepted






        argparse allows you to define arbitrary actions to take when encountering an argument, based on the action keyword argument to add_argument (see the docs)



        You can define an action to list your fonts and then abort argument parsing, which will avoid checking for the other required arguments.



        this could look like this:



        class ListFonts(argparse.Action):
        def __call__(self, parser, namespace, values, option_string):
        print("list of fonts here")
        parser.exit() # exits the program with no more arg parsing and checking


        Then you can add it to your argument like so:



        parser.add_argument('--list-fonts', nargs=0, action=ListFonts)


        Note nargs=0 has been added so that this argument doesn't require a value (the code in the question achieved this with action='store_true')



        This solution has a side-effect of enabling the invocations like the following to also list the fonts and exits without running the main program:



        my_prog --font Sans test.svg text --list-fonts


        This is likely not a problem as it's not a typical use case, especially if the help text explains this behaviour.



        If defining a new class for each such option feels too heavyweight, or perhaps you have more than one option that has this behaviour, then you could consider having a function that implements the desired action for each argument and then have a kind of factory function that returns a class that wraps the function. A complete example of this is shown below.



        def list_fonts():
        print("list of fonts here")

        def override(func):
        """ returns an argparse action that stops parsing and calls a function
        whenever a particular argument is encountered. The program is then exited """
        class OverrideAction(argparse.Action):
        def __call__(self, parser, namespace, values, option_string):
        func()
        parser.exit()
        return OverrideAction

        parser = argparse.ArgumentParser()

        parser.add_argument('output_file')
        parser.add_argument('text')
        parser.add_argument('--font', help='list options with --list-fonts')
        parser.add_argument('--list-fonts', nargs=0, action=override(list_fonts),
        help='list the font options then stop, don't generate output')
        args = parser.parse_args()





        share|improve this answer












        argparse allows you to define arbitrary actions to take when encountering an argument, based on the action keyword argument to add_argument (see the docs)



        You can define an action to list your fonts and then abort argument parsing, which will avoid checking for the other required arguments.



        this could look like this:



        class ListFonts(argparse.Action):
        def __call__(self, parser, namespace, values, option_string):
        print("list of fonts here")
        parser.exit() # exits the program with no more arg parsing and checking


        Then you can add it to your argument like so:



        parser.add_argument('--list-fonts', nargs=0, action=ListFonts)


        Note nargs=0 has been added so that this argument doesn't require a value (the code in the question achieved this with action='store_true')



        This solution has a side-effect of enabling the invocations like the following to also list the fonts and exits without running the main program:



        my_prog --font Sans test.svg text --list-fonts


        This is likely not a problem as it's not a typical use case, especially if the help text explains this behaviour.



        If defining a new class for each such option feels too heavyweight, or perhaps you have more than one option that has this behaviour, then you could consider having a function that implements the desired action for each argument and then have a kind of factory function that returns a class that wraps the function. A complete example of this is shown below.



        def list_fonts():
        print("list of fonts here")

        def override(func):
        """ returns an argparse action that stops parsing and calls a function
        whenever a particular argument is encountered. The program is then exited """
        class OverrideAction(argparse.Action):
        def __call__(self, parser, namespace, values, option_string):
        func()
        parser.exit()
        return OverrideAction

        parser = argparse.ArgumentParser()

        parser.add_argument('output_file')
        parser.add_argument('text')
        parser.add_argument('--font', help='list options with --list-fonts')
        parser.add_argument('--list-fonts', nargs=0, action=override(list_fonts),
        help='list the font options then stop, don't generate output')
        args = parser.parse_args()






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 at 15:50









        DanJAB

        406619




        406619






























            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%2f53434478%2fpython-argparse-ignore-other-options-when-a-specific-option-is-used%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)