kspl 1.1.0__tar.gz → 1.2.0__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.
kspl-1.2.0/PKG-INFO ADDED
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.3
2
+ Name: kspl
3
+ Version: 1.2.0
4
+ Summary: KConfig GUI for Software Product Lines with multiple variants.
5
+ License: MIT
6
+ Author: Cuinixam
7
+ Author-email: cuinixam@me.com
8
+ Requires-Python: <4.0,>=3.10
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Natural Language :: English
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Requires-Dist: customtkinter (>=5,<6)
20
+ Requires-Dist: kconfiglib (>=14,<15)
21
+ Requires-Dist: py-app-dev (>=2,<3)
22
+ Project-URL: Bug Tracker, https://github.com/cuinixam/kspl/issues
23
+ Project-URL: Changelog, https://github.com/cuinixam/kspl/blob/main/CHANGELOG.md
24
+ Project-URL: Repository, https://github.com/cuinixam/kspl
25
+ Description-Content-Type: text/markdown
26
+
27
+ # SPL KConfig GUI
28
+
29
+ <p align="center">
30
+ <a href="https://github.com/cuinixam/kspl/actions/workflows/ci.yml?query=branch%3Amain">
31
+ <img src="https://img.shields.io/github/actions/workflow/status/cuinixam/kspl/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
32
+ </a>
33
+ <a href="https://codecov.io/gh/cuinixam/kspl">
34
+ <img src="https://img.shields.io/codecov/c/github/cuinixam/kspl.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
35
+ </a>
36
+ </p>
37
+ <p align="center">
38
+ <a href="https://github.com/astral-sh/uv">
39
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
40
+ </a>
41
+ <a href="https://github.com/astral-sh/ruff">
42
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
43
+ </a>
44
+ <a href="https://github.com/pre-commit/pre-commit">
45
+ <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
46
+ </a>
47
+ </p>
48
+ <p align="center">
49
+ <a href="https://pypi.org/project/kspl/">
50
+ <img src="https://img.shields.io/pypi/v/kspl.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
51
+ </a>
52
+ <img src="https://img.shields.io/pypi/pyversions/kspl.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">
53
+ <img src="https://img.shields.io/pypi/l/kspl.svg?style=flat-square" alt="License">
54
+ </p>
55
+
56
+ ---
57
+
58
+ **Source Code**: <a href="https://github.com/cuinixam/kspl" target="_blank">https://github.com/cuinixam/kspl </a>
59
+
60
+ ---
61
+
62
+ KConfig GUI for Software Product Lines with multiple variants.
63
+
64
+ ## Installation
65
+
66
+ Install this via pip (or your favourite package manager):
67
+
68
+ `pip install kspl`
69
+
70
+ ## Usage
71
+
72
+ Start by importing it:
73
+
74
+ ```python
75
+ import kspl
76
+ ```
77
+
78
+ ## Contributors ✨
79
+
80
+ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
81
+
82
+ <!-- prettier-ignore-start -->
83
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
84
+ <!-- markdownlint-disable -->
85
+ <!-- markdownlint-enable -->
86
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
87
+ <!-- prettier-ignore-end -->
88
+
89
+ This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
90
+
91
+ ## Credits
92
+
93
+ [![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-orange.json)](https://github.com/copier-org/copier)
94
+
95
+ This package was created with
96
+ [Copier](https://copier.readthedocs.io/) and the
97
+ [browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)
98
+ project template.
99
+
kspl-1.2.0/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # SPL KConfig GUI
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/cuinixam/kspl/actions/workflows/ci.yml?query=branch%3Amain">
5
+ <img src="https://img.shields.io/github/actions/workflow/status/cuinixam/kspl/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
6
+ </a>
7
+ <a href="https://codecov.io/gh/cuinixam/kspl">
8
+ <img src="https://img.shields.io/codecov/c/github/cuinixam/kspl.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
9
+ </a>
10
+ </p>
11
+ <p align="center">
12
+ <a href="https://github.com/astral-sh/uv">
13
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
14
+ </a>
15
+ <a href="https://github.com/astral-sh/ruff">
16
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
17
+ </a>
18
+ <a href="https://github.com/pre-commit/pre-commit">
19
+ <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
20
+ </a>
21
+ </p>
22
+ <p align="center">
23
+ <a href="https://pypi.org/project/kspl/">
24
+ <img src="https://img.shields.io/pypi/v/kspl.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
25
+ </a>
26
+ <img src="https://img.shields.io/pypi/pyversions/kspl.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">
27
+ <img src="https://img.shields.io/pypi/l/kspl.svg?style=flat-square" alt="License">
28
+ </p>
29
+
30
+ ---
31
+
32
+ **Source Code**: <a href="https://github.com/cuinixam/kspl" target="_blank">https://github.com/cuinixam/kspl </a>
33
+
34
+ ---
35
+
36
+ KConfig GUI for Software Product Lines with multiple variants.
37
+
38
+ ## Installation
39
+
40
+ Install this via pip (or your favourite package manager):
41
+
42
+ `pip install kspl`
43
+
44
+ ## Usage
45
+
46
+ Start by importing it:
47
+
48
+ ```python
49
+ import kspl
50
+ ```
51
+
52
+ ## Contributors ✨
53
+
54
+ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
55
+
56
+ <!-- prettier-ignore-start -->
57
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
58
+ <!-- markdownlint-disable -->
59
+ <!-- markdownlint-enable -->
60
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
61
+ <!-- prettier-ignore-end -->
62
+
63
+ This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
64
+
65
+ ## Credits
66
+
67
+ [![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-orange.json)](https://github.com/copier-org/copier)
68
+
69
+ This package was created with
70
+ [Copier](https://copier.readthedocs.io/) and the
71
+ [browniebroke/pypackage-template](https://github.com/browniebroke/pypackage-template)
72
+ project template.
@@ -0,0 +1,167 @@
1
+ [build-system]
2
+ build-backend = "poetry.core.masonry.api"
3
+
4
+ requires = [ "poetry-core>=2,<3" ]
5
+
6
+ [project]
7
+ name = "kspl"
8
+ version = "1.2.0"
9
+ description = "KConfig GUI for Software Product Lines with multiple variants."
10
+ readme = "README.md"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Cuinixam", email = "cuinixam@me.com" },
14
+ ]
15
+ requires-python = "<4.0,>=3.10"
16
+ classifiers = [
17
+ "Development Status :: 2 - Pre-Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Natural Language :: English",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3 :: Only",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Libraries",
27
+ ]
28
+
29
+ dependencies = [
30
+ "customtkinter>=5,<6",
31
+ "kconfiglib>=14,<15",
32
+ "py-app-dev>=2,<3",
33
+ ]
34
+ urls."Bug Tracker" = "https://github.com/cuinixam/kspl/issues"
35
+ urls.Changelog = "https://github.com/cuinixam/kspl/blob/main/CHANGELOG.md"
36
+ urls.repository = "https://github.com/cuinixam/kspl"
37
+ scripts.kspl = "kspl.main:main"
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "pypeline-runner>=1,<2",
42
+ "pytest>=8,<9",
43
+ "pytest-cov>=6,<7",
44
+ "pre-commit>=4,<5",
45
+ "wrapt",
46
+ ]
47
+
48
+ [tool.ruff]
49
+ target-version = "py39"
50
+ line-length = 180
51
+ lint.select = [
52
+ "B", # flake8-bugbear
53
+ "D", # flake8-docstrings
54
+ "C4", # flake8-comprehensions
55
+ "S", # flake8-bandit
56
+ "F", # pyflake
57
+ "E", # pycodestyle
58
+ "W", # pycodestyle
59
+ "UP", # pyupgrade
60
+ "I", # isort
61
+ "RUF", # ruff specific
62
+ ]
63
+ lint.ignore = [
64
+ "D100", # Missing docstring in public module
65
+ "D101", # Missing docstring in public class
66
+ "D102", # Missing docstring in public method
67
+ "D103", # Missing docstring in public function
68
+ "D104", # Missing docstring in public package
69
+ "D105", # Missing docstring in magic method
70
+ "D106", # Missing docstring in public nested class
71
+ "D107", # Missing docstring in `__init__`
72
+ "D203", # 1 blank line required before class docstring
73
+ "D212", # Multi-line docstring summary should start at the first line
74
+ "D401", # First line of docstring should be in imperative mood
75
+ ]
76
+ lint.per-file-ignores."bootstrap.py" = [ "D200", "D205", "D417", "S603", "UP006", "UP035" ]
77
+ lint.per-file-ignores."conftest.py" = [ "D100" ]
78
+ lint.per-file-ignores."setup.py" = [ "D100" ]
79
+ lint.per-file-ignores."tests/**/*" = [
80
+ "D100",
81
+ "D101",
82
+ "D102",
83
+ "D103",
84
+ "D104",
85
+ "S101",
86
+ ]
87
+ lint.isort.known-first-party = [ "kspl", "tests" ]
88
+
89
+ [tool.pytest.ini_options]
90
+ addopts = """\
91
+ -v
92
+ -Wdefault
93
+ --cov=kspl
94
+ --cov-report=term
95
+ --cov-report=xml
96
+ """
97
+ pythonpath = [ "src" ]
98
+
99
+ [tool.coverage.run]
100
+ branch = true
101
+
102
+ [tool.coverage.paths]
103
+ source = [
104
+ "src",
105
+ ".tox/**/site-packages",
106
+ ]
107
+
108
+ [tool.coverage.report]
109
+ exclude_lines = [
110
+ "pragma: no cover",
111
+ "@overload",
112
+ "if TYPE_CHECKING",
113
+ "raise NotImplementedError",
114
+ 'if __name__ == "__main__":',
115
+ ]
116
+
117
+ [tool.mypy]
118
+ check_untyped_defs = true
119
+ disallow_any_generics = true
120
+ disallow_incomplete_defs = true
121
+ disallow_untyped_defs = true
122
+ mypy_path = "src/"
123
+ no_implicit_optional = true
124
+ show_error_codes = true
125
+ warn_unreachable = true
126
+ warn_unused_ignores = true
127
+ exclude = [
128
+ 'setup.py',
129
+ ]
130
+
131
+ [[tool.mypy.overrides]]
132
+ module = "tests.*"
133
+ allow_untyped_defs = true
134
+
135
+ [tool.semantic_release]
136
+ version_toml = [ "pyproject.toml:project.version" ]
137
+ version_variables = [
138
+ "src/kspl/__init__.py:__version__",
139
+ ]
140
+ build_command = """
141
+ pip install uv
142
+ uv lock
143
+ git add uv.lock
144
+ uv build
145
+ """
146
+
147
+ [tool.semantic_release.changelog]
148
+ exclude_commit_patterns = [
149
+ '''chore(?:\([^)]*?\))?: .+''',
150
+ '''ci(?:\([^)]*?\))?: .+''',
151
+ '''refactor(?:\([^)]*?\))?: .+''',
152
+ '''style(?:\([^)]*?\))?: .+''',
153
+ '''test(?:\([^)]*?\))?: .+''',
154
+ '''build\((?!deps\): .+)''',
155
+ '''Merged? .*''',
156
+ '''Initial [Cc]ommit.*''', # codespell:ignore
157
+ ]
158
+
159
+ [tool.semantic_release.changelog.environment]
160
+ keep_trailing_newline = true
161
+
162
+ [tool.semantic_release.branches.main]
163
+ match = "main"
164
+
165
+ [tool.semantic_release.branches.noop]
166
+ match = "(?!main$)"
167
+ prerelease = true
@@ -0,0 +1 @@
1
+ __version__ = "1.2.0"
@@ -1,9 +1,13 @@
1
- """Used to run main from the command line when run from this repository.
2
- This is required because kspl module is not visible when running
3
- from the repository."""
4
- import runpy
5
- import sys
6
- from pathlib import Path
7
-
8
- sys.path.insert(0, Path(__file__).parent.parent.absolute().as_posix())
9
- runpy.run_module("kspl.main", run_name="__main__")
1
+ """
2
+ Used to run main from the command line when run from this repository.
3
+
4
+ This is required because kspl module is not visible when running
5
+ from the repository.
6
+ """
7
+
8
+ import runpy
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ sys.path.insert(0, Path(__file__).parent.parent.absolute().as_posix())
13
+ runpy.run_module("kspl.main", run_name="__main__")
@@ -1,85 +1,71 @@
1
- from dataclasses import dataclass
2
- from pathlib import Path
3
- from typing import Any, Dict, List, Optional
4
-
5
- from py_app_dev.core.exceptions import UserNotificationException
6
- from py_app_dev.core.logging import logger
7
-
8
- from kspl.kconfig import EditableConfigElement, KConfig
9
-
10
-
11
- @dataclass
12
- class VariantViewData:
13
- """A variant is a set of configuration values for a KConfig model."""
14
-
15
- name: str
16
- config_dict: Dict[str, Any]
17
-
18
-
19
- @dataclass
20
- class VariantData:
21
- name: str
22
- config: KConfig
23
-
24
- def find_element(self, element_name: str) -> Optional[EditableConfigElement]:
25
- return self.config.find_element(element_name)
26
-
27
-
28
- class SPLKConfigData:
29
- def __init__(self, project_root_dir: Path) -> None:
30
- self.project_root_dir = project_root_dir.absolute()
31
- variant_config_files = self._search_variant_config_file(self.project_root_dir)
32
- if not self.kconfig_model_file.is_file():
33
- raise UserNotificationException(
34
- f"File {self.kconfig_model_file} does not exist."
35
- )
36
- self.model = KConfig(self.kconfig_model_file)
37
- if variant_config_files:
38
- self.variant_configs: List[VariantData] = [
39
- VariantData(
40
- self._get_variant_name(file), KConfig(self.kconfig_model_file, file)
41
- )
42
- for file in variant_config_files
43
- ]
44
- else:
45
- self.variant_configs = [VariantData("Default", self.model)]
46
- self.logger = logger.bind()
47
-
48
- @property
49
- def kconfig_model_file(self) -> Path:
50
- return self.project_root_dir / "KConfig"
51
-
52
- def get_elements(self) -> List[EditableConfigElement]:
53
- return self.model.elements
54
-
55
- def get_variants(self) -> List[VariantViewData]:
56
- variants = []
57
-
58
- for variant in self.variant_configs:
59
- variants.append(
60
- VariantViewData(
61
- variant.name,
62
- {
63
- config_elem.name: config_elem.value
64
- for config_elem in variant.config.elements
65
- if not config_elem.is_menu
66
- },
67
- )
68
- )
69
- return variants
70
-
71
- def _get_variant_name(self, file: Path) -> str:
72
- return file.relative_to(self.project_root_dir / "variants").parent.as_posix()
73
-
74
- def _search_variant_config_file(self, project_dir: Path) -> List[Path]:
75
- """
76
- Finds all files called 'config.txt' in the variants directory
77
- and returns a list with their paths.
78
- """
79
- return list((project_dir / "variants").glob("**/config.txt"))
80
-
81
- def find_variant_config(self, variant_name: str) -> Optional[VariantData]:
82
- for variant in self.variant_configs:
83
- if variant.name == variant_name:
84
- return variant
85
- return None
1
+ from dataclasses import dataclass
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ from py_app_dev.core.exceptions import UserNotificationException
6
+ from py_app_dev.core.logging import logger
7
+
8
+ from kspl.kconfig import EditableConfigElement, KConfig
9
+
10
+
11
+ @dataclass
12
+ class VariantViewData:
13
+ """A variant is a set of configuration values for a KConfig model."""
14
+
15
+ name: str
16
+ config_dict: dict[str, Any]
17
+
18
+
19
+ @dataclass
20
+ class VariantData:
21
+ name: str
22
+ config: KConfig
23
+
24
+ def find_element(self, element_name: str) -> EditableConfigElement | None:
25
+ return self.config.find_element(element_name)
26
+
27
+
28
+ class SPLKConfigData:
29
+ def __init__(self, project_root_dir: Path) -> None:
30
+ self.project_root_dir = project_root_dir.absolute()
31
+ variant_config_files = self._search_variant_config_file(self.project_root_dir)
32
+ if not self.kconfig_model_file.is_file():
33
+ raise UserNotificationException(f"File {self.kconfig_model_file} does not exist.")
34
+ self.model = KConfig(self.kconfig_model_file)
35
+ if variant_config_files:
36
+ self.variant_configs: list[VariantData] = [VariantData(self._get_variant_name(file), KConfig(self.kconfig_model_file, file)) for file in variant_config_files]
37
+ else:
38
+ self.variant_configs = [VariantData("Default", self.model)]
39
+ self.logger = logger.bind()
40
+
41
+ @property
42
+ def kconfig_model_file(self) -> Path:
43
+ return self.project_root_dir / "KConfig"
44
+
45
+ def get_elements(self) -> list[EditableConfigElement]:
46
+ return self.model.elements
47
+
48
+ def get_variants(self) -> list[VariantViewData]:
49
+ variants = []
50
+
51
+ for variant in self.variant_configs:
52
+ variants.append(
53
+ VariantViewData(
54
+ variant.name,
55
+ {config_elem.name: config_elem.value for config_elem in variant.config.elements if not config_elem.is_menu},
56
+ )
57
+ )
58
+ return variants
59
+
60
+ def _get_variant_name(self, file: Path) -> str:
61
+ return file.relative_to(self.project_root_dir / "variants").parent.as_posix()
62
+
63
+ def _search_variant_config_file(self, project_dir: Path) -> list[Path]:
64
+ """Finds all files called 'config.txt' in the variants directory and returns a list with their paths."""
65
+ return list((project_dir / "variants").glob("**/config.txt"))
66
+
67
+ def find_variant_config(self, variant_name: str) -> VariantData | None:
68
+ for variant in self.variant_configs:
69
+ if variant.name == variant_name:
70
+ return variant
71
+ return None