<commit_before>import re
import sys
import time
import unicodedata
import collections
import functools
import hmac
import logging

import six
import requests
import social_core

from six.moves.urllib_parse import urlparse, urlunparse, urlencode, \
                                   parse_qs as battery_parse_qs

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager

from .exceptions import AuthCanceled, AuthForbidden, AuthUnreachableProvider

SETTING_PREFIX = 'SOCIAL_AUTH'

PARTIAL_TOKEN_SESSION_NAME = 'partial_pipeline_token'

social_logger = logging.getLogger('social')

class SSLHttpAdapter(HTTPAdapter):
    """"
    Transport adapter that allows to use any SSL protocol. Based on:
    http://requests.rtfd.org/latest/user/advanced/#example-specific-ssl-version
    """
    def __init__(self, ssl_protocol):
        self.ssl_protocol = ssl_protocol
        super(SSLHttpAdapter, self).__init__()

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=self.ssl_protocol
        )

    @classmethod
    def ssl_adapter_session(cls, ssl_protocol):
        session = requests.Session()
        session.mount('https://', SSLHttpAdapter(ssl_protocol))
        return session

def import_module(name):
    __import__(name)
    return sys.modules[name]

def module_member(name):
    mod, member = name.rsplit('.', 1)
    module = import_module(mod)
    return getattr(module, member)

def user_agent():
    """Builds a simple User-Agent string to send in requests"""
    return 'social-auth-' + social_core.__version__

def url_add_parameters(url, params):
    """Adds parameters to URL, parameter will be repeated if already present"""
    if params:
        fragments = list(urlparse(url))
        value = parse_qs(fragments[4])
        value.update(params)
        fragments[4] = urlencode(value)
        url = urlunparse(fragments)
    return url

def to_setting_name(*names):
    return '_'.join([name.upper().replace('-', '_') for name in names if name])

def setting_name(*names):
    return to_setting_name(*((SETTING_PREFIX,) + names))

def sanitize_redirect(hosts, redirect_to):
    """
    Given a list of hostnames and an untrusted URL to redirect to,
    this method tests it to make sure it isn't garbage/harmful
    and returns it, else returns None, similar as how's it done
    on django.contrib.auth.views.
    """
    # Avoid redirect on evil URLs like ///evil.com
    if not redirect_to or not hasattr(redirect_to, 'startswith') or \
       redirect_to.startswith('///'):
        return None

    try:
        # Don't redirect to a host that's not in the list
        netloc = urlparse(redirect_to)[1] or hosts[0]
    except (TypeError, AttributeError):
        pass
    else:
        if netloc in hosts:
            return redirect_to

def user_is_authenticated(user):
    if user and hasattr(user, 'is_authenticated'):
        if isinstance(user.is_authenticated, collections.Callable):
            authenticated = user.is_authenticated()
        else:
            authenticated = user.is_authenticated
    elif user:
        authenticated = True
    else:
        authenticated = False
    return authenticated

def user_is_active(user):
    if user and hasattr(user, 'is_active'):
        if isinstance(user.is_active, collections.Callable):
            is_active = user.is_active()
        else:
            is_active = user.is_active
    elif user:
        is_active = True
    else:
        is_active = False
    return is_active

# This slugify version was borrowed from django revision a61dbd6
def slugify(value):
    """Converts to lowercase, removes non-word characters (alphanumerics
    and underscores) and converts spaces to hyphens. Also strips leading
    and trailing whitespace."""
    value = unicodedata.normalize('NFKD', six.text_type(value)) \
                       .encode('ascii', 'ignore') \
                       .decode('ascii')
    value = re.sub(r'[^\w\s-]', '', value).strip().lower()
    return re.sub(r'[-\s]+', '-', value)

def first(func, items):
    """Return the first item in the list for what func returns True"""
    for item in items:
        if func(item):
            return item

def parse_qs(value):
    """Like urlparse.parse_qs but transform list values to single items"""
    return drop_lists(battery_parse_qs(value))

def drop_lists(value):
    out = {}
    for key, val in value.items():
        val = val[0]
        if isinstance(key, six.binary_type):
            key = six.text_type(key, 'utf-8')
        if isinstance(val, six.binary_type):
            val = six.text_type(val, 'utf-8')
        out[key] = val
    return out

def partial_pipeline_data(backend, user=None, partial_token=None,
                          *args, **kwargs):
    request_data = backend.strategy.request_data()

    partial_argument_name = backend.setting('PARTIAL_PIPELINE_TOKEN_NAME',
                                            'partial_token')
    partial_token = partial_token or \
        request_data.get(partial_argument_name) or \
        backend.strategy.session_get(PARTIAL_TOKEN_SESSION_NAME, None)

    if partial_token:
        partial = backend.strategy.partial_load(partial_token)
        partial_matches_request = False

        if partial and partial.backend == backend.name:
            partial_matches_request = True

            # Normally when resuming a pipeline, request_data will be empty. We
            # only need to check for a uid match if new data was provided (i.e.
            # if current request specifies the ID_KEY).
            if backend.ID_KEY in request_data:
                id_from_partial = partial.kwargs.get('uid')
                id_from_request = request_data.get(backend.ID_KEY)

                if id_from_partial != id_from_request:
                    partial_matches_request = False

        if partial_matches_request:
            if user:  # don't update user if it's None
                kwargs.setdefault('user', user)
            kwargs.setdefault('request', request_data)
            partial.extend_kwargs(kwargs)
            return partial
        else:
            backend.strategy.clean_partial_pipeline(partial_token)

def build_absolute_uri(host_url, path=None):
    """Build absolute URI with given (optional) path"""
    path = path or ''
    if path.startswith('http://') or path.startswith('https://'):
        return path
    if host_url.endswith('/') and path.startswith('/'):
        path = path[1:]
    return host_url + path

def constant_time_compare(val1, val2):
    """Compare two values and prevent timing attacks for cryptographic use."""
    if isinstance(val1, six.text_type):
        val1 = val1.encode('utf-8')
    if isinstance(val2, six.text_type):
        val2 = val2.encode('utf-8')
    return hmac.compare_digest(val1, val2)

def is_url(value):
    return value and \
           (value.startswith('http://') or
            value.startswith('https://') or
            value.startswith('/'))

def setting_url(backend, *names):
    for name in names:
        if is_url(name):
            return name
        else:
            value = backend.setting(name)
            if is_url(value):
                return value

def handle_http_errors(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except requests.HTTPError as err:
            if err.response.status_code == 400:
                raise AuthCanceled(args[0], response=err.response)
            elif err.response.status_code == 401:
                raise AuthForbidden(args[0])
            elif err.response.status_code == 503:
                raise AuthUnreachableProvider(args[0])
            else:
                raise
    return wrapper

def append_slash(url):
    """Make sure we append a slash at the end of the URL otherwise we
    have issues with urljoin Example:
    >>> urlparse.urljoin('http://www.example.com/api/v3', 'user/1/')
    'http://www.example.com/api/user/1/'
    """
    if url and not url.endswith('/'):
        url = '{0}/'.format(url)
    return url

def get_strategy(strategy, storage, *args, **kwargs):
    Strategy = module_member(strategy)
    Storage = module_member(storage)
    return Strategy(Storage, *args, **kwargs)

class cache(object):
    """
    Cache decorator that caches the return value of a method for a
    specified time.

    It maintains a cache per class, so subclasses have a different cache entry
    for the same cached method.

    Does not work for methods with arguments.
    """
    def __init__(self, ttl):
        self.ttl = ttl
        self.cache = {}

    def __call__(self, fn):
        def wrapped(this):
            now = time.time()
            last_updated = None
            cached_value = None
            if this.__class__ in self.cache:
                last_updated, cached_value = self.cache[this.__class__]
            if not cached_value or now - last_updated > self.ttl:
                try:
                    cached_value = fn(this)
                    self.cache[this.__class__] = (now, cached_value)
                except:
                    # Use previously cached value when call fails, if available
                    if not cached_value:
                        raise
            return cached_value
        return wrapped
<commit_msg>Use callable builtin instead of ABC<commit_after>import re
import sys
import time
import unicodedata
import functools
import hmac
import logging

import six
import requests
import social_core

from six.moves.urllib_parse import urlparse, urlunparse, urlencode, \
                                   parse_qs as battery_parse_qs

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager

from .exceptions import AuthCanceled, AuthForbidden, AuthUnreachableProvider

SETTING_PREFIX = 'SOCIAL_AUTH'

PARTIAL_TOKEN_SESSION_NAME = 'partial_pipeline_token'

social_logger = logging.getLogger('social')

class SSLHttpAdapter(HTTPAdapter):
    """"
    Transport adapter that allows to use any SSL protocol. Based on:
    http://requests.rtfd.org/latest/user/advanced/#example-specific-ssl-version
    """
    def __init__(self, ssl_protocol):
        self.ssl_protocol = ssl_protocol
        super(SSLHttpAdapter, self).__init__()

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=self.ssl_protocol
        )

    @classmethod
    def ssl_adapter_session(cls, ssl_protocol):
        session = requests.Session()
        session.mount('https://', SSLHttpAdapter(ssl_protocol))
        return session

def import_module(name):
    __import__(name)
    return sys.modules[name]

def module_member(name):
    mod, member = name.rsplit('.', 1)
    module = import_module(mod)
    return getattr(module, member)

def user_agent():
    """Builds a simple User-Agent string to send in requests"""
    return 'social-auth-' + social_core.__version__

def url_add_parameters(url, params):
    """Adds parameters to URL, parameter will be repeated if already present"""
    if params:
        fragments = list(urlparse(url))
        value = parse_qs(fragments[4])
        value.update(params)
        fragments[4] = urlencode(value)
        url = urlunparse(fragments)
    return url

def to_setting_name(*names):
    return '_'.join([name.upper().replace('-', '_') for name in names if name])

def setting_name(*names):
    return to_setting_name(*((SETTING_PREFIX,) + names))

def sanitize_redirect(hosts, redirect_to):
    """
    Given a list of hostnames and an untrusted URL to redirect to,
    this method tests it to make sure it isn't garbage/harmful
    and returns it, else returns None, similar as how's it done
    on django.contrib.auth.views.
    """
    # Avoid redirect on evil URLs like ///evil.com
    if not redirect_to or not hasattr(redirect_to, 'startswith') or \
       redirect_to.startswith('///'):
        return None

    try:
        # Don't redirect to a host that's not in the list
        netloc = urlparse(redirect_to)[1] or hosts[0]
    except (TypeError, AttributeError):
        pass
    else:
        if netloc in hosts:
            return redirect_to

def user_is_authenticated(user):
    if user and hasattr(user, 'is_authenticated'):
        if callable(user.is_authenticated):
            authenticated = user.is_authenticated()
        else:
            authenticated = user.is_authenticated
    elif user:
        authenticated = True
    else:
        authenticated = False
    return authenticated

def user_is_active(user):
    if user and hasattr(user, 'is_active'):
        if callable(user.is_active):
            is_active = user.is_active()
        else:
            is_active = user.is_active
    elif user:
        is_active = True
    else:
        is_active = False
    return is_active

# This slugify version was borrowed from django revision a61dbd6
def slugify(value):
    """Converts to lowercase, removes non-word characters (alphanumerics
    and underscores) and converts spaces to hyphens. Also strips leading
    and trailing whitespace."""
    value = unicodedata.normalize('NFKD', six.text_type(value)) \
                       .encode('ascii', 'ignore') \
                       .decode('ascii')
    value = re.sub(r'[^\w\s-]', '', value).strip().lower()
    return re.sub(r'[-\s]+', '-', value)

