Пример #1
0
def indent(code, spaces=4):
    '''indent a block of code with whitespace (default is 4 spaces)'''
    indent = indentsize(code) 
    if type(spaces) is int: spaces = ' '*spaces
    # if '\t' is provided, will indent with a tab
    nspaces = indentsize(spaces)
    # blank lines (etc) need to be ignored
    lines = code.split('\n')
##  stq = "'''"; dtq = '"""'
##  in_stq = in_dtq = False
    for i in range(len(lines)):
        #FIXME: works... but shouldn't indent 2nd+ lines of multiline doc
        _indent = indentsize(lines[i])
        if indent > _indent: continue
        lines[i] = spaces+lines[i]
##      #FIXME: may fail when stq and dtq in same line (depends on ordering)
##      nstq, ndtq = lines[i].count(stq), lines[i].count(dtq)
##      if not in_dtq and not in_stq:
##          lines[i] = spaces+lines[i] # we indent
##          # entering a comment block
##          if nstq%2: in_stq = not in_stq
##          if ndtq%2: in_dtq = not in_dtq
##      # leaving a comment block
##      elif in_dtq and ndtq%2: in_dtq = not in_dtq
##      elif in_stq and nstq%2: in_stq = not in_stq
##      else: pass
    if lines[-1].strip() == '': lines[-1] = ''
    return '\n'.join(lines)
Пример #2
0
def _outdent(lines, spaces=None, all=True):
    '''outdent lines of code, accounting for docs and line continuations'''
    indent = indentsize(lines[0]) 
    if spaces is None or spaces > indent or spaces < 0: spaces = indent
    for i in range(len(lines) if all else 1):
        #FIXME: works... but shouldn't outdent 2nd+ lines of multiline doc
        _indent = indentsize(lines[i])
        if spaces > _indent: _spaces = _indent
        else: _spaces = spaces
        lines[i] = lines[i][_spaces:]
    return lines
Пример #3
0
def outdent(code, spaces=None, all=True):
    '''outdent a block of code (default is to strip all leading whitespace)'''
    indent = indentsize(code) 
    if spaces is None or spaces > indent or spaces < 0: spaces = indent
    #XXX: will this delete '\n' in some cases?
    if not all: return code[spaces:]
    return '\n'.join(_outdent(code.split('\n'), spaces=spaces, all=all))
Пример #4
0
def getcomments(pyObject):
    """Get lines of comments immediately preceding an object's source code.

    Returns None when source can't be found.
    """
    try:
        lines, lnum = findsource(pyObject)
    except (IOError, TypeError):
        return None

    if ismodule(pyObject):
        # Look for a comment block at the top of the file.
        start = 0
        if lines and lines[0][:2] == '#!': start = 1
        while start < len(lines) and string.strip(lines[start]) in ('', '#'):
            start = start + 1
        if start < len(lines) and lines[start][:1] == '#':
            comments = []
            end = start
            while end < len(lines) and lines[end][:1] == '#':
                comments.append(string.expandtabs(lines[end]))
                end = end + 1
            return string.join(comments, '')

    # Look for a preceding block of comments at the same indentation.
    elif lnum > 0:
        indent = indentsize(lines[lnum])
        end = lnum - 1
        if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \
            indentsize(lines[end]) == indent:
            comments = [string.lstrip(string.expandtabs(lines[end]))]
            if end > 0:
                end = end - 1
                comment = string.lstrip(string.expandtabs(lines[end]))
                while comment[:1] == '#' and indentsize(lines[end]) == indent:
                    comments[:0] = [comment]
                    end = end - 1
                    if end < 0: break
                    comment = string.lstrip(string.expandtabs(lines[end]))
            while comments and string.strip(comments[0]) == '#':
                comments[:1] = []
            while comments and string.strip(comments[-1]) == '#':
                comments[-1:] = []
            return string.join(comments, '')
Пример #5
0
def _matchlambda(func, line):
    """check if lambda object 'func' matches raw line of code 'line'"""
    from .detect import code as getcode
    from .detect import freevars, globalvars, varnames
    dummy = lambda: '__this_is_a_big_dummy_function__'
    # process the line (removing leading whitespace, etc)
    lhs, rhs = line.split('lambda ', 1)[-1].split(":", 1)  #FIXME: if !1 inputs
    try:  #FIXME: unsafe
        _ = eval("lambda %s : %s" % (lhs, rhs), globals(), locals())
    except:
        _ = dummy
    # get code objects, for comparison
    _, code = getcode(_).co_code, getcode(func).co_code
    # check if func is in closure
    _f = [line.count(i) for i in freevars(func).keys()]
    if not _f:  # not in closure
        # check if code matches
        if _ == code: return True
        return False
    # weak check on freevars
    if not all(_f): return False  #XXX: VERY WEAK
    # weak check on varnames and globalvars
    _f = varnames(func)
    _f = [line.count(i) for i in _f[0] + _f[1]]
    if _f and not all(_f): return False  #XXX: VERY WEAK
    _f = [line.count(i) for i in globalvars(func).keys()]
    if _f and not all(_f): return False  #XXX: VERY WEAK
    # check if func is a double lambda
    if (line.count('lambda ') > 1) and (lhs in freevars(func).keys()):
        _lhs, _rhs = rhs.split('lambda ', 1)[-1].split(":",
                                                       1)  #FIXME: if !1 inputs
        try:  #FIXME: unsafe
            _f = eval("lambda %s : %s" % (_lhs, _rhs), globals(), locals())
        except:
            _f = dummy
        # get code objects, for comparison
        _, code = getcode(_f).co_code, getcode(func).co_code
        if len(_) != len(code): return False
        #NOTE: should be same code same order, but except for 't' and '\x88'
        _ = set((i, j) for (i, j) in zip(_, code) if i != j)
        if len(_) != 1: return False  #('t','\x88')
        return True
    # check indentsize
    if not indentsize(line): return False  #FIXME: is this a good check???
    # check if code 'pattern' matches
    #XXX: or pattern match against dis.dis(code)? (or use uncompyle2?)
    _ = _.split(_[0])  # 't' #XXX: remove matching values if starts the same?
    _f = code.split(code[0])  # '\x88'
    #NOTE: should be same code different order, with different first element
    _ = dict(
        re.match('([\W\D\S])(.*)', _[i]).groups() for i in range(1, len(_)))
    _f = dict(
        re.match('([\W\D\S])(.*)', _f[i]).groups() for i in range(1, len(_f)))
    if (_.keys() == _f.keys()) and (sorted(_.values()) == sorted(_f.values())):
        return True
    return False
Пример #6
0
def get_internal_comments(object):
    lines, lnum = inspect.findsource(object)
    if len(lines) <= lnum + 1:
        # object is probably an emply module.
        return None
    indent = inspect.indentsize(lines[lnum+1])

    comments = []
    for line in lines[lnum + 1:]:
        comment = line.strip()
        # A line is a comment if it matches the indentation the first line and
        # begins with a '#'
        if inspect.indentsize(line) == indent and comment.startswith('#'):
            comments.append(comment)
        else:
            break
    if len(comments) == 0:
        return None
    else:
        return '\n'.join(comments)
Пример #7
0
def get_annotation_comment_and_line_by_source(container_object, variable_name, source_file):
    try:
        lines, lnum = get_source(container_object, source_file)
    except (OSError, TypeError):
        return None

    i = 1
    while indentsize(lines[lnum + i]) == indentsize(lines[lnum]):
        i += 1

    if len(lines) > lnum and indentsize(lines[lnum + i]) > indentsize(lines[lnum]):
        this_cls_indentsize = indentsize(lines[lnum + i])

        l = lnum + i
        while l < len(lines):
            cur_indentsize = indentsize(lines[l])
            if cur_indentsize < this_cls_indentsize and lines[l].strip() != "":
                break

            if cur_indentsize == this_cls_indentsize:
                expr = lines[l].strip().replace(" ", "")
                if expr.startswith(variable_name + ":"):
                    lnum = l
                    break
            l += 1

    if lnum > 0:
        indent = indentsize(lines[lnum])
        end = lnum - 1
        if end >= 0 and lines[end].lstrip()[:1] == '#' and \
                        indentsize(lines[end]) == indent:
            comments = [lines[end].expandtabs().lstrip()]
            if end > 0:
                end = end - 1
                comment = lines[end].expandtabs().lstrip()
                while comment[:1] == '#' and indentsize(lines[end]) == indent:
                    comments[:0] = [comment]
                    end = end - 1
                    if end < 0: break
                    comment = lines[end].expandtabs().lstrip()
            while comments and comments[0].strip() == '#':
                comments[:1] = []
            while comments and comments[-1].strip() == '#':
                comments[-1:] = []
            return '\n'.join(comments), lnum
    return None, lnum
Пример #8
0
def _find_line_info_of_attr_in_source(
        frame: Optional[FrameType], key: str,
        attr: "AbstractComplexExtractor") -> _LineInfo:
    if frame is None:
        return _LineInfo(None, None, None, f"{key}={attr!r}")

    file = frame.f_code.co_filename
    firstlineno = frame.f_lineno
    firstline_idx = firstlineno - 1
    try:
        lines, _ = inspect.findsource(frame)
    except OSError:
        # can't get the source code from python repl
        return _LineInfo(None, None, None, f"{key}={attr!r}")

    start_index = inspect.indentsize(lines[firstline_idx])
    for lineno, line in enumerate(lines[firstline_idx + 1:],
                                  start=firstlineno + 1):
        # iterate line in the code block body
        cur_index = inspect.indentsize(line)
        if cur_index <= start_index:
            # reach end of the code block,
            # use code block firstlineno as SyntaxError.lineno
            line = lines[firstline_idx]
            lineno = firstlineno
            break

        if line.lstrip().startswith(key):
            # find the line as SyntaxError.text
            break

    else:
        # reach EOF,
        # use code block firstlineno as SyntaxError.lineno
        line = lines[firstline_idx]
        lineno = firstlineno

    offset = inspect.indentsize(line)
    line = line.strip()
    return _LineInfo(file, lineno, offset, line)
Пример #9
0
def _matchlambda(func, line):
    """check if lambda object 'func' matches raw line of code 'line'"""
    from .detect import code as getcode
    from .detect import freevars, globalvars, varnames
    dummy = lambda : '__this_is_a_big_dummy_function__'
    # process the line (removing leading whitespace, etc)
    lhs,rhs = line.split('lambda ',1)[-1].split(":", 1) #FIXME: if !1 inputs
    try: #FIXME: unsafe
        _ = eval("lambda %s : %s" % (lhs,rhs), globals(),locals())
    except: _ = dummy
    # get code objects, for comparison
    _, code = getcode(_).co_code, getcode(func).co_code
    # check if func is in closure
    _f = [line.count(i) for i in freevars(func).keys()]
    if not _f: # not in closure
        # check if code matches
        if _ == code: return True
        return False
    # weak check on freevars
    if not all(_f): return False  #XXX: VERY WEAK
    # weak check on varnames and globalvars
    _f = varnames(func)
    _f = [line.count(i) for i in _f[0]+_f[1]]
    if _f and not all(_f): return False  #XXX: VERY WEAK
    _f = [line.count(i) for i in globalvars(func).keys()]
    if _f and not all(_f): return False  #XXX: VERY WEAK
    # check if func is a double lambda
    if (line.count('lambda ') > 1) and (lhs in freevars(func).keys()):
        _lhs,_rhs = rhs.split('lambda ',1)[-1].split(":",1) #FIXME: if !1 inputs
        try: #FIXME: unsafe
            _f = eval("lambda %s : %s" % (_lhs,_rhs), globals(),locals())
        except: _f = dummy
        # get code objects, for comparison
        _, code = getcode(_f).co_code, getcode(func).co_code
        if len(_) != len(code): return False
        #NOTE: should be same code same order, but except for 't' and '\x88'
        _ = set((i,j) for (i,j) in zip(_,code) if i != j)
        if len(_) != 1: return False #('t','\x88')
        return True
    # check indentsize
    if not indentsize(line): return False #FIXME: is this a good check???
    # check if code 'pattern' matches
    #XXX: or pattern match against dis.dis(code)? (or use uncompyle2?)
    _ = _.split(_[0])  # 't' #XXX: remove matching values if starts the same?
    _f = code.split(code[0])  # '\x88'
    #NOTE: should be same code different order, with different first element
    _ = dict(re.match(r'([\W\D\S])(.*)', _[i]).groups() for i in range(1,len(_)))
    _f = dict(re.match(r'([\W\D\S])(.*)', _f[i]).groups() for i in range(1,len(_f)))
    if (_.keys() == _f.keys()) and (sorted(_.values()) == sorted(_f.values())):
        return True
    return False
Пример #10
0
def get_func_source_code(func):
    if isinstance(func, types.MethodType):
        if sys.version_info[0] == 3:
            src_code = inspect.getsource(func.__self__.__class__)
        else:
            im_class = get_method_defined_class(func)
            src_code = inspect.getsource(im_class)
    else:
        src_code = inspect.getsource(func)
    indent = inspect.indentsize(src_code)
    if indent > 0:
        lines = src_code.split("\n")
        src_code = ""
        for line in lines:
            src_code += line[indent:] + "\n"
    return src_code
Пример #11
0
    def __init__(self, o):
        """Transcode a Python function or module

        In:
          - ``o`` -- Python function or module to transcode
        """
        if hasattr(o, '_js_name'):
            # Already transcoded
            self.name = o._js_name
            self.javascript = o._js_code
            return

        src = inspect.getsource(o)

        classname = ''
        if isinstance(o, types.MethodType):
            classname = o.im_class.__name__
            o = o.im_func

        if isinstance(o, types.FunctionType):
            if o.__module__ == '__main__':
                self.name = module = classname
            else:
                module = o.__module__.replace('.', '_')
                if classname:
                    module += ('_' + classname)
                self.name = module + '_'

            self.name += o.func_name

            indent = inspect.indentsize(src)
            src = ''.join([s.expandtabs()[indent:] for s in src.splitlines(True)])
        else:
            if o.__name__ == '__main__':
                self.name = module = ''
            else:
                self.name = module = o.__name__.replace('.', '_')

        self.javascript = str2js(src, module)

        # Keep the transcoded javascript
        o._js_name = self.name
        o._js_code = self.javascript
Пример #12
0
    def __init__(self, o):
        """Transcode a Python function or module

        In:
          - ``o`` -- Python function or module to transcode
        """
        if hasattr(o, '_js_name'):
            # Already transcoded
            self.name = o._js_name
            self.javascript = o._js_code
            return

        src = inspect.getsource(o)

        classname = ''
        if isinstance(o, types.MethodType):
            classname = o.im_class.__name__
            o = o.im_func

        if isinstance(o, types.FunctionType):
            if o.__module__ == '__main__':
                self.name = module = classname
            else:
                module = o.__module__.replace('.', '_')
                if classname:
                    module += ('_' + classname)
                self.name = module + '_'

            self.name += o.func_name

            indent = inspect.indentsize(src)
            src = ''.join([s.expandtabs()[indent:] for s in src.splitlines(True)])
        else:
            if o.__name__ == '__main__':
                self.name = module = ''
            else:
                self.name = module = o.__name__.replace('.', '_')

        self.javascript = str2js(src, module)

        # Keep the transcoded javascript
        o._js_name = self.name
        o._js_code = self.javascript
