csspin-python 3.1.1__py3-none-any.whl → 4.0.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/devpi.py CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  """Module implementing the devpi plugin for spin"""
19
19
 
20
-
21
20
  from typing import Iterable
22
21
 
23
22
  from csspin import Command, config, die, exists, readyaml, setenv, sh, task
csspin_python/pytest.py CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  """Module implementing the pytest plugin for spin"""
19
19
 
20
-
21
20
  from typing import Iterable
22
21
 
23
22
  from csspin import Path, Verbosity, config, die, interpolate1, option, setenv, sh, task
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 subprocess import check_output
77
+ from contextlib import contextmanager
78
+ from subprocess import CalledProcessError, 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]
@@ -164,6 +165,7 @@ defaults = config(
164
165
  client_secret="", # nosec: B106
165
166
  ),
166
167
  index_url="https://pypi.org/simple",
168
+ skip_js_build=None,
167
169
  requires=config(python=["build", "wheel"]),
168
170
  )
169
171
 
@@ -287,18 +289,74 @@ def nuget_install(cfg: ConfigTree) -> None:
287
289
  )
288
290
 
289
291
 
292
+ def _check_venv( # pylint: disable=too-many-return-statements
293
+ cfg: ConfigTree,
294
+ ) -> bool:
295
+ """
296
+ Checks whether the venv is actually a venv compatible
297
+ with our configuration and not just some dir.
298
+ """
299
+ try:
300
+ python_version = (
301
+ check_output([cfg.python.python, "--version"])
302
+ .decode()
303
+ .strip()
304
+ .replace("Python ", "")
305
+ )
306
+ except CalledProcessError:
307
+ return False
308
+ if not cfg.python.version and not cfg.python.use:
309
+ return False
310
+ if cfg.python.use:
311
+ try:
312
+ use_python_version = (
313
+ check_output([cfg.python.use, "--version"])
314
+ .decode()
315
+ .strip()
316
+ .replace("Python ", "")
317
+ )
318
+ except CalledProcessError:
319
+ return False
320
+ if use_python_version == python_version:
321
+ return True
322
+ else:
323
+ warn(
324
+ "The cfg.python.use version does not match the cfg.python.python "
325
+ "version set in the venv. If you want to update the python version "
326
+ "used in the venv, you have to manually remove it."
327
+ )
328
+ return True
329
+ if python_version.startswith(cfg.python.version):
330
+ return True
331
+ return False
332
+
333
+
290
334
  def provision(cfg: ConfigTree) -> None:
291
335
  """Provision the python plugin"""
336
+
337
+ info("Checking venv '{python.venv}'")
338
+
339
+ fresh_venv = False
340
+
341
+ if exists("{python.venv}"):
342
+ if not _check_venv(cfg):
343
+ _cleanup_memoed_provisioners(cfg)
344
+ rmtree(cfg.python.provisioner_memo)
345
+ rmtree(cfg.python.aws_auth.memo)
346
+ rmtree(cfg.python.venv)
347
+ fresh_venv = True
348
+ else:
349
+ fresh_venv = True
350
+
292
351
  with memoizer(cfg.python.provisioner_memo) as memo:
293
352
  if cfg.python.provisioner is None:
294
353
  cfg.python.provisioner = SimpleProvisioner(cfg)
295
354
  if not memo.check(cfg.python.provisioner):
296
355
  memo.add(cfg.python.provisioner)
297
-
298
356
  if not shutil.which(cfg.python.interpreter):
299
357
  cfg.python.provisioner.provision_python(cfg)
300
358
 
301
- venv_provision(cfg)
359
+ venv_provision(cfg, fresh_venv)
302
360
 
303
361
  cfg.python.site_packages = get_site_packages(interpreter=cfg.python.python)
304
362
 
@@ -332,6 +390,10 @@ def configure(cfg: ConfigTree) -> None:
332
390
 
333
391
  if exists(cfg.python.python):
334
392
  cfg.python.site_packages = get_site_packages(interpreter=cfg.python.python)
393
+ # Built JS should still be available in this case
394
+ # Skip only if users hasn't explicitly set it to False
395
+ if cfg.python.skip_js_build is None:
396
+ cfg.python.skip_js_build = True
335
397
 
336
398
  if cfg.python.aws_auth.enabled:
337
399
  _check_aws_token_validity(cfg)
@@ -451,24 +513,19 @@ class BashActivate(ActivateScriptPatcher):
451
513
  replacements = [
452
514
  ("deactivate", "origdeactivate"),
453
515
  ]