def first(func, items):
    """Return the first item in the list for what func returns True"""
    for item in items:
        if func(item):
            return item

def parse_qs(value):
    """Like urlparse.parse_qs but transform list values to single items"""
    return drop_lists(battery_parse_qs(value))

def drop_lists(value):
    out = {}
    for key, val in value.items():
        val = val[0]
        if isinstance(key, six.binary_type):
            key = six.text_type(key, 'utf-8')
        if isinstance(val, six.binary_type):
            val = six.text_type(val, 'utf-8')
        out[key] = val
    return out

def partial_pipeline_data(backend, user=None, partial_token=None,
                          *args, **kwargs):
    request_data = backend.strategy.request_data()

    partial_argument_name = backend.setting('PARTIAL_PIPELINE_TOKEN_NAME',
                                            'partial_token')
    partial_token = partial_token or \
        request_data.get(partial_argument_name) or \
        backend.strategy.session_get(PARTIAL_TOKEN_SESSION_NAME, None)

    if partial_token:
        partial = backend.strategy.partial_load(partial_token)
        partial_matches_request = False

        if partial and partial.backend == backend.name:
            partial_matches_request = True

            # Normally when resuming a pipeline, request_data will be empty. We
            # only need to check for a uid match if new data was provided (i.e.
            # if current request specifies the ID_KEY).
            if backend.ID_KEY in request_data:
                id_from_partial = partial.kwargs.get('uid')
                id_from_request = request_data.get(backend.ID_KEY)

                if id_from_partial != id_from_request:
                    partial_matches_request = False

        if partial_matches_request:
            if user:  # don't update user if it's None
                kwargs.setdefault('user', user)
            kwargs.setdefault('request', request_data)
            partial.extend_kwargs(kwargs)
            return partial
        else:
            backend.strategy.clean_partial_pipeline(partial_token)

def build_absolute_uri(host_url, path=None):
    """Build absolute URI with given (optional) path"""
    path = path or ''
    if path.startswith('http://') or path.startswith('https://'):
        return path
    if host_url.endswith('/') and path.startswith('/'):
        path = path[1:]
    return host_url + path

def constant_time_compare(val1, val2):
    """Compare two values and prevent timing attacks for cryptographic use."""
    if isinstance(val1, six.text_type):
        val1 = val1.encode('utf-8')
    if isinstance(val2, six.text_type):
        val2 = val2.encode('utf-8')
    return hmac.compare_digest(val1, val2)

def is_url(value):
    return value and \
           (value.startswith('http://') or
            value.startswith('https://') or
            value.startswith('/'))

def setting_url(backend, *names):
    for name in names:
        if is_url(name):
            return name
        else:
            value = backend.setting(name)
            if is_url(value):
                return value

def handle_http_errors(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except requests.HTTPError as err:
            if err.response.status_code == 400:
                raise AuthCanceled(args[0], response=err.response)
            elif err.response.status_code == 401:
                raise AuthForbidden(args[0])
            elif err.response.status_code == 503:
                raise AuthUnreachableProvider(args[0])
            else:
                raise
    return wrapper

def append_slash(url):
    """Make sure we append a slash at the end of the URL otherwise we
    have issues with urljoin Example:
    >>> urlparse.urljoin('http://www.example.com/api/v3', 'user/1/')
    'http://www.example.com/api/user/1/'
    """
    if url and not url.endswith('/'):
        url = '{0}/'.format(url)
    return url

def get_strategy(strategy, storage, *args, **kwargs):
    Strategy = module_member(strategy)
    Storage = module_member(storage)
    return Strategy(Storage, *args, **kwargs)

class cache(object):
    """
    Cache decorator that caches the return value of a method for a
    specified time.

    It maintains a cache per class, so subclasses have a different cache entry
    for the same cached method.

    Does not work for methods with arguments.
    """
    def __init__(self, ttl):
        self.ttl = ttl
        self.cache = {}

    def __call__(self, fn):
        def wrapped(this):
            now = time.time()
            last_updated = None
            cached_value = None
            if this.__class__ in self.cache:
                last_updated, cached_value = self.cache[this.__class__]
            if not cached_value or now - last_updated > self.ttl:
                try:
                    cached_value = fn(this)
                    self.cache[this.__class__] = (now, cached_value)
                except:
                    # Use previously cached value when call fails, if available
                    if not cached_value:
                        raise
            return cached_value
        return wrapped
<|endoftext|>


<commit_before>import re
import sys
import time
import unicodedata
import collections
import functools
import logging

import six
import requests
import social_core

from six.moves.urllib_parse import urlparse, urlunparse, urlencode, \
                                   parse_qs as battery_parse_qs

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager

from .exceptions import AuthCanceled, AuthUnreachableProvider

SETTING_PREFIX = 'SOCIAL_AUTH'

social_logger = logging.getLogger('social')

class SSLHttpAdapter(HTTPAdapter):
    """"
    Transport adapter that allows to use any SSL protocol. Based on:
    http://requests.rtfd.org/latest/user/advanced/#example-specific-ssl-version
    """
    def __init__(self, ssl_protocol):
        self.ssl_protocol = ssl_protocol
        super(SSLHttpAdapter, self).__init__()

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=self.ssl_protocol
        )

    @classmethod
    def ssl_adapter_session(cls, ssl_protocol):
        session = requests.Session()
        session.mount('https://', SSLHttpAdapter(ssl_protocol))
        return session

def import_module(name):
    __import__(name)
    return sys.modules[name]

def module_member(name):
    mod, member = name.rsplit('.', 1)
    module = import_module(mod)
    return getattr(module, member)

def user_agent():
    """Builds a simple User-Agent string to send in requests"""
    return 'social-auth-' + social_core.__version__

def url_add_parameters(url, params):
    """Adds parameters to URL, parameter will be repeated if already present"""
    if params:
        fragments = list(urlparse(url))
        value = parse_qs(fragments[4])
        value.update(params)
        fragments[4] = urlencode(value)
        url = urlunparse(fragments)
    return url

def to_setting_name(*names):
    return '_'.join([name.upper().replace('-', '_') for name in names if name])

def setting_name(*names):
    return to_setting_name(*((SETTING_PREFIX,) + names))

def sanitize_redirect(hosts, redirect_to):
    """
    Given a list of hostnames and an untrusted URL to redirect to,
    this method tests it to make sure it isn't garbage/harmful
    and returns it, else returns None, similar as how's it done
    on django.contrib.auth.views.
    """
    if redirect_to:
        try:
            # Don't redirect to a host that's not in the list
            netloc = urlparse(redirect_to)[1] or hosts[0]
        except (TypeError, AttributeError):
            pass
        else:
            if netloc in hosts:
                return redirect_to

def user_is_authenticated(user):
    if user and hasattr(user, 'is_authenticated'):
        if isinstance(user.is_authenticated, collections.Callable):
            authenticated = user.is_authenticated()
        else:
            authenticated = user.is_authenticated
    elif user:
        authenticated = True
    else:
        authenticated = False
    return authenticated

def user_is_active(user):
    if user and hasattr(user, 'is_active'):
        if isinstance(user.is_active, collections.Callable):
            is_active = user.is_active()
        else:
            is_active = user.is_active
    elif user:
        is_active = True
    else:
        is_active = False
    return is_active

# This slugify version was borrowed from django revision a61dbd6
def slugify(value):
    """Converts to lowercase, removes non-word characters (alphanumerics
    and underscores) and converts spaces to hyphens. Also strips leading
    and trailing whitespace."""
    value = unicodedata.normalize('NFKD', six.text_type(value)) \
                       .encode('ascii', 'ignore') \
                       .decode('ascii')
    value = re.sub('[^\w\s-]', '', value).strip().lower()
    return re.sub('[-\s]+', '-', value)

def first(func, items):
    """Return the first item in the list for what func returns True"""
    for item in items:
        if func(item):
            return item

def parse_qs(value):
    """Like urlparse.parse_qs but transform list values to single items"""
    return drop_lists(battery_parse_qs(value))

def drop_lists(value):
    out = {}
    for key, val in value.items():
        val = val[0]
        if isinstance(key, six.binary_type):
            key = six.text_type(key, 'utf-8')
        if isinstance(val, six.binary_type):
            val = six.text_type(val, 'utf-8')
        out[key] = val
    return out

def partial_pipeline_data(backend, user=None, partial_token=None,
                          *args, **kwargs):
    request_data = backend.strategy.request_data()

    partial_argument_name = backend.setting('PARTIAL_PIPELINE_TOKEN_NAME',
                                            'partial_token')
    partial_token = partial_token or \
        request_data.get(partial_argument_name) or \
        backend.strategy.session_get('partial_pipeline_token', None)

    if partial_token:
        partial = backend.strategy.partial_load(partial_token)
        partial_matches_request = False

        if partial and partial.backend == backend.name:
            partial_matches_request = True

            # Normally when resuming a pipeline, request_data will be empty. We
            # only need to check for a uid match if new data was provided (i.e.
            # if current request specifies the ID_KEY).
            if backend.ID_KEY in request_data:
                id_from_partial = partial.kwargs.get('uid')
                id_from_request = request_data.get(backend.ID_KEY)

                if id_from_partial != id_from_request:
                    partial_matches_request = False

        if partial_matches_request:
            if user:  # don't update user if it's None
                kwargs.setdefault('user', user)
            kwargs.setdefault('request', request_data)
            partial.extend_kwargs(kwargs)
            return partial
        else:
            backend.strategy.clean_partial_pipeline(partial_token)

def build_absolute_uri(host_url, path=None):
    """Build absolute URI with given (optional) path"""
    path = path or ''
    if path.startswith('http://') or path.startswith('https://'):
        return path
    if host_url.endswith('/') and path.startswith('/'):
        path = path[1:]
    return host_url + path

def constant_time_compare(val1, val2):
    """
    Returns True if the two strings are equal, False otherwise.
    The time taken is independent of the number of characters that match.
    This code was borrowed from Django 1.5.4-final
    """
    if len(val1) != len(val2):
        return False
    result = 0
    if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
        for x, y in zip(val1, val2):
            result |= x ^ y
    else:
        for x, y in zip(val1, val2):
            result |= ord(x) ^ ord(y)
    return result == 0

def is_url(value):
    return value and \
           (value.startswith('http://') or
            value.startswith('https://') or
            value.startswith('/'))

def setting_url(backend, *names):
    for name in names:
        if is_url(name):
            return name
        else:
            value = backend.setting(name)
            if is_url(value):
                return value