Пример #13
0
def getblocks(object, lstrip=False, enclosing=False, locate=False):
    """Return a list of source lines and starting line number for an object.
    Interactively-defined objects refer to lines in the interpreter's history.

    If enclosing=True, then also return any enclosing code.
    If lstrip=True, ensure there is no indentation in the first line of code.
    If locate=True, then also return the line number for the block of code.

    DEPRECATED: use 'getsourcelines' instead
    """
    lines, lnum = findsource(object)

    if ismodule(object):
        if lstrip: lines = _outdent(lines)
        return ([lines], [0]) if locate is True else [lines]

    #XXX: 'enclosing' means: closures only? or classes and files?
    indent = indentsize(lines[lnum])
    block = getblock(lines[lnum:]) #XXX: catch any TokenError here?

    if not enclosing or not indent:
        if lstrip: block = _outdent(block)
        return ([block], [lnum]) if locate is True else [block]

    pat1 = r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))'; pat1 = re.compile(pat1)
    pat2 = r'^(\s*@)'; pat2 = re.compile(pat2)
   #pat3 = r'^(\s*class\s)'; pat3 = re.compile(pat3) #XXX: enclosing class?
    #FIXME: bound methods need enclosing class (and then instantiation)
    #       *or* somehow apply a partial using the instance

    skip = 0
    line = 0
    blocks = []; _lnum = []
    target = ''.join(block)
    while line <= lnum: #XXX: repeat lnum? or until line < lnum?
        # see if starts with ('def','lambda') and contains our target block
        if pat1.match(lines[line]):
            if not skip:
                try: code = getblock(lines[line:])
                except TokenError: code = [lines[line]]
            if indentsize(lines[line]) > indent: #XXX: should be >= ?
                line += len(code) - skip
            elif target in ''.join(code):
                blocks.append(code) # save code block as the potential winner
                _lnum.append(line - skip) # save the line number for the match
                line += len(code) - skip
            else:
                line += 1
            skip = 0
        # find skip: the number of consecutive decorators
        elif pat2.match(lines[line]):
            try: code = getblock(lines[line:])
            except TokenError: code = [lines[line]]
            skip = 1
            for _line in code[1:]: # skip lines that are decorators
                if not pat2.match(_line): break
                skip += 1
            line += skip
        # no match: reset skip and go to the next line
        else:
            line +=1
            skip = 0

    if not blocks:
        blocks = [block]
        _lnum = [lnum]
    if lstrip: blocks = [_outdent(block) for block in blocks]
    # return last match
    return (blocks, _lnum) if locate is True else blocks
Пример #14
0
def getblocks(object, lstrip=False, enclosing=False, locate=False):
    """Return a list of source lines and starting line number for an object.
    Interactively-defined objects refer to lines in the interpreter's history.

    If enclosing=True, then also return any enclosing code.
    If lstrip=True, ensure there is no indentation in the first line of code.
    If locate=True, then also return the line number for the block of code.

    DEPRECATED: use 'getsourcelines' instead
    """
    lines, lnum = findsource(object)

    if ismodule(object):
        if lstrip: lines = _outdent(lines)
        return ([lines], [0]) if locate is True else [lines]

    #XXX: 'enclosing' means: closures only? or classes and files?
    indent = indentsize(lines[lnum])
    block = getblock(lines[lnum:])  #XXX: catch any TokenError here?

    if not enclosing or not indent:
        if lstrip: block = _outdent(block)
        return ([block], [lnum]) if locate is True else [block]

    pat1 = r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))'
    pat1 = re.compile(pat1)
    pat2 = r'^(\s*@)'
    pat2 = re.compile(pat2)
    #pat3 = r'^(\s*class\s)'; pat3 = re.compile(pat3) #XXX: enclosing class?
    #FIXME: bound methods need enclosing class (and then instantiation)
    #       *or* somehow apply a partial using the instance

    skip = 0
    line = 0
    blocks = []
    _lnum = []
    target = ''.join(block)
    while line <= lnum:  #XXX: repeat lnum? or until line < lnum?
        # see if starts with ('def','lambda') and contains our target block
        if pat1.match(lines[line]):
            if not skip:
                try:
                    code = getblock(lines[line:])
                except TokenError:
                    code = [lines[line]]
            if indentsize(lines[line]) > indent:  #XXX: should be >= ?
                line += len(code) - skip
            elif target in ''.join(code):
                blocks.append(code)  # save code block as the potential winner
                _lnum.append(line - skip)  # save the line number for the match
                line += len(code) - skip
            else:
                line += 1
            skip = 0
        # find skip: the number of consecutive decorators
        elif pat2.match(lines[line]):
            try:
                code = getblock(lines[line:])
            except TokenError:
                code = [lines[line]]
            skip = 1
            for _line in code[1:]:  # skip lines that are decorators
                if not pat2.match(_line): break
                skip += 1
            line += skip
        # no match: reset skip and go to the next line
        else:
            line += 1
            skip = 0

    if not blocks:
        blocks = [block]
        _lnum = [lnum]
    if lstrip: blocks = [_outdent(block) for block in blocks]
    # return last match
    return (blocks, _lnum) if locate is True else blocks
