Changeset - f4d128af1a01
[Not reviewed]
default
0 6 0
Mads Kiilerich - 9 years ago 2016-09-12 17:41:19
madski@unity3d.com
compat: drop unnecessary wrappers for old Python versions

Made unnecessary by other cleanup or upgrade to Python 2.6+.
6 files changed with 32 insertions and 530 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/api/__init__.py
Show inline comments
 
@@ -9,57 +9,58 @@
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.api
 
~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
JSON RPC controller
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Aug 20, 2011
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import inspect
 
import logging
 
import types
 
import traceback
 
import time
 
import itertools
 

	
 
from paste.response import replace_header
 
from pylons.controllers import WSGIController
 

	
 
from webob.exc import HTTPError
 

	
 
from kallithea.model.db import User
 
from kallithea.model import meta
 
from kallithea.lib.compat import izip_longest, json
 
from kallithea.lib.compat import json
 
from kallithea.lib.auth import AuthUser
 
from kallithea.lib.base import _get_ip_addr as _get_ip, _get_access_path
 
from kallithea.lib.utils2 import safe_unicode, safe_str
 

	
 
log = logging.getLogger('JSONRPC')
 

	
 

	
 
class JSONRPCError(BaseException):
 

	
 
    def __init__(self, message):
 
        self.message = message
 
        super(JSONRPCError, self).__init__()
 

	
 
    def __str__(self):
 
        return safe_str(self.message)
 

	
 

	
 
def jsonrpc_error(message, retid=None, code=None):
 
    """
 
    Generate a Response object with a JSON-RPC error body
 

	
 
    :param code:
 
    :param retid:
 
    :param message:
 
@@ -162,50 +163,50 @@ class JSONRPCController(WSGIController):
 
                return jsonrpc_error(retid=self._req_id,
 
                        message='request from IP:%s not allowed' % (ip_addr,))
 
            else:
 
                log.info('Access for IP:%s allowed', ip_addr)
 

	
 
        except Exception as e:
 
            return jsonrpc_error(retid=self._req_id,
 
                                 message='Invalid API key')
 

	
 
        self._error = None
 
        try:
 
            self._func = self._find_method()
 
        except AttributeError as e:
 
            return jsonrpc_error(retid=self._req_id,
 
                                 message=str(e))
 

	
 
        # now that we have a method, add self._req_params to
 
        # self.kargs and dispatch control to WGIController
 
        argspec = inspect.getargspec(self._func)
 
        arglist = argspec[0][1:]
 
        defaults = map(type, argspec[3] or [])
 
        default_empty = types.NotImplementedType
 

	
 
        # kw arguments required by this method
 
        func_kwargs = dict(izip_longest(reversed(arglist), reversed(defaults),
 
                                        fillvalue=default_empty))
 
        func_kwargs = dict(itertools.izip_longest(reversed(arglist), reversed(defaults),
 
                                                  fillvalue=default_empty))
 

	
 
        # this is little trick to inject logged in user for
 
        # perms decorators to work they expect the controller class to have
 
        # authuser attribute set
 
        self.authuser = auth_u
 

	
 
        # This attribute will need to be first param of a method that uses
 
        # api_key, which is translated to instance of user at that name
 
        USER_SESSION_ATTR = 'apiuser'
 

	
 
        if USER_SESSION_ATTR not in arglist:
 
            return jsonrpc_error(
 
                retid=self._req_id,
 
                message='This method [%s] does not support '
 
                         'authentication (missing %s param)' % (
 
                                    self._func.__name__, USER_SESSION_ATTR)
 
            )
 

	
 
        # get our arglist and check if we provided them as args
 
        for arg, default in func_kwargs.iteritems():
 
            if arg == USER_SESSION_ATTR:
 
                # USER_SESSION_ATTR is something translated from API key and
 
                # this is checked before so we don't need validate it
 
                continue
kallithea/controllers/summary.py
Show inline comments
 
@@ -7,78 +7,78 @@
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.controllers.summary
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Summary controller for Kallithea
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 18, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import traceback
 
import calendar
 
import logging
 
import itertools
 
from time import mktime
 
from datetime import timedelta, date
 

	
 
from pylons import tmpl_context as c, request
 
from pylons.i18n.translation import _
 
from webob.exc import HTTPBadRequest
 

	
 
from beaker.cache import cache_region, region_invalidate
 

	
 
from kallithea.lib.compat import product
 
from kallithea.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
 
    NodeDoesNotExistError
 
from kallithea.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
 
from kallithea.model.db import Statistics, CacheInvalidation, User
 
from kallithea.lib.utils import jsonify
 
from kallithea.lib.utils2 import safe_str
 
from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
 
    NotAnonymous
 
from kallithea.lib.base import BaseRepoController, render
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.lib.markup_renderer import MarkupRenderer
 
from kallithea.lib.celerylib.tasks import get_commits_stats
 
from kallithea.lib.compat import json
 
from kallithea.lib.vcs.nodes import FileNode
 
from kallithea.controllers.changelog import _load_changelog_summary
 

	
 
log = logging.getLogger(__name__)
 

	
 
README_FILES = [''.join([x[0][0], x[1][0]]) for x in
 
                    sorted(list(product(ALL_READMES, ALL_EXTS)),
 
                    sorted(list(itertools.product(ALL_READMES, ALL_EXTS)),
 
                           key=lambda y:y[0][1] + y[1][1])]
 

	
 

	
 
class SummaryController(BaseRepoController):
 

	
 
    def __before__(self):
 
        super(SummaryController, self).__before__()
 

	
 
    def __get_readme_data(self, db_repo):
 
        repo_name = db_repo.repo_name
 
        log.debug('Looking for README file')
 

	
 
        @cache_region('long_term', '_get_readme_from_cache')
 
        def _get_readme_from_cache(key, kind):
 
            readme_data = None
 
            readme_file = None
 
            try:
 
                # gets the landing revision! or tip if fails
 
                cs = db_repo.get_landing_changeset()
 
                if isinstance(cs, EmptyChangeset):
 
                    raise EmptyRepositoryError()
 
                renderer = MarkupRenderer()
 
                for f in README_FILES:
 
                    try:
kallithea/lib/auth_modules/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
Authentication modules
 
"""
 

	
 
import logging
 
import traceback
 
import importlib
 

	
 
from kallithea.lib.compat import importlib
 
from kallithea.lib.utils2 import str2bool
 
from kallithea.lib.compat import formatted_json, hybrid_property
 
from kallithea.lib.auth import PasswordGenerator
 
from kallithea.model.user import UserModel
 
from kallithea.model.db import Setting, User
 
from kallithea.model.meta import Session
 
from kallithea.model.user_group import UserGroupModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LazyFormencode(object):
 
    def __init__(self, formencode_obj, *args, **kwargs):
 
        self.formencode_obj = formencode_obj
 
        self.args = args
 
        self.kwargs = kwargs
 

	
 
    def __call__(self, *args, **kwargs):
 
        from inspect import isfunction
 
        formencode_obj = self.formencode_obj
 
        if isfunction(formencode_obj):
 
            #case we wrap validators into functions
 
            formencode_obj = self.formencode_obj(*args, **kwargs)
 
        return formencode_obj(*self.args, **self.kwargs)
kallithea/lib/compat.py
Show inline comments
 
@@ -6,92 +6,72 @@
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.lib.compat
 
~~~~~~~~~~~~~~~~~~~~
 

	
 
Python backward compatibility functions and common libs
 

	
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Oct 7, 2011
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 

	
 
import sys
 
import os
 
import functools
 
import importlib
 
from kallithea import __py_version__, is_windows
 

	
 
#==============================================================================
 
# json
 
#==============================================================================
 
from kallithea.lib.ext_json import json
 

	
 
# alias for formatted json
 
formatted_json = functools.partial(json.dumps, indent=4, sort_keys=True)
 

	
 
if __py_version__ >= (2, 7):
 

	
 
#==============================================================================
 
# unittest
 
#==============================================================================
 
if sys.version_info >= (2, 7):
 
    import unittest
 
else:
 
    import unittest2 as unittest
 

	
 
#==============================================================================
 
# izip_longest
 
#==============================================================================
 
try:
 
    from itertools import izip_longest
 
