2

Initially i thought to do something like:

#EXIT CODES
class ExitCode(object):
    (USERHOME_INVALID, \
    USERHOME_CANNOT_WRITE, \
    USERHOME_CANNOT_READ, \
    BASHRC_INVALID) = range(-1, -5, -1)

But than I've realized that I'll have to know exactly the total number of EXIT_CODES, so that I can pass it to the range() function. Let's suppose I'll have 87 (arbitrary) EXIT_CODES... I don't want to count to 87 (not that it's hard) but I am looking for a more elegant solution.

Any suggestions ?

EDIT: EXIT_CODE is a negative int that will be passed to sys.exit . Instead of writing the number I prefer to use some sort of constants (something like #defines or enums in C, or enums in Java).

1
  • 2
    Just a note - you don't need the backslashes in parentheses. It doesn't really matter, but they're superfluous, and not really "Pythonic". Commented Sep 16, 2010 at 23:09

5 Answers 5

2

Sounds like what you want is the Python equivalent of an enumeration in C# or other similar languages. How can I represent an 'Enum' in Python? provides several solutions, though they still require the number of items you have. EDIT: How can I represent an 'Enum' in Python? looks way better.

Or you could try something like this (probably not the best solution, though):

class _ExitCode:
    _exit_codes=["EXIT_CODE","EXIT_CODE_TWO"]
    def __getattr__(self, name):
        if name in _ExitCode._exit_codes:
            return -(_ExitCode._exit_codes.index(name)+1)
        raise AttributeError("Exit code %s not found" % name)

ExitCode=_ExitCode()
print ExitCode.EXIT_CODE #-1
Sign up to request clarification or add additional context in comments.

Comments

2

Maybe I don't understand the question, but why don't you simply make a dictionary of exit codes and implement the desired behaviour in a function?

EXIT_CODES = dict(SUCCESS=0,
                  USER_NAME_INVALID=-1,
                  OTHER_ERROR=-2)

def exit(code):
   try:
      return EXIT_CODES[code]  
   except KeyError:
      raise KeyError("exit code %s is not implemented" % code)

So you can use it like

# some computation goes here
return exit("SUCCESS")

And if you want to make "automatic" assignment of numbers (I don't recommend this) you can simply create a list of exit codes and return the negative of the index:

EXIT_CODES = ['SUCCESS', 'ERROR_1', 'ERROR_2']
return -EXIT_CODES.index('ERROR_1')
# will return -1

(for the last one, you can implement a function similar to the dictionary-based one)

1 Comment

The problem is with auto incremenation of the values contained by the dict. I don't want to write 0, -1, -2, ..., -87 manually and then realize i have to regroup them.
1

I must note that it's not at all certain a negative status makes sense for sys.exit(); at least on Linux, it will be interpreted as an unsigned 8-bit value (range 0-255). As for an enumerated type, it's possible to do something like:

class ExitStatus: pass
for code, name in enumerate("Success Failure CriticalFailure".split()):
    setattr(ExitStatus, name, code)

Resulting in something like:

>>> ExitStatus.__dict__
{'CriticalFailure': 2, 'Failure': 1, '__module__': '__main__',
'__doc__': None, 'Success': 0}

The predefined values in normal Unix systems are EXIT_FAILURE=1 and EXIT_SUCCESS=0.

Addendum: Considering the concern about IDE identification of identifiers, one could also do something like:

class EnumItem: pass
def adjustEnum(enum):
    value=0
    enumdict=enum.__dict__
    for k,v in enumdict.items():
        if isinstance(v,int):
            if v>=value:
                value=v+1
    for k,v in enumdict.items():
        if v is EnumItem:
            enumdict[k]=value
            value+=1

class ExitStatus:
    Success=0
    Failure=EnumItem
    CriticalFailure=EnumItem
adjustEnum(ExitStatus)

Second edit: Couldn't keep away. Here's a variant that assigns the values in the order you've written the names.

class EnumItem:
    serial=0
    def __init__(self):
        self.serial=self.__class__.serial
        self.__class__.serial+=1

def adjustEnum(enum):
    enumdict=enum.__dict__
    value=0
    unknowns={}
    for k,v in enumdict.items():
        if isinstance(v,int):
            if v>=value:
                value=v+1
        elif isinstance(v,EnumItem):
            unknowns[v.serial]=k
    for i,k in sorted(unknowns.items()):
        enumdict[k]=value
        value+=1
    return enum

@adjustEnum
class ExitStatus:
    Success=0
    Failure=EnumItem()
    CriticalFailure=EnumItem()

Obviously the growing complexity is inelegant, but it does work.

Comments

1

I guess I looked at this question earlier and didn't see it, but one obvious thing to do is use a dict.

def make_exit_codes(*exit_codes):
    return dict((name, -value - 1) for name, value in enumerate(exit_codes)) 

EXIT_CODES = make_exit_codes('USERHOME_INVALID', 'USERHOME_CANNOT_WRITE',
                             'USERHOME_CANNOT_READ', 'BASHRC_INVALID')

Comments

0

You can create variables (or class attributes) on-the-fly with Python. For example

ExitCodes = '''USERHOME_INVALID, USERHOME_CANNOT_WRITE,
               USERHOME_CANNOT_READ, BASHRC_INVALID'''

for i, s in enumerate(ExitCodes.split(','), 1):
    exec('%s = %d' % (s.strip(), -i))

print USERHOME_INVALID
print USERHOME_CANNOT_WRITE
print USERHOME_CANNOT_READ
print BASHRC_INVALID

sys.exit(USERHOME_INVALID)

>>> -1
>>> -2
>>> -3
>>> -4

5 Comments

Please don't use things like exec() too eagerly. You could probably do just as well using globals().__setitem__(s,-i).
this wouldn't have been worth a downvote if somebody else hadn't have upvoted it but using exec deserves to be at the bottom of the list here. l33tnerd's solution is much more elegant.
"A foolish consistency is the hobgoblins of little minds..." Which means, I believe, decide for yourself on a case-by-case basis.
I actually like this solution. The drawback is that the exec'ed variables aren't recognized by the IDE I am currently using (Eclipse&PyDev), as they are declared at runtime.
@Andrei Ciobanu. Never thought of that -- guess it would take a very smart Python-aware IDE to recognize identifiers created at runtime, and might not even be possible in some circumstances. However I suspect what you say would also be true for most of the answers currently posted. Thanks for pointing out another tradeoff to be considered.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.