pythonpython-2to3

Find all comparision between "bytes" and "str"


I am migrating one big project from Python 2 -> Python 3, the issue with comparison between "bytes" and "str" only found when the old code run into it and fail explicitly. If it falsely pass, i will not be aware. One example:

def read_var_startaddr(self, var_name):
#__get_var_name() will return bytes
if self.__get_var_name() == var_name:
    print("do something")        
return self.__get_startaddr() 

So i would like to fix this for the whole project, instead of waiting until something happens, there are twos things in my mind:

  1. Use Notepad++: Search the whole project with regular expression, and checking by eyes ... to make sure no unexpected replacement happen. Search with Notepad++
  2. I would like the create wrapper the basic operator "==" or "!=", with a purpose to auto convert and compare corresponding values.

My Question: With option 2, Is it possible to do wrap the basic operator, how to do it and what are the impacts it may cause? Is there better way?

Thanks a lot!


Solution

  • Perhaps give 2to3 a try first (a tag you selected I assume unassumingly). It's built in with Python 3, and might save you a lot of time.


    For number 2 specifically, you can overwrite the dunder method __eq__ in objects, and use that instead. Something like so:

    class Item:
        def __init__(self, item):
            if isinstance(item, bytes):
                self._item = item
            elif isinstance(item, str):
                self._item = bytes(item, 'utf-8')
            elif isinstance(item, int):
                self._item = bytes(str(item), 'utf-8')
            else:
                raise Exception("Item must be of type bytes, str, or int.")
    
        def __eq__(self, other):
            if isinstance(other, bytes):
                return self._item == other
            elif isinstance(other, str):
                return self._item.decode("utf-8") == other
            elif isinstance(other, int):
                if self._item.isdigit():
                    return int(self._item) == other
                else:
                    raise Exception("Cannot compare non-int to int.")
    

    Then all of the following would work:

    item = Item("hello")
    
    item == "hello"  # True
    item == b"hello" # True
    
    item = Item(100)
    
    item == 100 # True
    item == "100" # True
    item == b"100" # True
    

    Do note that all objects Item will now be comparable with respect to the new __eq__ we wrote. If you are wondering "is there a way to modify ALL == comparison signs", the answer is... technically yes, but I promise you it is not worth it. You would have to deal with the ast module and create some very confusing code.


    You could also more simply create a function compare_str_bytes() that uses some of the code above to compare bytes and strings accordingly.