csspin-python 6.0.1__py3-none-any.whl → 6.1.0__py3-none-any.whl

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.
csspin_python/pytest.py CHANGED
@@ -55,6 +55,8 @@ defaults = config(
55
55
 
56
56
  def _install_playwright_browsers(cfg: ConfigTree) -> None:
57
57
  """Let playwright install the browsers"""
58
+ if cfg.pytest.playwright.mirror:
59
+ setenv(PLAYWRIGHT_DOWNLOAD_HOST=cfg.pytest.playwright.mirror)
58
60
  sh(
59
61
  f"playwright install {' '.join(cfg.pytest.playwright.browsers)}",
60
62
  env={"PLAYWRIGHT_BROWSERS_PATH": cfg.pytest.playwright.browsers_path},
@@ -28,7 +28,7 @@ pytest:
28
28
  playwright:
29
29
  type: object
30
30
  help: |
31
- Settings necessary to also run playwright tests with the pytest
31
+ Settings necessary to also run Playwright tests with the pytest
32
32
  plugin.
33
33
  properties:
34
34
  enabled:
@@ -38,9 +38,15 @@ pytest:
38
38
  initialized.
39
39
  browsers_path:
40
40
  type: path
41
- help: Path for playwright to install the browsers.
41
+ help: Path for Playwright to install the browsers.
42
42
  browsers:
43
43
  type: list
44
44
  help: |
45
45
  The browsers to install and to use for running the
46
- playwright tests.
46
+ Playwright tests.
47
+ mirror:
48
+ type: str
49
+ help: |
50
+ Host to download the Playwright browsers from. The
51
+ mirror has to hold the files for the Playwright version
52
+ in use.
csspin_python/python.py CHANGED
@@ -68,7 +68,9 @@ point to the base installation.
68
68
 
69
69
  import abc
70
70
  import configparser
71
+ import contextlib
71
72
  import hashlib
73
+ import inspect
72
74
  import json
73
75
  import logging
74
76
  import os
@@ -125,6 +127,9 @@ from csspin import (
125
127
  )
126
128
  from csspin.tree import ConfigTree
127
129
 
130
+ # csspin's plugin development guide, for warnings pointing to its sections
131
+ _PLUGIN_GUIDE_URL = "https://csspin.readthedocs.io/en/stable/howtoplugins.html"
132
+
128
133
  defaults = config(
129
134
  build_wheels=["{spin.project_root}"],
130
135
  pyenv=config(
@@ -256,6 +261,8 @@ def pyenv_install(cfg: ConfigTree) -> None:
256
261
  sh("git", "pull")
257
262
  # we should set
258
263
  setenv(PYTHON_BUILD_CACHE_PATH=mkdir(cfg.python.pyenv.cache))
264
+ if cfg.python.pyenv.mirror:
265
+ setenv(PYTHON_BUILD_MIRROR_URL=cfg.python.pyenv.mirror)
259
266
  setenv(PYTHON_CFLAGS="-DOPENSSL_NO_COMP")
260
267
  try:
261
268
  sh(
@@ -293,6 +300,8 @@ def nuget_install(cfg: ConfigTree) -> None:
293
300
  "-mpip",
294
301
  None if cfg.verbosity > Verbosity.NORMAL else "-q",
295
302
  "install",
303
+ f"--index-url={cfg.python.index_url}",
304
+ *[f"--extra-index-url={url}" for url in cfg.python.extra_index_urls],
296
305
  "-U",
297
306
  "pip",
298
307
  "wheel",
@@ -414,14 +423,13 @@ def configure(cfg: ConfigTree) -> None:
414
423
  if cfg.python.aws_auth.enabled:
415
424
  _check_aws_token_validity(cfg)
416
425
 
417
- # Provide spin's subprocess environment (see python_env). Registered here
418
- # rather than in init so it is also available to the provision and
419
- # finalize_provision hooks of plugins depending on this one.
420
- cfg.spin.subprocess_environment = lambda: python_env(cfg)
421
-
422
426
 
423
427
  def init(cfg: ConfigTree) -> None:
424
- """Initialize the python plugin"""
428
+ """Initialize the python plugin and activate the virtual environment.
429
+
430
+ Runs before spin executes tasks, and during 'spin provision' as soon as the
431
+ virtual environment has been created (see venv_provision).
432
+ """
425
433
  if not cfg.python.use:
426
434
  logging.debug("Checking for %s", cfg.python.interpreter)
427
435
  if not exists(cfg.python.interpreter):
@@ -430,6 +438,36 @@ def init(cfg: ConfigTree) -> None:
430
438
  " project. You might want to run spin with the 'provision'"
431
439
  " task."
432
440
  )
441
+ activate(cfg)
442
+
443
+
444
+ def activate(cfg: ConfigTree) -> None:
445
+ """Activate the virtual environment for the processes spin starts, like its
446
+ 'activate' script does in a shell.
447
+
448
+ This only sets environment variables. It must never change spin's own
449
+ sys.path or sys.prefix (e.g. by executing 'activate_this.py'): plugin code
450
+ must not import from the project's virtual environment, which may use
451
+ another Python version (see "Outer and inner interpreter" in csspin's plugin
452
+ development guide).
453
+ """
454
+ venv = str(cfg.python.venv)
455
+ if os.environ.get("VIRTUAL_ENV") == venv:
456
+ return
457
+ if not exists(cfg.python.scriptdir):
458
+ die(
459
+ f"{cfg.python.venv} does not exist. You may want to provision"
460
+ " it using 'spin provision'"
461
+ )
462
+ if sys.platform == "win32":
463
+ echo(f"{cfg.python.scriptdir}\\activate.ps1")
464
+ else:
465
+ echo(f". {cfg.python.scriptdir}/activate")
466
+ os.environ["PATH"] = os.pathsep.join(
467
+ (str(cfg.python.scriptdir), os.environ.get("PATH", ""))
468
+ )
469
+ os.environ["VIRTUAL_ENV"] = venv
470
+ os.environ.pop("PYTHONHOME", None)
433
471
 
434
472
 
435
473
  def venv_init(cfg: ConfigTree) -> None:
@@ -450,25 +488,46 @@ def venv_init(cfg: ConfigTree) -> None:
450
488
  )
451
489
 
452
490
 
491
+ def _caller_location() -> str:
492
+ """Return 'file:line' of the innermost caller outside this module and
493
+ contextlib, i.e. the plugin code using one of our functions."""
494
+ skip = {os.path.normcase(__file__), os.path.normcase(contextlib.__file__)}
495
+ frame = inspect.currentframe()
496
+ try:
497
+ while frame is not None:
498
+ filename = frame.f_code.co_filename
499
+ if os.path.normcase(filename) not in skip:
500
+ return f"{filename}:{frame.f_lineno}"
501
+ frame = frame.f_back
502
+ return "<unknown>"
503
+ finally:
504
+ del frame
505
+
506
+
453
507
  @contextmanager
454
508
  def python_env(cfg: ConfigTree) -> Generator:
455
509
  """
456
- Context manager to activate the subprocess/python virtual environment and
457
- deactivate it once done.
458
-
459
- Registered as ``spin.subprocess_environment`` by the plugin's
460
- :py:func:`configure` hook, so ``csspin.sh`` activates the virtual environment
461
- around the commands it spawns. Activation is conditional: while the virtual
462
- environment has not been created yet (e.g. early during ``spin provision``)
463
- this is a no-op and the command runs in spin's in-process environment; once
464
- the venv exists it is activated. Saving and restoring
465
- ``os.environ``, ``sys.path`` and the ``sys`` prefix attributes makes nesting
466
- safe -- an explicit ``with python_env(cfg):`` block whose inner ``csspin.sh``
467
- re-enters this context.
468
-
469
- See the "The subprocess environment" section of csspin's plugin development
470
- guide for the general concept.
510
+ Context manager activating the virtual environment *in spin's process*,
511
+ including its sys.path, and deactivating it once done.
512
+
513
+ .. deprecated::
514
+ Plugin code must not import from the project's virtual environment,
515
+ which may use another Python version than spin (see "Outer and inner
516
+ interpreter" in csspin's plugin development guide). The virtual
517
+ environment is activated for the processes spin starts by
518
+ :py:func:`activate` already. Make modules a plugin imports dependencies
519
+ of its plugin package, or run the tools from the virtual environment as
520
+ subprocesses. This function will be removed in a future release.
521
+
522
+ Saving and restoring ``os.environ``, ``sys.path`` and the ``sys`` prefix
523
+ attributes makes nesting safe.
471
524
  """
525
+ warn(
526
+ f"{_caller_location()} uses csspin_python.python.python_env(), which is"
527
+ " deprecated and will be removed: plugin code must not import from the"
528
+ " project's virtual environment."
529
+ f" See {_PLUGIN_GUIDE_URL}#outer-and-inner-interpreter."
530
+ )
472
531
  if not exists(cfg.python.scriptdir / "activate_this.py"):
473
532
  # The virtual environment has not been provisioned (yet); run the command
474
533
  # in spin's in-process environment instead of activating.
@@ -891,12 +950,17 @@ class ProvisionerProtocol:
891
950
  ]
892
951
  virtualenv = Command(*cmd)
893
952
  # do not download seeds, since we update pip later anyway
894
- # add the plugins directory to the PYTHONPATH so that virtualenv will be found
953
+ # add the plugin packages to the PYTHONPATH so that virtualenv will be
954
+ # found; csspin versions without spin.plugin_site_packages install
955
+ # them into the plugins directory itself
956
+ plugin_site_packages = cfg.spin.get("plugin_site_packages") or (
957
+ cfg.spin.spin_dir / "plugins"
958
+ )
895
959
  virtualenv(
896
960
  "-p",
897
961
  cfg.python.interpreter,
898
962
  cfg.python.venv,
899
- env={"PYTHONPATH": cfg.spin.spin_dir / "plugins"},
963
+ env={"PYTHONPATH": plugin_site_packages},
900
964
  )
901
965
 
902
966
  def prerequisites(self: Self, cfg: ConfigTree) -> None:
@@ -133,7 +133,7 @@ def _ensure_cyclonedx_venv(cfg: ConfigTree, binary_dir: str, quiet: str | None)
133
133
  )
134
134
  rmtree(venv_cdx)
135
135
 
136
- sh(cfg.python.interpreter, "-m", "venv", venv_cdx, use_subprocess_environment=False)
136
+ sh(cfg.python.interpreter, "-m", "venv", venv_cdx)
137
137
  sh(
138
138
  interpreter_cdx,
139
139
  "-m",
@@ -145,7 +145,6 @@ def _ensure_cyclonedx_venv(cfg: ConfigTree, binary_dir: str, quiet: str | None)
145
145
  cfg.python.index_url,
146
146
  *[f"--extra-index-url={url}" for url in cfg.python.extra_index_urls],
147
147
  "cyclonedx-bom==" + requested_version,
148
- use_subprocess_environment=False,
149
148
  )
150
149
  with memoizer(memo_file) as memo:
151
150
  memo.add(memo_key)
@@ -167,15 +166,19 @@ def _run_cyclonedx(cfg: ConfigTree, third_party_deps: set[str], stderr: int) ->
167
166
  # Run --upgrade-deps and set PIP_CONSTRAINT to force pip and setuptools
168
167
  # to have the version from the constraint files, if they are present.
169
168
  # Necessary as python3.11 still has setuptools in the env created by
170
- # venv.
169
+ # venv. PIP_INDEX_URL and PIP_EXTRA_INDEX_URL point the upgrade at the
170
+ # configured indexes, because venv has no index option.
171
171
  sh(
172
172
  cfg.python.interpreter,
173
173
  "-m",
174
174
  "venv",
175
175
  "--upgrade-deps",
176
176
  venv,
177
- use_subprocess_environment=False,
178
- env={"PIP_CONSTRAINT": " ".join(cfg.python.constraints)},
177
+ env={
178
+ "PIP_CONSTRAINT": " ".join(cfg.python.constraints),
179
+ "PIP_INDEX_URL": cfg.python.index_url,
180
+ "PIP_EXTRA_INDEX_URL": " ".join(cfg.python.extra_index_urls),
181
+ },
179
182
  )
180
183
  if third_party_deps:
181
184
  sh(
@@ -192,7 +195,6 @@ def _run_cyclonedx(cfg: ConfigTree, third_party_deps: set[str], stderr: int) ->
192
195
  for constraint in cfg.python.constraints
193
196
  ],
194
197
  *third_party_deps,
195
- use_subprocess_environment=False,
196
198
  stderr=stderr,
197
199
  )
198
200
  sh(
@@ -203,7 +205,6 @@ def _run_cyclonedx(cfg: ConfigTree, third_party_deps: set[str], stderr: int) ->
203
205
  "uninstall",
204
206
  "-y",
205
207
  "pip",
206
- use_subprocess_environment=False,
207
208
  )
208
209
  return backtick( # type: ignore[no-any-return]
209
210
  interpreter_cdx,
@@ -213,7 +214,6 @@ def _run_cyclonedx(cfg: ConfigTree, third_party_deps: set[str], stderr: int) ->
213
214
  "--spec-version",
214
215
  cfg.python_sbom.spec_version,
215
216
  venv,
216
- use_subprocess_environment=False,
217
217
  stderr=stderr,
218
218
  )
219
219
 
@@ -19,6 +19,12 @@ python:
19
19
  cache:
20
20
  type: path
21
21
  help: Path to cache the Python sources downloaded by pyenv
22
+ mirror:
23
+ type: str
24
+ help: |
25
+ Base URL of a mirror for the Python sources downloaded
26
+ by pyenv. Ignored on Windows and when 'python.use' or
27
+ 'python.user_pyenv' is set.
22
28
  python_build:
23
29
  type: path
24
30
  help: Path to the python-build builtin plugin of pyenv
@@ -114,8 +120,9 @@ python:
114
120
  type: str
115
121
  help: |
116
122
  The index url from where packages should get installed into the
117
- venv. This value will also be put into cfg.python.pipconf, if
118
- not already mentioned there.
123
+ project's subprocess environment (i.e., 'python.venv'). This
124
+ value will also be put into 'python.pipconf', if not already
125
+ mentioned there.
119
126
  extra_index_urls:
120
127
  type: list
121
128
  help: |
@@ -145,6 +145,11 @@ class SimpleUvProvisioner(SimpleProvisioner):
145
145
  cfg.python.version,
146
146
  "--no-bin",
147
147
  "--no-registry",
148
+ (
149
+ f"--mirror={cfg.uv_provisioner.python_mirror}"
150
+ if cfg.uv_provisioner.python_mirror
151
+ else None
152
+ ),
148
153
  )
149
154
  cfg.python.interpreter = _get_uv_python(cfg)
150
155
  info(f"Using '{cfg.python.interpreter}' as interpreter")
@@ -158,7 +163,10 @@ class SimpleUvProvisioner(SimpleProvisioner):
158
163
  )
159
164
 
160
165
  def prerequisites(self, cfg: ConfigTree) -> None:
161
- self._uv_cmd("pip", "install", "pip")
166
+ # venv_provision runs the venv_hook only after the prerequisites, but
167
+ # installing pip already needs the uv.toml.
168
+ _configure_uv_toml(cfg)
169
+ self._install_command(f"--config-file={cfg.uv_provisioner.uv_toml_path}", "pip")
162
170
 
163
171
 
164
172
  def _set_extra_index_url(toml_content: dict, extra_index_urls: list[str]) -> None:
@@ -22,3 +22,10 @@ uv_provisioner:
22
22
  uv_toml:
23
23
  type: str
24
24
  help: Content for uv's config file
25
+ python_mirror:
26
+ type: str
27
+ help: |
28
+ Passed to 'uv python install' as '--mirror' when uv provisions
29
+ the Python interpreter. The mirror has to hold the files for
30
+ the uv version in use. Ignored when 'python.use' is set.
31
+ default: ''
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csspin-python
3
- Version: 6.0.1
3
+ Version: 6.1.0
4
4
  Summary: Plugin-package for csspin providing Python related plugins
5
5
  Author-email: CONTACT Software GmbH <info@contact-software.com>
6
6
  Maintainer-email: Waleri Enns <waleri.enns@contact-software.com>, Benjamin Thomas Schwertfeger <benjaminthomas.schwertfeger@contact-software.com>, Fabian Hafer <fabian.hafer@contact-software.com>
@@ -7,18 +7,18 @@ csspin_python/devpi.py,sha256=o7O06Dw-xt47y-M74TShcl9MUMaW78aFmw6i6ISYwoU,2351
7
7
  csspin_python/devpi_schema.yaml,sha256=2gPATWjVcfvCTrGZX2FK6wH8hh9KS0XzZ35JvZeJGEU,487
8
8
  csspin_python/playwright.py,sha256=oFfphLqa4AB6K9vasCUFHN0kFXu63n3ocrsqVuRp4-0,5102
9
9
  csspin_python/playwright_schema.yaml,sha256=TSeR16YHa7m7bfO59F2eMV-jXcglluTJdEpUeL16saY,1178
10
- csspin_python/pytest.py,sha256=vSLtmS-kNO0NPo_tszfEm5zGwJb6Yb5IGS-hA7CNguo,4544
11
- csspin_python/pytest_schema.yaml,sha256=tzXtdF6MvGC9v59EVRJFfLeMMHqPsXcFXy2zJtRECBI,1535
12
- csspin_python/python.py,sha256=uoWCm_X2_yGaOdnxAb_h2Mr8RjLd5MjuVL4cPF15E2E,41973
13
- csspin_python/python_sbom.py,sha256=l80mNwrIe3uK0F_3nnob_tY9EVunsWhrOlQHhYAMt3U,14523
10
+ csspin_python/pytest.py,sha256=wnQLHz5kmZKwv0acPt3d3gx91xVxI2qHCOOivl1Oq-Y,4651
11
+ csspin_python/pytest_schema.yaml,sha256=YsJ_O6wjaZARhfx0AU-Ska55qNpfkHtShrKUxgh3UiI,1804
12
+ csspin_python/python.py,sha256=XDl2c5dyu0IU8qAoRAvBRVPFMgb6RVjnuGCyTpJlf5E,44456
13
+ csspin_python/python_sbom.py,sha256=_DyH3dd9jdBxdP74RFb2L5hNPjNLWnRvFlotL4DFUqA,14550
14
14
  csspin_python/python_sbom_schema.yaml,sha256=kxz5TJdUmUkDwG6ZD9ORi7xj-yF_BjeMhjmsj6labgM,856
15
- csspin_python/python_schema.yaml,sha256=RwJgbyIRenj18-s60HmqkwWCGtd6G1acpJ9TDI9QjBQ,6448
15
+ csspin_python/python_schema.yaml,sha256=jAo2pX5ZqyUol-rn0x4ctIJAVU-Ni1jnn44TJmZVe_0,6803
16
16
  csspin_python/radon.py,sha256=uFqm6FEi5oWj-_XVaAm3s9cam0cUmr1_FwRf40K6xWs,1876
17
17
  csspin_python/radon_schema.yaml,sha256=rlRzXw5z4XbjOVznRiUxWGP4E9hx1Jm-gGw1iQiYzE0,548
18
- csspin_python/uv_provisioner.py,sha256=2M1I8PqWTCUxqaOeJI5rchmly6t-MnOPQfIx-kKzdQU,6757
19
- csspin_python/uv_provisioner_schema.yaml,sha256=Y8ZNC2OMnhR8Us3WUXAXK9hMjqGWAKFJB2puX4X5XNQ,727
20
- csspin_python-6.0.1.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
21
- csspin_python-6.0.1.dist-info/METADATA,sha256=AHEvlyahGD-q_aY2O8HE7A35QGVDtM8LOKrdfKyz1mk,5254
22
- csspin_python-6.0.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
23
- csspin_python-6.0.1.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
24
- csspin_python-6.0.1.dist-info/RECORD,,
18
+ csspin_python/uv_provisioner.py,sha256=jMdhoJDnpxALXliHNIDdrYFXOxlLJY1YMsssJlVhR_0,7132
19
+ csspin_python/uv_provisioner_schema.yaml,sha256=uvrkC1Ct4NDMzGSpwC2fmX_6MvoQtk59hIeRtAmcsKg,1045
20
+ csspin_python-6.1.0.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
21
+ csspin_python-6.1.0.dist-info/METADATA,sha256=JweD4VDTWLzmH4iHtr2WwSmQvvYoqPF9b_raU1K1_60,5254
22
+ csspin_python-6.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
23
+ csspin_python-6.1.0.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
24
+ csspin_python-6.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (84.0.0)
2
+ Generator: setuptools (84.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5