module_loading.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. #
  2. # Licensed to the Apache Software Foundation (ASF) under one
  3. # or more contributor license agreements. See the NOTICE file
  4. # distributed with this work for additional information
  5. # regarding copyright ownership. The ASF licenses this file
  6. # to you under the Apache License, Version 2.0 (the
  7. # "License"); you may not use this file except in compliance
  8. # with the License. You may obtain a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  12. # Unless required by applicable law or agreed to in writing,
  13. # software distributed under the License is distributed on an
  14. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. # KIND, either express or implied. See the License for the
  16. # specific language governing permissions and limitations
  17. # under the License.
  18. from __future__ import annotations
  19. import pkgutil
  20. from importlib import import_module
  21. from typing import TYPE_CHECKING, Callable
  22. if TYPE_CHECKING:
  23. from types import ModuleType
  24. def import_string(dotted_path: str):
  25. """
  26. Import a dotted module path and return the attribute/class designated by the last name in the path.
  27. Raise ImportError if the import failed.
  28. """
  29. try:
  30. module_path, class_name = dotted_path.rsplit(".", 1)
  31. except ValueError:
  32. raise ImportError(f"{dotted_path} doesn't look like a module path")
  33. module = import_module(module_path)
  34. try:
  35. return getattr(module, class_name)
  36. except AttributeError:
  37. raise ImportError(f'Module "{module_path}" does not define a "{class_name}" attribute/class')
  38. def qualname(o: object | Callable) -> str:
  39. """Convert an attribute/class/function to a string importable by ``import_string``."""
  40. if callable(o) and hasattr(o, "__module__") and hasattr(o, "__name__"):
  41. return f"{o.__module__}.{o.__name__}"
  42. cls = o
  43. if not isinstance(cls, type): # instance or class
  44. cls = type(cls)
  45. name = cls.__qualname__
  46. module = cls.__module__
  47. if module and module != "__builtin__":
  48. return f"{module}.{name}"
  49. return name
  50. def iter_namespace(ns: ModuleType):
  51. return pkgutil.iter_modules(ns.__path__, ns.__name__ + ".")