Exemplo n.º 1
0
    def _explain_how_realized(self, expectation, reasons):
        message = fmt("Realized {0!r}", expectation)

        # For the breakdown, we want to skip any expectations that were exact occurrences,
        # since there's no point explaining that occurrence was realized by itself.
        skip = [exp for exp in reasons.keys() if isinstance(exp, Occurrence)]
        for exp in skip:
            reasons.pop(exp, None)

        if reasons == {expectation: some.object}:
            # If there's only one expectation left to explain, and it's the top-level
            # one, then we have already printed it, so just add the explanation.
            reason = reasons[expectation]
            if "\n" in message:
                message += fmt(" == {0!r}", reason)
            else:
                message += fmt("\n      == {0!r}", reason)
        elif reasons:
            # Otherwise, break it down expectation by expectation.
            message += ":"
            for exp, reason in reasons.items():
                message += fmt("\n\n   where {0!r}\n      == {1!r}", exp,
                               reason)
        else:
            message += "."

        log.info("{0}", message)
Exemplo n.º 2
0
def srcnameof(obj):
    """Returns the most descriptive name of a Python module, class, or function,
    including source information (filename and linenumber), if available.

    Best-effort, but guaranteed to not fail - always returns something.
    """

    name = nameof(obj, quote=True)

    # Get the source information if possible.
    try:
        src_file = filename(inspect.getsourcefile(obj), "replace")
    except Exception:
        pass
    else:
        name += fmt(" (file {0!r}", src_file)
        try:
            _, src_lineno = inspect.getsourcelines(obj)
        except Exception:
            pass
        else:
            name += fmt(", line {0}", src_lineno)
        name += ")"

    return name
Exemplo n.º 3
0
 def parse(s):
     n = parser(s)
     if start is not None and n < start:
         raise ValueError(fmt("must be >= {0}", start))
     if stop is not None and n >= stop:
         raise ValueError(fmt("must be < {0}", stop))
     return n
Exemplo n.º 4
0
    def describe_circumstances(self):
        id = collections.OrderedDict(self._id)

        # Keep it all on one line if it's short enough, but indent longer ones.
        s = fmt("{0!j:indent=None}", id)
        if len(s) > SINGLE_LINE_REPR_LIMIT:
            s = fmt("{0!j}", id)
        return s
Exemplo n.º 5
0
def attach_by_socket(session,
                     target,
                     method,
                     listener="server",
                     cwd=None,
                     wait=True,
                     log_dir=None):
    log.info("Attaching {0} to {1} by socket using {2}.", session, target,
             method.upper())

    assert method in ("api", "cli")
    assert listener in ("server")  # TODO: ("adapter", "server")

    config = _attach_common_config(session, target, cwd)

    host = config["host"] = attach_by_socket.host
    port = config["port"] = attach_by_socket.port

    if method == "cli":
        args = [os.path.dirname(ptvsd.__file__)]
        if wait:
            args += ["--wait"]
        args += ["--host", compat.filename_str(host), "--port", str(port)]
        if not config["subProcess"]:
            args += ["--no-subprocesses"]
        if log_dir is not None:
            args += ["--log-dir", log_dir]
        debug_me = None
    elif method == "api":
        args = []
        debug_me = """
import ptvsd
ptvsd.enable_attach(({host!r}, {port!r}), {args})
if {wait!r}:
    ptvsd.wait_for_attach()
"""
        attach_args = "" if log_dir is None else fmt("log_dir={0!r}", log_dir)
        debug_me = fmt(debug_me,
                       host=host,
                       port=port,
                       wait=wait,
                       args=attach_args)
    else:
        raise ValueError
    args += target.cli(session.spawn_debuggee.env)

    session.spawn_debuggee(args, cwd=cwd, debug_me=debug_me)
    if wait:
        session.wait_for_enable_attach()

    session.connect_to_adapter((host, port))
    return session.request_attach()
Exemplo n.º 6
0
def parse(args, options=options):
    seen = set()
    it = (compat.filename(arg) for arg in args)

    while True:
        try:
            arg = next(it)
        except StopIteration:
            raise ValueError("missing target: " + TARGET)

        switch = arg if arg.startswith("-") else ""
        for i, (sw, placeholder, action, _) in enumerate(switches):
            if not isinstance(sw, tuple):
                sw = (sw, )
            if switch in sw:
                break
        else:
            raise ValueError("unrecognized switch " + switch)

        if i in seen:
            raise ValueError("duplicate switch " + switch)
        else:
            seen.add(i)

        try:
            action(arg, it)
        except StopIteration:
            assert placeholder is not None
            raise ValueError(fmt("{0}: missing {1}", switch, placeholder))
        except Exception as exc:
            raise ValueError(
                fmt("invalid {0} {1}: {2}", switch, placeholder, exc))

        if options.target is not None:
            break

    for i, (sw, placeholder, _, required) in enumerate(switches):
        if not required or i in seen:
            continue
        if isinstance(sw, tuple):
            sw = sw[0]
        message = fmt("missing required {0}", sw)
        if placeholder is not None:
            message += " " + placeholder
        raise ValueError(message)

    if options.target_kind == "pid" and options.wait:
        raise ValueError("--pid does not support --wait")

    return it
Exemplo n.º 7
0
def inject(pid, ptvsd_args):
    host, port = Connection.listener.getsockname()

    cmdline = [
        sys.executable,
        compat.filename(os.path.dirname(ptvsd.__file__)),
        "--client",
        "--host",
        host,
        "--port",
        str(port),
    ]
    if adapter.access_token is not None:
        cmdline += ["--client-access-token", adapter.access_token]
    cmdline += ptvsd_args
    cmdline += ["--pid", str(pid)]

    log.info("Spawning attach-to-PID debugger injector: {0!r}", cmdline)
    try:
        injector = subprocess.Popen(
            cmdline,
            bufsize=0,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
        )
    except Exception as exc:
        log.exception("Failed to inject debug server into process with PID={0}", pid)
        raise messaging.MessageHandlingError(
            fmt(
                "Failed to inject debug server into process with PID={0}: {1}", pid, exc
            )
        )

    # We need to capture the output of the injector - otherwise it can get blocked
    # on a write() syscall when it tries to print something.

    def capture_output():
        while True:
            line = injector.stdout.readline()
            if not line:
                break
            log.info("Injector[PID={0}] output:\n{1}", pid, line.rstrip())
        log.info("Injector[PID={0}] exited.", pid)

    thread = threading.Thread(
        target=capture_output, name=fmt("Injector[PID={0}] output", pid)
    )
    thread.daemon = True
    thread.start()
Exemplo n.º 8
0
def Response(request, body=some.object):
    assert isinstance(request, Expectation) or isinstance(
        request, RequestOccurrence)

    exp = PatternExpectation("response", request, body)
    exp.timeline = request.timeline
    exp.has_lower_bound = request.has_lower_bound

    # Try to be as specific as possible.
    if isinstance(request, Expectation):
        if request.circumstances[0] != "request":
            exp.describe = lambda: fmt("response to {0!r}", request)
            return
        else:
            items = (("command", request.circumstances[1]), )
    else:
        items = (("command", request.command), )

    if isinstance(request, Occurrence):
        items += (("request_seq", request.seq), )

    if body is some.object:
        items += (("\002...", "...\003"), )
    elif body is some.error or body == some.error:
        items += (("success", False), )
        if body == some.error:
            items += (("message", compat.force_str(body)), )
    else:
        items += (("body", body), )

    exp.describe = lambda: _describe_message("response", *items)
    return exp
Exemplo n.º 9
0
def test_wrapper(request, long_tmpdir):
    def write_log(filename, data):
        filename = os.path.join(log.log_dir, filename)
        if not isinstance(data, bytes):
            data = data.encode("utf-8")
        with open(filename, "wb") as f:
            f.write(data)

    session.Session.reset_counter()

    session.Session.tmpdir = long_tmpdir
    original_log_dir = log.log_dir

    try:
        if log.log_dir is None:
            log.log_dir = (long_tmpdir / "ptvsd_logs").strpath
        else:
            log_subdir = request.node.nodeid
            log_subdir = log_subdir.replace("::", "/")
            for ch in r":?*|<>":
                log_subdir = log_subdir.replace(ch, fmt("&#{0};", ord(ch)))
            log.log_dir += "/" + log_subdir

        try:
            py.path.local(log.log_dir).remove()
        except Exception:
            pass

        print("\n")  # make sure on-screen logs start on a new line
        with log.to_file(prefix="tests"):
            timestamp.reset()
            log.info("{0} started.", request.node.nodeid)
            try:
                yield
            finally:
                failed = False
                for report_attr in ("setup_report", "call_report", "teardown_report"):
                    try:
                        report = getattr(request.node, report_attr)
                    except AttributeError:
                        continue

                    failed |= report.failed
                    log.write_format(
                        "error" if report.failed else "info",
                        "pytest {0} phase for {1} {2}.",
                        report.when,
                        request.node.nodeid,
                        report.outcome,
                    )

                    write_log(report_attr + ".log", report.longreprtext)
                    write_log(report_attr + ".stdout.log", report.capstdout)
                    write_log(report_attr + ".stderr.log", report.capstderr)

                if failed:
                    write_log("FAILED.log", "")
                    logs.dump()
    finally:
        log.log_dir = original_log_dir
Exemplo n.º 10
0
 def __repr__(self):
     return fmt(
         "{2}{0}.{1}",
         self.index,
         self.describe_circumstances(),
         "" if self.observed else "*",
     )
Exemplo n.º 11
0
    def listen(self):
        self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._server_socket.settimeout(self.TIMEOUT)
        self._server_socket.bind(("127.0.0.1", 0))
        _, self.port = self._server_socket.getsockname()
        self._server_socket.listen(0)

        def accept_worker():
            log.info(
                "Listening for incoming connection from {0} on port {1}...",
                self,
                self.port,
            )

            try:
                self._socket, _ = self._server_socket.accept()
            except socket.timeout:
                raise log.exception("Timed out waiting for {0} to connect",
                                    self)

            self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            log.info("Incoming connection from {0} accepted.", self)
            self._setup_stream()

        accept_thread = threading.Thread(target=accept_worker,
                                         name=fmt("{0} listener", self))
        accept_thread.daemon = True
        accept_thread.start()
Exemplo n.º 12
0
    def __init__(self, component, message):
        """Parses an "initialize" request or response and extracts the feature flags.

        For every "X" in self.PROPERTIES, sets self["X"] to the corresponding value
        from message.payload if it's present there, or to the default value otherwise.
        """

        assert message.is_request("initialize") or message.is_response(
            "initialize")

        self.component = component

        payload = message.payload
        for name, validate in self.PROPERTIES.items():
            value = payload.get(name, ())
            if not callable(validate):
                validate = json.default(validate)

            try:
                value = validate(value)
            except Exception as exc:
                raise message.isnt_valid("{0!j} {1}", name, exc)

            assert value != (), fmt(
                "{0!j} must provide a default value for missing properties.",
                validate)
            self[name] = value

        log.debug("{0}", self)
Exemplo n.º 13
0
    def report_paths(get_paths, label=None):
        prefix = fmt("    {0}: ", label or get_paths)

        expr = None
        if not callable(get_paths):
            expr = get_paths
            get_paths = lambda: util.evaluate(expr)
        try:
            paths = get_paths()
        except AttributeError:
            report("{0}<missing>\n", prefix)
            return
        except Exception:
            exception(
                "Error evaluating {0}",
                repr(expr) if expr else compat.srcnameof(get_paths),
            )
            return

        if not isinstance(paths, (list, tuple)):
            paths = [paths]

        for p in sorted(paths):
            report("{0}{1}", prefix, p)
            rp = os.path.realpath(p)
            if p != rp:
                report("({0})", rp)
            report("\n")

            prefix = " " * len(prefix)
Exemplo n.º 14
0
def test_add_and_remove_breakpoint(pyfile, target, run):
    @pyfile
    def code_to_debug():
        import debug_me  # noqa

        for i in range(0, 10):
            print(i)  # @bp
        ()  # @wait_for_output

    with debug.Session() as session:
        session.config["redirectOutput"] = True

        with run(session, target(code_to_debug)):
            session.set_breakpoints(code_to_debug, all)

        session.wait_for_stop(
            "breakpoint",
            expected_frames=[some.dap.frame(code_to_debug, line="bp")])

        # Remove breakpoint inside the loop.
        session.set_breakpoints(code_to_debug, ["wait_for_output"])
        session.request_continue()

        session.wait_for_stop(
            "breakpoint",
            expected_frames=[
                some.dap.frame(code_to_debug, line="wait_for_output")
            ],
        )
        session.request_continue()

    expected_stdout = "".join((fmt("{0}\n", i) for i in range(0, 10)))
    assert session.output("stdout") == expected_stdout
Exemplo n.º 15
0
    def __init__(self, method, url, *args, **kwargs):
        """Invokes requests.method(url, *args, **kwargs) on a background thread,
        and immediately returns.

        If method() raises an exception, it is logged, unless log_errors=False.
        """

        self.method = method
        self.url = url

        self.log_errors = kwargs.pop("log_errors", True)

        self.request = None
        """The underlying requests.Request object.

        Not set until wait_for_response() returns.
        """

        self.exception = None
        """Exception that occurred while performing the request, if any.

        Not set until wait_for_response() returns.
        """

        log.info("{0}", self)

        func = getattr(requests, method)
        self._worker_thread = threading.Thread(
            target=lambda: self._worker(func, *args, **kwargs),
            name=fmt("WebRequest({0})", self),
        )
        self._worker_thread.daemon = True
        self._worker_thread.start()
    def inject_server(self, pid, ptvsd_args):
        with self.accept_connection_from_server() as (host, port):
            cmdline = [
                sys.executable,
                compat.filename(os.path.dirname(ptvsd.__file__)),
                "--client",
                "--host",
                host,
                "--port",
                str(port),
            ]
            cmdline += ptvsd_args
            cmdline += ["--pid", str(pid)]

            log.info("{0} spawning attach-to-PID debugger injector: {1!r}",
                     self, cmdline)

            try:
                subprocess.Popen(
                    cmdline,
                    bufsize=0,
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                )
            except Exception as exc:
                log.exception("{0} failed to inject debugger", self)
                raise messaging.MessageHandlingError(
                    fmt("Failed to inject debugger: {0}", exc))
Exemplo n.º 17
0
    def notify_of_subprocess(self, conn):
        with self.session:
            if self.start_request is None or conn in self._known_subprocesses:
                return
            if "processId" in self.start_request.arguments:
                log.warning(
                    "Not reporting subprocess for {0}, because the parent process "
                    'was attached to using "processId" rather than "port".',
                    self.session,
                )
                return

            log.info("Notifying {0} about {1}.", self, conn)
            body = dict(self.start_request.arguments)
            self._known_subprocesses.add(conn)

        body["name"] = fmt("Subprocess {0}", conn.pid)
        body["request"] = "attach"
        if "host" not in body:
            body["host"] = "127.0.0.1"
        if "port" not in body:
            _, body["port"] = self.listener.getsockname()
        if "processId" in body:
            del body["processId"]
        body["subProcessId"] = conn.pid

        self.channel.send_event("ptvsd_attach", body)
Exemplo n.º 18
0
 def __repr__(self):
     result = type(self).__name__
     args = [str(x) for x in self._args] + [
         fmt("{0}={1}", k, v) for k, v in self._kwargs.items()
     ]
     if len(args):
         result += "(" + ", ".join(args) + ")"
     return result
Exemplo n.º 19
0
 def make_breakpoint(line):
     if isinstance(line, int):
         descr = str(line)
     else:
         marker = line
         line = get_marked_line_numbers()[marker]
         descr = fmt("{0} (@{1})", line, marker)
     bp_log.append((line, descr))
     return {"line": line}
Exemplo n.º 20
0
    def _capture(self, fd, name):
        assert name not in self._chunks
        self._chunks[name] = []

        thread = threading.Thread(target=lambda: self._worker(fd, name),
                                  name=fmt("{0} {1}", self, name))
        thread.daemon = True
        thread.start()
        self._worker_threads.append(thread)
Exemplo n.º 21
0
def _dump_worker_log(command, problem, exc_info=None):
    reason = fmt("{0}.{1}() {2}", _name, command, problem)
    if _worker_log_filename is None:
        reason += ", but there is no log."
    else:
        try:
            with open(_worker_log_filename) as f:
                worker_log = f.read()
        except Exception:
            reason += fmt(", but log {0} could not be retrieved.",
                          _worker_log_filename)
        else:
            reason += fmt("; watchdog worker process log:\n\n{0}", worker_log)

    if exc_info is None:
        log.error("{0}", reason)
    else:
        log.exception("{0}", reason, exc_info=exc_info)
    return reason
Exemplo n.º 22
0
def _attach_common_config(session, target, cwd):
    assert target.code is None or "debug_me" in target.code, fmt(
        "{0} must import debug_me.", target.filename
    )

    target.configure(session)
    config = session.config
    if cwd is not None:
        config.setdefault("pathMappings", [{"localRoot": cwd, "remoteRoot": "."}])
    return config
