def test_universal_new_lines(self): test_file = os.path.join(TEST_DIR, 'dos-file') lines = pyficache.getlines(test_file) self.assertEqual(lines, ['Foo\n', 'bar\n', 'baz\n']) self.assertTrue(test_file in pyficache.file_cache) file_obj = pyficache.file_cache[test_file] self.assertEqual('\r\n', file_obj.eols) test_file = os.path.join(TEST_DIR, 'mixed-eol-file') lines = pyficache.getlines(test_file) self.assertEqual(lines, ['Unix\n', 'DOS\n', 'unix\n']) self.assertTrue(test_file in pyficache.file_cache) file_obj = pyficache.file_cache[test_file] self.assertEqual(('\n', '\r\n'), file_obj.eols)
def find_ref(self): """Get the external file reference and line number. :raises: :class:`~doorstop.common.DoorstopError` when no reference is found :return: relative path to file or None (when no reference set), line number (when found in file) or None (when found as filename) or None (when no reference set) """ # Return immediately if no external reference if not self.ref: log.debug("no external reference to search for") return None, None # Update the cache if not settings.CACHE_PATHS: pyficache.clear_file_cache() # Search for the external reference log.debug("seraching for ref '{}'...".format(self.ref)) pattern = r"(\b|\W){}(\b|\W)".format(re.escape(self.ref)) log.trace("regex: {}".format(pattern)) regex = re.compile(pattern) for path, filename, relpath in self.tree.vcs.paths: # Skip the item's file while searching if path == self.path: continue # Check for a matching filename if filename == self.ref: return relpath, None # Skip extensions that should not be considered text if os.path.splitext(filename)[-1] in settings.SKIP_EXTS: continue # Search for the reference in the file lines = pyficache.getlines(path) if lines is None: log.trace("unable to read lines from: {}".format(path)) continue for lineno, line in enumerate(lines, start=1): if regex.search(line): log.debug("found ref: {}".format(relpath)) return relpath, lineno msg = "external reference not found: {}".format(self.ref) raise DoorstopError(msg)
def find_file_reference(ref_path, root, tree, item_path, keyword=None): """Find the external file reference. :raises: :class:`~doorstop.common.DoorstopError` when no reference is found :return: Tuple (ref_path, line) when reference is found """ log.debug("searching for ref '{}'...".format(ref_path)) ref_full_path = os.path.join(root, ref_path) for path, filename, relpath in tree.vcs.paths: # Skip the item's file while searching if path == item_path: continue if path == ref_full_path: if keyword is None: return relpath, None # Search for the reference in the file lines = pyficache.getlines(path) if lines is None: log.trace( # type: ignore "unable to read lines from: {}".format( path)) # type: ignore continue log.debug("searching for ref '{}'...".format(keyword)) pattern = r"(\b|\W){}(\b|\W)".format(re.escape(keyword)) log.trace("regex: {}".format(pattern)) # type: ignore regex = re.compile(pattern) for lineno, line in enumerate(lines, start=1): if regex.search(line): log.debug("found ref: {}".format(relpath)) return relpath, lineno msg = "external reference not found: {}".format(ref_path) raise DoorstopError(msg)
def run(self, args): co = self.proc.curframe.f_code name = co.co_name try: opts, args = getopt(args[1:], "hpPAto:O", [ "help", "parent", "pretty", "AST", 'tree', "offset=", "offsets" ]) except GetoptError as err: # print help information and exit: print(str( err)) # will print something like "option -a not recognized" return show_parent = False show_ast = False offset = None show_offsets = False for o, a in opts: if o in ("-h", "--help"): self.proc.commands['help'].run(['help', 'deparse']) return elif o in ("-O", "--offsets"): show_offsets = True elif o in ("-p", "--parent"): show_parent = True elif o in ("-A", "--tree", '--AST'): show_ast = True elif o in ("-o", '--offset'): offset = a else: self.errmsg("unhandled option '%s'" % o) pass pass nodeInfo = None try: float_version = sysinfo2float() except: self.errmsg(sys.exc_info()[1]) return if len(args) >= 1 and args[0] == '.': temp_filename, name_for_code = deparse_and_cache(co, self.errmsg) if not temp_filename: return self.print_text(''.join(getlines(temp_filename))) return elif show_offsets: deparsed = deparse_code(float_version, co, is_pypy=IS_PYPY) self.section("Offsets known:") m = self.columnize_commands( list(sorted(deparsed.offsets.keys(), key=lambda x: str(x[0])))) self.msg_nocr(m) return elif offset is not None: mess = ("The 'deparse' command when given an argument requires an" " instruction offset. Got: '%s'" % offset) last_i = self.proc.get_an_int(offset, mess) if last_i is None: return else: last_i = self.proc.curframe.f_lasti if last_i == -1: last_i = 0 try: deparsed = deparse_code(float_version, co, is_pypy=IS_PYPY) nodeInfo = deparsed_find((name, last_i), deparsed, co) if not nodeInfo: self.errmsg( "Can't find exact offset %d; giving inexact results" % last_i) deparsed = deparse_code_around_offset(co.co_name, last_i, float_version, co, is_pypy=IS_PYPY) except: self.errmsg(sys.exc_info()[1]) self.errmsg("error in deparsing code at offset %d" % last_i) return if not nodeInfo: nodeInfo = deparsed_find((name, last_i), deparsed, co) if nodeInfo: extractInfo = deparsed.extract_node_info(nodeInfo) parentInfo = None # print extractInfo if show_ast: p = deparsed.ast if show_parent: parentInfo, p = deparsed.extract_parent_info(nodeInfo.node) self.msg(p) if extractInfo: self.rst_msg("*instruction:* %s" % (nodeInfo.node)) self.print_text(extractInfo.selectedLine) self.msg(extractInfo.markerLine) if show_parent: if not parentInfo: parentInfo, p = deparsed.extract_parent_info( nodeInfo.node) if parentInfo: self.section("Contained in...") self.rst_msg("\t*Grammar Symbol:* %s" % p.kind) self.print_text(parentInfo.selectedLine) self.msg(parentInfo.markerLine) pass pass pass elif last_i == -1: if name: self.msg("At beginning of %s " % name) elif self.core.filename(None): self.msg("At beginning of program %s" % self.core.filename(None)) else: self.msg("At beginning") else: self.errmsg( "haven't recorded info for offset %d. Offsets I know are:" % last_i) m = self.columnize_commands( list(sorted(deparsed.offsets.keys(), key=lambda x: str(x[0])))) self.msg_nocr(m) return
def test_basic(self): filename = __file__ if '.pyc' == filename[-4:]: filename = filename[:-1] pass fp = open(filename, 'r') compare_lines = fp.readlines() self.assertTrue( compare_lines, "Should have been able to read %s for comparing" % filename) fp.close() # Test getlines to read this file. lines = pyficache.getlines(__file__) self.assertEqual( compare_lines, lines, 'We should get exactly the same lines as ' 'reading this file.') # Test getline to read this file. The file should now be cached, # so internally a different set of routines are used. test_line = 2 line = pyficache.getline(__file__, test_line, {'strip_nl': False}) self.assertEqual( compare_lines[test_line - 1], line, 'We should get exactly the same line as reading ' 'this file.') line = pyficache.getline(__file__, test_line, {'output': 'light'}) self.assertTrue( line.index('Unit test for pyficache') > 0, 'Terminal formatted line 2 should have ' '"Unit test for pyficache"') # Test getting the line via a relative file name old_dir = os.getcwd() os.chdir(os.path.dirname(os.path.abspath((__file__)))) short_file = os.path.basename(__file__) test_line = 10 line = pyficache.getline(short_file, test_line, {'strip_nl': False}) self.assertEqual( compare_lines[test_line - 1], line, 'Short filename lookup on %s should work' % short_file) os.chdir(old_dir) # Write a temporary file; read contents, rewrite it and check that # we get a change when calling getline. (fd, path) = mkstemp(prefix="pyfcache", suffix='.txt') test_string = "Now is the time.\n" with open(path, 'w') as f: f.write(test_string) f.close() pass line = pyficache.getline(path, 1, {'strip_nl': False}) self.assertEqual( test_string, line, "C'mon - a simple line test like this worked " "before.") with open(path, 'w') as f: test_string = "Now is another time." f.write(test_string) f.close() pass pyficache.checkcache() line = pyficache.getline(path, 1) self.assertEqual(test_string, line, "checkcache should have reread the temporary file.") try: os.remove(path) except: pass return
def run(self, args): if sys.version_info[:2] > (3, 8): self.errmsg("Deparsing for Python greater than 3.8 not impemented") return co = self.proc.curframe.f_code name = co.co_name try: opts, args = getopt( args[1:], "hpPto:O", ["help", "parent", "pretty", "tree", "offset=", "offsets"], ) except GetoptError as err: # print help information and exit: self.errmsg(str( err)) # will print something like "option -a not recognized" return show_parent = False show_tree = False offset = None show_offsets = False for o, a in opts: if o in ("-h", "--help"): self.proc.commands["help"].run(["help", "deparse"]) return elif o in ("-O", "--offsets"): show_offsets = True elif o in ("-p", "--parent"): show_parent = True elif o in ( "-t", "--tree", ): show_tree = True elif o in ("-o", "--offset"): offset = a else: self.errmsg("unhandled option '%s'" % o) pass pass nodeInfo = None if len(args) >= 1 and args[0] == ".": temp_filename, name_for_code = deparse_and_cache( co, self.errmsg, tempdir=self.settings["tempdir"]) if not temp_filename: return self.print_text("".join(getlines(temp_filename))) return elif show_offsets: deparsed = code_deparse(co) self.section("Offsets known:") m = self.columnize_commands( list(sorted(deparsed.offsets.keys(), key=lambda x: str(x[0])))) self.msg_nocr(m) return elif offset is not None: mess = ("The 'deparse' command when given an argument requires an" " instruction offset. Got: '%s'" % offset) last_i = self.proc.get_an_int(offset, mess) if last_i is None: return else: last_i = self.proc.curframe.f_lasti if last_i == -1: last_i = 0 deparsed, nodeInfo = deparse_offset(co, name, last_i, self.errmsg) if not deparsed: return if nodeInfo: extractInfo = deparsed.extract_node_info(nodeInfo) parentInfo = None # print extractInfo if show_tree: p = deparsed.ast if show_parent: parentInfo, p = deparsed.extract_parent_info(nodeInfo.node) self.msg(p) if extractInfo: self.rst_msg("*instruction:* %s" % (nodeInfo.node)) self.print_text(extractInfo.selectedLine) self.msg(extractInfo.markerLine) if show_parent: if not parentInfo: parentInfo, p = deparsed.extract_parent_info( nodeInfo.node) if parentInfo: self.section("Contained in...") self.rst_msg("\t*Grammar Symbol:* %s" % p.kind) self.print_text(parentInfo.selectedLine) self.msg(parentInfo.markerLine) pass pass pass elif last_i == -1: if name: self.msg("At beginning of %s " % name) elif self.core.filename(None): self.msg("At beginning of program %s" % self.core.filename(None)) else: self.msg("At beginning") else: self.errmsg( "haven't recorded info for offset %d. Offsets I know are:" % last_i) offsets = [ key[1] for key in deparsed.offsets.keys() if isinstance(key[1], int) ] m = self.columnize_commands(list(sorted(offsets))) self.msg_nocr(m) return