def handle_http_errors(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except requests.HTTPError as err:
            if err.response.status_code == 400:
                raise AuthCanceled(args[0], response=err.response)
            elif err.response.status_code == 503:
                raise AuthUnreachableProvider(args[0])
            else:
                raise
    return wrapper

def append_slash(url):
    """Make sure we append a slash at the end of the URL otherwise we
    have issues with urljoin Example:
    >>> urlparse.urljoin('http://www.example.com/api/v3', 'user/1/')
    'http://www.example.com/api/user/1/'
    """
    if url and not url.endswith('/'):
        url = '{0}/'.format(url)
    return url

def get_strategy(strategy, storage, *args, **kwargs):
    Strategy = module_member(strategy)
    Storage = module_member(storage)
    return Strategy(Storage, *args, **kwargs)

class cache(object):
    """
    Cache decorator that caches the return value of a method for a
    specified time.

    It maintains a cache per class, so subclasses have a different cache entry
    for the same cached method.

    Does not work for methods with arguments.
    """
    def __init__(self, ttl):
        self.ttl = ttl
        self.cache = {}

    def __call__(self, fn):
        def wrapped(this):
            now = time.time()
            last_updated = None
            cached_value = None
            if this.__class__ in self.cache:
                last_updated, cached_value = self.cache[this.__class__]
            if not cached_value or now - last_updated > self.ttl:
                try:
                    cached_value = fn(this)
                    self.cache[this.__class__] = (now, cached_value)
                except:
                    # Use previously cached value when call fails, if available
                    if not cached_value:
                        raise
            return cached_value
        return wrapped
<commit_msg>Raise AuthForbidden on 401.<commit_after>import re
import sys
import time
import unicodedata
import collections
import functools
import logging

import six
import requests
import social_core

from six.moves.urllib_parse import urlparse, urlunparse, urlencode, \
                                   parse_qs as battery_parse_qs

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager

from .exceptions import AuthCanceled, AuthForbidden, AuthUnreachableProvider

SETTING_PREFIX = 'SOCIAL_AUTH'

social_logger = logging.getLogger('social')

class SSLHttpAdapter(HTTPAdapter):
    """"
    Transport adapter that allows to use any SSL protocol. Based on:
    http://requests.rtfd.org/latest/user/advanced/#example-specific-ssl-version
    """
    def __init__(self, ssl_protocol):
        self.ssl_protocol = ssl_protocol
        super(SSLHttpAdapter, self).__init__()

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=self.ssl_protocol
        )

    @classmethod
    def ssl_adapter_session(cls, ssl_protocol):
        session = requests.Session()
        session.mount('https://', SSLHttpAdapter(ssl_protocol))
        return session

def import_module(name):
    __import__(name)
    return sys.modules[name]

def module_member(name):
    mod, member = name.rsplit('.', 1)
    module = import_module(mod)
    return getattr(module, member)

def user_agent():
    """Builds a simple User-Agent string to send in requests"""
    return 'social-auth-' + social_core.__version__

def url_add_parameters(url, params):
    """Adds parameters to URL, parameter will be repeated if already present"""
    if params:
        fragments = list(urlparse(url))
        value = parse_qs(fragments[4])
        value.update(params)
        fragments[4] = urlencode(value)
        url = urlunparse(fragments)
    return url

def to_setting_name(*names):
    return '_'.join([name.upper().replace('-', '_') for name in names if name])

def setting_name(*names):
    return to_setting_name(*((SETTING_PREFIX,) + names))

def sanitize_redirect(hosts, redirect_to):
    """
    Given a list of hostnames and an untrusted URL to redirect to,
    this method tests it to make sure it isn't garbage/harmful
    and returns it, else returns None, similar as how's it done
    on django.contrib.auth.views.
    """
    if redirect_to:
        try:
            # Don't redirect to a host that's not in the list
            netloc = urlparse(redirect_to)[1] or hosts[0]
        except (TypeError, AttributeError):
            pass
        else:
            if netloc in hosts:
                return redirect_to

def user_is_authenticated(user):
    if user and hasattr(user, 'is_authenticated'):
        if isinstance(user.is_authenticated, collections.Callable):
            authenticated = user.is_authenticated()
        else:
            authenticated = user.is_authenticated
    elif user:
        authenticated = True
    else:
        authenticated = False
    return authenticated

def user_is_active(user):
    if user and hasattr(user, 'is_active'):
        if isinstance(user.is_active, collections.Callable):
            is_active = user.is_active()
        else:
            is_active = user.is_active
    elif user:
        is_active = True
    else:
        is_active = False
    return is_active

# This slugify version was borrowed from django revision a61dbd6
def slugify(value):
    """Converts to lowercase, removes non-word characters (alphanumerics
    and underscores) and converts spaces to hyphens. Also strips leading
    and trailing whitespace."""
    value = unicodedata.normalize('NFKD', six.text_type(value)) \
                       .encode('ascii', 'ignore') \
                       .decode('ascii')
    value = re.sub('[^\w\s-]', '', value).strip().lower()
    return re.sub('[-\s]+', '-', value)

def first(func, items):
    """Return the first item in the list for what func returns True"""
    for item in items:
        if func(item):
            return item

def parse_qs(value):
    """Like urlparse.parse_qs but transform list values to single items"""
    return drop_lists(battery_parse_qs(value))

def drop_lists(value):
    out = {}
    for key, val in value.items():
        val = val[0]
        if isinstance(key, six.binary_type):
            key = six.text_type(key, 'utf-8')
        if isinstance(val, six.binary_type):
            val = six.text_type(val, 'utf-8')
        out[key] = val
    return out

def partial_pipeline_data(backend, user=None, partial_token=None,
                          *args, **kwargs):
    request_data = backend.strategy.request_data()

    partial_argument_name = backend.setting('PARTIAL_PIPELINE_TOKEN_NAME',
                                            'partial_token')
    partial_token = partial_token or \
        request_data.get(partial_argument_name) or \
        backend.strategy.session_get('partial_pipeline_token', None)

    if partial_token:
        partial = backend.strategy.partial_load(partial_token)
        partial_matches_request = False

        if partial and partial.backend == backend.name:
            partial_matches_request = True

            # Normally when resuming a pipeline, request_data will be empty. We
            # only need to check for a uid match if new data was provided (i.e.
            # if current request specifies the ID_KEY).
            if backend.ID_KEY in request_data:
                id_from_partial = partial.kwargs.get('uid')
                id_from_request = request_data.get(backend.ID_KEY)

                if id_from_partial != id_from_request:
                    partial_matches_request = False

        if partial_matches_request:
            if user:  # don't update user if it's None
                kwargs.setdefault('user', user)
            kwargs.setdefault('request', request_data)
            partial.extend_kwargs(kwargs)
            return partial
        else:
            backend.strategy.clean_partial_pipeline(partial_token)

def build_absolute_uri(host_url, path=None):
    """Build absolute URI with given (optional) path"""
    path = path or ''
    if path.startswith('http://') or path.startswith('https://'):
        return path
    if host_url.endswith('/') and path.startswith('/'):
        path = path[1:]
    return host_url + path

def constant_time_compare(val1, val2):
    """
    Returns True if the two strings are equal, False otherwise.
    The time taken is independent of the number of characters that match.
    This code was borrowed from Django 1.5.4-final
    """
    if len(val1) != len(val2):
        return False
    result = 0
    if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
        for x, y in zip(val1, val2):
            result |= x ^ y
    else:
        for x, y in zip(val1, val2):
            result |= ord(x) ^ ord(y)
    return result == 0

def is_url(value):
    return value and \
           (value.startswith('http://') or
            value.startswith('https://') or
            value.startswith('/'))

def setting_url(backend, *names):
    for name in names:
        if is_url(name):
            return name
        else:
            value = backend.setting(name)
            if is_url(value):
                return value

def handle_http_errors(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except requests.HTTPError as err:
            if err.response.status_code == 400:
                raise AuthCanceled(args[0], response=err.response)
            elif err.response.status_code == 401:
                raise AuthForbidden(args[0])
            elif err.response.status_code == 503:
                raise AuthUnreachableProvider(args[0])
            else:
                raise
    return wrapper

def append_slash(url):
    """Make sure we append a slash at the end of the URL otherwise we
    have issues with urljoin Example:
    >>> urlparse.urljoin('http://www.example.com/api/v3', 'user/1/')
    'http://www.example.com/api/user/1/'
    """
    if url and not url.endswith('/'):
        url = '{0}/'.format(url)
    return url

def get_strategy(strategy, storage, *args, **kwargs):
    Strategy = module_member(strategy)
    Storage = module_member(storage)
    return Strategy(Storage, *args, **kwargs)

class cache(object):
    """
    Cache decorator that caches the return value of a method for a
    specified time.

    It maintains a cache per class, so subclasses have a different cache entry
    for the same cached method.

    Does not work for methods with arguments.
    """
    def __init__(self, ttl):
        self.ttl = ttl
        self.cache = {}

    def __call__(self, fn):
        def wrapped(this):
            now = time.time()
            last_updated = None
            cached_value = None
            if this.__class__ in self.cache:
                last_updated, cached_value = self.cache[this.__class__]
            if not cached_value or now - last_updated > self.ttl:
                try:
                    cached_value = fn(this)
                    self.cache[this.__class__] = (now, cached_value)
                except:
                    # Use previously cached value when call fails, if available
                    if not cached_value:
                        raise
            return cached_value
        return wrapped
<|endoftext|>


<commit_before>import warnings

import numpy as np
from numpy.testing import assert_array_almost_equal as assert_close
import skimage
from skimage import data
from skimage import exposure
from skimage.color import rgb2gray
from skimage.util.dtype import dtype_range

# Test histogram equalization
# ===========================

# squeeze image intensities to lower image contrast
test_img = skimage.img_as_float(data.camera())
test_img = exposure.rescale_intensity(test_img / 5. + 100)

def test_equalize_ubyte():
    img = skimage.img_as_ubyte(test_img)
    img_eq = exposure.equalize_hist(img)

    cdf, bin_edges = exposure.cumulative_distribution(img_eq)
    check_cdf_slope(cdf)

def test_equalize_float():
    img = skimage.img_as_float(test_img)
    img_eq = exposure.equalize_hist(img)

    cdf, bin_edges = exposure.cumulative_distribution(img_eq)
    check_cdf_slope(cdf)

def check_cdf_slope(cdf):
    """Slope of cdf which should equal 1 for an equalized histogram."""
    norm_intensity = np.linspace(0, 1, len(cdf))
    slope, intercept = np.polyfit(norm_intensity, cdf, 1)
    assert 0.9 < slope < 1.1

# Test rescale intensity
# ======================

def test_rescale_stretch():
    image = np.array([51, 102, 153], dtype=np.uint8)
    out = exposure.rescale_intensity(image)
    assert out.dtype == np.uint8
    assert_close(out, [0, 127, 255])

def test_rescale_shrink():
    image = np.array([51., 102., 153.])
    out = exposure.rescale_intensity(image)
    assert_close(out, [0, 0.5, 1])

def test_rescale_in_range():
    image = np.array([51., 102., 153.])
    out = exposure.rescale_intensity(image, in_range=(0, 255))
    assert_close(out, [0.2, 0.4, 0.6])

def test_rescale_in_range_clip():
    image = np.array([51., 102., 153.])
    out = exposure.rescale_intensity(image, in_range=(0, 102))
    assert_close(out, [0.5, 1, 1])

def test_rescale_out_range():
    image = np.array([-10, 0, 10], dtype=np.int8)
    out = exposure.rescale_intensity(image, out_range=(0, 127))
    assert out.dtype == np.int8
    assert_close(out, [0, 63, 127])

# Test adaptive histogram equalization
# ====================================

def test_adapthist_scalar():
    '''Test a scalar uint8 image
    '''
    img = skimage.img_as_ubyte(data.moon())
    adapted = exposure.equalize_adapthist(img, clip_limit=0.02)
    assert adapted.min() == 0
    assert adapted.max() == (1 << 16) - 1
    assert img.shape == adapted.shape
    full_scale = skimage.exposure.rescale_intensity(skimage.img_as_uint(img))

    assert_almost_equal = np.testing.assert_almost_equal
    assert_almost_equal(peak_snr(full_scale, adapted), 101.231, 3)
    assert_almost_equal(norm_brightness_err(full_scale, adapted),
                        0.041, 3)
    return img, adapted

def test_adapthist_grayscale():
    '''Test a grayscale float image
    '''
    img = skimage.img_as_float(data.lena())
    img = rgb2gray(img)
    img = np.dstack((img, img, img))
    adapted = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01,
                        nbins=128)
    assert_almost_equal = np.testing.assert_almost_equal
    assert img.shape == adapted.shape
    assert_almost_equal(peak_snr(img, adapted), 97.531, 3)
    assert_almost_equal(norm_brightness_err(img, adapted), 0.0313, 3)
    return data, adapted

