From dc74ba66284c1c4e0e1038cf8eb0184c3d5b2ebf Mon Sep 17 00:00:00 2001 From: Timothy Crosley Date: Wed, 21 Sep 2016 22:39:34 -0700 Subject: [PATCH] Fully working cli support for objects --- hug/__init__.py | 2 +- hug/route.py | 28 ++++++++++++++++------------ tests/test_route.py | 44 +++++++++++++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/hug/__init__.py b/hug/__init__.py index 4d3935e2..cb9a4e0b 100644 --- a/hug/__init__.py +++ b/hug/__init__.py @@ -40,7 +40,7 @@ from hug.decorators import (default_input_format, default_output_format, directive, extend_api, middleware_class, request_middleware, response_middleware, startup, wraps) from hug.route import (call, cli, connect, delete, exception, get, get_post, head, http, local, - not_found, object, cli_object, options, patch, post, put, sink, static, trace) + not_found, object, options, patch, post, put, sink, static, trace) from hug.types import create as type from hug import development_runner # isort:skip diff --git a/hug/route.py b/hug/route.py index 05aa2574..9edbf74a 100644 --- a/hug/route.py +++ b/hug/route.py @@ -42,7 +42,10 @@ class Object(http): def __init__(self, urls=None, accept=HTTP_METHODS, output=None, **kwargs): super().__init__(urls=urls, accept=accept, output=output, **kwargs) - def __call__(self, method_or_class): + def __call__(self, method_or_class=None, **kwargs): + if not method_or_class and kwargs: + return self.where(**kwargs) + if isinstance(method_or_class, (MethodType, FunctionType)): routes = getattr(method_or_class, '_hug_http_routes', []) routes.append(self.route) @@ -56,13 +59,13 @@ def __call__(self, method_or_class): for argument in dir(instance): argument = getattr(instance, argument, None) - http_routes = getattr(handler, '_hug_http_routes', ()) + http_routes = getattr(argument, '_hug_http_routes', ()) for route in http_routes: - http(**router.accept(method).where(**route).route)(handler) + http(**self.where(**route).route)(argument) cli_routes = getattr(argument, '_hug_cli_routes', ()) for route in cli_routes: - cli(**router.accept(method).where(**route).route)(handler) + cli(**self.where(**route).route)(argument) return method_or_class @@ -78,23 +81,25 @@ def decorator(class_definition): handler = getattr(instance, method.lower(), None) if handler: http_routes = getattr(handler, '_hug_http_routes', ()) - cli_routes = getattr(argument, '_hug_cli_routes', ()) - if http_routes or cli_routes: + if http_routes: for route in http_routes: http(**router.accept(method).where(**route).route)(handler) - for route in cli_routes: - cli(**router.accept(method).where(**route).route)(handler) else: http(**router.accept(method).route)(handler) + + cli_routes = getattr(handler, '_hug_cli_routes', ()) + if cli_routes: + for route in cli_routes: + cli(**self.where(**route).route)(handler) return class_definition return decorator def cli(self, method): """Registers a method on an Object as a CLI route""" - routes = getattr(method_or_class, '_hug_cli_routes', []) + routes = getattr(method, '_hug_cli_routes', []) routes.append(self.route) - method_or_class._hug_cli_routes = routes - return method_or_class + method._hug_cli_routes = routes + return method class API(object): @@ -227,7 +232,6 @@ def put_post(self, *kargs, **kwargs): put_post.__doc__ = "Exposes a Python method externally under both the HTTP POST and PUT methods" object = Object() -cli_object = CLIObject # DEPRECATED: for backwords compatibility with hug 1.x.x call = http diff --git a/tests/test_route.py b/tests/test_route.py index 7d7dc3f5..14d2fda0 100644 --- a/tests/test_route.py +++ b/tests/test_route.py @@ -73,25 +73,39 @@ def post(self): assert hug.test.post(api, 'home').data == 'bye' -class TestCLIObject(object): - """A set of tests to ensure CLI class based routing works as intended""" +def test_routing_class_with_cli_commands(): + """Basic operation test""" + @hug.object(name='git', version='1.0.0') + class GIT(object): + """An example of command like calls via an Object""" - def test_commands(self): - """Basic operation test""" - @hug.object(name='git', version='1.0.0') - class GIT(object): - """An example of command like calls via an Object""" + @hug.object.cli + def push(self, branch='master'): + return 'Pushing {}'.format(branch) - @hug.object.cli - def push(self, branch='master'): - return 'Pushing {}'.format(branch) + @hug.object.cli + def pull(self, branch='master'): + return 'Pulling {}'.format(branch) - @hug.object.cli - def pull(self, branch='master'): - return 'Pulling {}'.format(branch) + assert 'token' in hug.test.cli(GIT.push, branch='token') + assert 'another token' in hug.test.cli(GIT.pull, branch='another token') - assert 'token' in hug.test.cli(GIT.push, branch='token') - assert 'another token' in hug.test.cli(GIT.pull, branch='another token') + +def test_routing_class_based_method_view_with_cli_routing(): + """Test creating class based routers using method mappings exposing cli endpoints""" + @hug.object.http_methods() + class EndPoint(object): + + @hug.object.cli + def get(self): + return 'hi there!' + + def post(self): + return 'bye' + + assert hug.test.get(api, 'endpoint').data == 'hi there!' + assert hug.test.post(api, 'endpoint').data == 'bye' + assert hug.test.cli(EndPoint.get) == 'hi there!' def test_routing_instance():