diff mbox

[6/n] pwclient: diagnose hash_parser errors gracefully

Message ID 1409313728-20022-1-git-send-email-rep.dot.nop@gmail.com
State Accepted
Headers show

Commit Message

Bernhard Reutner-Fischer Aug. 29, 2014, 12:02 p.m. UTC
a386e636cc0adaa760a66b6ab042178027fc45c7 removed argparse mutual
exclusive group, so manually diagnose:

1) missing required hash_str / IDs
2) if both hash_str as well as IDs are seen

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
---
 apps/patchwork/bin/pwclient | 45 +++++++++++++++++++++++++++++++++------------
 1 file changed, 33 insertions(+), 12 deletions(-)

Comments

Jacob Keller Aug. 29, 2014, 3:14 p.m. UTC | #1
On Fri, 2014-08-29 at 14:02 +0200, Bernhard Reutner-Fischer wrote:
> a386e636cc0adaa760a66b6ab042178027fc45c7 removed argparse mutual

> exclusive group, so manually diagnose:

> 

> 1) missing required hash_str / IDs

> 2) if both hash_str as well as IDs are seen

> 

> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>

> ---

>  apps/patchwork/bin/pwclient | 45 +++++++++++++++++++++++++++++++++------------

>  1 file changed, 33 insertions(+), 12 deletions(-)

> 

> diff --git a/apps/patchwork/bin/pwclient b/apps/patchwork/bin/pwclient

> index bd79b3a..86feef0 100755

> --- a/apps/patchwork/bin/pwclient

> +++ b/apps/patchwork/bin/pwclient

> @@ -332,7 +332,7 @@ class _RecursiveHelpAction(argparse._HelpAction):

>  def main():

>      hash_parser = argparse.ArgumentParser(add_help=False, version=False)

>      hash_parser.add_argument(

> -        '-h', metavar='HASH', dest='hash', action='store', required=False,

> +        '-h', metavar='HASH', dest='hash', action='store',

>          help='''Lookup by patch hash'''

>      )