def test_adapthist_color():
    '''Test an RGB color uint16 image
    '''
    img = skimage.img_as_uint(data.lena())
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter('always')
        hist, bin_centers = exposure.histogram(img)
        assert len(w) > 0
    adapted = exposure.equalize_adapthist(img, clip_limit=0.01)
    assert_almost_equal = np.testing.assert_almost_equal
    assert adapted.min() == 0
    assert adapted.max() == 1.0
    assert img.shape == adapted.shape
    full_scale = skimage.exposure.rescale_intensity(img)
    assert_almost_equal(peak_snr(full_scale, adapted), 102.940, 3)
    assert_almost_equal(norm_brightness_err(full_scale, adapted),
                        0.0110, 3)
    return data, adapted

def peak_snr(img1, img2):
    '''Peak signal to noise ratio of two images

    Parameters
    ----------
    img1 : array-like
    img2 : array-like

    Returns
    -------
    peak_snr : float
        Peak signal to noise ratio
    '''
    if img1.ndim == 3:
        img1, img2 = rgb2gray(img1.copy()), rgb2gray(img2.copy())
    img1 = skimage.img_as_float(img1)
    img2 = skimage.img_as_float(img2)
    mse = 1. / img1.size * np.square(img1 - img2).sum()
    _, max_ = dtype_range[img1.dtype.type]
    return 20 * np.log(max_ / mse)

def norm_brightness_err(img1, img2):
    '''Normalized Absolute Mean Brightness Error between two images

    Parameters
    ----------
    img1 : array-like
    img2 : array-like

    Returns
    -------
    norm_brightness_error : float
        Normalized absolute mean brightness error
    '''
    if img1.ndim == 3:
        img1, img2 = rgb2gray(img1), rgb2gray(img2)
    ambe = np.abs(img1.mean() - img2.mean())
    nbe = ambe / dtype_range[img1.dtype.type][1]
    return nbe

if __name__ == '__main__':
    from numpy import testing
    testing.run_module_suite()

# Test Gamma Correction
# =====================

def test_rescale_intensity_gamma_one():
    """Same image should be returned for gamma equal to one"""
    image = data.camera()
    result = exposure.rescale_intensity_gamma(image, 1)
    assert result.mean() == image.mean()
    assert result.std() == image.std()

def test_rescale_intensity_gamma_zero():
    """White image should be returned for gamma equal to zero"""
    image = data.camera()
    result = exposure.rescale_intensity_gamma(image, 0)
    dtype = image.dtype.type
    assert result.mean() == dtype_range[dtype][1]
    assert result.std() == 0

def test_rescale_intensity_gamma_less_one():
    """Output's mean should be greater than input's mean for gamma less than
    one"""
    image = data.camera()
    result = exposure.rescale_intensity_gamma(image, 0.5)
    assert result.mean() > image.mean()

def test_rescale_intensity_gamma_greater_one():
    """Output's mean should be less than input's mean for gamma greater than
    one"""
    image = data.camera()
    result = exposure.rescale_intensity_gamma(image, 2)
    assert result.mean() < image.mean()

# Test Logarithmic Correction
# ===========================

def test_rescale_intensity_logarithmic():
    """Output's mean should be greater than input's mean and all pixel values
    in output should be either greater than or equal to that of corresponding
    pixel in input for logarithmiccorrection with multiplier constant equal
    to unity"""
    image = data.camera()
    result = exposure.rescale_intensity_logarithmic(image, 1)
    assert result.mean() > image.mean()
    assert result.all() >= image.all()

def test_rescale_intensity_inv_logarithmic():
    """Output's mean should be less than input's mean and all pixel values
    in output should be either less than or equal to that of corresponding
    pixel in inputfor inverse logarithmic correction with multiplier constant
    equal to unity"""
    image = data.camera()
    result = exposure.rescale_intensity_logarithmic(image, 1, -1)
    assert result.mean() < image.mean()
    assert result.all() <= image.all()

# Test Sigmoid Correction
# =======================

def test_rescale_intensity_sigmoid_cutoff_one():
    """Output's std should be less than input's std and all pixel values
    in output should be either less than or equal to that of
    corresponding pixel in input for sigmoid correction with cutoff equal
    to one and gain of 10"""
    image = data.camera()
    result = exposure.rescale_intensity_sigmoid(image, 1, 10)
    assert result.std() < image.std()
    assert result.all() <= image.all()

def test_rescale_intensity_sigmoid_cutoff_zero():
    """Output's std should be less than input's std and all pixel values
    in output should be either greater than or equal to that of
    corresponding pixel in input for sigmoid correction with cutoff equal
    to zero and gain of 10"""
    image = data.camera()
    result = exposure.rescale_intensity_sigmoid(image, 0, 10)
    assert result.std() < image.std()
    assert result.all() >= image.all()

def test_rescale_intensity_sigmoid_cutoff_half():
    """Output's std should be greater than input's std for sigmoid
    correction with cutoff equal to 0.5 and gain of 10"""
    image = data.camera()
    result = exposure.rescale_intensity_sigmoid(image, 0.5, 10)
    assert result.std() > image.std()
<commit_msg>Added stronger tests<commit_after>import warnings

import numpy as np
from numpy.testing import assert_array_almost_equal as assert_close
from numpy.testing import assert_array_equal
import skimage
from skimage import data
from skimage import exposure
from skimage.color import rgb2gray
from skimage.util.dtype import dtype_range

# Test histogram equalization
# ===========================

# squeeze image intensities to lower image contrast
test_img = skimage.img_as_float(data.camera())
test_img = exposure.rescale_intensity(test_img / 5. + 100)

def test_equalize_ubyte():
    img = skimage.img_as_ubyte(test_img)
    img_eq = exposure.equalize_hist(img)

    cdf, bin_edges = exposure.cumulative_distribution(img_eq)
    check_cdf_slope(cdf)

def test_equalize_float():
    img = skimage.img_as_float(test_img)
    img_eq = exposure.equalize_hist(img)

    cdf, bin_edges = exposure.cumulative_distribution(img_eq)
    check_cdf_slope(cdf)

def check_cdf_slope(cdf):
    """Slope of cdf which should equal 1 for an equalized histogram."""
    norm_intensity = np.linspace(0, 1, len(cdf))
    slope, intercept = np.polyfit(norm_intensity, cdf, 1)
    assert 0.9 < slope < 1.1

# Test rescale intensity
# ======================

def test_rescale_stretch():
    image = np.array([51, 102, 153], dtype=np.uint8)
    out = exposure.rescale_intensity(image)
    assert out.dtype == np.uint8
    assert_close(out, [0, 127, 255])

def test_rescale_shrink():
    image = np.array([51., 102., 153.])
    out = exposure.rescale_intensity(image)
    assert_close(out, [0, 0.5, 1])

def test_rescale_in_range():
    image = np.array([51., 102., 153.])
    out = exposure.rescale_intensity(image, in_range=(0, 255))
    assert_close(out, [0.2, 0.4, 0.6])

def test_rescale_in_range_clip():
    image = np.array([51., 102., 153.])
    out = exposure.rescale_intensity(image, in_range=(0, 102))
    assert_close(out, [0.5, 1, 1])

def test_rescale_out_range():
    image = np.array([-10, 0, 10], dtype=np.int8)
    out = exposure.rescale_intensity(image, out_range=(0, 127))
    assert out.dtype == np.int8
    assert_close(out, [0, 63, 127])

# Test adaptive histogram equalization
# ====================================

def test_adapthist_scalar():
    '''Test a scalar uint8 image
    '''
    img = skimage.img_as_ubyte(data.moon())
    adapted = exposure.equalize_adapthist(img, clip_limit=0.02)
    assert adapted.min() == 0
    assert adapted.max() == (1 << 16) - 1
    assert img.shape == adapted.shape
    full_scale = skimage.exposure.rescale_intensity(skimage.img_as_uint(img))

    assert_almost_equal = np.testing.assert_almost_equal
    assert_almost_equal(peak_snr(full_scale, adapted), 101.231, 3)
    assert_almost_equal(norm_brightness_err(full_scale, adapted),
                        0.041, 3)
    return img, adapted

def test_adapthist_grayscale():
    '''Test a grayscale float image
    '''
    img = skimage.img_as_float(data.lena())
    img = rgb2gray(img)
    img = np.dstack((img, img, img))
    adapted = exposure.equalize_adapthist(img, 10, 9, clip_limit=0.01,
                        nbins=128)
    assert_almost_equal = np.testing.assert_almost_equal
    assert img.shape == adapted.shape
    assert_almost_equal(peak_snr(img, adapted), 97.531, 3)
    assert_almost_equal(norm_brightness_err(img, adapted), 0.0313, 3)
    return data, adapted

def test_adapthist_color():
    '''Test an RGB color uint16 image
    '''
    img = skimage.img_as_uint(data.lena())
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter('always')
        hist, bin_centers = exposure.histogram(img)
        assert len(w) > 0
    adapted = exposure.equalize_adapthist(img, clip_limit=0.01)
    assert_almost_equal = np.testing.assert_almost_equal
    assert adapted.min() == 0
    assert adapted.max() == 1.0
    assert img.shape == adapted.shape
    full_scale = skimage.exposure.rescale_intensity(img)
    assert_almost_equal(peak_snr(full_scale, adapted), 102.940, 3)
    assert_almost_equal(norm_brightness_err(full_scale, adapted),
                        0.0110, 3)
    return data, adapted

def peak_snr(img1, img2):
    '''Peak signal to noise ratio of two images

    Parameters
    ----------
    img1 : array-like
    img2 : array-like

    Returns
    -------
    peak_snr : float
        Peak signal to noise ratio
    '''
    if img1.ndim == 3:
        img1, img2 = rgb2gray(img1.copy()), rgb2gray(img2.copy())
    img1 = skimage.img_as_float(img1)
    img2 = skimage.img_as_float(img2)
    mse = 1. / img1.size * np.square(img1 - img2).sum()
    _, max_ = dtype_range[img1.dtype.type]
    return 20 * np.log(max_ / mse)

def norm_brightness_err(img1, img2):
    '''Normalized Absolute Mean Brightness Error between two images

    Parameters
    ----------
    img1 : array-like
    img2 : array-like

    Returns
    -------
    norm_brightness_error : float
        Normalized absolute mean brightness error
    '''
    if img1.ndim == 3:
        img1, img2 = rgb2gray(img1), rgb2gray(img2)
    ambe = np.abs(img1.mean() - img2.mean())
    nbe = ambe / dtype_range[img1.dtype.type][1]
    return nbe

if __name__ == '__main__':
    from numpy import testing
    testing.run_module_suite()

# Test Gamma Correction
# =====================

