diff --git a/tests/auto/test_auto.py b/tests/auto/test_auto.py index 6d4da95..0744417 100644 --- a/tests/auto/test_auto.py +++ b/tests/auto/test_auto.py @@ -11,7 +11,7 @@ do_autopath() from tiramisu import Config, MetaConfig, \ StrOption, SymLinkOption, OptionDescription, Leadership, DynOptionDescription, \ submulti, undefined, owners, Params, ParamOption, Calculation -from tiramisu.error import PropertiesOptionError, APIError, ConfigError, LeadershipError +from tiramisu.error import PropertiesOptionError, ConfigError, LeadershipError ICON = u'\u2937' OPTIONS_TYPE = {'str': {'type': str, @@ -148,7 +148,7 @@ def _set_value(cfg, pathwrite, conf, **kwargs): with warnings.catch_warnings(record=True) as w: if isleader: if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): - with raises(APIError): + with raises(ConfigError): cfg_.option(pathwrite, 0).value.set(first_value[0]) if not set_permissive: cfg_.option(pathwrite).value.set([first_value[0]]) @@ -165,7 +165,7 @@ def _set_value(cfg, pathwrite, conf, **kwargs): with raises(PropertiesOptionError): cfg_.forcepermissive.option(pathwrite).value.set([first_value[0]]) if len(first_value) > 1: - with raises(APIError): + with raises(ConfigError): cfg_.unrestraint.option(pathwrite).value.set(first_value[1]) elif isfollower: if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): @@ -183,7 +183,7 @@ def _set_value(cfg, pathwrite, conf, **kwargs): cfg_.option(pathwrite, 1).value.set(second_value) with raises(PropertiesOptionError): cfg_.forcepermissive.option(pathwrite, 1).value.set(second_value) - with raises(APIError): + with raises(ConfigError): cfg_.unrestraint.option(pathwrite).value.set([second_value, second_value]) else: @@ -202,7 +202,7 @@ def _set_value(cfg, pathwrite, conf, **kwargs): cfg_.option(pathwrite).value.set(first_value) with raises(PropertiesOptionError): cfg_.forcepermissive.option(pathwrite).value.set(first_value) - #FIXME raises(APIError, "cfg_.unrestraint.option(pathwrite).value.set(first_value)") + #FIXME raises(ConfigError, "cfg_.unrestraint.option(pathwrite).value.set(first_value)") def _getproperties(multi, isfollower, kwargs): diff --git a/tests/test_config.py b/tests/test_config.py index dc1be5d..c0f6d6d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -13,7 +13,7 @@ from tiramisu import Config from tiramisu.i18n import _ from tiramisu import Config, IntOption, FloatOption, ChoiceOption, \ BoolOption, StrOption, SymLinkOption, OptionDescription, undefined -from tiramisu.error import ConflictError, ConfigError, PropertiesOptionError, APIError +from tiramisu.error import ConflictError, ConfigError, PropertiesOptionError def make_description(): @@ -293,7 +293,7 @@ def test_duplicated_option_diff_od(): def test_cannot_assign_value_to_option_description(): od1 = make_description() cfg = Config(od1) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('gc').value.set(3) # assert not list_sessions() diff --git a/tests/test_config_api.py b/tests/test_config_api.py index 03c6702..bc45197 100644 --- a/tests/test_config_api.py +++ b/tests/test_config_api.py @@ -9,7 +9,7 @@ from tiramisu import Config, IntOption, FloatOption, StrOption, ChoiceOption, \ BoolOption, FilenameOption, SymLinkOption, IPOption, \ PortOption, NetworkOption, NetmaskOption, BroadcastOption, \ DomainnameOption, OptionDescription -from tiramisu.error import PropertiesOptionError, ValueWarning, APIError +from tiramisu.error import PropertiesOptionError, ValueWarning, ConfigError import warnings @@ -112,7 +112,7 @@ def test_make_dict_not_value(config_type): cfg.property.read_write() cfg.permissive.add('hidden') cfg = get_config(cfg, config_type) - with raises(APIError): + with raises(ConfigError): cfg.option('s1.a').value.dict() diff --git a/tests/test_leadership.py b/tests/test_leadership.py index c7e03c2..1e92db9 100644 --- a/tests/test_leadership.py +++ b/tests/test_leadership.py @@ -7,7 +7,7 @@ import pytest from tiramisu.setting import groups, owners from tiramisu import ChoiceOption, BoolOption, IntOption, IPOption, NetworkOption, NetmaskOption, \ StrOption, OptionDescription, Leadership, Config -from tiramisu.error import LeadershipError, PropertiesOptionError, APIError, ConfigError +from tiramisu.error import LeadershipError, PropertiesOptionError, ConfigError groups.family = groups.GroupType('family') @@ -267,7 +267,7 @@ def test_not_groups_len(config_type): od1 = OptionDescription('root', '', [interface1]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('ip_admin_eth0.ip_admin_eth0').value.len() @@ -437,9 +437,9 @@ def test_groups_with_leader_index_mandatory(config_type): cfg = get_config(cfg, config_type) cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1']) # index is mandatory - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('ip_admin_eth0.netmask_admin_eth0').value.reset() - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('ip_admin_eth0.netmask_admin_eth0').value.get() @@ -542,9 +542,9 @@ def test_values_with_leader_and_followers1(config_type): cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145", "192.168.230.147"]) if config_type != 'tiramisu-api': # FIXME - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('ip_admin_eth0.netmask_admin_eth0').value.set([None]) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('ip_admin_eth0.netmask_admin_eth0').value.pop(0) if config_type == 'tiramisu-api': cfg.send() @@ -608,7 +608,7 @@ def test_reset_values_with_leader_and_followers_default(config_type): cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('255.255.255.0') assert cfg.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owner assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == owner - with pytest.raises(APIError): + with pytest.raises(ConfigError): # index is mandatory cfg.option('ip_admin_eth0.netmask_admin_eth0').owner.get() cfg.option('ip_admin_eth0.ip_admin_eth0').value.reset() @@ -653,7 +653,7 @@ def test_values_with_leader_and_followers_follower(config_type): cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('255.255.255.0') if config_type != 'tiramisu-api': # FIXME - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.pop(1) #reset cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145', @@ -905,14 +905,14 @@ def test_wrong_index(): cfg = Config(od1) cfg.property.read_write() assert cfg.option('od.ip_admin_eth0.ip_admin_eth0').option.get() - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('od.ip_admin_eth0.ip_admin_eth0', 0).option.get() assert cfg.option('od.ip_admin_eth0.netmask_admin_eth0', 0).option.get() assert cfg.option('od.ip_admin_eth0').option.get() - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('od.ip_admin_eth0', 0).option.get() assert cfg.option('od').option.get() - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('od', 0).option.get() # assert not list_sessions() diff --git a/tests/test_metaconfig.py b/tests/test_metaconfig.py index bcc3fe3..6035c94 100644 --- a/tests/test_metaconfig.py +++ b/tests/test_metaconfig.py @@ -7,7 +7,7 @@ from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, BoolOpt IPOption, OptionDescription, Leadership, Config, GroupConfig, MetaConfig, \ Calculation, Params, ParamOption, ParamValue, calc_value, ParamSelfOption, \ valid_network_netmask, valid_not_equal -from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError +from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError from .config import config_type, get_config @@ -418,7 +418,7 @@ def test_not_meta(): GroupConfig([conf2, conf2], name='conf8') grp = GroupConfig([conf1, conf2]) assert grp.config.type() == 'groupconfig' - with pytest.raises(APIError): + with pytest.raises(ConfigError): grp.option('od1.i1').value.get() conf1, conf2 = grp.config.list() errors = grp.value.set('od1.i1', 7) @@ -547,7 +547,7 @@ def test_meta_leadership_value(): meta = MetaConfig([conf1, conf2], name="meta") conf1.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.8']) assert conf1.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None - with pytest.raises(APIError): + with pytest.raises(ConfigError): conf1.option('ip_admin_eth0.ip_admin_eth0', 0).value.get() # conf1.option('ip_admin_eth0.ip_admin_eth0').value.reset() diff --git a/tests/test_mixconfig.py b/tests/test_mixconfig.py index 2660bd8..3c8a46b 100644 --- a/tests/test_mixconfig.py +++ b/tests/test_mixconfig.py @@ -8,7 +8,7 @@ from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \ OptionDescription, Leadership, Config, GroupConfig, MixConfig, \ MetaConfig, Params, ParamOption, ParamValue, ParamSelfOption, Calculation, \ valid_network_netmask -from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError +from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError owners.addowner('mix1') owners.addowner('mix2') diff --git a/tests/test_option.py b/tests/test_option.py index ec044d5..b620b3b 100644 --- a/tests/test_option.py +++ b/tests/test_option.py @@ -6,9 +6,7 @@ do_autopath() import pytest import warnings -from tiramisu.error import ValueWarning, APIError - -from tiramisu.error import APIError, ConfigError +from tiramisu.error import ConfigError, ValueWarning from tiramisu import IntOption, SymLinkOption, OptionDescription, Config, Calculation, groups from tiramisu.i18n import _ @@ -71,9 +69,9 @@ def test_option_unknown(): od = OptionDescription('od', '', [i]) cfg = Config(od) # - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('test').unknown.get() - with pytest.raises(APIError): + with pytest.raises(ConfigError): # only choice cfg.option('test').value.list() @@ -267,9 +265,9 @@ def test_asign_optiondescription(): od1 = OptionDescription('od', '', [i]) od2 = OptionDescription('od', '', [od1]) cfg = Config(od2) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('od').value.set('test') - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('od').value.reset() # assert not list_sessions() @@ -322,5 +320,5 @@ def test_option_unknown_func(): i3 = IntOption('test3', 'description', min_number=3, max_number=6, warnings_only=True) od = OptionDescription('od', '', [i1, i2, i3]) cfg = Config(od) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('test1').value.unknown() diff --git a/tests/test_option_owner.py b/tests/test_option_owner.py index e1f1c95..6eeccf4 100644 --- a/tests/test_option_owner.py +++ b/tests/test_option_owner.py @@ -6,7 +6,7 @@ import pytest from tiramisu.setting import owners, groups from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ StrOption, OptionDescription, SymLinkOption, Leadership, Config -from tiramisu.error import ConfigError, ConstError, PropertiesOptionError, APIError +from tiramisu.error import ConfigError, ConstError, PropertiesOptionError from .config import config_type, get_config @@ -54,7 +54,7 @@ def test_owner_unknown_func(config_type): od1 = OptionDescription('tiramisu', '', [gcdummy]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): owner = cfg.option('dummy').owner.unknown() # assert not list_sessions() @@ -200,9 +200,9 @@ def test_setowner_optiondescription(config_type): od1 = OptionDescription('tiramisu', '', [descr1]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('tiramisu').owner.get() - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('tiramisu').owner.set('user') # assert not list_sessions() @@ -219,7 +219,7 @@ def test_setowner_symlinkoption(config_type): assert not cfg.option('tiramisu.symdummy').owner.isdefault() if config_type == 'tiramisu-api': cfg.send() - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg_ori.option('tiramisu.symdummy').owner.set('user') # assert not list_sessions() diff --git a/tests/test_permissive.py b/tests/test_permissive.py index 0885b96..b5e24e9 100644 --- a/tests/test_permissive.py +++ b/tests/test_permissive.py @@ -5,7 +5,7 @@ do_autopath() import pytest from tiramisu import IntOption, StrOption, OptionDescription, Config -from tiramisu.error import PropertiesOptionError, ConfigError, APIError +from tiramisu.error import PropertiesOptionError, ConfigError from .config import config_type, get_config @@ -21,7 +21,7 @@ def test_forcepermissive_and_unrestraint(config_type): cfg_ori.property.read_write() cfg_ori.property.read_write() cfg = get_config(cfg_ori, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg_ori.unrestraint.forcepermissive.add('disabled') diff --git a/tests/test_symlink.py b/tests/test_symlink.py index a66e9ac..0499346 100644 --- a/tests/test_symlink.py +++ b/tests/test_symlink.py @@ -6,7 +6,7 @@ from .config import config_type, get_config from tiramisu import BoolOption, StrOption, SymLinkOption, \ OptionDescription, Leadership, Config, Calculation, calc_value, Params, ParamOption, ParamValue -from tiramisu.error import PropertiesOptionError, ConfigError, APIError +from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.setting import groups, owners @@ -43,7 +43,7 @@ def test_symlink_assign_option(config_type): [linkopt, OptionDescription("s1", "", [boolopt])]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('c').value.set(True) # assert not list_sessions() @@ -55,7 +55,7 @@ def test_symlink_del_option(config_type): [linkopt, OptionDescription("s1", "", [boolopt])]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('c').value.reset() # assert not list_sessions() @@ -191,7 +191,7 @@ def test_symlink_assign(config_type): [linkopt, OptionDescription("s1", "", [boolopt])]) cfg = Config(od1) cfg = get_config(cfg, config_type) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('c').value.set(True) # assert not list_sessions() @@ -250,7 +250,7 @@ def test_symlink_with_leader(config_type): cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2']) assert cfg.value.dict() == {'ip_admin_eth0.ip_admin_eth0': [{'ip_admin_eth0.ip_admin_eth0': 'val1', 'ip_admin_eth0.netmask_admin_eth0': None}, {'ip_admin_eth0.ip_admin_eth0': 'val2', 'ip_admin_eth0.netmask_admin_eth0': None}], 'leader': ['val1', 'val2']} cfg.option('ip_admin_eth0.ip_admin_eth0').value.pop(0) - with pytest.raises(APIError): + with pytest.raises(ConfigError): cfg.option('leader').value.pop(0) # assert not list_sessions() @@ -269,13 +269,13 @@ def test_symlink_with_follower(config_type): # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == 'default' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).owner.get() == 'default' - with pytest.raises(APIError): + with pytest.raises(ConfigError): assert cfg.option('follower', 0).owner.get() == 'default' assert cfg.option('follower').owner.get() == 'default' # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == None - with pytest.raises(APIError): + with pytest.raises(ConfigError): assert cfg.option('follower', 0).value.get() == None assert cfg.option('follower').value.get() == [None, None] # @@ -284,13 +284,13 @@ def test_symlink_with_follower(config_type): # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'val3' - with pytest.raises(APIError): + with pytest.raises(ConfigError): assert cfg.option('follower', 0).value.get() == None assert cfg.option('follower').value.get() == [None, 'val3'] # assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).owner.get() == 'default' assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).owner.get() == 'user' - with pytest.raises(APIError): + with pytest.raises(ConfigError): assert cfg.option('follower', 0).owner.get() == 'default' assert cfg.option('follower').owner.get() == 'user' # assert not list_sessions() diff --git a/tiramisu/__init__.py b/tiramisu/__init__.py index e2dbb20..0686f7e 100644 --- a/tiramisu/__init__.py +++ b/tiramisu/__init__.py @@ -20,7 +20,7 @@ from .function import calc_value, calc_value_property_help, valid_ip_netmask, \ from .autolib import Calculation, Params, ParamOption, ParamDynOption, ParamSelfOption, \ ParamValue, ParamIndex, ParamSuffix, ParamInformation, ParamSelfInformation from .option import * -from .error import APIError +from .error import ConfigError from .api import Config, MetaConfig, GroupConfig, MixConfig from .option import __all__ as all_options from .setting import owners, groups, undefined @@ -40,7 +40,7 @@ allfuncs = ['Calculation', 'MixConfig', 'GroupConfig', 'Config', - 'APIError', + 'ConfigError', 'undefined', 'owners', 'groups', diff --git a/tiramisu/api.py b/tiramisu/api.py index e258c97..3078d69 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -22,7 +22,7 @@ from functools import wraps from copy import deepcopy -from .error import APIError, ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning +from .error import ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning from .i18n import _ from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, \ FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, EXPIRATION_TIME @@ -92,7 +92,7 @@ class CommonTiramisu(TiramisuHelp): self._validate_properties, ) except AssertionError as err: - raise APIError(str(err)) + raise ConfigError(str(err)) except Exception as err: raise err return options_bag @@ -136,13 +136,13 @@ def option_type(typ): option.get_type() == 'choice' and 'choice' in types)): if not option.impl_is_optiondescription() and not option.impl_is_symlinkoption() and option.impl_is_follower(): if 'with_index' in types and args[0]._index is not None: - raise APIError(_(f'please do not specify index ({args[0].__class__.__name__}.{func.__name__})')) + raise ConfigError(_(f'please do not specify index ({args[0].__class__.__name__}.{func.__name__})')) if 'with_index' not in types and args[0]._index is None: - raise APIError(_(f'please specify index with a follower option ({args[0].__class__.__name__}.{func.__name__})')) + raise ConfigError(_(f'please specify index with a follower option ({args[0].__class__.__name__}.{func.__name__})')) elif args[0]._index is not None: - raise APIError(_(f'please specify an index only for follower option ({args[0].__class__.__name__}.{func.__name__})')) + raise ConfigError(_(f'please specify an index only for follower option ({args[0].__class__.__name__}.{func.__name__})')) return func(args[0], options_bag, *args[1:], **kwargs) - raise APIError(_(f'please specify a valid sub function ({args[0].__class__.__name__}.{func.__name__})')) + raise ConfigError(_(f'please specify a valid sub function ({args[0].__class__.__name__}.{func.__name__})')) wrapped.func = func return wrapped return wrapper @@ -163,7 +163,7 @@ class CommonTiramisuOption(CommonTiramisu): self._config_bag = config_bag def __getattr__(self, subfunc): - raise APIError(_('please specify a valid sub function ({})').format(subfunc)) + raise ConfigError(_('please specify a valid sub function ({})').format(subfunc)) class _TiramisuOptionWalk: @@ -853,7 +853,7 @@ class TiramisuOption(CommonTiramisu, TiramisuConfig): self._index, self._config_bag, ) - raise APIError(_('please specify a valid sub function ({})').format(subfunc)) + raise ConfigError(_('please specify a valid sub function ({})').format(subfunc)) @option_type('optiondescription') def find(self, @@ -1522,7 +1522,7 @@ class TiramisuAPI(TiramisuHelp): self._orig_config_bags) elif subfunc in ['forcepermissive', 'unrestraint']: if self._orig_config_bags: - raise APIError(_('do not use unrestraint and forcepermissive together')) + raise ConfigError(_('do not use unrestraint and forcepermissive together')) config_bag = self._config_bag.copy() if subfunc == 'unrestraint': config_bag.unrestraint() @@ -1546,7 +1546,7 @@ class TiramisuAPI(TiramisuHelp): # del config_bag.permissives return self._registers[subfunc](config_bag, self._orig_config_bags) - raise APIError(_('please specify a valid sub function ({})').format(subfunc)) + raise ConfigError(_('please specify a valid sub function ({})').format(subfunc)) def __dir__(self): return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config'] diff --git a/tiramisu/config.py b/tiramisu/config.py index 4d49598..374c5eb 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -25,7 +25,7 @@ from typing import Optional, List, Any, Union from .error import PropertiesOptionError, ConfigError, ConflictError, \ - LeadershipError, APIError + LeadershipError from .option import SynDynOptionDescription, DynOptionDescription, Leadership, Option from .option.baseoption import BaseOption from .setting import OptionBag, ConfigBag, Settings, undefined, groups @@ -790,7 +790,7 @@ class _CommonConfig(_SubConfig): if idx == last_idx: if option_index is not None: if option.impl_is_optiondescription() or option.impl_is_symlinkoption() or not option.impl_is_follower(): - raise APIError('index must be set only with a follower option') + raise ConfigError('index must be set only with a follower option') if leadership_length is not None: length = leadership_length else: diff --git a/tiramisu/error.py b/tiramisu/error.py index 49857c9..7df1672 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -132,7 +132,8 @@ class ConfigError(Exception): or if a calculation cannot be carried out""" def __init__(self, exp, - ori_err=None): + ori_err=None, + ): super().__init__(exp) self.ori_err = ori_err @@ -209,7 +210,3 @@ class ValueOptionError(_CommonError, ValueError): class ValueErrorWarning(ValueWarning): tmpl = _('"{0}" is an invalid {1} for "{2}"') - - -class APIError(Exception): - pass