Exemplo n.º 23
0
 def __setitem__(self, key, value):
     """Sets debug_me.scratchpad[key] = value inside the debugged process.
     """
     log.info("{0} debug_me.scratchpad[{1!r}] = {2!r}", self.session, key,
              value)
     expr = fmt("sys.modules['debug_me'].scratchpad[{0!r}] = {1!r}", key,
                value)
     self.session.request("evaluate", {
         "context": "repl",
         "expression": expr
     })
Exemplo n.º 24
0
def prefixed(format_string, *args, **kwargs):
    """Adds a prefix to all messages logged from the current thread for the duration
    of the context manager.
    """
    prefix = fmt(format_string, *args, **kwargs)
    old_prefix = getattr(_tls, "prefix", "")
    _tls.prefix = prefix + old_prefix
    try:
        yield
    finally:
        _tls.prefix = old_prefix
Exemplo n.º 25
0
def connect(session_id, launcher_port):
    global channel
    assert channel is None

    sock = sockets.create_client()
    sock.connect(("127.0.0.1", launcher_port))

    stream = messaging.JsonIOStream.from_socket(sock,
                                                fmt("Adapter-{0}", session_id))
    channel = messaging.JsonMessageChannel(stream, handlers=Handlers())
    channel.start()
Exemplo n.º 26
0
 def start(self):
     config = self.config
     request = config.get("request", None)
     if request == "attach":
         host = config["host"]
         port = config["port"]
         self.connect_to_adapter((host, port))
         return self.request_attach()
     else:
         raise ValueError(
             fmt('Unsupported "request":{0!j} in session.config', request))
Exemplo n.º 27
0
 def _process_event(self, event):
     occ = self.timeline.record_event(event, block=False)
     if event.event == "exited":
         self.observe(occ)
         self.exit_code = event("exitCode", int)
         assert self.exit_code == self.expected_exit_code
     elif event.event == "ptvsd_attach":
         self.observe(occ)
         pid = event("subProcessId", int)
         watchdog.register_spawn(
             pid, fmt("{0}-subprocess-{1}", self.debuggee_id, pid))
Exemplo n.º 28
0
Arquivo: json.py Projeto: yazici/ptvsd
    def validate(value):
        if value == ():
            return {}

        of_type(dict)(value)
        if validate_value:
            for k, v in value.items():
                try:
                    value[k] = validate_value(v)
                except (TypeError, ValueError) as exc:
                    raise type(exc)(fmt("[{0!j}] {1}", k, exc))
        return value
Exemplo n.º 29
0
def write_format(level, format_string, *args, **kwargs):
    # Don't spend cycles doing expensive formatting if we don't have to. Errors are
    # always formatted, so that error() can return the text even if it's not logged.
    if level != "error" and level not in _levels:
        return

    try:
        text = fmt(format_string, *args, **kwargs)
    except Exception:
        exception()
        raise

    return write(level, text, kwargs.pop("_to_files", all))
Exemplo n.º 30
0
    def __init__(self, sock):
        from ptvsd.adapter import sessions

        self.server = None
        """The Server component, if this debug server belongs to Session.
        """

        self.pid = None

        stream = messaging.JsonIOStream.from_socket(sock, str(self))
        self.channel = messaging.JsonMessageChannel(stream, self)
        self.channel.start()

        try:
            info = self.channel.request("pydevdSystemInfo")
            process_info = info("process", json.object())
            self.pid = process_info("pid", int)
            self.ppid = process_info("ppid", int, optional=True)
            if self.ppid == ():
                self.ppid = None

            self.channel.name = stream.name = str(self)
            with _lock:
                if any(conn.pid == self.pid for conn in _connections):
                    raise KeyError(
                        fmt("{0} is already connected to this adapter", self))
                _connections.append(self)
                _connections_changed.set()

        except Exception:
            log.exception("Failed to accept incoming server connection:")
            # If we couldn't retrieve all the necessary info from the debug server,
            # or there's a PID clash, we don't want to track this debuggee anymore,
            # but we want to continue accepting connections.
            self.channel.close()
            return

        parent_session = sessions.get(self.ppid)
        if parent_session is None:
            log.info("No active debug session for parent process of {0}.",
                     self)
        else:
            try:
                parent_session.ide.notify_of_subprocess(self)
            except Exception:
                # This might fail if the IDE concurrently disconnects from the parent
                # session. We still want to keep the connection around, in case the
                # IDE reconnects later. If the parent session was "launch", it'll take
                # care of closing the remaining server connections.
                log.exception("Failed to notify parent session about {0}:",
                              self)