Пример #15
0
    def __init__(cls, name: str, bases: Tuple[type], attr_dict: Dict[str,
                                                                     Any]):
        super().__init__(name, bases, attr_dict)
        field_names: List[str] = []

        __init_args = inspect.getfullargspec(getattr(cls, "__init__")).args

        for key, attr in attr_dict.items():
            if isinstance(type(attr), ComplexExtractorMeta):
                if key in __init_args[1:]:
                    # Item's attribute overwrites the 'Item.__init__' parameters except first parameter.
                    args = []  # type: List[Any]
                    exc_args = None
                    frame = inspect.currentframe()
                    assert (
                        frame is not None
                    ), "If running in an implementation without Python stack frame support this function returns None."
                    try:
                        outer_frame = frame.f_back

                        filename = outer_frame.f_code.co_filename
                        firstlineno = outer_frame.f_lineno
                        firstline_idx = firstlineno - 1
                        lines = None
                        try:
                            lines, _ = inspect.findsource(outer_frame)
                        except OSError:
                            # can't get the source code from python repl
                            pass

                        if lines is not None:
                            start_index = inspect.indentsize(
                                lines[firstline_idx])
                            for lineno, line in enumerate(
                                    lines[firstline_idx + 1:],
                                    start=firstlineno + 1):
                                # iterate line in the code block body
                                cur_index = inspect.indentsize(line)
                                if cur_index <= start_index:
                                    # reach end of the code block, use code block firstlineno as SyntaxError.lineno
                                    line = lines[firstline_idx]
                                    lineno = firstlineno
                                    break

                                if line.lstrip().startswith(key):
                                    # find the line as SyntaxError.text
                                    break

                            else:
                                # reach EOF, use code block firstlineno as SyntaxError.lineno
                                line = lines[firstline_idx]
                                lineno = firstlineno

                            offset = inspect.indentsize(line)
                            line = line.strip()
                            exc_args = (filename, lineno, offset, line)
                        else:
                            line = f"{key}={attr!r}"

                    finally:
                        del outer_frame
                        del frame

                    args.append(
                        f"{line!r} overwriten the parameter {key!r} of '{name}.__init__' method. "
                        f"Please using the optional parameter name={key!r} in {attr!r} to avoid overwriting parameter name."
                    )
                    if exc_args is not None:
                        args.append(exc_args)

                    raise SyntaxError(*args)

                field_names.append(key)

        cls._field_names = field_names
Пример #16
0
 def _func_to_code(self, func):
     lines = inspect.getsourcelines(func)[0]
     indent = inspect.indentsize(lines[0])
     code = ''.join([ i[indent:] for i in lines ])
     return code