├── .gitignore ├── Default.sublime-commands ├── LICENSE ├── Main.sublime-menu ├── Python + Virtualenv.sublime-build ├── README.md ├── Virtualenv (Windows).sublime-settings ├── Virtualenv.sublime-settings ├── commands.py ├── integrations.py ├── messages.json ├── messages ├── install.txt ├── v1.1.0.txt └── v1.1.2.txt └── virtualenv_lib.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Editor files 2 | ~* 3 | *.sublime-project 4 | *.sublime-workspace 5 | 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | env/ 16 | bin/ 17 | build/ 18 | develop-eggs/ 19 | dist/ 20 | eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | 30 | # Installer logs 31 | pip-log.txt 32 | pip-delete-this-directory.txt 33 | 34 | # Unit test / coverage reports 35 | htmlcov/ 36 | .tox/ 37 | .coverage 38 | .cache 39 | nosetests.xml 40 | coverage.xml 41 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "Virtualenv: New", "command": "new_virtualenv" }, 3 | { "caption": "Virtualenv: New (venv)", "command": "new_builtin_virtualenv" }, 4 | { "caption": "Virtualenv: Activate", "command": "activate_virtualenv" }, 5 | { "caption": "Virtualenv: Deactivate", "command": "deactivate_virtualenv" }, 6 | { "caption": "Virtualenv: Remove", "command": "remove_virtualenv" }, 7 | { "caption": "Virtualenv: Add directory", "command": "add_virtualenv_directory" }, 8 | 9 | { "caption": "Virtualenv: SublimeREPL - Python", "command": "current_virtualenv_repl" } 10 | ] 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Adrián López Calvo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [{ 2 | "caption": "Preferences", 3 | "id": "preferences", 4 | "mnemonic": "n", 5 | "children": [{ 6 | "caption": "Package Settings", 7 | "id": "package-settings", 8 | "mnemonic": "P", 9 | "children": [{ 10 | "caption": "Virtualenv", 11 | "children": [ 12 | { 13 | "caption": "README", 14 | "command": "open_file", 15 | "args": { 16 | "file": "${packages}/Virtualenv/README.md" 17 | } 18 | }, 19 | { "caption": "-" }, 20 | { 21 | "caption": "Settings – Default", 22 | "command": "open_file", 23 | "args": { 24 | "file": "${packages}/Virtualenv/Virtualenv.sublime-settings" 25 | } 26 | }, 27 | { 28 | "caption": "Settings – User", 29 | "command": "open_file", 30 | "args": { 31 | "file": "${packages}/User/Virtualenv.sublime-settings" 32 | } 33 | } 34 | ] 35 | }] 36 | }] 37 | }] -------------------------------------------------------------------------------- /Python + Virtualenv.sublime-build: -------------------------------------------------------------------------------- 1 | { 2 | "target": "virtualenv_exec", 3 | "shell_cmd": "python -u \"$file\"", 4 | "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", 5 | "selector": "source.python" 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sublime Text - Virtualenv 2 | ========================= 3 | 4 | Manage your virtualenvs directly from Sublime Text __3__. 5 | 6 | ## Disclaimer: Not Maintained 7 | 8 | **I cannot maintain this project anymore since I stopped using Sublime Text. If you're interested on taking over reach out and we can discuss.** 9 | 10 | ## Features 11 | 12 | - __Reusable build system__. Execute code with a virtualenv without 13 | editing your paths manually. 14 | - __Virtualenv search__. Finds virtualenvs in the open folders or _anywhere_ in your system. 15 | - __Activation/Deactivation__. Select or disable the current virtualenv easily. 16 | - __Create and delete virtualenvs__. With target python selection. Supports both the standard 17 | [virtualenv][] package and the built-in [venv][pyvenv] module from Python 3.3. 18 | - __Integration with other packages__. SublimeREPL. 19 | 20 | 21 | ## Support 22 | 23 | Only Sublime Text 3. Tested in Linux and Windows but it should work in OS X as well. 24 | 25 | 26 | ## Installation 27 | 28 | Install through Package Control as usual: 29 | 30 | 1. Open command palette through the menu or with `Ctrl+Shift+P`. 31 | 2. Select `Package Control: Install Package`. 32 | 3. Search _Virtualenv_ and press enter. 33 | 34 | Detailed instructions [here][packageControl]. 35 | 36 | 37 | ## Usage 38 | 39 | #### Code Execution 40 | 41 | Enable the `Python + Virtualenv` build system through the `Tools -> Build System` menu and execute with `Ctrl+B`. If you do not have any other custom Python builds defined, `Automatic` should work too. 42 | 43 | The build system works with or without an activated virtualenv, so it can be used as default build for Python. 44 | 45 | #### Activate 46 | 47 | Search `Virtualenv: Activate` in the command palette and select the desired virtualenv. 48 | 49 | #### Deactivate 50 | 51 | The command `Virtualenv: Deactivate` is available when a virtualenv is activated. 52 | 53 | #### Creating a virtualenv 54 | 55 | Choose `Virtualenv: New` (or `Virtualenv: New (venv)` for built-in virtualenv), type a destination 56 | path and select a python binary. The new virtualenv will be activated automatically. 57 | 58 | #### Deleting a virtualenv 59 | 60 | Use the command `Virtualenv: Remove`, choose a virtualenv and confirm. 61 | 62 | #### Integrations 63 | 64 | Launch a Python REPL using the current virtualenv with the command `Virtualenv: SublimeREPL - Python`. 65 | 66 | 67 | ## Settings 68 | 69 | The list of default settings is available through `Preferences -> Package Settings -> Virtualenv -> Default`. Do not modify the default settings as you will lose all the changes if the package is updated. You should override the necessary settings in `Package Settings -> Virtualenv -> User` instead. 70 | 71 | #### executable 72 | 73 | The executable used for virtualenv creation. Defaults to `python -m virtualenv`, assuming that virtualenv is installed on the default python prefix. 74 | Depending on your setup you might want to change this to something like: `virtualenv`, `virtualenv-3.3`, `python3 -m virtualenv`, etc. 75 | 76 | #### virtualenv_directories 77 | 78 | A list of directory paths searched for virtualenvs. By default, includes [virtualenvwrapper][]'s `WORKON_HOME`. `~/.virtualenvs` in Linux and OS X, and `~\Envs` in Windows ([virtualenvwrapper-win][]). 79 | 80 | There is a shortcut command for quickly adding a virtualenv directory to your settings: `Virtualenv: Add directory`. 81 | 82 | #### extra_paths 83 | 84 | Additional paths searched for python binaries. It might be useful in case of portable python installations. Defaults to none. 85 | 86 | 87 | ## Advanced 88 | 89 | The current virtualenv path is stored in the project settings and can be edited manually if the project has been saved to a `*.sublime-project` file. 90 | 91 | Extending or customizing the build system should be possible. Just set `"target": "virtualenv_exec"` in your build system definition, or import and inherit from `Virtualenv.commands.VirtualenvExecCommand`. More information on Sublime Text's build systems [here][buildSystems]. 92 | 93 | 94 | ## Future plans 95 | 96 | Just some ideas for possible improvements. 97 | 98 | - Integration with more packages. Paths for [SublimeCodeIntel][]? 99 | - _Brother_ package for `pip` commands. 100 | 101 | 102 | 103 | 104 | [packageControl]: https://sublime.wbond.net/docs/usage "Package Control" 105 | [buildSystems]: http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/build_systems.html "Sublime Text build systems" 106 | [virtualenv]: https://virtualenv.pypa.io/en/latest/ "virtualenv" 107 | [virtualenvwrapper]: http://virtualenvwrapper.readthedocs.org/en/latest/ "virtualenvwrapper" 108 | [virtualenvwrapper-win]: https://github.com/davidmarble/virtualenvwrapper-win/ "virtualenvwrapper-win" 109 | [pyvenv]: https://docs.python.org/3.3/library/venv.html "pyvenv" 110 | [SublimeREPL]: https://github.com/wuub/SublimeREPL "SublimeREPL" 111 | [SublimeCodeIntel]: http://sublimecodeintel.github.io/SublimeCodeIntel/ "SublimeCodeIntel" 112 | -------------------------------------------------------------------------------- /Virtualenv (Windows).sublime-settings: -------------------------------------------------------------------------------- 1 | // Default settings for Virtualenv plugin in Windows systems: 2 | { 3 | // Directory paths searched for virtualenvs. 4 | // First one will be used as default destination for new virtualenvs. 5 | "virtualenv_directories": [ 6 | "~\\Envs", // virtualenwrapper-win %WORKON_HOME% 7 | ] 8 | } -------------------------------------------------------------------------------- /Virtualenv.sublime-settings: -------------------------------------------------------------------------------- 1 | // Default settings for Virtualenv plugin: 2 | { 3 | // Assuming virtualenv installed on default python prefix. 4 | // Depending on your setup you might want to change this to something like: 5 | // "virtualenv", "virtualenv-3.3", "python3 -m virtualenv" ... 6 | "executable": "python -m virtualenv", 7 | 8 | // Directory paths searched for virtualenvs. 9 | // First one will be used as default destination for new virtualenvs. 10 | "virtualenv_directories": [ 11 | "~/.virtualenvs", // virtualenvwrapper $WORKON_HOME 12 | ], 13 | 14 | // Additonal paths searched for python installations. 15 | // Portable pythons? Perhaps? 16 | "extra_paths": [] 17 | } -------------------------------------------------------------------------------- /commands.py: -------------------------------------------------------------------------------- 1 | """Sublime Text commands for virtualenv management.""" 2 | 3 | import logging 4 | import os.path 5 | import shlex 6 | import shutil 7 | import sys 8 | 9 | import sublime 10 | import sublime_plugin 11 | import Default as sublime_default 12 | 13 | from . import virtualenv_lib as virtualenv 14 | 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | 19 | SETTINGS = "Virtualenv.sublime-settings" 20 | 21 | 22 | def settings(): 23 | """Return the settings of the plugin.""" 24 | return sublime.load_settings(SETTINGS) 25 | 26 | 27 | def save_settings(): 28 | """Save plugin settings to disk.""" 29 | sublime.save_settings(SETTINGS) 30 | settings.save = save_settings 31 | 32 | 33 | class InvalidVirtualenv(Exception): 34 | 35 | """Exception raised when the current virtualenv is missing or corrupt.""" 36 | 37 | def __init__(self, venv): 38 | """Construct automatic error message from virtualenv path.""" 39 | message = ( 40 | "Virtualenv at \"{}\" is missing, corrupt or has been deleted.".format(venv)) 41 | super(InvalidVirtualenv, self).__init__(message) 42 | self.message = message 43 | 44 | 45 | class VirtualenvCommand(sublime_plugin.WindowCommand): 46 | 47 | """Base command with virtualenv management functionality.""" 48 | 49 | @property 50 | def virtualenv_exec(self): 51 | """Virtualenv executable as specified in the settings. 52 | 53 | Returns a list with the command split by shlex.split(). 54 | """ 55 | return shlex.split(settings().get('executable')) 56 | 57 | @property 58 | def virtualenv_directories(self): 59 | """The list of directory paths specified in the settings.""" 60 | return [os.path.expanduser(path) 61 | for path in settings().get('virtualenv_directories')] 62 | 63 | def get_virtualenv(self, validate=False, **kwargs): 64 | """Get current virtualenv from project data. 65 | 66 | (It will work even if the project has not been saved. 67 | The data is stored internally anyway.) 68 | 69 | Takes an optional flag 'validate'. If True, the virtualenv 70 | will be checked and if the validation fails 'InvalidVirtualenv' 71 | is raised. 72 | """ 73 | venv = kwargs.pop('virtualenv', "") 74 | if not venv: 75 | project_data = self.window.project_data() or {} 76 | venv = project_data.get('virtualenv', "") 77 | venv = os.path.expanduser(venv) 78 | 79 | if validate and venv and not virtualenv.is_valid(venv): 80 | self.set_virtualenv(None) 81 | raise InvalidVirtualenv(venv) 82 | 83 | return venv 84 | 85 | def set_virtualenv(self, venv): 86 | """Update the current virtualenv in project data. 87 | 88 | If the passed venv in None, remove virtualenv data from project. 89 | """ 90 | project_data = self.window.project_data() or {} 91 | 92 | if venv: 93 | project_data['virtualenv'] = venv 94 | sublime.status_message("({}) ACTIVATED".format(os.path.basename(venv))) 95 | else: 96 | try: 97 | del project_data['virtualenv'] 98 | sublime.status_message("DEACTIVATED") 99 | except KeyError: 100 | pass 101 | 102 | self.window.set_project_data(project_data) 103 | logger.info("Current virtualenv set to \"{}\".".format(venv)) 104 | 105 | def find_virtualenvs(self): 106 | """Return a list of (basename, path) tuples of the found virtualenvs. 107 | 108 | Searches in open folders and paths defined in the settings. 109 | 110 | The result is valid as input for Sublime's quick panel. 111 | """ 112 | search_dirs = self.window.folders() + self.virtualenv_directories 113 | venvs = virtualenv.find_virtualenvs(search_dirs) 114 | return [[os.path.basename(venv), venv] for venv in venvs] 115 | 116 | def find_pythons(self): 117 | """Find python executables in the system. 118 | 119 | Searches in os.environ and additional directories defined 120 | in the settings. 121 | """ 122 | extra_paths = tuple(settings().get('extra_paths', [])) 123 | return virtualenv.find_pythons(extra_paths=extra_paths) 124 | 125 | 126 | class VirtualenvExecCommand(sublime_default.exec.ExecCommand, VirtualenvCommand): 127 | 128 | """Extends the default exec command adapting the build parameters.""" 129 | 130 | def run(self, **kwargs): 131 | """Exec the command with virtualenv. 132 | 133 | If a virtualenv is active and valid update the build parameters 134 | as needed and call the built-in command. 135 | 136 | Else, if no virtualenv is active, do nothing and call the built-in 137 | command. 138 | 139 | Else, if the active virtualenv is invalid or corrupt display an error 140 | message and cancel execution. 141 | """ 142 | try: 143 | venv = self.get_virtualenv(validate=True, **kwargs) 144 | except InvalidVirtualenv as error: 145 | sublime.error_message(str(error) + " Execution cancelled!") 146 | else: 147 | if venv: 148 | kwargs = self.update_exec_kwargs(venv, **kwargs) 149 | logger.info("Command executed with virtualenv \"{}\".".format(venv)) 150 | super(VirtualenvExecCommand, self).run(**kwargs) 151 | 152 | def update_exec_kwargs(self, venv, **kwargs): 153 | """Modify exec kwargs to make use of the virtualenv.""" 154 | postactivate = virtualenv.activate(venv) 155 | kwargs['path'] = postactivate['path'] 156 | kwargs['env'] = dict(kwargs.get('env', {}), **postactivate['env']) 157 | kwargs['env'].pop('PYTHONHOME', None) 158 | # On OS X, avoid being run in a login shell, to preserve the virtualenv-ized PATH 159 | if sys.platform == 'darwin' and 'shell_cmd' in kwargs: 160 | kwargs['cmd'] = ['/bin/bash', '-c', kwargs['shell_cmd']] 161 | del kwargs['shell_cmd'] 162 | return kwargs 163 | 164 | 165 | class ActivateVirtualenvCommand(VirtualenvCommand): 166 | 167 | """Command for selecting active virtualenv.""" 168 | 169 | def run(self, **kwargs): 170 | """Display available virtualenvs in quick panel.""" 171 | self.available_venvs = self.find_virtualenvs() 172 | self.window.show_quick_panel(self.available_venvs, self._set_virtualenv) 173 | 174 | def _set_virtualenv(self, index): 175 | if index != -1: 176 | venv = self.available_venvs[index][1] 177 | self.set_virtualenv(venv) 178 | 179 | 180 | class DeactivateVirtualenvCommand(VirtualenvCommand): 181 | 182 | """"Commmand for deactivating the virtualenv.""" 183 | 184 | def run(self, **kwargs): 185 | """Just delete the virtualenv entry from project data.""" 186 | self.set_virtualenv(None) 187 | 188 | def is_enabled(self): 189 | """Only if the virtualenv entry is set.""" 190 | return bool(self.get_virtualenv()) 191 | 192 | 193 | class NewVirtualenvCommand(VirtualenvCommand): 194 | 195 | """Command for creating a new virtualenv.""" 196 | 197 | def run(self, **kwargs): 198 | """Show input panel requesting virtualenv destination.""" 199 | self.window.show_input_panel( 200 | "Virtualenv Path:", self.virtualenv_directories[0] + os.path.sep, 201 | self.get_python, None, None) 202 | 203 | def get_python(self, venv): 204 | """Show available python binaries in quick panel. 205 | 206 | Callback called with virtualenv destination. 207 | """ 208 | if not venv: 209 | return 210 | 211 | self.venv = os.path.expanduser(os.path.normpath(venv)) 212 | self.found_pythons = self.find_pythons() 213 | self.window.show_quick_panel(self.found_pythons, self.create_virtualenv) 214 | 215 | def create_virtualenv(self, python_index): 216 | """Execute the command and create the virtualenv. 217 | 218 | Callback called with selected python. 219 | 220 | Constructs the appropriate command with the virtualenv command, 221 | the selected python and the destination. 222 | 223 | Delegates command execution to the built-in exec command, so 224 | the process can be killed. 225 | 226 | It will also activate the created virtualenv. 227 | """ 228 | cmd = self.virtualenv_exec 229 | if python_index != -1: 230 | python = self.found_pythons[python_index] 231 | cmd += ['-p', python] 232 | cmd += [self.venv] 233 | self.window.run_command('exec', {'cmd': cmd}) 234 | self.set_virtualenv(self.venv) 235 | 236 | 237 | class NewBuiltinVirtualenvCommand(NewVirtualenvCommand): 238 | 239 | """Command for creating a new virtualenv with built-in venv module.""" 240 | 241 | def find_pythons(self): 242 | """With venv module available.""" 243 | extra_paths = tuple(settings().get('extra_paths', [])) 244 | return virtualenv.find_pythons( 245 | extra_paths=extra_paths, req_modules=('venv', )) 246 | 247 | def create_virtualenv(self, python_index): 248 | """With the venv module installed in the selected python.""" 249 | if python_index == -1: 250 | return 251 | 252 | python = self.found_pythons[python_index] 253 | cmd = [python, "-m", "venv", self.venv] 254 | self.window.run_command('exec', {'cmd': cmd}) 255 | self.set_virtualenv(self.venv) 256 | 257 | 258 | class RemoveVirtualenvCommand(VirtualenvCommand): 259 | 260 | """Command for deleting virtualenv directories.""" 261 | 262 | def run(self, **kwargs): 263 | """Display quick panel with found virtualenvs.""" 264 | self.available_venvs = self.find_virtualenvs() 265 | self.window.show_quick_panel(self.available_venvs, self.remove_virtualenv) 266 | 267 | def remove_virtualenv(self, index): 268 | """Request confirmation and delete the directory tree. 269 | 270 | Also set current virtualenv to None. 271 | """ 272 | if index == -1: 273 | return 274 | 275 | venv = self.available_venvs[index][1] 276 | confirmed = sublime.ok_cancel_dialog( 277 | "Please confirm deletion of virtualenv at:\n\"{}\".".format(venv)) 278 | if confirmed: 279 | try: 280 | shutil.rmtree(venv) 281 | logger.info("\"{}\" deleted.".format(venv)) 282 | except (IOError, OSError): 283 | logger.error("Could not delete \"{}\".".format(venv)) 284 | else: 285 | if venv == self.get_virtualenv(): 286 | self.set_virtualenv(None) 287 | 288 | 289 | class AddVirtualenvDirectoryCommand(VirtualenvCommand): 290 | 291 | """Shortcut command for adding paths to the 'virtualenv_directories' setting.""" 292 | 293 | def run(self, **kwargs): 294 | """Shot input panel requesting path to user.""" 295 | self.window.show_input_panel( 296 | "Directory path:", os.path.expanduser("~") + os.path.sep, 297 | self.add_directory, None, None) 298 | 299 | def add_directory(self, directory): 300 | """Add given directory to the list. 301 | 302 | If the path is not a directory show error dialog. 303 | """ 304 | if not directory: 305 | return 306 | 307 | directory = os.path.expanduser(os.path.normpath(directory)) 308 | if not os.path.isdir(directory): 309 | sublime.error_message("\"{}\" is not a directory.".format(directory)) 310 | return 311 | 312 | directories = self.virtualenv_directories 313 | directories.append(directory) 314 | settings().set('virtualenv_directories', directories) 315 | settings.save() 316 | -------------------------------------------------------------------------------- /integrations.py: -------------------------------------------------------------------------------- 1 | """Integrations with other Sublime packages.""" 2 | 3 | import sublime 4 | 5 | from .commands import VirtualenvCommand, InvalidVirtualenv 6 | from . import virtualenv_lib as virtualenv 7 | 8 | 9 | # SublimeREPL integration: 10 | class CurrentVirtualenvReplCommand(VirtualenvCommand): 11 | 12 | """Launches a Python REPL with the active virtualenv.""" 13 | 14 | def run(self, **kwargs): 15 | """Open the REPL with the virtualenv. 16 | 17 | Based on the original Python + virtualenv REPL: 18 | https://github.com/wuub/SublimeREPL/blob/master/lang_integration.py#L86 19 | """ 20 | try: 21 | venv = self.get_virtualenv(validate=True, **kwargs) 22 | except InvalidVirtualenv as error: 23 | sublime.error_message(str(error) + " REPL cancelled!") 24 | return 25 | 26 | postactivate = virtualenv.activate(venv) 27 | 28 | self.window.run_command('repl_open', { 29 | 'type': 'subprocess', 30 | 'autocomplete_server': True, 31 | 32 | 'cmd': ["python", "-u", "${packages}/SublimeREPL/config/Python/ipy_repl.py"], 33 | 'cwd': "$file_path", 34 | 'encoding': 'utf8', 35 | 'extend_env': dict({ 36 | 'PATH': postactivate['path'], 37 | 'PYTHONIOENCODING': 'utf-8' 38 | }, **postactivate['env']), 39 | 40 | 'syntax': "Packages/Python/Python.tmLanguage", 41 | 'external_id': "python" 42 | }) 43 | 44 | def is_enabled(self): 45 | """If SublimeREPL is installed and a virtualenv is active.""" 46 | try: 47 | import SublimeREPL # noqa 48 | return bool(self.get_virtualenv()) 49 | except ImportError: 50 | return False 51 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.txt", 3 | "1.1.0": "messages/v1.1.0.txt", 4 | "1.1.1": "messages/v1.1.1.txt" 5 | } 6 | -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- 1 | Sublime Text - Virtualenv 2 | ========================= 3 | 4 | Manage your virtualenvs directly from Sublime Text 3. (BETA) 5 | 6 | ## Features 7 | 8 | - Reusable build system. Execute code with a virtualenv without 9 | editing your paths manually. 10 | - Virtualenv search. Finds virtualenvs in the open folders or anywhere in your system. 11 | - Activation/Deactivation. Select or disable the current virtualenv easily. 12 | - Create and delete virtualenvs. With target python selection. 13 | 14 | 15 | ## Support 16 | 17 | Only Sublime Text 3. Tested in Linux and Windows but it should work in OS X as well. 18 | 19 | 20 | ## Usage 21 | 22 | - Set your build system to `Python + Virtualenv`. (Tools -> Build System) 23 | - Search "Virtualenv" in the command palette. 24 | 25 | 26 | For further details and instructions see the README: 27 | Preferences -> Package Settings -> Virtualenv -> README 28 | 29 | ----------------------------------------------------------------------------------------- 30 | 31 | Hello! Thank you for testing this package. 32 | 33 | IMPORTANT: 34 | 35 | Before you start using the commands verify that the default settings are suitable for 36 | your system. Check them in Preferences -> Package Settings -> Virtualenv. 37 | *But* do not modify the default settings as you will lose all the changes if the package 38 | is updated. You should override the necessary settings in Virtualenv -> User instead. 39 | 40 | Please report any issues or suggestions in the issue tracker: 41 | https://github.com/AdrianLC/sublime-text-virtualenv/issues 42 | -------------------------------------------------------------------------------- /messages/v1.1.0.txt: -------------------------------------------------------------------------------- 1 | Virtualenv 1.1.0 2 | ================ 3 | 4 | - pypy executables should also show up now in the list of available python targets. 5 | - Added creation of virtualenvs with the built-in 'venv' module (Python 3.3+). 6 | - Integration with SublimeREPL. If SublimeREPL is installed and a virtualenv is active the 7 | command "Virtualenv: SublimeREPL - Python" will launch a REPL with the current virtualenv. 8 | -------------------------------------------------------------------------------- /messages/v1.1.2.txt: -------------------------------------------------------------------------------- 1 | Virtualenv 1.1.2 2 | ================ 3 | 4 | - Fixed an issue with virtualenvs not being correctly activated on Mac OS X. 5 | -------------------------------------------------------------------------------- /virtualenv_lib.py: -------------------------------------------------------------------------------- 1 | """Utility functions for working with virtualenvs. 2 | 3 | (Everything not dependent on Sublime or its API should go here.) 4 | """ 5 | 6 | __all__ = ('activate', 'find_virtualenvs', 'is_virtualenv', 'find_pythons') 7 | 8 | from functools import lru_cache 9 | from itertools import chain 10 | import logging 11 | import os 12 | import re 13 | import subprocess 14 | import sys 15 | 16 | 17 | logger = logging.getLogger(__name__) 18 | 19 | 20 | BINDIR = "bin" 21 | ACTIVATE_SCRIPT = "activate" 22 | if sys.platform == 'win32': 23 | BINDIR = "Scripts" 24 | ACTIVATE_SCRIPT += ".bat" 25 | 26 | PYTHON_NAME_RE = re.compile(r'python[\d\.]*(?:\.exe)?$') 27 | PYPY_NAME_RE = re.compile(r'pypy[\d\.]*(?:\.exe)?$') 28 | 29 | 30 | def activate(virtualenv): 31 | """Return a dict with the changes caused by the virtualenv. 32 | 33 | The changes are: 34 | - Prepend the path of the virtualenv binary directory to $PATH. 35 | - Set a $VIRTUAL_ENV variable with the path to the activated virtualenv. 36 | """ 37 | system_path = os.environ.get('PATH', os.defpath) 38 | virtualenv_path = os.path.join(virtualenv, BINDIR) # /path/to/venv/bin 39 | path = os.pathsep.join((virtualenv_path, system_path)) # PATH=/path/to/venv/bin:$PATH 40 | 41 | env = {'VIRTUAL_ENV': virtualenv} 42 | 43 | return {'path': path, 'env': env} 44 | 45 | 46 | def find_virtualenvs(paths): 47 | """Find virtualenvs in the given paths. 48 | 49 | Returns a sorted list with the results. 50 | """ 51 | virtualenvs = [] 52 | for path in paths: 53 | if not os.path.isdir(path): 54 | logger.warning("{} is not a directory. Path ignored.".format(path)) 55 | continue 56 | subdirs = filter(os.path.isdir, (os.path.join(path, name) for name in os.listdir(path))) 57 | virtualenvs += sorted(filter(is_virtualenv, subdirs)) 58 | return virtualenvs 59 | 60 | 61 | def is_virtualenv(path): 62 | """Test whether 'path' is a virtualenv. 63 | 64 | Assumes that any directory with a "./bin/activate" is a valid virtualenv. 65 | """ 66 | try: 67 | return os.path.isfile(os.path.join(path, BINDIR, ACTIVATE_SCRIPT)) 68 | except IOError: 69 | return False 70 | 71 | is_valid = is_virtualenv 72 | 73 | 74 | @lru_cache() 75 | def find_pythons(paths=(), extra_paths=(), req_modules=()): 76 | """Find available python binaries. 77 | 78 | Matches a regex against filenames. 79 | 80 | Searches every directory in $PATH by default. 81 | Extends the search to any additional directory passed in 'extra_paths'. 82 | 83 | Found pythons will be optionally filtered based on the availability of 84 | modules passed through the 'req_modules' parameter. 85 | 86 | Returns a sorted list with the results. 87 | """ 88 | paths = paths or os.environ.get('PATH', os.defpath).split(os.pathsep) 89 | paths = chain(paths, extra_paths) 90 | 91 | is_exec = lambda path: os.path.isfile(path) and os.access(path, os.X_OK) 92 | 93 | found_pythons = [] 94 | for path in filter(os.path.isdir, paths): 95 | names = os.listdir(path) 96 | python_names = sorted(filter(PYTHON_NAME_RE.match, names)) 97 | pypy_names = sorted(filter(PYPY_NAME_RE.match, names)) 98 | pythons = list(filter(is_exec, (os.path.join(path, name) 99 | for name in python_names + pypy_names))) 100 | 101 | if req_modules: 102 | # Hide subprocess window in Windows: 103 | startupinfo = None 104 | if sys.platform == 'win32': 105 | startupinfo = subprocess.STARTUPINFO() 106 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 107 | 108 | modules = ", ".join(req_modules) 109 | for python in pythons[:]: 110 | cmd = [python, "-c", "import " + modules] 111 | import_error = subprocess.call(cmd, startupinfo=startupinfo) 112 | if import_error: 113 | pythons.remove(python) 114 | 115 | found_pythons += pythons 116 | return found_pythons 117 | --------------------------------------------------------------------------------