Skip to content
Snippets Groups Projects
Commit 6e6d8506 authored by Piotr Maślanka's avatar Piotr Maślanka
Browse files

some tests

parent 4db89f23
No related branches found
No related tags found
No related merge requests found
...@@ -4,12 +4,185 @@ Decorator for debug-time typechecking ...@@ -4,12 +4,185 @@ Decorator for debug-time typechecking
""" """
from __future__ import print_function, absolute_import, division from __future__ import print_function, absolute_import, division
import six import six
import inspect
import logging import logging
import itertools
try:
import typing
except ImportError:
from backports import typing
import types import types
from collections import namedtuple
import functools import functools
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
List = typing.List
Tuple = typing.Tuple
Dict = typing.Dict
NewType = typing.NewType
Callable = typing.Callable
Sequence = typing.Sequence
TypeVar = typing.TypeVar
Generic = typing.Generic
Pair = typing.Pair
Mapping = typing.Mapping
Iterable = typing.Iterable
Union = typing.Union
Any = typing.Any
Optional = typing.Optional
# Internal tokens - only instances will be
class _NotGiven(object):
pass
class _NoDefault(object):
pass
_CSArgument = namedtuple('_CSArgument', ('name', 'required','default_value'))
class CSArgument(_CSArgument):
def __str__(self):
p = ['Argument '+self.name]
if not self.required:
p.append('optional with default %s' % (self.default_value, ))
return ' '.join(p)
class CSVarargsPlaceholder(CSArgument):
def __init__(self, name):
super(CSVarargsPlaceholder, self).__init__('name', False, ())
class CSKwargsPlaceholder(CSArgument):
def __init__(self, name):
super(CSKwargsPlaceholder, self).__init__('name', False, {})
class TypeErrorReason(object):
pass
class CSTypeError(TypeError):
"""
A TypeError exception on steroids
"""
def __str__(self):
return 'Problem with argument %s' % (arg.name, )
def __init__(self, arg):
"""
:param arg: Argument definition
:type arg: CSArgument
"""
super(CSTypeError, self).__init__(str(self))
self.arg = arg
class CSBadTypeError(CSTypeError):
def __init__(self, arg, expected, got):
super(CSBadTypeError, self).__init__(arg)
self.expected = expected
self.got = got
def __str__(self):
return 'Bad type given for arg %s, expected %s got %s' % (self.arg.name, self.expected, self.got)
class CSNotGivenError(CSTypeError):
def __str__(self):
return 'Value for argument %s not given' % (self.arg.name, )
class CSMultipleValuesGivenError(CSTypeError):
def __str__(self):
return 'Got multiple values for argument' % (self.arg.name, )
class CallSignature(object):
"""
Call signature of a callable.
Properties:
- has_varargs (Bool) - if has varargs
- has_kwargs (Bool) - if has kwargs
- locals (Dict[str => CSArgument]) - list of locals this function call will generate
- pos_args (List[CSArgument)] - list of positional arguments
- varargs_name (Union[str, None]) - name of varargs argument, or None if not present
- kwargs_name (Union[str, None]) - name of kwargs argument, or None if not present
"""
__slots__ = ('has_varargs', 'has_kwargs', 'pos_args', 'locals')
def count_required_positionals(self):
return len((a for a in self.pos_args if a.required))
def __init__(self, callable):
args, varargs, kwargs, defaults = inspect.getargspec(callable)
# pad them
while len(defaults) < len(args):
defaults = [_NoDefault] + list(defaults)
# process positionals
self.pos_args = []
self.locals = {}
for arg, default in zip(args, defaults):
cs_arg = CSArgument(arg,
default is _NoDefault,
default)
self.pos_args.append(cs_arg)
self.locals[arg] = cs_arg
self.varargs_name = varargs
if varargs is not None:
self.has_varargs = True
self.locals[self.varargs_name] = CSVarargsPlaceholder(self.varargs_name)
self.kwargs_name = kwargs
if kwargs is not None:
self.has_kwargs = True
self.locals[self.kwargs_name] = CSKwargsPlaceholder(self.kwargs_name)
def result(self, *args, **kwargs):
"""
Simulate a function call, see what locals are defined
Return a dict of (local_variable_name => it's value),
or TypeError
:param args: function call parameters
:param kwargs: function call parameters
:return: dict
:raise CSTypeError: call would raise a TypeError
"""
assert len(args) >= self.count_required_positionals()
locals = {}
# positional
for arg, value in itertools.izip_longest(self.pos_args,
args[:len(self.pos_args)],
fillvalue=_NotGiven):
if value is _NotGiven:
if arg.required:
raise CSNotGivenError(arg)
else:
value = arg.default_value
locals[arg.name] = value
# varargs
if self.has_varargs:
locals[self.varargs_name] = args[len(self.pos_args):]
# kwargs
if self.has_kwargs:
locals[self.kwargs_name] = kwargs
return locals
def typed(*t_args, **t_kwargs): def typed(*t_args, **t_kwargs):
......
...@@ -16,6 +16,7 @@ setup(name='satella', ...@@ -16,6 +16,7 @@ setup(name='satella',
install_requires=[ install_requires=[
"six", "six",
"monotonic", "monotonic",
"typing"
], ],
tests_require=[ tests_require=[
"nose" "nose"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment