Exemple #1
0
def test_bunchify():
    x = bunchify(dict(a=[dict(b=5), 9, (1, 2)], c=8))
    assert x.a[0].b == 5
    assert x.a[1] == 9
    assert isinstance(x.a[2], tuple)
    assert x.c == 8
    assert x.pop("c") == 8
Exemple #2
0
 def __init__(self,
              host,
              port,
              path="/api",
              name=None,
              timeout=None,
              ttl=120,
              init_methods=True,
              client_type=None,
              credentials=DEFAULT_CREDENTIALS,
              rpc_retries=2):
     self._rpc_retries = rpc_retries
     self._conn_params = bunchify(host=host,
                                  port=port,
                                  timeout=timeout or 120)
     self._path = path
     self._ttl = ttl
     self._conn = None
     self._headers = {}
     if credentials:
         b64 = codecs.encode(credentials.encode("latin1"),
                             "base64").replace(b"\n", b"")
         self._headers["authorization"] = b"Basic " + b64
     if client_type:
         self._headers['Client-Type'] = client_type
     self._spec = None
     self._exception_handlers = {}
     self._lock = RLock()
     self.long_operations = self._LongOperations(self)
     self.name = name
     if init_methods:
         self._populate_methods()
Exemple #3
0
class IndentableTextBuffer():
    NICE_BOX = bunchify(
        LINE="─",
        INDENT_SEGMENT="│   ",
        OPEN="┬",
        INDENT_OPEN="├───",
        INDENT_CLOSE="╰",
        SEGMENT_END="╼ ",
        SEGMENT_START=" ╾",
        SECTION_OPEN="╮",
        SECTION_SEGMENT="│",
        SECTION_CLOSE="╯",
    )
    TEXTUAL_BOX = bunchify(
        LINE="-",
        INDENT_SEGMENT="|   ",
        INDENT_OPEN="+---",
        OPEN=".",
        INDENT_CLOSE="`",
        SEGMENT_END="- ",
        SEGMENT_START=" -",
        SECTION_OPEN=".",
        SECTION_SEGMENT="|",
        SECTION_CLOSE="*",
    )

    def __init__(self, fmt="", *args, **kwargs):
        self.current = self.root = Node(fmt, args, kwargs, [])

    def __repr__(self):
        return self.render(width=80)

    def __len__(self):
        def count(root):
            for child in root.children:
                if isinstance(child, str):
                    yield 1
                else:
                    yield from count(child)

        return sum(count(self.root))

    def write(self, line, *args, **kwargs):
        if args or kwargs:
            line = line.format(*args, **kwargs)
        self.current.children.append(line)

    def extend(self, other):
        self.current.children.extend(other.root.children)

    @contextmanager
    def indent(self, fmt, *args, **kwargs):
        parent = self.current
        self.current = Node(fmt, args, kwargs, [])
        parent.children.append(self.current)
        yield
        self.current = parent

    def render(self,
               width=None,
               textual=None,
               prune=False,
               file=None,
               overflow='ignore',
               edges=True):
        if width is None:
            from .logging import TERM_WIDTH as width
        if textual is None:
            from .logging import GRAPHICAL
            textual = not GRAPHICAL

        buff = file if file else StringIO()
        G = self.TEXTUAL_BOX if textual else self.NICE_BOX
        from textwrap import wrap

        def has_descendents(elem):
            if isinstance(elem, str):
                return True
            return any(map(has_descendents, elem.children))

        def write_tree(elem, depth=0):
            if isinstance(elem, str):
                prefix = G.INDENT_SEGMENT * (depth - 1)
                prefix += G.INDENT_SEGMENT
                for par in elem.splitlines():
                    if overflow == "wrap":
                        lines = wrap(par, width - len(prefix) - 1)
                    elif overflow == "trim":
                        lines = [compact(par, width - len(prefix) - 1)]
                    else:
                        lines = [par]
                    for line in lines:
                        line = prefix + line
                        if len(line) < width:
                            if edges:
                                line = line.ljust(width -
                                                  1) + G.SECTION_SEGMENT
                        buff.write(line + "\n")
            elif not prune or has_descendents(elem):
                if depth:
                    prefix = G.INDENT_SEGMENT * (depth - 1) + G.INDENT_OPEN
                else:
                    prefix = ""
                txt = (G.SEGMENT_END +
                       elem.fmt.format(*elem.args, **elem.kwargs) +
                       G.SEGMENT_START) if elem.fmt else ""
                header = prefix + G.OPEN + txt
                buff.write(
                    header.ljust(width - 1, G.LINE) + G.SECTION_OPEN + "\n")
                for child in elem.children:
                    write_tree(child, depth + 1)
                footer = (G.INDENT_SEGMENT * depth + G.INDENT_CLOSE + G.LINE *
                          (width - len(G.INDENT_SEGMENT) *
                           (depth + 1) - len(txt) + 2) + txt)
                buff.write(footer + G.SECTION_CLOSE + "\n")

        write_tree(self.root)
        if not file:
            return buff.getvalue()
Exemple #4
0
        def make_request():
            if not quiet:
                _logger.debug("request  >> #%04d: %s/%s", message_id, self.url,
                              method)
            try:
                try:
                    conn = self.get_connection(
                        timeout_override=timeout_override)
                except:
                    typ, exc, tb = sys.exc_info()
                    raise_if_async_exception(exc)
                    raise_with_traceback(
                        ConnectionError(url=self.url,
                                        message_id=message_id,
                                        exc=exc), tb)

                json_req = _make_request(message_id, method, params)

                try:
                    conn.request('POST', self._path, json_req, self._headers)
                except socket.timeout:
                    typ, exc, tb = sys.exc_info()
                    raise_if_async_exception(exc)
                    raise_with_traceback(ServerTimeout(**exc_params), tb)
                except:
                    typ, exc, tb = sys.exc_info()
                    raise_if_async_exception(exc)
                    raise_with_traceback(RequestError(exc=exc, **exc_params),
                                         tb)

                try:
                    response = conn.getresponse()
                except socket.timeout:
                    typ, exc, tb = sys.exc_info()
                    raise_if_async_exception(exc)
                    raise_with_traceback(ServerTimeout(**exc_params), tb)
                except:
                    typ, exc, tb = sys.exc_info()
                    raise_if_async_exception(exc)
                    # To address leader temporarily being down ("BadStatusLine")
                    time.sleep(1)
                    raise_with_traceback(ReplyError(exc=exc, **exc_params), tb)
            except:
                self._conn = None  # create a new connection next time
                raise

            if response.status == 408 or response.status == 400:
                # AWS issues
                _logger.debug("Got error code %s, on request #%04d, retrying",
                              response.status, message_id)
                self._conn = None  # create a new connection next time
                time.sleep(0.5)
                self.retry_last_rpc(
                    'Got error code %s - %s' %
                    (response.status, httpclient.responses[response.status]))

            if response.status == 301:
                # redirect
                new_url = response.getheader("location")
                parsed = urlparse(new_url)
                _logger.debug("redirecting http://%s:%s/%s to %s",
                              self._conn_params.host, self._conn_params.port,
                              self._path, new_url)
                #   print("redirect to", new_url)

                orig = Bunch(**self._conn_params)
                if ":" in parsed.netloc:
                    host, port = parsed.netloc.split(":")
                    self._conn_params.host = host
                    self._conn_params.port = int(port)
                else:
                    self._conn_params.host = parsed.netloc

                self.expire_connection()
                conn = self.get_connection(timeout_override=timeout_override)
                conn.request('POST', self._path,
                             _make_request(message_id, method, params),
                             self._headers)
                response = conn.getresponse()
                self.expire_connection()
                self._conn_params = orig

            if response.status == 503:
                # service not available, retry again later
                time.sleep(0.5)
                return self.retry_last_rpc("Service unavailable, retry later")

            try:
                response_text = response.read().decode('utf-8')
            except socket.timeout:
                self._conn = None  # create a new connection next time
                typ, exc, tb = sys.exc_info()
                raise_with_traceback(ServerTimeout(**exc_params), tb)
            except IncompleteRead:
                self._conn = None  # create a new connection next time
                typ, exc, tb = sys.exc_info()
                raise_with_traceback(ReadError(exc=exc, **exc_params), tb)

            if response.status != 200:
                # some other error
                raise HTTPException(status=response.status,
                                    reason=response.reason,
                                    text=response_text,
                                    **exc_params)

            try:
                response_object = json.loads(response_text)
            except ValueError:
                raise ResponseError("Could not parse json respone",
                                    response_text=response_text,
                                    **exc_params)

            if not quiet:
                _logger.debug("response << #%04d: %s -> %s",
                              response_object.get('id', -1), method,
                              DataSize(response.getheader("content-length")))

            if message_id != response_object.get('id'):
                raise ResponseIdMismatch(responded=response_object.get('id'),
                                         response_text=response_text,
                                         **exc_params)

            if 'error' not in response_object:
                result = response_object['result']
                return bunchify(result) if should_bunchify else result

            error_code = response_object['error'].pop('code', None)
            error_data = response_object['error'].pop(
                'data', "(no further information)")
            remote_message = response_object['error'].pop(
                'message', "(no message)")
            server_node_id = response.getheader('server-node-id', None)

            if error_code == -32601:  # Method not Found
                raise RemoteMethodNotFound(method=method)
                # raise AttributeError('%s' % remote_message)

            if error_code == -32602:  # Invalid Params
                raise TypeError('%s(%s)' % (remote_message, error_data))

            if isinstance(error_data, dict):
                if server_node_id:
                    error_data['served_by_node'] = server_node_id

                if 'exceptionClass' in error_data:
                    exception_class = error_data.pop('exceptionClass')
                    if isinstance(exception_class, list):
                        exceptions._register_ancestry(exception_class)
                        exception_class = exception_class[0]
                    exception_name = exception_class.rpartition(".")[-1]
                    handler = self._exception_handlers.get(
                        exception_name) or getattr(exceptions, exception_name)
                    if hasattr(handler, '__bases__') and error_data.get(
                            "retry",
                            False) and RetrySignal not in handler.__bases__:
                        handler.__bases__ += (RetrySignal, )
                    exception_text = error_data.pop('exceptionText',
                                                    remote_message)
                    error_data['jrpc'] = exc_params
                    raise handler(exception_text, **error_data)
                else:
                    exc_params.update(error_data)
                    raise RemoteException(remote_message, **exc_params)
            else:
                if error_data:
                    remote_message += "\n%s" % (error_data, )
                exc_params.update(response_object['error'])

                if server_node_id:
                    exc_params['served_by_node'] = server_node_id

                raise RemoteException(remote_message, **exc_params)