Reputation: 11140
Consider the simplest possible python setup.py cmd
:
from distutils.core import Command, setup
class Foo(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
pass
setup(
cmdclass={'cmd': Foo}
)
It does precisely nothing.
But suppose something goes wrong while we're doing nothing, how should the command return a non-zero exit code to the user?
Return values seem to be ignored; the documentation says only:
All terminal output and filesystem interaction should be done by run().
which seems relevant without being particularly helpful.
Perhaps we should infer to exit
:
class Foo(Command):
# ...
def run(self):
exit(1)
This works, of course.
But it's not clear to me that it's the right thing to do: if the command is run as a part of a longer process, or it's overriding a built-in command, presumably nothing further will execute.
We could raise a relevant exception directly instead, assuming it might be more likely to be well-handled, but then there's a nasty traceback when we exit - what if we've already logged something nicer ourselves?
class Foo(Command):
# ...
def run(self):
print('Oh noes!', file=sys.stderr)
exit(1)
Is this safe to do; is there a better alternative?
Upvotes: 3
Views: 579
Reputation: 18938
While exit will defintely work, raising any of the distutils.errors
with the error message desired to halt execution is how distutils handle problems internally. For instance, if one wish to prevent editable (develop) installation method provided by setuptools, using only distutils
API, raising DistutilsError
can be achieve this.
from setuptools.command.develop import develop
from distutils.errors import DistutilsError
class fail_develop(develop):
def run(self):
raise DistutilsError('develop installation mode unsupported')
setup(
...
cmdclass={'develop': fail_develop},
)
Running that with the develop option may result in this:
running develop
error: develop installation mode unsupported
Execution will halt, as that is trapped and a SystemExit
will be raised (now if somehow the whole process is wrapped by some other Python libraries that trap all exceptions including SystemExit
or some other process expect a non-zero exit code, a traceback or other unexpected output will likely be produced). While on the surface this is not too different than raising SystemExit
(or calling sys.exit
) directly, there are prefixes that do get generated for errors such as DistutilsSetupError
that one might raise in a custom Distribution
class. So with all that said, calling sys.exit
is fine.
Upvotes: 1