API Documentation¶
McsArgs¶
-
class
py_meta_utils.McsArgs(mcs: type, name: str, bases: Tuple[Type[object], ...], clsdict: Dict[str, Any])[source]¶ Data holder for the parameters to
type.__new__():class Metaclass(type): def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) # do stuff return super().__new__(*mcs_args) # or in short-hand: class Metaclass(type): def __new__(mcs, *args): mcs_args = McsArgs(mcs, *args) # do stuff return super().__new__(*mcs_args)
-
getattr(name, default: Any = <py_meta_utils._missing object>)[source]¶ Convenience method equivalent to
deep_getattr(mcs_args.clsdict, mcs_args.bases, 'attr_name'[, default])
-
module¶ Returns the module of the class-under-construction, or
None.
-
qualname¶ Returns the fully qualified name of the class-under-construction, if possible, otherwise just the class name.
-
Meta¶ Returns the class
Metafrom the class-under-construction.Raises
KeyErrorif it’s not present.
-
is_abstract¶ Whether or not the class-under-construction was declared as abstract (NOTE: this property is usable even before the
MetaOptionsFactoryhas run)
-
deep_getattr¶
-
py_meta_utils.deep_getattr(clsdict: Dict[str, Any], bases: Tuple[Type[object], ...], name: str, default: Any = <py_meta_utils._missing object>) → Any[source]¶ Acts just like
getattrwould on a constructed class object, except this operates on the pre-construction class dictionary and base classes. In other words, first we look for the attribute in the class dictionary, and then we search all the base classes (in method resolution order), finally returning the default value if the attribute was not found in any of the class dictionary or base classes (or it raisesAttributeErrorif no default was given).
MetaOption¶
-
class
py_meta_utils.MetaOption(name: str, default: Any = None, inherit: bool = False)[source]¶ Base class for custom meta options.
-
name= None¶ The attribute name of the option on class
Metaobjects.
-
default= None¶ The default value for this meta option.
-
inherit= None¶ Whether or not this option’s value should be inherited from the class
Metaof any base classes.
-
get_value(Meta: Type[object], base_classes_meta, mcs_args: py_meta_utils.McsArgs) → Any[source]¶ Returns the value for
self.namegiven the class-under-construction’s classMeta. If it’s not found there, andself.inherit == Trueand there is a base class that has a classMeta, use that value, otherwiseself.default.Parameters: - Meta – the class
Meta(if any) from the class-under-construction (NOTE: this will be anobjectorNone, NOT an instance ofMetaOptionsFactory) - base_classes_meta – the
MetaOptionsFactoryinstance (if any) from the base class of the class-under-construction - mcs_args – the
McsArgsfor the class-under-construction
- Meta – the class
-
AbstractMetaOption¶
-
class
py_meta_utils.AbstractMetaOption[source]¶ A meta option that allows designating a class as abstract, using either:
class SomeAbstractBase(metaclass=MetaclassWithAnOptionsFactory): __abstract__ = True # or class SomeAbstractBase(metaclass=MetaclassWithAnOptionsFactory): class Meta: abstract = True
In the latter case, we make sure to set the
__abstract__class attribute for backwards compatibility with libraries that do not understandMetaoptions.-
name = 'abstract'
The attribute name on class
Metaobjects isabstract.-
default = False
The default value is
False.-
inherit = False
We do not inherit this value from the class
Metaof base classes.-
MetaOptionsFactory¶
-
class
py_meta_utils.MetaOptionsFactory[source]¶ Base class for meta options factory classes. Subclasses should either set
_optionsto a list ofMetaOptionsubclasses (or instances):class MyMetaOptionsFactory(MetaOptionsFactory): _options = [AbstractMetaOption]
Or override
_get_meta_options()to return a list ofMetaOptioninstances:class MyMetaOptionsFactory(MetaOptionsFactory): def _get_meta_options(self): return [AbstractMetaOption()]
IMPORTANT: If you add any attributes and/or methods to your factory subclass, they must be protected (ie, prefixed with an
_character).-
_options= []¶ A list of
MetaOptionsubclasses (or instances) that this factory supports.
-
_get_meta_options() → List[py_meta_utils.MetaOption][source]¶ Returns a list of
MetaOptioninstances that this factory supports.
-
_contribute_to_class(mcs_args: py_meta_utils.McsArgs)[source]¶ Where the magic happens. Takes one parameter, the
McsArgsof the class-under-construction, and processes the declaredclass Metafrom it (if any). We fill ourself with the declared meta options’ name/value pairs, give the declared meta options a chance to also contribute to the class-under- construction, and finally replace the class-under-construction’sclass Metawith this populated factory instance (akaself).
-
_fill_from_meta(Meta: Type[object], base_classes_meta, mcs_args: py_meta_utils.McsArgs)[source]¶ Iterate over our supported meta options, and set attributes on the factory instance (self) for each meta option’s name/value. Raises
TypeErrorif we discover any unsupported meta options on the class-under-construction’sclass Meta.
-
process_factory_meta_options¶
-
py_meta_utils.process_factory_meta_options(mcs_args: py_meta_utils.McsArgs, default_factory_class: Type[py_meta_utils.MetaOptionsFactory] = <class 'py_meta_utils.MetaOptionsFactory'>, factory_attr_name: str = '_meta_options_factory_class') → py_meta_utils.MetaOptionsFactory[source]¶ Main entry point for consumer metaclasses. Usage:
from py_meta_utils import (AbstractMetaOption, McsArgs, MetaOptionsFactory, process_factory_meta_options) class YourMetaOptionsFactory(MetaOptionsFactory): _options = [AbstractMetaOption] class YourMetaclass(type): def __new__(mcs, name, bases, clsdict): mcs_args = McsArgs(mcs, name, bases, clsdict) # process_factory_meta_options must come *before* super().__new__() process_factory_meta_options(mcs_args, YourMetaOptionsFactory) return super().__new__(*mcs_args) class YourClass(metaclass=YourMetaclass): pass
Subclasses of
YourClassmay set their_meta_options_factory_classattribute to a subclass ofYourMetaOptionsFactoryto customize their own supported meta options:from py_meta_utils import MetaOption class FooMetaOption(MetaOption): def __init__(self): super().__init__(name='foo', default=None, inherit=True) class FooMetaOptionsFactory(YourMetaOptionsFactory): _options = YourMetaOptionsFactory._options + [ FooMetaOption, ] class FooClass(YourClass): _meta_options_factory_class = FooMetaOptionsFactory class Meta: foo = 'bar'
Parameters: - mcs_args – The
McsArgsfor the class-under-construction - default_factory_class – The default MetaOptionsFactory class to use, if
the
factory_attr_nameattribute is not set on the class-under-construction - factory_attr_name – The attribute name to look for an overridden factory meta options class on the class-under-construction
Returns: The populated instance of the factory class
- mcs_args – The
Utility Classes¶
EnsureProtectedMembers¶
-
class
py_meta_utils.EnsureProtectedMembers(name, bases, clsdict)[source]¶ Metaclass to ensure that all members (attributes and method names) of consumer classes are protected (ie, prefixed with an
_).Consumer classes may have an _allowed_properties class attribute set to a list of allowed public properties.
Raises
NameErrorif any public members not in cls._allowed_properties are found.
Singleton¶
-
class
py_meta_utils.Singleton[source]¶ A metaclass that makes a consumer class a singleton:
from py_meta_utils import Singleton class Foo(metaclass=Singleton): pass foo = Foo() assert foo == Foo() == Foo() # True
Note that if you subclass a singleton, then you must inform the base class:
Foo.set_singleton_class(YourFooSubclass)
This way, calling
Foo()will still return the same instance ofYourFooSubclassas if callingYourFooSubclass()itself:foo = Foo() sub = YourFooSubclass() assert foo == sub == Foo() == YourFooSubclass()
OptionalClass¶
-
class
py_meta_utils.OptionalClass(*args, **kwargs)[source]¶ Use this as a generic base class if you have classes that depend on an optional package:
try: from optional_dependency import SomeClass except ImportError: from py_meta_utils import OptionalClass as SomeClass class Optional(SomeClass): pass
OptionalMetaclass¶
-
class
py_meta_utils.OptionalMetaclass[source]¶ Use this as a generic base metaclass if you need to subclass a metaclass from an optional package:
try: from optional_dependency import SomeMetaclass except ImportError: from py_meta_utils import OptionalMetaclass as SomeMetaclass class Optional(metaclass=SomeMetaclass): pass