1import functools 2import os 3import pathlib 4import types 5import warnings 6 7from typing import Union, Iterable, ContextManager, BinaryIO, TextIO, Any 8 9from . import _common 10 11Package = Union[types.ModuleType, str] 12Resource = str 13 14 15def deprecated(func): 16 @functools.wraps(func) 17 def wrapper(*args, **kwargs): 18 warnings.warn( 19 f"{func.__name__} is deprecated. Use files() instead. " 20 "Refer to https://importlib-resources.readthedocs.io" 21 "/en/latest/using.html#migrating-from-legacy for migration advice.", 22 DeprecationWarning, 23 stacklevel=2, 24 ) 25 return func(*args, **kwargs) 26 27 return wrapper 28 29 30def normalize_path(path): 31 # type: (Any) -> str 32 """Normalize a path by ensuring it is a string. 33 34 If the resulting string contains path separators, an exception is raised. 35 """ 36 str_path = str(path) 37 parent, file_name = os.path.split(str_path) 38 if parent: 39 raise ValueError(f'{path!r} must be only a file name') 40 return file_name 41 42 43@deprecated 44def open_binary(package: Package, resource: Resource) -> BinaryIO: 45 """Return a file-like object opened for binary reading of the resource.""" 46 return (_common.files(package) / normalize_path(resource)).open('rb') 47 48 49@deprecated 50def read_binary(package: Package, resource: Resource) -> bytes: 51 """Return the binary contents of the resource.""" 52 return (_common.files(package) / normalize_path(resource)).read_bytes() 53 54 55@deprecated 56def open_text( 57 package: Package, 58 resource: Resource, 59 encoding: str = 'utf-8', 60 errors: str = 'strict', 61) -> TextIO: 62 """Return a file-like object opened for text reading of the resource.""" 63 return (_common.files(package) / normalize_path(resource)).open( 64 'r', encoding=encoding, errors=errors 65 ) 66 67 68@deprecated 69def read_text( 70 package: Package, 71 resource: Resource, 72 encoding: str = 'utf-8', 73 errors: str = 'strict', 74) -> str: 75 """Return the decoded string of the resource. 76 77 The decoding-related arguments have the same semantics as those of 78 bytes.decode(). 79 """ 80 with open_text(package, resource, encoding, errors) as fp: 81 return fp.read() 82 83 84@deprecated 85def contents(package: Package) -> Iterable[str]: 86 """Return an iterable of entries in `package`. 87 88 Note that not all entries are resources. Specifically, directories are 89 not considered resources. Use `is_resource()` on each entry returned here 90 to check if it is a resource or not. 91 """ 92 return [path.name for path in _common.files(package).iterdir()] 93 94 95@deprecated 96def is_resource(package: Package, name: str) -> bool: 97 """True if `name` is a resource inside `package`. 98 99 Directories are *not* resources. 100 """ 101 resource = normalize_path(name) 102 return any( 103 traversable.name == resource and traversable.is_file() 104 for traversable in _common.files(package).iterdir() 105 ) 106 107 108@deprecated 109def path( 110 package: Package, 111 resource: Resource, 112) -> ContextManager[pathlib.Path]: 113 """A context manager providing a file path object to the resource. 114 115 If the resource does not already exist on its own on the file system, 116 a temporary file will be created. If the file was created, the file 117 will be deleted upon exiting the context manager (no exception is 118 raised if the file was deleted prior to the context manager 119 exiting). 120 """ 121 return _common.as_file(_common.files(package) / normalize_path(resource)) 122