except ImportError:
 
    import itertools
 

	
 
    def izip_longest(*args, **kwds):
 
        fillvalue = kwds.get("fillvalue")
 

	
 
        def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
 
            yield counter()  # yields the fillvalue, or raises IndexError
 

	
 
        fillers = itertools.repeat(fillvalue)
 
        iters = [itertools.chain(it, sentinel(), fillers)
 
                    for it in args]
 
        try:
 
            for tup in itertools.izip(*iters):
 
                yield tup
 
        except IndexError:
 
            pass
 

	
 

	
 
#==============================================================================
 
# OrderedDict
 
# OrderedDict - Python 2.7 could perhaps use collections.OrderedDict
 
#==============================================================================
 

	
 
# Python Software Foundation License
 

	
 
# XXX: it feels like using the class with "is" and "is not" instead of "==" and
 
# "!=" should be faster.
 
class _Nil(object):
 

	
 
    def __repr__(self):
 
        return "nil"
 

	
 
    def __eq__(self, other):
 
        if (isinstance(other, _Nil)):
 
            return True
 
        else:
 
            return NotImplemented
 

	
 
    def __ne__(self, other):
 
        if (isinstance(other, _Nil)):
 
            return False
 
        else:
 
            return NotImplemented
 

	
 
_nil = _Nil()
 
@@ -356,215 +336,41 @@ class _odict(object):
 
        Useful for debugging.
 
        """
 
        dict_impl = self._dict_impl()
 
        form = "odict low level repr lh,lt,data: %r, %r, %s"
 
        return form % (dict_impl.__getattribute__(self, 'lh'),
 
                       dict_impl.__getattribute__(self, 'lt'),
 
                       dict_impl.__repr__(self))
 

	
 

	
 
class OrderedDict(_odict, dict):
 

	
 
    def _dict_impl(self):
 
        return dict
 

	
 

	
 
#==============================================================================
 
# OrderedSet
 
#==============================================================================
 
from sqlalchemy.util import OrderedSet
 

	
 

	
 
#==============================================================================
 
# Hybrid property/method
 
#==============================================================================
 
from sqlalchemy.ext.hybrid import hybrid_method, hybrid_property
 
from sqlalchemy.ext.hybrid import hybrid_property
 

	
 

	
 
#==============================================================================
 
# kill FUNCTIONS
 
# kill
 
#==============================================================================
 
if is_windows:
 
if os.name == 'nt': # Windows
 
    import ctypes
 

	
 
    def kill(pid, sig):
 
        """kill function for Win32"""
 
        kernel32 = ctypes.windll.kernel32
 
        handle = kernel32.OpenProcess(1, 0, pid)
 
        return (0 != kernel32.TerminateProcess(handle, 0))
 

	
 
else:
 
    kill = os.kill
 

	
 

	
 
#==============================================================================
 
# itertools.product
 
#==============================================================================
 

	
 
try:
 
    from itertools import product
 
except ImportError:
 
    def product(*args, **kwds):
 
        # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
 
        # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
 
        pools = map(tuple, args) * kwds.get('repeat', 1)
 
        result = [[]]
 
        for pool in pools:
 
            result = [x + [y] for x in result for y in pool]
 
        for prod in result:
 
            yield tuple(prod)
 

	
 

	
 
#==============================================================================
 
# BytesIO
 
#==============================================================================
 

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

	
 

	
 
#==============================================================================
 
# bytes
 
#==============================================================================
 
if __py_version__ >= (2, 6):
 
    _bytes = bytes
 
else:
 
    # in py2.6 bytes is a synonym for str
 
    _bytes = str
 

	
 
if __py_version__ >= (2, 6):
 
    _bytearray = bytearray
 
else:
 
    import array
 
    # no idea if this is correct but all integration tests are passing
 
    # i think we never use bytearray anyway
 
    _bytearray = array
 

	
 

	
 
#==============================================================================
 
# deque
 
#==============================================================================
 

	
 
if __py_version__ >= (2, 6):
 
    from collections import deque
 
else:
 
    #need to implement our own deque with maxlen
 
    class deque(object):
 

	
 
        def __init__(self, iterable=(), maxlen= -1):
 
            if not hasattr(self, 'data'):
 
                self.left = self.right = 0
 
                self.data = {}
 
            self.maxlen = maxlen or -1
 
            self.extend(iterable)
 

	
 
        def append(self, x):
 
            self.data[self.right] = x
 
            self.right += 1
 
            if self.maxlen != -1 and len(self) > self.maxlen:
 
                self.popleft()
 

	
 
        def appendleft(self, x):
 
            self.left -= 1
 
            self.data[self.left] = x
 
            if self.maxlen != -1 and len(self) > self.maxlen:
 
                self.pop()
 

	
 
        def pop(self):
 
            if self.left == self.right:
 
                raise IndexError('cannot pop from empty deque')
 
            self.right -= 1
 
            elem = self.data[self.right]
 
            del self.data[self.right]
 
            return elem
 

	
 
        def popleft(self):
 
            if self.left == self.right:
 
                raise IndexError('cannot pop from empty deque')
 
            elem = self.data[self.left]
 
            del self.data[self.left]
 
            self.left += 1
 
            return elem
 

	
 
        def clear(self):
 
            self.data.clear()
 
            self.left = self.right = 0
 

	
 
        def extend(self, iterable):
 
            for elem in iterable:
 
                self.append(elem)
 

	
 
        def extendleft(self, iterable):
 
            for elem in iterable:
 
                self.appendleft(elem)
 

	
 
        def rotate(self, n=1):
 
            if self:
 
                n %= len(self)
 
                for i in xrange(n):
 
                    self.appendleft(self.pop())
 

	
 
        def __getitem__(self, i):
 
            if i < 0:
 
                i += len(self)
 
            try:
 
                return self.data[i + self.left]
 
            except KeyError:
 
                raise IndexError
 

	
 
        def __setitem__(self, i, value):
 
            if i < 0:
 
                i += len(self)
 
            try:
 
                self.data[i + self.left] = value
 
            except KeyError:
 
                raise IndexError
 

	
 
        def __delitem__(self, i):
 
            size = len(self)
 
            if not (-size <= i < size):
 
                raise IndexError
 
            data = self.data
 
            if i < 0:
 
                i += size
 
            for j in xrange(self.left + i, self.right - 1):
 
                data[j] = data[j + 1]
 
            self.pop()
 

	
 
        def __len__(self):
 
            return self.right - self.left
 

	
 
        def __cmp__(self, other):
 
            if type(self) != type(other):
 
                return cmp(type(self), type(other))
 
            return cmp(list(self), list(other))
 

	
 
        def __repr__(self, _track=None):
 
            _track = _track or []
 
            if id(self) in _track:
 
                return '...'
 
            _track.append(id(self))
 
            r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
 
            _track.remove(id(self))
 
            return r
 

	
 
        def __getstate__(self):
 
            return (tuple(self),)
 

	
 
        def __setstate__(self, s):
 
            self.__init__(s[0])
 

	
 
        def __hash__(self):
 
            raise TypeError
 

	
 
        def __copy__(self):
 
            return self.__class__(self)
 

	
 
        def __deepcopy__(self, memo=None):
 
            from copy import deepcopy
 
            memo = memo or {}
 
            result = self.__class__()
 
            memo[id(self)] = result
 
            result.__init__(deepcopy(tuple(self), memo))
 
            return result
kallithea/lib/vcs/subprocessio.py
Show inline comments
 
@@ -3,117 +3,118 @@ Module provides a class allowing to wrap
 
input, output, error streams into a meaningful, non-blocking, concurrent
 
stream processor exposing the output data as an iterator fitting to be a
 
return value passed by a WSGI application to a WSGI server per PEP 3333.
 

	
 
Copyright (c) 2011  Daniel Dotsenko <dotsa[at]hotmail.com>
 

	
 
This file is part of git_http_backend.py Project.
 

	
 
git_http_backend.py Project is free software: you can redistribute it and/or
 
modify it under the terms of the GNU Lesser General Public License as
 
published by the Free Software Foundation, either version 2.1 of the License,
 
or (at your option) any later version.
 

	
 
git_http_backend.py Project is distributed in the hope that it will be useful,
 
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
GNU Lesser General Public License for more details.
 

	
 
You should have received a copy of the GNU Lesser General Public License
 
along with git_http_backend.py Project.
 
If not, see <http://www.gnu.org/licenses/>.
 
"""
 
import os
 
import subprocess
 
from kallithea.lib.vcs.utils.compat import deque, Event, Thread, _bytes, _bytearray
 
import collections
 
import threading
 

	
 

	
 
class StreamFeeder(Thread):
 
class StreamFeeder(threading.Thread):
 
    """
 
    Normal writing into pipe-like is blocking once the buffer is filled.
 
    This thread allows a thread to seep data from a file-like into a pipe
 
    without blocking the main thread.
 
    We close inpipe once the end of the source stream is reached.
 
    """
 

	
 
    def __init__(self, source):
 
        super(StreamFeeder, self).__init__()
 
        self.daemon = True
 
        filelike = False
 
        self.bytes = _bytes()
 
        if type(source) in (type(''), _bytes, _bytearray):  # string-like
 
            self.bytes = _bytes(source)
 
        self.bytes = bytes()
 
        if type(source) in (type(''), bytes, bytearray):  # string-like
 
            self.bytes = bytes(source)
 
        else:  # can be either file pointer or file-like
 
            if type(source) in (int, long):  # file pointer it is
 
                ## converting file descriptor (int) stdin into file-like
 
                source = os.fdopen(source, 'rb', 16384)
 
            # let's see if source is file-like by now
 
            filelike = hasattr(source, 'read')
 
        if not filelike and not self.bytes:
 
            raise TypeError("StreamFeeder's source object must be a readable "
 
                            "file-like, a file descriptor, or a string-like.")
 
        self.source = source
 
        self.readiface, self.writeiface = os.pipe()
 

	
 
    def run(self):
 
        t = self.writeiface
 
        if self.bytes:
 
            os.write(t, self.bytes)
 
        else:
 
            s = self.source
 
            b = s.read(4096)
 
            while b:
 
                os.write(t, b)
 
                b = s.read(4096)
 
        os.close(t)
 

	
 
    @property
 
    def output(self):
 
        return self.readiface
 

	
 

	
 
class InputStreamChunker(Thread):
 
class InputStreamChunker(threading.Thread):
 
    def __init__(self, source, target, buffer_size, chunk_size):
 

	
 
        super(InputStreamChunker, self).__init__()
 

	
 
        self.daemon = True  # die die die.
 

	
 
        self.source = source
 
        self.target = target
 
        self.chunk_count_max = int(buffer_size / chunk_size) + 1
 
        self.chunk_size = chunk_size
 

	
 
        self.data_added = Event()
 
        self.data_added = threading.Event()
 
        self.data_added.clear()
 

	
 
        self.keep_reading = Event()
 
        self.keep_reading = threading.Event()
 
        self.keep_reading.set()
 

	
 
        self.EOF = Event()
 
        self.EOF = threading.Event()
 
        self.EOF.clear()
 

	
 
        self.go = Event()
 
        self.go = threading.Event()
 
        self.go.set()
 

	
 
    def stop(self):
 
        self.go.clear()
 
        self.EOF.set()
 
        try:
 
            # this is not proper, but is done to force the reader thread let
 
            # go of the input because, if successful, .close() will send EOF
 
            # down the pipe.
 
            self.source.close()
 
        except:
 
            pass
 

	
 
    def run(self):
 
        s = self.source
 
        t = self.target
 
        cs = self.chunk_size
 
        ccm = self.chunk_count_max
 
        kr = self.keep_reading
 
        da = self.data_added
 
        go = self.go
 

	
 
        try:
 
            b = s.read(cs)
 
@@ -142,69 +143,69 @@ class InputStreamChunker(Thread):
 
        da.set()  # for cases when done but there was no input.
 

	
 

	
 
