csspin-python 3.1.0__py3-none-any.whl → 3.2.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/python.py +84 -62
- csspin_python/python_schema.yaml +11 -1
- csspin_python/uv_provisioner.py +1 -1
- {csspin_python-3.1.0.dist-info → csspin_python-3.2.0.dist-info}/METADATA +6 -2
- {csspin_python-3.1.0.dist-info → csspin_python-3.2.0.dist-info}/RECORD +8 -8
- {csspin_python-3.1.0.dist-info → csspin_python-3.2.0.dist-info}/WHEEL +0 -0
- {csspin_python-3.1.0.dist-info → csspin_python-3.2.0.dist-info}/licenses/LICENSE +0 -0
- {csspin_python-3.1.0.dist-info → csspin_python-3.2.0.dist-info}/top_level.txt +0 -0
csspin_python/python.py
CHANGED
|
@@ -74,9 +74,10 @@ import os
|
|
|
74
74
|
import re
|
|
75
75
|
import shutil
|
|
76
76
|
import sys
|
|
77
|
+
from contextlib import contextmanager
|
|
77
78
|
from subprocess import check_output
|
|
78
79
|
from textwrap import dedent, indent
|
|
79
|
-
from typing import Iterable, Type, Union
|
|
80
|
+
from typing import Generator, Iterable, Type, Union
|
|
80
81
|
|
|
81
82
|
try:
|
|
82
83
|
from typing import Self # type: ignore[attr-defined]
|
|
@@ -159,33 +160,13 @@ defaults = config(
|
|
|
159
160
|
key_duration=3600 * 10, # 10 hours
|
|
160
161
|
static_oidc=False,
|
|
161
162
|
index="16.0/simple",
|
|
163
|
+
# Need to set client secret to empty string, otherwise the string "None"
|
|
164
|
+
# would be handled as secret and obfucsated in logs.
|
|
165
|
+
client_secret="", # nosec: B106
|
|
162
166
|
),
|
|
163
167
|
index_url="https://pypi.org/simple",
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
system=config(
|
|
167
|
-
debian=config(
|
|
168
|
-
apt=[
|
|
169
|
-
"build-essential",
|
|
170
|
-
"curl",
|
|
171
|
-
"git",
|
|
172
|
-
"libbz2-dev",
|
|
173
|
-
"libffi-dev",
|
|
174
|
-
"libkrb5-dev",
|
|
175
|
-
"liblzma-dev",
|
|
176
|
-
"libncursesw5-dev",
|
|
177
|
-
"libreadline-dev",
|
|
178
|
-
"libsqlite3-dev",
|
|
179
|
-
"libssl-dev",
|
|
180
|
-
"libxml2-dev",
|
|
181
|
-
"libxmlsec1-dev",
|
|
182
|
-
"make",
|
|
183
|
-
"xz-utils",
|
|
184
|
-
"zlib1g-dev",
|
|
185
|
-
]
|
|
186
|
-
)
|
|
187
|
-
),
|
|
188
|
-
),
|
|
168
|
+
skip_js_build=None,
|
|
169
|
+
requires=config(python=["build", "wheel"]),
|
|
189
170
|
)
|
|
190
171
|
|
|
191
172
|
|
|
@@ -310,12 +291,23 @@ def nuget_install(cfg: ConfigTree) -> None:
|
|
|
310
291
|
|
|
311
292
|
def provision(cfg: ConfigTree) -> None:
|
|
312
293
|
"""Provision the python plugin"""
|
|
294
|
+
if not cfg.python.use and exists(cfg.python.python):
|
|
295
|
+
python_version = (
|
|
296
|
+
check_output([cfg.python.python, "--version"])
|
|
297
|
+
.decode()
|
|
298
|
+
.strip()
|
|
299
|
+
.replace("Python ", "")
|
|
300
|
+
)
|
|
301
|
+
if python_version and not python_version.startswith(cfg.python.version):
|
|
302
|
+
_cleanup_memoed_provisioners(cfg)
|
|
303
|
+
rmtree(cfg.python.provisioner_memo)
|
|
304
|
+
rmtree(cfg.python.aws_auth.memo)
|
|
305
|
+
rmtree(cfg.python.venv)
|
|
313
306
|
with memoizer(cfg.python.provisioner_memo) as memo:
|
|
314
307
|
if cfg.python.provisioner is None:
|
|
315
308
|
cfg.python.provisioner = SimpleProvisioner(cfg)
|
|
316
309
|
if not memo.check(cfg.python.provisioner):
|
|
317
310
|
memo.add(cfg.python.provisioner)
|
|
318
|
-
|
|
319
311
|
if not shutil.which(cfg.python.interpreter):
|
|
320
312
|
cfg.python.provisioner.provision_python(cfg)
|
|
321
313
|
|
|
@@ -353,6 +345,10 @@ def configure(cfg: ConfigTree) -> None:
|
|
|
353
345
|
|
|
354
346
|
if exists(cfg.python.python):
|
|
355
347
|
cfg.python.site_packages = get_site_packages(interpreter=cfg.python.python)
|
|
348
|
+
# Built JS should still be available in this case
|
|
349
|
+
# Skip only if users hasn't explicitly set it to False
|
|
350
|
+
if cfg.python.skip_js_build is None:
|
|
351
|
+
cfg.python.skip_js_build = True
|
|
356
352
|
|
|
357
353
|
if cfg.python.aws_auth.enabled:
|
|
358
354
|
_check_aws_token_validity(cfg)
|
|
@@ -831,13 +827,31 @@ class SimpleProvisioner(ProvisionerProtocol):
|
|
|
831
827
|
)
|
|
832
828
|
|
|
833
829
|
def install(self: Self, cfg: ConfigTree) -> None:
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
830
|
+
@contextmanager
|
|
831
|
+
def skip_js_build(cfg: ConfigTree) -> Generator[None, None, None]:
|
|
832
|
+
if cfg.python.skip_js_build:
|
|
833
|
+
try:
|
|
834
|
+
setenv(SETUPTOOLS_CE_BUILD_JS_SKIP=1)
|
|
835
|
+
yield
|
|
836
|
+
setenv(SETUPTOOLS_CE_BUILD_JS_SKIP=None)
|
|
837
|
+
finally:
|
|
838
|
+
# Make sure the variable will not be written into the
|
|
839
|
+
# activation scripts
|
|
840
|
+
global EXPORTS # pylint: disable=global-statement
|
|
841
|
+
EXPORTS = [
|
|
842
|
+
(k, v) for k, v in EXPORTS if k != "SETUPTOOLS_CE_BUILD_JS_SKIP"
|
|
843
|
+
]
|
|
844
|
+
else:
|
|
845
|
+
yield
|
|
846
|
+
|
|
847
|
+
with skip_js_build(cfg):
|
|
848
|
+
if self._m.items():
|
|
849
|
+
self._install_command("--upgrade", *self._split(self._requirements))
|
|
850
|
+
else:
|
|
851
|
+
self._install_command(*self._split(self._requirements))
|
|
852
|
+
self._m.clear()
|
|
853
|
+
for req in self._requirements:
|
|
854
|
+
self._m.add(_req_for_memo(req, cfg.spin.project_root))
|
|
841
855
|
|
|
842
856
|
@staticmethod
|
|
843
857
|
def _split(requirements: Iterable[str]) -> list[str]:
|
|
@@ -847,20 +861,6 @@ class SimpleProvisioner(ProvisionerProtocol):
|
|
|
847
861
|
requirement_list.extend(requirement.split())
|
|
848
862
|
return requirement_list
|
|
849
863
|
|
|
850
|
-
@staticmethod
|
|
851
|
-
def _filter(
|
|
852
|
-
requirements: set[str], memo: Memoizer, project_root: Union[Path, str]
|
|
853
|
-
) -> set[str]:
|
|
854
|
-
"""
|
|
855
|
-
We want to filter all requirements prior to installing them, because we
|
|
856
|
-
only want to run the install, when there are changes, as it takes pip
|
|
857
|
-
quite some time to check, whether it has to do something.
|
|
858
|
-
"""
|
|
859
|
-
if all(memo.check(_req_for_memo(req, project_root)) for req in requirements):
|
|
860
|
-
return set()
|
|
861
|
-
else:
|
|
862
|
-
return requirements
|
|
863
|
-
|
|
864
864
|
|
|
865
865
|
def _file_hash(filename: Union[Path, str]) -> str:
|
|
866
866
|
"""
|
|
@@ -922,8 +922,8 @@ def venv_provision( # pylint: disable=too-many-branches,missing-function-docstr
|
|
|
922
922
|
cfg: ConfigTree,
|
|
923
923
|
) -> None:
|
|
924
924
|
fresh_env = False
|
|
925
|
-
|
|
926
925
|
info("Checking venv '{python.venv}'")
|
|
926
|
+
|
|
927
927
|
if not exists(cfg.python.venv):
|
|
928
928
|
info("Provisioning venv '{python.venv}'")
|
|
929
929
|
cfg.python.provisioner.provision_venv(cfg)
|
|
@@ -964,6 +964,19 @@ def venv_provision( # pylint: disable=too-many-branches,missing-function-docstr
|
|
|
964
964
|
|
|
965
965
|
def cleanup(cfg: ConfigTree) -> None:
|
|
966
966
|
"""Remove directories and files generated by the python plugin."""
|
|
967
|
+
_cleanup_memoed_provisioners(cfg)
|
|
968
|
+
rmtree(cfg.python.provisioner_memo)
|
|
969
|
+
rmtree(cfg.python.aws_auth.memo)
|
|
970
|
+
for path in cfg.python.build_wheels:
|
|
971
|
+
current_path = Path(interpolate1(path))
|
|
972
|
+
rmtree(current_path / "build")
|
|
973
|
+
rmtree(current_path / "dist")
|
|
974
|
+
for filename in os.listdir(current_path):
|
|
975
|
+
if filename.endswith(".egg-info") or filename.endswith(".dist-info"):
|
|
976
|
+
rmtree(current_path / filename)
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
def _cleanup_memoed_provisioners(cfg: ConfigTree) -> None:
|
|
967
980
|
with memoizer(cfg.python.provisioner_memo) as memo:
|
|
968
981
|
for provisioner in memo.items():
|
|
969
982
|
try:
|
|
@@ -975,16 +988,6 @@ def cleanup(cfg: ConfigTree) -> None:
|
|
|
975
988
|
)
|
|
976
989
|
memo.clear()
|
|
977
990
|
|
|
978
|
-
rmtree(cfg.python.provisioner_memo)
|
|
979
|
-
rmtree(cfg.python.aws_auth.memo)
|
|
980
|
-
for path in cfg.python.build_wheels:
|
|
981
|
-
current_path = Path(interpolate1(path))
|
|
982
|
-
rmtree(current_path / "build")
|
|
983
|
-
rmtree(current_path / "dist")
|
|
984
|
-
for filename in os.listdir(current_path):
|
|
985
|
-
if filename.endswith(".egg-info") or filename.endswith(".dist-info"):
|
|
986
|
-
rmtree(current_path / filename)
|
|
987
|
-
|
|
988
991
|
|
|
989
992
|
def _get_pipconf(cfg: ConfigTree) -> Path:
|
|
990
993
|
"""Retrieve the pipconf configuration file path."""
|
|
@@ -1018,7 +1021,9 @@ def _obfuscate_index_url(index_url: str) -> None:
|
|
|
1018
1021
|
secrets.add(index_url.split(":")[2].split("@")[0]) # Codeartifact token
|
|
1019
1022
|
|
|
1020
1023
|
|
|
1021
|
-
def _check_aws_token_validity(
|
|
1024
|
+
def _check_aws_token_validity( # pylint: disable=too-many-locals
|
|
1025
|
+
cfg: ConfigTree,
|
|
1026
|
+
) -> None:
|
|
1022
1027
|
"""
|
|
1023
1028
|
If csspin-python[aws_auth] is installed, we can use csaccess to get the
|
|
1024
1029
|
CodeArtifact authentication token.
|
|
@@ -1034,6 +1039,17 @@ def _check_aws_token_validity(cfg: ConfigTree) -> None:
|
|
|
1034
1039
|
|
|
1035
1040
|
import time
|
|
1036
1041
|
|
|
1042
|
+
if not (
|
|
1043
|
+
client_secret := (
|
|
1044
|
+
interpolate1(cfg.python.aws_auth.client_secret)
|
|
1045
|
+
or os.getenv("CS_AWS_OIDC_CLIENT_SECRET")
|
|
1046
|
+
)
|
|
1047
|
+
):
|
|
1048
|
+
die(
|
|
1049
|
+
"Please provide a client secret for CodeArtifact access via"
|
|
1050
|
+
" 'python.aws_auth.client_secret'."
|
|
1051
|
+
)
|
|
1052
|
+
|
|
1037
1053
|
current_time = int(time.time())
|
|
1038
1054
|
timestamp_key = "aws_auth_timestamp"
|
|
1039
1055
|
|
|
@@ -1059,18 +1075,24 @@ def _check_aws_token_validity(cfg: ConfigTree) -> None:
|
|
|
1059
1075
|
memo.items().remove(item)
|
|
1060
1076
|
else:
|
|
1061
1077
|
info("Updating Codeartifact token.")
|
|
1078
|
+
from urllib.error import HTTPError
|
|
1062
1079
|
from urllib.parse import urljoin
|
|
1063
1080
|
|
|
1064
1081
|
opts = {
|
|
1082
|
+
"client_secret": client_secret,
|
|
1065
1083
|
"static_oidc": interpolate1(cfg.python.aws_auth.static_oidc).lower()
|
|
1066
|
-
== "true"
|
|
1084
|
+
== "true",
|
|
1067
1085
|
}
|
|
1068
1086
|
if cfg.python.aws_auth.client_id:
|
|
1069
1087
|
opts["client_id"] = interpolate1(cfg.python.aws_auth.client_id)
|
|
1070
1088
|
if cfg.python.aws_auth.role_arn:
|
|
1071
1089
|
opts["aws_role_arn"] = interpolate1(cfg.python.aws_auth.role_arn)
|
|
1072
1090
|
|
|
1073
|
-
|
|
1091
|
+
try:
|
|
1092
|
+
index_base_url = get_ca_pypi_url_programmatic(**opts)
|
|
1093
|
+
except HTTPError as e:
|
|
1094
|
+
die(f"Failed to establish CodeArtifact connection: {e}")
|
|
1095
|
+
|
|
1074
1096
|
index_url = urljoin(
|
|
1075
1097
|
index_base_url + "/", interpolate1(cfg.python.aws_auth.index)
|
|
1076
1098
|
)
|
csspin_python/python_schema.yaml
CHANGED
|
@@ -148,10 +148,20 @@ python:
|
|
|
148
148
|
CodeArtifact.
|
|
149
149
|
index:
|
|
150
150
|
type: str
|
|
151
|
-
help: The
|
|
151
|
+
help: The CodeArtifact repository index (e.g. "16.0/simple").
|
|
152
152
|
client_id:
|
|
153
153
|
type: str
|
|
154
154
|
help: The OIDC client ID to use.
|
|
155
|
+
client_secret:
|
|
156
|
+
type: secret
|
|
157
|
+
help: |
|
|
158
|
+
The OIDC client secret to use, defaults to the
|
|
159
|
+
environment variable 'CS_AWS_OIDC_CLIENT_SECRET'.
|
|
155
160
|
role_arn:
|
|
156
161
|
type: str
|
|
157
162
|
help: The role ARN to assume when authenticating.
|
|
163
|
+
skip_js_build:
|
|
164
|
+
type: bool
|
|
165
|
+
help: |
|
|
166
|
+
If true the build_js part of setuptools_ce will be skipped
|
|
167
|
+
during provision.
|
csspin_python/uv_provisioner.py
CHANGED
|
@@ -180,7 +180,7 @@ def _update_index_url_in_toml(cfg: ConfigTree) -> None:
|
|
|
180
180
|
"""
|
|
181
181
|
Update the index-url in the uv.toml in case it changed.
|
|
182
182
|
"""
|
|
183
|
-
if (uv_toml_path := interpolate1(cfg.uv_provisioner.uv_toml_path)).exists():
|
|
183
|
+
if (uv_toml_path := interpolate1(Path(cfg.uv_provisioner.uv_toml_path))).exists():
|
|
184
184
|
with open(uv_toml_path, mode="r+b") as fd:
|
|
185
185
|
toml_content = tomllib.load(fd)
|
|
186
186
|
if toml_content.get("index-url") != cfg.python.index_url:
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csspin-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.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
7
|
License-Expression: Apache-2.0
|
|
8
|
-
Project-URL:
|
|
8
|
+
Project-URL: CONTACT Software GmbH, https://contact-software.com
|
|
9
|
+
Project-URL: Documentation, https://csspin-python.readthedocs.io/en/stable/
|
|
10
|
+
Project-URL: Issue Tracker, https://github.com/cslab/csspin-python/issues
|
|
11
|
+
Project-URL: Release Notes, https://csspin-python.readthedocs.io/en/stable/relnotes.html
|
|
12
|
+
Project-URL: Repository, https://github.com/cslab/csspin-python
|
|
9
13
|
Classifier: Environment :: Console
|
|
10
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
15
|
Classifier: Intended Audience :: Developers
|
|
@@ -8,14 +8,14 @@ csspin_python/playwright.py,sha256=oFfphLqa4AB6K9vasCUFHN0kFXu63n3ocrsqVuRp4-0,5
|
|
|
8
8
|
csspin_python/playwright_schema.yaml,sha256=TSeR16YHa7m7bfO59F2eMV-jXcglluTJdEpUeL16saY,1178
|
|
9
9
|
csspin_python/pytest.py,sha256=pTOb5zFd9RINZwJsHNaRuSGVDkPMABzaAhwpAJo1nQE,4574
|
|
10
10
|
csspin_python/pytest_schema.yaml,sha256=tzXtdF6MvGC9v59EVRJFfLeMMHqPsXcFXy2zJtRECBI,1535
|
|
11
|
-
csspin_python/python.py,sha256=
|
|
12
|
-
csspin_python/python_schema.yaml,sha256=
|
|
11
|
+
csspin_python/python.py,sha256=rSdF72FkcxiCrzLWSV7Cr4Thx5OgHGN7b6RKgOaXFEg,35871
|
|
12
|
+
csspin_python/python_schema.yaml,sha256=pgVVjByUYjxQWek7aFmjQzRwmq2ROLvHYgwGPMrT9sM,6351
|
|
13
13
|
csspin_python/radon.py,sha256=uFqm6FEi5oWj-_XVaAm3s9cam0cUmr1_FwRf40K6xWs,1876
|
|
14
14
|
csspin_python/radon_schema.yaml,sha256=rlRzXw5z4XbjOVznRiUxWGP4E9hx1Jm-gGw1iQiYzE0,548
|
|
15
|
-
csspin_python/uv_provisioner.py,sha256=
|
|
15
|
+
csspin_python/uv_provisioner.py,sha256=MGedx4e286ZE1miwh70y6b3wePw3mmc0m1kG6H_738I,5999
|
|
16
16
|
csspin_python/uv_provisioner_schema.yaml,sha256=Y8ZNC2OMnhR8Us3WUXAXK9hMjqGWAKFJB2puX4X5XNQ,727
|
|
17
|
-
csspin_python-3.
|
|
18
|
-
csspin_python-3.
|
|
19
|
-
csspin_python-3.
|
|
20
|
-
csspin_python-3.
|
|
21
|
-
csspin_python-3.
|
|
17
|
+
csspin_python-3.2.0.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
|
|
18
|
+
csspin_python-3.2.0.dist-info/METADATA,sha256=54Kz-P7RQC4aHc31QmvyZnY2QSZgrnn9BnIW5ogr8ws,5031
|
|
19
|
+
csspin_python-3.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
csspin_python-3.2.0.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
|
|
21
|
+
csspin_python-3.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|