Source code for finstmt.config_manage.statements
import json
from dataclasses import asdict, dataclass
from typing import Any, Dict, List, Sequence, Tuple, Union
from sympy import IndexedBase
from finstmt.config_manage.base import ConfigManagerBase
from finstmt.config_manage.statement import StatementConfigManager
from finstmt.exc import NoSuchItemException
from finstmt.items.config import ItemConfig
from finstmt.logger import logger
[docs]@dataclass
class StatementsConfigManager(ConfigManagerBase):
"""
Main configuration interface. Handles all of the configuration for a set of financial statements.
"""
config_managers: Dict[str, StatementConfigManager]
[docs] def get(self, item_key: str) -> ItemConfig:
"""
Get entire configuration for item by key
"""
config, _ = self._get(item_key)
return config
def __getattr__(self, item_key: str) -> ItemConfig:
"""
Get the config for a given key
"""
# When copying the object, config_managers can be undefined and so would cause a
# recursive loop without this check
if item_key == "config_managers":
# Trigger the default Python behavior
return object.__getattribute__(self, item_key)
try:
return self.get(item_key)
except NoSuchItemException:
raise AttributeError(item_key)
def __dir__(self) -> List[str]:
return self.keys
def _get(self, item_key: str) -> Tuple[ItemConfig, str]:
"""
For internal use, get the config as well as the key of the financial statement type it belongs to
"""
for fin_statement_type, manager in self.config_managers.items():
try:
return manager.get(item_key), fin_statement_type
except NoSuchItemException:
continue
raise NoSuchItemException(item_key)
[docs] def set(self, item_key: str, config: ItemConfig):
"""
Set entire configuration for item by key
"""
orig_config, fin_statement_key = self._get(item_key)
self.config_managers[fin_statement_key].set(item_key, config)
[docs] def update(self, item_key: str, config_keys: Union[str, Sequence[str]], value: Any):
"""
Update configuration for item by item key and nested config keys
:param item_key:
:param config_keys:
:param value:
:return:
"""
if isinstance(config_keys, str):
config_keys = [config_keys]
orig_config, fin_statement_key = self._get(item_key)
nested_config = orig_config
for i, config_key in enumerate(config_keys):
if i == len(config_keys) - 1:
# Last iteration, now set value
setattr(nested_config, config_key, value)
logger.debug(
f"Set {config_key} for {item_key} on {type(nested_config)} to {value}"
)
else:
# Not last iteration, need to get nested config
nested_config = getattr(nested_config, config_key)
self.set(item_key, orig_config)
[docs] def update_all(self, config_keys: Union[str, Sequence[str]], value: Any):
"""
Update configuration for all items by nested config keys
:param config_keys:
:param value:
:return:
"""
for item_key in self.keys:
self.update(item_key, config_keys, value)
@property
def sympy_namespace(self) -> Dict[str, IndexedBase]:
ns_dict = {}
for cfg_mgr in self.config_managers.values():
ns_dict.update(cfg_mgr.sympy_namespace)
return ns_dict
@property
def keys(self) -> List[str]:
all_keys = set()
for manager in self.config_managers.values():
all_keys.update(manager.keys)
return list(all_keys)
@property
def items(self) -> List[ItemConfig]:
all_items = []
for manager in self.config_managers.values():
# Get unique maintaining order within a statement
for item in manager.items:
if item in all_items:
continue
all_items.append(item)
return all_items
[docs] def dict(self) -> dict:
item_data: Dict[str, dict] = {}
for item in self.items:
item_data[item.key] = asdict(item)
return item_data
[docs] def json(self, **kwargs) -> str:
return json.dumps(self.dict(), **kwargs)