Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
#
# class Foo:
# blah = ic
# Foo.blah()
#
parentBlockSource = textwrap.dedent(parentBlockSource)
potentialCalls = [
node for node in ast.walk(ast.parse(parentBlockSource))
if isAstNodeIceCreamCall(node, icNames, icMethod) and
linenoRelativeToParent in getAllLineNumbersOfAstNode(node)]
if not potentialCalls:
# TODO(grun): Add note that to NoSourceAvailableError that this
# situation can occur when the underlying source changed during
# execution.
raise NoSourceAvailableError()
endLine = lineno - parentBlockStartLine + 1
startLine = min(call.lineno for call in potentialCalls)
lines = parentBlockSource.splitlines()[startLine - 1: endLine]
# inspect's lineno attribute doesn't point to the closing right parenthesis
# if the closing right parenthesis is on its own line without any
# arguments. E.g.
#
# ic(1,
# 2 <--- inspect's reported lineno.
# ) <--- Should be the reported lineno.
#
# Detect this situation and add the missing right parenthesis.
if isCallStrMissingClosingRightParenthesis('\n'.join(lines).strip()):
lines.append(')')
# which bypasses getblock().
#
# Also, the errors raised differ between Python2 and Python3 . In Python2,
# inspect.findsource() and inspect.getsource() raise IOErrors. In Python3,
# inspect.findsource() and inspect.getsource() raise OSErrors.
try:
if code.co_name == '': # Module -> use workaround above.
parentBlockStartLine = 1
lines = inspect.findsource(code)[0] # Raises [IO/OS]Error.
parentBlockSource = ''.join(lines)
else: # Not a module -> use inspect.getsource() normally.
parentBlockStartLine = code.co_firstlineno
parentBlockSource = inspect.getsource(code) # Raises [IO/OS]Error.
except (IOError, OSError) as err:
if 'source code' in err.args[0]:
raise NoSourceAvailableError()
else:
raise
lineno = inspect.getframeinfo(callFrame)[1]
linenoRelativeToParent = lineno - parentBlockStartLine + 1
# There could be multiple ic() calls on the same line(s), like
#
# ic(1); ic(2); ic(3,
# 4,
# 5); ic(6)
#
# so include all of them. Which invocation is the appropriate one will be
# determined later via bytecode offset calculations.
#
# TODO(grun): Support invocations of ic() where ic() is an attribute chain
def __call__(self, *args):
if self.enabled:
callFrame = inspect.currentframe().f_back
try:
out = self._format(callFrame, *args)
except NoSourceAvailableError as err:
prefix = callOrValue(self.prefix)
out = prefix + 'Error: ' + err.infoMessage
self.outputFunction(out)
if not args: # E.g. ic().
passthrough = None
elif len(args) == 1: # E.g. ic(1).
passthrough = args[0]
else: # E.g. ic(1, 2, 3).
passthrough = args
return passthrough