def test_rescale_intensity_gamma_one():
    """Same image should be returned for gamma equal to one"""
    image = data.camera()
    result = exposure.rescale_intensity_gamma(image, 1)
    assert_array_equal(result, image)

def test_rescale_intensity_gamma_zero():
    """White image should be returned for gamma equal to zero"""
    image = data.camera()
    result = exposure.rescale_intensity_gamma(image, 0)
    dtype = image.dtype.type
    assert result.mean() == dtype_range[dtype][1]
    assert result.std() == 0

def test_rescale_intensity_gamma_less_one():
    """Verifying the output with expected results for gamma
    correction with gamma equal to half"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[  0,  31,  45,  55,  63,  71,  78,  84],
        [ 90,  95, 100, 105, 110, 115, 119, 123],
        [127, 131, 135, 139, 142, 146, 149, 153],
        [156, 159, 162, 165, 168, 171, 174, 177],
        [180, 183, 186, 188, 191, 194, 196, 199],
        [201, 204, 206, 209, 211, 214, 216, 218],
        [221, 223, 225, 228, 230, 232, 234, 236],
        [238, 241, 243, 245, 247, 249, 251, 253]], dtype=np.uint8)

    result = exposure.rescale_intensity_gamma(image, 0.5)
    assert_array_equal(result, expected)

def test_rescale_intensity_gamma_greater_one():
    """Verifying the output with expected results for gamma
    correction with gamma equal to two"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[  0,   0,   0,   0,   1,   1,   2,   3],
        [  4,   5,   6,   7,   9,  10,  12,  14],
        [ 16,  18,  20,  22,  25,  27,  30,  33],
        [ 36,  39,  42,  45,  49,  52,  56,  60],
        [ 64,  68,  72,  76,  81,  85,  90,  95],
        [100, 105, 110, 116, 121, 127, 132, 138],
        [144, 150, 156, 163, 169, 176, 182, 189],
        [196, 203, 211, 218, 225, 233, 241, 249]], dtype=np.uint8)

    result = exposure.rescale_intensity_gamma(image, 2)
    assert_array_equal(result, expected)

# Test Logarithmic Correction
# ===========================

def test_rescale_intensity_logarithmic():
    """Verifying the output with expected results for logarithmic
    correction with multiplier constant multiplier equal to unity"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[  0,   5,  11,  16,  22,  27,  33,  38],
        [ 43,  48,  53,  58,  63,  68,  73,  77],
        [ 82,  86,  91,  95, 100, 104, 109, 113],
        [117, 121, 125, 129, 133, 137, 141, 145],
        [149, 153, 157, 160, 164, 168, 172, 175],
        [179, 182, 186, 189, 193, 196, 199, 203],
        [206, 209, 213, 216, 219, 222, 225, 228],
        [231, 234, 238, 241, 244, 246, 249, 252]], dtype=np.uint8)

    result = exposure.rescale_intensity_logarithmic(image, 1)
    assert_array_equal(result, expected)

def test_rescale_intensity_inv_logarithmic():
    """Verifying the output with expected results for inverse logarithmic
    correction with multiplier constant multiplier equal to unity"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[  0,   2,   5,   8,  11,  14,  17,  20],
        [ 23,  26,  29,  32,  35,  38,  41,  45],
        [ 48,  51,  55,  58,  61,  65,  68,  72],
        [ 76,  79,  83,  87,  90,  94,  98, 102],
        [106, 110, 114, 118, 122, 126, 130, 134],
        [138, 143, 147, 151, 156, 160, 165, 170],
        [174, 179, 184, 188, 193, 198, 203, 208],
        [213, 218, 224, 229, 234, 239, 245, 250]], dtype=np.uint8)

    result = exposure.rescale_intensity_logarithmic(image, 1, -1)
    assert_array_equal(result, expected)

# Test Sigmoid Correction
# =======================

def test_rescale_intensity_sigmoid_cutoff_one():
    """Verifying the output with expected results for sigmoid correction
    with cutoff equal to one and gain of 5"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[  1,   1,   1,   2,   2,   2,   2,   2],
        [  3,   3,   3,   4,   4,   4,   5,   5],
        [  5,   6,   6,   7,   7,   8,   9,  10],
        [ 10,  11,  12,  13,  14,  15,  16,  18],
        [ 19,  20,  22,  24,  25,  27,  29,  32],
        [ 34,  36,  39,  41,  44,  47,  50,  54],
        [ 57,  61,  64,  68,  72,  76,  80,  85],
        [ 89,  94,  99, 104, 108, 113, 118, 123]], dtype=np.uint8)

    result = exposure.rescale_intensity_sigmoid(image, 1, 5)
    assert_array_equal(result, expected)

def test_rescale_intensity_sigmoid_cutoff_zero():
    """Verifying the output with expected results for sigmoid correction
    with cutoff equal to zero and gain of 10"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[127, 137, 147, 156, 166, 175, 183, 191],
        [198, 205, 211, 216, 221, 225, 229, 232],
        [235, 238, 240, 242, 244, 245, 247, 248],
        [249, 250, 250, 251, 251, 252, 252, 253],
        [253, 253, 253, 253, 254, 254, 254, 254],
        [254, 254, 254, 254, 254, 254, 254, 254],
        [254, 254, 254, 254, 254, 254, 254, 254],
        [254, 254, 254, 254, 254, 254, 254, 254]], dtype=np.uint8)

    result = exposure.rescale_intensity_sigmoid(image, 0, 10)
    assert_array_equal(result, expected)

def test_rescale_intensity_sigmoid_cutoff_half():
    """Verifying the output with expected results for sigmoid correction
    with cutoff equal to half and gain of 10"""
    image = np.uint8(4 * np.arange(64).reshape(8,8))
    expected = np.array([[  1,   1,   2,   2,   3,   3,   4,   5],
        [  5,   6,   7,   9,  10,  12,  14,  16],
        [ 19,  22,  25,  29,  34,  39,  44,  50],
        [ 57,  64,  72,  80,  89,  99, 108, 118],
        [128, 138, 148, 158, 167, 176, 184, 192],
        [199, 205, 211, 217, 221, 226, 229, 233],
        [236, 238, 240, 242, 244, 246, 247, 248],
        [249, 250, 250, 251, 251, 252, 252, 253]], dtype=np.uint8)

    result = exposure.rescale_intensity_sigmoid(image, 0.5, 10)
    assert_array_equal(result, expected)
<|endoftext|>


<commit_before>#!/usr/bin/env python2
"""
Modified from http://kmkeen.com/socketserver/
"""

import socket
def client(string):
    HOST, PORT = '172.24.16.68', 6386
    # SOCK_STREAM == a TCP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #sock.setblocking(0)  # optional non-blocking
    sock.connect((HOST, PORT))
    sock.send(string)
    print "tx"
    reply = sock.recv(16384)  # limit reply to 16K
    print "rx"
    sock.close()
    print "close"
    return reply

#assert client('2+2') == '4'
i = client("INFO")
print "%r" % i<commit_msg>Working with socket<commit_after>#!/usr/bin/env python2
"""
Modified from http://kmkeen.com/socketserver/
"""

import socket
def client(string):
    HOST, PORT = '172.24.16.68', 6386
    # SOCK_STREAM == a TCP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #sock.setblocking(0)  # optional non-blocking
    sock.connect((HOST, PORT))
    sock.send(string)
    print "tx"
    reply = sock.recv(16384)  # limit reply to 16K
    print "rx"
    sock.close()
    print "close"
    return reply

#assert client('2+2') == '4'
i = client("INFO\n")
print "%r" % i<|endoftext|>


<commit_before>from . import wsgi_handler
from skitai.server import http_request, http_response
from skitai.lib import producers, compressors
from skitai.server.threads import trigger
import asynchat
from h2.connection import H2Connection
from h2.exceptions import ProtocolError
from h2.events import DataReceived, RequestReceived, StreamEnded, PriorityUpdated
from h2.errors import PROTOCOL_ERROR

try:
	from cStringIO import StringIO as BytesIO
except ImportError:
	from io import BytesIO
import threading

class http2_response (http_response.http_response):
	USE_DATA_COMPRESS = True

	def __init__ (self, request):
		http_response.http_response.__init__ (self, request)

	def push (self, thing):
		if not self.responsable (): return
		if type(thing) is bytes:
			self.outgoing.push (producers.simple_producer (thing))
		else:
			self.outgoing.push (thing)

	def build_reply_header (self):
		h = [(b":status", str (self.reply_code).encode ("utf8"))]
		for k, v in self.reply_headers:
			h.append ((k.encode ("utf8"), str (v).encode ("utf8")))
		return h

	def done (self, *args, **karg):
		# removed by HTTP/2.0 Spec.
		self.delete ('transfer-encoding')
		self.delete ('connection')

		if len (self.outgoing) == 0:
			outgoing_producer = None

		else:
			way_to_compress = ""
			if self.USE_DATA_COMPRESS and not self.has_key ('Content-Encoding'):
				maybe_compress = self.request.get_header ("Accept-Encoding")
				if maybe_compress and self.has_key ("content-length") and int (self ["Content-Length"]) <= http_response.UNCOMPRESS_MAX:
					maybe_compress = ""
				else:
					content_type = self ["Content-Type"]
					if maybe_compress and content_type and (content_type.startswith ("text/") or content_type.endswith ("/json-rpc")):
						accept_encoding = [x.strip () for x in maybe_compress.split (",")]
						if "gzip" in accept_encoding:
							way_to_compress = "gzip"
						elif "deflate" in accept_encoding:
							way_to_compress = "deflate"

				if way_to_compress:
					if self.has_key ('Content-Length'):
						self.delete ("content-length") # rebuild
					self.update ('Content-Encoding', way_to_compress)

			if way_to_compress:
				if way_to_compress == "gzip":
					producer = producers.gzipped_producer
				else: # deflate
					producer = producers.compressed_producer
				outgoing_producer = producer (producers.composite_producer (self.outgoing))
			else:
				outgoing_producer = producers.composite_producer (self.outgoing)

			outgoing_producer = producers.globbing_producer (producers.hooked_producer (outgoing_producer, self.log))

		self.request.http2.push_response (
			self.request.stream_id,
			self.build_reply_header (),
			outgoing_producer
		)

class http2_request (http_request.http_request):
	def __init__ (self, *args):
		self.request_number = self.request_count.inc()
		(self.http2, self.channel, self.request,
		 self.command, self.uri, self.version,
		 self.header,
		 self.stream_id) = args

		self.logger = self.channel.server.server_logger
		self.server_ident = self.channel.server.SERVER_IDENT
		self.body = None
		self.reply_code = 200
		self.reply_message = ""
		self._split_uri = None
		self._header_cache = {}
		self.gzip_encoded = False
		self.response = http2_response (self)

class priority_producer_fifo:
	def __init__ (self):
		self.l = []
		self._lock = threading.Lock ()

	def __len__ (self):
		with self._lock:
			l = len (self.l)
		return l

	def __getitem__(self, index):
		with self._lock:
			i = self.l [index]
		return i

	def __setitem__(self, index, item):
		with self._lock:
			self.l.insert (index, item)

	def __delitem__ (self, index):
		with self._lock:
			del self.l [index]

	def append (self, item):
		try:
			w1 = item.weight
			d1 = item.depends_on
		except AttributeError:
			with self._lock:
				self.l.append (item)
			return

		index = 0
		inserted = False
		with self._lock:
			for each in self.l:
				try:
					w2 = each.weight
					d2 = each.depends_on
				except AttributeError:
					pass
				else:
					if d2 >= d1 and w2 <= w1:
						self.l.insert (index, item)
						inserted = True
						break
				index += 1

		if not inserted:
			with self._lock:
				self.l.append (item)

		#with self._lock:
		#	print ('+++++++++++++++++', self.l)

	def appendleft (self, item):
		with self._lock:
			self.l.insert (0, item)

	def clear (self):
		with self._lock:
			self.l = []

