refactor: Update config to use future annotations and move merge_dicts to misc.

This commit is contained in:
UpstreamData
2024-01-25 11:32:03 -07:00
parent c5eed797ec
commit b328a27f04
8 changed files with 64 additions and 55 deletions

View File

@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from copy import deepcopy
from dataclasses import asdict, dataclass, field from dataclasses import asdict, dataclass, field
from pyasic.config.fans import FanModeConfig from pyasic.config.fans import FanModeConfig
@@ -21,6 +20,7 @@ from pyasic.config.mining import MiningModeConfig
from pyasic.config.pools import PoolConfig from pyasic.config.pools import PoolConfig
from pyasic.config.power_scaling import PowerScalingConfig from pyasic.config.power_scaling import PowerScalingConfig
from pyasic.config.temperature import TemperatureConfig from pyasic.config.temperature import TemperatureConfig
from pyasic.misc import merge_dicts
@dataclass @dataclass
@@ -93,7 +93,7 @@ class MinerConfig:
def as_bosminer(self, user_suffix: str = None) -> dict: def as_bosminer(self, user_suffix: str = None) -> dict:
return { return {
**merge(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()), **merge_dicts(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()),
**self.mining_mode.as_bosminer(), **self.mining_mode.as_bosminer(),
**self.pools.as_bosminer(user_suffix=user_suffix), **self.pools.as_bosminer(user_suffix=user_suffix),
**self.power_scaling.as_bosminer(), **self.power_scaling.as_bosminer(),
@@ -120,8 +120,10 @@ class MinerConfig:
def as_auradine(self, user_suffix: str = None) -> dict: def as_auradine(self, user_suffix: str = None) -> dict:
return { return {
**self.fan_mode.as_auradine(), **self.fan_mode.as_auradine(),
**self.temperature.as_auradine(),
**self.mining_mode.as_auradine(), **self.mining_mode.as_auradine(),
**self.pools.as_auradine(user_suffix=user_suffix), **self.pools.as_auradine(user_suffix=user_suffix),
**self.power_scaling.as_auradine(),
} }
@classmethod @classmethod
@@ -203,14 +205,3 @@ class MinerConfig:
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]), fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]), mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
) )
def merge(a: dict, b: dict) -> dict:
result = deepcopy(a)
for b_key, b_val in b.items():
a_val = result.get(b_key)
if isinstance(a_val, dict) and isinstance(b_val, dict):
result[b_key] = merge(a_val, b_val)
else:
result[b_key] = deepcopy(b_val)
return result

View File

@@ -13,14 +13,15 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from enum import Enum from enum import Enum
from typing import Union
class MinerConfigOption(Enum): class MinerConfigOption(Enum):
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
return cls.default() return cls.default()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -67,7 +68,7 @@ class MinerConfigOption(Enum):
@dataclass @dataclass
class MinerConfigValue: class MinerConfigValue:
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
return cls() return cls()
def as_dict(self) -> dict: def as_dict(self) -> dict:

View File

@@ -13,8 +13,9 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue from pyasic.config.base import MinerConfigOption, MinerConfigValue
@@ -26,7 +27,7 @@ class FanModeNormal(MinerConfigValue):
minimum_speed: int = 0 minimum_speed: int = 0
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeNormal": def from_dict(cls, dict_conf: dict | None) -> "FanModeNormal":
cls_conf = {} cls_conf = {}
if dict_conf.get("minimum_fans") is not None: if dict_conf.get("minimum_fans") is not None:
cls_conf["minimum_fans"] = dict_conf["minimum_fans"] cls_conf["minimum_fans"] = dict_conf["minimum_fans"]
@@ -57,7 +58,7 @@ class FanModeManual(MinerConfigValue):
minimum_fans: int = 1 minimum_fans: int = 1
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeManual": def from_dict(cls, dict_conf: dict | None) -> "FanModeManual":
cls_conf = {} cls_conf = {}
if dict_conf.get("speed") is not None: if dict_conf.get("speed") is not None:
cls_conf["speed"] = dict_conf["speed"] cls_conf["speed"] = dict_conf["speed"]
@@ -101,7 +102,7 @@ class FanModeImmersion(MinerConfigValue):
mode: str = field(init=False, default="immersion") mode: str = field(init=False, default="immersion")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeImmersion": def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -124,7 +125,7 @@ class FanModeConfig(MinerConfigOption):
return cls.normal() return cls.normal()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -132,9 +133,9 @@ class FanModeConfig(MinerConfigOption):
if mode is None: if mode is None:
return cls.default() return cls.default()
clsattr = getattr(cls, mode) cls_attr = getattr(cls, mode)
if clsattr is not None: if cls_attr is not None:
return clsattr().from_dict(dict_conf) return cls_attr().from_dict(dict_conf)
@classmethod @classmethod
def from_am_modern(cls, web_conf: dict): def from_am_modern(cls, web_conf: dict):

