def is_python_interpreter(filename): """Evaluate wether a file is a python interpreter or not.""" real_filename = os.path.realpath(filename) # To follow symlink if existent if (not osp.isfile(real_filename) or not is_python_interpreter_valid_name(filename)): return False elif is_pythonw(filename): if os.name == 'nt': # pythonw is a binary on Windows if not encoding.is_text_file(real_filename): return True else: return False elif sys.platform == 'darwin': # pythonw is a text file in Anaconda but a binary in # the system if is_anaconda() and encoding.is_text_file(real_filename): return True elif not encoding.is_text_file(real_filename): return True else: return False else: # There's no pythonw in other systems return False elif encoding.is_text_file(real_filename): # At this point we can't have a text file return False else: return check_python_help(filename)
def open(self, fnames=None): """Open files with the appropriate application""" if fnames is None: fnames = self.get_selected_filenames() for fname in fnames: if osp.isfile(fname) and encoding.is_text_file(fname): self.parent_widget.sig_open_file.emit(fname) else: self.open_outside_spyder([fname])
def is_python_interpreter(filename): """Evaluate wether a file is a python interpreter or not.""" real_filename = os.path.realpath(filename) # To follow symlink if existent if (not osp.isfile(real_filename) or encoding.is_text_file(real_filename) or not is_python_interpreter_valid_name(filename)): return False try: proc = run_program(filename, ["-h"]) output = to_text_string(proc.communicate()[0]) valid = ("Options and arguments (and corresponding environment " "variables)") if 'usage:' in output and valid in output: return True else: return False except: return False
def find_files_in_path(self, path): if self.pathlist is None: self.pathlist = [] self.pathlist.append(path) for path, dirs, files in os.walk(path): with QMutexLocker(self.mutex): if self.stopped: return False try: for d in dirs[:]: dirname = os.path.join(path, d) if re.search(self.exclude, dirname + os.sep): dirs.remove(d) for f in files: filename = os.path.join(path, f) if re.search(self.exclude, filename): continue if is_text_file(filename): self.find_string_in_file(filename) except re.error: self.error_flag = _("invalid regular expression") return False return True
def test_is_text_file(tmpdir): p = tmpdir.mkdir("sub").join("random_text.txt") p.write("Some random text") assert is_text_file(str(p)) == True
def browse(self, fpath=None): """Prompt user to select an application not found on the list.""" app = None item = None if sys.platform == 'darwin': if fpath is None: basedir = '/Applications/' filters = _('Applications (*.app)') title = _('Select application') fpath, __ = getopenfilename(self, title, basedir, filters) if fpath and fpath.endswith('.app') and os.path.isdir(fpath): app = os.path.basename(fpath).split('.app')[0] for row in range(self.list.count()): item = self.list.item(row) if app == item.text() and fpath == item.fpath: break else: item = None elif os.name == 'nt': if fpath is None: basedir = 'C:\\' filters = _('Applications (*.exe *.bat *.com)') title = _('Select application') fpath, __ = getopenfilename(self, title, basedir, filters) if fpath: check_1 = fpath.endswith('.bat') and is_text_file(fpath) check_2 = (fpath.endswith(('.exe', '.com')) and not is_text_file(fpath)) if check_1 or check_2: app = os.path.basename(fpath).capitalize().rsplit('.')[0] for row in range(self.list.count()): item = self.list.item(row) if app == item.text() and fpath == item.fpath: break else: item = None else: if fpath is None: basedir = '/' filters = _('Applications (*.desktop)') title = _('Select application') fpath, __ = getopenfilename(self, title, basedir, filters) if fpath and fpath.endswith(('.desktop')) and is_text_file(fpath): entry_data = parse_linux_desktop_entry(fpath) app = entry_data['name'] for row in range(self.list.count()): item = self.list.item(row) if app == item.text() and fpath == item.fpath: break else: item = None if fpath: if item: self.list.setCurrentItem(item) elif app: icon = get_application_icon(fpath) item = QListWidgetItem(icon, app) item.fpath = fpath self.list.addItem(item) self.list.setCurrentItem(item) self.list.setFocus() self._refresh()
def get_icon_by_extension_or_type(fname, scale_factor): """Return the icon depending on the file extension""" application_icons = {} application_icons.update(BIN_FILES) application_icons.update(DOCUMENT_FILES) if osp.isdir(fname): return icon('DirOpenIcon', scale_factor) else: basename = osp.basename(fname) __, extension = osp.splitext(basename.lower()) mime_type, __ = mime.guess_type(basename) if is_dark_interface(): icon_by_extension = QIcon(get_image_path('binary.svg')) else: icon_by_extension = QIcon(get_image_path('binary_light.svg')) if extension in OFFICE_FILES: icon_by_extension = icon(OFFICE_FILES[extension], scale_factor) elif extension in LANGUAGE_ICONS: icon_by_extension = icon(LANGUAGE_ICONS[extension], scale_factor) else: if extension == '.ipynb': if is_dark_interface(): icon_by_extension = QIcon( get_image_path('notebook_dark.svg')) else: icon_by_extension = QIcon( get_image_path('notebook_light.svg')) elif extension == '.tex': if is_dark_interface(): icon_by_extension = QIcon( get_image_path('file_type_tex.svg')) else: icon_by_extension = QIcon( get_image_path('file_type_light_tex.svg')) elif is_text_file(fname): icon_by_extension = icon('TextFileIcon', scale_factor) elif mime_type is not None: try: # Fix for spyder-ide/spyder#5080. Even though # mimetypes.guess_type documentation states that # the return value will be None or a tuple of # the form type/subtype, in the Windows registry, # .sql has a mimetype of text\plain # instead of text/plain therefore mimetypes is # returning it incorrectly. file_type, bin_name = mime_type.split('/') except ValueError: file_type = None if file_type is None: if is_dark_interface(): icon_by_extension = QIcon(get_image_path('binary.svg')) else: icon_by_extension = QIcon( get_image_path('binary_light.svg')) elif file_type == 'audio': icon_by_extension = icon('AudioFileIcon', scale_factor) elif file_type == 'video': icon_by_extension = icon('VideoFileIcon', scale_factor) elif file_type == 'image': icon_by_extension = icon('ImageFileIcon', scale_factor) elif file_type == 'application': if bin_name in application_icons: icon_by_extension = icon(application_icons[bin_name], scale_factor) return icon_by_extension
def find_files_in_path(self, path): if self.pathlist is None: self.pathlist = [] self.pathlist.append(path) for path, dirs, files in os.walk(path): with QMutexLocker(self.mutex): if self.stopped: return False try: # For directories for d in dirs[:]: with QMutexLocker(self.mutex): if self.stopped: return False dirname = os.path.join(path, d) # Only search in regular directories st_dir_mode = os.stat(dirname).st_mode if not stat.S_ISDIR(st_dir_mode): dirs.remove(d) if (self.exclude and re.search(self.exclude, dirname + os.sep)): # Exclude patterns defined by the user dirs.remove(d) elif d.startswith('.'): # Exclude all dot dirs. dirs.remove(d) # For files for f in files: with QMutexLocker(self.mutex): if self.stopped: return False filename = os.path.join(path, f) ext = osp.splitext(filename)[1] # Only search in regular files (i.e. not pipes) st_file_mode = os.stat(filename).st_mode if not stat.S_ISREG(st_file_mode): continue # Exclude patterns defined by the user if self.exclude and re.search(self.exclude, filename): continue # Don't search in plain text files with skipped extensions # (e.g .svg) if ext in self.SKIPPED_EXTENSIONS: continue # It's much faster to check for extension first before # validating if the file is plain text. if (ext in self.PYTHON_EXTENSIONS or ext in self.USEFUL_EXTENSIONS or is_text_file(filename)): self.find_string_in_file(filename) except re.error: self.error_flag = _("invalid regular expression") return False # Process any pending results if self.partial_results: self.process_results() return True
def get_icon_by_extension_or_type(self, fname, scale_factor): """Return the icon depending on the file extension""" application_icons = {} application_icons.update(self.BIN_FILES) application_icons.update(self.DOCUMENT_FILES) basename = osp.basename(fname) __, extension = osp.splitext(basename.lower()) mime_type, __ = mime.guess_type(basename) if osp.isdir(fname): extension = "Folder" if (extension, scale_factor) in self.ICONS_BY_EXTENSION: return self.ICONS_BY_EXTENSION[(extension, scale_factor)] if osp.isdir(fname): icon_by_extension = self.icon('DirOpenIcon', scale_factor) else: icon_by_extension = self.icon('binary') if extension in self.OFFICE_FILES: icon_by_extension = self.icon(self.OFFICE_FILES[extension], scale_factor) elif extension in self.LANGUAGE_ICONS: icon_by_extension = self.icon(self.LANGUAGE_ICONS[extension], scale_factor) else: if extension == '.ipynb': icon_by_extension = self.icon('notebook') elif extension == '.tex': icon_by_extension = self.icon('file_type_tex') elif is_text_file(fname): icon_by_extension = self.icon('TextFileIcon', scale_factor) elif mime_type is not None: try: # Fix for spyder-ide/spyder#5080. Even though # mimetypes.guess_type documentation states that # the return value will be None or a tuple of # the form type/subtype, in the Windows registry, # .sql has a mimetype of text\plain # instead of text/plain therefore mimetypes is # returning it incorrectly. file_type, bin_name = mime_type.split('/') except ValueError: file_type = None if file_type is None: icon_by_extension = self.icon('binary') elif file_type == 'audio': icon_by_extension = self.icon('AudioFileIcon', scale_factor) elif file_type == 'video': icon_by_extension = self.icon('VideoFileIcon', scale_factor) elif file_type == 'image': icon_by_extension = self.icon('ImageFileIcon', scale_factor) elif file_type == 'application': if bin_name in application_icons: icon_by_extension = self.icon( application_icons[bin_name], scale_factor) self.ICONS_BY_EXTENSION[(extension, scale_factor)] = icon_by_extension return icon_by_extension
def create_file_manage_actions(self, fnames): """Return file management actions""" only_files = all([osp.isfile(_fn) for _fn in fnames]) only_modules = all([ osp.splitext(_fn)[1] in ('.py', '.pyw', '.ipy') for _fn in fnames ]) only_notebooks = all( [osp.splitext(_fn)[1] == '.ipynb' for _fn in fnames]) only_valid = all([encoding.is_text_file(_fn) for _fn in fnames]) run_action = create_action(self, _("Run"), icon=ima.icon('run'), triggered=self.run) edit_action = create_action(self, _("Edit"), icon=ima.icon('edit'), triggered=self.clicked) move_action = create_action(self, _("Move..."), icon="move.png", triggered=self.move) delete_action = create_action(self, _("Delete..."), icon=ima.icon('editdelete'), triggered=self.delete) rename_action = create_action(self, _("Rename..."), icon=ima.icon('rename'), triggered=self.rename) open_action = create_action(self, _("Open"), triggered=self.open) ipynb_convert_action = create_action(self, _("Convert to Python script"), icon=ima.icon('python'), triggered=self.convert_notebooks) actions = [] if only_modules: actions.append(run_action) if only_valid and only_files: actions.append(edit_action) else: actions.append(open_action) actions += [delete_action, rename_action] basedir = fixpath(osp.dirname(fnames[0])) if all([fixpath(osp.dirname(_fn)) == basedir for _fn in fnames]): actions.append(move_action) actions += [None] if only_notebooks and nbexporter is not None: actions.append(ipynb_convert_action) # VCS support is quite limited for now, so we are enabling the VCS # related actions only when a single file/folder is selected: dirname = fnames[0] if osp.isdir(fnames[0]) else osp.dirname(fnames[0]) if len(fnames) == 1 and vcs.is_vcs_repository(dirname): # QAction.triggered works differently for PySide and PyQt if not API == 'pyside': commit_slot = lambda _checked, fnames=[dirname]:\ self.vcs_command(fnames, 'commit') browse_slot = lambda _checked, fnames=[dirname]:\ self.vcs_command(fnames, 'browse') else: commit_slot = lambda fnames=[dirname]:\ self.vcs_command(fnames, 'commit') browse_slot = lambda fnames=[dirname]:\ self.vcs_command(fnames, 'browse') vcs_ci = create_action(self, _("Commit"), icon=ima.icon('vcs_commit'), triggered=commit_slot) vcs_log = create_action(self, _("Browse repository"), icon=ima.icon('vcs_browse'), triggered=browse_slot) actions += [None, vcs_ci, vcs_log] return actions
def create_file_manage_actions(self, fnames): """Return file management actions""" only_files = all([osp.isfile(_fn) for _fn in fnames]) only_modules = all([osp.splitext(_fn)[1] in ('.py', '.pyw', '.ipy') for _fn in fnames]) only_notebooks = all([osp.splitext(_fn)[1] == '.ipynb' for _fn in fnames]) only_valid = all([encoding.is_text_file(_fn) for _fn in fnames]) run_action = create_action(self, _("Run"), icon=ima.icon('run'), triggered=self.run) edit_action = create_action(self, _("Edit"), icon=ima.icon('edit'), triggered=self.clicked) move_action = create_action(self, _("Move..."), icon="move.png", triggered=self.move) delete_action = create_action(self, _("Delete..."), icon=ima.icon('editdelete'), triggered=self.delete) rename_action = create_action(self, _("Rename..."), icon=ima.icon('rename'), triggered=self.rename) open_action = create_action(self, _("Open"), triggered=self.open) ipynb_convert_action = create_action(self, _("Convert to Python script"), icon=ima.icon('python'), triggered=self.convert_notebooks) actions = [] if only_modules: actions.append(run_action) if only_valid and only_files: actions.append(edit_action) else: actions.append(open_action) actions += [delete_action, rename_action] basedir = fixpath(osp.dirname(fnames[0])) if all([fixpath(osp.dirname(_fn)) == basedir for _fn in fnames]): actions.append(move_action) actions += [None] if only_notebooks and nbexporter is not None: actions.append(ipynb_convert_action) # VCS support is quite limited for now, so we are enabling the VCS # related actions only when a single file/folder is selected: dirname = fnames[0] if osp.isdir(fnames[0]) else osp.dirname(fnames[0]) if len(fnames) == 1 and vcs.is_vcs_repository(dirname): # QAction.triggered works differently for PySide and PyQt if not API == 'pyside': commit_slot = lambda _checked, fnames=[dirname]:\ self.vcs_command(fnames, 'commit') browse_slot = lambda _checked, fnames=[dirname]:\ self.vcs_command(fnames, 'browse') else: commit_slot = lambda fnames=[dirname]:\ self.vcs_command(fnames, 'commit') browse_slot = lambda fnames=[dirname]:\ self.vcs_command(fnames, 'browse') vcs_ci = create_action(self, _("Commit"), icon=ima.icon('vcs_commit'), triggered=commit_slot) vcs_log = create_action(self, _("Browse repository"), icon=ima.icon('vcs_browse'), triggered=browse_slot) actions += [None, vcs_ci, vcs_log] return actions