csspin-python 2.1.0__py3-none-any.whl → 2.1.1__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/behave.py +11 -11
- csspin_python/devpi.py +6 -3
- csspin_python/playwright.py +12 -9
- csspin_python/pytest.py +10 -7
- csspin_python/python.py +107 -77
- csspin_python/radon.py +8 -6
- {csspin_python-2.1.0.dist-info → csspin_python-2.1.1.dist-info}/METADATA +2 -1
- csspin_python-2.1.1.dist-info/RECORD +19 -0
- csspin_python-2.1.0.dist-info/RECORD +0 -19
- {csspin_python-2.1.0.dist-info → csspin_python-2.1.1.dist-info}/WHEEL +0 -0
- {csspin_python-2.1.0.dist-info → csspin_python-2.1.1.dist-info}/licenses/LICENSE +0 -0
- {csspin_python-2.1.0.dist-info → csspin_python-2.1.1.dist-info}/top_level.txt +0 -0
csspin_python/behave.py
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import contextlib
|
|
22
22
|
import sys
|
|
23
|
-
from typing import Generator
|
|
23
|
+
from typing import Generator, Iterable
|
|
24
24
|
|
|
25
25
|
from csspin import config, die, info, option, rmtree, setenv, sh, task, writetext
|
|
26
26
|
from csspin.tree import ConfigTree
|
|
@@ -67,16 +67,16 @@ def configure(cfg: ConfigTree) -> None:
|
|
|
67
67
|
cfg.behave.opts.append("--tags=~windows")
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def create_coverage_pth(cfg: ConfigTree) ->
|
|
70
|
+
def create_coverage_pth(cfg: ConfigTree) -> Path: # pylint: disable=unused-argument
|
|
71
71
|
"""Creating the coverage path file and returning its path"""
|
|
72
|
-
coverage_pth_path = cfg.python.site_packages / "coverage.pth"
|
|
72
|
+
coverage_pth_path: Path = cfg.python.site_packages / "coverage.pth"
|
|
73
73
|
info(f"Create {coverage_pth_path}")
|
|
74
74
|
writetext(coverage_pth_path, "import coverage; coverage.process_startup()")
|
|
75
75
|
return coverage_pth_path
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
@contextlib.contextmanager
|
|
79
|
-
def with_coverage(cfg: ConfigTree) -> Generator:
|
|
79
|
+
def with_coverage(cfg: ConfigTree) -> Generator[None, None, None]:
|
|
80
80
|
"""Context-manager enabling to run coverage"""
|
|
81
81
|
coverage_pth = ""
|
|
82
82
|
try:
|
|
@@ -95,28 +95,28 @@ def with_coverage(cfg: ConfigTree) -> Generator:
|
|
|
95
95
|
|
|
96
96
|
@task(when="cept")
|
|
97
97
|
def behave( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
98
|
-
cfg,
|
|
99
|
-
instance: option(
|
|
98
|
+
cfg: ConfigTree,
|
|
99
|
+
instance: option( # type: ignore[valid-type]
|
|
100
100
|
"-i", # noqa: F821
|
|
101
101
|
"--instance", # noqa: F821
|
|
102
102
|
help="Directory of the CONTACT Elements instance.", # noqa: F722
|
|
103
103
|
),
|
|
104
|
-
coverage: option(
|
|
104
|
+
coverage: option( # type: ignore[valid-type]
|
|
105
105
|
"-c", # noqa: F821
|
|
106
106
|
"--coverage", # noqa: F821
|
|
107
107
|
is_flag=True,
|
|
108
108
|
help="Run the tests while collecting coverage.", # noqa: F722
|
|
109
109
|
),
|
|
110
|
-
debug: option(
|
|
110
|
+
debug: option( # type: ignore[valid-type]
|
|
111
111
|
"--debug", is_flag=True, help="Start debug server." # noqa: F722,F821
|
|
112
112
|
),
|
|
113
|
-
with_test_report: option(
|
|
113
|
+
with_test_report: option( # type: ignore[valid-type]
|
|
114
114
|
"--with-test-report", # noqa: F722
|
|
115
115
|
is_flag=True,
|
|
116
116
|
help="Create a test execution report.", # noqa: F722
|
|
117
117
|
),
|
|
118
|
-
args,
|
|
119
|
-
):
|
|
118
|
+
args: Iterable[str],
|
|
119
|
+
) -> None:
|
|
120
120
|
"""Run Gherkin tests using behave."""
|
|
121
121
|
# pylint: disable=missing-function-docstring
|
|
122
122
|
coverage_enabled = coverage or cfg.behave.coverage
|
csspin_python/devpi.py
CHANGED
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"""Module implementing the devpi plugin for spin"""
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
from typing import Iterable
|
|
22
|
+
|
|
21
23
|
from csspin import Command, config, die, exists, readyaml, setenv, sh, task
|
|
24
|
+
from csspin.tree import ConfigTree
|
|
22
25
|
|
|
23
26
|
defaults = config(
|
|
24
27
|
formats=["bdist_wheel"],
|
|
@@ -34,13 +37,13 @@ defaults = config(
|
|
|
34
37
|
)
|
|
35
38
|
|
|
36
39
|
|
|
37
|
-
def init(cfg): # pylint: disable=unused-argument
|
|
40
|
+
def init(cfg: ConfigTree) -> None: # pylint: disable=unused-argument
|
|
38
41
|
"""Sets some environment variables"""
|
|
39
42
|
setenv(DEVPI_VENV="{python.venv}", DEVPI_CLIENTDIR="{spin.spin_dir}/devpi")
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
@task("devpi:upload")
|
|
43
|
-
def upload(cfg):
|
|
46
|
+
def upload(cfg: ConfigTree) -> None:
|
|
44
47
|
"""Upload project wheel to a package server."""
|
|
45
48
|
if not cfg.devpi.user:
|
|
46
49
|
die("devpi.user is required!")
|
|
@@ -68,7 +71,7 @@ def upload(cfg):
|
|
|
68
71
|
|
|
69
72
|
|
|
70
73
|
@task()
|
|
71
|
-
def devpi(cfg, args):
|
|
74
|
+
def devpi(cfg: ConfigTree, args: Iterable[str]) -> None:
|
|
72
75
|
"""Run the 'devpi' command inside the project's virtual environment.
|
|
73
76
|
|
|
74
77
|
All command line arguments are simply passed through to 'devpi'.
|
csspin_python/playwright.py
CHANGED
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
"""Module implementing the playwright plugin for spin"""
|
|
19
19
|
|
|
20
|
+
from typing import Iterable
|
|
21
|
+
|
|
20
22
|
from csspin import Path, Verbosity, config, die, option, setenv, sh, task
|
|
23
|
+
from csspin.tree import ConfigTree
|
|
21
24
|
|
|
22
25
|
defaults = config(
|
|
23
26
|
browsers_path="{spin.data}/playwright_browsers",
|
|
@@ -50,29 +53,29 @@ defaults = config(
|
|
|
50
53
|
|
|
51
54
|
@task(when="cept")
|
|
52
55
|
def playwright( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
53
|
-
cfg,
|
|
54
|
-
instance: option(
|
|
56
|
+
cfg: ConfigTree,
|
|
57
|
+
instance: option( # type: ignore[valid-type]
|
|
55
58
|
"-i", # noqa: F821
|
|
56
59
|
"--instance", # noqa: F821
|
|
57
60
|
default=None,
|
|
58
61
|
help="Directory of the CONTACT Elements instance.", # noqa: F722
|
|
59
62
|
),
|
|
60
|
-
coverage: option(
|
|
63
|
+
coverage: option( # type: ignore[valid-type]
|
|
61
64
|
"-c", # noqa: F821
|
|
62
65
|
"--coverage", # noqa: F821
|
|
63
66
|
is_flag=True,
|
|
64
67
|
help="Run the tests while collecting coverage.", # noqa: F722
|
|
65
68
|
),
|
|
66
|
-
debug: option(
|
|
69
|
+
debug: option( # type: ignore[valid-type]
|
|
67
70
|
"--debug", is_flag=True, help="Start debug server." # noqa: F722,F821
|
|
68
71
|
),
|
|
69
|
-
with_test_report: option(
|
|
72
|
+
with_test_report: option( # type: ignore[valid-type]
|
|
70
73
|
"--with-test-report", # noqa: F722
|
|
71
74
|
is_flag=True,
|
|
72
75
|
help="Create a test execution report.", # noqa: F722
|
|
73
76
|
),
|
|
74
|
-
args,
|
|
75
|
-
):
|
|
77
|
+
args: Iterable[str],
|
|
78
|
+
) -> None:
|
|
76
79
|
"""Run the playwright tests with pytest."""
|
|
77
80
|
setenv(
|
|
78
81
|
PLAYWRIGHT_BROWSERS_PATH=cfg.playwright.browsers_path,
|
|
@@ -113,7 +116,7 @@ def playwright( # pylint: disable=too-many-arguments,too-many-positional-argume
|
|
|
113
116
|
sh(*cmd, *opts, *args, *cfg.playwright.tests)
|
|
114
117
|
|
|
115
118
|
|
|
116
|
-
def _download_playwright_browsers(cfg):
|
|
119
|
+
def _download_playwright_browsers(cfg: ConfigTree) -> None:
|
|
117
120
|
"""Let playwright install the browsers"""
|
|
118
121
|
sh(
|
|
119
122
|
f"playwright install {' '.join(cfg.playwright.browsers)}",
|
|
@@ -121,6 +124,6 @@ def _download_playwright_browsers(cfg):
|
|
|
121
124
|
)
|
|
122
125
|
|
|
123
126
|
|
|
124
|
-
def provision(cfg):
|
|
127
|
+
def provision(cfg: ConfigTree) -> None:
|
|
125
128
|
"""Install playwright browsers during provisioning"""
|
|
126
129
|
_download_playwright_browsers(cfg)
|
csspin_python/pytest.py
CHANGED
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"""Module implementing the pytest plugin for spin"""
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
from typing import Iterable
|
|
22
|
+
|
|
21
23
|
from csspin import Path, Verbosity, config, die, option, setenv, sh, task
|
|
24
|
+
from csspin.tree import ConfigTree
|
|
22
25
|
|
|
23
26
|
defaults = config(
|
|
24
27
|
coverage=False,
|
|
@@ -49,29 +52,29 @@ defaults = config(
|
|
|
49
52
|
|
|
50
53
|
@task(when="test")
|
|
51
54
|
def pytest( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
52
|
-
cfg,
|
|
53
|
-
instance: option(
|
|
55
|
+
cfg: ConfigTree,
|
|
56
|
+
instance: option( # type: ignore[valid-type]
|
|
54
57
|
"-i", # noqa: F821
|
|
55
58
|
"--instance", # noqa: F821
|
|
56
59
|
default=None,
|
|
57
60
|
help="Directory of the CONTACT Elements instance.", # noqa: F722
|
|
58
61
|
),
|
|
59
|
-
coverage: option(
|
|
62
|
+
coverage: option( # type: ignore[valid-type]
|
|
60
63
|
"-c", # noqa: F821
|
|
61
64
|
"--coverage", # noqa: F821
|
|
62
65
|
is_flag=True,
|
|
63
66
|
help="Run the tests while collecting coverage.", # noqa: F722
|
|
64
67
|
),
|
|
65
|
-
debug: option(
|
|
68
|
+
debug: option( # type: ignore[valid-type]
|
|
66
69
|
"--debug", is_flag=True, help="Start debug server." # noqa: F722,F821
|
|
67
70
|
),
|
|
68
|
-
with_test_report: option(
|
|
71
|
+
with_test_report: option( # type: ignore[valid-type]
|
|
69
72
|
"--with-test-report", # noqa: F722
|
|
70
73
|
is_flag=True,
|
|
71
74
|
help="Create a test execution report.", # noqa: F722
|
|
72
75
|
),
|
|
73
|
-
args,
|
|
74
|
-
):
|
|
76
|
+
args: Iterable[str],
|
|
77
|
+
) -> None:
|
|
75
78
|
"""Run the 'pytest' command."""
|
|
76
79
|
opts = cfg.pytest.opts
|
|
77
80
|
if cfg.verbosity == Verbosity.QUIET:
|
csspin_python/python.py
CHANGED
|
@@ -75,6 +75,14 @@ import shutil
|
|
|
75
75
|
import sys
|
|
76
76
|
from subprocess import check_output
|
|
77
77
|
from textwrap import dedent, indent
|
|
78
|
+
from typing import Iterable, Type, Union
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
from typing import Self # type: ignore[attr-defined]
|
|
82
|
+
except ImportError:
|
|
83
|
+
from typing import TypeVar
|
|
84
|
+
|
|
85
|
+
Self = TypeVar("Self") # type: ignore[misc]
|
|
78
86
|
|
|
79
87
|
from click.exceptions import Abort
|
|
80
88
|
from csspin import (
|
|
@@ -185,16 +193,16 @@ defaults = config(
|
|
|
185
193
|
|
|
186
194
|
|
|
187
195
|
@task()
|
|
188
|
-
def python(args):
|
|
196
|
+
def python(args: Iterable[object]) -> None:
|
|
189
197
|
"""Run the Python interpreter used for this projects."""
|
|
190
198
|
sh("python", *args)
|
|
191
199
|
|
|
192
200
|
|
|
193
201
|
@task("python:wheel", when="package")
|
|
194
202
|
def wheel(
|
|
195
|
-
cfg,
|
|
196
|
-
paths: argument(type=str, nargs=-1, required=False), #
|
|
197
|
-
):
|
|
203
|
+
cfg: ConfigTree,
|
|
204
|
+
paths: argument(type=str, nargs=-1, required=False), # type: ignore[valid-type]
|
|
205
|
+
) -> None:
|
|
198
206
|
"""Build a wheel of the current project and any additional wheels."""
|
|
199
207
|
setenv(PIP_INDEX_URL=cfg.python.index_url)
|
|
200
208
|
search_paths = paths or cfg.python.build_wheels
|
|
@@ -226,8 +234,13 @@ def wheel(
|
|
|
226
234
|
|
|
227
235
|
|
|
228
236
|
@task()
|
|
229
|
-
def env():
|
|
230
|
-
"""
|
|
237
|
+
def env() -> None:
|
|
238
|
+
"""
|
|
239
|
+
Generate command to activate the virtual environment
|
|
240
|
+
|
|
241
|
+
NOTE: spin itself should not be run from within the activated virtual
|
|
242
|
+
environment!
|
|
243
|
+
"""
|
|
231
244
|
if sys.platform == "win32":
|
|
232
245
|
# Don't care about cmd
|
|
233
246
|
print(normpath("{python.scriptdir}", "activate.ps1"))
|
|
@@ -235,12 +248,12 @@ def env():
|
|
|
235
248
|
print(f". {normpath('{python.scriptdir}', 'activate')}")
|
|
236
249
|
|
|
237
250
|
|
|
238
|
-
def pyenv_install(cfg):
|
|
251
|
+
def pyenv_install(cfg: ConfigTree) -> None:
|
|
239
252
|
"""Install and setup the virtual environment using pyenv"""
|
|
240
253
|
with namespaces(cfg.python):
|
|
241
254
|
if cfg.python.user_pyenv:
|
|
242
255
|
info("Using your existing pyenv installation ...")
|
|
243
|
-
sh(
|
|
256
|
+
sh("pyenv", "install", "--skip-existing", {cfg.python.version})
|
|
244
257
|
cfg.python.interpreter = backtick("pyenv which python --nosystem").strip()
|
|
245
258
|
else:
|
|
246
259
|
info("Installing Python {version} to {inst_dir}")
|
|
@@ -248,16 +261,18 @@ def pyenv_install(cfg):
|
|
|
248
261
|
# pyenv is by far the most robust way to install a
|
|
249
262
|
# version of Python.
|
|
250
263
|
if not exists("{pyenv.path}"):
|
|
251
|
-
sh(
|
|
264
|
+
sh("git", "clone", cfg.python.pyenv.url, cfg.python.pyenv.path)
|
|
252
265
|
else:
|
|
253
266
|
with cd(cfg.python.pyenv.path):
|
|
254
|
-
sh("git pull")
|
|
267
|
+
sh("git", "pull")
|
|
255
268
|
# we should set
|
|
256
269
|
setenv(PYTHON_BUILD_CACHE_PATH=mkdir(cfg.python.pyenv.cache))
|
|
257
270
|
setenv(PYTHON_CFLAGS="-DOPENSSL_NO_COMP")
|
|
258
271
|
try:
|
|
259
272
|
sh(
|
|
260
|
-
|
|
273
|
+
cfg.python.pyenv.python_build,
|
|
274
|
+
cfg.python.version,
|
|
275
|
+
cfg.python.inst_dir,
|
|
261
276
|
)
|
|
262
277
|
except Abort:
|
|
263
278
|
error("Failed to build the Python interpreter - removing it")
|
|
@@ -265,7 +280,7 @@ def pyenv_install(cfg):
|
|
|
265
280
|
raise
|
|
266
281
|
|
|
267
282
|
|
|
268
|
-
def nuget_install(cfg):
|
|
283
|
+
def nuget_install(cfg: ConfigTree) -> None:
|
|
269
284
|
"""Install the virtual environment using nuget"""
|
|
270
285
|
if not exists(cfg.python.nuget.exe):
|
|
271
286
|
download(cfg.python.nuget.url, cfg.python.nuget.exe)
|
|
@@ -283,7 +298,7 @@ def nuget_install(cfg):
|
|
|
283
298
|
"-source",
|
|
284
299
|
cfg.python.nuget.source,
|
|
285
300
|
)
|
|
286
|
-
sh(
|
|
301
|
+
sh(cfg.python.interpreter, "-m", "ensurepip", "--upgrade")
|
|
287
302
|
sh(
|
|
288
303
|
cfg.python.interpreter,
|
|
289
304
|
"-mpip",
|
|
@@ -314,7 +329,7 @@ def provision(cfg: ConfigTree) -> None:
|
|
|
314
329
|
cfg.python.site_packages = get_site_packages(interpreter=cfg.python.python)
|
|
315
330
|
|
|
316
331
|
|
|
317
|
-
def configure(cfg):
|
|
332
|
+
def configure(cfg: ConfigTree) -> None:
|
|
318
333
|
"""Configure the python plugin"""
|
|
319
334
|
if not cfg.python.version and not cfg.python.use:
|
|
320
335
|
die(
|
|
@@ -348,7 +363,7 @@ def configure(cfg):
|
|
|
348
363
|
_check_aws_token_validity(cfg)
|
|
349
364
|
|
|
350
365
|
|
|
351
|
-
def init(cfg):
|
|
366
|
+
def init(cfg: ConfigTree) -> None:
|
|
352
367
|
"""Initialize the python plugin"""
|
|
353
368
|
if not cfg.python.use:
|
|
354
369
|
logging.debug("Checking for %s", cfg.python.interpreter)
|
|
@@ -365,7 +380,7 @@ def init(cfg):
|
|
|
365
380
|
ACTIVATED = False
|
|
366
381
|
|
|
367
382
|
|
|
368
|
-
def venv_init(cfg):
|
|
383
|
+
def venv_init(cfg: ConfigTree) -> None:
|
|
369
384
|
"""Activate the virtual environment"""
|
|
370
385
|
global ACTIVATED # pylint: disable=global-statement
|
|
371
386
|
if os.environ.get("VIRTUAL_ENV", "") != cfg.python.venv and not ACTIVATED:
|
|
@@ -386,7 +401,38 @@ def venv_init(cfg):
|
|
|
386
401
|
ACTIVATED = True
|
|
387
402
|
|
|
388
403
|
|
|
389
|
-
|
|
404
|
+
class ActivateScriptPatcher(abc.ABC):
|
|
405
|
+
activatescript: Union[str, Path]
|
|
406
|
+
setpattern: str
|
|
407
|
+
resetpattern: str
|
|
408
|
+
old_env_pattern: str
|
|
409
|
+
patchmarker: str
|
|
410
|
+
replacements: list[tuple[str, str]]
|
|
411
|
+
script: str
|
|
412
|
+
|
|
413
|
+
@staticmethod
|
|
414
|
+
@abc.abstractmethod
|
|
415
|
+
def interpolate_environ_value(value: str) -> str:
|
|
416
|
+
"""
|
|
417
|
+
Translate value so the script can handle uninterpolated "{ENVVAR}" literals in value
|
|
418
|
+
|
|
419
|
+
Example:
|
|
420
|
+
# Assume the following subset of os.environ
|
|
421
|
+
os.environ = {
|
|
422
|
+
"PATH": "/bin:/usr/bin",
|
|
423
|
+
"COMPILER_PATHS": "/compiler/A/bin:/compiler/B/bin",
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
# Now, setenv has been called with
|
|
427
|
+
# setenv(PATH="{python.scriptdir}:{COMPILER_PATHS}:{PATH}") thus the
|
|
428
|
+
# value of ``PATH`` in ``EXPORTS`` equals "/venv/bin:{COMPILER_PATHS}:{PATH}" as
|
|
429
|
+
# ``COMPILER_PATHS`` and ``PATH`` haven't been interpolated yet.
|
|
430
|
+
interpolate_environ_value(value) => /venv/bin:/compiler/A/bin:/compiler/B/bin:/bin:/usr/bin
|
|
431
|
+
"""
|
|
432
|
+
return value
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def patch_activate(schema: Type[ActivateScriptPatcher]) -> None:
|
|
390
436
|
"""Patch the activate script"""
|
|
391
437
|
if exists(schema.activatescript):
|
|
392
438
|
setters = []
|
|
@@ -397,9 +443,9 @@ def patch_activate(schema):
|
|
|
397
443
|
setters.append(schema.setpattern.format(name=name, value=value))
|
|
398
444
|
resetters.add(schema.resetpattern.format(name=name))
|
|
399
445
|
old_value_setters.add(schema.old_env_pattern.format(name=name))
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
446
|
+
resetters_string = "\n".join(resetters)
|
|
447
|
+
setters_string = "\n".join(setters)
|
|
448
|
+
old_value_setters_string = "\n".join(old_value_setters)
|
|
403
449
|
original = readtext(schema.activatescript)
|
|
404
450
|
if schema.patchmarker not in original:
|
|
405
451
|
shutil.copyfile(
|
|
@@ -418,36 +464,13 @@ def patch_activate(schema):
|
|
|
418
464
|
newscript = schema.script.format(
|
|
419
465
|
patchmarker=schema.patchmarker,
|
|
420
466
|
original=original,
|
|
421
|
-
resetters=
|
|
422
|
-
old_value_setters=
|
|
423
|
-
setters=
|
|
467
|
+
resetters=resetters_string,
|
|
468
|
+
old_value_setters=old_value_setters_string,
|
|
469
|
+
setters=setters_string,
|
|
424
470
|
)
|
|
425
471
|
writetext(f"{schema.activatescript}", newscript)
|
|
426
472
|
|
|
427
473
|
|
|
428
|
-
class ActivateScriptPatcher(abc.ABC):
|
|
429
|
-
@staticmethod
|
|
430
|
-
@abc.abstractmethod
|
|
431
|
-
def interpolate_environ_value(value):
|
|
432
|
-
"""
|
|
433
|
-
Translate value so the script can handle uninterpolated "{ENVVAR}" literals in value
|
|
434
|
-
|
|
435
|
-
Example:
|
|
436
|
-
# Assume the following subset of os.environ
|
|
437
|
-
os.environ = {
|
|
438
|
-
"PATH": "/bin:/usr/bin",
|
|
439
|
-
"COMPILER_PATHS": "/compiler/A/bin:/compiler/B/bin",
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
# Now, setenv has been called with
|
|
443
|
-
# setenv(PATH="{python.scriptdir}:{COMPILER_PATHS}:{PATH}") thus the
|
|
444
|
-
# value of ``PATH`` in ``EXPORTS`` equals "/venv/bin:{COMPILER_PATHS}:{PATH}" as
|
|
445
|
-
# ``COMPILER_PATHS`` and ``PATH`` haven't been interpolated yet.
|
|
446
|
-
interpolate_environ_value(value) => /venv/bin:/compiler/A/bin:/compiler/B/bin:/bin:/usr/bin
|
|
447
|
-
"""
|
|
448
|
-
return value
|
|
449
|
-
|
|
450
|
-
|
|
451
474
|
class BashActivate(ActivateScriptPatcher):
|
|
452
475
|
patchmarker = "\n## Patched by csspin_python.python\n"
|
|
453
476
|
activatescript = Path("{python.scriptdir}") / "activate"
|
|
@@ -510,7 +533,7 @@ class BashActivate(ActivateScriptPatcher):
|
|
|
510
533
|
)
|
|
511
534
|
|
|
512
535
|
@staticmethod
|
|
513
|
-
def interpolate_environ_value(value):
|
|
536
|
+
def interpolate_environ_value(value: str) -> str:
|
|
514
537
|
if not value:
|
|
515
538
|
return ""
|
|
516
539
|
keys = re.findall(r"{(?P<key>\w+?)}", value)
|
|
@@ -564,7 +587,7 @@ class PowershellActivate(ActivateScriptPatcher):
|
|
|
564
587
|
)
|
|
565
588
|
|
|
566
589
|
@staticmethod
|
|
567
|
-
def interpolate_environ_value(value):
|
|
590
|
+
def interpolate_environ_value(value: str) -> str:
|
|
568
591
|
if not value:
|
|
569
592
|
return ""
|
|
570
593
|
keys = re.findall(r"{(?P<key>\w+?)}", value)
|
|
@@ -577,7 +600,7 @@ class PowershellActivate(ActivateScriptPatcher):
|
|
|
577
600
|
class BatchActivate(ActivateScriptPatcher):
|
|
578
601
|
patchmarker = "\nREM Patched by csspin_python.python\n"
|
|
579
602
|
activatescript = Path("{python.scriptdir}") / "activate.bat"
|
|
580
|
-
replacements =
|
|
603
|
+
replacements = []
|
|
581
604
|
old_env_pattern = dedent(
|
|
582
605
|
"""
|
|
583
606
|
if defined _OLD_SPIN_VALUE_{name} goto ENDIFSPIN{name}1
|
|
@@ -614,7 +637,7 @@ class BatchActivate(ActivateScriptPatcher):
|
|
|
614
637
|
)
|
|
615
638
|
|
|
616
639
|
@staticmethod
|
|
617
|
-
def interpolate_environ_value(value):
|
|
640
|
+
def interpolate_environ_value(value: str) -> str:
|
|
618
641
|
if not value:
|
|
619
642
|
return ""
|
|
620
643
|
keys = re.findall(r"{(?P<key>\w+?)}", value)
|
|
@@ -627,7 +650,7 @@ class BatchActivate(ActivateScriptPatcher):
|
|
|
627
650
|
class BatchDeactivate(ActivateScriptPatcher):
|
|
628
651
|
patchmarker = "\nREM Patched by csspin_python.python\n"
|
|
629
652
|
activatescript = Path("{python.scriptdir}") / "deactivate.bat"
|
|
630
|
-
replacements =
|
|
653
|
+
replacements = []
|
|
631
654
|
old_env_pattern = ""
|
|
632
655
|
setpattern = ""
|
|
633
656
|
resetpattern = dedent(
|
|
@@ -658,7 +681,7 @@ class BatchDeactivate(ActivateScriptPatcher):
|
|
|
658
681
|
class PythonActivate(ActivateScriptPatcher):
|
|
659
682
|
patchmarker = "# Patched by csspin_python.python\n"
|
|
660
683
|
activatescript = Path("{python.scriptdir}") / "activate_this.py"
|
|
661
|
-
replacements =
|
|
684
|
+
replacements = []
|
|
662
685
|
old_env_pattern = ""
|
|
663
686
|
setpattern = 'os.environ["{name}"] = fr"{value}"'
|
|
664
687
|
resetpattern = ""
|
|
@@ -671,7 +694,7 @@ class PythonActivate(ActivateScriptPatcher):
|
|
|
671
694
|
)
|
|
672
695
|
|
|
673
696
|
@staticmethod
|
|
674
|
-
def interpolate_environ_value(value):
|
|
697
|
+
def interpolate_environ_value(value: str) -> str:
|
|
675
698
|
if not value:
|
|
676
699
|
return ""
|
|
677
700
|
keys = re.findall(r"{(?P<key>\w+?)}", value)
|
|
@@ -681,7 +704,7 @@ class PythonActivate(ActivateScriptPatcher):
|
|
|
681
704
|
return value
|
|
682
705
|
|
|
683
706
|
|
|
684
|
-
def get_site_packages(interpreter):
|
|
707
|
+
def get_site_packages(interpreter: Path) -> Path:
|
|
685
708
|
"""Return the path to the virtual environments site-packages."""
|
|
686
709
|
return Path(
|
|
687
710
|
check_output(
|
|
@@ -696,7 +719,7 @@ def get_site_packages(interpreter):
|
|
|
696
719
|
)
|
|
697
720
|
|
|
698
721
|
|
|
699
|
-
def finalize_provision(cfg):
|
|
722
|
+
def finalize_provision(cfg: ConfigTree) -> None:
|
|
700
723
|
"""Patching the activate scripts and preparing the site-packages"""
|
|
701
724
|
cfg.python.provisioner.install(cfg)
|
|
702
725
|
|
|
@@ -732,8 +755,11 @@ class ProvisionerProtocol:
|
|
|
732
755
|
The provisioner will be memoized, so make sure it works with ``pickle.dumps``.
|
|
733
756
|
"""
|
|
734
757
|
|
|
758
|
+
requirements: set[str]
|
|
759
|
+
devpackages: set[str]
|
|
760
|
+
|
|
735
761
|
# noinspection PyMethodMayBeStatic
|
|
736
|
-
def provision_python(self, cfg: ConfigTree) -> None:
|
|
762
|
+
def provision_python(self: Self, cfg: ConfigTree) -> None:
|
|
737
763
|
"""Provision the project's python interpreter"""
|
|
738
764
|
if sys.platform == "win32":
|
|
739
765
|
nuget_install(cfg)
|
|
@@ -742,7 +768,7 @@ class ProvisionerProtocol:
|
|
|
742
768
|
pyenv_install(cfg)
|
|
743
769
|
|
|
744
770
|
# noinspection PyMethodMayBeStatic
|
|
745
|
-
def provision_venv(self, cfg: ConfigTree) -> None:
|
|
771
|
+
def provision_venv(self: Self, cfg: ConfigTree) -> None:
|
|
746
772
|
"""Provision the virtual environment of the project"""
|
|
747
773
|
# virtualenv is guaranteed to be available like this
|
|
748
774
|
# as we declared it as one of spin's dependencies
|
|
@@ -761,26 +787,26 @@ class ProvisionerProtocol:
|
|
|
761
787
|
env={"PYTHONPATH": cfg.spin.spin_dir / "plugins"},
|
|
762
788
|
)
|
|
763
789
|
|
|
764
|
-
def prerequisites(self, cfg: ConfigTree) -> None:
|
|
790
|
+
def prerequisites(self: Self, cfg: ConfigTree) -> None:
|
|
765
791
|
"""Provide requirements for the provisioning strategy."""
|
|
766
792
|
|
|
767
|
-
def lock(self, cfg: ConfigTree) -> None:
|
|
793
|
+
def lock(self: Self, cfg: ConfigTree) -> None:
|
|
768
794
|
"""Lock the project's dependencies."""
|
|
769
795
|
|
|
770
|
-
def add(self, cfg: ConfigTree, req: str, devpackage: bool = False) -> None:
|
|
796
|
+
def add(self: Self, cfg: ConfigTree, req: str, devpackage: bool = False) -> None:
|
|
771
797
|
"""Add an extra dependency (incl. development ones)."""
|
|
772
798
|
|
|
773
|
-
def lock_extras(self, cfg: ConfigTree) -> None:
|
|
799
|
+
def lock_extras(self: Self, cfg: ConfigTree) -> None:
|
|
774
800
|
"""Lock the extra dependencies."""
|
|
775
801
|
|
|
776
|
-
def sync(self, cfg: ConfigTree) -> None:
|
|
802
|
+
def sync(self: Self, cfg: ConfigTree) -> None:
|
|
777
803
|
"""Synchronize the environment with the locked dependencies."""
|
|
778
804
|
|
|
779
|
-
def install(self, cfg: ConfigTree) -> None:
|
|
805
|
+
def install(self: Self, cfg: ConfigTree) -> None:
|
|
780
806
|
"""Install the project itself."""
|
|
781
807
|
|
|
782
808
|
# noinspection PyMethodMayBeStatic
|
|
783
|
-
def cleanup(self, cfg: ConfigTree) -> None:
|
|
809
|
+
def cleanup(self: Self, cfg: ConfigTree) -> None:
|
|
784
810
|
"""Cleanup the provisioned environment"""
|
|
785
811
|
rmtree(cfg.python.venv)
|
|
786
812
|
|
|
@@ -792,12 +818,12 @@ class SimpleProvisioner(ProvisionerProtocol):
|
|
|
792
818
|
longer required.
|
|
793
819
|
"""
|
|
794
820
|
|
|
795
|
-
def __init__(self):
|
|
821
|
+
def __init__(self: Self) -> None:
|
|
796
822
|
self.requirements = set()
|
|
797
823
|
self.devpackages = set()
|
|
798
824
|
self.m = Memoizer("{python.memo}")
|
|
799
825
|
|
|
800
|
-
def prerequisites(self, cfg):
|
|
826
|
+
def prerequisites(self: Self, cfg: ConfigTree) -> None:
|
|
801
827
|
# We'll need pip
|
|
802
828
|
sh(
|
|
803
829
|
"python",
|
|
@@ -811,23 +837,23 @@ class SimpleProvisioner(ProvisionerProtocol):
|
|
|
811
837
|
"pip",
|
|
812
838
|
)
|
|
813
839
|
|
|
814
|
-
def lock(self, cfg):
|
|
840
|
+
def lock(self: Self, cfg: ConfigTree) -> None:
|
|
815
841
|
"""Noop"""
|
|
816
842
|
|
|
817
|
-
def add(self, cfg, req, devpackage=False):
|
|
843
|
+
def add(self: Self, cfg: ConfigTree, req: str, devpackage: bool = False) -> None:
|
|
818
844
|
# Add the requirement or devpackage if not already there.
|
|
819
845
|
if not self.m.check(req):
|
|
820
846
|
lst = self.devpackages if devpackage else self.requirements
|
|
821
847
|
lst.add(req)
|
|
822
848
|
|
|
823
|
-
def sync(self, cfg):
|
|
849
|
+
def sync(self: Self, cfg: ConfigTree) -> None:
|
|
824
850
|
self.__execute_installation(
|
|
825
851
|
self.requirements,
|
|
826
852
|
None if cfg.verbosity > Verbosity.NORMAL else "-q",
|
|
827
853
|
cfg.python.index_url,
|
|
828
854
|
)
|
|
829
855
|
|
|
830
|
-
def install(self, cfg):
|
|
856
|
+
def install(self: Self, cfg: ConfigTree) -> None:
|
|
831
857
|
quietflag = None if cfg.verbosity > Verbosity.NORMAL else "-q"
|
|
832
858
|
self.__execute_installation(self.devpackages, quietflag, cfg.python.index_url)
|
|
833
859
|
|
|
@@ -862,14 +888,16 @@ class SimpleProvisioner(ProvisionerProtocol):
|
|
|
862
888
|
if pip_check.returncode:
|
|
863
889
|
die(pip_check.stdout)
|
|
864
890
|
|
|
865
|
-
def _split(self, reqset):
|
|
891
|
+
def _split(self: Self, reqset: set[str]) -> list[str]:
|
|
866
892
|
"""to pass whitespace-less args to sh()"""
|
|
867
893
|
reqlist = []
|
|
868
894
|
for req in reqset:
|
|
869
895
|
reqlist.extend(req.split())
|
|
870
896
|
return reqlist
|
|
871
897
|
|
|
872
|
-
def __execute_installation(
|
|
898
|
+
def __execute_installation(
|
|
899
|
+
self: Self, packages: set[str], quietflag: Union[str, None], index_url: str
|
|
900
|
+
) -> None:
|
|
873
901
|
"""Install packages that are not yet memoized"""
|
|
874
902
|
if to_install := {package for package in packages if not self.m.check(package)}:
|
|
875
903
|
sh(
|
|
@@ -886,7 +914,9 @@ class SimpleProvisioner(ProvisionerProtocol):
|
|
|
886
914
|
self.m.save()
|
|
887
915
|
|
|
888
916
|
|
|
889
|
-
def venv_provision(
|
|
917
|
+
def venv_provision( # pylint: disable=too-many-branches,missing-function-docstring
|
|
918
|
+
cfg: ConfigTree,
|
|
919
|
+
) -> None:
|
|
890
920
|
fresh_env = False
|
|
891
921
|
|
|
892
922
|
info("Checking venv '{python.venv}'")
|
|
@@ -961,7 +991,7 @@ def cleanup(cfg: ConfigTree) -> None:
|
|
|
961
991
|
rmtree(current_path / filename)
|
|
962
992
|
|
|
963
993
|
|
|
964
|
-
def _get_pipconf(cfg):
|
|
994
|
+
def _get_pipconf(cfg: ConfigTree) -> Path:
|
|
965
995
|
"""Retrieve the pipconf configuration file path."""
|
|
966
996
|
if sys.platform == "win32":
|
|
967
997
|
pipconf = interpolate1(Path(cfg.python.venv)) / "pip.ini"
|
|
@@ -971,7 +1001,7 @@ def _get_pipconf(cfg):
|
|
|
971
1001
|
return pipconf
|
|
972
1002
|
|
|
973
1003
|
|
|
974
|
-
def _configure_pipconf(cfg, update=False):
|
|
1004
|
+
def _configure_pipconf(cfg: ConfigTree, update: bool = False) -> None:
|
|
975
1005
|
"""Configure the pip configuration file"""
|
|
976
1006
|
config_parser = configparser.ConfigParser()
|
|
977
1007
|
config_parser.read_string(cfg.python.pipconf)
|
|
@@ -985,7 +1015,7 @@ def _configure_pipconf(cfg, update=False):
|
|
|
985
1015
|
config_parser.write(fd)
|
|
986
1016
|
|
|
987
1017
|
|
|
988
|
-
def _obfuscate_index_url(index_url):
|
|
1018
|
+
def _obfuscate_index_url(index_url: str) -> None:
|
|
989
1019
|
"""Add the CodeArtifact token to the secrets."""
|
|
990
1020
|
|
|
991
1021
|
from csspin import secrets
|
|
@@ -993,7 +1023,7 @@ def _obfuscate_index_url(index_url):
|
|
|
993
1023
|
secrets.add(index_url.split(":")[2].split("@")[0]) # Codeartifact token
|
|
994
1024
|
|
|
995
1025
|
|
|
996
|
-
def _check_aws_token_validity(cfg):
|
|
1026
|
+
def _check_aws_token_validity(cfg: ConfigTree) -> None:
|
|
997
1027
|
"""
|
|
998
1028
|
If csspin-python[aws_auth] is installed, we can use csaccess to get the
|
|
999
1029
|
CodeArtifact authentication token.
|
csspin_python/radon.py
CHANGED
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
"""Module implementing the radon plugin for spin"""
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
|
+
from typing import Iterable
|
|
21
22
|
|
|
22
23
|
from csspin import config, info, option, sh, task
|
|
24
|
+
from csspin.tree import ConfigTree
|
|
23
25
|
|
|
24
26
|
defaults = config(
|
|
25
27
|
exe="radon",
|
|
@@ -36,20 +38,20 @@ defaults = config(
|
|
|
36
38
|
|
|
37
39
|
@task()
|
|
38
40
|
def radon(
|
|
39
|
-
cfg,
|
|
40
|
-
allsource: option(
|
|
41
|
+
cfg: ConfigTree,
|
|
42
|
+
allsource: option( # type: ignore[valid-type]
|
|
41
43
|
"--all", # noqa: F821
|
|
42
44
|
"allsource", # noqa: F821
|
|
43
45
|
is_flag=True,
|
|
44
46
|
help="Run for all src- and test-files.", # noqa: F722,F821
|
|
45
47
|
),
|
|
46
|
-
args,
|
|
47
|
-
):
|
|
48
|
+
args: Iterable[str],
|
|
49
|
+
) -> None:
|
|
48
50
|
"""Run radon to measure code complexity."""
|
|
49
51
|
if allsource:
|
|
50
|
-
files =
|
|
52
|
+
files = ["{spin.project_root}/src", "{spin.project_root}/tests"]
|
|
51
53
|
else:
|
|
52
|
-
files = args
|
|
54
|
+
files = list(args)
|
|
53
55
|
if not files and hasattr(cfg, "vcs") and hasattr(cfg.vcs, "modified"):
|
|
54
56
|
info("Found modified files.")
|
|
55
57
|
files = cfg.vcs.modified
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: csspin-python
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.1
|
|
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>
|
|
@@ -20,6 +20,7 @@ Classifier: Topic :: Software Development
|
|
|
20
20
|
Requires-Python: >=3.9
|
|
21
21
|
Description-Content-Type: text/x-rst
|
|
22
22
|
License-File: LICENSE
|
|
23
|
+
Requires-Dist: platformdirs~=4.3.8
|
|
23
24
|
Requires-Dist: virtualenv
|
|
24
25
|
Provides-Extra: aws-auth
|
|
25
26
|
Requires-Dist: csaccess>=0.1.0; extra == "aws-auth"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
csspin_python/behave.py,sha256=iJZeyIqB7V_NzTdLTZldNY9W_GGwCWkXe6WY69wpDqs,4997
|
|
2
|
+
csspin_python/behave_schema.yaml,sha256=8qoOCK-uTmwgRRW29urgK0X_kgn0zO0X34v89bvii2w,1241
|
|
3
|
+
csspin_python/debugpy.py,sha256=v0ZZopv5TNoSaFf2kiePsw9OmhBpjfOBFh0u71jTcnQ,962
|
|
4
|
+
csspin_python/debugpy_schema.yaml,sha256=BeH30nSirDYctkdhS9xMXUG5htj3PED_ZjmxPG5WRUc,364
|
|
5
|
+
csspin_python/devpi.py,sha256=C-5O_vA06CwQR4uElOw-2VH2-m001SpxowM_X6RbRwo,2352
|
|
6
|
+
csspin_python/devpi_schema.yaml,sha256=2gPATWjVcfvCTrGZX2FK6wH8hh9KS0XzZ35JvZeJGEU,487
|
|
7
|
+
csspin_python/playwright.py,sha256=mzSsLcmewDZnZwdSyp5HytEMnXgkoJ9s1XXkd05eOwU,4254
|
|
8
|
+
csspin_python/playwright_schema.yaml,sha256=WFMok7dB7G6L8f8y_2_RKHjGe4ww1iUUS4tqCoUI1FE,1054
|
|
9
|
+
csspin_python/pytest.py,sha256=Mx6l4Cb28FjdZgL9Vd1zBbhcnYyc4QsqwkozksoKZJc,3189
|
|
10
|
+
csspin_python/pytest_schema.yaml,sha256=1bF8hNsJfV-LHUwGBBJ3GnQOZJiIQkG81DCBma2MalU,809
|
|
11
|
+
csspin_python/python.py,sha256=AbIX3r07c4tVAj0jIfjiRi7Vk9XFiap6AvS4xCYee48,34461
|
|
12
|
+
csspin_python/python_schema.yaml,sha256=F_PMK8D3KBvXK945b6-oRDoaxuDgxkBGqVPAJ-eFmv0,5970
|
|
13
|
+
csspin_python/radon.py,sha256=uFqm6FEi5oWj-_XVaAm3s9cam0cUmr1_FwRf40K6xWs,1876
|
|
14
|
+
csspin_python/radon_schema.yaml,sha256=rlRzXw5z4XbjOVznRiUxWGP4E9hx1Jm-gGw1iQiYzE0,548
|
|
15
|
+
csspin_python-2.1.1.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
|
|
16
|
+
csspin_python-2.1.1.dist-info/METADATA,sha256=pIuulk5YG9JUQqORop0oV4GoX0DdHZoOOGktz8YkhYA,4209
|
|
17
|
+
csspin_python-2.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
csspin_python-2.1.1.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
|
|
19
|
+
csspin_python-2.1.1.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
csspin_python/behave.py,sha256=iA5t-vwMDhmWoo-FHaeZ6JyIzj6k4r2WLyYa2AjXyp4,4815
|
|
2
|
-
csspin_python/behave_schema.yaml,sha256=8qoOCK-uTmwgRRW29urgK0X_kgn0zO0X34v89bvii2w,1241
|
|
3
|
-
csspin_python/debugpy.py,sha256=v0ZZopv5TNoSaFf2kiePsw9OmhBpjfOBFh0u71jTcnQ,962
|
|
4
|
-
csspin_python/debugpy_schema.yaml,sha256=BeH30nSirDYctkdhS9xMXUG5htj3PED_ZjmxPG5WRUc,364
|
|
5
|
-
csspin_python/devpi.py,sha256=2NhGYzq4aVzDa_d80uItUlYM9cA0uRFQ4rvnCryxL2k,2213
|
|
6
|
-
csspin_python/devpi_schema.yaml,sha256=2gPATWjVcfvCTrGZX2FK6wH8hh9KS0XzZ35JvZeJGEU,487
|
|
7
|
-
csspin_python/playwright.py,sha256=nYuPjuTfGx_6QPYsUpr-eAZARyXX_hZF8D4AxeI2u1s,4003
|
|
8
|
-
csspin_python/playwright_schema.yaml,sha256=WFMok7dB7G6L8f8y_2_RKHjGe4ww1iUUS4tqCoUI1FE,1054
|
|
9
|
-
csspin_python/pytest.py,sha256=EwxPynyPWS72NTtIah1jUGVa7fJYY8I2_NQz0y0U7Os,2978
|
|
10
|
-
csspin_python/pytest_schema.yaml,sha256=1bF8hNsJfV-LHUwGBBJ3GnQOZJiIQkG81DCBma2MalU,809
|
|
11
|
-
csspin_python/python.py,sha256=du1sFA6Uh8Wp5V6sN3_iSsQNEz-OZBAJG-FdgCyvsjM,33114
|
|
12
|
-
csspin_python/python_schema.yaml,sha256=F_PMK8D3KBvXK945b6-oRDoaxuDgxkBGqVPAJ-eFmv0,5970
|
|
13
|
-
csspin_python/radon.py,sha256=OSV0vTz7SMMHC82jUvWsBq6vtWolOjdiZ2bBdxplVJ4,1744
|
|
14
|
-
csspin_python/radon_schema.yaml,sha256=rlRzXw5z4XbjOVznRiUxWGP4E9hx1Jm-gGw1iQiYzE0,548
|
|
15
|
-
csspin_python-2.1.0.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
|
|
16
|
-
csspin_python-2.1.0.dist-info/METADATA,sha256=-cWwMdEo8x0I1_vcEAjiCO5DC79Y-ymGXro6Qig7Q4s,4174
|
|
17
|
-
csspin_python-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
-
csspin_python-2.1.0.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
|
|
19
|
-
csspin_python-2.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|