mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 01:47:45 +03:00 
			
		
		
		
	Refactored utils
This commit is contained in:
		
							parent
							
								
									3d6041e5e1
								
							
						
					
					
						commit
						d7e1d9c598
					
				| 
						 | 
				
			
			@ -1,155 +0,0 @@
 | 
			
		|||
import collections
 | 
			
		||||
import re
 | 
			
		||||
from functools import wraps
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class cached_property(object):
 | 
			
		||||
    """
 | 
			
		||||
    A property that is only computed once per instance and then replaces itself
 | 
			
		||||
    with an ordinary attribute. Deleting the attribute resets the property.
 | 
			
		||||
    Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
 | 
			
		||||
    """  # noqa
 | 
			
		||||
 | 
			
		||||
    def __init__(self, func):
 | 
			
		||||
        self.__doc__ = getattr(func, '__doc__')
 | 
			
		||||
        self.func = func
 | 
			
		||||
 | 
			
		||||
    def __get__(self, obj, cls):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return self
 | 
			
		||||
        value = obj.__dict__[self.func.__name__] = self.func(obj)
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def memoize(fun):
 | 
			
		||||
    """A simple memoize decorator for functions supporting positional args."""
 | 
			
		||||
    @wraps(fun)
 | 
			
		||||
    def wrapper(*args, **kwargs):
 | 
			
		||||
        key = (args, frozenset(sorted(kwargs.items())))
 | 
			
		||||
        try:
 | 
			
		||||
            return cache[key]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            ret = cache[key] = fun(*args, **kwargs)
 | 
			
		||||
        return ret
 | 
			
		||||
    cache = {}
 | 
			
		||||
    return wrapper
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# From this response in Stackoverflow
 | 
			
		||||
# http://stackoverflow.com/a/19053800/1072990
 | 
			
		||||
def to_camel_case(snake_str):
 | 
			
		||||
    components = snake_str.split('_')
 | 
			
		||||
    # We capitalize the first letter of each component except the first one
 | 
			
		||||
    # with the 'title' method and join them together.
 | 
			
		||||
    return components[0] + "".join(x.title() for x in components[1:])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# From this response in Stackoverflow
 | 
			
		||||
# http://stackoverflow.com/a/1176023/1072990
 | 
			
		||||
def to_snake_case(name):
 | 
			
		||||
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
 | 
			
		||||
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProxySnakeDict(collections.MutableMapping):
 | 
			
		||||
    __slots__ = ('data')
 | 
			
		||||
 | 
			
		||||
    def __init__(self, data):
 | 
			
		||||
        self.data = data
 | 
			
		||||
 | 
			
		||||
    def __contains__(self, key):
 | 
			
		||||
        return key in self.data or to_camel_case(key) in self.data
 | 
			
		||||
 | 
			
		||||
    def get(self, key, default=None):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.__getitem__(key)
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            return default
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self.iterkeys()
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return len(self.data)
 | 
			
		||||
 | 
			
		||||
    def __delitem__(self):
 | 
			
		||||
        raise TypeError('ProxySnakeDict does not support item deletion')
 | 
			
		||||
 | 
			
		||||
    def __setitem__(self):
 | 
			
		||||
        raise TypeError('ProxySnakeDict does not support item assignment')
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        if key in self.data:
 | 
			
		||||
            item = self.data[key]
 | 
			
		||||
        else:
 | 
			
		||||
            camel_key = to_camel_case(key)
 | 
			
		||||
            if camel_key in self.data:
 | 
			
		||||
                item = self.data[camel_key]
 | 
			
		||||
            else:
 | 
			
		||||
                raise KeyError(key, camel_key)
 | 
			
		||||
 | 
			
		||||
        if isinstance(item, dict):
 | 
			
		||||
            return ProxySnakeDict(item)
 | 
			
		||||
        return item
 | 
			
		||||
 | 
			
		||||
    def keys(self):
 | 
			
		||||
        return list(self.iterkeys())
 | 
			
		||||
 | 
			
		||||
    def items(self):
 | 
			
		||||
        return list(self.iteritems())
 | 
			
		||||
 | 
			
		||||
    def iterkeys(self):
 | 
			
		||||
        for k in self.data.keys():
 | 
			
		||||
            yield to_snake_case(k)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def iteritems(self):
 | 
			
		||||
        for k in self.iterkeys():
 | 
			
		||||
            yield k, self[k]
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return dict(self.iteritems()).__repr__()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LazyMap(object):
 | 
			
		||||
    def __init__(self, origin, _map, state=None):
 | 
			
		||||
        self._origin = origin
 | 
			
		||||
        self._origin_iter = origin.__iter__()
 | 
			
		||||
        self._state = state or []
 | 
			
		||||
        self._finished = False
 | 
			
		||||
        self._map = _map
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self if not self._finished else iter(self._state)
 | 
			
		||||
 | 
			
		||||
    def iter(self):
 | 
			
		||||
        return self.__iter__()
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return self._origin.__len__()
 | 
			
		||||
 | 
			
		||||
    def __next__(self):
 | 
			
		||||
        try:
 | 
			
		||||
            n = next(self._origin_iter)
 | 
			
		||||
            n = self._map(n)
 | 
			
		||||
        except StopIteration as e:
 | 
			
		||||
            self._finished = True
 | 
			
		||||
            raise e
 | 
			
		||||
        else:
 | 
			
		||||
            self._state.append(n)
 | 
			
		||||
            return n
 | 
			
		||||
 | 
			
		||||
    def next(self):
 | 
			
		||||
        return self.__next__()
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        item = self._origin.__getitem__(key)
 | 
			
		||||
        if isinstance(key, slice):
 | 
			
		||||
            return LazyMap(item, self._map)
 | 
			
		||||
        return self._map(item)
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, name):
 | 
			
		||||
        return getattr(self._origin, name)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<LazyMap %s>" % repr(self._origin)
 | 
			
		||||
							
								
								
									
										7
									
								
								graphene/utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								graphene/utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
