Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-16 Thread Steven D'Aprano
On Sun, 17 Apr 2016 02:09 am, Dennis Lee Bieber wrote:


> VMS had a whole slew of "no error" status values (essentially all
> positive odd integers were "success", but different values carried
> additional information. 

1 = success
3 = success against all odds
5 = success but at great cost
7 = success, and it was as easy as falling off a log
9 = success, and it was so easy you ought to be ashamed for
asking the computer to do it instead of doing it yourself
11 = I told you I already did it yesterday
13 = done, but it wasn't worth doing
15 = well that was easier than I expected
17 = that was harder than I expected
19 = I did it, but I'm not going to do it again

> Even integers were errors [I forget if positive or 
> negative were "warnings" vs "error"])
> 
> True, the simplest was "1", which just carried "success -- no
> additional details" and "0" was "unspecified failure".



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-16 Thread Ben Finney
Dennis Lee Bieber  writes:

> On Sat, 16 Apr 2016 16:56:10 +1000, Ben Finney 
> declaimed the following:
>
> >It seems strange that even the constant for “no error” exit status
> >should be defined only for Unix :-/
>
>   VMS had a whole slew of "no error" status values

That's fine; those values can be defined per operating system, and
maybe they should be.

My concern is that (according to the documentation) the “no error” exit
status *isn't even defined* on non-Unix operating systems, as though
no other OS uses it.

-- 
 \ “Do unto others twenty-five percent better than you expect them |
  `\  to do unto you. (The twenty-five percent is [to correct] for |
_o__)error.)” —Linus Pauling's Golden Rule |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-16 Thread Chris Angelico
On Sat, Apr 16, 2016 at 4:56 PM, Ben Finney  wrote:
> Stephen Hansen  writes:
>
>> > * You can use named constants from ‘os’ for the purpose of specifying
>> >   exit status numbers.
>>
>> Only on *nix.
>
> Hmm, I didn't see that. It seems strange that even the constant for “no
> error” exit status should be defined only for Unix :-/

Maybe it's an error to use anything non-Unix??

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-16 Thread Ben Finney
Stephen Hansen  writes:

> > * You can use named constants from ‘os’ for the purpose of specifying
> >   exit status numbers.
>
> Only on *nix.

Hmm, I didn't see that. It seems strange that even the constant for “no
error” exit status should be defined only for Unix :-/

-- 
 \ “Geeks like to think that they can ignore politics. You can |
  `\leave politics alone, but politics won't leave you alone.” |
_o__) —Richard M. Stallman, 2002-07-26 |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-15 Thread Stephen Hansen

> * You can use named constants from ‘os’ for the purpose of specifying
>   exit status numbers.

Only on *nix. 

Even then it varies from platform to platform which constants you can
use. I'd prefer to document the return status and use numbers/my own
constants directly, that way supporting any platform (even windows,
where its %ERRORLEVEL%

--S
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-15 Thread Ben Finney
c...@zip.com.au writes:

> 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.

That's good. A couple of points:

* If you allow ‘main’ to be called with no arguments, and default to the
  actual command-line, then ‘main’ becomes a function you can use as a
  Setuptools entry point.

* If the ‘main’ function encounters no exception, it will return ‘None’
  instead of the correct exit status of 0.

* You can use named constants from ‘os’ for the purpose of specifying
  exit status numbers.

  https://docs.python.org/3/library/os.html#os._exit>

So::

def main(argv=None):
""" Mainline procedure for this program.

:param argv: Sequence of command-line arguments.
Default: `sys.argv`.
:return: Exit status (integer) for this program.

"""
exit_status = os.EX_OK

if argv is None:
argv = sys.argv

try:
...
except Exception as exc:
logging.exception(exc)
exit_status = os.EX_SOFTWARE

return exit_status

if __name__ == '__main__':
sys.exit(main(sys.argv))

-- 
 \  “He that would make his own liberty secure must guard even his |
  `\ enemy from oppression.” —Thomas Paine |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-15 Thread cs

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 
--
https://mail.python.org/mailman/listinfo/python-lis

Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Ben Finney
"Martin A. Brown"  writes:

> The only change from what Ben suggests is that, once I found os.EX_OK,
> I just kept on using it, instead of difining my own EXIT_SUCCESS in
> every program.

Ah, thank you! I was unaware of the exit-status constants in ‘os’::

The following exit codes are defined and can be used with _exit(),
although they are not required. These are typically used for system
programs written in Python […]

https://docs.python.org/3/library/os.html#os._exit>

That defines a whole lot of exit status values with mnemonic names. I
will try to make use of those instead of re-inventing them.

-- 
 \   “Let others praise ancient times; I am glad I was born in |
  `\  these.” —Ovid (43 BCE–18 CE) |
_o__)  |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Martin A. Brown

Hello all,

Apologies for this post which is fundamentally, a 'me too' post, but 
I couldn't help but chime in here.

>This is good practice, putting the mainline code into a ‘main’ 
>function, and keeping the ‘if __name__ == '__main__'’ block small 
>and obvious.
>
>What I prefer to do is to make the ‘main’ function accept the
>command-line arguments, and return the exit status for the program::
>
>def main(argv):
>exit_status = EXIT_STATUS_SUCCESS
>try:
>parse_command_line(argv)
>setup_program()
>run_program()
>except SystemExit as exc:
>exit_status = exc.code
>except Exception as exc:
>logging.exception(exc)
>exit_status = EXIT_STATUS_ERROR
>
>return exit_status
>
>if __name__ == '__main__':
>exit_status = main(sys.argv)
>sys.exit(exit_status)
>
>That way, the ‘main’ function is testable like any other function: 
>specify the command line arguments, and receive the exit status. 
>But the rest of the code doesn't need to know that's happening.

