Make functions importable when using argparse











up vote
0
down vote

favorite












I have the following CLI program which adds two numbers:



import argparse

def foo(args):
print('X + Y:', args.x + args.y)
return args.x + args.y


if __name__ == '__main__':
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-x', type=int, default=1)
foo_parser.add_argument('-y', type=int, default=2)
foo_parser.set_defaults(func=foo)

parser.add_argument('--debug', action='store_true', default=False)


args = parser.parse_args()
args.func(args)


Suppose now I want my users to also be able to import foo and call it directly with arguments x and y. I.e. I want foo to look like this:



def foo(x, y):
print('X + Y:', x + y)
return x + y


How can I adapt args.func(args) to handle this new foo?










share|improve this question
























  • One solution might involve something like args.func(*vars(args)). I'm not sure how to remove func from vars(args), though.
    – Evidlo
    Nov 5 at 4:22












  • def foo(x=0, y=0): can be called a variety of ways. foo(1,2), foo(x=1, y=2), foo(**adict), foo(**vars(args)).
    – hpaulj
    Nov 5 at 6:02















up vote
0
down vote

favorite












I have the following CLI program which adds two numbers:



import argparse

def foo(args):
print('X + Y:', args.x + args.y)
return args.x + args.y


if __name__ == '__main__':
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-x', type=int, default=1)
foo_parser.add_argument('-y', type=int, default=2)
foo_parser.set_defaults(func=foo)

parser.add_argument('--debug', action='store_true', default=False)


args = parser.parse_args()
args.func(args)


Suppose now I want my users to also be able to import foo and call it directly with arguments x and y. I.e. I want foo to look like this:



def foo(x, y):
print('X + Y:', x + y)
return x + y


How can I adapt args.func(args) to handle this new foo?










share|improve this question
























  • One solution might involve something like args.func(*vars(args)). I'm not sure how to remove func from vars(args), though.
    – Evidlo
    Nov 5 at 4:22












  • def foo(x=0, y=0): can be called a variety of ways. foo(1,2), foo(x=1, y=2), foo(**adict), foo(**vars(args)).
    – hpaulj
    Nov 5 at 6:02













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have the following CLI program which adds two numbers:



import argparse

def foo(args):
print('X + Y:', args.x + args.y)
return args.x + args.y


if __name__ == '__main__':
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-x', type=int, default=1)
foo_parser.add_argument('-y', type=int, default=2)
foo_parser.set_defaults(func=foo)

parser.add_argument('--debug', action='store_true', default=False)


args = parser.parse_args()
args.func(args)


Suppose now I want my users to also be able to import foo and call it directly with arguments x and y. I.e. I want foo to look like this:



def foo(x, y):
print('X + Y:', x + y)
return x + y


How can I adapt args.func(args) to handle this new foo?










share|improve this question















I have the following CLI program which adds two numbers:



import argparse

def foo(args):
print('X + Y:', args.x + args.y)
return args.x + args.y


if __name__ == '__main__':
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-x', type=int, default=1)
foo_parser.add_argument('-y', type=int, default=2)
foo_parser.set_defaults(func=foo)

parser.add_argument('--debug', action='store_true', default=False)


args = parser.parse_args()
args.func(args)


Suppose now I want my users to also be able to import foo and call it directly with arguments x and y. I.e. I want foo to look like this:



def foo(x, y):
print('X + Y:', x + y)
return x + y


How can I adapt args.func(args) to handle this new foo?







python argparse






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 5 at 4:46

























asked Nov 5 at 4:13









Evidlo

484




484












  • One solution might involve something like args.func(*vars(args)). I'm not sure how to remove func from vars(args), though.
    – Evidlo
    Nov 5 at 4:22












  • def foo(x=0, y=0): can be called a variety of ways. foo(1,2), foo(x=1, y=2), foo(**adict), foo(**vars(args)).
    – hpaulj
    Nov 5 at 6:02


















  • One solution might involve something like args.func(*vars(args)). I'm not sure how to remove func from vars(args), though.
    – Evidlo
    Nov 5 at 4:22












  • def foo(x=0, y=0): can be called a variety of ways. foo(1,2), foo(x=1, y=2), foo(**adict), foo(**vars(args)).
    – hpaulj
    Nov 5 at 6:02
















