1import importlib 2import typing 3 4 5class ImportFromStringError(Exception): 6 pass 7 8 9def import_from_string(import_str: str) -> typing.Any: 10 module_str, _, attrs_str = import_str.partition(":") 11 if not module_str or not attrs_str: 12 message = ( 13 'Import string "{import_str}" must be in format "<module>:<attribute>".' 14 ) 15 raise ImportFromStringError(message.format(import_str=import_str)) 16 17 try: 18 module = importlib.import_module(module_str) 19 except ImportError as exc: 20 if exc.name != module_str: 21 raise exc from None 22 message = 'Could not import module "{module_str}".' 23 raise ImportFromStringError(message.format(module_str=module_str)) 24 25 instance = module 26 try: 27 for attr_str in attrs_str.split("."): 28 instance = getattr(instance, attr_str) 29 except AttributeError as exc: 30 message = 'Attribute "{attrs_str}" not found in module "{module_str}".' 31 raise ImportFromStringError( 32 message.format(attrs_str=attrs_str, module_str=module_str) 33 ) 34 35 return instance 36