Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: cs@zip.com.au Newsgroups: comp.lang.python Subject: Re: sys.exit(1) vs raise SystemExit vs raise Date: Sat, 16 Apr 2016 13:48:33 +1000 Lines: 154 Message-ID: References: <20160416034833.GA24653@cskk.homeip.net> Reply-To: python-list@python.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed X-Trace: news.uni-berlin.de 6L1BkLNm+EGdcX4stfj+SAbbzF5kSUHpzacxBUYhvyog== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'anyway.': 0.04; 'context': 0.05; '__name__': 0.07; 'caller': 0.07; 'debugging.': 0.07; 'exception.': 0.07; 'main()': 0.07; 'skip:! 20': 0.07; 'scripts': 0.09; 'abort': 0.09; 'appropriate.': 0.09; 'exception,': 0.09; 'failed:': 0.09; 'oserror': 0.09; 'output,': 0.09; 'prevents': 0.09; 'stderr': 0.09; 'unhandled': 0.09; 'python': 0.10; '2.7': 0.13; 'exception': 0.13; 'output': 0.13; 'stack': 0.13; 'def': 0.13; 'do,': 0.15; "'__main__':": 0.16; '(also': 0.16; '_do_': 0.16; 'configuring': 0.16; 'e))': 0.16; 'expects': 0.16; 'from:addr:cs': 0.16; 'from:addr:zip.com.au': 0.16; 'main():': 0.16; 'message-id:@cskk.homeip.net': 0.16; 'normally.': 0.16; 'occurred.': 0.16; 'received:io': 0.16; 'received:psf.io': 0.16; 'resist': 0.16; 'simpson': 0.16; 'sys.exit(1)': 0.16; 'systemexit': 0.16; 'try/except': 0.16; 'wrote:': 0.16; 'debugging': 0.18; 'instance,': 0.18; 'skip:l 30': 0.18; 'try:': 0.18; 'library': 0.20; 'preferred': 0.20; 'skip:" 30': 0.20; 'to:name:python-list@python.org': 0.20; 'not,': 0.22; '%s"': 0.22; 'exceptions': 0.22; 'file:': 0.22; 'function,': 0.22; 'simpler': 0.22; 'cheers,': 0.22; 'code.': 0.23; 'this:': 0.23; '(most': 0.24; 'somewhere': 0.24; 'written': 0.24; 'header:In-Reply-To:1': 0.24; 'module': 0.25; 'header:User-Agent:1': 0.26; 'example': 0.26; 'linux': 0.26; 'error': 0.27; 'logging': 0.27; 'finally,': 0.27; 'function': 0.28; "skip:' 10": 0.28; 'fine': 0.28; '(it': 0.29; 'code:': 0.29; 'raise': 0.29; 'print': 0.30; 'code': 0.30; 'class.': 0.30; 'error.': 0.31; 'knows': 0.32; 'generally': 0.32; 'subject:) ': 0.32; 'useful': 0.33; 'problem': 0.33; 'done,': 0.33; 'instead,': 0.33; 'definition': 0.34; 'file': 0.34; 'except': 0.34; 'handle': 0.34; 'could': 0.35; 'functions.': 0.35; 'replace': 0.35; 'something': 0.35; 'level': 0.35; 'but': 0.36; 'should': 0.36; 'instead': 0.36; 'there': 0.36; '(i.e.': 0.36; 'to:addr:python-list': 0.36; 'subject:: ': 0.37; 'being': 0.37; 'agree': 0.37; 'suggestion': 0.37; 'charset:us-ascii': 0.37; 'received:localdomain': 0.38; 'turned': 0.38; 'wrong': 0.38; 'anything': 0.38; 'log': 0.38; 'skip:o 20': 0.38; 'goes': 0.39; "didn't": 0.39; 'enough': 0.39; 'to:addr:python.org': 0.40; 'where': 0.40; 'still': 0.40; 'called': 0.40; 'from:no real name:2**0': 0.60; 'chance': 0.60; 'your': 0.60; 'skip:u 10': 0.61; 'avoid': 0.61; 'back': 0.62; 'more': 0.63; 'believe': 0.66; 'cameron': 0.66; 'here': 0.66; 'situation': 0.67; 'header:Reply- To:1': 0.67; 'records': 0.70; 'reply-to:no real name:2**0': 0.71; 'yourself': 0.73; '>def': 0.84; '>if': 0.84; 'eg:': 0.84; 'outermost': 0.84; 'personally.': 0.84; 'reply- to:addr:python.org': 0.84; 'returns.': 0.84; 'think:': 0.84; 'wiring': 0.84; 'dealt': 0.91 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Mailman-Original-Message-ID: <20160416034833.GA24653@cskk.homeip.net> X-Mailman-Original-References: Xref: csiph.com comp.lang.python:107074 On 12Apr2016 18:20, Ganesh Pal wrote: >I m on python 2.7 and Linux , I have a simple code need suggestion if I > I could replace sys.exit(1) with raise SystemExit . > >==Actual code== > >def main(): > try: > create_logdir() > create_dataset() > unittest.main() > except Exception as e: > logging.exception(e) > sys.exit(EXIT_STATUS_ERROR) > >if __name__ == '__main__': > main() > >==Changed Code== > > >def main(): > try: > create_logdir() > create_dataset() > unittest.main() > except Exception as e: > logging.exception(e) > raise SystemExit > >if __name__ == '__main__': > main() I am against both of these personally. My preferred pattern is like this: def main(argv): try: ... except Exception as e: logging.exception(e) return 1 if __name__ == '__main__': sys.exit(main(sys.argv)) Notice that main() is back to being a normal function with normal returns. Also, most of us would avoid the "except Exception" and just let a top level except bubble out: that way you get a stack backtrace for debugging. I agree it prevents logging the exception and makes for uglier console output, but I think it is a win. And if you _do_ want to log the exception there is always this: try: ... except Exception as e: logging.exception(e) raise to recite the exception into the log and still let it bubble out normally. The problem with the "except Exception" pattern is that it catches and _hides_ _every_ exception, not merely the narrow set of specific exceptions that you understand. Finally, it is frowned upon to raise a bare Exception class. In python 3 I believe it is actually forbidden, so it is nonportable anyway. But even In Python to it is best to supply an Exception instance, not the class: raise SystemExit(1) >2. All the functions in try block have exception bubbled out using raise > > Example for create_logdir() here is the function definition > >def create_logdir(): > > try: > os.makedirs(LOG_DIR) > except OSError as e: > sys.stderr.write("Failed to create log directory...Exiting !!!") > raise > print "log file: " + corrupt_log > return True > >def main(): > try: > create_logdir() > except Exception as e: > logging.exception(e) > raise SystemExit > >(a) In case if create_logdir() fails we will get the below error ,is >this fine or do I need to improve this code. > >Failed to create log directory...Exiting !!!ERROR:root:[Errno 17] File >exists: '/var/log/dummy' > >Traceback (most recent call last): > File "corrupt_test.py", line 245, in main > create_logdir() > File "corrupt_test.py", line 53, in create_logdir > os.makedirs(LOG_DIR) > File "/usr/local/lib/python2.7/os.py", line 157, in makedirs >OSError: [Errno 17] File exists: '/var/log/dummy' I prefer the bubble out approach, perhap with a log or warning messages as you have done, eg: logging.exception("create_logdir failed: makedirs(%r): %s" % (LOG_DIR, e)) raise (Also not that that log message records more context: context is very useful when debugging problems.) For very small scripts sys.stderr.write is ok, but in general any of your functions that turned out to be generally useful might migrate into a library in order to be reused; consider that stderr is not always the place for messages; instead reading for the logging module with error() or wanr() or exception() as appropriate. There is more scope for configuring where the output goes that way without wiring it into your inner functions. >3. Can I have just raise , instead of SystemExit or sys.exit(1) . This >looks wrong to me > > def main(): > > try: > create_logdir() > except Exception as e > logging.exception(e) > raise This is what I would do, myself. Think: has the exception been "handled", meaning has the situation been dealt with because it was expected? If not, let the exception bubble out so that the user knows that something _not_ understood by the program has occurred. Finally, it is generally bad to SystemExit or sys.exit() from inside anything other than the outermost main() function. And I resist it even there; the main function, if written well, may often be called from somewhere else usefully, and that makes it effectively a library function (it has been reused). Such a function should not unilaterally abort the program. How rude! Instead, let the exception bubble out: perhaps the _caller_ of main() expects it and can handle it. By aborting and not "raise"ing, you have deprived the caller of the chance to do something appropriate, even though you yourself (i.e. "main") do not know enough context to handle the exception. So I am for "raise" myself. And then only because you want to log the error. If you didn't want to log the exception you could avoid the try/except _entirely_ and have simpler code: let the caller worry about unhandled exceptions! Cheers, Cameron Simpson