One solution might involve something like args.func(*vars(args)). I'm not sure how to remove func from vars(args), though.
– Evidlo
Nov 5 at 4:22






One solution might involve something like args.func(*vars(args)). I'm not sure how to remove func from vars(args), though.
– Evidlo
Nov 5 at 4:22














def foo(x=0, y=0): can be called a variety of ways. foo(1,2), foo(x=1, y=2), foo(**adict), foo(**vars(args)).
– hpaulj
Nov 5 at 6:02




def foo(x=0, y=0): can be called a variety of ways. foo(1,2), foo(x=1, y=2), foo(**adict), foo(**vars(args)).
– hpaulj
Nov 5 at 6:02












2 Answers
2






active

oldest

votes

















up vote
1
down vote



accepted










The use of args.func(**vars(args)) is not a best fit for use-cases which require import as well as a CLI view




  • When users import a function and call it, they expect a return value for further processing (nothing printed on a console. The caller can decide to print based on the result obtained)

  • When they use a CLI, they expect to see an output printed on the console and a proper exit code (0 or 1 based on the return value)


The ideal way is to separate the parsing/CLI management/sum-function into separate functions and delegate processing once the parsing is complete (below is a sample example)



from __future__ import print_function # for python2
import argparse

def mysum(x, y=5):
return x+y

def delegator(input_args):
func_map = {
"mysum" : {
"func" : mysum,
"args": (input_args.get("x"),),
"kwargs" : {
"y" : input_args.get("y")
},
"result_renderer": print
}
}

func_data = func_map.get(input_args.get("action_to_perform"))

func = func_data.get("func")
args = func_data.get("args")
kwargs = func_data.get("kwargs")
renderer = func_data.get("result_renderer")

renderer(func(*args, **kwargs))

if __name__ == '__main__':
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="action_to_perform")

foo_parser = subparsers.add_parser('mysum')
foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
foo_parser.add_argument('-y', metavar='PATH', type=int, default=3)
delegator(vars(parser.parse_args()))


Above example would also remove *args, **kwargs from your original function and lets the delegator send only what is needed by the function based on the command



You can extend it to support multiple commands

Hope this helps!