View File

@@ -13,8 +13,9 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Dict, Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue from pyasic.config.base import MinerConfigOption, MinerConfigValue
from pyasic.web.braiins_os.proto.braiins.bos.v1 import ( from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
@@ -34,7 +35,7 @@ class MiningModeNormal(MinerConfigValue):
mode: str = field(init=False, default="normal") mode: str = field(init=False, default="normal")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeNormal": def from_dict(cls, dict_conf: dict | None) -> "MiningModeNormal":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -52,7 +53,7 @@ class MiningModeSleep(MinerConfigValue):
mode: str = field(init=False, default="sleep") mode: str = field(init=False, default="sleep")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeSleep": def from_dict(cls, dict_conf: dict | None) -> "MiningModeSleep":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -70,7 +71,7 @@ class MiningModeLPM(MinerConfigValue):
mode: str = field(init=False, default="low") mode: str = field(init=False, default="low")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeLPM": def from_dict(cls, dict_conf: dict | None) -> "MiningModeLPM":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -88,7 +89,7 @@ class MiningModeHPM(MinerConfigValue):
mode: str = field(init=False, default="high") mode: str = field(init=False, default="high")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeHPM": def from_dict(cls, dict_conf: dict | None) -> "MiningModeHPM":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -107,7 +108,7 @@ class MiningModePowerTune(MinerConfigValue):
power: int = None power: int = None
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModePowerTune": def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
return cls(dict_conf.get("power")) return cls(dict_conf.get("power"))
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -145,7 +146,7 @@ class MiningModeHashrateTune(MinerConfigValue):
hashrate: int = None hashrate: int = None
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeHashrateTune": def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
return cls(dict_conf.get("hashrate")) return cls(dict_conf.get("hashrate"))
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -177,7 +178,7 @@ class ManualBoardSettings(MinerConfigValue):
volt: float volt: float
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "ManualBoardSettings": def from_dict(cls, dict_conf: dict | None) -> "ManualBoardSettings":
return cls(freq=dict_conf["freq"], volt=dict_conf["volt"]) return cls(freq=dict_conf["freq"], volt=dict_conf["volt"])
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -190,10 +191,10 @@ class MiningModeManual(MinerConfigValue):
global_freq: float global_freq: float
global_volt: float global_volt: float
boards: Dict[int, ManualBoardSettings] = field(default_factory=dict) boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual": def from_dict(cls, dict_conf: dict | None) -> "MiningModeManual":
return cls( return cls(
global_freq=dict_conf["global_freq"], global_freq=dict_conf["global_freq"],
global_volt=dict_conf["global_volt"], global_volt=dict_conf["global_volt"],
@@ -232,7 +233,7 @@ class MiningModeConfig(MinerConfigOption):
return cls.normal() return cls.normal()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -240,9 +241,9 @@ class MiningModeConfig(MinerConfigOption):
if mode is None: if mode is None:
return cls.default() return cls.default()
clsattr = getattr(cls, mode) cls_attr = getattr(cls, mode)
if clsattr is not None: if cls_attr is not None:
return clsattr().from_dict(dict_conf) return cls_attr().from_dict(dict_conf)
@classmethod @classmethod
def from_am_modern(cls, web_conf: dict): def from_am_modern(cls, web_conf: dict):

View File

@@ -13,10 +13,12 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
import random import random
import string import string
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Dict, List, Union from typing import List
from pyasic.config.base import MinerConfigValue from pyasic.config.base import MinerConfigValue
@@ -108,7 +110,7 @@ class Pool(MinerConfigValue):
return {"url": self.url, "user": self.user, "pass": self.password} return {"url": self.url, "user": self.user, "pass": self.password}
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "Pool": def from_dict(cls, dict_conf: dict | None) -> "Pool":
return cls( return cls(
url=dict_conf["url"], user=dict_conf["user"], password=dict_conf["password"] url=dict_conf["url"], user=dict_conf["user"], password=dict_conf["password"]
) )
@@ -169,7 +171,7 @@ class Pool(MinerConfigValue):
@dataclass @dataclass
class PoolGroup(MinerConfigValue): class PoolGroup(MinerConfigValue):
pools: List[Pool] = field(default_factory=list) pools: list[Pool] = field(default_factory=list)
quota: int = 1 quota: int = 1
name: str = None name: str = None
@@ -254,7 +256,7 @@ class PoolGroup(MinerConfigValue):
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools] return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PoolGroup": def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
cls_conf = {} cls_conf = {}
if dict_conf.get("quota") is not None: if dict_conf.get("quota") is not None:
@@ -330,14 +332,14 @@ class PoolConfig(MinerConfigValue):
return cls() return cls()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PoolConfig": def from_dict(cls, dict_conf: dict | None) -> "PoolConfig":
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]]) return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
@classmethod @classmethod
def simple(cls, pools: List[Union[Pool, Dict[str, str]]]) -> "PoolConfig": def simple(cls, pools: list[Pool | dict[str, str]]) -> "PoolConfig":
group_pools = [] group_pools = []
for pool in pools: for pool in pools:
if isinstance(pool, dict): if isinstance(pool, dict):

