1

I'm wondering how could one create a program to detect the following cases in the code, when comparing a variable to hardcoded values, instead of using enumeration, dynamically?

class AccountType:
    BBAN = '000'
    IBAN = '001'
    UBAN = '002'
    LBAN = '003'

I would like the code to report (drop a warning into the log) in the following case:

payee_account_type = self.get_payee_account_type(rc)     # '001' for ex.
if payee_account_type in ('001', '002'):                 # Report on unsafe lookup
    print 'okay, but not sure about the codes, man'

To encourage people to use the following approach:

payee_account_type = self.get_payee_account_type(rc)
if payee_account_type in (AccountType.IBAN, AccountType.UBAN):
    print 'do this for sure'

Which is much safer.


It's not a problem to verify the == and != checks like below:

if payee_account_type == '001':
    print 'codes again'

By wrapping payee_account_type into a class, with the following __eq__ implemented:

class Variant:
    def __init__(self, value):
        self._value = value

    def get_value(self):
        return self._value

class AccountType:
    BBAN = Variant('000')
    IBAN = Variant('001')
    UBAN = Variant('002')
    LBAN = Variant('003')

class AccountTypeWrapper(object):
    def __init__(self, account_type):
        self._account_type = account_type

    def __eq__(self, other):
        if isinstance(other, Variant):
            # Safe usage
            return self._account_type == other.get_value()

        # The value is hardcoded
        log.warning('Unsafe comparison. Use proper enumeration object')
        return self._account_type == other

But what to do with tuple lookups?


I know, I could create a convention method wrapping the lookup, where the check can be done:

if IbanUtils.account_type_in(account_type, AccountType.IBAN, AccountType.UBAN):
    pass

class IbanUtils(object):
    def account_type_in(self, account_type, *types_to_check):
        for type in types_to_check:
            if not isinstance(type, Variant):
                log.warning('Unsafe usage')

            return account_type in types_to_check

But it's not an option for me, because I have a lot of legacy code I cannot touch, but still need to report on.

astronaut
  • 560
  • 1
  • 6
  • 18
  • 1
    There's no (non-fragile) way to detect that from within the running code. if the value passed in is `'001'`, you can't know whether it was a literal or a variable outside the function. You could do it if you make your `BBAN` values some string subclass, because then you could check for that subclass. – BrenBarn May 29 '14 at 06:56
  • @BrenBarn, please have a look at the edits – astronaut May 29 '14 at 07:08
  • 1
    Can you give an example of the behavior you're seeing that you want to change? Overriding `__eq__` should already handle the `blah in ('a', 'b')` case, because the elements in the tuple will be compared sequentially for equality. – BrenBarn May 29 '14 at 07:18
  • @BrenBarn, you're absolutely right! ``__eq__`` works for tuple lookups too. I think I came up with the answer myself, you just pointed it out to me. Thanks! – astronaut May 29 '14 at 07:23

0 Answers0