class BufferedGenerator(object):
 
    """
 
    Class behaves as a non-blocking, buffered pipe reader.
 
    Reads chunks of data (through a thread)
 
    from a blocking pipe, and attaches these to an array (Deque) of chunks.
 
    Reading is halted in the thread when max chunks is internally buffered.
 
    The .next() may operate in blocking or non-blocking fashion by yielding
 
    '' if no data is ready
 
    to be sent or by not returning until there is some data to send
 
    When we get EOF from underlying source pipe we raise the marker to raise
 
    StopIteration after the last chunk of data is yielded.
 
    """
 

	
 
    def __init__(self, source, buffer_size=65536, chunk_size=4096,
 
                 starting_values=None, bottomless=False):
 
        starting_values = starting_values or []
 
        if bottomless:
 
            maxlen = int(buffer_size / chunk_size)
 
        else:
 
            maxlen = None
 

	
 
        self.data = deque(starting_values, maxlen)
 
        self.data = collections.deque(starting_values, maxlen)
 
        self.worker = InputStreamChunker(source, self.data, buffer_size,
 
                                         chunk_size)
 
        if starting_values:
 
            self.worker.data_added.set()
 
        self.worker.start()
 

	
 
    ####################
 
    # Generator's methods
 
    ####################
 

	
 
    def __iter__(self):
 
        return self
 

	
 
    def next(self):
 
        while not len(self.data) and not self.worker.EOF.is_set():
 
            self.worker.data_added.clear()
 
            self.worker.data_added.wait(0.2)
 
        if len(self.data):
 
            self.worker.keep_reading.set()
 
            return _bytes(self.data.popleft())
 
            return bytes(self.data.popleft())
 
        elif self.worker.EOF.is_set():
 
            raise StopIteration
 

	
 
    def throw(self, type, value=None, traceback=None):
 
        if not self.worker.EOF.is_set():
 
            raise type(value)
 

	
 
    def start(self):
 
        self.worker.start()
 

	
 
    def stop(self):
 
        self.worker.stop()
 

	
 
    def close(self):
 
        try:
 
            self.worker.stop()
 
            self.throw(GeneratorExit)
 
        except (GeneratorExit, StopIteration):
 
            pass
 

	
 
    def __del__(self):
 
        self.close()
 

	
 
    ####################
 
@@ -212,49 +213,49 @@ class BufferedGenerator(object):
 
    ####################
 
    @property
 
    def input(self):
 
        return self.worker.w
 

	
 
    @property
 
    def data_added_event(self):
 
        return self.worker.data_added
 

	
 
    @property
 
    def data_added(self):
 
        return self.worker.data_added.is_set()
 

	
 
    @property
 
    def reading_paused(self):
 
        return not self.worker.keep_reading.is_set()
 

	
 
    @property
 
    def done_reading_event(self):
 
        """
 
        Done_reading does not mean that the iterator's buffer is empty.
 
        Iterator might have done reading from underlying source, but the read
 
        chunks might still be available for serving through .next() method.
 

	
 
        :returns: An Event class instance.
 
        :returns: An threading.Event class instance.
 
        """
 
        return self.worker.EOF
 

	
 
    @property
 
    def done_reading(self):
 
        """
 
        Done_reading does not mean that the iterator's buffer is empty.
 
        Iterator might have done reading from underlying source, but the read
 
        chunks might still be available for serving through .next() method.
 

	
 
        :returns: An Bool value.
 
        """
 
        return self.worker.EOF.is_set()
 

	
 
    @property
 
    def length(self):
 
        """
 
        returns int.
 

	
 
        This is the length of the queue of chunks, not the length of
 
        the combined contents in those chunks.
 

	
 
        __len__() cannot be meaningfully implemented because this
 
        reader is just flying through a bottomless pit content and
kallithea/lib/vcs/utils/compat.py
Show inline comments
 
"""
 
Various utilities to work with Python < 2.7.
 

	
 
Those utilities may be deleted once ``vcs`` stops support for older Python
 
versions.
 