class fake_channel (asynchat.async_chat):
	def __init__ (self, channel):
		asynchat.async_chat.__init__ (self)
		self._channel = channel
		self._data = b""

		# override members
		self.addr = channel.addr
		self.connected = channel.connected

	def __getattr__ (self, attr):
		return getattr (self._channel, attr)

	def set_data (self, data):
		self._data = data

	def recv (self, buffer_size):
		data, self._data = self._data, b""
		return data

	def collect_incoming_data (self, data):
		self.current_request.collect_incoming_data (data)

	def found_terminator (self):
		self.current_request.found_terminator ()

class HTTP2:
	collector = None
	producer = None

	def __init__ (self, handler, request):
		self.handler = handler
		self.wasc = handler.wasc
		self.request = request
		self.channel = request.channel
		self.conn = H2Connection(client_side = False)
		self.channel.producer_fifo = priority_producer_fifo ()
		self.channel.push (self.get_connection_preface ())

		self.data_length = 0
		self.rfile = BytesIO ()
		self.buf = b""

		self.stream_data = {}
		self.stream_weights = {}

		self._closed = False
		self._got_preamble = False

		self._plock = threading.Lock ()
		self._clock = threading.Lock ()

		if self.request.version == "1.1":
			self.channel.set_terminator (18) # PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
		else:
			self.conn.receive_data (b"PRI * HTTP/2.0\r\n\r\n")
			self.channel.set_terminator (6) # SM\r\n\r\n

	def close (self):
		if self._closed: return
		self._closed = True
		if self.channel:
			self.channel.current_request = None  # break circ. ref
		self.handler.finish_request (self.request)

	def closed (self):
		return self._closed

	def get_connection_preface (self):
		h2settings = self.request.get_header ("HTTP2-Settings")
		if h2settings:
			self.conn.initiate_upgrade_connection (h2settings)
		else:
			self.conn.initiate_connection()
		return self.conn.data_to_send ()

	def collect_incoming_data (self, data):
		#print ("RECV", repr (data), len (data), '::', self.channel.get_terminator ())
		if not data:
			# closed connection
			self.close ()
			return

		if self.data_length:
			self.rfile.write (data)
		else:
			self.buf += data

	def found_terminator (self):
		buf, self.buf = self.buf, b""

		#print ("FOUND", repr (buf), '::', self.data_length, self.channel.get_terminator ())
		events = None
		if not self._got_preamble:
			events = self.conn.receive_data (buf)
			self.channel.set_terminator (9)
			self._got_preamble = True

		elif self.data_length:
			events = self.conn.receive_data (self.rfile.getvalue ())
			self.data_length = 0
			self.rfile.seek (0)
			self.rfile.truncate ()
			self.channel.set_terminator (9) # for frame header

		elif buf:
			events = self.conn.receive_data (buf)
			self.data_length = self.conn.incoming_buffer._parse_frame_header (buf) [-1]
			self.channel.set_terminator (self.data_length == 0 and 9 or self.data_length)	# next frame header

		else:
			raise ProtocolError ("Frame decode error")

		if events:
			self.handle_events (events)

	def push_response (self, stream_id, headers, producer):
		with self._clock:
			try:
				depends_on, weight = self.stream_weights [stream_id]
			except KeyError:
				depends_on, weight = 0, 1

		#import random
		#weight = random.randrange (1, 256)
		outgoing_producer = producers.h2stream_producer (stream_id, depends_on, weight, headers, producer, self.conn, self._plock)

		with self._clock:
			try:
				del self.stream_weights [stream_id]
			except KeyError:
				pass

			r = None
			try:
				r = self.stream_data [stream_id]
			except KeyError:
				pass
			else:
				del self.stream_data [stream_id]

			if r:
				r.http2 = None # break bacj ref.

		self.channel.push_with_producer (outgoing_producer)

	def handle_events (self, events):
		for event in events:
			#print (event)
			if isinstance(event, RequestReceived):
				self.handle_request (event)

			elif isinstance(event, PriorityUpdated):
				if event.exclusive:
					# rebuild depend_ons
					with self._clock:
						for stream_id in list (self.stream_weights.keys ()):
							depends_on, weight = self.stream_weights [stream_id]
							if depends_on == event.depends_on:
								self.stream_weights [stream_id] = (event.stream_id, weight)

				with self._clock:
					self.stream_weights [event.stream_id] = (event.depends_on, event.weight)

			elif isinstance(event, DataReceived):
				r = None
				with self._clock:
					try:
						r = self.stream_data [event.stream_id]
					except KeyError:
						pass

				# POST, PUT method
				if r:
					r.channel.set_data (event.data)
					r.channel.handle_read ()

			elif isinstance(event, StreamEnded):
				r = None
				with self._clock:
					try:
						r = self.stream_data [event.stream_id]
					except KeyError:
						# GET,... method
						pass

				if r and r.collector:
					raise ProtocolError ("Data frame not complete")

		data_to_send = self.conn.data_to_send ()
		if data_to_send:
			self.channel.push (data_to_send)

	def handle_request (self, event):
		command = "GET"
		uri = "/"
		headers = []
		for k, v in event.headers:
			if k[0] == ":":
				if k == ":method": command = v
				elif k == ":path": uri = v
				continue
			headers.append ("%s: %s" % (k, v))

		fch = fake_channel (self.channel)
		r = http2_request (self, fch, "%s %s HTTP/2.0" % (command, uri), command.lower (), uri, "2.0", headers, event.stream_id)
		fch.current_request = r

		self.channel.request_counter.inc()
		self.channel.server.total_requests.inc()

		for h in self.channel.server.handlers:
			if h.match (r):
				try:
					h.handle_request (r)
				except:
					self.channel.server.trace()
					try: r.response.error (500)
					except: pass
				else:
					if r.collector:
						with self._clock:
							self.stream_data [event.stream_id] = r
				return

		try: r.response.error (404)
		except: pass

class Handler (wsgi_handler.Handler):
	KEEP_ALIVE = 300
	def match (self, request):
		if request.command == "pri" and request.uri == "*" and request.version == "2.0":
			return True
		upgrade = request.get_header ("upgrade")
		return upgrade and upgrade.lower () == "h2c" and request.version == "1.1" and request.command == "get"

	def handle_request (self, request):
		if request.version == "1.1":
			header = [
				("Connection", "Upgrade"),
				("Upgrade", "h2c")
			]
			request.response.start_response ("101 Switching Protocols", header)
			request.response.done ()

		http2 = HTTP2 (self, request)
		request.channel.current_request = http2
		request.channel.set_response_timeout (self.KEEP_ALIVE)
		request.channel.set_keep_alive (self.KEEP_ALIVE)

	def finish_request (self, request):
		if request.channel:
			request.channel.close_when_done ()

	<commit_msg>0.16 - http2<commit_after>from . import wsgi_handler
from skitai.server import http_request, http_response
from skitai.lib import producers, compressors
from skitai.server.threads import trigger
import asynchat
from h2.connection import H2Connection
from h2.exceptions import ProtocolError
from h2.events import DataReceived, RequestReceived, StreamEnded, PriorityUpdated
from h2.errors import PROTOCOL_ERROR

try:
	from cStringIO import StringIO as BytesIO
except ImportError:
	from io import BytesIO
import threading

class http2_response (http_response.http_response):
	USE_DATA_COMPRESS = True

	def __init__ (self, request):
		http_response.http_response.__init__ (self, request)

	def push (self, thing):
		if not self.responsable (): return
		if type(thing) is bytes:
			self.outgoing.push (producers.simple_producer (thing))
		else:
			self.outgoing.push (thing)

	def build_reply_header (self):
		h = [(b":status", str (self.reply_code).encode ("utf8"))]
		for k, v in self.reply_headers:
			h.append ((k.encode ("utf8"), str (v).encode ("utf8")))
		return h

	def done (self, *args, **karg):
		# removed by HTTP/2.0 Spec.
		self.delete ('transfer-encoding')
		self.delete ('connection')

		if len (self.outgoing) == 0:
			outgoing_producer = None

		else:
			way_to_compress = ""
			if self.USE_DATA_COMPRESS and not self.has_key ('Content-Encoding'):
				maybe_compress = self.request.get_header ("Accept-Encoding")
				if maybe_compress and self.has_key ("content-length") and int (self ["Content-Length"]) <= http_response.UNCOMPRESS_MAX:
					maybe_compress = ""
				else:
					content_type = self ["Content-Type"]
					if maybe_compress and content_type and (content_type.startswith ("text/") or content_type.endswith ("/json-rpc")):
						accept_encoding = [x.strip () for x in maybe_compress.split (",")]
						if "gzip" in accept_encoding:
							way_to_compress = "gzip"
						elif "deflate" in accept_encoding:
							way_to_compress = "deflate"

				if way_to_compress:
					if self.has_key ('Content-Length'):
						self.delete ("content-length") # rebuild
					self.update ('Content-Encoding', way_to_compress)

			if way_to_compress:
				if way_to_compress == "gzip":
					producer = producers.gzipped_producer
				else: # deflate
					producer = producers.compressed_producer
				outgoing_producer = producer (producers.composite_producer (self.outgoing))
			else:
				outgoing_producer = producers.composite_producer (self.outgoing)

			outgoing_producer = producers.globbing_producer (producers.hooked_producer (outgoing_producer, self.log))

		self.request.http2.push_response (
			self.request.stream_id,
			self.build_reply_header (),
			outgoing_producer
		)

class http2_request (http_request.http_request):
	def __init__ (self, *args):
		self.request_number = self.request_count.inc()
		(self.http2, self.channel, self.request,
		 self.command, self.uri, self.version,
		 self.header,
		 self.stream_id) = args

		self.logger = self.channel.server.server_logger
		self.server_ident = self.channel.server.SERVER_IDENT
		self.body = None
		self.reply_code = 200
		self.reply_message = ""
		self._split_uri = None
		self._header_cache = {}
		self.gzip_encoded = False
		self.response = http2_response (self)

class priority_producer_fifo:
	def __init__ (self):
		self.l = []
		self._lock = threading.Lock ()

	def __len__ (self):
		with self._lock:
			l = len (self.l)
		return l

	def __getitem__(self, index):
		with self._lock:
			i = self.l [index]
		return i

	def __setitem__(self, index, item):
		with self._lock:
			self.l.insert (index, item)

	def __delitem__ (self, index):
		with self._lock:
			del self.l [index]

	def append (self, item):
		try:
			w1 = item.weight
			d1 = item.depends_on
		except AttributeError:
			with self._lock:
				self.l.append (item)
			return

		index = 0
		inserted = False
		with self._lock:
			for each in self.l:
				try:
					w2 = each.weight
					d2 = each.depends_on
				except AttributeError:
					pass
				else:
					if d2 >= d1 and w2 <= w1:
						self.l.insert (index, item)
						inserted = True
						break
				index += 1

		if not inserted:
			with self._lock:
				self.l.append (item)

		#with self._lock:
		#	print ('+++++++++++++++++', self.l)

	def appendleft (self, item):
		with self._lock:
			self.l.insert (0, item)

	def clear (self):
		with self._lock:
			self.l = []

