Escape both bytes and unicode strings for "ids" in Metafunc.parametrize
This commit is contained in:
		
							parent
							
								
									ceacc12b52
								
							
						
					
					
						commit
						4405dd0ffe
					
				| 
						 | 
					@ -23,7 +23,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Changes**
 | 
					**Changes**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*
 | 
					* Fix (`#1351 <https://github.com/pytest-dev/pytest/issues/1351>`_):
 | 
				
			||||||
 | 
					  explicitly passed parametrize ids do not get escaped to ascii.
 | 
				
			||||||
 | 
					  Thanks `@ceridwen`_ for the PR.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*
 | 
					*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1025,9 +1025,12 @@ class Metafunc(FuncargnamesCompatAttr):
 | 
				
			||||||
        if callable(ids):
 | 
					        if callable(ids):
 | 
				
			||||||
            idfn = ids
 | 
					            idfn = ids
 | 
				
			||||||
            ids = None
 | 
					            ids = None
 | 
				
			||||||
        if ids and len(ids) != len(argvalues):
 | 
					        if ids:
 | 
				
			||||||
 | 
					            if len(ids) != len(argvalues):
 | 
				
			||||||
                raise ValueError('%d tests specified with %d ids' %(
 | 
					                raise ValueError('%d tests specified with %d ids' %(
 | 
				
			||||||
                    len(argvalues), len(ids)))
 | 
					                    len(argvalues), len(ids)))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                ids = [_escape_strings(i) for i in ids]
 | 
				
			||||||
        if not ids:
 | 
					        if not ids:
 | 
				
			||||||
            ids = idmaker(argnames, argvalues, idfn)
 | 
					            ids = idmaker(argnames, argvalues, idfn)
 | 
				
			||||||
        newcalls = []
 | 
					        newcalls = []
 | 
				
			||||||
| 
						 | 
					@ -1078,21 +1081,29 @@ class Metafunc(FuncargnamesCompatAttr):
 | 
				
			||||||
        self._calls.append(cs)
 | 
					        self._calls.append(cs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if _PY3:
 | 
					if _PY3:
 | 
				
			||||||
    import codecs
 | 
					    import codecs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _escape_bytes(val):
 | 
					    def _escape_strings(val):
 | 
				
			||||||
        """
 | 
					        """If val is pure ascii, returns it as a str().  Otherwise, escapes
 | 
				
			||||||
        If val is pure ascii, returns it as a str(), otherwise escapes
 | 
					        bytes objects into a sequence of escaped bytes:
 | 
				
			||||||
        into a sequence of escaped bytes:
 | 
					
 | 
				
			||||||
        b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
 | 
					        b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        and escapes unicode objects into a sequence of escaped unicode
 | 
				
			||||||
 | 
					        ids, e.g.:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        '4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        note:
 | 
					        note:
 | 
				
			||||||
           the obvious "v.decode('unicode-escape')" will return
 | 
					           the obvious "v.decode('unicode-escape')" will return
 | 
				
			||||||
           valid utf-8 unicode if it finds them in the string, but we
 | 
					           valid utf-8 unicode if it finds them in bytes, but we
 | 
				
			||||||
           want to return escaped bytes for any byte, even if they match
 | 
					           want to return escaped bytes for any byte, even if they match
 | 
				
			||||||
           a utf-8 string.
 | 
					           a utf-8 string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        if isinstance(val, bytes):
 | 
				
			||||||
            if val:
 | 
					            if val:
 | 
				
			||||||
                # source: http://goo.gl/bGsnwC
 | 
					                # source: http://goo.gl/bGsnwC
 | 
				
			||||||
                encoded_bytes, _ = codecs.escape_encode(val)
 | 
					                encoded_bytes, _ = codecs.escape_encode(val)
 | 
				
			||||||
| 
						 | 
					@ -1101,15 +1112,24 @@ if _PY3:
 | 
				
			||||||
                # empty bytes crashes codecs.escape_encode (#1087)
 | 
					                # empty bytes crashes codecs.escape_encode (#1087)
 | 
				
			||||||
                return ''
 | 
					                return ''
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
    def _escape_bytes(val):
 | 
					            return val.encode('unicode_escape').decode('ascii')
 | 
				
			||||||
        """
 | 
					else:
 | 
				
			||||||
        In py2 bytes and str are the same type, so return it unchanged if it
 | 
					    def _escape_strings(val):
 | 
				
			||||||
        is a full ascii string, otherwise escape it into its binary form.
 | 
					        """In py2 bytes and str are the same type, so return if it's a bytes
 | 
				
			||||||
 | 
					        object, return it unchanged if it is a full ascii string,
 | 
				
			||||||
 | 
					        otherwise escape it into its binary form.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If it's a unicode string, change the unicode characters into
 | 
				
			||||||
 | 
					        unicode escapes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        if isinstance(val, bytes):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                return val.decode('ascii')
 | 
					                return val.decode('ascii')
 | 
				
			||||||
            except UnicodeDecodeError:
 | 
					            except UnicodeDecodeError:
 | 
				
			||||||
                return val.encode('string-escape')
 | 
					                return val.encode('string-escape')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return val.encode('unicode-escape')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _idval(val, argname, idx, idfn):
 | 
					def _idval(val, argname, idx, idfn):
 | 
				
			||||||
| 
						 | 
					@ -1117,28 +1137,20 @@ def _idval(val, argname, idx, idfn):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            s = idfn(val)
 | 
					            s = idfn(val)
 | 
				
			||||||
            if s:
 | 
					            if s:
 | 
				
			||||||
                return s
 | 
					                return _escape_strings(s)
 | 
				
			||||||
        except Exception:
 | 
					        except Exception:
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if isinstance(val, bytes):
 | 
					    if isinstance(val, bytes) or (_PY2 and isinstance(val, unicode)):
 | 
				
			||||||
        return _escape_bytes(val)
 | 
					        return _escape_strings(val)
 | 
				
			||||||
    elif isinstance(val, (float, int, str, bool, NoneType)):
 | 
					    elif isinstance(val, (float, int, str, bool, NoneType)):
 | 
				
			||||||
        return str(val)
 | 
					        return str(val)
 | 
				
			||||||
    elif isinstance(val, REGEX_TYPE):
 | 
					    elif isinstance(val, REGEX_TYPE):
 | 
				
			||||||
        return val.pattern
 | 
					        return _escape_strings(val.pattern)
 | 
				
			||||||
    elif enum is not None and isinstance(val, enum.Enum):
 | 
					    elif enum is not None and isinstance(val, enum.Enum):
 | 
				
			||||||
        return str(val)
 | 
					        return str(val)
 | 
				
			||||||
    elif isclass(val) and hasattr(val, '__name__'):
 | 
					    elif isclass(val) and hasattr(val, '__name__'):
 | 
				
			||||||
        return val.__name__
 | 
					        return val.__name__
 | 
				
			||||||
    elif _PY2 and isinstance(val, unicode):
 | 
					 | 
				
			||||||
        # special case for python 2: if a unicode string is
 | 
					 | 
				
			||||||
        # convertible to ascii, return it as an str() object instead
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            return str(val)
 | 
					 | 
				
			||||||
        except UnicodeError:
 | 
					 | 
				
			||||||
            # fallthrough
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
    return str(argname)+str(idx)
 | 
					    return str(argname)+str(idx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _idvalset(idx, valset, argnames, idfn):
 | 
					def _idvalset(idx, valset, argnames, idfn):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue