Skip to content

Commit

Permalink
readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Евгений authored and Евгений committed May 2, 2023
1 parent fd68907 commit 90fa7ae
Showing 1 changed file with 111 additions and 4 deletions.
115 changes: 111 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@

Thanks to this package, it is very easy to manage the lifecycle of packages directly from the code. In runtime.

- ⚡ You can use 2 different versions of the same library in the same program.
- ⚡ You can use incompatible libraries in the same project, as well as libraries with incompatible/conflicting dependencies.
- ⚡ It's easy to share written scripts. The script file becomes self-sufficient - the user does not need to install the necessary libraries.
- ⚡ The library does not leave behind "garbage". After the end of the program, no additional files remain in the system.
⚡ You can use 2 different versions of the same library in the same program.
⚡ You can use incompatible libraries in the same project, as well as libraries with incompatible/conflicting dependencies.
⚡ It's easy to share written scripts. The script file becomes self-sufficient - the user does not need to install the necessary libraries.
⚡ The library does not leave behind "garbage". After the end of the program, no additional files remain in the system.


## Table of contents

- [**Quick start**](#quick-start)
- [**Imports**](#imports)
- [**Installing multiple packages**](#installing-multiple-packages)
- [**Options**](#options)
- [**Output and logging**](#output-and-logging)
- [**How does it work?**](#how-does-it-work)


Expand Down Expand Up @@ -100,3 +102,108 @@ with installed('flask==2.0.2') as context_1:
print(flask_1.__version__) # 2.0.2
print(flask_2.__version__) # 2.0.0
```

> Keep in mind that although inter-thread isolation is used inside the library, working with contexts is not completely thread-safe. You can write code in such a way that two different contexts import different modules in separate threads at the same time. In this case, you may get paradoxical results. Therefore, it is recommended to additionally isolate with mutexes all cases where you import something from contexts in different threads.

## Options

You can use [any options](https://pip.pypa.io/en/stable/cli/pip_install/) available for `pip`. To do this, you need to slightly change the name of the option, replacing the hyphens with underscores, and pass it as an argument to `installed`. Here is an example of how using the `--index-url` option will look like:

```python
with installed('super_test_project==0.0.1', index_url='https://test.pypi.org/simple/'):
import super_test
```

You cannot use options that tell `pip` where to install libraries.


## Output and logging

By default, you can see the output of the installation progress in the console:

```python
>>> with installed('flask'):
... import flask
...
Collecting flask
Using cached Flask-2.3.2-py3-none-any.whl (96 kB)
Collecting click>=8.1.3
Using cached click-8.1.3-py3-none-any.whl (96 kB)
Collecting importlib-metadata>=3.6.0
Using cached importlib_metadata-6.6.0-py3-none-any.whl (22 kB)
Collecting Jinja2>=3.1.2
Using cached Jinja2-3.1.2-py3-none-any.whl (133 kB)
Collecting Werkzeug>=2.3.3
Using cached Werkzeug-2.3.3-py3-none-any.whl (242 kB)
Collecting itsdangerous>=2.1.2
Using cached itsdangerous-2.1.2-py3-none-any.whl (15 kB)
Collecting blinker>=1.6.2
Using cached blinker-1.6.2-py3-none-any.whl (13 kB)
Collecting zipp>=0.5
Using cached zipp-3.15.0-py3-none-any.whl (6.8 kB)
Collecting MarkupSafe>=2.0
Using cached MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl (17 kB)
Installing collected packages: zipp, MarkupSafe, Werkzeug, Jinja2, itsdangerous, importlib-metadata, click, blinker, flask
Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.2 Werkzeug-2.3.3 blinker-1.6.2 click-8.1.3 flask-2.3.2 importlib-metadata-6.6.0 itsdangerous-2.1.2 zipp-3.15.0
```

If you don't want to see this output, pass the `catch_output` argument:

```python
>>> with installed('flask', catch_output=True):
... import flask
...
>>>
```

In case of installation errors, you will get an `installed.errors.InstallingPackageError` exception. From the object of this exception, you can get `stdout` and `stderr` even if you have forbidden the output:

```python
from installed.errors import InstallingPackageError


try:
with installed('some_wrong_pack', catch_output=True):
import some_wrong_module
except InstallingPackageError as e:
print(e.stdout)
print(e.stderr)
```

Logging is also enabled by default for installing packages. You can see it if you configure logging correctly. In this case:

```python
import logging


logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.StreamHandler(),
]
)

with installed('flask', catch_output=True):
import flask
```

... the logs will look something like this:

```
2023-05-02 13:47:56,752 [INFO] The beginning of the execution of the command "/Users/pomponchik/Desktop/Projects/magic-action-runner/venv/bin/python3 -m venv /var/folders/54/p5qzzp9j65zckq9kd2k31t9c0000gn/T/tmpiajesk4s/venv".
2023-05-02 13:47:58,993 [INFO] The command "/Users/pomponchik/Desktop/Projects/magic-action-runner/venv/bin/python3 -m venv /var/folders/54/p5qzzp9j65zckq9kd2k31t9c0000gn/T/tmpiajesk4s/venv" has been executed.
2023-05-02 13:47:58,993 [INFO] The beginning of the execution of the command "/Users/pomponchik/Desktop/Projects/magic-action-runner/venv/bin/python3 -m pip install --target=/var/folders/54/p5qzzp9j65zckq9kd2k31t9c0000gn/T/tmpiajesk4s/venv/lib/python3.9/site-packages flask".
2023-05-02 13:48:01,052 [INFO] The command "/Users/pomponchik/Desktop/Projects/magic-action-runner/venv/bin/python3 -m pip install --target=/var/folders/54/p5qzzp9j65zckq9kd2k31t9c0000gn/T/tmpiajesk4s/venv/lib/python3.9/site-packages flask" has been executed.
```

The `INFO` [level](https://docs.python.org/3/library/logging.html#logging-levels) is used by default. For errors - `ERROR`.

## How does it work?

This package is essentially a wrapper for `venv` and `pip`.

When entering the context, a temporary folder is created using the [tempfile](https://docs.python.org/3/library/tempfile.html) library. Then it is added to [sys.path](https://docs.python.org/3/library/sys.html#sys.path), and after exiting the context, it is removed from there. To install the package in this particular temporary folder, the `--target` argument is passed to pip, indicating the path to it. Interaction with `pip` and `venv` occurs through [subprocesses](https://docs.python.org/3/library/subprocess.html).

The `import_here` method works by temporarily substituting [sys.path](https://docs.python.org/3/library/sys.html#sys.path) and [sys.modules](https://docs.python.org/3/library/sys.html#sys.modules). This is necessary so that the search for packages takes place only in the necessary directories.

0 comments on commit 90fa7ae

Please sign in to comment.