• Kirill Smelkov's avatar
    X golang_str: Fix bstr/ustr __eq__ and friends to return NotImplemented wrt non-string types · a341f761
    Kirill Smelkov authored
    In 54c2a3cf (golang_str: Teach bstr/ustr to compare wrt any
    string with automatic coercion) I've added __eq__, __ne__, __lt__ etc
    methods to our strings, but __lt__ and other comparison to raise
    TypeError against any non-string type. My idea was to mimic user-visible
    py3 behaviour such as
    
        >>> "abc" > 1
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        TypeError: '>' not supported between instances of 'str' and 'int'
    
    However it turned out that the implementation was not exactly matching
    what Python is doing internally which lead to incorrect behaviour when
    bstr or ustr is compared wrt another type with its own __cmp__. In the
    general case for `a op b` Python first queries a.__op__(b) and
    b.__op'__(a) and sometimes other methods before going to .__cmp__. This
    relies on the methods to return NotImplemented instead of raising an
    exception and if a trial raises TypeError everything is stopped and that
    TypeError is returned to the caller.
    
    Jérome reports a real breakage due to this when bstr is compared wrt
    distutils.version.LooseVersion . LooseVersion is basically
    
        class LooseVersion(Version):
            def __cmp__ (self, other):
                if isinstance(other, StringType):
                    other = LooseVersion(other)
    
                return cmp(self.version, other.version)
    
    but due to my thinko on `LooseVersion < bstr` the control flow was not
    getting into that LooseVersion.__cmp__ because bstr.__gt__ was tried
    first and raised TypeError.
    
    -> Fix all comparison operations to return NotImplemented instead of
    raising TypeError and make sure in the tests that this behaviour exactly
    matches what native str type does.
    
    The fix is needed not only for py2 because added test_strings_cmp_wrt_distutils_LooseVersion
    was failing on py3 as well without the fix.
    
    /reported-by @jerome
    /reported-on nexedi/slapos!1575 (comment 206080)
    a341f761
_golang_str.pyx 101 KB