# *****************************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# ******************************************************************************
from dlab_core.domain.exceptions import DLabException
[docs]LC_ERR_ARGUMENT_TYPE_DICT = 'Argument must be of type dict.'
[docs]class RoutingException(DLabException):
"""Base class for Routing exceptions"""
pass
[docs]class RouteArgumentTypeException(RoutingException):
pass
[docs]class RouteArgumentKeyException(RoutingException):
pass
[docs]class RouteArgumentValueException(RoutingException):
pass
[docs]class RouteInvokeCallableException(RoutingException):
pass
[docs]class CLIRoute(object):
def __init__(self, invoke, arguments):
"""
:type invoke: callable
:param invoke: method that will be invoked by router
:type arguments: dict
:param arguments: command, split into an array of strings
"""
self.invoke = invoke
self.arguments = arguments
@property
[docs] def invoke(self):
"""
:rtype invoke: callable
:return invoke: method that will be invoked by router
"""
return self._invoke
@invoke.setter
def invoke(self, invoke):
"""
:type invoke: callable
:param invoke: method that will be invoked by router
"""
if not callable(invoke):
raise RouteInvokeCallableException()
self._invoke = invoke
@property
[docs] def arguments(self):
"""
:rtype arguments: dict
:return arguments: dict of arguments, where key is index of argument
and value - the argument itself
"""
return self._arguments
@arguments.setter
def arguments(self, arguments):
"""
:type arguments: dict
:param arguments: dict of arguments, where key is index of argument
and value - the argument itself
"""
if not isinstance(arguments, dict):
raise RouteArgumentTypeException(LC_ERR_ARGUMENT_TYPE_DICT)
for item in arguments.items():
self.validate_arguments_dict(*item)
self._arguments = arguments
@staticmethod
[docs] def validate_arguments_dict(key, value):
if not isinstance(key, int):
raise RouteArgumentKeyException(key)
if not isinstance(value, str):
raise RouteArgumentValueException(value)
[docs]class CLIRouter(object):
def __init__(self, routes=()):
self._routes = []
if len(routes):
for route in routes:
self.add(route)
[docs] def add(self, route):
"""
:type route: CLIRoute
:param route: Cli route.
"""
if isinstance(route, CLIRoute):
self._routes.append(route)
[docs] def match(self, args):
"""
:type args: list
:param args: command, split into an array of strings
:rtype Route
:return route matched by all parameters with maximum match size
"""
items = [r for r in self._routes if self.match_args(r.arguments, args)]
return self.extract_maximum_match(items)
@staticmethod
@staticmethod
[docs] def match_args(route_args, cli_args):
"""
:type route_args: dict
:param route_args: dict of route args
:type cli_args: list
:param cli_args: cli arguments
:rtype: bool
:returns True or False depending on matching cli args to routing args
If maximum route arguments index is less then cli args count and
values from cli equal corresponding indexes values return True
"""
return (max(route_args) < len(cli_args) and all(
[cli_args[index] == val for index, val in route_args.items()]))