Plugins¶
By default, two types of project are supported: poetry and pipenv. New types can be added by enabling plugins which contain adapters for those project types.
A plugin is simply a Python module containing one or more subclasses of workspace.core.adapter.Adapter, which must implement its abstract methods.
Adding plugins¶
Expand the following to see an example plugin for Python projects using requirements.txt files:
plugins/requirementstxt.py
import os
import shlex
import subprocess
from typing import Set, Tuple
import requirements
from workspace.core.adapter import Adapter
class RequirementsTXTAdapter(Adapter, name="requirementstxt"):
def validate(self):
"""Attempt to parse the requirements."""
_ = self._requirements
def run_args(self, command: str) -> Tuple[str, dict]:
"""Get modified command and kwargs that should be used when running inside the project."""
command, kwargs = super().run_args(command)
venv_path = self._ensure_virtualenv()
env = os.environ.copy()
env["VIRTUAL_ENV"] = str(venv_path)
env["PATH"] = f"{venv_path/'bin'}:{env['PATH']}"
kwargs["env"] = env
return command, kwargs
def sync(self, include_dev: bool = True) -> subprocess.CompletedProcess:
"""Sync dependencies of the project."""
command = ["pip", "install", "-r", "requirements.txt"]
if include_dev:
command.extend(["-r", "requirements-dev.txt"])
return self.run(shlex.join(command))
def dependencies(self, include_dev: bool = True) -> Set[str]:
"""Get other workspaces this project depends upon."""
deps = self._requirements["default"]
if include_dev:
deps.extend(self._requirements["dev"])
results = set()
for dep in deps:
if dep.editable:
path = (self._project.resolved_path / dep.path).resolve()
project = self._project.root.get_project_by_path(path)
if project:
results.add(project.name)
return results
@property
def _requirements(self):
"""Parse the requirements files."""
return {
"default": list(requirements.parse((self._project.resolved_path / "requirements.txt").read_text())),
"dev": list(requirements.parse((self._project.resolved_path / "requirements-dev.txt").read_text())),
}
def _ensure_virtualenv(self):
"""Ensure virtualenv exists."""
venv_path = self._project.resolved_path / ".venv"
if not (venv_path / "bin/python").exists():
subprocess.run(["python", "-m", "venv", venv_path], check=True)
return venv_path
Provided the above example is on the PYTHONPATH, it can be enabled using
Projects using requirements.txt files can then be added to the workspace.
Showing currently enabled plugins¶
The currently enabled plugins can be shown using:
Disabling plugins¶
Plugins can be disabled using:
Warning
Ensure that no projects use types enabled by a plugin before disabling it, or the workspace will not be able to interact with the project.