grim/pyscovery
Clone
Summary
Browse
Changes
Graph
Update the homepage for the new home
draft
default
tip
2020-04-27, Gary Kramlich
367b9e9dadad
Update the homepage for the new home
# pyscovery - A python plugin finder
# Copyright (C) 2013-2014 Gary Kramlich <grim@reaperworld.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
pyscovery is a Python plugin loader that will search for classes based from a
list of modules and optionally use the file system to recurse into packages.
This is different from pkg_resources and friends since it doesn't require you
to add every module that might have packages, it will discover it for you.
I wrote this because none of the existing solutions fit my need of being able
to logically group similar plugins in the filesystem.
"""
import
importlib
import
inspect
import
pkgutil
__version__
=
'1.3'
class
Loader
(
object
):
""" A pyscovery loader """
def
__init__
(
self
):
pass
def
find
(
self
,
cls
,
path
,
create
,
*
args
,
**
kwargs
):
"""Find all plugins that are subclasses of cls.
:param cls: The class whose subclasses to find.
:type cls: class
:param path: The path to look for packages in.
:type path: string
:param create: return instances rather than just return their class.
:type create: bool
:param args: Additional arguments to pass to each constructor. Ignored if
create is False.
:type args: arguments
:param kwargs: Additional keyword arguements to pass to each constructor.
Ignored if create is False.
:type kwargs: kwargs
:returns: Generator of subclasses of cls
"""
if
not
inspect
.
isclass
(
cls
):
raise
TypeError
(
'
{}
is not a class instance'
.
format
(
cls
))
cls_name
=
cls
.
__name__
for
_
,
name
,
_
in
pkgutil
.
walk_packages
(
path
):
mod
=
importlib
.
import_module
(
name
)
for
symbol_name
in
dir
(
mod
):
if
symbol_name
==
cls_name
:
continue
symbol
=
getattr
(
mod
,
symbol_name
,
None
)
if
not
inspect
.
isclass
(
symbol
):
continue
if
inspect
.
isabstract
(
symbol
):
continue
if
not
issubclass
(
symbol
,
cls
):
continue
if
create
:
yield
symbol
(
*
args
,
**
kwargs
)
else
:
yield
symbol
_DEFAULT_LOADER
=
Loader
()
def
find
(
cls
,
recurse
,
create
,
*
args
,
**
kwargs
):
"""Find all plugins that are subclasses of cls in the current search paths
:param cls: The class whose subclasses to find.
:type cls: class
:param recurse: Whether or not to recurse into packages.
:type recurse: bool
:param create: return instances rather than just return their class.
:type create: bool
:param args: Additional arguments to pass to each constructor. Ignored if
create is False.
:type args: arguments
:param kwargs: Additional keyword arguements to pass to each constructor.
Ignored if create is False.
:type kwargs: kwargs
:returns: Generator of subclasses of cls
"""
return
_DEFAULT_LOADER
.
find
(
cls
,
recurse
,
create
,
*
args
,
**
kwargs
)