[patch] show unexpected tracebacks to stderr

Martin Pool mbp at canonical.com
Tue Jun 20 00:48:41 BST 2006


On 15 Jun 2006, John Arbash Meinel <john at arbash-meinel.com> wrote:
> Martin Pool wrote:
> > bzr.log was a nice idea, but it's a bit unobvious.

> I can see a lot of nice cleanup happening.

Thanks

> Why did you get rid of BzrOptionError in favor of BzrCommandError?

I was trying to clean up exceptions that are constructed with different
meanings depending just on the format string provided to them.  Perhaps
this was taking it too far.  

> v- PEP8 here
> 
> > -class BzrCommandError(BzrError):
> > +class BzrCommandError(BzrNewError):
> > +    """Error from user command"""
> > +    is_user_error = True
> >      # Error from malformed user command
> >      # This is being misused as a generic exception
> >      # pleae subclass. RBC 20051030
> > @@ -172,15 +195,14 @@
> >      # are not intended to be caught anyway.  UI code need not subclass
> >      # BzrCommandError, and non-UI code should not throw a subclass of
> >      # BzrCommandError.  ADHB 20051211
> 
> ...
> 

> The '%r' was in case there was a Unicode path that could not be
> displayed in the current encoding. You can chose how you want to handle
> it. But is PathError a user_error or not?
> These seem like hidden internal classes, that if one escapes, it should
> be a bug.

OK, I'll put them back to not user_error and %r.

> 
> >  
> >  class NoSuchFile(PathError):
> > -    """No such file: %(path)r%(extra)s"""
> > +    """No such file: %(path)s%(extra)s"""
> >  
> >  
> >  class FileExists(PathError):
> > -    """File exists: %(path)r%(extra)s"""
> > +    """File exists: %(path)s%(extra)s"""
> >  
> >  
> >  class DirectoryNotEmpty(PathError):
> > -    """Directory not empty: %(path)r%(extra)s"""
> > +    """Directory not empty: %(path)s%(extra)s"""
> >  
> >  
> >  class ResourceBusy(PathError):
> > -    """Device or resource busy: %(path)r%(extra)s"""
> > +    """Device or resource busy: %(path)s%(extra)s"""
> >  
> >  
> >  class PermissionDenied(PathError):
> > -    """Permission denied: %(path)r%(extra)s"""
> > +    """Permission denied: %(path)s%(extra)s"""
> >  
> >  
> >  class PathNotChild(BzrNewError):
> > -    """Path %(path)r is not a child of path %(base)r%(extra)s"""
> > +    """Path %(path)s is not a child of path %(base)s%(extra)s"""
> > +
> > +    is_user_error = False
> > +
> >      def __init__(self, path, base, extra=None):
> >          BzrNewError.__init__(self)
> >          self.path = path
> > @@ -244,7 +269,7 @@
> >  
> 
> v- PEP8 here as well
> >  class ObjectNotLocked(LockError):
> > -    """%(obj)r is not locked"""
> > +    """%(obj)s is not locked"""
> > +    is_user_error = False
> >      # this can indicate that any particular object is not locked; see also
> >      # LockNotHeld which means that a particular *lock* object is not held by
> >      # the caller -- perhaps they should be unified.
> > @@ -366,7 +388,7 @@
> >  
> 
> 

> v- Here you switch r => s, but then left another %r

OK, should probably revert that.

> >  class LockBreakMismatch(LockError):
> > -    """Lock was released and re-acquired before being broken: %(lock)s: held by %(holder)r, wanted to break %(target)r"""
> > +    """Lock was released and re-acquired before being broken: %(lock)s: held by %(holder)s, wanted to break %(target)r"""
> >      def __init__(self, lock, holder, target):
> >          self.lock = lock
> >          self.holder = holder
> > @@ -425,42 +447,38 @@
> >      """Commit refused because there are unknowns in the tree."""
> >  
> >  
> 
> 
> > === modified file 'bzrlib/tests/test_source.py'
> > --- bzrlib/tests/test_source.py	
> > +++ bzrlib/tests/test_source.py	
> > @@ -72,4 +72,4 @@
> >          # written. Note that this is an exact equality so that when the number
> >          # drops, it is not given a buffer but rather this test updated
> >          # immediately.
> > -        self.assertEqual(4, occurences)
> > +        self.assertEqual(3, occurences)
> 
> Good for us.
> 
> 
> v- I thought we weren't doing 'Authors' statements.

I'll remove it.

> 
> > === modified file 'bzrlib/tests/test_trace.py'
> > --- bzrlib/tests/test_trace.py	
> > +++ bzrlib/tests/test_trace.py	
> 
> 
> ...
> These seem like API changes that would need to be deprecated first.

I suppose they are.  It's satisfying to just pull it out but I suppose
we can have the deferred satisfaction of knowing it will be deleted in
the future.
 
> > -def log_exception(msg=None):
> > -    """Log the last exception to stderr and the trace file.
> > -
> > -    The exception string representation is used as the error
> > -    summary, unless msg is given.
> > -    """
> > -    if msg:
> > -        error(msg)
> > -    else:
> > -        exc_str = format_exception_short(sys.exc_info())
> > -        error(exc_str)
> > -    log_exception_quietly()
> > -
> > -
> >  def log_exception_quietly():
> >      """Log the last exception to the trace file only.
> >  
> 
> Does this handle the case of commands that shouldn't show anything on
> EPIPE? Probably that exception is caught in the decorator, so isn't
> important here.

Yes, I think they should catch it below this level.

> > +def report_exception(exc_info, err_file):
> > +    exc_type, exc_object, exc_tb = exc_info
> > +    if (isinstance(exc_object, IOError)
> > +        and getattr(exc_object, 'errno', None) == errno.EPIPE):
> > +        print >>err_file, "bzr: broken pipe"
> > +    elif isinstance(exc_object, KeyboardInterrupt):
> > +        print >>err_file, "bzr: interrupted"
> > +    elif getattr(exc_object, 'is_user_error', False):
> > +        report_user_error(exc_info, err_file)
> > +    elif isinstance(exc_object, (OSError, IOError)):
> > +        # Might be nice to catch all of these and show them as something more
> > +        # specific, but there are too many cases at the moment.
> > +        report_user_error(exc_info, err_file)
> > +    else:
> > +        report_bug(exc_info, err_file)
> 
> 
> A couple small things, but +1 overall.

Thankyou for the review comments.  I'll fix them up and merge it in.

-- 
Martin




More information about the bazaar mailing list