From ef7cfef94e2db9b11ebcc7ebb5e49d3c654e1f2d Mon Sep 17 00:00:00 2001 From: MBounouar Date: Wed, 18 Jan 2023 22:10:19 +0100 Subject: [PATCH] remove argcheck (#161) --- src/zipline/utils/argcheck.py | 351 ---------------------------------- tests/utils/test_argcheck.py | 284 --------------------------- 2 files changed, 635 deletions(-) delete mode 100644 src/zipline/utils/argcheck.py delete mode 100644 tests/utils/test_argcheck.py diff --git a/src/zipline/utils/argcheck.py b/src/zipline/utils/argcheck.py deleted file mode 100644 index 33faebee58..0000000000 --- a/src/zipline/utils/argcheck.py +++ /dev/null @@ -1,351 +0,0 @@ -# -# Copyright 2014 Quantopian, Inc. -# -# Licensed 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 collections import namedtuple -from itertools import chain, zip_longest - -from zipline.errors import ZiplineError -from zipline.utils.compat import getargspec - - -Argspec = namedtuple("Argspec", ["args", "starargs", "kwargs"]) - - -def singleton(cls): - instances = {} - - def getinstance(): - if cls not in instances: - instances[cls] = cls() - return instances[cls] - - return getinstance - - -@singleton -class Ignore: - def __str__(self): - return "Argument.ignore" - - __repr__ = __str__ - - -@singleton -class NoDefault: - def __str__(self): - return "Argument.no_default" - - __repr__ = __str__ - - -@singleton -class AnyDefault: - def __str__(self): - return "Argument.any_default" - - __repr__ = __str__ - - -class Argument(namedtuple("Argument", ["name", "default"])): - """ - An argument to a function. - Argument.no_default is a value representing no default to the argument. - Argument.ignore is a value that says you should ignore the default value. - """ - - no_default = NoDefault() - any_default = AnyDefault() - ignore = Ignore() - - def __new__(cls, name=ignore, default=ignore): - return super(Argument, cls).__new__(cls, name, default) - - def __str__(self): - if self.has_no_default(self) or self.ignore_default(self): - return str(self.name) - else: - return "=".join([str(self.name), str(self.default)]) - - def __repr__(self): - return "Argument(%s, %s)" % (repr(self.name), repr(self.default)) - - def _defaults_match(self, arg): - return ( - any(map(Argument.ignore_default, [self, arg])) - or ( - self.default is Argument.any_default - and arg.default is not Argument.no_default - ) - or ( - arg.default is Argument.any_default - and self.default is not Argument.no_default - ) - or self.default == arg.default - ) - - def _names_match(self, arg): - return ( - self.name == arg.name - or self.name is Argument.ignore - or arg.name is Argument.ignore - ) - - def matches(self, arg): - return self._names_match(arg) and self._defaults_match(arg) - - __eq__ = matches - - @staticmethod - def parse_argspec(callable_): - """ - Takes a callable and returns a tuple with the list of Argument objects, - the name of *args, and the name of **kwargs. - If *args or **kwargs is not present, it will be None. - This returns a namedtuple called Argspec that has three fields named: - args, starargs, and kwargs. - """ - args, varargs, keywords, defaults = getargspec(callable_) - defaults = list(defaults or []) - - if getattr(callable_, "__self__", None) is not None: - # This is a bound method, drop the self param. - args = args[1:] - - first_default = len(args) - len(defaults) - return Argspec( - [ - Argument( - arg, - Argument.no_default - if n < first_default - else defaults[n - first_default], - ) - for n, arg in enumerate(args) - ], - varargs, - keywords, - ) - - @staticmethod - def has_no_default(arg): - return arg.default is Argument.no_default - - @staticmethod - def ignore_default(arg): - return arg.default is Argument.ignore - - -def _expect_extra(expected, present, exc_unexpected, exc_missing, exc_args): - """ - Checks for the presence of an extra to the argument list. Raises expections - if this is unexpected or if it is missing and expected. - """ - if present: - if not expected: - raise exc_unexpected(*exc_args) - elif expected and expected is not Argument.ignore: - raise exc_missing(*exc_args) - - -def verify_callable_argspec( - callable_, - expected_args=Argument.ignore, - expect_starargs=Argument.ignore, - expect_kwargs=Argument.ignore, -): - """ - Checks the callable_ to make sure that it satisfies the given - expectations. - expected_args should be an iterable of Arguments in the order you expect to - receive them. - expect_starargs means that the function should or should not take a *args - param. expect_kwargs says the callable should or should not take **kwargs - param. - If expected_args, expect_starargs, or expect_kwargs is Argument.ignore, - then the checks related to that argument will not occur. - - Example usage: - - callable_check( - f, - [Argument('a'), Argument('b', 1)], - expect_starargs=True, - expect_kwargs=Argument.ignore - ) - """ - if not callable(callable_): - raise NotCallable(callable_) - - expected_arg_list = list( - expected_args if expected_args is not Argument.ignore else [] - ) - - args, starargs, kwargs = Argument.parse_argspec(callable_) - - exc_args = callable_, args, starargs, kwargs - - # Check the *args. - _expect_extra( - expect_starargs, - starargs, - UnexpectedStarargs, - NoStarargs, - exc_args, - ) - # Check the **kwargs. - _expect_extra( - expect_kwargs, - kwargs, - UnexpectedKwargs, - NoKwargs, - exc_args, - ) - - if expected_args is Argument.ignore: - # Ignore the argument list checks. - return - - if len(args) < len(expected_arg_list): - # One or more argument that we expected was not present. - raise NotEnoughArguments( - callable_, - args, - starargs, - kwargs, - [arg for arg in expected_arg_list if arg not in args], - ) - elif len(args) > len(expected_arg_list): - raise TooManyArguments(callable_, args, starargs, kwargs) - - # Empty argument that will not match with any actual arguments. - missing_arg = Argument(object(), object()) - - for expected, provided in zip_longest( - expected_arg_list, args, fillvalue=missing_arg - ): - if not expected.matches(provided): - raise MismatchedArguments(callable_, args, starargs, kwargs) - - -class BadCallable(TypeError, AssertionError, ZiplineError): - """ - The given callable is not structured in the expected way. - """ - - _lambda_name = (lambda: None).__name__ - - def __init__(self, callable_, args, starargs, kwargs): - self.callable_ = callable_ - self.args = args - self.starargs = starargs - self.kwargsname = kwargs - - self.kwargs = {} - - def format_callable(self): - if self.callable_.__name__ == self._lambda_name: - fmt = "%s %s" - name = "lambda" - else: - fmt = "%s(%s)" - name = self.callable_.__name__ - - return fmt % ( - name, - ", ".join( - chain( - (str(arg) for arg in self.args), - ("*" + sa for sa in (self.starargs,) if sa is not None), - ("**" + ka for ka in (self.kwargsname,) if ka is not None), - ) - ), - ) - - @property - def msg(self): - return str(self) - - -class NoStarargs(BadCallable): - def __str__(self): - return "%s does not allow for *args" % self.format_callable() - - -class UnexpectedStarargs(BadCallable): - def __str__(self): - return "%s should not allow for *args" % self.format_callable() - - -class NoKwargs(BadCallable): - def __str__(self): - return "%s does not allow for **kwargs" % self.format_callable() - - -class UnexpectedKwargs(BadCallable): - def __str__(self): - return "%s should not allow for **kwargs" % self.format_callable() - - -class NotCallable(BadCallable): - """ - The provided 'callable' is not actually a callable. - """ - - def __init__(self, callable_): - self.callable_ = callable_ - - def __str__(self): - return "%s is not callable" % self.format_callable() - - def format_callable(self): - try: - return self.callable_.__name__ - except AttributeError: - return str(self.callable_) - - -class NotEnoughArguments(BadCallable): - """ - The callback does not accept enough arguments. - """ - - def __init__(self, callable_, args, starargs, kwargs, missing_args): - super(NotEnoughArguments, self).__init__(callable_, args, starargs, kwargs) - self.missing_args = missing_args - - def __str__(self): - missing_args = list(map(str, self.missing_args)) - return "%s is missing argument%s: %s" % ( - self.format_callable(), - "s" if len(missing_args) > 1 else "", - ", ".join(missing_args), - ) - - -class TooManyArguments(BadCallable): - """ - The callback cannot be called by passing the expected number of arguments. - """ - - def __str__(self): - return "%s accepts too many arguments" % self.format_callable() - - -class MismatchedArguments(BadCallable): - """ - The argument lists are of the same lengths, but not in the correct order. - """ - - def __str__(self): - return "%s accepts mismatched parameters" % self.format_callable() diff --git a/tests/utils/test_argcheck.py b/tests/utils/test_argcheck.py deleted file mode 100644 index b3aa48c00b..0000000000 --- a/tests/utils/test_argcheck.py +++ /dev/null @@ -1,284 +0,0 @@ -# -# Copyright 2014 Quantopian, Inc. -# -# Licensed 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 zipline.utils.argcheck import ( - verify_callable_argspec, - Argument, - NoStarargs, - UnexpectedStarargs, - NoKwargs, - UnexpectedKwargs, - NotCallable, - NotEnoughArguments, - TooManyArguments, - MismatchedArguments, -) - -import pytest - - -class TestArgCheck: - def test_not_callable(self): - """ - Check the results of a non-callable object. - """ - not_callable = "a" - - with pytest.raises(NotCallable): - verify_callable_argspec(not_callable) - - def test_no_starargs(self): - """ - Tests when a function does not have *args and it was expected. - """ - - def f(a): - pass - - with pytest.raises(NoStarargs): - verify_callable_argspec(f, expect_starargs=True) - - def test_starargs(self): - """ - Tests when a function has *args and it was expected. - """ - - def f(*args): - pass - - verify_callable_argspec(f, expect_starargs=True) - - def test_unexcpected_starargs(self): - """ - Tests a function that unexpectedly accepts *args. - """ - - def f(*args): - pass - - with pytest.raises(UnexpectedStarargs): - verify_callable_argspec(f, expect_starargs=False) - - def test_ignore_starargs(self): - """ - Tests checking a function ignoring the presence of *args. - """ - - def f(*args): - pass - - def g(): - pass - - verify_callable_argspec(f, expect_starargs=Argument.ignore) - verify_callable_argspec(g, expect_starargs=Argument.ignore) - - def test_no_kwargs(self): - """ - Tests when a function does not have **kwargs and it was expected. - """ - - def f(): - pass - - with pytest.raises(NoKwargs): - verify_callable_argspec(f, expect_kwargs=True) - - def test_kwargs(self): - """ - Tests when a function has **kwargs and it was expected. - """ - - def f(**kwargs): - pass - - verify_callable_argspec(f, expect_kwargs=True) - - def test_unexpected_kwargs(self): - """ - Tests a function that unexpectedly accepts **kwargs. - """ - - def f(**kwargs): - pass - - with pytest.raises(UnexpectedKwargs): - verify_callable_argspec(f, expect_kwargs=False) - - def test_ignore_kwargs(self): - """ - Tests checking a function ignoring the presence of **kwargs. - """ - - def f(**kwargs): - pass - - def g(): - pass - - verify_callable_argspec(f, expect_kwargs=Argument.ignore) - verify_callable_argspec(g, expect_kwargs=Argument.ignore) - - def test_arg_subset(self): - """ - Tests when the args are a subset of the expectations. - """ - - def f(a, b): - pass - - with pytest.raises(NotEnoughArguments): - verify_callable_argspec(f, [Argument("a"), Argument("b"), Argument("c")]) - - def test_arg_superset(self): - def f(a, b, c): - pass - - with pytest.raises(TooManyArguments): - verify_callable_argspec(f, [Argument("a"), Argument("b")]) - - def test_no_default(self): - """ - Tests when an argument expects a default and it is not present. - """ - - def f(a): - pass - - with pytest.raises(MismatchedArguments): - verify_callable_argspec(f, [Argument("a", 1)]) - - def test_default(self): - """ - Tests when an argument expects a default and it is present. - """ - - def f(a=1): - pass - - verify_callable_argspec(f, [Argument("a", 1)]) - - def test_ignore_default(self): - """ - Tests that ignoring defaults works as intended. - """ - - def f(a=1): - pass - - verify_callable_argspec(f, [Argument("a")]) - - def test_mismatched_args(self): - def f(a, b): - pass - - with pytest.raises(MismatchedArguments): - verify_callable_argspec(f, [Argument("c"), Argument("d")]) - - def test_ignore_args(self): - """ - Tests the ignore argument list feature. - """ - - def f(a): - pass - - def g(): - pass - - h = "not_callable" - - verify_callable_argspec(f) - verify_callable_argspec(g) - with pytest.raises(NotCallable): - verify_callable_argspec(h) - - def test_out_of_order(self): - """ - Tests the case where arguments are not in the correct order. - """ - - def f(a, b): - pass - - with pytest.raises(MismatchedArguments): - verify_callable_argspec(f, [Argument("b"), Argument("a")]) - - def test_wrong_default(self): - """ - Tests the case where a default is expected, but the default provided - does not match the one expected. - """ - - def f(a=1): - pass - - with pytest.raises(MismatchedArguments): - verify_callable_argspec(f, [Argument("a", 2)]) - - def test_any_default(self): - """ - Tests the any_default option. - """ - - def f(a=1): - pass - - def g(a=2): - pass - - def h(a): - pass - - expected_args = [Argument("a", Argument.any_default)] - verify_callable_argspec(f, expected_args) - verify_callable_argspec(g, expected_args) - with pytest.raises(MismatchedArguments): - verify_callable_argspec(h, expected_args) - - def test_ignore_name(self): - """ - Tests ignoring a param name. - """ - - def f(a): - pass - - def g(b): - pass - - def h(c=1): - pass - - expected_args = [Argument(Argument.ignore, Argument.no_default)] - verify_callable_argspec(f, expected_args) - verify_callable_argspec(f, expected_args) - with pytest.raises(MismatchedArguments): - verify_callable_argspec(h, expected_args) - - def test_bound_method(self): - class C: - def f(self, a, b): - pass - - method = C().f - - verify_callable_argspec(method, [Argument("a"), Argument("b")]) - with pytest.raises(NotEnoughArguments): - # Assert that we don't count self. - verify_callable_argspec( - method, - [Argument("self"), Argument("a"), Argument("b")], - )