class fake_channel (asynchat.async_chat):
	def __init__ (self, channel):
		asynchat.async_chat.__init__ (self)
		self._channel = channel
		self._data = b""

		# override members
		self.addr = channel.addr
		self.connected = channel.connected

	def __getattr__ (self, attr):
		return getattr (self._channel, attr)

	def set_data (self, data):
		self._data = data

	def recv (self, buffer_size):
		data, self._data = self._data, b""
		return data

	def collect_incoming_data (self, data):
		self.current_request.collect_incoming_data (data)

	def found_terminator (self):
		self.current_request.found_terminator ()

class HTTP2:
	collector = None
	producer = None

	def __init__ (self, handler, request):
		self.handler = handler
		self.wasc = handler.wasc
		self.request = request
		self.channel = request.channel
		self.channel.producer_fifo = priority_producer_fifo ()

		self.conn = H2Connection(client_side = False)
		self.frame_buf = self.conn.incoming_buffer
		self.channel.push (self.get_connection_preface ())

		self.data_length = 0
		self.current_frame = None
		self.rfile = BytesIO ()
		self.buf = b""

		self.stream_data = {}
		self.stream_weights = {}

		self._closed = False
		self._got_preamble = False

		self._plock = threading.Lock ()
		self._clock = threading.Lock ()

		if self.request.version == "1.1":
			self.channel.set_terminator (18) # PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
		else:
			self.conn.receive_data (b"PRI * HTTP/2.0\r\n\r\n")
			self.channel.set_terminator (6) # SM\r\n\r\n

	def close (self):
		if self._closed: return
		self._closed = True
		if self.channel:
			self.channel.current_request = None  # break circ. ref
		self.handler.finish_request (self.request)

	def closed (self):
		return self._closed

	def get_connection_preface (self):
		h2settings = self.request.get_header ("HTTP2-Settings")
		if h2settings:
			self.conn.initiate_upgrade_connection (h2settings)
		else:
			self.conn.initiate_connection()
		return self.conn.data_to_send ()

	def collect_incoming_data (self, data):
		#print ("RECV", repr (data), len (data), '::', self.channel.get_terminator ())
		if not data:
			# closed connection
			self.close ()
			return

		if self.data_length:
			self.rfile.write (data)
		else:
			self.buf += data

	def set_frame_data (self, data):
		if not self.current_frame:
			return []
		self.current_frame.parse_body (memoryview (data))
		self.current_frame = self.frame_buf._update_header_buffer (self.current_frame)
		return self.conn._receive_frame(self.current_frame)

	def found_terminator (self):
		buf, self.buf = self.buf, b""

		#print ("FOUND", repr (buf), '::', self.data_length, self.channel.get_terminator ())
		events = None
		if not self._got_preamble:
			self.conn.receive_data (buf)
			self.channel.set_terminator (9)
			self._got_preamble = True

		elif self.data_length:
			events = self.set_frame_data (self.rfile.getvalue ())
			self.data_length = 0
			self.current_frame = None
			self.rfile.seek (0)
			self.rfile.truncate ()
			self.channel.set_terminator (9) # for frame header

		elif buf:
			self.current_frame, self.data_length = self.frame_buf._parse_frame_header (buf)
			if self.data_length == 0:
				events = self.set_frame_data (b'')
			self.channel.set_terminator (self.data_length == 0 and 9 or self.data_length)	# next frame header

		else:
			raise ProtocolError ("Frame decode error")

		if events:
			self.handle_events (events)

	def push_response (self, stream_id, headers, producer):
		with self._clock:
			try:
				depends_on, weight = self.stream_weights [stream_id]
			except KeyError:
				depends_on, weight = 0, 1

		#import random
		#weight = random.randrange (1, 256)
		outgoing_producer = producers.h2stream_producer (stream_id, depends_on, weight, headers, producer, self.conn, self._plock)

		with self._clock:
			try:
				del self.stream_weights [stream_id]
			except KeyError:
				pass

			r = None
			try:
				r = self.stream_data [stream_id]
			except KeyError:
				pass
			else:
				del self.stream_data [stream_id]

			if r:
				r.http2 = None # break bacj ref.

		self.channel.push_with_producer (outgoing_producer)

	def handle_events (self, events):
		for event in events:
			#print (event)
			if isinstance(event, RequestReceived):
				self.handle_request (event)

			elif isinstance(event, PriorityUpdated):
				if event.exclusive:
					# rebuild depend_ons
					with self._clock:
						for stream_id in list (self.stream_weights.keys ()):
							depends_on, weight = self.stream_weights [stream_id]
							if depends_on == event.depends_on:
								self.stream_weights [stream_id] = (event.stream_id, weight)

				with self._clock:
					self.stream_weights [event.stream_id] = (event.depends_on, event.weight)

			elif isinstance(event, DataReceived):
				r = None
				with self._clock:
					try:
						r = self.stream_data [event.stream_id]
					except KeyError:
						pass

				# POST, PUT method
				if r:
					r.channel.set_data (event.data)
					r.channel.handle_read ()

			elif isinstance(event, StreamEnded):
				r = None
				with self._clock:
					try:
						r = self.stream_data [event.stream_id]
					except KeyError:
						# GET,... method
						pass

				if r and r.collector:
					raise ProtocolError ("Data frame not complete")

		data_to_send = self.conn.data_to_send ()
		if data_to_send:
			self.channel.push (data_to_send)

	def handle_request (self, event):
		command = "GET"
		uri = "/"
		headers = []
		for k, v in event.headers:
			if k[0] == ":":
				if k == ":method": command = v
				elif k == ":path": uri = v
				continue
			headers.append ("%s: %s" % (k, v))

		fch = fake_channel (self.channel)
		r = http2_request (self, fch, "%s %s HTTP/2.0" % (command, uri), command.lower (), uri, "2.0", headers, event.stream_id)
		fch.current_request = r

		self.channel.request_counter.inc()
		self.channel.server.total_requests.inc()

		for h in self.channel.server.handlers:
			if h.match (r):
				try:
					h.handle_request (r)
				except:
					self.channel.server.trace()
					try: r.response.error (500)
					except: pass
				else:
					if r.collector:
						with self._clock:
							self.stream_data [event.stream_id] = r
				return

		try: r.response.error (404)
		except: pass

class Handler (wsgi_handler.Handler):
	KEEP_ALIVE = 300
	def match (self, request):
		if request.command == "pri" and request.uri == "*" and request.version == "2.0":
			return True
		upgrade = request.get_header ("upgrade")
		return upgrade and upgrade.lower () == "h2c" and request.version == "1.1" and request.command == "get"

	def handle_request (self, request):
		if request.version == "1.1":
			header = [
				("Connection", "Upgrade"),
				("Upgrade", "h2c")
			]
			request.response.start_response ("101 Switching Protocols", header)
			request.response.done ()

		http2 = HTTP2 (self, request)
		request.channel.current_request = http2
		request.channel.set_response_timeout (self.KEEP_ALIVE)
		request.channel.set_keep_alive (self.KEEP_ALIVE)

	def finish_request (self, request):
		if request.channel:
			request.channel.close_when_done ()

	<|endoftext|>


<commit_before>from django.conf import settings
from django.db.models import query
from django.db import models
from django.core.urlresolvers import reverse
from django.db.utils import IntegrityError
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
import hashlib
from datetime import datetime
import logging
from softdelete.signals import *

def _determine_change_set(obj, create=True):
    try:
        qs = SoftDeleteRecord.objects.filter(content_type=ContentType.objects.get_for_model(obj),
                                      object_id=obj.pk).latest('created_date').changeset
        logging.debug("Found changeset via latest recordset")
    except:
        try:
            qs = ChangeSet.objects.filter(content_type=ContentType.objects.get_for_model(obj),
                                          object_id=obj.pk).latest('created_date')
            logging.debug("Found changeset")
        except:
            if create:
                qs = ChangeSet.objects.create(content_type=ContentType.objects.get_for_model(obj),
                                              object_id=obj.pk)
                logging.debug("Creating changeset")
            else:
                logging.debug("Raising ObjectDoesNotExist")
                raise ObjectDoesNotExist
    return qs

class SoftDeleteQuerySet(query.QuerySet):
    # cpbotha: temporarily disabled. What is this for? The double return at the
    # end is also suspicious.
    def get2(self, *args, **kwargs):
        ms = models.Manager()
        ms.model = self.model
        return ms.get(*args, **kwargs)
        return self.model.objects.all_with_deleted().get(*args, **kwargs)

    def delete(self, using=settings.DATABASES['default'], *args, **kwargs):
        if not len(self):
            return
        cs = kwargs.get('changeset')
        logging.debug("STARTING QUERYSET SOFT-DELETE: %s. %s" % (self, len(self)))
        for obj in self:
            rs, c = SoftDeleteRecord.objects.get_or_create(changeset=cs or _determine_change_set(obj),
                                                    content_type=ContentType.objects.get_for_model(obj),
                                                    object_id=obj.pk)
            logging.debug(" -----  CALLING delete() on %s" % obj)
            obj.delete(using, *args, **kwargs)

    def undelete(self, using=settings.DATABASES['default'], *args, **kwargs):
        logging.debug("UNDELETING %s" % self)
        for obj in self:
            cs = _determine_change_set(obj)
            cs.undelete()
        logging.debug("FINISHED UNDELETING %s" %self)

class SoftDeleteManager(models.Manager):
    def get_query_set(self):
        qs = super(SoftDeleteManager,self).get_query_set().filter(deleted_at__isnull=1)
        qs.__class__ = SoftDeleteQuerySet
        return qs

    def all_with_deleted(self):
        qs = super(SoftDeleteManager, self).get_query_set()
        qs.__class__ = SoftDeleteQuerySet
        return qs

    def deleted_set(self):
        qs = super(SoftDeleteManager, self).get_query_set().filter(deleted_at__isnull=0)
        qs.__class__ = SoftDeleteQuerySet
        return qs

    def get(self, *args, **kwargs):
        return self.all_with_deleted().get(*args, **kwargs)

    def filter(self, *args, **kwargs):
        if 'pk' in kwargs:
            qs = self.all_with_deleted().filter(*args, **kwargs)
        else:
            qs = self.get_query_set().filter(*args, **kwargs)
        qs.__class__ = SoftDeleteQuerySet
        return qs

