debugpy/tests/debug/targets.py
Pavel Minaev 4f43e00a07 Remove suppport for arrays in "program" and "module" debug configuration properties as alternative to "args".
Change the meaning of array for "code" debug configuration property to represent multiple lines of code.

Switch tests to use "args".
2020-02-21 15:55:17 -08:00

164 lines
4.7 KiB
Python

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.
from __future__ import absolute_import, division, print_function, unicode_literals
import py
from debugpy.common import fmt
from tests.patterns import some
class Target(object):
"""Describes Python code that gets run by a Runner.
"""
def __init__(self, filename, args=()):
if filename is not None and not isinstance(filename, py.path.local):
filename = py.path.local(filename)
self.filename = filename
self.args = args
if self.filename is None:
self.code = None
else:
with open(self.filename.strpath, "rb") as f:
self.code = f.read().decode("utf-8")
def configure(self, session):
"""Configures the session to execute this target.
This should only modify session.config, but gets access to the entire session
to retrieve information about it.
"""
raise NotImplementedError
def cli(self, env):
"""Provides the command line arguments, suitable for passing to python or
python -m debugpy, to execute this target.
Returns command line arguments as a list, e.g. ["-m", "module"].
If any environment variables are needed to properly interpret the command
line - e.g. PYTHONPATH - the implementation should send them in env.
"""
raise NotImplementedError
@property
def co_filename(self):
"""co_filename of code objects created at runtime from the source that this
Target describes, assuming no path mapping.
"""
assert (
self.filename is not None
), "co_filename requires Target created from filename"
return self.filename.strpath
@property
def source(self):
"""DAP "source" JSON for this Target."""
return some.dap.source(py.path.local(self.co_filename))
@property
def lines(self):
"""Same as self.filename.lines, if it is valid - e.g. for @pyfile objects.
"""
assert (
self.filename is not None
), "lines() requires Target created from filename"
return self.filename.lines
class Program(Target):
"""A Python script, executed directly: python foo.py
"""
pytest_id = "program"
def __repr__(self):
return fmt("program {0!j}", self.filename)
def configure(self, session):
session.config["program"] = self.filename
session.config["args"] = self.args
def cli(self, env):
return [self.filename.strpath] + list(self.args)
class Module(Target):
"""A Python module, executed by name: python -m foo.bar
If created from a filename, the module name is the name of the file, and the
Target will automatically add a PYTHONPATH entry.
"""
pytest_id = "module"
def __init__(self, filename=None, name=None, args=()):
assert (filename is None) ^ (name is None)
super(Module, self).__init__(filename, args)
self.name = name if name is not None else self.filename.purebasename
def __repr__(self):
return fmt("module {0}", self.name)
def configure(self, session):
session.config["module"] = self.name
session.config["args"] = self.args
def cli(self, env):
if self.filename is not None:
env.prepend_to("PYTHONPATH", self.filename.dirname)
return ["-m", self.name] + list(self.args)
class Code(Target):
"""A snippet of Python code: python -c "print('foo')"
If created from a filename, the code is the contents of the file.
"""
pytest_id = "code"
def __init__(self, filename=None, code=None, args=()):
assert (filename is None) ^ (code is None)
super(Code, self).__init__(filename, args)
if code is not None:
self.code = code
def __repr__(self):
lines = self.code.split("\n")
return fmt("code: {0!j}", lines)
def configure(self, session):
session.config["code"] = self.code
session.config["args"] = self.args
def cli(self, env):
return ["-c", self.code] + list(self.args)
@property
def co_filename(self):
return "<string>"
@property
def source(self):
"""DAP "source" JSON for this Target."""
return some.dap.source("<string>")
all_named = [Program, Module]
"""All targets that produce uniquely named code objects at runtime, and thus can
have breakpoints set in them.
"""
all_unnamed = [Code]
"""All targets that produce unnamed code objects at runtime, and thus cannot have
breakpoints set in them.
"""
all = all_named + all_unnamed