API¶
Bonfig¶
An alternative, more beautiful way to build configs!
-
class
bonfig.
Bonfig
(*args, frozen=True, **kwargs)¶ Base class for all Bonfigs.
Parameters: - frozen : bool, optional
Freeze Bonfig just after initialisation - by calling
Bonfig.freeze()
.- *args
Positional arguments, passed to
Bonfig.load()
.- **kwargs
Keyword arguments, passed to
Bonfig.load()
.
Notes
Instances of this class shouldn’t be created directly, instead it should be subclassed (see examples).
Ideally do overwrite or call __init__ directly, instead use the provided load hook for initialising things like data stores.
Attributes: - __fields__ : set
a set containing all the classes Field attributes.
- __store_attrs__ : set
a set containing the names of each store attribute for that class
Methods
freeze
()Freeze Bonfig stores. load
(*args, **kwargs)Hook called during initialisation for loading store attributes. -
freeze
()¶ Freeze Bonfig stores.
Works by creating a copy of each store as dict, then converting to an MappingProxyType.
Notes
In order to ‘freeze’ your store, it each container needs to implement both __getitem__() and keys() as a minimum.
-
load
(*args, **kwargs)¶ Hook called during initialisation for loading store attributes.
Is basically __init__, but called at the right time such that locking works and that fields can be initialised.
Parameters: - *args
args from __init__
- **kwargs
kwargs from __init__
Notes
As load is called before Field`s are initialised, values can be overwritten by fields unless `Field.val=None.
-
class
bonfig.
Store
(_name=None)¶ Placeholder class, allowing structure of store to be created in Bonfig.
Upon initialisation should be overwritten with an container object that supports __getitem__ using
Bonfig.load()
.Any Fields ultimately belonging to a Store will look in the container that the Store object is overwritten with during
Bonfig.load()
.Examples
>>> class Config(Bonfig): ... a = Store('my store') ... b = Store() ... ... f1 = a.Field() ... f2 = b.Field() >>> Config.a.name 'my store' >>> Config.b.name 'b' >>> Config.a.Field functools.partial(<class 'bonfig.fields.Field'>, _store=<Store: my store>) >>> Config.b.Section functools.partial(<class 'bonfig.fields.Section'>, _store=<Store: b>)
Attributes: name
: str, optionalName of store.
-
is_with_proxy
¶ Check if self is an original Store or a proxy of another from a with statement.
-
name
¶ Name of store.
For any Fields that ultimately belong to this store will have this value as
Field.store_attr
.
Fields¶
NOTE¶
You will notice in the Field and Section parameters for __init__ which start with ‘_’, these arguments are not intended to be set directly. Instead these classes should be accessed by either parent Stores or Sections, and these arguments will be implicitly set.
Attributes¶
- fields : FieldDict
- A global dict -like object that stores all of the field classes. This dict is used to provide stores and sections with access to field classes, as such, add to this global dict to make custom fields available in that context. (By default includes Field, IntField, FloatField, BoolField and DatetimeField.
-
class
bonfig.fields.
Section
(name=None, *, _supsection=None, _store=None)¶ Convenience class for building up multi-level Bonfigs s.
Any Field s created from Section.Field implicitly have the Field.section attribute set to that Section.
Parameters: - name : str, optional
name of Section. Default behaviour is to take the name of the class attribute Section was set to (using __set_name__).
- _supsection : Section, optional
Section that owns this section. Rather than setting directly, this should be done by creating this Section instance using supsection.Section.
- _store : Store
Store that section belongs to.
Examples
>>> class Config(Bonfig): ... s = Store() ... ... A = s.Section() ... Af = A.Field('A - f') ... ... B = A.Section('B within A') ... Bf = B.Field('B - f') ... ... def load(self): ... self.s = {} >>> >>> c = Config() >>> c.A.keys ['sec_A'] >>> c.B.keys ['A', 'B within A'] >>> c.Af 'A - f' >>> Config.Af.keys ['A', 'Af'] >>> Config.Bf.keys ['A', 'B within A', 'Bf'] >>> c.s {'A': { 'Af': 'A - f', 'B within A': { 'Bf': 'B - f' } } }
Attributes: is_with_proxy
Check if self is an original Section or a proxy of another from a with statement.
keys
Keys used to look get to this section of the store
name
Name of Section.
-
classmethod
_from_with
(with_owner)¶ Internal method for creating a ‘proxy’ of a Section object for use in with blocks.
-
is_with_proxy
¶ Check if self is an original Section or a proxy of another from a with statement.
-
keys
¶ Keys used to look get to this section of the store
-
name
¶ Name of Section.
-
class
bonfig.fields.
Field
(val=None, default=None, name=None, *, _store=None, _section=None)¶ Class representing a parameter from your configuration. This object encapsulates how this parameter is serialised and deserialsed as well as how and where it’s fetched from.
Parameters: - val : object, optional
value that will be inserted into store upon initialisation. (Note if set to None, no value will be added to the store rather that a value equal to None.)
- default : object, optional
Fallback value for this parameter if not found in store. If set to None then AttributeError will be raised.
- name : str, optional
Key that is used to get value of Field as stored in store. Default behaviour is to take the name of the class attribute Field was set to (using __set_name__).
- _store : Store
store that this Field belongs to/ looks into. Shouldn’t really be set directly, instead use Store.Field to create Field instances.
- _section : Section, optional
section that this Field belongs to. The section provides a set of ‘pre-keys’ that are looked up before name in store in order to fetch the Field ‘s value. Rather than setting directly, Section.Field should be used.
Notes
The __add__ method of Field objects is also implemented for convenience, however, note that as the Store and Section of a field is derived from the Store or Section that ultimately made it, this could lead to unexpected behaviour if this is used between stores and sections e.g.
Works:
>>> from bonfig import Bonfig, Store >>> class Config(Bonfig): ... s = Store() ... FIRST_NAME = s.Field("Garry") ... FULL_NAME = FIRST_NAME + 'Lineker' ... >>> c = Config() >>> c.FIRST_NAME "Garry" >>> c.FULL_NAME "GarryLineker"
Also works:
>>> from bonfig import Bonfig, Store >>> class Config(Bonfig): ... s = Store() ... FIRST_NAME = s.Field("Garry") ... LAST_NAME = s.Field("Lineker") ... FULL_NAME = FIRST_NAME + LAST_NAME ... >>> c = Config() >>> c.FULL_NAME "GarryLineker"
Examples
>>> class Config(Bonfig): ... s = Store() ... ... f1 = s.Field('first field') ... f2 = s.Field() ... f3 = s.Field(default='f3 not found') ... f4 = s.Field('fourth field', name='field1') ... ... def load(self): ... self.s = {} >>> c = Config() >>> c.f1 'first field' >>> c.f2 KeyError: 'f2' >>> c.f3 'f3 not found' >>> c.f4 'forth field' >>> c.s {'f1': 'first field', 'field1': 'fourth field'}
Attributes: keys
Keys used to look up value within store.
store_attr
Name of Bonfig instance attribute that values are looked up in.
-
_get_store
(bonfig)¶ Get store attribute from bonfig.
-
_get_value
(store)¶ Hook to allow you to control how the value is looked up in the data Store.
-
_initialise
(bonfig)¶ Initialise Field.
This method is called during initialisation, and sets the value found within store at self.keys to self.val, unless self.val is None, in which case, nothing happens!
Notes
This process takes place just after
Bonfig.load()
and for each Field. As such any values set fromBonfig.load
are liable to be overwritten by initialise unless self.val=None.
-
_post_get
(val)¶ Apply function to values after they are fetched from data Store
-
_pre_set
(val)¶ Apply function to values before they are inserted into data Store
-
keys
¶ Keys used to look up value within store.
-
store_attr
¶ Name of Bonfig instance attribute that values are looked up in.
-
bonfig.fields.
make_sub_field
(name, bases, post_get=None, pre_set=None, doc=None)¶ Factory function for producing Field-like classes.
Parameters: - name : str
Name of new field class
- post_get : func
Function to apply to values just after they are fetched from the data
Store
.- pre_set : func
Function to apply to values just before they are inserted into the data
Store
.- bases : cls
Class for the newly created class to subclass (defaults to
Field
).- doc : str, optional
docstring :)
Returns: - cls : cls
New Field subclass.
-
class
bonfig.fields.
FieldDict
(bases, *args, **kwargs)¶ Subclass of dict for storing field classes.
Methods
add
(field_cls)Add a field_cls class to a field_cls dict. clear
()copy
()fromkeys
($type, iterable[, value])Create a new dictionary with keys from iterable and values set to value. get
($self, key[, default])Return the value for key if key is in the dictionary, else default. items
()keys
()make_quick
(name[, post_get, pre_set, …])Factory function for producing Field -like classes. pop
(k[,d])If key is not found, d is returned if given, otherwise KeyError is raised popitem
()2-tuple; but raise KeyError if D is empty. setdefault
($self, key[, default])Insert key with a value of default if key is not in the dictionary. update
([E, ]**F)If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k] values
()-
add
(field_cls)¶ Add a field_cls class to a field_cls dict. This method implicitly uses field_cls.__name__ as the key.
Parameters: - field_cls : cls
A Field subclass that you want to be added to the dict
Returns: - field_cls : cls
Returns the same field_cls instance back. This allows the method to be used as a class decorator!
Examples
>>> @fields.add >>> class ListField(Field): ... ... def __init__(self, val=None, default=None, name=None, *, _store=None, _section=None, sep=', '): ... super().__init__(val, default=default, name=name, _store=_store, _section=_section) ... self.sep = sep ... ... def post_get(self, val): ... return val.split(self.sep) ... ... def pre_set(self, val): ... return self.sep.join(val)
-
make_quick
(name, post_get=None, pre_set=None, doc_preamble=None)¶ Factory function for producing Field -like classes.
Parameters: - name : str
Name of new class
- post_get : func, optional
Function to apply to values just after they are fetched from the data Store.
- pre_set : func, optional
Function to apply to values just before they are inserted into the data Store.
- bases : cls
Class for the newly created class to subclass (defaults to
Field
).- doc_preamble : str, optional
docstring to prepend to Field docstring!
Returns: - cls : cls
New Field subclass.
Examples
>>> IntField = fields.make_quick('IntField', int, str)
-
-
class
bonfig.fields.
IntField
(val=None, default=None, name=None, *, _store=None, _section=None)¶ Field that serialises and de-serialises values as integers.
Values are stored as strings within store
Parameters: - val, default, name, fmt, _store, _section : object
See baseclass
Field
See also
Field
- Parent class
Examples
>>> class Config(Bonfig): ... s = Store() ... days = s.IntField(365) ... >>> c = Config() >>> c.days 365 >>> c.s {'days': '365'}
Attributes: keys
Keys used to look up value within store.
store_attr
Name of Bonfig instance attribute that values are looked up in.
-
_post_get
(val)¶ Apply function to values after they are fetched from data Store
-
_pre_set
(val)¶ Apply function to values before they are inserted into data Store
-
class
bonfig.fields.
BoolField
(val=None, default=None, name=None, *, _store=None, _section=None)¶ Field that serialises and de-serialises values as Booleans.
Values are stored as strings within store
Parameters: - val, default, name, fmt, _store, _section : object
See baseclass
Field
See also
Field
- Parent class
Examples
>>> class Config(Bonfig): ... s = Store() ... do = s.BoolField(True) ... >>> c = Config() >>> c.do True >>> c.s {'do': 'True'}
Attributes: keys
Keys used to look up value within store.
store_attr
Name of Bonfig instance attribute that values are looked up in.
-
_post_get
(val)¶ Apply function to values after they are fetched from data Store
-
_pre_set
(val)¶ Apply function to values before they are inserted into data Store
-
class
bonfig.fields.
FloatField
(val=None, default=None, name=None, *, _store=None, _section=None)¶ Field that serialises and de-serialises values as floats.
Values are stored as strings within store
Parameters: - val, default, name, fmt, _store, _section : object
See baseclass
Field
See also
Field
- Parent class
Examples
>>> class Config(Bonfig): ... s = Store() ... pi = s.FloatField(3.14159) ... >>> c = Config() >>> c.pi 3.14159 >>> c.s {'pi': '3.14159'}
Attributes: keys
Keys used to look up value within store.
store_attr
Name of Bonfig instance attribute that values are looked up in.
-
_post_get
(val)¶ Apply function to values after they are fetched from data Store
-
_pre_set
(val)¶ Apply function to values before they are inserted into data Store
-
class
bonfig.fields.
DatetimeField
(val=None, default=None, name=None, fmt=None, *, _store=None, _section=None)¶ Field that serialises and de-serialises fields that are datetime strings!
Values are stored as strings within store
Parameters: - val : str, datetime.datetime
Either str or datetime, if str will be automatically converted to datetime.
- fmt : str
Required keyword argument - format to read and write datetime with (using datetime.datetime.strptime and strftime)
- default, name, _store, _section : object
See
Field
See also
Field
- Parent class
Examples
>>> class Config(Bonfig): ... s = Store() ... when = s.DatetimeField('25/12/1995', fmt='%d/%m/%Y') ... >>> c = Config() >>> c.when datetime.datetime(1995, 12, 25, 0, 0) >>> c.s {'when': '25/12/1995'}
Attributes: keys
Keys used to look up value within store.
store_attr
Name of Bonfig instance attribute that values are looked up in.
-
_post_get
(val)¶ Apply function to values after they are fetched from data Store
-
_pre_set
(val)¶ Apply function to values before they are inserted into data Store
-
class
bonfig.fields.
PathField
(val=None, default=None, name=None, *, _store=None, _section=None)¶ Field that serialises and de-serialises fields that are pathlib.Path objects.
Values are stored as strings within store.
Parameters: - val : str, pathlib.Path
Either str or pathlib.Path, if str, will be automatically converted to pathlib.Path.
- default, name, fmt, _store, _section : object
See
Field
See also
Field
- Parent class
Examples
>>> class Config(Bonfig): ... s = Store() ... base = s.PathField('') # '' required as None is not a valid Path ... file = base / 'important.txt' ... >>> c = Config() >>> c.base Path('.') >>> c.file Path('important.txt') >>> c.s
Attributes: keys
Keys used to look up value within store.
store_attr
Name of Bonfig instance attribute that values are looked up in.
-
_post_get
(val)¶ Apply function to values after they are fetched from data Store
-
_pre_set
(val)¶ Apply function to values before they are inserted into data Store