>      hash_parser.add_argument(

> @@ -474,11 +474,13 @@ def main():

>  

>      args = action_parser.parse_args()

>      args=dict(vars(args))

> +    action = args.get('subcmd')

>  

>      if args.get('hash') and len(args.get('id')):

>          # mimic mutual exclusive group

> -        sys.stderr.write("[-h HASH] and [ID [ID ...]] are mutually exlusive!\n")

> -        action_parser.print_help()

> +        sys.stderr.write("Error: [-h HASH] and [ID [ID ...]] " +

> +          "are mutually exlusive\n")

> +        locals()[action + '_parser'].print_help()

>          sys.exit(1)

>  

>      # set defaults

> @@ -493,8 +495,6 @@ def main():

>      patch_ids = None

>      url = DEFAULT_URL

>  

> -    action = args.get('subcmd')

> -

>      if args.get('s'):

>          state_str = args.get('s')

>      if args.get('p'):

> @@ -510,7 +510,9 @@ def main():

>      if args.get('c'):

>          # update multiple IDs with a single commit-hash does not make sense

>          if action == 'update' and patch_ids and len(patch_ids) > 1:

> -            sys.stderr.write("Declining update with COMMIT-REF on multiple IDs\n")

> +            sys.stderr.write(

> +              "Declining update with COMMIT-REF on multiple IDs\n"

> +            )

>              update_parser.print_help()

>              sys.exit(1)

>          commit_str = args.get('c')

> @@ -618,6 +620,23 @@ def main():

>      if hash_str != None:

>          patch_ids = [patch_id_from_hash(rpc, project_str, hash_str)]

>  

> +    # helper for non_empty() to print correct helptext

> +    h = None

> +    try:

> +        h = locals()[action + '_parser']

> +    except:

> +        pass # never happens


This is bad. Why blindly pass any exceptions here?? If you "know" it
never happens then you shouldn't have an except block, since that will
prevent debugging real exceptions that could occur. Unless you are
specifically blocking some exception you know will happen? but then it
should be typed to only catch the ones you know of.......

> +    # Require either hash_str or IDs for

> +    def non_empty(h, patch_ids):

> +        """Error out if no patch IDs were specified"""

> +        if patch_ids == None or len(patch_ids) < 1:

> +            sys.stderr.write("Error: Missing Argument! " +

> +              "Either [-h HASH] or [ID [ID ...]] are required\n")

> +            if h:

> +                h.print_help()

> +            sys.exit(1)

> +        return patch_ids

> +

>      if action == 'list' or action == 'search':

>          if args.get('patch_name') != None:

>              filt.add("name__icontains", args.get('patch_name'))

> @@ -630,29 +649,31 @@ def main():

>          action_states(rpc)

>  

>      elif action == 'view':

> -        for patch_id in patch_ids:

> +        for patch_id in non_empty(h, patch_ids):

>              s = rpc.patch_get_mbox(patch_id)

>              if len(s) > 0:

>                  print unicode(s).encode("utf-8")

>  

>      elif action in ('get', 'save', 'info'):

>          if action == 'info':

> -            [action_info(rpc, patch_id) for patch_id in patch_ids]

> +            [action_info(rpc, patch_id) for patch_id in non_empty(h, patch_ids)]

>          else:

> -            [action_get(rpc, patch_id) for patch_id in patch_ids]

> +            [action_get(rpc, patch_id) for patch_id in non_empty(h, patch_ids)]

>  

>      elif action == 'apply':

> -        [action_apply(rpc, patch_id) for patch_id in patch_ids]

> +        [action_apply(rpc, patch_id) for patch_id in non_empty(h, patch_ids)]

>  

>      elif action == 'git-am':

>          cmd = ['git', 'am']

>          if do_signoff:

>              cmd.append('-s')

> -        [action_apply(rpc, patch_id, cmd) for patch_id in patch_ids]

> +        [action_apply(rpc, patch_id, cmd) for patch_id in

> +         non_empty(h, patch_ids)]

>  

>      elif action == 'update':

>          [action_update_patch(rpc, patch_id, state = state_str,

> -                commit = commit_str) for patch_id in patch_ids]

> +                commit = commit_str

> +         ) for patch_id in non_empty(h, patch_ids)]

>  

>      else:

