diff options
Diffstat (limited to 'release/scripts/modules/bpy/path.py')
-rw-r--r-- | release/scripts/modules/bpy/path.py | 104 |
1 files changed, 69 insertions, 35 deletions
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py index 874efc2e131..d7c6101115d 100644 --- a/release/scripts/modules/bpy/path.py +++ b/release/scripts/modules/bpy/path.py @@ -43,10 +43,11 @@ __all__ = ( import bpy as _bpy import os as _os -from _bpy_path import (extensions_audio, - extensions_movie, - extensions_image, - ) +from _bpy_path import ( + extensions_audio, + extensions_movie, + extensions_image, + ) def _getattr_bytes(var, attr): @@ -60,7 +61,7 @@ def abspath(path, start=None, library=None): :arg start: Relative to this path, when not set the current filename is used. - :type start: string + :type start: string or bytes :arg library: The library this path is from. This is only included for convenience, when the library is not None its path replaces *start*. :type library: :class:`bpy.types.Library` @@ -89,9 +90,11 @@ def relpath(path, start=None): """ Returns the path relative to the current blend file using the "//" prefix. + :arg path: An absolute path. + :type path: string or bytes :arg start: Relative to this path, when not set the current filename is used. - :type start: string + :type start: string or bytes """ if isinstance(path, bytes): if not path.startswith(b"//"): @@ -111,11 +114,18 @@ def is_subdir(path, directory): """ Returns true if *path* in a subdirectory of *directory*. Both paths must be absolute. + + :arg path: An absolute path. + :type path: string or bytes """ from os.path import normpath, normcase path = normpath(normcase(path)) directory = normpath(normcase(directory)) - return path.startswith(directory) + if len(path) > len(directory): + if path.startswith(directory): + sep = ord(_os.sep) if isinstance(directory, bytes) else _os.sep + return (path[len(directory)] == sep) + return False def clean_name(name, replace="_"): @@ -124,26 +134,50 @@ def clean_name(name, replace="_"): may cause problems under various circumstances, such as writing to a file. All characters besides A-Z/a-z, 0-9 are replaced with "_" - or the replace argument if defined. + or the *replace* argument if defined. """ - bad_chars = ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" - "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d" - "\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c" - "\x2e\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x40\x5b\x5c\x5d\x5e\x60\x7b" - "\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a" - "\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99" - "\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8" - "\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6" - "\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5" - "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4" - "\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3" - "\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe") - - for ch in bad_chars: - name = name.replace(ch, replace) - return name + if replace != "_": + if len(replace) != 1 or ord(replace) > 255: + raise ValueError("Value must be a single ascii character") + + def maketrans_init(): + trans_cache = clean_name._trans_cache + trans = trans_cache.get(replace) + if trans is None: + bad_chars = ( + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2e, 0x2f, 0x3a, + 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x5b, 0x5c, + 0x5d, 0x5e, 0x60, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, + ) + trans = str.maketrans({char: replace for char in bad_chars}) + trans_cache[replace] = trans + return trans + + trans = maketrans_init() + return name.translate(trans) +clean_name._trans_cache = {} def _clean_utf8(name): @@ -221,7 +255,8 @@ def resolve_ncase(path): if _os.path.isdir(dirpath): try: files = _os.listdir(dirpath) - except PermissionError: # We might not have the permission to list dirpath... + except PermissionError: + # We might not have the permission to list dirpath... return path, False else: return path, False @@ -248,22 +283,21 @@ def ensure_ext(filepath, ext, case_sensitive=False): """ Return the path with the extension added if it is not already set. - :arg ext: The extension to check for. + :arg ext: The extension to check for, can be a compound extension. Should + start with a dot, such as '.blend' or '.tar.gz'. :type ext: string :arg case_sensitive: Check for matching case when comparing extensions. :type case_sensitive: bool """ - fn_base, fn_ext = _os.path.splitext(filepath) - if fn_base and fn_ext: - if ((case_sensitive and ext == fn_ext) or - (ext.lower() == fn_ext.lower())): + if case_sensitive: + if filepath.endswith(ext): return filepath - else: - return fn_base + ext - else: - return filepath + ext + if filepath[-len(ext):].lower().endswith(ext.lower()): + return filepath + + return filepath + ext def module_names(path, recursive=False): |