From 851f56dc371f47a7486bc8e71f2e14af80a9b29a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20M=C3=A1tl?= Date: Fri, 12 Mar 2021 15:45:25 +0100 Subject: [PATCH] Fixed class method utils --- chamber/utils/__init__.py | 26 ++++++++++++------- example/Makefile | 5 ++-- .../apps/test_chamber/tests/utils/__init__.py | 26 +++++++++++++++++-- example/manage.py | 0 4 files changed, 43 insertions(+), 14 deletions(-) mode change 100644 => 100755 example/manage.py diff --git a/chamber/utils/__init__.py b/chamber/utils/__init__.py index 43df93a..c1f3f3c 100644 --- a/chamber/utils/__init__.py +++ b/chamber/utils/__init__.py @@ -10,6 +10,10 @@ from django.utils.text import normalize_newlines +class InvalidFunctionArguments(Exception): + pass + + def remove_accent(string_with_diacritics): """ Removes a diacritics from a given string" @@ -28,7 +32,7 @@ def get_class_method(cls_or_inst, method_name): meth = meth.fget elif isinstance(meth, cached_property): meth = meth.func - return meth + return meth if callable(meth) else None def keep_spacing(value, autoescape=True): @@ -43,15 +47,19 @@ def keep_spacing(value, autoescape=True): return mark_safe(value.replace(' ', '  ').replace('\n', '
')) -def call_method_with_unknown_input(method, **fun_kwargs): - method_kwargs_names = inspect.getargspec(method)[0][1:] - - method_kwargs = {arg_name: fun_kwargs[arg_name] for arg_name in method_kwargs_names if arg_name in fun_kwargs} - - if len(method_kwargs_names) == len(method_kwargs): - return method(**method_kwargs) +def call_function_with_unknown_input(function, **kwargs): + """ + Call function and use kwargs from input if function requires them. + :param function: function to call. + :param kwargs: function input kwargs or extra kwargs which will not be used. + :return: function result or raised InvalidFunctionArguments exception. + """ + function_kwargs_names = set(inspect.signature(function).parameters.keys()) + function_kwargs = {k: v for k, v in kwargs.items() if k in function_kwargs_names} + if len(function_kwargs_names) == len(function_kwargs): + return function(**function_kwargs) else: - raise RuntimeError('Invalid method parameters') + raise InvalidFunctionArguments('Function {} arguments has not subset of fun kwargs'.format(function)) def generate_container_app_config(name,): diff --git a/example/Makefile b/example/Makefile index a313b18..e15bcb3 100644 --- a/example/Makefile +++ b/example/Makefile @@ -13,7 +13,7 @@ SETTINGS = settings DJANGO_SETTINGS_MODULE = $(DJANGO_DIR).settings.$(SETTINGS) DJANGO_POSTFIX = --settings=$(DJANGO_SETTINGS_MODULE) --pythonpath=$(PYTHONPATH) PYTHON_BIN = $(VIRTUAL_ENV)/bin -PYTHON = python3.7 +PYTHON = python3 PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) PYTHON_VERSION_MAJOR := $(word 1,${PYTHON_VERSION_FULL}).$(word 2,${PYTHON_VERSION_FULL}) TYPE = dev @@ -40,8 +40,7 @@ pip: $(PYTHON_BIN)/pip install -r requirements.txt initvirtualenv: - virtualenv -p $(PYTHON) --no-site-packages $(VIRTUAL_ENV) - $(PYTHON_BIN)/pip install setuptools --upgrade + virtualenv -p $(PYTHON) $(VIRTUAL_ENV) bootstrap: initvirtualenv pip diff --git a/example/dj/apps/test_chamber/tests/utils/__init__.py b/example/dj/apps/test_chamber/tests/utils/__init__.py index 88306f0..f51096f 100644 --- a/example/dj/apps/test_chamber/tests/utils/__init__.py +++ b/example/dj/apps/test_chamber/tests/utils/__init__.py @@ -3,8 +3,11 @@ from django.test import TestCase from django.utils.functional import cached_property from django.utils.safestring import SafeData, mark_safe +from django.utils.functional import cached_property -from chamber.utils import get_class_method, keep_spacing, remove_accent +from chamber.utils import ( + get_class_method, keep_spacing, remove_accent, call_function_with_unknown_input, InvalidFunctionArguments +) from germanium.decorators import data_provider # pylint: disable=E0401 from germanium.tools import assert_equal, assert_true # pylint: disable=E0401 @@ -26,6 +29,8 @@ def property_method(self): def cached_property_method(self): pass + attribute = 'attribute' + class UtilsTestCase(TestCase): @@ -49,10 +54,14 @@ def test_should_remove_accent_from_string_when_unicode_error(self): [TestClass.property_method.fget, TestClass(), 'property_method'], [TestClass.cached_property_method.func, TestClass, 'cached_property_method'], [TestClass.cached_property_method.func, TestClass(), 'cached_property_method'], + [None, TestClass, 'attribute'], + [None, TestClass(), 'attribute'], + [None, TestClass, 'invalid'], + [None, TestClass(), 'invalid'], ] @data_provider(classes_and_method_names) - def test_should_return_class_method(self, expected_method, cls_or_inst, method_name): + def test_get_class_method_should_return_right_class_method_or_none(self, expected_method, cls_or_inst, method_name): assert_equal(expected_method, get_class_method(cls_or_inst, method_name)) values_for_keep_spacing = [ @@ -68,3 +77,16 @@ def test_should_keep_spacing(self, expected, value, autoescape): escaped_value = keep_spacing(value, autoescape) assert_equal(expected, escaped_value) assert_true(isinstance(escaped_value, SafeData)) + + def test_call_function_with_unknown_input_should_return_right_response_or_exception(self): + def test_function(a, b, c): + assert_equal(a, 3) + assert_equal(b, 2) + assert_equal(c, 1) + + call_function_with_unknown_input(test_function, a=3, b=2, c=1) + call_function_with_unknown_input(test_function, c=1, a=3, b=2) + call_function_with_unknown_input(test_function, c=1, a=3, b=2, d=8, e=9) + + with assert_raises(InvalidFunctionArguments): + call_function_with_unknown_input(test_function, a=3, b=2) diff --git a/example/manage.py b/example/manage.py old mode 100644 new mode 100755