Re-type config paths in `ConfigError`s to be `StrSequence`s (#15615)
Part of #14809. Signed-off-by: Sean Quah <seanq@matrix.org>
This commit is contained in:
parent
e15aa00bc0
commit
68dcd2cbcb
|
@ -0,0 +1 @@
|
||||||
|
Re-type config paths in `ConfigError`s to be `StrSequence`s instead of `Iterable[str]`s.
|
|
@ -44,6 +44,7 @@ import jinja2
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from synapse.types import StrSequence
|
||||||
from synapse.util.templates import _create_mxc_to_http_filter, _format_ts_filter
|
from synapse.util.templates import _create_mxc_to_http_filter, _format_ts_filter
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -58,7 +59,7 @@ class ConfigError(Exception):
|
||||||
the problem lies.
|
the problem lies.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg: str, path: Optional[Iterable[str]] = None):
|
def __init__(self, msg: str, path: Optional[StrSequence] = None):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
|
|
@ -61,9 +61,10 @@ from synapse.config import ( # noqa: F401
|
||||||
voip,
|
voip,
|
||||||
workers,
|
workers,
|
||||||
)
|
)
|
||||||
|
from synapse.types import StrSequence
|
||||||
|
|
||||||
class ConfigError(Exception):
|
class ConfigError(Exception):
|
||||||
def __init__(self, msg: str, path: Optional[Iterable[str]] = None):
|
def __init__(self, msg: str, path: Optional[StrSequence] = None):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,17 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# 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 typing import Any, Dict, Iterable, Type, TypeVar
|
from typing import Any, Dict, Type, TypeVar
|
||||||
|
|
||||||
import jsonschema
|
import jsonschema
|
||||||
from pydantic import BaseModel, ValidationError, parse_obj_as
|
from pydantic import BaseModel, ValidationError, parse_obj_as
|
||||||
|
|
||||||
from synapse.config._base import ConfigError
|
from synapse.config._base import ConfigError
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict, StrSequence
|
||||||
|
|
||||||
|
|
||||||
def validate_config(
|
def validate_config(
|
||||||
json_schema: JsonDict, config: Any, config_path: Iterable[str]
|
json_schema: JsonDict, config: Any, config_path: StrSequence
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Validates a config setting against a JsonSchema definition
|
"""Validates a config setting against a JsonSchema definition
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ def validate_config(
|
||||||
|
|
||||||
|
|
||||||
def json_error_to_config_error(
|
def json_error_to_config_error(
|
||||||
e: jsonschema.ValidationError, config_path: Iterable[str]
|
e: jsonschema.ValidationError, config_path: StrSequence
|
||||||
) -> ConfigError:
|
) -> ConfigError:
|
||||||
"""Converts a json validation error to a user-readable ConfigError
|
"""Converts a json validation error to a user-readable ConfigError
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ from urllib import parse as urlparse
|
||||||
import attr
|
import attr
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict, StrSequence
|
||||||
|
|
||||||
from ._base import Config, ConfigError
|
from ._base import Config, ConfigError
|
||||||
from ._util import validate_config
|
from ._util import validate_config
|
||||||
|
@ -80,7 +80,7 @@ class OembedConfig(Config):
|
||||||
)
|
)
|
||||||
|
|
||||||
def _parse_and_validate_provider(
|
def _parse_and_validate_provider(
|
||||||
self, providers: List[JsonDict], config_path: Iterable[str]
|
self, providers: List[JsonDict], config_path: StrSequence
|
||||||
) -> Iterable[OEmbedEndpointConfig]:
|
) -> Iterable[OEmbedEndpointConfig]:
|
||||||
# Ensure it is the proper form.
|
# Ensure it is the proper form.
|
||||||
validate_config(
|
validate_config(
|
||||||
|
@ -112,7 +112,7 @@ class OembedConfig(Config):
|
||||||
api_endpoint, patterns, endpoint.get("formats")
|
api_endpoint, patterns, endpoint.get("formats")
|
||||||
)
|
)
|
||||||
|
|
||||||
def _glob_to_pattern(self, glob: str, config_path: Iterable[str]) -> Pattern:
|
def _glob_to_pattern(self, glob: str, config_path: StrSequence) -> Pattern:
|
||||||
"""
|
"""
|
||||||
Convert the glob into a sane regular expression to match against. The
|
Convert the glob into a sane regular expression to match against. The
|
||||||
rules followed will be slightly different for the domain portion vs.
|
rules followed will be slightly different for the domain portion vs.
|
||||||
|
|
|
@ -27,7 +27,7 @@ from netaddr import AddrFormatError, IPNetwork, IPSet
|
||||||
from twisted.conch.ssh.keys import Key
|
from twisted.conch.ssh.keys import Key
|
||||||
|
|
||||||
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
|
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict, StrSequence
|
||||||
from synapse.util.module_loader import load_module
|
from synapse.util.module_loader import load_module
|
||||||
from synapse.util.stringutils import parse_and_validate_server_name
|
from synapse.util.stringutils import parse_and_validate_server_name
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ def _6to4(network: IPNetwork) -> IPNetwork:
|
||||||
def generate_ip_set(
|
def generate_ip_set(
|
||||||
ip_addresses: Optional[Iterable[str]],
|
ip_addresses: Optional[Iterable[str]],
|
||||||
extra_addresses: Optional[Iterable[str]] = None,
|
extra_addresses: Optional[Iterable[str]] = None,
|
||||||
config_path: Optional[Iterable[str]] = None,
|
config_path: Optional[StrSequence] = None,
|
||||||
) -> IPSet:
|
) -> IPSet:
|
||||||
"""
|
"""
|
||||||
Generate an IPSet from a list of IP addresses or CIDRs.
|
Generate an IPSet from a list of IP addresses or CIDRs.
|
||||||
|
|
|
@ -84,7 +84,15 @@ JsonSerializable = object
|
||||||
|
|
||||||
# Collection[str] that does not include str itself; str being a Sequence[str]
|
# Collection[str] that does not include str itself; str being a Sequence[str]
|
||||||
# is very misleading and results in bugs.
|
# is very misleading and results in bugs.
|
||||||
|
#
|
||||||
|
# StrCollection is an unordered collection of strings. If ordering is important,
|
||||||
|
# StrSequence can be used instead.
|
||||||
StrCollection = Union[Tuple[str, ...], List[str], AbstractSet[str]]
|
StrCollection = Union[Tuple[str, ...], List[str], AbstractSet[str]]
|
||||||
|
# Sequence[str] that does not include str itself; str being a Sequence[str]
|
||||||
|
# is very misleading and results in bugs.
|
||||||
|
#
|
||||||
|
# Unlike StrCollection, StrSequence is an ordered collection of strings.
|
||||||
|
StrSequence = Union[Tuple[str, ...], List[str]]
|
||||||
|
|
||||||
|
|
||||||
# Note that this seems to require inheriting *directly* from Interface in order
|
# Note that this seems to require inheriting *directly* from Interface in order
|
||||||
|
|
|
@ -14,17 +14,17 @@
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import itertools
|
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Any, Iterable, Tuple, Type
|
from typing import Any, Tuple, Type
|
||||||
|
|
||||||
import jsonschema
|
import jsonschema
|
||||||
|
|
||||||
from synapse.config._base import ConfigError
|
from synapse.config._base import ConfigError
|
||||||
from synapse.config._util import json_error_to_config_error
|
from synapse.config._util import json_error_to_config_error
|
||||||
|
from synapse.types import StrSequence
|
||||||
|
|
||||||
|
|
||||||
def load_module(provider: dict, config_path: Iterable[str]) -> Tuple[Type, Any]:
|
def load_module(provider: dict, config_path: StrSequence) -> Tuple[Type, Any]:
|
||||||
"""Loads a synapse module with its config
|
"""Loads a synapse module with its config
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -39,9 +39,7 @@ def load_module(provider: dict, config_path: Iterable[str]) -> Tuple[Type, Any]:
|
||||||
|
|
||||||
modulename = provider.get("module")
|
modulename = provider.get("module")
|
||||||
if not isinstance(modulename, str):
|
if not isinstance(modulename, str):
|
||||||
raise ConfigError(
|
raise ConfigError("expected a string", path=tuple(config_path) + ("module",))
|
||||||
"expected a string", path=itertools.chain(config_path, ("module",))
|
|
||||||
)
|
|
||||||
|
|
||||||
# We need to import the module, and then pick the class out of
|
# We need to import the module, and then pick the class out of
|
||||||
# that, so we split based on the last dot.
|
# that, so we split based on the last dot.
|
||||||
|
@ -55,19 +53,17 @@ def load_module(provider: dict, config_path: Iterable[str]) -> Tuple[Type, Any]:
|
||||||
try:
|
try:
|
||||||
provider_config = provider_class.parse_config(module_config)
|
provider_config = provider_class.parse_config(module_config)
|
||||||
except jsonschema.ValidationError as e:
|
except jsonschema.ValidationError as e:
|
||||||
raise json_error_to_config_error(
|
raise json_error_to_config_error(e, tuple(config_path) + ("config",))
|
||||||
e, itertools.chain(config_path, ("config",))
|
|
||||||
)
|
|
||||||
except ConfigError as e:
|
except ConfigError as e:
|
||||||
raise _wrap_config_error(
|
raise _wrap_config_error(
|
||||||
"Failed to parse config for module %r" % (modulename,),
|
"Failed to parse config for module %r" % (modulename,),
|
||||||
prefix=itertools.chain(config_path, ("config",)),
|
prefix=tuple(config_path) + ("config",),
|
||||||
e=e,
|
e=e,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
"Failed to parse config for module %r" % (modulename,),
|
"Failed to parse config for module %r" % (modulename,),
|
||||||
path=itertools.chain(config_path, ("config",)),
|
path=tuple(config_path) + ("config",),
|
||||||
) from e
|
) from e
|
||||||
else:
|
else:
|
||||||
provider_config = module_config
|
provider_config = module_config
|
||||||
|
@ -92,9 +88,7 @@ def load_python_module(location: str) -> ModuleType:
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
|
||||||
def _wrap_config_error(
|
def _wrap_config_error(msg: str, prefix: StrSequence, e: ConfigError) -> "ConfigError":
|
||||||
msg: str, prefix: Iterable[str], e: ConfigError
|
|
||||||
) -> "ConfigError":
|
|
||||||
"""Wrap a relative ConfigError with a new path
|
"""Wrap a relative ConfigError with a new path
|
||||||
|
|
||||||
This is useful when we have a ConfigError with a relative path due to a problem
|
This is useful when we have a ConfigError with a relative path due to a problem
|
||||||
|
@ -102,7 +96,7 @@ def _wrap_config_error(
|
||||||
"""
|
"""
|
||||||
path = prefix
|
path = prefix
|
||||||
if e.path:
|
if e.path:
|
||||||
path = itertools.chain(prefix, e.path)
|
path = tuple(prefix) + tuple(e.path)
|
||||||
|
|
||||||
e1 = ConfigError(msg, path)
|
e1 = ConfigError(msg, path)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue