pydepinject 0.0.2.dev0__tar.gz → 0.0.4.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.
Files changed (30) hide show
  1. pydepinject-0.0.4.dev0/MANIFEST.in +7 -0
  2. pydepinject-0.0.4.dev0/PKG-INFO +283 -0
  3. pydepinject-0.0.4.dev0/README.md +250 -0
  4. pydepinject-0.0.4.dev0/pyproject.toml +261 -0
  5. pydepinject-0.0.4.dev0/src/pydepinject/__init__.py +356 -0
  6. pydepinject-0.0.4.dev0/src/pydepinject/backends.py +208 -0
  7. pydepinject-0.0.4.dev0/src/pydepinject.egg-info/PKG-INFO +283 -0
  8. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/pydepinject.egg-info/SOURCES.txt +1 -1
  9. pydepinject-0.0.4.dev0/src/pydepinject.egg-info/requires.txt +11 -0
  10. pydepinject-0.0.4.dev0/tests/conftest.py +31 -0
  11. pydepinject-0.0.4.dev0/tests/test_pydepinject.py +478 -0
  12. pydepinject-0.0.2.dev0/MANIFEST.in +0 -4
  13. pydepinject-0.0.2.dev0/PKG-INFO +0 -178
  14. pydepinject-0.0.2.dev0/Readme.md +0 -139
  15. pydepinject-0.0.2.dev0/pyproject.toml +0 -140
  16. pydepinject-0.0.2.dev0/src/pydepinject/__init__.py +0 -235
  17. pydepinject-0.0.2.dev0/src/pydepinject/backends.py +0 -167
  18. pydepinject-0.0.2.dev0/src/pydepinject.egg-info/PKG-INFO +0 -178
  19. pydepinject-0.0.2.dev0/src/pydepinject.egg-info/requires.txt +0 -18
  20. pydepinject-0.0.2.dev0/tests/conftest.py +0 -19
  21. pydepinject-0.0.2.dev0/tests/test_pydepinject.py +0 -270
  22. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/LICENSE +0 -0
  23. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/setup.cfg +0 -0
  24. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/pydepinject.egg-info/dependency_links.txt +0 -0
  25. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/pydepinject.egg-info/top_level.txt +0 -0
  26. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/requirementmanager.egg-info/PKG-INFO +0 -0
  27. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/requirementmanager.egg-info/SOURCES.txt +0 -0
  28. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/requirementmanager.egg-info/dependency_links.txt +0 -0
  29. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/requirementmanager.egg-info/requires.txt +0 -0
  30. {pydepinject-0.0.2.dev0 → pydepinject-0.0.4.dev0}/src/requirementmanager.egg-info/top_level.txt +0 -0
@@ -0,0 +1,7 @@
1
+ graft src
2
+ graft tests
3
+ include LICENSE README.md pyproject.toml
4
+ global-exclude *~ *.py[cod] *.so *.md
5
+ global-exclude tasks/*
6
+ exclude .yamlfmt
7
+ graft build_backend
@@ -0,0 +1,283 @@
1
+ Metadata-Version: 2.4
2
+ Name: pydepinject
3
+ Version: 0.0.4.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.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: packaging>=24.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
+
68
+ print(requests.__version__)
69
+ print(np.__version__)
70
+
71
+
72
+ my_function()
73
+ ```
74
+
75
+ ### Context Manager
76
+
77
+ You can also use the `requires` as a context manager:
78
+
79
+ ```python
80
+ from pydepinject import requires
81
+
82
+
83
+ with requires("requests", "numpy"):
84
+ import requests
85
+ import numpy as np
86
+
87
+ print(requests.__version__)
88
+ print(np.__version__)
89
+ ```
90
+
91
+ ### Virtual Environment with specific name
92
+
93
+ The `requires` can create a virtual environment with a specific name:
94
+
95
+ ```python
96
+ @requires("requests", venv_name="myenv")
97
+ def my_function():
98
+ import requests
99
+
100
+ print(requests.__version__)
101
+
102
+
103
+ with requires("pylint", "requests", venv_name="myenv"):
104
+ import pylint
105
+
106
+ print(pylint.__version__)
107
+ import requests # This is also available here because it was installed in the same virtual environment
108
+
109
+ print(requests.__version__)
110
+
111
+
112
+ # The virtual environment name can also be set as PYDEPINJECT_VENV_NAME environment variable
113
+ import os
114
+
115
+ os.environ["PYDEPINJECT_VENV_NAME"] = "myenv"
116
+
117
+
118
+ @requires("requests")
119
+ def my_function():
120
+ import requests
121
+
122
+ print(requests.__version__)
123
+
124
+
125
+ with requires("pylint", "requests"):
126
+ import pylint
127
+
128
+ print(pylint.__version__)
129
+ import requests # This is also available here because it was installed in the same virtual environment
130
+
131
+ print(requests.__version__)
132
+ ```
133
+
134
+
135
+
136
+ ### Reusable Virtual Environments
137
+
138
+ The `requires` can create named virtual environments and reuse them across multiple functions or code blocks:
139
+
140
+ ```python
141
+ @requires("requests", venv_name="myenv", ephemeral=False)
142
+ def my_function():
143
+ import requests
144
+
145
+ print(requests.__version__)
146
+
147
+
148
+ with requires("pylint", "requests", venv_name="myenv", ephemeral=False):
149
+ import pylint
150
+
151
+ print(pylint.__version__)
152
+ import requests # This is also available here because it was installed in the same virtual environment
153
+
154
+ print(requests.__version__)
155
+ ```
156
+
157
+ ### Managing Virtual Environments
158
+
159
+ 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:
160
+
161
+ ```python
162
+ @requires("requests", venv_name="myenv", ephemeral=True)
163
+ def my_function():
164
+ import requests
165
+
166
+ print(requests.__version__)
167
+
168
+
169
+ my_function()
170
+ ```
171
+
172
+ ### Forcing Virtual Environment Recreation
173
+
174
+ 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.
175
+
176
+ ```python
177
+ from pydepinject import requires
178
+
179
+
180
+ # This will delete the "my-clean-env" venv if it exists and create it from scratch
181
+ @requires("requests", venv_name="my-clean-env", recreate=True)
182
+ def my_function():
183
+ import requests
184
+
185
+ print(requests.__version__)
186
+
187
+
188
+ my_function()
189
+ ```
190
+
191
+ ## Logging
192
+
193
+ 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:
194
+
195
+ ```python
196
+ import logging
197
+
198
+ logging.basicConfig(level=logging.INFO) # or DEBUG for verbose output
199
+ logging.getLogger("pydepinject").setLevel(logging.DEBUG)
200
+ ```
201
+
202
+ You can also integrate with your application's logging setup (structlog, rich logging, etc.) by attaching handlers as you normally would.
203
+ ## Backend selection
204
+
205
+ 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.
206
+
207
+ You can control backend selection:
208
+ - Environment variable: set PYDEPINJECT_VENV_BACKEND, e.g. `PYDEPINJECT_VENV_BACKEND=venv` or `PYDEPINJECT_VENV_BACKEND=uv|venv`.
209
+ - API param: pass `venv_backend="uv"`, `"venv"`, or a pipe-separated list like `"uv|venv"` to requires/RequirementManager.
210
+
211
+ On Windows, paths (Scripts, Lib/site-packages) are handled automatically.
212
+
213
+ ## Advanced options
214
+
215
+ ### Additional installer arguments
216
+ 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.
217
+
218
+ ```python
219
+ from pydepinject import requires
220
+
221
+
222
+ @requires(
223
+ "requests",
224
+ install_args=(
225
+ "--index-url",
226
+ "https://pypi.myorg/simple",
227
+ "--upgrade-strategy",
228
+ "eager",
229
+ ),
230
+ venv_backend="venv",
231
+ )
232
+ def my_function():
233
+ import requests
234
+
235
+ print(requests.__version__)
236
+ ```
237
+
238
+ These arguments are appended to the installer command.
239
+
240
+ ### Virtual environment identity
241
+ For unnamed environments, a unique directory is generated based on a stable identity key. This key is derived from:
242
+ - The set of requirements, which are normalized, canonicalized (e.g., `PyYAML` becomes `pyyaml`), and sorted alphabetically to ensure a consistent order.
243
+ - The active Python version tag (e.g., `py3.11`).
244
+ - The selected backend (`uv` or `venv`).
245
+ - A short hash of the current Python interpreter's path to distinguish between different Python installations.
246
+
247
+ 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.
248
+
249
+ ### Venv metadata
250
+ After successful installs, a metadata file `.pydepinject-{timestamp}.json` is written into the venv directory. It records:
251
+ - pydepinject version, backend, Python version, interpreter path
252
+ - Target platform, requested packages, forwarded install args
253
+ - An ISO 8601 timestamp (UTC)
254
+
255
+ 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.
256
+
257
+ This helps with debugging and reproducibility.
258
+
259
+ ## Configuration with Environment Variables
260
+
261
+ `pydepinject` can be configured using the following environment variables:
262
+
263
+ - **`PYDEPINJECT_VENV_ROOT`**: Specifies the root directory where virtual environments are stored. If not set, a default temporary directory is used.
264
+ - **`PYDEPINJECT_VENV_NAME`**: Sets a default name for the virtual environment, which can be useful for creating persistent, reusable environments across different runs.
265
+ - **`PYDEPINJECT_VENV_BACKEND`**: Defines the virtual environment backend to use. Supported values are `uv` and `venv`. `uv` is preferred for its speed.
266
+
267
+ These variables provide a convenient way to standardize behavior in CI/CD pipelines or development environments.
268
+
269
+ ## Unit Tests
270
+
271
+ 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.
272
+
273
+ ### Running Tests
274
+
275
+ To run the unit tests, ensure you have `pytest` installed, and then execute the following command:
276
+
277
+ ```bash
278
+ pytest
279
+ ```
280
+
281
+ ## License
282
+
283
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
@@ -0,0 +1,250 @@
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
+
35
+ print(requests.__version__)
36
+ print(np.__version__)
37
+
38
+
39
+ my_function()
40
+ ```
41
+
42
+ ### Context Manager
43
+
44
+ You can also use the `requires` as a context manager:
45
+
46
+ ```python
47
+ from pydepinject import requires
48
+
49
+
50
+ with requires("requests", "numpy"):
51
+ import requests
52
+ import numpy as np
53
+
54
+ print(requests.__version__)
55
+ print(np.__version__)
56
+ ```
57
+
58
+ ### Virtual Environment with specific name
59
+
60
+ The `requires` can create a virtual environment with a specific name:
61
+
62
+ ```python
63
+ @requires("requests", venv_name="myenv")
64
+ def my_function():
65
+ import requests
66
+
67
+ print(requests.__version__)
68
+
69
+
70
+ with requires("pylint", "requests", venv_name="myenv"):
71
+ import pylint
72
+
73
+ print(pylint.__version__)
74
+ import requests # This is also available here because it was installed in the same virtual environment
75
+
76
+ print(requests.__version__)
77
+
78
+
79
+ # The virtual environment name can also be set as PYDEPINJECT_VENV_NAME environment variable
80
+ import os
81
+
82
+ os.environ["PYDEPINJECT_VENV_NAME"] = "myenv"
83
+
84
+
85
+ @requires("requests")
86
+ def my_function():
87
+ import requests
88
+
89
+ print(requests.__version__)
90
+
91
+
92
+ with requires("pylint", "requests"):
93
+ import pylint
94
+
95
+ print(pylint.__version__)
96
+ import requests # This is also available here because it was installed in the same virtual environment
97
+
98
+ print(requests.__version__)
99
+ ```
100
+
101
+
102
+
103
+ ### Reusable Virtual Environments
104
+
105
+ The `requires` can create named virtual environments and reuse them across multiple functions or code blocks:
106
+
107
+ ```python
108
+ @requires("requests", venv_name="myenv", ephemeral=False)
109
+ def my_function():
110
+ import requests
111
+
112
+ print(requests.__version__)
113
+
114
+
115
+ with requires("pylint", "requests", venv_name="myenv", ephemeral=False):
116
+ import pylint
117
+
118
+ print(pylint.__version__)
119
+ import requests # This is also available here because it was installed in the same virtual environment
120
+
121
+ print(requests.__version__)
122
+ ```
123
+
124
+ ### Managing Virtual Environments
125
+
126
+ 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:
127
+
128
+ ```python
129
+ @requires("requests", venv_name="myenv", ephemeral=True)
130
+ def my_function():
131
+ import requests
132
+
133
+ print(requests.__version__)
134
+
135
+
136
+ my_function()
137
+ ```
138
+
139
+ ### Forcing Virtual Environment Recreation
140
+
141
+ 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.
142
+
143
+ ```python
144
+ from pydepinject import requires
145
+
146
+
147
+ # This will delete the "my-clean-env" venv if it exists and create it from scratch
148
+ @requires("requests", venv_name="my-clean-env", recreate=True)
149
+ def my_function():
150
+ import requests
151
+
152
+ print(requests.__version__)
153
+
154
+
155
+ my_function()
156
+ ```
157
+
158
+ ## Logging
159
+
160
+ 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:
161
+
162
+ ```python
163
+ import logging
164
+
165
+ logging.basicConfig(level=logging.INFO) # or DEBUG for verbose output
166
+ logging.getLogger("pydepinject").setLevel(logging.DEBUG)
167
+ ```
168
+
169
+ You can also integrate with your application's logging setup (structlog, rich logging, etc.) by attaching handlers as you normally would.
170
+ ## Backend selection
171
+
172
+ 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.
173
+
174
+ You can control backend selection:
175
+ - Environment variable: set PYDEPINJECT_VENV_BACKEND, e.g. `PYDEPINJECT_VENV_BACKEND=venv` or `PYDEPINJECT_VENV_BACKEND=uv|venv`.
176
+ - API param: pass `venv_backend="uv"`, `"venv"`, or a pipe-separated list like `"uv|venv"` to requires/RequirementManager.
177
+
178
+ On Windows, paths (Scripts, Lib/site-packages) are handled automatically.
179
+
180
+ ## Advanced options
181
+
182
+ ### Additional installer arguments
183
+ 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.
184
+
185
+ ```python
186
+ from pydepinject import requires
187
+
188
+
189
+ @requires(
190
+ "requests",
191
+ install_args=(
192
+ "--index-url",
193
+ "https://pypi.myorg/simple",
194
+ "--upgrade-strategy",
195
+ "eager",
196
+ ),
197
+ venv_backend="venv",
198
+ )
199
+ def my_function():
200
+ import requests
201
+
202
+ print(requests.__version__)
203
+ ```
204
+
205
+ These arguments are appended to the installer command.
206
+
207
+ ### Virtual environment identity
208
+ For unnamed environments, a unique directory is generated based on a stable identity key. This key is derived from:
209
+ - The set of requirements, which are normalized, canonicalized (e.g., `PyYAML` becomes `pyyaml`), and sorted alphabetically to ensure a consistent order.
210
+ - The active Python version tag (e.g., `py3.11`).
211
+ - The selected backend (`uv` or `venv`).
212
+ - A short hash of the current Python interpreter's path to distinguish between different Python installations.
213
+
214
+ 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.
215
+
216
+ ### Venv metadata
217
+ After successful installs, a metadata file `.pydepinject-{timestamp}.json` is written into the venv directory. It records:
218
+ - pydepinject version, backend, Python version, interpreter path
219
+ - Target platform, requested packages, forwarded install args
220
+ - An ISO 8601 timestamp (UTC)
221
+
222
+ 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.
223
+
224
+ This helps with debugging and reproducibility.
225
+
226
+ ## Configuration with Environment Variables
227
+
228
+ `pydepinject` can be configured using the following environment variables:
229
+
230
+ - **`PYDEPINJECT_VENV_ROOT`**: Specifies the root directory where virtual environments are stored. If not set, a default temporary directory is used.
231
+ - **`PYDEPINJECT_VENV_NAME`**: Sets a default name for the virtual environment, which can be useful for creating persistent, reusable environments across different runs.
232
+ - **`PYDEPINJECT_VENV_BACKEND`**: Defines the virtual environment backend to use. Supported values are `uv` and `venv`. `uv` is preferred for its speed.
233
+
234
+ These variables provide a convenient way to standardize behavior in CI/CD pipelines or development environments.
235
+
236
+ ## Unit Tests
237
+
238
+ 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.
239
+
240
+ ### Running Tests
241
+
242
+ To run the unit tests, ensure you have `pytest` installed, and then execute the following command:
243
+
244
+ ```bash
245
+ pytest
246
+ ```
247
+
248
+ ## License
249
+
250
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.