This repository has been archived by the owner on Jan 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #28 from dephell/try-command
Try command
- Loading branch information
Showing
11 changed files
with
224 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
# built-in | ||
import subprocess | ||
import shlex | ||
from argparse import REMAINDER, ArgumentParser | ||
from pathlib import Path | ||
from tempfile import TemporaryDirectory | ||
from typing import Set | ||
|
||
|
||
# project | ||
from dephell_venvs import VEnv | ||
|
||
# app | ||
from ..context_tools import env_var | ||
from ..actions import get_python, get_resolver | ||
from ..config import builders | ||
from ..controllers import analize_conflict | ||
from ..models import Requirement | ||
from ..package_manager import PackageManager | ||
from .base import BaseCommand | ||
|
||
|
||
class JailTryCommand(BaseCommand): | ||
"""Try packages into temporary isolated environment. | ||
https://dephell.readthedocs.io/en/latest/cmd-jail-try.html | ||
""" | ||
@classmethod | ||
def get_parser(cls) -> ArgumentParser: | ||
parser = ArgumentParser( | ||
prog='dephell jail try', | ||
description=cls.__doc__, | ||
) | ||
builders.build_config(parser) | ||
builders.build_venv(parser) | ||
builders.build_output(parser) | ||
builders.build_other(parser) | ||
parser.add_argument('--command', help='command to execute.') | ||
parser.add_argument('name', nargs=REMAINDER, help='packages to install') | ||
return parser | ||
|
||
def __call__(self) -> bool: | ||
resolver = get_resolver(reqs=self.args.name) | ||
name = next(iter(resolver.graph.get_layer(0))).dependencies[0].name | ||
|
||
command = self.config.get('command') | ||
if not command: | ||
command = 'python' | ||
if isinstance(command, str): | ||
command = shlex.split(command) | ||
|
||
with TemporaryDirectory() as base_path: | ||
base_path = Path(base_path) | ||
|
||
# make venv | ||
venv = VEnv(path=base_path) | ||
if venv.exists(): | ||
self.logger.error('already installed', extra=dict(package=name)) | ||
return False | ||
python = get_python(self.config) | ||
self.logger.info('creating venv...', extra=dict( | ||
venv=str(venv.path), | ||
python=str(python.path), | ||
)) | ||
venv.create(python_path=python.path) | ||
|
||
# install | ||
ok = self._install(resolver=resolver, python_path=venv.python_path) | ||
if not ok: | ||
return False | ||
|
||
# install executable | ||
executable = venv.bin_path / command[0] | ||
if not executable.exists(): | ||
self.logger.warning('executable is not found in venv, trying to install...', extra=dict( | ||
executable=command[0], | ||
)) | ||
ok = self._install( | ||
resolver=get_resolver(reqs=command[:1]), | ||
python_path=venv.python_path, | ||
) | ||
if not ok: | ||
return False | ||
if not executable.exists(): | ||
self.logger.error('package installed, but executable is not found') | ||
return False | ||
|
||
# make startup script to import installed packages | ||
startup_path = base_path / '_startup.py' | ||
packages = self._get_startup_packages(lib_path=venv.lib_path, packages=self.args.name) | ||
if not packages: | ||
self.logger.error('cannot find any packages') | ||
return False | ||
startup_path.write_text('import ' + ', '.join(sorted(packages))) | ||
|
||
# run | ||
self.logger.info('running...') | ||
with env_var(key='PYTHONSTARTUP', value=str(startup_path)): | ||
result = subprocess.run([str(executable)] + command[1:]) | ||
if result.returncode != 0: | ||
self.logger.error('command failed', extra=dict(code=result.returncode)) | ||
return False | ||
|
||
return True | ||
|
||
def _install(self, resolver, python_path: Path) -> bool: | ||
self.logger.info('build dependencies graph...') | ||
resolved = resolver.resolve(silent=self.config['silent']) | ||
if not resolved: | ||
conflict = analize_conflict(resolver=resolver) | ||
self.logger.warning('conflict was found') | ||
print(conflict) | ||
return False | ||
|
||
# install | ||
reqs = Requirement.from_graph(graph=resolver.graph, lock=True) | ||
self.logger.info('installation...', extra=dict( | ||
executable=python_path, | ||
packages=len(reqs), | ||
)) | ||
code = PackageManager(executable=python_path).install(reqs=reqs) | ||
if code != 0: | ||
return False | ||
self.logger.info('installed') | ||
return True | ||
|
||
@staticmethod | ||
def _get_startup_packages(lib_path: Path, packages) -> Set[str]: | ||
names = set() | ||
for path in lib_path.iterdir(): | ||
name = path.name | ||
if name == '__pycache__': | ||
continue | ||
if name.endswith('.py'): | ||
names.add(name.split('.')[0]) | ||
elif path.is_dir() and '.' not in name: | ||
names.add(name) | ||
|
||
if packages: | ||
packages = {package.lower().replace('-', '_') for package in packages} | ||
if len(names & packages) == len(packages): | ||
return packages | ||
|
||
return names |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# dephell jail try | ||
|
||
Try python packages in an isolated environment. | ||
|
||
Try [textdistance](https://github.com/orsinium/textdistance): | ||
|
||
```bash | ||
$ dephell jail try textdistance | ||
INFO creating venv... (python=/usr/local/bin/python3.7, venv=/tmp/tmpgixqt4_q) | ||
INFO build dependencies graph... | ||
INFO installation... (executable=/tmp/tmpgixqt4_q/bin/python3.7, packages=1) | ||
Collecting textdistance==4.1.3 (from -r /tmp/tmpduyecsir/requiements.txt (line 2)) | ||
Installing collected packages: textdistance | ||
Successfully installed textdistance-4.1.3 | ||
INFO installed | ||
INFO running... | ||
Python 3.7.0 (default, Dec 24 2018, 12:47:36) | ||
[GCC 5.4.0 20160609] on linux | ||
Type "help", "copyright", "credits" or "license" for more information. | ||
>>> | ||
``` | ||
|
||
In this example DepHell installs latest `texdistance` release in a temporary virtual environment and runs python interpreter with already imported `textdistance` inside. | ||
|
||
Use [ipython](https://ipython.org/) instead of standart python interpreter: | ||
|
||
```bash | ||
$ dephell jail try --command=ipython textdistance | ||
``` | ||
|
||
Set python version: | ||
|
||
```bash | ||
$ dephell jail try --python=3.5 textdistance | ||
... | ||
Python 3.5.3 (928a4f70d3de, Feb 08 2019, 10:42:58) | ||
[PyPy 7.0.0 with GCC 6.2.0 20160901] on linux | ||
Type "help", "copyright", "credits" or "license" for more information. | ||
>>>> | ||
``` | ||
|
||
Install flake8 and plugin for it and run checks on given path: | ||
|
||
```bash | ||
$ dephell jail try --command="flake8 ./dephell" flake8 flake8-commas | ||
``` | ||
|
||
## See also | ||
|
||
1. [How DepHell choose Python interpreter](python-lookup). | ||
1. [dephell jail install](cmd-jail-install) to install CLI tool in permanent jail. | ||
1. [dephell venv create](cmd-venv-create) for information about virtual environments management in DepHell. | ||
1. [dephell package install](cmd-package-install) to install package into project virtual environment. | ||
1. [dephell deps install](cmd-deps-install) to install all project dependencies. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,7 @@ | |
cmd-jail-install | ||
cmd-jail-list | ||
cmd-jail-remove | ||
cmd-jail-try | ||
.. toctree:: | ||
:maxdepth: 1 | ||
|