454
- old_env_pattern = dedent(
455
- """
516
+ old_env_pattern = dedent("""
456
517
  if [ -z ${{{name}+x}} ]; then
457
518
  export _OLD_SPIN_UNSET{name}=""
458
519
  else
459
520
  export _OLD_SPIN_VALUE{name}="${name}"
460
521
  fi
461
- """
462
- )
463
- setpattern = dedent(
464
- """
522
+ """)
523
+ setpattern = dedent("""
465
524
  {name}="{value}"
466
525
  export {name}
467
- """
468
- )
526
+ """)
469
527
  resetpattern = indent(
470
- dedent(
471
- """
528
+ dedent("""
472
529
  if ! [ -z "${{_OLD_SPIN_VALUE{name}+_}}" ] ; then
473
530
  {name}="$_OLD_SPIN_VALUE{name}"
474
531
  export {name}
@@ -478,12 +535,10 @@ class BashActivate(ActivateScriptPatcher):
478
535
  unset {name}
479
536
  unset _OLD_SPIN_UNSET{name}
480
537
  fi
481
- """
482
- ),
538
+ """),
483
539
  prefix=" ",
484
540
  )
485
- script = dedent(
486
- """
541
+ script = dedent("""
487
542
  {patchmarker}
488
543
  {original}
489
544
  deactivate () {{
@@ -503,8 +558,7 @@ class BashActivate(ActivateScriptPatcher):
503
558
  # commands. Without forgetting past commands the $PATH changes
504
559
  # we made may not be respected
505
560
  hash -r 2>/dev/null
506
- """
507
- )
561
+ """)
508
562
 
509
563
  @staticmethod
510
564
  def interpolate_environ_value(value: str) -> str:
@@ -526,24 +580,19 @@ class PowershellActivate(ActivateScriptPatcher):
526
580
  old_env_pattern = (
527
581
  "New-Variable -Scope global -Name _OLD_SPIN_{name} -Value $env:{name}"
528
582
  )
529
- setpattern = dedent(
530
- """
583
+ setpattern = dedent("""
531
584
  $env:{name} = "{value}"
532
- """
533
- )
585
+ """)
534
586
  resetpattern = indent(
535
- dedent(
536
- """
587
+ dedent("""
537
588
  if (Test-Path variable:_OLD_SPIN_{name}) {{
538
589
  $env:{name} = $variable:_OLD_SPIN_{name}
539
590
  Remove-Variable "_OLD_SPIN_{name}" -Scope global
540
591
  }}
541
- """
542
- ),
592
+ """),
543
593
  prefix=" ",
544
594
  )
545
- script = dedent(
546
- """
595
+ script = dedent("""
547
596
  {patchmarker}
548
597
  {original}
549
598
  function global:deactivate([switch] $NonDestructive) {{
@@ -557,8 +606,7 @@ class PowershellActivate(ActivateScriptPatcher):
557
606
  deactivate -nondestructive
558
607
  {old_value_setters}
559
608
  {setters}
560
- """
561
- )
609
+ """)
562
610
 
563
611
  @staticmethod
564
612
  def interpolate_environ_value(value: str) -> str:
@@ -575,8 +623,7 @@ class BatchActivate(ActivateScriptPatcher):
575
623
  patchmarker = "\nREM Patched by csspin_python.python\n"
576
624
  activatescript = Path("{python.scriptdir}") / "activate.bat"
577
625
  replacements = []
578
- old_env_pattern = dedent(
579
- """
626
+ old_env_pattern = dedent("""
580
627
  if defined _OLD_SPIN_VALUE_{name} goto ENDIFSPIN{name}1
581
628
  if defined _OLD_SPIN_UNSET_{name} goto ENDIFSPIN{name}2
582
629
  if defined {name} goto ENDIFSPIN{name}3
@@ -596,19 +643,16 @@ class BatchActivate(ActivateScriptPatcher):
596
643
  set "_OLD_SPIN_UNSET_{name}= "
597
644
  goto ENDIFSPIN{name}5
598
645
  :ENDIFSPIN{name}5
599
- """
600
- )
646
+ """)
601
647
  setpattern = 'set "{name}={value}"'
602
648
  resetpattern = ""
603
- script = dedent(
604
- """
649
+ script = dedent("""
605
650
  @echo off
606
651
  {patchmarker}
607
652
  {original}
608
653
  {old_value_setters}
609
654
  {setters}
610
- """
611
- )
655
+ """)
612
656
 
613
657
  @staticmethod
614
658
  def interpolate_environ_value(value: str) -> str:
@@ -627,8 +671,7 @@ class BatchDeactivate(ActivateScriptPatcher):
627
671
  replacements = []
628
672
  old_env_pattern = ""
629
673
  setpattern = ""
630
- resetpattern = dedent(
631
- """
674
+ resetpattern = dedent("""
632
675
  if defined _OLD_SPIN_VALUE_{name} goto ENDIFVSPIN{name}1
633
676
  if defined _OLD_SPIN_UNSET_{name} goto ENDIFVSPIN{name}2
634
677
  :ENDIFVSPIN{name}1
@@ -640,16 +683,13 @@ class BatchDeactivate(ActivateScriptPatcher):
640
683
  set _OLD_SPIN_UNSET_{name}=
641
684
  goto ENDIFVSPIN{name}0
642
685
  :ENDIFVSPIN{name}0
643
- """
644
- )
645
- script = dedent(
646
- """
686
+ """)
687
+ script = dedent("""
647
688
  @echo off
648
689
  {patchmarker}
649
690
  {original}
650
691
  {resetters}
651
- """
652
- )
692
+ """)
653
693
 
654
694
 
655
695
  class PythonActivate(ActivateScriptPatcher):
@@ -659,13 +699,11 @@ class PythonActivate(ActivateScriptPatcher):
659
699
  old_env_pattern = ""
660
700
  setpattern = 'os.environ["{name}"] = fr"{value}"'
661
701
  resetpattern = ""
662
- script = dedent(
663
- """
702
+ script = dedent("""
664
703
  {patchmarker}
665
704
  {original}
666
705
  {setters}
667
- """
668
- )
706
+ """)
669
707
 
670
708
  @staticmethod
671
709
  def interpolate_environ_value(value: str) -> str:
@@ -810,13 +848,31 @@ class SimpleProvisioner(ProvisionerProtocol):
810
848
  )
811
849
 
812
850
  def install(self: Self, cfg: ConfigTree) -> None:
813
- if requirements := self._filter(
814
- self._requirements, self._m, cfg.spin.project_root
815
- ):
816
- self._install_command(*self._split(requirements))
817
- self._m.clear()
818
- for req in requirements:
819
- self._m.add(_req_for_memo(req, cfg.spin.project_root))
851
+ @contextmanager
852
+ def skip_js_build(cfg: ConfigTree) -> Generator[None, None, None]:
853
+ if cfg.python.skip_js_build:
854
+ try:
855
+ setenv(SETUPTOOLS_CE_BUILD_JS_SKIP=1)
856
+ yield
857
+ setenv(SETUPTOOLS_CE_BUILD_JS_SKIP=None)
858
+ finally:
859
+ # Make sure the variable will not be written into the
860
+ # activation scripts
861
+ global EXPORTS # pylint: disable=global-statement
862
+ EXPORTS = [
863
+ (k, v) for k, v in EXPORTS if k != "SETUPTOOLS_CE_BUILD_JS_SKIP"
864
+ ]
865
+ else:
866
+ yield
867
+
868
+ with skip_js_build(cfg):
869
+ if self._m.items():
870
+ self._install_command("--upgrade", *self._split(self._requirements))
871
+ else:
872
+ self._install_command(*self._split(self._requirements))
873
+ self._m.clear()
874
+ for req in self._requirements:
875
+ self._m.add(_req_for_memo(req, cfg.spin.project_root))
820
876
 
821
877
  @staticmethod
822
878
  def _split(requirements: Iterable[str]) -> list[str]:
@@ -826,20 +882,6 @@ class SimpleProvisioner(ProvisionerProtocol):
826
882
  requirement_list.extend(requirement.split())
827
883
  return requirement_list
828
884
 
829
- @staticmethod
830
- def _filter(
831
- requirements: set[str], memo: Memoizer, project_root: Union[Path, str]
832
- ) -> set[str]:
833
- """
834
- We want to filter all requirements prior to installing them, because we
835
- only want to run the install, when there are changes, as it takes pip
836
- quite some time to check, whether it has to do something.
837
- """
838
- if all(memo.check(_req_for_memo(req, project_root)) for req in requirements):
839
- return set()
840
- else:
841
- return requirements
842
-
843
885
 
844
886
  def _file_hash(filename: Union[Path, str]) -> str:
845
887
  """
@@ -898,15 +940,12 @@ def _req_for_memo(
898
940
 
899
941
 
900
942
  def venv_provision( # pylint: disable=too-many-branches,missing-function-docstring
901
- cfg: ConfigTree,
943
+ cfg: ConfigTree, fresh_venv: bool = False
902
944
  ) -> None:
903
- fresh_env = False
904
945
 
905
- info("Checking venv '{python.venv}'")
906
- if not exists(cfg.python.venv):
946
+ if fresh_venv:
907
947
  info("Provisioning venv '{python.venv}'")
908
948
  cfg.python.provisioner.provision_venv(cfg)
909
- fresh_env = True
910
949
 
911
950
  # This sets PATH to the venv
912
951
  init(cfg)
@@ -914,7 +953,7 @@ def venv_provision( # pylint: disable=too-many-branches,missing-function-docstr
914
953
  _configure_pipconf(cfg)
915
954
 
916
955
  # Establish the prerequisites
917
- if fresh_env:
956
+ if fresh_venv:
918
957
  cfg.python.provisioner.prerequisites(cfg)
919
958
 
920
959
  # Plugins can define a 'venv_hook' function, to give them a
@@ -943,6 +982,19 @@ def venv_provision( # pylint: disable=too-many-branches,missing-function-docstr
943
982
 
944
983
  def cleanup(cfg: ConfigTree) -> None:
945
984
  """Remove directories and files generated by the python plugin."""
985
+ _cleanup_memoed_provisioners(cfg)
986
+ rmtree(cfg.python.provisioner_memo)
987
+ rmtree(cfg.python.aws_auth.memo)
988
+ for path in cfg.python.build_wheels:
989
+ current_path = Path(interpolate1(path))
990
+ rmtree(current_path / "build")
991
+ rmtree(current_path / "dist")
992
+ for filename in os.listdir(current_path):
993
+ if filename.endswith(".egg-info") or filename.endswith(".dist-info"):
994
+ rmtree(current_path / filename)
995
+
996
+
997
+ def _cleanup_memoed_provisioners(cfg: ConfigTree) -> None:
946
998
  with memoizer(cfg.python.provisioner_memo) as memo:
947
999
  for provisioner in memo.items():
948
1000
  try:
@@ -954,16 +1006,6 @@ def cleanup(cfg: ConfigTree) -> None:
954
1006
  )
955
1007
  memo.clear()
956
1008
 
957
- rmtree(cfg.python.provisioner_memo)
958
- rmtree(cfg.python.aws_auth.memo)
959
- for path in cfg.python.build_wheels:
960
- current_path = Path(interpolate1(path))
961
- rmtree(current_path / "build")
962
- rmtree(current_path / "dist")
963
- for filename in os.listdir(current_path):
964
- if filename.endswith(".egg-info") or filename.endswith(".dist-info"):
965
- rmtree(current_path / filename)
966
-
967
1009
 
968
1010
  def _get_pipconf(cfg: ConfigTree) -> Path:
969
1011
  """Retrieve the pipconf configuration file path."""
@@ -160,3 +160,8 @@ python:
160
160
  role_arn:
161
161
  type: str
162
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.
@@ -181,8 +181,9 @@ def _update_index_url_in_toml(cfg: ConfigTree) -> None:
181
181
  Update the index-url in the uv.toml in case it changed.
182
182
  """
183
183
  if (uv_toml_path := interpolate1(Path(cfg.uv_provisioner.uv_toml_path))).exists():
184
- with open(uv_toml_path, mode="r+b") as fd:
184
+ with open(uv_toml_path, mode="rb") as fd:
185
185
  toml_content = tomllib.load(fd)
186
- if toml_content.get("index-url") != cfg.python.index_url:
187
- toml_content["index-url"] = cfg.python.index_url
186
+ if toml_content.get("index-url") != cfg.python.index_url:
187
+ toml_content["index-url"] = cfg.python.index_url
188
+ with open(uv_toml_path, mode="wb") as fd:
188
189
  tomli_w.dump(toml_content, fd)
@@ -1,23 +1,27 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csspin-python
3
- Version: 3.1.1
3
+ Version: 4.0.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: Homepage, https://contact-software.com
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
12
16
  Classifier: Operating System :: OS Independent
13
17
  Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.9
15
18
  Classifier: Programming Language :: Python :: 3.10
16
19
  Classifier: Programming Language :: Python :: 3.11
17
20
  Classifier: Programming Language :: Python :: 3.12
18
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
19
23
  Classifier: Topic :: Software Development
20
- Requires-Python: >=3.9
24
+ Requires-Python: >=3.10
21
25
  Description-Content-Type: text/x-rst
22
26
  License-File: LICENSE
23
27
  Requires-Dist: platformdirs~=4.3.8
@@ -86,7 +90,7 @@ within the `spinfile.yaml` configuration file of your project.
86
90
  - csspin_python.pytest
87
91
 
88
92
  python:
89
- version: 3.9.8
93
+ version: 3.10.19
90
94
  requirements:
91
95
  - sphinx-click
92
96
  - sphinx-rtd-theme
@@ -2,20 +2,20 @@ csspin_python/behave.py,sha256=iJZeyIqB7V_NzTdLTZldNY9W_GGwCWkXe6WY69wpDqs,4997
2
2
  csspin_python/behave_schema.yaml,sha256=8qoOCK-uTmwgRRW29urgK0X_kgn0zO0X34v89bvii2w,1241
3
3
  csspin_python/debugpy.py,sha256=v0ZZopv5TNoSaFf2kiePsw9OmhBpjfOBFh0u71jTcnQ,962
4
4
  csspin_python/debugpy_schema.yaml,sha256=BeH30nSirDYctkdhS9xMXUG5htj3PED_ZjmxPG5WRUc,364
5
- csspin_python/devpi.py,sha256=C-5O_vA06CwQR4uElOw-2VH2-m001SpxowM_X6RbRwo,2352
5
+ csspin_python/devpi.py,sha256=o7O06Dw-xt47y-M74TShcl9MUMaW78aFmw6i6ISYwoU,2351
6
6
  csspin_python/devpi_schema.yaml,sha256=2gPATWjVcfvCTrGZX2FK6wH8hh9KS0XzZ35JvZeJGEU,487
7
7
  csspin_python/playwright.py,sha256=oFfphLqa4AB6K9vasCUFHN0kFXu63n3ocrsqVuRp4-0,5102
8
8
  csspin_python/playwright_schema.yaml,sha256=TSeR16YHa7m7bfO59F2eMV-jXcglluTJdEpUeL16saY,1178
9
- csspin_python/pytest.py,sha256=pTOb5zFd9RINZwJsHNaRuSGVDkPMABzaAhwpAJo1nQE,4574
9
+ csspin_python/pytest.py,sha256=N9YaU_ouQab0PFPf46HLE7Vg4JeoZW4dzVD7EevqJ1U,4573
10
10
  csspin_python/pytest_schema.yaml,sha256=tzXtdF6MvGC9v59EVRJFfLeMMHqPsXcFXy2zJtRECBI,1535
11
- csspin_python/python.py,sha256=32L4S6fKMWh5tbU-Rv5l6NVqrjjPLAiL25cB5gfeiC4,34784
12
- csspin_python/python_schema.yaml,sha256=_EBDglOM9AuXOvYUjFRJkUmtezCHcObEYmO64f-FOHI,6176
11
+ csspin_python/python.py,sha256=ogmaOdaXXZHaCYaPa0b2y11Rn6ZgMgzRftUG6-seBWM,36824
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=MGedx4e286ZE1miwh70y6b3wePw3mmc0m1kG6H_738I,5999
15
+ csspin_python/uv_provisioner.py,sha256=1e-_Sb39JrqNWyaUNeBX59R5tutXLJ1ZsT7urCN1U0I,6044
16
16
  csspin_python/uv_provisioner_schema.yaml,sha256=Y8ZNC2OMnhR8Us3WUXAXK9hMjqGWAKFJB2puX4X5XNQ,727
17
- csspin_python-3.1.1.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
18
- csspin_python-3.1.1.dist-info/METADATA,sha256=OsIblHbaQVC9ybAydVQ1L-YEzqKtzw3qyJZnXqc-nZs,4715
19
- csspin_python-3.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
- csspin_python-3.1.1.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
21
- csspin_python-3.1.1.dist-info/RECORD,,
17
+ csspin_python-4.0.0.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
18
+ csspin_python-4.0.0.dist-info/METADATA,sha256=yC8s-jxM6RQjQWi6UsukDCZlGdoV_NOFubcZ0Y-QERM,5035
19
+ csspin_python-4.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
20
+ csspin_python-4.0.0.dist-info/top_level.txt,sha256=QSeglMEGbFu1z4L6MCQYwo01NgL0KojWvC4rzgMQ8gU,14
21
+ csspin_python-4.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5