share|improve this answer




























    up vote
    0
    down vote













    This is the cleanest way I've found so far:



    import argparse

    def foo(*, x, y, **kwargs):
    print('X + Y:', x + y)
    return x + y

    if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()

    foo_parser = subparsers.add_parser('foo')
    foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
    foo_parser.add_argument('-y', metavar='PATH', type=int, default=2)
    foo_parser.set_defaults(func=foo)

    parser.add_argument('--debug', action='store_true', default=False)

    args = parser.parse_args()
    args.func(**vars(args))


    Maybe someone else can find something better.






    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',
      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%2f53148256%2fmake-functions-importable-when-using-argparse%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      1
      down vote



      accepted










      The use of args.func(**vars(args)) is not a best fit for use-cases which require import as well as a CLI view




      • When users import a function and call it, they expect a return value for further processing (nothing printed on a console. The caller can decide to print based on the result obtained)

      • When they use a CLI, they expect to see an output printed on the console and a proper exit code (0 or 1 based on the return value)


      The ideal way is to separate the parsing/CLI management/sum-function into separate functions and delegate processing once the parsing is complete (below is a sample example)



      from __future__ import print_function # for python2
      import argparse

      def mysum(x, y=5):
      return x+y

      def delegator(input_args):
      func_map = {
      "mysum" : {
      "func" : mysum,
      "args": (input_args.get("x"),),
      "kwargs" : {
      "y" : input_args.get("y")
      },
      "result_renderer": print
      }
      }

      func_data = func_map.get(input_args.get("action_to_perform"))

      func = func_data.get("func")
      args = func_data.get("args")
      kwargs = func_data.get("kwargs")
      renderer = func_data.get("result_renderer")

      renderer(func(*args, **kwargs))

      if __name__ == '__main__':
      parser = argparse.ArgumentParser()
      subparsers = parser.add_subparsers(dest="action_to_perform")

      foo_parser = subparsers.add_parser('mysum')
      foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
      foo_parser.add_argument('-y', metavar='PATH', type=int, default=3)
      delegator(vars(parser.parse_args()))


      Above example would also remove *args, **kwargs from your original function and lets the delegator send only what is needed by the function based on the command



      You can extend it to support multiple commands

      Hope this helps!






      share|improve this answer

























        up vote
        1
        down vote



        accepted










        The use of args.func(**vars(args)) is not a best fit for use-cases which require import as well as a CLI view




        • When users import a function and call it, they expect a return value for further processing (nothing printed on a console. The caller can decide to print based on the result obtained)

        • When they use a CLI, they expect to see an output printed on the console and a proper exit code (0 or 1 based on the return value)


        The ideal way is to separate the parsing/CLI management/sum-function into separate functions and delegate processing once the parsing is complete (below is a sample example)



        from __future__ import print_function # for python2
        import argparse

        def mysum(x, y=5):
        return x+y

        def delegator(input_args):
        func_map = {
        "mysum" : {
        "func" : mysum,
        "args": (input_args.get("x"),),
        "kwargs" : {
        "y" : input_args.get("y")
        },
        "result_renderer": print
        }
        }

        func_data = func_map.get(input_args.get("action_to_perform"))

        func = func_data.get("func")
        args = func_data.get("args")
        kwargs = func_data.get("kwargs")
        renderer = func_data.get("result_renderer")

        renderer(func(*args, **kwargs))

        if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="action_to_perform")

        foo_parser = subparsers.add_parser('mysum')
        foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
        foo_parser.add_argument('-y', metavar='PATH', type=int, default=3)
        delegator(vars(parser.parse_args()))


        Above example would also remove *args, **kwargs from your original function and lets the delegator send only what is needed by the function based on the command



        You can extend it to support multiple commands

        Hope this helps!






        share|improve this answer























          up vote
          1
          down vote



          accepted







          up vote
          1
          down vote



          accepted






          The use of args.func(**vars(args)) is not a best fit for use-cases which require import as well as a CLI view




          • When users import a function and call it, they expect a return value for further processing (nothing printed on a console. The caller can decide to print based on the result obtained)

          • When they use a CLI, they expect to see an output printed on the console and a proper exit code (0 or 1 based on the return value)


          The ideal way is to separate the parsing/CLI management/sum-function into separate functions and delegate processing once the parsing is complete (below is a sample example)



          from __future__ import print_function # for python2
          import argparse

          def mysum(x, y=5):
          return x+y

          def delegator(input_args):
          func_map = {
          "mysum" : {
          "func" : mysum,
          "args": (input_args.get("x"),),
          "kwargs" : {
          "y" : input_args.get("y")
          },
          "result_renderer": print
          }
          }

          func_data = func_map.get(input_args.get("action_to_perform"))

          func = func_data.get("func")
          args = func_data.get("args")
          kwargs = func_data.get("kwargs")
          renderer = func_data.get("result_renderer")

          renderer(func(*args, **kwargs))

          if __name__ == '__main__':
          parser = argparse.ArgumentParser()
          subparsers = parser.add_subparsers(dest="action_to_perform")

          foo_parser = subparsers.add_parser('mysum')
          foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
          foo_parser.add_argument('-y', metavar='PATH', type=int, default=3)
          delegator(vars(parser.parse_args()))


          Above example would also remove *args, **kwargs from your original function and lets the delegator send only what is needed by the function based on the command



          You can extend it to support multiple commands

          Hope this helps!






          share|improve this answer












          The use of args.func(**vars(args)) is not a best fit for use-cases which require import as well as a CLI view




          • When users import a function and call it, they expect a return value for further processing (nothing printed on a console. The caller can decide to print based on the result obtained)

          • When they use a CLI, they expect to see an output printed on the console and a proper exit code (0 or 1 based on the return value)


          The ideal way is to separate the parsing/CLI management/sum-function into separate functions and delegate processing once the parsing is complete (below is a sample example)



          from __future__ import print_function # for python2
          import argparse

          def mysum(x, y=5):
          return x+y

          def delegator(input_args):
          func_map = {
          "mysum" : {
          "func" : mysum,
          "args": (input_args.get("x"),),
          "kwargs" : {
          "y" : input_args.get("y")
          },
          "result_renderer": print
          }
          }

          func_data = func_map.get(input_args.get("action_to_perform"))

          func = func_data.get("func")
          args = func_data.get("args")
          kwargs = func_data.get("kwargs")
          renderer = func_data.get("result_renderer")

          renderer(func(*args, **kwargs))

          if __name__ == '__main__':
          parser = argparse.ArgumentParser()
          subparsers = parser.add_subparsers(dest="action_to_perform")

          foo_parser = subparsers.add_parser('mysum')
          foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
          foo_parser.add_argument('-y', metavar='PATH', type=int, default=3)
          delegator(vars(parser.parse_args()))


          Above example would also remove *args, **kwargs from your original function and lets the delegator send only what is needed by the function based on the command



          You can extend it to support multiple commands

          Hope this helps!







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 8 at 14:40









          pvpks

          1066




          1066
























              up vote
              0
              down vote













              This is the cleanest way I've found so far:



              import argparse

              def foo(*, x, y, **kwargs):
              print('X + Y:', x + y)
              return x + y

              if __name__ == '__main__':
              parser = argparse.ArgumentParser()
              subparsers = parser.add_subparsers()

              foo_parser = subparsers.add_parser('foo')
              foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
              foo_parser.add_argument('-y', metavar='PATH', type=int, default=2)
              foo_parser.set_defaults(func=foo)

              parser.add_argument('--debug', action='store_true', default=False)

              args = parser.parse_args()
              args.func(**vars(args))


              Maybe someone else can find something better.






              share|improve this answer



























                up vote
                0
                down vote













                This is the cleanest way I've found so far:



                import argparse

                def foo(*, x, y, **kwargs):
                print('X + Y:', x + y)
                return x + y

                if __name__ == '__main__':
                parser = argparse.ArgumentParser()
                subparsers = parser.add_subparsers()

                foo_parser = subparsers.add_parser('foo')
                foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
                foo_parser.add_argument('-y', metavar='PATH', type=int, default=2)
                foo_parser.set_defaults(func=foo)

                parser.add_argument('--debug', action='store_true', default=False)

                args = parser.parse_args()
                args.func(**vars(args))


                Maybe someone else can find something better.






                share|improve this answer

























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  This is the cleanest way I've found so far:



                  import argparse

                  def foo(*, x, y, **kwargs):
                  print('X + Y:', x + y)
                  return x + y

                  if __name__ == '__main__':
                  parser = argparse.ArgumentParser()
                  subparsers = parser.add_subparsers()

                  foo_parser = subparsers.add_parser('foo')
                  foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
                  foo_parser.add_argument('-y', metavar='PATH', type=int, default=2)
                  foo_parser.set_defaults(func=foo)

                  parser.add_argument('--debug', action='store_true', default=False)

                  args = parser.parse_args()
                  args.func(**vars(args))


                  Maybe someone else can find something better.






                  share|improve this answer














                  This is the cleanest way I've found so far:



                  import argparse

                  def foo(*, x, y, **kwargs):
                  print('X + Y:', x + y)
                  return x + y

                  if __name__ == '__main__':
                  parser = argparse.ArgumentParser()
                  subparsers = parser.add_subparsers()

                  foo_parser = subparsers.add_parser('foo')
                  foo_parser.add_argument('-x', metavar='PATH', type=int, default=1)
                  foo_parser.add_argument('-y', metavar='PATH', type=int, default=2)
                  foo_parser.set_defaults(func=foo)

                  parser.add_argument('--debug', action='store_true', default=False)

                  args = parser.parse_args()
                  args.func(**vars(args))


                  Maybe someone else can find something better.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 11 at 4:42

























                  answered Nov 5 at 4:38









                  Evidlo

                  484




                  484






























                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53148256%2fmake-functions-importable-when-using-argparse%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

                      Bressuire

                      Vorschmack

                      Quarantine