You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

manager.py 5.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. """
  2. Copyright (c) OpenMMLab. All rights reserved.
  3. """
  4. import inspect
  5. import threading
  6. import warnings
  7. from collections import OrderedDict
  8. from typing import Type, TypeVar
  9. _lock = threading.RLock()
  10. T = TypeVar("T")
  11. def _accquire_lock() -> None:
  12. """Acquire the module-level lock for serializing access to shared data.
  13. This should be released with _release_lock().
  14. """
  15. if _lock:
  16. _lock.acquire()
  17. def _release_lock() -> None:
  18. """Release the module-level lock acquired by calling _accquire_lock()."""
  19. if _lock:
  20. _lock.release()
  21. class ManagerMeta(type):
  22. """The metaclass for global accessible class.
  23. The subclasses inheriting from ``ManagerMeta`` will manage their
  24. own ``_instance_dict`` and root instances. The constructors of subclasses
  25. must contain the ``name`` argument.
  26. Examples:
  27. >>> class SubClass1(metaclass=ManagerMeta):
  28. >>> def __init__(self, *args, **kwargs):
  29. >>> pass
  30. AssertionError: <class '__main__.SubClass1'>.__init__ must have the
  31. name argument.
  32. >>> class SubClass2(metaclass=ManagerMeta):
  33. >>> def __init__(self, name):
  34. >>> pass
  35. >>> # valid format.
  36. """
  37. def __init__(cls, *args):
  38. cls._instance_dict = OrderedDict()
  39. params = inspect.getfullargspec(cls)
  40. params_names = params[0] if params[0] else []
  41. assert "name" in params_names, f"{cls} must have the `name` argument"
  42. super().__init__(*args)
  43. class ManagerMixin(metaclass=ManagerMeta):
  44. """``ManagerMixin`` is the base class for classes that have global access
  45. requirements.
  46. The subclasses inheriting from ``ManagerMixin`` can get their
  47. global instances.
  48. Examples:
  49. >>> class GlobalAccessible(ManagerMixin):
  50. >>> def __init__(self, name=''):
  51. >>> super().__init__(name)
  52. >>>
  53. >>> GlobalAccessible.get_instance('name')
  54. >>> instance_1 = GlobalAccessible.get_instance('name')
  55. >>> instance_2 = GlobalAccessible.get_instance('name')
  56. >>> assert id(instance_1) == id(instance_2)
  57. Args:
  58. name (str): Name of the instance. Defaults to ''.
  59. """
  60. def __init__(self, name: str = ""):
  61. assert isinstance(name, str) and name, "name argument must be an non-empty string."
  62. self._instance_name = name
  63. @classmethod
  64. def get_instance(cls: Type[T], name: str, **kwargs) -> T:
  65. """Get subclass instance by name if the name exists.
  66. If corresponding name instance has not been created, ``get_instance``
  67. will create an instance, otherwise ``get_instance`` will return the
  68. corresponding instance.
  69. Examples
  70. >>> instance1 = GlobalAccessible.get_instance('name1')
  71. >>> # Create name1 instance.
  72. >>> instance.instance_name
  73. name1
  74. >>> instance2 = GlobalAccessible.get_instance('name1')
  75. >>> # Get name1 instance.
  76. >>> assert id(instance1) == id(instance2)
  77. Args:
  78. name (str): Name of instance. Defaults to ''.
  79. Returns:
  80. object: Corresponding name instance, the latest instance, or root
  81. instance.
  82. """
  83. _accquire_lock()
  84. assert isinstance(name, str), f"type of name should be str, but got {type(cls)}"
  85. instance_dict = cls._instance_dict # type: ignore
  86. # Get the instance by name.
  87. if name not in instance_dict:
  88. instance = cls(name=name, **kwargs) # type: ignore
  89. instance_dict[name] = instance # type: ignore
  90. elif kwargs:
  91. warnings.warn(
  92. f"{cls} instance named of {name} has been created, "
  93. "the method `get_instance` should not accept any other "
  94. "arguments"
  95. )
  96. # Get latest instantiated instance or root instance.
  97. _release_lock()
  98. return instance_dict[name]
  99. @classmethod
  100. def get_current_instance(cls):
  101. """Get latest created instance.
  102. Before calling ``get_current_instance``, The subclass must have called
  103. ``get_instance(xxx)`` at least once.
  104. Examples
  105. >>> instance = GlobalAccessible.get_current_instance()
  106. AssertionError: At least one of name and current needs to be set
  107. >>> instance = GlobalAccessible.get_instance('name1')
  108. >>> instance.instance_name
  109. name1
  110. >>> instance = GlobalAccessible.get_current_instance()
  111. >>> instance.instance_name
  112. name1
  113. Returns:
  114. object: Latest created instance.
  115. """
  116. _accquire_lock()
  117. if not cls._instance_dict:
  118. raise RuntimeError(
  119. f"Before calling {cls.__name__}.get_current_instance(), you "
  120. "should call get_instance(name=xxx) at least once."
  121. )
  122. name = next(iter(reversed(cls._instance_dict)))
  123. _release_lock()
  124. return cls._instance_dict[name]
  125. @classmethod
  126. def check_instance_created(cls, name: str) -> bool:
  127. """Check whether the name corresponding instance exists.
  128. Args:
  129. name (str): Name of instance.
  130. Returns:
  131. bool: Whether the name corresponding instance exists.
  132. """
  133. return name in cls._instance_dict
  134. @property
  135. def instance_name(self) -> str:
  136. """Get the name of instance.
  137. Returns:
  138. str: Name of instance.
  139. """
  140. return self._instance_name

An efficient Python toolkit for Abductive Learning (ABL), a novel paradigm that integrates machine learning and logical reasoning in a unified framework.