from .str_converters import to_camel_case, to_snake_case
 | 
			
		||||
from .proxy_snake_dict import ProxySnakeDict
 | 
			
		||||
from .caching import cached_property, memoize
 | 
			
		||||
from .lazymap import LazyMap
 | 
			
		||||
 | 
			
		||||
__all__ = ['to_camel_case', 'to_snake_case', 'ProxySnakeDict',
 | 
			
		||||
           'cached_property', 'memoize', 'LazyMap']
 | 
			
		||||
							
								
								
									
										35
									
								
								graphene/utils/caching.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								graphene/utils/caching.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
from functools import wraps
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CachedPropery(object):
 | 
			
		||||
    """
 | 
			
		||||
    A property that is only computed once per instance and then replaces itself
 | 
			
		||||
    with an ordinary attribute. Deleting the attribute resets the property.
 | 
			
		||||
    Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
 | 
			
		||||
    """  # noqa
 | 
			
		||||
 | 
			
		||||
    def __init__(self, func):
 | 
			
		||||
        self.__doc__ = getattr(func, '__doc__')
 | 
			
		||||
        self.func = func
 | 
			
		||||
 | 
			
		||||
    def __get__(self, obj, cls):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return self
 | 
			
		||||
        value = obj.__dict__[self.func.__name__] = self.func(obj)
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
cached_property = CachedPropery
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def memoize(fun):
 | 
			
		||||
    """A simple memoize decorator for functions supporting positional args."""
 | 
			
		||||
    @wraps(fun)
 | 
			
		||||
    def wrapper(*args, **kwargs):
 | 
			
		||||
        key = (args, frozenset(sorted(kwargs.items())))
 | 
			
		||||
        try:
 | 
			
		||||
            return cache[key]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            ret = cache[key] = fun(*args, **kwargs)
 | 
			
		||||
        return ret
 | 
			
		||||
    cache = {}
 | 
			
		||||
    return wrapper
 | 
			
		||||
							
								
								
									
										42
									
								
								graphene/utils/lazymap.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								graphene/utils/lazymap.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
class LazyMap(object):
 | 
			
		||||
    def __init__(self, origin, _map, state=None):
 | 
			
		||||
        self._origin = origin
 | 
			
		||||
        self._origin_iter = origin.__iter__()
 | 
			
		||||
        self._state = state or []
 | 
			
		||||
        self._finished = False
 | 
			
		||||
        self._map = _map
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self if not self._finished else iter(self._state)
 | 
			
		||||
 | 
			
		||||
    def iter(self):
 | 
			
		||||
        return self.__iter__()
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return self._origin.__len__()
 | 
			
		||||
 | 
			
		||||
    def __next__(self):
 | 
			
		||||
        try:
 | 
			
		||||
            n = next(self._origin_iter)
 | 
			
		||||
            n = self._map(n)
 | 
			
		||||
        except StopIteration as e:
 | 
			
		||||
            self._finished = True
 | 
			
		||||
            raise e
 | 
			
		||||
        else:
 | 
			
		||||
            self._state.append(n)
 | 
			
		||||
            return n
 | 
			
		||||
 | 
			
		||||
    def next(self):
 | 
			
		||||
        return self.__next__()
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        item = self._origin.__getitem__(key)
 | 
			
		||||
        if isinstance(key, slice):
 | 
			
		||||
            return LazyMap(item, self._map)
 | 
			
		||||
        return self._map(item)
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, name):
 | 
			
		||||
        return getattr(self._origin, name)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<LazyMap %s>" % repr(self._origin)
 | 
			
		||||
							
								
								
									
										63
									
								
								graphene/utils/proxy_snake_dict.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								graphene/utils/proxy_snake_dict.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
import collections
 | 
			
		||||
 | 
			
		||||