"""
 

	
 
import sys
 
import array
 

	
 
if sys.version_info >= (2, 7):
 
    unittest = __import__('unittest')
 
else:
 
    unittest = __import__('unittest2')
 

	
 

	
 
if sys.version_info >= (2, 6):
 
    _bytes = bytes
 
else:
 
    # in py2.6 bytes is a synonym for str
 
    _bytes = str
 

	
 
if sys.version_info >= (2, 6):
 
    _bytearray = bytearray
 
else:
 
    # no idea if this is correct but all integration tests are passing
 
    # i think we never use bytearray anyway
 
    _bytearray = array
 

	
 
if sys.version_info >= (2, 6):
 
    from collections import deque
 
else:
 
    #need to implement our own deque with maxlen
 
    class deque(object):
 

	
 
        def __init__(self, iterable=(), maxlen= -1):
 
            if not hasattr(self, 'data'):
 
                self.left = self.right = 0
 
                self.data = {}
 
            self.maxlen = maxlen or -1
 
            self.extend(iterable)
 

	
 
        def append(self, x):
 
            self.data[self.right] = x
 
            self.right += 1
 
            if self.maxlen != -1 and len(self) > self.maxlen:
 
                self.popleft()
 

	
 
        def appendleft(self, x):
 
            self.left -= 1
 
            self.data[self.left] = x
 
            if self.maxlen != -1 and len(self) > self.maxlen:
 
                self.pop()
 

	
 
        def pop(self):
 
            if self.left == self.right:
 
                raise IndexError('cannot pop from empty deque')
 
            self.right -= 1
 
            elem = self.data[self.right]
 
            del self.data[self.right]
 
            return elem
 

	
 
        def popleft(self):
 
            if self.left == self.right:
 
                raise IndexError('cannot pop from empty deque')
 
            elem = self.data[self.left]
 
            del self.data[self.left]
 
            self.left += 1
 
            return elem
 

	
 
        def clear(self):
 
            self.data.clear()
 
            self.left = self.right = 0
 

	
 
        def extend(self, iterable):
 
            for elem in iterable:
 
                self.append(elem)
 

	
 
        def extendleft(self, iterable):
 
            for elem in iterable:
 
                self.appendleft(elem)
 

	
 
        def rotate(self, n=1):
 
            if self:
 
                n %= len(self)
 
                for i in xrange(n):
 
                    self.appendleft(self.pop())
 

	
 
        def __getitem__(self, i):
 
            if i < 0:
 
                i += len(self)
 
            try:
 
                return self.data[i + self.left]
 
            except KeyError:
 
                raise IndexError
 

	
 
        def __setitem__(self, i, value):
 
            if i < 0:
 
                i += len(self)
 
            try:
 
                self.data[i + self.left] = value
 
            except KeyError:
 
                raise IndexError
 

	
 
        def __delitem__(self, i):
 
            size = len(self)
 
            if not (-size <= i < size):
 
                raise IndexError
 
            data = self.data
 
            if i < 0:
 
                i += size
 
            for j in xrange(self.left + i, self.right - 1):
 
                data[j] = data[j + 1]
 
            self.pop()
 

	
 
        def __len__(self):
 
            return self.right - self.left
 

	
 
        def __cmp__(self, other):
 
            if type(self) != type(other):
 
                return cmp(type(self), type(other))
 
            return cmp(list(self), list(other))
 

	
 
        def __repr__(self, _track=None):
 
            _track = _track or []
 
            if id(self) in _track:
 
                return '...'
 
            _track.append(id(self))
 
            r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
 
            _track.remove(id(self))
 
            return r
 

	
 
        def __getstate__(self):
 
            return (tuple(self),)
 

	
 
        def __setstate__(self, s):
 
            self.__init__(s[0])
 

	
 
        def __hash__(self):
 
            raise TypeError
 

	
 
        def __copy__(self):
 
            return self.__class__(self)
 

	
 
        def __deepcopy__(self, memo=None):
 
            from copy import deepcopy
 
            memo = memo or {}
 
            result = self.__class__()
 
            memo[id(self)] = result
 
            result.__init__(deepcopy(tuple(self), memo))
 
            return result
 

	
 

	
 
#==============================================================================
 
# threading.Event
 
#==============================================================================
 

	
 
if sys.version_info >= (2, 6):
 
    from threading import Event, Thread
 
else:
 
    from threading import _Verbose, Lock, Thread, _time, \
 
        _allocate_lock, RLock, _sleep
 

	
 
    def Condition(*args, **kwargs):
 
        return _Condition(*args, **kwargs)
 

	
 
    class _Condition(_Verbose):
 

	
 
        def __init__(self, lock=None, verbose=None):
 
            _Verbose.__init__(self, verbose)
 
            if lock is None:
 
                lock = RLock()
 
            self.__lock = lock
 
            # Export the lock's acquire() and release() methods
 
            self.acquire = lock.acquire
 
            self.release = lock.release
 
            # If the lock defines _release_save() and/or _acquire_restore(),
 
            # these override the default implementations (which just call
 
            # release() and acquire() on the lock).  Ditto for _is_owned().
 
            try:
 
                self._release_save = lock._release_save
 
            except AttributeError:
 
                pass
 
            try:
 
                self._acquire_restore = lock._acquire_restore
 
            except AttributeError:
 
                pass
 
            try:
 
                self._is_owned = lock._is_owned
 
            except AttributeError:
 
                pass
 
            self.__waiters = []
 

	
 
        def __enter__(self):
 
            return self.__lock.__enter__()
 

	
 
        def __exit__(self, *args):
 
            return self.__lock.__exit__(*args)
 

	
 
        def __repr__(self):
 
            return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
 

	
 
        def _release_save(self):
 
            self.__lock.release()           # No state to save
 

	
 
        def _acquire_restore(self, x):
 
            self.__lock.acquire()           # Ignore saved state
 

	
 
        def _is_owned(self):
 
            # Return True if lock is owned by current_thread.
 
            # This method is called only if __lock doesn't have _is_owned().
 
            if self.__lock.acquire(0):
 
                self.__lock.release()
 
                return False
 
            else:
 
                return True
 

	
 
        def wait(self, timeout=None):
 
            if not self._is_owned():
 
                raise RuntimeError("cannot wait on un-acquired lock")
 
            waiter = _allocate_lock()
 
            waiter.acquire()
 
            self.__waiters.append(waiter)
 
            saved_state = self._release_save()
 
            try:    # restore state no matter what (e.g., KeyboardInterrupt)
 
                if timeout is None:
 
                    waiter.acquire()
 
                    if __debug__:
 
                        self._note("%s.wait(): got it", self)
 
                else:
 
                    # Balancing act:  We can't afford a pure busy loop, so we
 
                    # have to sleep; but if we sleep the whole timeout time,
 
                    # we'll be unresponsive.  The scheme here sleeps very
 
                    # little at first, longer as time goes on, but never longer
 
                    # than 20 times per second (or the timeout time remaining).
 
                    endtime = _time() + timeout
 
                    delay = 0.0005 # 500 us -> initial delay of 1 ms
 
                    while True:
 
                        gotit = waiter.acquire(0)
 
                        if gotit:
 
                            break
 
                        remaining = endtime - _time()
 
                        if remaining <= 0:
 
                            break
 
                        delay = min(delay * 2, remaining, .05)
 
                        _sleep(delay)
 
                    if not gotit:
 
                        if __debug__:
 
                            self._note("%s.wait(%s): timed out", self, timeout)
 
                        try:
 
                            self.__waiters.remove(waiter)
 
                        except ValueError:
 
                            pass
 
                    else:
 
                        if __debug__:
 
                            self._note("%s.wait(%s): got it", self, timeout)
 
            finally:
 
                self._acquire_restore(saved_state)
 

	
 
        def notify(self, n=1):
 
            if not self._is_owned():
 
                raise RuntimeError("cannot notify on un-acquired lock")
 
            __waiters = self.__waiters
 
            waiters = __waiters[:n]
 
            if not waiters:
 
                if __debug__:
 
                    self._note("%s.notify(): no waiters", self)
 
                return
 
            self._note("%s.notify(): notifying %d waiter%s", self, n,
 
                       n != 1 and "s" or "")
 
            for waiter in waiters:
 
                waiter.release()
 
                try:
 
                    __waiters.remove(waiter)
 
                except ValueError:
 
                    pass
 

	
 
        def notifyAll(self):
 
            self.notify(len(self.__waiters))
 

	
 
        notify_all = notifyAll
 

	
 
    def Event(*args, **kwargs):
 
        return _Event(*args, **kwargs)
 

	
 
    class _Event(_Verbose):
 

	
 
        # After Tim Peters' event class (without is_posted())
 

	
 
        def __init__(self, verbose=None):
 
            _Verbose.__init__(self, verbose)
 
            self.__cond = Condition(Lock())
 
            self.__flag = False
 

	
 
        def isSet(self):
 
            return self.__flag
 

	
 
        is_set = isSet
 

	
 
        def set(self):
 
            self.__cond.acquire()
 
            try:
 
                self.__flag = True
 
                self.__cond.notify_all()
 
            finally:
 
                self.__cond.release()
 

	
 
        def clear(self):
 
            self.__cond.acquire()
 
            try:
 
                self.__flag = False
 
            finally:
 
                self.__cond.release()
 

	
 
        def wait(self, timeout=None):
 
            self.__cond.acquire()
 
            try:
 
                if not self.__flag:
 
                    self.__cond.wait(timeout)
 
            finally:
 
                self.__cond.release()
0 comments (0 inline, 0 general)