pydepinject 0.0.2.dev0__tar.gz → 0.0.3.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pydepinject-0.0.3.dev0/MANIFEST.in +7 -0
- pydepinject-0.0.3.dev0/PKG-INFO +260 -0
- pydepinject-0.0.3.dev0/README.md +227 -0
- pydepinject-0.0.3.dev0/pyproject.toml +263 -0
- pydepinject-0.0.3.dev0/src/pydepinject/__init__.py +356 -0
- pydepinject-0.0.3.dev0/src/pydepinject/backends.py +208 -0
- pydepinject-0.0.3.dev0/src/pydepinject.egg-info/PKG-INFO +260 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/pydepinject.egg-info/SOURCES.txt +1 -1
- pydepinject-0.0.3.dev0/src/pydepinject.egg-info/requires.txt +11 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/tests/conftest.py +14 -2
- pydepinject-0.0.3.dev0/tests/test_pydepinject.py +478 -0
- pydepinject-0.0.2.dev0/MANIFEST.in +0 -4
- pydepinject-0.0.2.dev0/PKG-INFO +0 -178
- pydepinject-0.0.2.dev0/Readme.md +0 -139
- pydepinject-0.0.2.dev0/pyproject.toml +0 -140
- pydepinject-0.0.2.dev0/src/pydepinject/__init__.py +0 -235
- pydepinject-0.0.2.dev0/src/pydepinject/backends.py +0 -167
- pydepinject-0.0.2.dev0/src/pydepinject.egg-info/PKG-INFO +0 -178
- pydepinject-0.0.2.dev0/src/pydepinject.egg-info/requires.txt +0 -18
- pydepinject-0.0.2.dev0/tests/test_pydepinject.py +0 -270
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/LICENSE +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/setup.cfg +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/pydepinject.egg-info/dependency_links.txt +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/pydepinject.egg-info/top_level.txt +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/requirementmanager.egg-info/PKG-INFO +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/requirementmanager.egg-info/SOURCES.txt +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/requirementmanager.egg-info/dependency_links.txt +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/requirementmanager.egg-info/requires.txt +0 -0
- {pydepinject-0.0.2.dev0 → pydepinject-0.0.3.dev0}/src/requirementmanager.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydepinject
|
|
3
|
+
Version: 0.0.3.dev0
|
|
4
|
+
Summary: A package to dynamically inject requirements into a virtual environment.
|
|
5
|
+
Author: pydepinject
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: homepage, https://github.com/pydepinject/pydepinject
|
|
8
|
+
Project-URL: documentation, https://github.com/pydepinject/pydepinject
|
|
9
|
+
Project-URL: repository, https://github.com/pydepinject/pydepinject
|
|
10
|
+
Keywords: virtualenv,requirements,dependency management
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: packaging>=23.0
|
|
24
|
+
Requires-Dist: typing-extensions>=4.4.0
|
|
25
|
+
Provides-Extra: lint
|
|
26
|
+
Requires-Dist: isort; extra == "lint"
|
|
27
|
+
Requires-Dist: pylint; extra == "lint"
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: pytest; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
31
|
+
Requires-Dist: pytest-xdist; extra == "test"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# Requirement Manager
|
|
35
|
+
|
|
36
|
+
This project provides a `RequirementManager` (`requires` is an alias) class to manage Python package requirements using virtual environments. It can be used as a decorator or context manager to ensure specific packages are installed and available during the execution of a function or code block.
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- Automatically creates and manages virtual environments.
|
|
41
|
+
- Checks if the required packages are already installed.
|
|
42
|
+
- Installs packages if they are not already available.
|
|
43
|
+
- Supports ephemeral virtual environments that are deleted after use.
|
|
44
|
+
- Can be used as a decorator or context manager.
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
`pip install pydepinject`
|
|
49
|
+
|
|
50
|
+
To use the `uv` backend for faster environment and package management, ensure `uv` is installed separately. You can find installation instructions at [https://github.com/astral-sh/uv](https://github.com/astral-sh/uv).
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Decorator
|
|
56
|
+
|
|
57
|
+
To use the `requires` as a decorator, simply decorate your function with the required packages:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from pydepinject import requires
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@requires("requests", "numpy")
|
|
64
|
+
def my_function():
|
|
65
|
+
import requests
|
|
66
|
+
import numpy as np
|
|
67
|
+
print(requests.__version__)
|
|
68
|
+
print(np.__version__)
|
|
69
|
+
|
|
70
|
+
my_function()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Context Manager
|
|
74
|
+
|
|
75
|
+
You can also use the `requires` as a context manager:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from pydepinject import requires
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
with requires("requests", "numpy"):
|
|
82
|
+
import requests
|
|
83
|
+
import numpy as np
|
|
84
|
+
print(requests.__version__)
|
|
85
|
+
print(np.__version__)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Virtual Environment with specific name
|
|
89
|
+
|
|
90
|
+
The `requires` can create a virtual environment with a specific name:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
@requires("requests", venv_name="myenv")
|
|
94
|
+
def my_function():
|
|
95
|
+
import requests
|
|
96
|
+
print(requests.__version__)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
with requires("pylint", "requests", venv_name="myenv"):
|
|
100
|
+
import pylint
|
|
101
|
+
print(pylint.__version__)
|
|
102
|
+
import requests # This is also available here because it was installed in the same virtual environment
|
|
103
|
+
print(requests.__version__)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# The virtual environment name can also be set as PYDEPINJECT_VENV_NAME environment variable
|
|
107
|
+
import os
|
|
108
|
+
os.environ["PYDEPINJECT_VENV_NAME"] = "myenv"
|
|
109
|
+
|
|
110
|
+
@requires("requests")
|
|
111
|
+
def my_function():
|
|
112
|
+
import requests
|
|
113
|
+
print(requests.__version__)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
with requires("pylint", "requests"):
|
|
117
|
+
import pylint
|
|
118
|
+
print(pylint.__version__)
|
|
119
|
+
import requests # This is also available here because it was installed in the same virtual environment
|
|
120
|
+
print(requests.__version__)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
### Reusable Virtual Environments
|
|
126
|
+
|
|
127
|
+
The `requires` can create named virtual environments and reuse them across multiple functions or code blocks:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
@requires("requests", venv_name="myenv", ephemeral=False)
|
|
131
|
+
def my_function():
|
|
132
|
+
import requests
|
|
133
|
+
print(requests.__version__)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
with requires("pylint", "requests", venv_name="myenv", ephemeral=False):
|
|
137
|
+
import pylint
|
|
138
|
+
print(pylint.__version__)
|
|
139
|
+
import requests # This is also available here because it was installed in the same virtual environment
|
|
140
|
+
print(requests.__version__)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Managing Virtual Environments
|
|
144
|
+
|
|
145
|
+
The `requires` can automatically delete ephemeral virtual environments after use. This is useful when you want to ensure that the virtual environment is clean and does not persist after the function or code block completes:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
@requires("requests", venv_name="myenv", ephemeral=True)
|
|
149
|
+
def my_function():
|
|
150
|
+
import requests
|
|
151
|
+
print(requests.__version__)
|
|
152
|
+
|
|
153
|
+
my_function()
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Forcing Virtual Environment Recreation
|
|
157
|
+
|
|
158
|
+
If you need to ensure a completely clean environment, you can force its recreation using the `recreate=True` parameter. This will delete and rebuild the virtual environment even if it already exists.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from pydepinject import requires
|
|
162
|
+
|
|
163
|
+
# This will delete the "my-clean-env" venv if it exists and create it from scratch
|
|
164
|
+
@requires("requests", venv_name="my-clean-env", recreate=True)
|
|
165
|
+
def my_function():
|
|
166
|
+
import requests
|
|
167
|
+
print(requests.__version__)
|
|
168
|
+
|
|
169
|
+
my_function()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Logging
|
|
173
|
+
|
|
174
|
+
This library uses Python's standard logging but does not configure handlers or levels by default. Configure logging in your application to see debug output:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
import logging
|
|
178
|
+
|
|
179
|
+
logging.basicConfig(level=logging.INFO) # or DEBUG for verbose output
|
|
180
|
+
logging.getLogger("pydepinject").setLevel(logging.DEBUG)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
You can also integrate with your application's logging setup (structlog, rich logging, etc.) by attaching handlers as you normally would.
|
|
184
|
+
## Backend selection
|
|
185
|
+
|
|
186
|
+
By default, backends are tried in priority order "uv|venv". If uv is installed on your system, it will be preferred for faster environment creation and installs; otherwise the standard library venv backend is used.
|
|
187
|
+
|
|
188
|
+
You can control backend selection:
|
|
189
|
+
- Environment variable: set PYDEPINJECT_VENV_BACKEND, e.g. `PYDEPINJECT_VENV_BACKEND=venv` or `PYDEPINJECT_VENV_BACKEND=uv|venv`.
|
|
190
|
+
- API param: pass `venv_backend="uv"`, `"venv"`, or a pipe-separated list like `"uv|venv"` to requires/RequirementManager.
|
|
191
|
+
|
|
192
|
+
On Windows, paths (Scripts, Lib/site-packages) are handled automatically.
|
|
193
|
+
|
|
194
|
+
## Advanced options
|
|
195
|
+
|
|
196
|
+
### Additional installer arguments
|
|
197
|
+
You can forward extra arguments to the underlying installer (pip or uv pip) via `install_args`. This is useful for custom indexes, constraints files, proxies, etc.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from pydepinject import requires
|
|
201
|
+
|
|
202
|
+
@requires(
|
|
203
|
+
"requests",
|
|
204
|
+
install_args=(
|
|
205
|
+
"--index-url", "https://pypi.myorg/simple",
|
|
206
|
+
"--upgrade-strategy", "eager",
|
|
207
|
+
),
|
|
208
|
+
venv_backend="venv",
|
|
209
|
+
)
|
|
210
|
+
def my_function():
|
|
211
|
+
import requests
|
|
212
|
+
print(requests.__version__)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
These arguments are appended to the installer command.
|
|
216
|
+
|
|
217
|
+
### Virtual environment identity
|
|
218
|
+
For unnamed environments, a unique directory is generated based on a stable identity key. This key is derived from:
|
|
219
|
+
- The set of requirements, which are normalized, canonicalized (e.g., `PyYAML` becomes `pyyaml`), and sorted alphabetically to ensure a consistent order.
|
|
220
|
+
- The active Python version tag (e.g., `py3.11`).
|
|
221
|
+
- The selected backend (`uv` or `venv`).
|
|
222
|
+
- A short hash of the current Python interpreter's path to distinguish between different Python installations.
|
|
223
|
+
|
|
224
|
+
This process guarantees that identical dependency sets produce the same virtual environment, while any change in requirements, Python version, or backend results in a new, distinct environment. Named environments (created using the `venv_name` parameter) are not affected by this hashing mechanism.
|
|
225
|
+
|
|
226
|
+
### Venv metadata
|
|
227
|
+
After successful installs, a metadata file `.pydepinject-{timestamp}.json` is written into the venv directory. It records:
|
|
228
|
+
- pydepinject version, backend, Python version, interpreter path
|
|
229
|
+
- Target platform, requested packages, forwarded install args
|
|
230
|
+
- An ISO 8601 timestamp (UTC)
|
|
231
|
+
|
|
232
|
+
There might be multiple metadata files if the venv is reused across different runs with different requirements or install args. Each file is timestamped to avoid collisions.
|
|
233
|
+
|
|
234
|
+
This helps with debugging and reproducibility.
|
|
235
|
+
|
|
236
|
+
## Configuration with Environment Variables
|
|
237
|
+
|
|
238
|
+
`pydepinject` can be configured using the following environment variables:
|
|
239
|
+
|
|
240
|
+
- **`PYDEPINJECT_VENV_ROOT`**: Specifies the root directory where virtual environments are stored. If not set, a default temporary directory is used.
|
|
241
|
+
- **`PYDEPINJECT_VENV_NAME`**: Sets a default name for the virtual environment, which can be useful for creating persistent, reusable environments across different runs.
|
|
242
|
+
- **`PYDEPINJECT_VENV_BACKEND`**: Defines the virtual environment backend to use. Supported values are `uv` and `venv`. `uv` is preferred for its speed.
|
|
243
|
+
|
|
244
|
+
These variables provide a convenient way to standardize behavior in CI/CD pipelines or development environments.
|
|
245
|
+
|
|
246
|
+
## Unit Tests
|
|
247
|
+
|
|
248
|
+
Unit tests are provided to verify the functionality of the `requires`. The tests use `pytest` and cover various scenarios including decorator usage, context manager usage, ephemeral environments, and more.
|
|
249
|
+
|
|
250
|
+
### Running Tests
|
|
251
|
+
|
|
252
|
+
To run the unit tests, ensure you have `pytest` installed, and then execute the following command:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
pytest
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Requirement Manager
|
|
2
|
+
|
|
3
|
+
This project provides a `RequirementManager` (`requires` is an alias) class to manage Python package requirements using virtual environments. It can be used as a decorator or context manager to ensure specific packages are installed and available during the execution of a function or code block.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Automatically creates and manages virtual environments.
|
|
8
|
+
- Checks if the required packages are already installed.
|
|
9
|
+
- Installs packages if they are not already available.
|
|
10
|
+
- Supports ephemeral virtual environments that are deleted after use.
|
|
11
|
+
- Can be used as a decorator or context manager.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
`pip install pydepinject`
|
|
16
|
+
|
|
17
|
+
To use the `uv` backend for faster environment and package management, ensure `uv` is installed separately. You can find installation instructions at [https://github.com/astral-sh/uv](https://github.com/astral-sh/uv).
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Decorator
|
|
23
|
+
|
|
24
|
+
To use the `requires` as a decorator, simply decorate your function with the required packages:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from pydepinject import requires
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@requires("requests", "numpy")
|
|
31
|
+
def my_function():
|
|
32
|
+
import requests
|
|
33
|
+
import numpy as np
|
|
34
|
+
print(requests.__version__)
|
|
35
|
+
print(np.__version__)
|
|
36
|
+
|
|
37
|
+
my_function()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Context Manager
|
|
41
|
+
|
|
42
|
+
You can also use the `requires` as a context manager:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from pydepinject import requires
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
with requires("requests", "numpy"):
|
|
49
|
+
import requests
|
|
50
|
+
import numpy as np
|
|
51
|
+
print(requests.__version__)
|
|
52
|
+
print(np.__version__)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Virtual Environment with specific name
|
|
56
|
+
|
|
57
|
+
The `requires` can create a virtual environment with a specific name:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
@requires("requests", venv_name="myenv")
|
|
61
|
+
def my_function():
|
|
62
|
+
import requests
|
|
63
|
+
print(requests.__version__)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
with requires("pylint", "requests", venv_name="myenv"):
|
|
67
|
+
import pylint
|
|
68
|
+
print(pylint.__version__)
|
|
69
|
+
import requests # This is also available here because it was installed in the same virtual environment
|
|
70
|
+
print(requests.__version__)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# The virtual environment name can also be set as PYDEPINJECT_VENV_NAME environment variable
|
|
74
|
+
import os
|
|
75
|
+
os.environ["PYDEPINJECT_VENV_NAME"] = "myenv"
|
|
76
|
+
|
|
77
|
+
@requires("requests")
|
|
78
|
+
def my_function():
|
|
79
|
+
import requests
|
|
80
|
+
print(requests.__version__)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
with requires("pylint", "requests"):
|
|
84
|
+
import pylint
|
|
85
|
+
print(pylint.__version__)
|
|
86
|
+
import requests # This is also available here because it was installed in the same virtual environment
|
|
87
|
+
print(requests.__version__)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
### Reusable Virtual Environments
|
|
93
|
+
|
|
94
|
+
The `requires` can create named virtual environments and reuse them across multiple functions or code blocks:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
@requires("requests", venv_name="myenv", ephemeral=False)
|
|
98
|
+
def my_function():
|
|
99
|
+
import requests
|
|
100
|
+
print(requests.__version__)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
with requires("pylint", "requests", venv_name="myenv", ephemeral=False):
|
|
104
|
+
import pylint
|
|
105
|
+
print(pylint.__version__)
|
|
106
|
+
import requests # This is also available here because it was installed in the same virtual environment
|
|
107
|
+
print(requests.__version__)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Managing Virtual Environments
|
|
111
|
+
|
|
112
|
+
The `requires` can automatically delete ephemeral virtual environments after use. This is useful when you want to ensure that the virtual environment is clean and does not persist after the function or code block completes:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
@requires("requests", venv_name="myenv", ephemeral=True)
|
|
116
|
+
def my_function():
|
|
117
|
+
import requests
|
|
118
|
+
print(requests.__version__)
|
|
119
|
+
|
|
120
|
+
my_function()
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Forcing Virtual Environment Recreation
|
|
124
|
+
|
|
125
|
+
If you need to ensure a completely clean environment, you can force its recreation using the `recreate=True` parameter. This will delete and rebuild the virtual environment even if it already exists.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from pydepinject import requires
|
|
129
|
+
|
|
130
|
+
# This will delete the "my-clean-env" venv if it exists and create it from scratch
|
|
131
|
+
@requires("requests", venv_name="my-clean-env", recreate=True)
|
|
132
|
+
def my_function():
|
|
133
|
+
import requests
|
|
134
|
+
print(requests.__version__)
|
|
135
|
+
|
|
136
|
+
my_function()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Logging
|
|
140
|
+
|
|
141
|
+
This library uses Python's standard logging but does not configure handlers or levels by default. Configure logging in your application to see debug output:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import logging
|
|
145
|
+
|
|
146
|
+
logging.basicConfig(level=logging.INFO) # or DEBUG for verbose output
|
|
147
|
+
logging.getLogger("pydepinject").setLevel(logging.DEBUG)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
You can also integrate with your application's logging setup (structlog, rich logging, etc.) by attaching handlers as you normally would.
|
|
151
|
+
## Backend selection
|
|
152
|
+
|
|
153
|
+
By default, backends are tried in priority order "uv|venv". If uv is installed on your system, it will be preferred for faster environment creation and installs; otherwise the standard library venv backend is used.
|
|
154
|
+
|
|
155
|
+
You can control backend selection:
|
|
156
|
+
- Environment variable: set PYDEPINJECT_VENV_BACKEND, e.g. `PYDEPINJECT_VENV_BACKEND=venv` or `PYDEPINJECT_VENV_BACKEND=uv|venv`.
|
|
157
|
+
- API param: pass `venv_backend="uv"`, `"venv"`, or a pipe-separated list like `"uv|venv"` to requires/RequirementManager.
|
|
158
|
+
|
|
159
|
+
On Windows, paths (Scripts, Lib/site-packages) are handled automatically.
|
|
160
|
+
|
|
161
|
+
## Advanced options
|
|
162
|
+
|
|
163
|
+
### Additional installer arguments
|
|
164
|
+
You can forward extra arguments to the underlying installer (pip or uv pip) via `install_args`. This is useful for custom indexes, constraints files, proxies, etc.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from pydepinject import requires
|
|
168
|
+
|
|
169
|
+
@requires(
|
|
170
|
+
"requests",
|
|
171
|
+
install_args=(
|
|
172
|
+
"--index-url", "https://pypi.myorg/simple",
|
|
173
|
+
"--upgrade-strategy", "eager",
|
|
174
|
+
),
|
|
175
|
+
venv_backend="venv",
|
|
176
|
+
)
|
|
177
|
+
def my_function():
|
|
178
|
+
import requests
|
|
179
|
+
print(requests.__version__)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
These arguments are appended to the installer command.
|
|
183
|
+
|
|
184
|
+
### Virtual environment identity
|
|
185
|
+
For unnamed environments, a unique directory is generated based on a stable identity key. This key is derived from:
|
|
186
|
+
- The set of requirements, which are normalized, canonicalized (e.g., `PyYAML` becomes `pyyaml`), and sorted alphabetically to ensure a consistent order.
|
|
187
|
+
- The active Python version tag (e.g., `py3.11`).
|
|
188
|
+
- The selected backend (`uv` or `venv`).
|
|
189
|
+
- A short hash of the current Python interpreter's path to distinguish between different Python installations.
|
|
190
|
+
|
|
191
|
+
This process guarantees that identical dependency sets produce the same virtual environment, while any change in requirements, Python version, or backend results in a new, distinct environment. Named environments (created using the `venv_name` parameter) are not affected by this hashing mechanism.
|
|
192
|
+
|
|
193
|
+
### Venv metadata
|
|
194
|
+
After successful installs, a metadata file `.pydepinject-{timestamp}.json` is written into the venv directory. It records:
|
|
195
|
+
- pydepinject version, backend, Python version, interpreter path
|
|
196
|
+
- Target platform, requested packages, forwarded install args
|
|
197
|
+
- An ISO 8601 timestamp (UTC)
|
|
198
|
+
|
|
199
|
+
There might be multiple metadata files if the venv is reused across different runs with different requirements or install args. Each file is timestamped to avoid collisions.
|
|
200
|
+
|
|
201
|
+
This helps with debugging and reproducibility.
|
|
202
|
+
|
|
203
|
+
## Configuration with Environment Variables
|
|
204
|
+
|
|
205
|
+
`pydepinject` can be configured using the following environment variables:
|
|
206
|
+
|
|
207
|
+
- **`PYDEPINJECT_VENV_ROOT`**: Specifies the root directory where virtual environments are stored. If not set, a default temporary directory is used.
|
|
208
|
+
- **`PYDEPINJECT_VENV_NAME`**: Sets a default name for the virtual environment, which can be useful for creating persistent, reusable environments across different runs.
|
|
209
|
+
- **`PYDEPINJECT_VENV_BACKEND`**: Defines the virtual environment backend to use. Supported values are `uv` and `venv`. `uv` is preferred for its speed.
|
|
210
|
+
|
|
211
|
+
These variables provide a convenient way to standardize behavior in CI/CD pipelines or development environments.
|
|
212
|
+
|
|
213
|
+
## Unit Tests
|
|
214
|
+
|
|
215
|
+
Unit tests are provided to verify the functionality of the `requires`. The tests use `pytest` and cover various scenarios including decorator usage, context manager usage, ephemeral environments, and more.
|
|
216
|
+
|
|
217
|
+
### Running Tests
|
|
218
|
+
|
|
219
|
+
To run the unit tests, ensure you have `pytest` installed, and then execute the following command:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pytest
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
|