View File

@@ -13,8 +13,9 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue from pyasic.config.base import MinerConfigOption, MinerConfigValue
from pyasic.web.braiins_os.proto.braiins.bos.v1 import ( from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
@@ -31,7 +32,7 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
duration: int = None duration: int = None
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PowerScalingShutdownEnabled": def from_dict(cls, dict_conf: dict | None) -> "PowerScalingShutdownEnabled":
return cls(duration=dict_conf.get("duration")) return cls(duration=dict_conf.get("duration"))
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
@@ -51,7 +52,7 @@ class PowerScalingShutdownDisabled(MinerConfigValue):
mode: str = field(init=False, default="disabled") mode: str = field(init=False, default="disabled")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PowerScalingShutdownDisabled": def from_dict(cls, dict_conf: dict | None) -> "PowerScalingShutdownDisabled":
return cls() return cls()
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
@@ -66,7 +67,7 @@ class PowerScalingShutdown(MinerConfigOption):
disabled = PowerScalingShutdownDisabled disabled = PowerScalingShutdownDisabled
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -107,9 +108,7 @@ class PowerScalingEnabled(MinerConfigValue):
mode: str = field(init=False, default="enabled") mode: str = field(init=False, default="enabled")
power_step: int = None power_step: int = None
minimum_power: int = None minimum_power: int = None
shutdown_enabled: Union[ shutdown_enabled: PowerScalingShutdownEnabled | PowerScalingShutdownDisabled = None
PowerScalingShutdownEnabled, PowerScalingShutdownDisabled
] = None
@classmethod @classmethod
def from_bosminer(cls, power_scaling_conf: dict) -> "PowerScalingEnabled": def from_bosminer(cls, power_scaling_conf: dict) -> "PowerScalingEnabled":
@@ -122,7 +121,7 @@ class PowerScalingEnabled(MinerConfigValue):
) )
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PowerScalingEnabled": def from_dict(cls, dict_conf: dict | None) -> "PowerScalingEnabled":
cls_conf = { cls_conf = {
"power_step": dict_conf.get("power_step"), "power_step": dict_conf.get("power_step"),
"minimum_power": dict_conf.get("minimum_power"), "minimum_power": dict_conf.get("minimum_power"),
@@ -175,7 +174,7 @@ class PowerScalingConfig(MinerConfigOption):
return cls.disabled() return cls.disabled()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()

View File

@@ -13,8 +13,9 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Union
from pyasic.config.base import MinerConfigValue from pyasic.config.base import MinerConfigValue
@@ -40,7 +41,7 @@ class TemperatureConfig(MinerConfigValue):
return {"temp_control": temp_cfg} return {"temp_control": temp_cfg}
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "TemperatureConfig": def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
return cls( return cls(
target=dict_conf.get("target"), target=dict_conf.get("target"),
hot=dict_conf.get("hot"), hot=dict_conf.get("hot"),

View File

@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from copy import deepcopy
from pyasic.rpc import APIError from pyasic.rpc import APIError
@@ -76,3 +78,14 @@ def api_min_version(version: str):
return inner return inner
return decorator return decorator
def merge_dicts(a: dict, b: dict) -> dict:
result = deepcopy(a)
for b_key, b_val in b.items():
a_val = result.get(b_key)
if isinstance(a_val, dict) and isinstance(b_val, dict):
result[b_key] = merge_dicts(a_val, b_val)
else:
result[b_key] = deepcopy(b_val)
return result