>          sys.stderr.write("Unknown action '%s'\n" % action)
Bernhard Reutner-Fischer Sept. 8, 2014, 11:22 a.m. UTC | #2
[Please keep me CC'ed]

On Fri, Aug 29, 2014 at 03:14:35PM +0000, Keller, Jacob E wrote:
>On Fri, 2014-08-29 at 14:02 +0200, Bernhard Reutner-Fischer wrote:

>> @@ -618,6 +620,23 @@ def main():
>>      if hash_str != None:
>>          patch_ids = [patch_id_from_hash(rpc, project_str, hash_str)]
>>  
>> +    # helper for non_empty() to print correct helptext
>> +    h = None
>> +    try:
>> +        h = locals()[action + '_parser']
>> +    except:
>> +        pass # never happens
>
>This is bad. Why blindly pass any exceptions here?? If you "know" it
>never happens then you shouldn't have an except block, since that will
>prevent debugging real exceptions that could occur. Unless you are
>specifically blocking some exception you know will happen? but then it
>should be typed to only catch the ones you know of.......

Iff we update to an argparse that supports aliases and we do not
deprecate action == "search" as an alias for "list" then we might end up
with no search_parser here. As that is not a real show-stopper, i did
choose to just not print the corresponding parser's help-text if there
is no such parser. Note that this currently cannot happen since we
cannot use aliases with argparse from python-2.7 (AFAICS).

thanks,
>
>> +    # Require either hash_str or IDs for
>> +    def non_empty(h, patch_ids):
>> +        """Error out if no patch IDs were specified"""
>> +        if patch_ids == None or len(patch_ids) < 1:
>> +            sys.stderr.write("Error: Missing Argument! " +
>> +              "Either [-h HASH] or [ID [ID ...]] are required\n")
>> +            if h:
>> +                h.print_help()
>> +            sys.exit(1)
>> +        return patch_ids
>> +
>>      if action == 'list' or action == 'search':
>>          if args.get('patch_name') != None:
>>              filt.add("name__icontains", args.get('patch_name'))
>> @@ -630,29 +649,31 @@ def main():
>>          action_states(rpc)
>>  
>>      elif action == 'view':
>> -        for patch_id in patch_ids:
>> +        for patch_id in non_empty(h, patch_ids):
>>              s = rpc.patch_get_mbox(patch_id)
>>              if len(s) > 0:
>>                  print unicode(s).encode("utf-8")
Jacob Keller Sept. 8, 2014, 10:34 p.m. UTC | #3
> -----Original Message-----
> From: Bernhard Reutner-Fischer [mailto:rep.dot.nop@gmail.com]
> Sent: Monday, September 08, 2014 4:23 AM
> To: Keller, Jacob E
> Cc: patchwork@lists.ozlabs.org
> Subject: Re: [PATCH 6/n] pwclient: diagnose hash_parser errors
> gracefully
> 
> [Please keep me CC'ed]
> 
> On Fri, Aug 29, 2014 at 03:14:35PM +0000, Keller, Jacob E wrote:
> >On Fri, 2014-08-29 at 14:02 +0200, Bernhard Reutner-Fischer wrote:
> 
> >> @@ -618,6 +620,23 @@ def main():
> >>      if hash_str != None:
> >>          patch_ids = [patch_id_from_hash(rpc, project_str, hash_str)]
> >>
> >> +    # helper for non_empty() to print correct helptext
> >> +    h = None
> >> +    try:
> >> +        h = locals()[action + '_parser']
> >> +    except:
> >> +        pass # never happens
> >
> >This is bad. Why blindly pass any exceptions here?? If you "know" it
> >never happens then you shouldn't have an except block, since that will
> >prevent debugging real exceptions that could occur. Unless you are
> >specifically blocking some exception you know will happen? but then it
> >should be typed to only catch the ones you know of.......
> 
> Iff we update to an argparse that supports aliases and we do not
> deprecate action == "search" as an alias for "list" then we might end up
> with no search_parser here. As that is not a real show-stopper, i did
> choose to just not print the corresponding parser's help-text if there
> is no such parser. Note that this currently cannot happen since we
> cannot use aliases with argparse from python-2.7 (AFAICS).
> 
> thanks,
> >

That makes sense :)

Regards,
Jake

> >> +    # Require either hash_str or IDs for
> >> +    def non_empty(h, patch_ids):
> >> +        """Error out if no patch IDs were specified"""
> >> +        if patch_ids == None or len(patch_ids) < 1:
> >> +            sys.stderr.write("Error: Missing Argument! " +
> >> +              "Either [-h HASH] or [ID [ID ...]] are required\n")
> >> +            if h:
> >> +                h.print_help()
> >> +            sys.exit(1)
> >> +        return patch_ids
> >> +
> >>      if action == 'list' or action == 'search':
> >>          if args.get('patch_name') != None:
> >>              filt.add("name__icontains", args.get('patch_name'))
> >> @@ -630,29 +649,31 @@ def main():
> >>          action_states(rpc)
> >>
> >>      elif action == 'view':
> >> -        for patch_id in patch_ids:
> >> +        for patch_id in non_empty(h, patch_ids):
> >>              s = rpc.patch_get_mbox(patch_id)
> >>              if len(s) > 0:
> >>                  print unicode(s).encode("utf-8")
diff mbox

Patch

diff --git a/apps/patchwork/bin/pwclient b/apps/patchwork/bin/pwclient
index bd79b3a..86feef0 100755
--- a/apps/patchwork/bin/pwclient
+++ b/apps/patchwork/bin/pwclient
@@ -332,7 +332,7 @@  class _RecursiveHelpAction(argparse._HelpAction):
 def main():
     hash_parser = argparse.ArgumentParser(add_help=False, version=False)
     hash_parser.add_argument(
-        '-h', metavar='HASH', dest='hash', action='store', required=False,
+        '-h', metavar='HASH', dest='hash', action='store',
         help='''Lookup by patch hash'''
     )
     hash_parser.add_argument(
@@ -474,11 +474,13 @@  def main():
 
     args = action_parser.parse_args()
     args=dict(vars(args))
+    action = args.get('subcmd')
 
     if args.get('hash') and len(args.get('id')):
         # mimic mutual exclusive group
-        sys.stderr.write("[-h HASH] and [ID [ID ...]] are mutually exlusive!\n")
-        action_parser.print_help()
+        sys.stderr.write("Error: [-h HASH] and [ID [ID ...]] " +
+          "are mutually exlusive\n")
+        locals()[action + '_parser'].print_help()
         sys.exit(1)
 
     # set defaults
@@ -493,8 +495,6 @@  def main():
     patch_ids = None
     url = DEFAULT_URL
 
-    action = args.get('subcmd')
-
     if args.get('s'):
         state_str = args.get('s')
     if args.get('p'):
@@ -510,7 +510,9 @@  def main():
     if args.get('c'):
         # update multiple IDs with a single commit-hash does not make sense
         if action == 'update' and patch_ids and len(patch_ids) > 1:
-            sys.stderr.write("Declining update with COMMIT-REF on multiple IDs\n")
+            sys.stderr.write(
+              "Declining update with COMMIT-REF on multiple IDs\n"
+            )
             update_parser.print_help()
             sys.exit(1)
         commit_str = args.get('c')
@@ -618,6 +620,23 @@  def main():
     if hash_str != None:
         patch_ids = [patch_id_from_hash(rpc, project_str, hash_str)]
 
+    # helper for non_empty() to print correct helptext
+    h = None
+    try:
+        h = locals()[action + '_parser']
+    except:
+        pass # never happens
+    # Require either hash_str or IDs for
+    def non_empty(h, patch_ids):
+        """Error out if no patch IDs were specified"""
+        if patch_ids == None or len(patch_ids) < 1:
+            sys.stderr.write("Error: Missing Argument! " +
+              "Either [-h HASH] or [ID [ID ...]] are required\n")
+            if h:
+                h.print_help()
+            sys.exit(1)
+        return patch_ids
+
     if action == 'list' or action == 'search':
         if args.get('patch_name') != None:
             filt.add("name__icontains", args.get('patch_name'))
@@ -630,29 +649,31 @@  def main():
         action_states(rpc)
 
     elif action == 'view':
-        for patch_id in patch_ids:
+        for patch_id in non_empty(h, patch_ids):
             s = rpc.patch_get_mbox(patch_id)
             if len(s) > 0:
                 print unicode(s).encode("utf-8")
 
     elif action in ('get', 'save', 'info'):
         if action == 'info':
-            [action_info(rpc, patch_id) for patch_id in patch_ids]
+            [action_info(rpc, patch_id) for patch_id in non_empty(h, patch_ids)]
         else:
-            [action_get(rpc, patch_id) for patch_id in patch_ids]
+            [action_get(rpc, patch_id) for patch_id in non_empty(h, patch_ids)]
 
     elif action == 'apply':
-        [action_apply(rpc, patch_id) for patch_id in patch_ids]
+        [action_apply(rpc, patch_id) for patch_id in non_empty(h, patch_ids)]
 
     elif action == 'git-am':
         cmd = ['git', 'am']
         if do_signoff:
             cmd.append('-s')
-        [action_apply(rpc, patch_id, cmd) for patch_id in patch_ids]
+        [action_apply(rpc, patch_id, cmd) for patch_id in
+         non_empty(h, patch_ids)]
 
     elif action == 'update':
         [action_update_patch(rpc, patch_id, state = state_str,
-                commit = commit_str) for patch_id in patch_ids]
+                commit = commit_str
+         ) for patch_id in non_empty(h, patch_ids)]
 
     else:
         sys.stderr.write("Unknown action '%s'\n" % action)