This is only a riff or a variant of what Ben has written.  Here's what I like
to write:

  def run(argv):
  if program_runs_smoothly:
  return os.EX_OK
  else:
  # -- call logging, report to STDERR, or just raise an Exception
  return SOMETHING_ELSE

  def main():
  sys.exit(run(sys.argv[1:]))
  
  if __name__ == '__main__':
  main()

Why do I do this?

  * the Python program runs from CLI because [if __name__ == '__main__']
  * I can use main() as an entry point with setuptools
  * my unit testing code can pass any argv it wants to the function run()
  * the run() function never calls sys.exit(), so my tests can see what WOULD
have been the process exit code

The only change from what Ben suggests is that, once I found os.EX_OK, I just
kept on using it, instead of difining my own EXIT_SUCCESS in every program.

Clearly, in my above example the contents of the run() function look strange.
Usually it has more different kinds of stuff in it.

Anyway, best of luck!

-Martin

-- 
Martin A. Brown
http://linux-ip.net/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Ben Finney
Ganesh Pal  writes:

> 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 .

No, but you can replace::

sys.exit(1)

with::

raise SystemExit(1)

As you know from reading the ‘sys.exit’ documentation
https://docs.python.org/3/library/sys.html#sys.exit>, ‘sys.exit’ is
implemented by performing ‘raise SystemExit(exit_status)’. So those do
virtually the same thing.

> ==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()

This is good practice, putting the mainline code into a ‘main’ function,
and keeping the ‘if __name__ == '__main__'’ block small and obvious.

What I prefer to do is to make the ‘main’ function accept the
command-line arguments, and return the exit status for the program::

def main(argv):
exit_status = EXIT_STATUS_SUCCESS
try:
parse_command_line(argv)
setup_program()
run_program()
except SystemExit as exc:
exit_status = exc.code
except Exception as exc:
logging.exception(exc)
exit_status = EXIT_STATUS_ERROR

return exit_status

if __name__ == '__main__':
exit_status = main(sys.argv)
sys.exit(exit_status)

That way, the ‘main’ function is testable like any other function:
specify the command line arguments, and receive the exit status. But the
rest of the code doesn't need to know that's happening.

-- 
 \  “Programs must be written for people to read, and only |
  `\incidentally for machines to execute.” —Abelson & Sussman, |
_o__)  _Structure and Interpretation of Computer Programs_ |
Ben Finney

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Random832
On Tue, Apr 12, 2016, at 10:12, Ganesh Pal wrote:
> >
> >
> > No; raise SystemExit is equivalent to sys.exit(0); you would need raise
> > SystemExit(1) to return 1.
> >
> 
> Thanks will replace SystemExit with SystemExit(1) .
> 
> 
> 
> > Why do you want to do this, though? What do you think you gain from it?
> >
> 
>  Iam trying to have a single exit point for many functions: example
>  create_logdir() , create_dataset() and unittest.main() will bubble out
>  an
> exception using raise

How is this not accomplished by using sys.exit(1) in the except block?


> I would want to terminate the program when this happens .
> 
> Do you see any problem if  *raise *SystemExit(1) is used in the except
> block ?

I still don't understand what you think you gain from this.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Ganesh Pal
>
>
> No; raise SystemExit is equivalent to sys.exit(0); you would need raise
> SystemExit(1) to return 1.
>

Thanks will replace SystemExit with SystemExit(1) .



> Why do you want to do this, though? What do you think you gain from it?
>

 Iam trying to have a single exit point for many functions: example
 create_logdir() , create_dataset() and unittest.main() will bubble out an
exception using raise





I would want to terminate the program when this happens .



Do you see any problem if  *raise *SystemExit(1) is used in the except block ?



 *def *main():


*try*:

create_logdir()

create_dataset()

unittest.main()

*except *Exception *as *e:

logging.exception(e)

*raise *SystemExit(1)





I see the below error only on pdb so thinking whats wrong in the above code
?



“*Exception AttributeError: "'NoneType' object has no attribute 'path'" in
 ignored “ *





(Pdb) n

SystemExit: SystemExit()

> /var/crash/local_qa/bin/corrupt_test.py(253)()

-> main()

(Pdb) n

--Return--

> /var/crash/local_qa/bin/corrupt_test.py(253)()->None

-> main()

(Pdb) n

Exception AttributeError: "'NoneType' object has no attribute 'path'" in
 ignored
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Random832
On Tue, Apr 12, 2016, at 08:50, 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 .

No; raise SystemExit is equivalent to sys.exit(0); you would need raise
SystemExit(1) to return 1.

Why do you want to do this, though? What do you think you gain from it?
-- 
https://mail.python.org/mailman/listinfo/python-list


sys.exit(1) vs raise SystemExit vs raise

2016-04-12 Thread Ganesh Pal
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()


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'


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

 Regards,

Ganesh
-- 
https://mail.python.org/mailman/listinfo/python-list