def safe_filename(filename, os_type='unix', no_control=True, ascii_only=True,
                  case=None, encoding='utf8', max_length=None):
    '''Return a safe filename or path part.

    Args:
        filename (str): The filename or path component.
        os_type (str): If ``unix``, escape the slash. If ``windows``, escape
            extra Windows characters.
        no_control (bool): If True, escape control characters.
        ascii_only (bool): If True, escape non-ASCII characters.
        case (str): If ``lower``, lowercase the string. If ``upper``, uppercase
            the string.
        encoding (str): The character encoding.
        max_length (int): The maximum length of the filename.

    This function assumes that `filename` has not already been percent-encoded.

    Returns:
        str
    '''
    assert isinstance(filename, str), \
        'Expect str. Got {}.'.format(type(filename))

    if filename in ('.', os.curdir):
        new_filename = '%2E'
    elif filename in ('.', os.pardir):
        new_filename = '%2E%2E'
    else:
        unix = os_type == 'unix'
        windows = os_type == 'windows'
        encoder_args = (unix, no_control, windows, ascii_only)

        if encoder_args not in _encoder_cache:
            _encoder_cache[encoder_args] = PercentEncoder(
                unix=unix, control=no_control, windows=windows,
                ascii_=ascii_only
            )

        encoder = _encoder_cache[encoder_args]
        encoded_filename = filename.encode(encoding)
        new_filename = encoder.quote(encoded_filename).decode(encoding)

    if os_type == 'windows':
        if new_filename[-1] in ' .':
            new_filename = '{0}{1:02X}'.format(
                new_filename[:-1], new_filename[-1]
            )

    if max_length and len(new_filename) > max_length:
        hash_obj = hashlib.sha1(new_filename.encode(encoding))
        new_length = max(0, max_length - 8)
        new_filename = '{0}{1}'.format(
            new_filename[:new_length], hash_obj.hexdigest()[:8]
        )

    if case == 'lower':
        new_filename = new_filename.lower()
    elif case == 'upper':
        new_filename = new_filename.upper()

    return new_filename
def safe_filename ( filename , os_type = 'unix' , no_control = True , ascii_only = True , case = None , encoding = 'utf8' , max_length = None ) : assert isinstance ( filename , str ) , 'Expect str. Got {}.' . format ( type ( filename ) ) if filename in ( '.' , os . curdir ) : new_filename = '%2E' elif filename in ( '.' , os . pardir ) : new_filename = '%2E%2E' else : unix = os_type == 'unix' windows = os_type == 'windows' encoder_args = ( unix , no_control , windows , ascii_only ) if encoder_args not in _encoder_cache : _encoder_cache [ encoder_args ] = PercentEncoder ( unix = unix , control = no_control , windows = windows , ascii_ = ascii_only ) encoder = _encoder_cache [ encoder_args ] encoded_filename = filename . encode ( encoding ) new_filename = encoder . quote ( encoded_filename ) . decode ( encoding ) if os_type == 'windows' : if new_filename [ - 1 ] in ' .' : new_filename = '{0}{1:02X}' . format ( new_filename [ : - 1 ] , new_filename [ - 1 ] ) if max_length and len ( new_filename ) > max_length : hash_obj = hashlib . sha1 ( new_filename . encode ( encoding ) ) new_length = max ( 0 , max_length - 8 ) new_filename = '{0}{1}' . format ( new_filename [ : new_length ] , hash_obj . hexdigest ( ) [ : 8 ] ) if case == 'lower' : new_filename = new_filename . lower ( ) elif case == 'upper' : new_filename = new_filename . upper ( ) return new_filename
Return a safe filename or path part.

    Args:
        filename (str): The filename or path component.
        os_type (str): If ``unix``, escape the slash. If ``windows``, escape
            extra Windows characters.
        no_control (bool): If True, escape control characters.
        ascii_only (bool): If True, escape non-ASCII characters.
        case (str): If ``lower``, lowercase the string. If ``upper``, uppercase
            the string.
        encoding (str): The character encoding.
        max_length (int): The maximum length of the filename.

    This function assumes that `filename` has not already been percent-encoded.

    Returns:
        str