SettingsBase
This commit is contained in:
parent
040341021c
commit
1cdc722f46
@ -22,20 +22,41 @@ class ConfigurationError(Exception):
|
|||||||
|
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
|
|
||||||
class Module:
|
class SettingsBase:
|
||||||
output = None
|
"""
|
||||||
position = 0
|
Support class for providing a nice and flexible settings interface
|
||||||
|
|
||||||
|
Classes inherit from this class and define what settings they provide and
|
||||||
|
which are required.
|
||||||
|
|
||||||
|
The constructor is either passed a dictionary containing these settings, or
|
||||||
|
keyword arguments specifying the same.
|
||||||
|
|
||||||
|
Settings are stored as attributes of self
|
||||||
|
"""
|
||||||
|
|
||||||
settings = tuple() # Can also be a tuple of two-tuples (setting, docstring)
|
settings = tuple() # Can also be a tuple of two-tuples (setting, docstring)
|
||||||
|
"""settings should be tuple containing two types of elements:
|
||||||
|
* bare strings, which must be valid identifiers.
|
||||||
|
* two-tuples, the first element being a identifier (as above) and the second
|
||||||
|
a docstring for the particular setting"""
|
||||||
|
|
||||||
required = tuple()
|
required = tuple()
|
||||||
|
"""required can list settings which are required"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
if len(self.settings) and isinstance(self.settings[0], tuple):
|
def flatten_settings(settings):
|
||||||
self.settings, docstrings = zip(*self.settings)
|
return tuple((flatten_setting(setting) for setting in settings))
|
||||||
|
|
||||||
|
def flatten_setting(setting):
|
||||||
|
return setting[0] if isinstance(setting, tuple) else setting
|
||||||
|
|
||||||
|
self.settings = flatten_settings(self.settings)
|
||||||
|
|
||||||
required = set()
|
required = set()
|
||||||
self.required = set(self.required)
|
self.required = set(self.required)
|
||||||
|
|
||||||
if len(args) == 1 and not len(kwargs):
|
if len(args) == 1 and not kwargs:
|
||||||
# User can also pass in a dict for their settings
|
# User can also pass in a dict for their settings
|
||||||
# Note: you could do that anyway, with the ** syntax
|
# Note: you could do that anyway, with the ** syntax
|
||||||
# Note2: just for backwards compatibility
|
# Note2: just for backwards compatibility
|
||||||
@ -48,6 +69,7 @@ class Module:
|
|||||||
else:
|
else:
|
||||||
raise ConfigurationError(type(self).__name__, key=key)
|
raise ConfigurationError(type(self).__name__, key=key)
|
||||||
|
|
||||||
|
# Some nice set magic :-)
|
||||||
required &= set(self.required)
|
required &= set(self.required)
|
||||||
if len(required) != len(self.required):
|
if len(required) != len(self.required):
|
||||||
raise ConfigurationError(type(self).__name__, missing=self.required-required)
|
raise ConfigurationError(type(self).__name__, missing=self.required-required)
|
||||||
@ -59,6 +81,10 @@ class Module:
|
|||||||
|
|
||||||
In case you don't want to type that super()…blabla :-)"""
|
In case you don't want to type that super()…blabla :-)"""
|
||||||
|
|
||||||
|
class Module(SettingsBase):
|
||||||
|
output = None
|
||||||
|
position = 0
|
||||||
|
|
||||||
def registered(self, status_handler):
|
def registered(self, status_handler):
|
||||||
"""Called when this module is registered with a status handler"""
|
"""Called when this module is registered with a status handler"""
|
||||||
|
|
||||||
@ -121,7 +147,7 @@ class StandaloneIO(IOHandler):
|
|||||||
"""
|
"""
|
||||||
I/O handler for standalone usage of i3pystatus (w/o i3status)
|
I/O handler for standalone usage of i3pystatus (w/o i3status)
|
||||||
|
|
||||||
writing as usual, reading will always return a empty JSON array,
|
Writing works as usual, but reading will always return a empty JSON array,
|
||||||
and the i3bar protocol header
|
and the i3bar protocol header
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -132,6 +158,7 @@ class StandaloneIO(IOHandler):
|
|||||||
"[]",
|
"[]",
|
||||||
",[]",
|
",[]",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, interval=1):
|
def __init__(self, interval=1):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
@ -164,9 +191,11 @@ class JSONIO:
|
|||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def parse_line(self, line):
|
def parse_line(self, line):
|
||||||
"""Parse a single line of JSON and write modified JSON back.
|
"""
|
||||||
|
Parse a single line of JSON and write modified JSON back.
|
||||||
|
|
||||||
Usage is quite simple using the usual with-Syntax."""
|
Usage is quite simple using the usual with-Syntax.
|
||||||
|
"""
|
||||||
|
|
||||||
prefix = ""
|
prefix = ""
|
||||||
|
|
||||||
@ -179,9 +208,7 @@ class JSONIO:
|
|||||||
self.io.write_line(prefix + json.dumps(j))
|
self.io.write_line(prefix + json.dumps(j))
|
||||||
|
|
||||||
class ClassFinder:
|
class ClassFinder:
|
||||||
"""
|
"""Support class to find classes of specific bases in a module"""
|
||||||
Support class to find classes of specific bases in a module
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, baseclass, exclude=[]):
|
def __init__(self, baseclass, exclude=[]):
|
||||||
self.baseclass = baseclass
|
self.baseclass = baseclass
|
||||||
@ -192,7 +219,7 @@ class ClassFinder:
|
|||||||
|
|
||||||
def search_module(self, module):
|
def search_module(self, module):
|
||||||
# Neat trick: [(x,y),(u,v)] becomes [(x,u),(y,v)]
|
# Neat trick: [(x,y),(u,v)] becomes [(x,u),(y,v)]
|
||||||
return zip(*inspect.getmembers(module, self.predicate))[1]
|
return list(zip(*inspect.getmembers(module, self.predicate)))[1]
|
||||||
|
|
||||||
def get_class(self, module):
|
def get_class(self, module):
|
||||||
classes = self.search_module(module)
|
classes = self.search_module(module)
|
||||||
@ -206,6 +233,9 @@ class ClassFinder:
|
|||||||
|
|
||||||
return classes[0]
|
return classes[0]
|
||||||
|
|
||||||
|
def instanciate_class(self, module, *args, **kwargs):
|
||||||
|
return self.get_class(module)(*args, **kwargs)
|
||||||
|
|
||||||
class i3pystatus:
|
class i3pystatus:
|
||||||
modules = []
|
modules = []
|
||||||
|
|
||||||
@ -217,14 +247,8 @@ class i3pystatus:
|
|||||||
|
|
||||||
self.finder = ClassFinder(baseclass=Module, exclude=[Module, IntervalModule, AsyncModule])
|
self.finder = ClassFinder(baseclass=Module, exclude=[Module, IntervalModule, AsyncModule])
|
||||||
|
|
||||||
@classmethod
|
def get_instance_for_module(self, module, position, args, kwargs):
|
||||||
def _make_instance(cls, module, position, args, kwargs):
|
|
||||||
if isinstance(module, types.ModuleType):
|
if isinstance(module, types.ModuleType):
|
||||||
# Okay, we got a module, let's find the class
|
|
||||||
# and create an instance
|
|
||||||
|
|
||||||
cls = self.finder.get_class(module)
|
|
||||||
|
|
||||||
if not isinstance(position, int) and not args:
|
if not isinstance(position, int) and not args:
|
||||||
# If the user does this: register(modsde, mdesettings) with mdesettings
|
# If the user does this: register(modsde, mdesettings) with mdesettings
|
||||||
# being a dict Python will put mdesettings into the position argument
|
# being a dict Python will put mdesettings into the position argument
|
||||||
@ -233,7 +257,7 @@ class i3pystatus:
|
|||||||
args = (position,)
|
args = (position,)
|
||||||
position = 0
|
position = 0
|
||||||
|
|
||||||
module = cls(*args, **kwargs)
|
module = self.finder.instanciate_class(module, *args, **kwargs)
|
||||||
elif args or kwargs:
|
elif args or kwargs:
|
||||||
raise ValueError("Additional arguments are invalid if 'module' is already an object")
|
raise ValueError("Additional arguments are invalid if 'module' is already an object")
|
||||||
|
|
||||||
@ -242,7 +266,7 @@ class i3pystatus:
|
|||||||
def register(self, module, position=0, *args, **kwargs):
|
def register(self, module, position=0, *args, **kwargs):
|
||||||
"""Register a new module."""
|
"""Register a new module."""
|
||||||
|
|
||||||
module, position = self._make_instance(module, position, args, kwargs)
|
module, position = self.get_instance_for_module(module, position, args, kwargs)
|
||||||
|
|
||||||
self.modules.append(module)
|
self.modules.append(module)
|
||||||
module.position = position
|
module.position = position
|
||||||
|
Loading…
Reference in New Issue
Block a user