Adds ability to extend one config with another

apply_config() checks for 'extends' in TOML config

2.3.0 section added to CHANGELOG

three example extender.toml configs added

minor version bump
This commit is contained in:
onyx-and-iris 2023-07-11 20:27:52 +01:00
parent 8e30c57020
commit 2a98707bf8
7 changed files with 87 additions and 16 deletions

View File

@ -11,6 +11,12 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
- [x] - [x]
## [2.2.0] - 2023-07-11
### Added
- user configs may now extend other user configs. check `config extends` section in README.
## [2.1.2] - 2023-07-05 ## [2.1.2] - 2023-07-05
### Added ### Added

View File

@ -44,7 +44,7 @@ port = 6980
streamname = "Command1" streamname = "Command1"
``` ```
It should be placed next to your `__main__.py` file. It should be placed in \<user home directory\> / "Documents" / "Voicemeeter" / "configs"
Alternatively you may pass `ip`, `port`, `streamname` as keyword arguments. Alternatively you may pass `ip`, `port`, `streamname` as keyword arguments.
@ -359,8 +359,8 @@ vban.apply(
Or for each class you may do: Or for each class you may do:
```python ```python
vban.strip[0].apply(mute: true, gain: 3.2, A1: true) vban.strip[0].apply({"mute": True, "gain": 3.2, "A1": True})
vban.bus[0].apply(A1: true) vban.vban.outstream[0].apply({"on": True, "name": "streamname", "bit": 24})
``` ```
## Config Files ## Config Files
@ -369,7 +369,7 @@ vban.bus[0].apply(A1: true)
You may load config files in TOML format. You may load config files in TOML format.
Three example configs have been included with the package. Remember to save Three example configs have been included with the package. Remember to save
current settings before loading a user config. To set one you may do: current settings before loading a user config. To load one you may do:
```python ```python
import vban_cmd import vban_cmd
@ -379,6 +379,27 @@ with vban_cmd.api('banana') as vban:
will load a config file at configs/banana/example.toml for Voicemeeter Banana. will load a config file at configs/banana/example.toml for Voicemeeter Banana.
Your configs may be located in one of the following paths:
- \<current working directory\> / "configs" / kind_id
- \<user home directory\> / ".config" / "vban-cmd" / kind_id
- \<user home directory\> / "Documents" / "Voicemeeter" / "configs" / kind_id
If a config with the same name is located in multiple locations, only the first one found is loaded into memory, in the above order.
#### `config extends`
You may also load a config that extends another config with overrides or additional parameters.
You just need to define a key `extends` in the config TOML, that names the config to be extended.
Three example 'extender' configs are included with the repo. You may load them with:
```python
import voicemeeterlib
with voicemeeterlib.api('banana') as vm:
vm.apply_config('extender')
```
## Events ## Events
Level updates are considered high volume, by default they are NOT listened for. Use `subs` keyword arg to initialize event updates. Level updates are considered high volume, by default they are NOT listened for. Use `subs` keyword arg to initialize event updates.

View File

@ -0,0 +1,12 @@
extends = "example"
[strip-0]
label = "strip0_extended"
A1 = false
gain = 0.0
[bus-0]
label = "bus0_extended"
mute = false
[vban-in-3]
name = "vban_extended"

View File

@ -0,0 +1,12 @@
extends = "example"
[strip-0]
label = "strip0_extended"
A1 = false
gain = 0.0
[bus-0]
label = "bus0_extended"
mute = false
[vban-in-3]
name = "vban_extended"

View File

@ -0,0 +1,12 @@
extends = "example"
[strip-0]
label = "strip0_extended"
A1 = false
gain = 0.0
[bus-0]
label = "bus0_extended"
mute = false
[vban-in-3]
name = "vban_extended"

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "vban-cmd" name = "vban-cmd"
version = "2.2.0" version = "2.3.0"
description = "Python interface for the VBAN RT Packet Service (Sendtext)" description = "Python interface for the VBAN RT Packet Service (Sendtext)"
authors = ["onyx-and-iris <code@onyxandiris.online>"] authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT" license = "MIT"

View File

@ -64,8 +64,9 @@ class VbanCmd(metaclass=ABCMeta):
def get_filepath(): def get_filepath():
filepaths = [ filepaths = [
Path.cwd() / "vban.toml", Path.cwd() / "vban.toml",
Path.cwd() / "configs" / "vban.toml",
Path.home() / ".config" / "vban-cmd" / "vban.toml", Path.home() / ".config" / "vban-cmd" / "vban.toml",
Path.home() / "Documents" / "Voicemeeter" / "vban.toml", Path.home() / "Documents" / "Voicemeeter" / "configs" / "vban.toml",
] ]
for filepath in filepaths: for filepath in filepaths:
if filepath.exists(): if filepath.exists():
@ -75,11 +76,10 @@ class VbanCmd(metaclass=ABCMeta):
with open(filepath, "rb") as f: with open(filepath, "rb") as f:
conn = tomllib.load(f) conn = tomllib.load(f)
assert ( assert (
"ip" in conn["connection"] "connection" in conn and "ip" in conn["connection"]
), "please provide ip, by kwarg or config" ), "expected [connection][ip] in vban config"
return conn["connection"] return conn["connection"]
else: raise VBANCMDError("no ip provided and no vban.toml located.")
raise VBANCMDError("no ip provided and no vban.toml located.")
def __enter__(self): def __enter__(self):
self.login() self.login()
@ -101,7 +101,7 @@ class VbanCmd(metaclass=ABCMeta):
self.producer.start() self.producer.start()
self.logger.info( self.logger.info(
"Successfully logged into {kind} with ip='{ip}', port={port}, streamname='{streamname}'".format( "Successfully logged into VBANCMD {kind} with ip='{ip}', port={port}, streamname='{streamname}'".format(
**self.__dict__ **self.__dict__
) )
) )
@ -189,16 +189,24 @@ class VbanCmd(metaclass=ABCMeta):
def apply_config(self, name): def apply_config(self, name):
"""applies a config from memory""" """applies a config from memory"""
error_msg = ( ERR_MSG = (
f"No config with name '{name}' is loaded into memory", f"No config with name '{name}' is loaded into memory",
f"Known configs: {list(self.configs.keys())}", f"Known configs: {list(self.configs.keys())}",
) )
try: try:
self.apply(self.configs[name]) config = self.configs[name].copy()
self.logger.info(f"Profile '{name}' applied!")
except KeyError as e: except KeyError as e:
self.logger.error(("\n").join(error_msg)) self.logger.error(("\n").join(ERR_MSG))
raise VBANCMDError(("\n").join(error_msg)) from e raise VBANCMDError(("\n").join(ERR_MSG)) from e
if "extends" in config:
extended = config.pop("extends")
config = self.configs[extended] | config
self.logger.debug(
f"profile '{name}' extends '{extended}', profiles merged.."
)
self.apply(config)
self.logger.info(f"Profile '{name}' applied!")
def logout(self): def logout(self):
self.running = False self.running = False