class SoftDeleteObject(models.Model):
    deleted_at = models.DateTimeField(blank=True, null=True, default=None)
    objects = SoftDeleteManager()
    class Meta:
        abstract = True
        permissions = (
            ('can_undelete', 'Can undelete this object'),
            )

    def __init__(self, *args, **kwargs):
        super(SoftDeleteObject, self).__init__(*args, **kwargs)
        self.__dirty = False

    def get_deleted(self):
        return self.deleted_at != None

    def set_deleted(self, d):
        """Called via the admin interface (if user checks the "deleted" checkox)"::
        if d != self.deleted_flag:
            self.__dirty = True
        self.deleted_at = datetime.utcnow()

    deleted = property(get_deleted)

    def _do_delete(self, changeset, related):
        rel = related.get_accessor_name()
        try:
            getattr(self, rel).all().delete(changeset=changeset)
        except:
            try:
                getattr(self, rel).all().delete()
            except:
                getattr(self, rel).__class__.objects.all().delete()

    def delete(self, using=settings.DATABASES['default'], *args, **kwargs):
        models.signals.pre_delete.send(sender=self.__class__,
                                       instance=self,
                                       using=using)
        pre_soft_delete.send(sender=self.__class__,
                             instance=self,
                             using=using)
        logging.debug('SOFT DELETING type: %s, %s' % (type(self), self))
        cs = kwargs.get('changeset') or _determine_change_set(self)
        SoftDeleteRecord.objects.get_or_create(changeset=cs,
                                        content_type=ContentType.objects.get_for_model(self),
                                        object_id=self.pk)
        self.deleted_at = datetime.today()
        self.save()
        for x in self._meta.get_all_related_objects():
            self._do_delete(cs, x)
        for x in self._meta.get_all_related_many_to_many_objects():
            self._do_delete(cs, x)
        logging.debug("FINISHED SOFT DELETING RELATED %s" % self)
        models.signals.post_delete.send(sender=self.__class__,
                                        instance=self,
                                        using=using)
        post_soft_delete.send(sender=self.__class__,
                              instance=self,
                              using=using)

    def _do_undelete(self, using=settings.DATABASES['default']):
        pre_undelete.send(sender=self.__class__,
                          instance=self,
                          using=using)
        self.deleted_at = None
        self.save()
        post_undelete.send(sender=self.__class__,
                           instance=self,
                           using=using)

    def undelete(self, using=settings.DATABASES['default'], *args, **kwargs):
        logging.debug('UNDELETING %s' % self)
        cs = kwargs.get('changeset') or _determine_change_set(self, False)
        cs.undelete(using)
        logging.debug('FINISHED UNDELETING RELATED %s' % self)

    def save(self, **kwargs):
        super(SoftDeleteObject, self).save(**kwargs)
        if self.__dirty:
            self.__dirty = False
            if not self.deleted:
                self.undelete()
            else:
                self.delete()

class ChangeSet(models.Model):
    created_date = models.DateTimeField(default=datetime.utcnow)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    record = generic.GenericForeignKey('content_type', 'object_id')

    def get_content(self):
        self.record = self.content_type.model_class().objects.get(pk=self.object_id)
        return self.record

    def set_content(self, obj):
        self.record = obj

    def undelete(self, using=settings.DATABASES['default']):
        logging.debug("CHANGESET UNDELETE: %s" % self)
        self.content._do_undelete(using)
        for related in self.soft_delete_records.all():
            related.undelete(using)
        self.delete()
        logging.debug("FINISHED CHANGESET UNDELETE: %s" % self)

    def __unicode__(self):
        return 'Changeset: %s, %s' % (self.created_date, self.record)

    content = property(get_content, set_content)

class SoftDeleteRecord(models.Model):
    changeset = models.ForeignKey(ChangeSet, related_name='soft_delete_records')
    created_date = models.DateTimeField(default=datetime.utcnow)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    record = generic.GenericForeignKey('content_type', 'object_id')

    class Meta:
        unique_together= (('changeset', 'content_type', 'object_id'),)

    def get_content(self):
        self.record = self.content_type.model_class().objects.get(pk=self.object_id)
        return self.record

    def set_content(self, obj):
        self.record = obj

    def undelete(self, using=settings.DATABASES['default']):
        self.content._do_undelete(using)

    def __unicode__(self):
        return u'SoftDeleteRecord: (%s), (%s/%s), %s' % (self.content,
                                                  self.content_type,
                                                  self.object_id,
                                                  self.changeset.created_date)

    content = property(get_content, set_content)

<commit_msg>Changes due to cpbotha's fork; using deleted_at instead of deleted_flag<commit_after>from django.conf import settings
from django.db.models import query
from django.db import models
from django.core.urlresolvers import reverse
from django.db.utils import IntegrityError
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
import hashlib
from datetime import datetime
import logging
from softdelete.signals import *

def _determine_change_set(obj, create=True):
    try:
        qs = SoftDeleteRecord.objects.filter(content_type=ContentType.objects.get_for_model(obj),
                                      object_id=obj.pk).latest('created_date').changeset
        logging.debug("Found changeset via latest recordset")
    except:
        try:
            qs = ChangeSet.objects.filter(content_type=ContentType.objects.get_for_model(obj),
                                          object_id=obj.pk).latest('created_date')
            logging.debug("Found changeset")
        except:
            if create:
                qs = ChangeSet.objects.create(content_type=ContentType.objects.get_for_model(obj),
                                              object_id=obj.pk)
                logging.debug("Creating changeset")
            else:
                logging.debug("Raising ObjectDoesNotExist")
                raise ObjectDoesNotExist
    return qs

class SoftDeleteQuerySet(query.QuerySet):
    # cpbotha: temporarily disabled. What is this for? The double return at the
    # end is also suspicious.
    def get2(self, *args, **kwargs):
        ms = models.Manager()
        ms.model = self.model
        return ms.get(*args, **kwargs)
        return self.model.objects.all_with_deleted().get(*args, **kwargs)

    def delete(self, using=settings.DATABASES['default'], *args, **kwargs):
        if not len(self):
            return
        cs = kwargs.get('changeset')
        logging.debug("STARTING QUERYSET SOFT-DELETE: %s. %s" % (self, len(self)))
        for obj in self:
            rs, c = SoftDeleteRecord.objects.get_or_create(changeset=cs or _determine_change_set(obj),
                                                    content_type=ContentType.objects.get_for_model(obj),
                                                    object_id=obj.pk)
            logging.debug(" -----  CALLING delete() on %s" % obj)
            obj.delete(using, *args, **kwargs)

    def undelete(self, using=settings.DATABASES['default'], *args, **kwargs):
        logging.debug("UNDELETING %s" % self)
        for obj in self:
            cs = _determine_change_set(obj)
            cs.undelete()
        logging.debug("FINISHED UNDELETING %s" %self)

class SoftDeleteManager(models.Manager):
    def get_query_set(self):
        qs = super(SoftDeleteManager,self).get_query_set().filter(deleted_at__isnull=1)
        qs.__class__ = SoftDeleteQuerySet
        return qs

    def all_with_deleted(self):
        qs = super(SoftDeleteManager, self).get_query_set()
        qs.__class__ = SoftDeleteQuerySet
        return qs

    def deleted_set(self):
        qs = super(SoftDeleteManager, self).get_query_set().filter(deleted_at__isnull=0)
        qs.__class__ = SoftDeleteQuerySet
        return qs

    def get(self, *args, **kwargs):
        return self.all_with_deleted().get(*args, **kwargs)

    def filter(self, *args, **kwargs):
        if 'pk' in kwargs:
            qs = self.all_with_deleted().filter(*args, **kwargs)
        else:
            qs = self.get_query_set().filter(*args, **kwargs)
        qs.__class__ = SoftDeleteQuerySet
        return qs

class SoftDeleteObject(models.Model):
    deleted_at = models.DateTimeField(blank=True, null=True, default=None)
    objects = SoftDeleteManager()
    class Meta:
        abstract = True
        permissions = (
            ('can_undelete', 'Can undelete this object'),
            )

    def __init__(self, *args, **kwargs):
        super(SoftDeleteObject, self).__init__(*args, **kwargs)
        self.__dirty = False

    def get_deleted(self):
        return self.deleted_at != None

    def set_deleted(self, d):
        """Called via the admin interface (if user checks the "deleted" checkox)"""
        if d and not self.deleted_at:
            self.__dirty = True
            self.deleted_at = datetime.utcnow()
        elif not d and self.deleted_at:
            self.__dirty = True
            self.deleted_at = datetime.utcnow()

    deleted = property(get_deleted, set_deleted)

    def _do_delete(self, changeset, related):
        rel = related.get_accessor_name()
        try:
            getattr(self, rel).all().delete(changeset=changeset)
        except:
            try:
                getattr(self, rel).all().delete()
            except:
                getattr(self, rel).__class__.objects.all().delete()

    def delete(self, using=settings.DATABASES['default'], *args, **kwargs):
        models.signals.pre_delete.send(sender=self.__class__,
                                       instance=self,
                                       using=using)
        pre_soft_delete.send(sender=self.__class__,
                             instance=self,
                             using=using)
        logging.debug('SOFT DELETING type: %s, %s' % (type(self), self))
        cs = kwargs.get('changeset') or _determine_change_set(self)
        SoftDeleteRecord.objects.get_or_create(changeset=cs,
                                        content_type=ContentType.objects.get_for_model(self),
                                        object_id=self.pk)
        self.deleted_at = datetime.today()
        self.save()
        for x in self._meta.get_all_related_objects():
            self._do_delete(cs, x)
        for x in self._meta.get_all_related_many_to_many_objects():
            self._do_delete(cs, x)
        logging.debug("FINISHED SOFT DELETING RELATED %s" % self)
        models.signals.post_delete.send(sender=self.__class__,
                                        instance=self,
                                        using=using)
        post_soft_delete.send(sender=self.__class__,
                              instance=self,
                              using=using)

    def _do_undelete(self, using=settings.DATABASES['default']):
        pre_undelete.send(sender=self.__class__,
                          instance=self,
                          using=using)
        self.deleted_at = None
        self.save()
        post_undelete.send(sender=self.__class__,
                           instance=self,
                           using=using)

    def undelete(self, using=settings.DATABASES['default'], *args, **kwargs):
        logging.debug('UNDELETING %s' % self)
        cs = kwargs.get('changeset') or _determine_change_set(self, False)
        cs.undelete(using)
        logging.debug('FINISHED UNDELETING RELATED %s' % self)

    def save(self, **kwargs):
        super(SoftDeleteObject, self).save(**kwargs)
        if self.__dirty:
            self.__dirty = False
            if not self.deleted:
                self.undelete()
            else:
                self.delete()

class ChangeSet(models.Model):
    created_date = models.DateTimeField(default=datetime.utcnow)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    record = generic.GenericForeignKey('content_type', 'object_id')

    def get_content(self):
        self.record = self.content_type.model_class().objects.get(pk=self.object_id)
        return self.record

    def set_content(self, obj):
        self.record = obj

    def undelete(self, using=settings.DATABASES['default']):
        logging.debug("CHANGESET UNDELETE: %s" % self)
        self.content._do_undelete(using)
        for related in self.soft_delete_records.all():
            related.undelete(using)
        self.delete()
        logging.debug("FINISHED CHANGESET UNDELETE: %s" % self)

    def __unicode__(self):
        return 'Changeset: %s, %s' % (self.created_date, self.record)

    content = property(get_content, set_content)

class SoftDeleteRecord(models.Model):
    changeset = models.ForeignKey(ChangeSet, related_name='soft_delete_records')
    created_date = models.DateTimeField(default=datetime.utcnow)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    record = generic.GenericForeignKey('content_type', 'object_id')

    class Meta:
        unique_together= (('changeset', 'content_type', 'object_id'),)

    def get_content(self):
        self.record = self.content_type.model_class().objects.get(pk=self.object_id)
        return self.record

    def set_content(self, obj):
        self.record = obj

    def undelete(self, using=settings.DATABASES['default']):
        self.content._do_undelete(using)

    def __unicode__(self):
        return u'SoftDeleteRecord: (%s), (%s/%s), %s' % (self.content,
                                                  self.content_type,
                                                  self.object_id,
                                                  self.changeset.created_date)

    content = property(get_content, set_content)

<|endoftext|>