41 lines
1.5 KiB
Python
41 lines
1.5 KiB
Python
# Copyright (c) 2018, Ansible Project
|
|
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
__metaclass__ = type
|
|
|
|
|
|
"""
|
|
Modules in _utils are waiting to find a better home. If you need to use them, be prepared for them
|
|
to move to a different location in the future.
|
|
"""
|
|
|
|
|
|
def get_all_subclasses(cls):
|
|
'''
|
|
Recursively search and find all subclasses of a given class
|
|
|
|
:arg cls: A python class
|
|
:rtype: set
|
|
:returns: The set of python classes which are the subclasses of `cls`.
|
|
|
|
In python, you can use a class's :py:meth:`__subclasses__` method to determine what subclasses
|
|
of a class exist. However, `__subclasses__` only goes one level deep. This function searches
|
|
each child class's `__subclasses__` method to find all of the descendent classes. It then
|
|
returns an iterable of the descendent classes.
|
|
'''
|
|
# Retrieve direct subclasses
|
|
subclasses = set(cls.__subclasses__())
|
|
to_visit = list(subclasses)
|
|
# Then visit all subclasses
|
|
while to_visit:
|
|
for sc in to_visit:
|
|
# The current class is now visited, so remove it from list
|
|
to_visit.remove(sc)
|
|
# Appending all subclasses to visit and keep a reference of available class
|
|
for ssc in sc.__subclasses__():
|
|
if ssc not in subclasses:
|
|
to_visit.append(ssc)
|
|
subclasses.add(ssc)
|
|
return subclasses
|