def _get_target_directory(self): if self._should_install_to_site_packages(): return normpath_with_actual_case(self._backend_proxy.get_site_packages()) else: usp = self._backend_proxy.get_user_site_packages() os.makedirs(usp, exist_ok=True) return normpath_with_actual_case(usp)
def _create_venv(self): path = askdirectory( parent=self.winfo_toplevel(), initialdir=None, title=tr( "Select an existing virtual environemnt or an empty directory for new virtual environment" ), ) assert os.path.isdir(path) path = normpath_with_actual_case(path) if not os.listdir(path): proc = subprocess.Popen( [running.get_interpreter_for_subprocess(), "-m", "venv", path], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ) dlg = SubprocessDialog(self, proc, tr("Creating virtual environment")) ui_utils.show_dialog(dlg) if running_on_windows(): exe_path = normpath_with_actual_case( os.path.join(path, "Scripts", "python.exe")) else: exe_path = os.path.join(path, "bin", "python3") if os.path.exists(exe_path): self._configuration_variable.set(exe_path) else: # Undefined error handling. pass
def _get_target_directory(self): if self._targets_virtual_environment(): return normpath_with_actual_case( self._backend_proxy.get_site_packages()) else: usp = self._backend_proxy.get_user_site_packages() os.makedirs(usp, exist_ok=True) return normpath_with_actual_case(usp)
def _create_venv(self, event=None): if not _check_venv_installed(self): return messagebox.showinfo( "Creating new virtual environment", "After clicking 'OK' you need to choose an empty directory, " "which will be the root of your new virtual environment.", parent=self, ) path = None while True: path = askdirectory( parent=self.winfo_toplevel(), initialdir=path, title=tr("Select empty directory for new virtual environment"), ) if not path: return if os.listdir(path): messagebox.showerror( tr("Bad directory"), tr("Selected directory is not empty.\nSelect another or cancel." ), master=self, ) else: break assert os.path.isdir(path) path = normpath_with_actual_case(path) proc = subprocess.Popen( [running.get_interpreter_for_subprocess(), "-m", "venv", path], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ) from thonny.workdlg import SubprocessDialog dlg = SubprocessDialog(self, proc, tr("Creating virtual environment"), autostart=True) ui_utils.show_dialog(dlg) if running_on_windows(): exe_path = normpath_with_actual_case( os.path.join(path, "Scripts", "python.exe")) else: exe_path = os.path.join(path, "bin", "python3") if os.path.exists(exe_path): self._configuration_variable.set(exe_path)
def _get_target_directory(self): if self._use_user_install(): import site assert hasattr(site, "getusersitepackages") os.makedirs(site.getusersitepackages(), exist_ok=True) return normpath_with_actual_case(site.getusersitepackages()) else: for d in sys.path: if ("site-packages" in d or "dist-packages" in d) and path_startswith(d, sys.prefix): return normpath_with_actual_case(d) return None
def _is_read_only_package(self, name): dist = self._get_active_dist(name) if dist is None: return False else: return (normpath_with_actual_case(dist["location"]) != self._get_target_directory())
def execute_current(self, command_name: str) -> None: """ This method's job is to create a command for running/debugging current file/script and submit it to shell """ if not self.is_waiting_toplevel_command(): self.restart_backend(False, False, 2) filename = get_saved_current_script_filename() if not filename: # cancel must have been pushed return # changing dir may be required script_dir = normpath_with_actual_case(os.path.dirname(filename)) if get_workbench().get_option( "run.auto_cd") and command_name[0].isupper(): working_directory = script_dir # type: Optional[str] else: working_directory = None args = self._get_active_arguments() self.execute_script(filename, args, working_directory, command_name)
def request_focus_into(self, path): if path == "": if running_on_windows(): # list of drives, can't cd self.focus_into(path) return else: path = "/" if not os.path.isdir(path): return proxy = get_runner().get_backend_proxy() if ( proxy and proxy.uses_local_filesystem() and proxy.get_cwd() != path and get_runner().is_waiting_toplevel_command() ): get_shell().submit_magic_command(construct_cd_command(normpath_with_actual_case(path))) else: # it's OK, if it's already focused into this directory # focus again to refresh self.focus_into(path) get_workbench().set_local_cwd(path)
def ask_new_local_path(self): if self._filename is None: initialdir = get_workbench().get_local_cwd() initialfile = None else: initialdir = os.path.dirname(self._filename) initialfile = os.path.basename(self._filename) # http://tkinter.unpythonic.net/wiki/tkFileDialog new_filename = asksaveasfilename( filetypes=_dialog_filetypes, defaultextension=".py", initialdir=initialdir, initialfile=initialfile, ) # Different tkinter versions may return different values if new_filename in ["", (), None]: return None # Seems that in some Python versions defaultextension # acts funny if new_filename.lower().endswith(".py.py"): new_filename = new_filename[:-3] if running_on_windows(): # may have /-s instead of \-s and wrong case new_filename = os.path.join( normpath_with_actual_case(os.path.dirname(new_filename)), os.path.basename(new_filename), ) if new_filename.endswith(".py"): base = os.path.basename(new_filename) mod_name = base[:-3].lower() if running_on_windows(): mod_name = mod_name.lower() if mod_name in [ "math", "turtle", "random", "statistics", "pygame", "matplotlib", "numpy", ]: # More proper name analysis will be performed by ProgramNamingAnalyzer if not tk.messagebox.askyesno( "Potential problem", "If you name your script '%s', " % base + "you won't be able to import the library module named '%s'" % mod_name + ".\n\n" + "Do you still want to use this name for your script?", ): return self.ask_new_local_path() return new_filename
def load_plugin() -> None: get_workbench().set_default( "file.last_browser_folder", normpath_with_actual_case(os.path.expanduser("~")) ) get_workbench().set_default(HIDDEN_FILES_OPTION, False) get_workbench().add_view(FilesView, tr("Files"), "nw") for ext in [".py", ".pyw", ".pyi", ".txt", ".log", ".json", ".yml", ".yaml", ".md", ".rst"]: get_workbench().set_default(get_file_handler_conf_key(ext), "thonny")
def _create_venv(self): path = None while True: path = askdirectory( master=self, initialdir=path, title=_("Select empty directory for new virtual environment"), ) if not path: return if os.listdir(path): messagebox.showerror( _("Bad directory"), _("Selected directory is not empty.\nSelect another or cancel." ), parent=get_workbench(), ) else: break assert os.path.isdir(path) path = normpath_with_actual_case(path) proc = subprocess.Popen( [running.get_frontend_python(), "-m", "venv", path], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ) dlg = SubprocessDialog(self, proc, _("Creating virtual environment")) ui_utils.show_dialog(dlg) if running_on_windows(): exe_path = normpath_with_actual_case( os.path.join(path, "Scripts", "python.exe")) else: exe_path = os.path.join(path, "bin", "python3") if os.path.exists(exe_path): self._configuration_variable.set(exe_path)
def get_editor(self, filename, open_when_necessary=False): if not is_remote_path(filename) and os.path.isfile(filename): filename = normpath_with_actual_case(os.path.abspath(filename)) for child in self.winfo_children(): child_filename = child.get_filename(False) if child_filename == filename: return child if open_when_necessary: return self._open_file(filename) else: return None
def get_editor(self, filename_or_id, open_when_necessary=False): if os.path.isfile(filename_or_id): filename_or_id = normpath_with_actual_case(os.path.abspath(filename_or_id)) for child in self.winfo_children(): assert isinstance(child, Editor) child_identifier = child.get_identifier() if child_identifier == filename_or_id: return child if open_when_necessary: return self._open_file(filename_or_id) else: return None
def _load_local_file(self, filename, keep_undo=False): with open(filename, "rb") as fp: source = fp.read() # Make sure Windows filenames have proper format filename = normpath_with_actual_case(filename) self._filename = filename self._last_known_mtime = os.path.getmtime(self._filename) get_workbench().event_generate("Open", editor=self, filename=filename) self._code_view.set_content_as_bytes(source, keep_undo) self.get_text_widget().edit_modified(False) self._code_view.focus_set() self.master.remember_recent_file(filename)
def _start_show_package_info(self, name): self.current_package_data = None # Fetch info from PyPI self._set_state("fetching") # Follwing fetches info about latest version. # This is OK even when we're looking an installed older version # because new version may have more relevant and complete info. _start_fetching_package_info(name, None, self._show_package_info) self.info_text.direct_delete("1.0", "end") self.name_label["text"] = "" self.name_label.grid() self.command_frame.grid() active_dist = self._get_active_dist(name) if active_dist is not None: self.name_label["text"] = active_dist["project_name"] self.info_text.direct_insert("end", _("Installed version:") + " ", ("caption", )) self.info_text.direct_insert("end", active_dist["version"] + "\n") self.info_text.direct_insert("end", _("Installed to:") + " ", ("caption", )) self.info_text.direct_insert( "end", normpath_with_actual_case(active_dist["location"]), ("url", )) self.info_text.direct_insert("end", "\n\n") self._select_list_item(name) else: self._select_list_item(0) # update gui if self._is_read_only_package(name): self.install_button.grid_remove() self.uninstall_button.grid_remove() self.advanced_button.grid_remove() else: self.install_button.grid(row=0, column=0) self.advanced_button.grid(row=0, column=2) if active_dist is not None: # existing package in target directory self.install_button["text"] = _("Upgrade") self.install_button["state"] = "disabled" self.uninstall_button.grid(row=0, column=1) else: # new package self.install_button["text"] = _("Install") self.uninstall_button.grid_remove()
def _load_local_file(self, filename, keep_undo=False): with tokenize.open(filename) as fp: # TODO: support also text files source = fp.read() # get the file file format (DOS/UNIX) self._newlines = fp.newlines # Make sure Windows filenames have proper format filename = normpath_with_actual_case(filename) self._filename = filename self._last_known_mtime = os.path.getmtime(self._filename) get_workbench().event_generate("Open", editor=self, filename=filename) self._code_view.set_content(source, keep_undo) self.get_text_widget().edit_modified(False) self._code_view.focus_set() self.master.remember_recent_file(filename)
def _get_interpreters(): result = set() if running_on_windows(): # registry result.update(_get_interpreters_from_windows_registry()) for minor in [6, 7, 8, 9]: for dir_ in [ "C:\\Python3%d" % minor, "C:\\Python3%d-32" % minor, "C:\\Python3%d-64" % minor, "C:\\Program Files\\Python 3.%d" % minor, "C:\\Program Files\\Python 3.%d-64" % minor, "C:\\Program Files (x86)\\Python 3.%d" % minor, "C:\\Program Files (x86)\\Python 3.%d-32" % minor, "C:\\Program Files (x86)\\Python 3.%d-32" % minor, os.path.expanduser( "~\\AppData\Local\Programs\Python\Python3%d" % minor), os.path.expanduser( "~\\AppData\Local\Programs\Python\Python3%d-32" % minor), ]: path = os.path.join(dir_, WINDOWS_EXE) if os.path.exists(path): result.add(normpath_with_actual_case(path)) # other locations for dir_ in [ "C:\\Anaconda3", "C:\\ProgramData\\Anaconda3", os.path.expanduser("~\\Anaconda3"), ]: path = os.path.join(dir_, WINDOWS_EXE) if os.path.exists(path): result.add(normpath_with_actual_case(path)) else: # Common unix locations dirs = [ "/bin", "/usr/bin", "/usr/local/bin", os.path.expanduser("~/.local/bin"), os.path.expanduser("~/anaconda3/bin"), ] for dir_ in dirs: # if the dir_ is just a link to another dir_, skip it # (not to show items twice) # for example on Fedora /bin -> usr/bin if not os.path.exists(dir_): continue apath = normpath_with_actual_case(dir_) if apath != dir_ and apath in dirs: continue for name in [ "python3", "python3.5", "python3.6", "python3.7", "python3.8" ]: path = os.path.join(dir_, name) if os.path.exists(path): result.add(path) if running_on_mac_os(): for version in ["3.6", "3.7", "3.8", "3.9"]: dir_ = os.path.join( "/Library/Frameworks/Python.framework/Versions", version, "bin") path = os.path.join(dir_, "python3") if os.path.exists(path): result.add(path) from shutil import which for command in [ "python3", "python3.6", "python3.7", "python3.8", "python3.9" ]: path = which(command) if path is not None and os.path.isabs(path): result.add(path) for path in get_workbench().get_option("CustomInterpreter.used_paths"): if os.path.exists(path): result.add(normpath_with_actual_case(path)) return sorted(result)
def load_plugin() -> None: get_workbench().set_default( "file.last_browser_folder", normpath_with_actual_case(os.path.expanduser("~"))) get_workbench().add_view(FilesView, _("Files"), "nw")
def ask_new_local_path(self): if self._filename is None: initialdir = get_workbench().get_local_cwd() initialfile = None else: initialdir = os.path.dirname(self._filename) initialfile = os.path.basename(self._filename) # https://tcl.tk/man/tcl8.6/TkCmd/getOpenFile.htm type_var = tk.StringVar(value="") new_filename = asksaveasfilename( filetypes=_dialog_filetypes, defaultextension=None, initialdir=initialdir, initialfile=initialfile, parent=get_workbench(), typevariable=type_var, ) logger.info("Save dialog returned %r with typevariable %r", new_filename, type_var.get()) # Different tkinter versions may return different values if new_filename in ["", (), None]: return None if running_on_windows(): # may have /-s instead of \-s and wrong case new_filename = os.path.join( normpath_with_actual_case(os.path.dirname(new_filename)), os.path.basename(new_filename), ) if type_var.get() == PYTHON_FILES_STR or type_var.get() == "": new_filename = self._check_add_py_extension( new_filename, without_asking=type_var.get() == PYTHON_FILES_STR ) if new_filename.endswith(".py"): base = os.path.basename(new_filename) mod_name = base[:-3].lower() if running_on_windows(): mod_name = mod_name.lower() if mod_name in [ "math", "turtle", "random", "statistics", "pygame", "matplotlib", "numpy", ]: # More proper name analysis will be performed by ProgramNamingAnalyzer if not tk.messagebox.askyesno( "Potential problem", "If you name your script '%s', " % base + "you won't be able to import the library module named '%s'" % mod_name + ".\n\n" + "Do you still want to use this name for your script?", master=self, ): return self.ask_new_local_path() return new_filename
def save_file(self, ask_filename=False): if self._filename is not None and not ask_filename: get_workbench().event_generate("Save", editor=self, filename=self._filename) else: # http://tkinter.unpythonic.net/wiki/tkFileDialog new_filename = asksaveasfilename( master=get_workbench(), filetypes=_dialog_filetypes, defaultextension=".py", initialdir=get_workbench().get_cwd(), ) # Different tkinter versions may return different values if new_filename in [ "", (), None, ]: return None # Seems that in some Python versions defaultextension # acts funny if new_filename.lower().endswith(".py.py"): new_filename = new_filename[:-3] if running_on_windows(): # may have /-s instead of \-s and wrong case new_filename = os.path.join( normpath_with_actual_case(os.path.dirname(new_filename)), os.path.basename(new_filename)) if new_filename.endswith(".py"): base = os.path.basename(new_filename) mod_name = base[:-3].lower() if running_on_windows(): mod_name = mod_name.lower() if mod_name in [ "math", "turtle", "random", "statistics", "pygame", "matplotlib", "numpy", ]: # More proper name analysis will be performed by ProgramNamingAnalyzer if not tk.messagebox.askyesno( "Potential problem", "If you name your script '%s', " % base + "you won't be able to import the library module named '%s'" % mod_name + ".\n\n" + "Do you still want to use this name for your script?", parent=get_workbench(), ): return self.save_file(ask_filename) self._filename = new_filename get_workbench().event_generate("SaveAs", editor=self, filename=new_filename) content = self._code_view.get_content_as_bytes() try: f = open(self._filename, mode="wb") f.write(content) f.flush() # Force writes on disk, see https://learn.adafruit.com/adafruit-circuit-playground-express/creating-and-editing-code#1-use-an-editor-that-writes-out-the-file-completely-when-you-save-it os.fsync(f) f.close() self._last_known_mtime = os.path.getmtime(self._filename) except PermissionError: if askyesno( "Permission Error", "Looks like this file or folder is not writable.\n\n" + "Do you want to save under another folder and/or filename?", parent=get_workbench(), ): return self.save_file(True) else: return None self.master.remember_recent_file(self._filename) self._code_view.text.edit_modified(False) return self._filename
def construct_cd_command(path): return construct_cmd_line(["%cd", normpath_with_actual_case(path)])