from .str_converters import to_camel_case, to_snake_case
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProxySnakeDict(collections.MutableMapping):
 | 
			
		||||
    __slots__ = ('data')
 | 
			
		||||
 | 
			
		||||
    def __init__(self, data):
 | 
			
		||||
        self.data = data
 | 
			
		||||
 | 
			
		||||
    def __contains__(self, key):
 | 
			
		||||
        return key in self.data or to_camel_case(key) in self.data
 | 
			
		||||
 | 
			
		||||
    def get(self, key, default=None):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.__getitem__(key)
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            return default
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self.iterkeys()
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return len(self.data)
 | 
			
		||||
 | 
			
		||||
    def __delitem__(self):
 | 
			
		||||
        raise TypeError('ProxySnakeDict does not support item deletion')
 | 
			
		||||
 | 
			
		||||
    def __setitem__(self):
 | 
			
		||||
        raise TypeError('ProxySnakeDict does not support item assignment')
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, key):
 | 
			
		||||
        if key in self.data:
 | 
			
		||||
            item = self.data[key]
 | 
			
		||||
        else:
 | 
			
		||||
            camel_key = to_camel_case(key)
 | 
			
		||||
            if camel_key in self.data:
 | 
			
		||||
                item = self.data[camel_key]
 | 
			
		||||
            else:
 | 
			
		||||
                raise KeyError(key, camel_key)
 | 
			
		||||
 | 
			
		||||
        if isinstance(item, dict):
 | 
			
		||||
            return ProxySnakeDict(item)
 | 
			
		||||
        return item
 | 
			
		||||
 | 
			
		||||
    def keys(self):
 | 
			
		||||
        return list(self.iterkeys())
 | 
			
		||||
 | 
			
		||||
    def items(self):
 | 
			
		||||
        return list(self.iteritems())
 | 
			
		||||
 | 
			
		||||
    def iterkeys(self):
 | 
			
		||||
        for k in self.data.keys():
 | 
			
		||||
            yield to_snake_case(k)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def iteritems(self):
 | 
			
		||||
        for k in self.iterkeys():
 | 
			
		||||
            yield k, self[k]
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return dict(self.iteritems()).__repr__()
 | 
			
		||||
							
								
								
									
										17
									
								
								graphene/utils/str_converters.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								graphene/utils/str_converters.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
import re
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# From this response in Stackoverflow
 | 
			
		||||
# http://stackoverflow.com/a/19053800/1072990
 | 
			
		||||
def to_camel_case(snake_str):
 | 
			
		||||
    components = snake_str.split('_')
 | 
			
		||||
    # We capitalize the first letter of each component except the first one
 | 
			
		||||
    # with the 'title' method and join them together.
 | 
			
		||||
    return components[0] + "".join(x.title() for x in components[1:])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# From this response in Stackoverflow
 | 
			
		||||
# http://stackoverflow.com/a/1176023/1072990
 | 
			
		||||
def to_snake_case(name):
 | 
			
		||||
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
 | 
			
		||||
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
 | 
			
		||||
| 
						 | 
				
			
			@ -1,12 +1,4 @@
 | 
			
		|||
from graphene.utils import ProxySnakeDict, to_snake_case
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_snake_case():
 | 
			
		||||
    assert to_snake_case('snakesOnAPlane') == 'snakes_on_a_plane'
 | 
			
		||||
    assert to_snake_case('SnakesOnAPlane') == 'snakes_on_a_plane'
 | 
			
		||||
    assert to_snake_case('snakes_on_a_plane') == 'snakes_on_a_plane'
 | 
			
		||||
    assert to_snake_case('IPhoneHysteria') == 'i_phone_hysteria'
 | 
			
		||||
    assert to_snake_case('iPhoneHysteria') == 'i_phone_hysteria'
 | 
			
		||||
from graphene.utils import ProxySnakeDict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_proxy_snake_dict():
 | 
			
		||||
| 
						 | 
				
			
			@ -32,5 +24,3 @@ def test_proxy_snake_dict_as_kwargs():
 | 
			
		|||
    def func(**kwargs):
 | 
			
		||||
        return kwargs.get('my_data')
 | 
			
		||||
    assert func(**p) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								tests/utils/test_str_converter.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/utils/test_str_converter.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
from graphene.utils import to_snake_case, to_camel_case
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_snake_case():
 | 
			
		||||
    assert to_snake_case('snakesOnAPlane') == 'snakes_on_a_plane'
 | 
			
		||||
    assert to_snake_case('SnakesOnAPlane') == 'snakes_on_a_plane'
 | 
			
		||||
    assert to_snake_case('snakes_on_a_plane') == 'snakes_on_a_plane'
 | 
			
		||||
    assert to_snake_case('IPhoneHysteria') == 'i_phone_hysteria'
 | 
			
		||||
    assert to_snake_case('iPhoneHysteria') == 'i_phone_hysteria'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_camel_case():
 | 
			
		||||
    assert to_camel_case('snakes_on_a_plane') == 'snakesOnAPlane'
 | 
			
		||||
    assert to_camel_case('i_phone_hysteria') == 'iPhoneHysteria'
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user