poetry-plugin-lock-filter 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 RealDioBrando
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,216 @@
1
+ Metadata-Version: 2.4
2
+ Name: poetry-plugin-lock-filter
3
+ Version: 0.1.0
4
+ Summary: Poetry plugin and CLI for creating marker-specific lock files
5
+ Author: RealDioBrando
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 RealDioBrando
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/RealDioBrando/poetry-plugin-lock-filter
29
+ Project-URL: Issues, https://github.com/RealDioBrando/poetry-plugin-lock-filter/issues
30
+ Keywords: poetry,plugin,lock,markers,platform
31
+ Classifier: Development Status :: 4 - Beta
32
+ Classifier: Environment :: Console
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Topic :: Software Development :: Build Tools
39
+ Requires-Python: >=3.11
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE
42
+ Requires-Dist: packaging>=24.2
43
+ Requires-Dist: poetry<3,>=2.1
44
+ Requires-Dist: tomlkit>=0.11
45
+ Dynamic: license-file
46
+
47
+ # poetry-plugin-lock-filter
48
+
49
+ A Poetry 2.x plugin and standalone CLI for creating **marker-specific lock files**.
50
+
51
+ Poetry writes a universal `poetry.lock` that contains every marker branch. Installation evaluates those markers at runtime, but the lock file itself remains broad. This project post-processes a Poetry lock file and keeps only packages whose markers match a selected target environment.
52
+
53
+ ## Why
54
+
55
+ Given dependencies such as:
56
+
57
+ ```toml
58
+ [tool.poetry.dependencies]
59
+ linux-only = { version = "1.0", markers = "sys_platform == 'linux'" }
60
+ windows-only = { version = "2.0", markers = "sys_platform == 'win32'" }
61
+ ```
62
+
63
+ Poetry 2.4.1 writes both packages to `poetry.lock`, even when only one branch is active on the current machine.
64
+
65
+ `poetry install` selects the correct packages, but tools that read `poetry.lock` directly often see both branches. This plugin produces a clean, target-specific lock file without changing the original.
66
+
67
+ ## Features
68
+
69
+ - Poetry plugin command: `poetry filter-lock`
70
+ - Standalone command: `poetry-lock-filter`
71
+ - Presets for common target environments
72
+ - Repeated `--env KEY=VALUE` overrides
73
+ - Main-group filtering by default
74
+ - Optional-package exclusion by default
75
+ - Dependency pruning so retained packages only reference retained dependencies
76
+ - JSON report output
77
+ - Original `poetry.lock` is preserved by default
78
+
79
+ ## Installation
80
+
81
+ Install as a Poetry plugin:
82
+
83
+ ```bash
84
+ poetry self add git+https://github.com/RealDioBrando/poetry-plugin-lock-filter.git
85
+ ```
86
+
87
+ Or install it as a normal Python package:
88
+
89
+ ```bash
90
+ pip install git+https://github.com/RealDioBrando/poetry-plugin-lock-filter.git
91
+ ```
92
+
93
+ ## Poetry plugin usage
94
+
95
+ Run inside a Poetry project:
96
+
97
+ ```bash
98
+ poetry filter-lock
99
+ ```
100
+
101
+ This reads the project’s `poetry.lock` and writes:
102
+
103
+ ```text
104
+ poetry.target.lock
105
+ ```
106
+
107
+ The default target environment is:
108
+
109
+ ```text
110
+ Linux
111
+ aarch64
112
+ CPython 3.11
113
+ ```
114
+
115
+ ## Standalone usage
116
+
117
+ ```bash
118
+ poetry-lock-filter \
119
+ --project /path/to/project \
120
+ --output poetry.target.lock \
121
+ --preset linux-aarch64-cp311
122
+ ```
123
+
124
+ If `--project` is omitted, the command uses the current directory.
125
+
126
+ ## Target presets
127
+
128
+ - `current`
129
+ - `linux-aarch64-cp311`
130
+ - `linux-x86_64-cp311`
131
+ - `windows-x86_64-cp311`
132
+
133
+ Override individual environment markers:
134
+
135
+ ```bash
136
+ poetry filter-lock \
137
+ --preset linux-aarch64-cp311 \
138
+ --env python_version=3.11 \
139
+ --env platform_machine=aarch64
140
+ ```
141
+
142
+ Use `--preset current` to filter for the machine running the command.
143
+
144
+ ## Options
145
+
146
+ ```text
147
+ --output PATH Output lock file; default poetry.target.lock
148
+ --preset NAME Target environment preset
149
+ --env KEY=VALUE Override a marker environment value; repeatable
150
+ --group NAME Dependency group to retain; default main
151
+ --include-optional Keep optional packages
152
+ --report PATH Write a JSON filtering report
153
+ --no-check Do not require a fresh lock file
154
+ ```
155
+
156
+ The standalone command also supports:
157
+
158
+ ```text
159
+ --project PATH Poetry project directory
160
+ --lock PATH Explicit lock file path
161
+ ```
162
+
163
+ ## Example report
164
+
165
+ ```json
166
+ {
167
+ "status": "success",
168
+ "input": "poetry.lock",
169
+ "output": "poetry.target.lock",
170
+ "group": "main",
171
+ "target_environment": {
172
+ "python_version": "3.11",
173
+ "sys_platform": "linux",
174
+ "platform_machine": "aarch64"
175
+ },
176
+ "included_packages": ["linux-only"],
177
+ "excluded_packages": [
178
+ {
179
+ "package": "windows-only",
180
+ "reason": "marker",
181
+ "marker": "sys_platform == \"win32\""
182
+ }
183
+ ]
184
+ }
185
+ ```
186
+
187
+ ## Dependency pruning
188
+
189
+ The filter also removes dependency references from retained packages when the referenced package was excluded.
190
+
191
+ For example, if `linux-only` depends on `linux-helper`, and both match the target environment, both are retained. If `linux-only` has a Windows-only dependency, that dependency edge is removed from the filtered lock.
192
+
193
+ ## Compatibility
194
+
195
+ - Python 3.11 or newer
196
+ - Poetry 2.1 or newer
197
+ - Poetry lock format 2.1 or newer
198
+
199
+ ## Development
200
+
201
+ ```bash
202
+ python -m venv .venv
203
+ .venv/bin/python -m pip install -e .[dev]
204
+ .venv/bin/python -m unittest discover -s tests -v
205
+ ```
206
+
207
+ ## License
208
+
209
+ MIT
210
+
211
+
212
+ ## Related projects
213
+
214
+ - [poetry-plugin-export](https://github.com/python-poetry/poetry-plugin-export) exports a Poetry lock file to requirements formats, but does not create a marker-filtered lock file.
215
+ - [poetry-lock-package](https://github.com/bneijt/poetry-lock-package) turns a lock file into a pinned package, but does not filter packages by environment markers.
216
+ - [ofiuco](https://github.com/oxidase/ofiuco) provides Bazel rules for cross-platform Poetry lock files, but is not a Poetry plugin or standalone marker filter.
@@ -0,0 +1,170 @@
1
+ # poetry-plugin-lock-filter
2
+
3
+ A Poetry 2.x plugin and standalone CLI for creating **marker-specific lock files**.
4
+
5
+ Poetry writes a universal `poetry.lock` that contains every marker branch. Installation evaluates those markers at runtime, but the lock file itself remains broad. This project post-processes a Poetry lock file and keeps only packages whose markers match a selected target environment.
6
+
7
+ ## Why
8
+
9
+ Given dependencies such as:
10
+
11
+ ```toml
12
+ [tool.poetry.dependencies]
13
+ linux-only = { version = "1.0", markers = "sys_platform == 'linux'" }
14
+ windows-only = { version = "2.0", markers = "sys_platform == 'win32'" }
15
+ ```
16
+
17
+ Poetry 2.4.1 writes both packages to `poetry.lock`, even when only one branch is active on the current machine.
18
+
19
+ `poetry install` selects the correct packages, but tools that read `poetry.lock` directly often see both branches. This plugin produces a clean, target-specific lock file without changing the original.
20
+
21
+ ## Features
22
+
23
+ - Poetry plugin command: `poetry filter-lock`
24
+ - Standalone command: `poetry-lock-filter`
25
+ - Presets for common target environments
26
+ - Repeated `--env KEY=VALUE` overrides
27
+ - Main-group filtering by default
28
+ - Optional-package exclusion by default
29
+ - Dependency pruning so retained packages only reference retained dependencies
30
+ - JSON report output
31
+ - Original `poetry.lock` is preserved by default
32
+
33
+ ## Installation
34
+
35
+ Install as a Poetry plugin:
36
+
37
+ ```bash
38
+ poetry self add git+https://github.com/RealDioBrando/poetry-plugin-lock-filter.git
39
+ ```
40
+
41
+ Or install it as a normal Python package:
42
+
43
+ ```bash
44
+ pip install git+https://github.com/RealDioBrando/poetry-plugin-lock-filter.git
45
+ ```
46
+
47
+ ## Poetry plugin usage
48
+
49
+ Run inside a Poetry project:
50
+
51
+ ```bash
52
+ poetry filter-lock
53
+ ```
54
+
55
+ This reads the project’s `poetry.lock` and writes:
56
+
57
+ ```text
58
+ poetry.target.lock
59
+ ```
60
+
61
+ The default target environment is:
62
+
63
+ ```text
64
+ Linux
65
+ aarch64
66
+ CPython 3.11
67
+ ```
68
+
69
+ ## Standalone usage
70
+
71
+ ```bash
72
+ poetry-lock-filter \
73
+ --project /path/to/project \
74
+ --output poetry.target.lock \
75
+ --preset linux-aarch64-cp311
76
+ ```
77
+
78
+ If `--project` is omitted, the command uses the current directory.
79
+
80
+ ## Target presets
81
+
82
+ - `current`
83
+ - `linux-aarch64-cp311`
84
+ - `linux-x86_64-cp311`
85
+ - `windows-x86_64-cp311`
86
+
87
+ Override individual environment markers:
88
+
89
+ ```bash
90
+ poetry filter-lock \
91
+ --preset linux-aarch64-cp311 \
92
+ --env python_version=3.11 \
93
+ --env platform_machine=aarch64
94
+ ```
95
+
96
+ Use `--preset current` to filter for the machine running the command.
97
+
98
+ ## Options
99
+
100
+ ```text
101
+ --output PATH Output lock file; default poetry.target.lock
102
+ --preset NAME Target environment preset
103
+ --env KEY=VALUE Override a marker environment value; repeatable
104
+ --group NAME Dependency group to retain; default main
105
+ --include-optional Keep optional packages
106
+ --report PATH Write a JSON filtering report
107
+ --no-check Do not require a fresh lock file
108
+ ```
109
+
110
+ The standalone command also supports:
111
+
112
+ ```text
113
+ --project PATH Poetry project directory
114
+ --lock PATH Explicit lock file path
115
+ ```
116
+
117
+ ## Example report
118
+
119
+ ```json
120
+ {
121
+ "status": "success",
122
+ "input": "poetry.lock",
123
+ "output": "poetry.target.lock",
124
+ "group": "main",
125
+ "target_environment": {
126
+ "python_version": "3.11",
127
+ "sys_platform": "linux",
128
+ "platform_machine": "aarch64"
129
+ },
130
+ "included_packages": ["linux-only"],
131
+ "excluded_packages": [
132
+ {
133
+ "package": "windows-only",
134
+ "reason": "marker",
135
+ "marker": "sys_platform == \"win32\""
136
+ }
137
+ ]
138
+ }
139
+ ```
140
+
141
+ ## Dependency pruning
142
+
143
+ The filter also removes dependency references from retained packages when the referenced package was excluded.
144
+
145
+ For example, if `linux-only` depends on `linux-helper`, and both match the target environment, both are retained. If `linux-only` has a Windows-only dependency, that dependency edge is removed from the filtered lock.
146
+
147
+ ## Compatibility
148
+
149
+ - Python 3.11 or newer
150
+ - Poetry 2.1 or newer
151
+ - Poetry lock format 2.1 or newer
152
+
153
+ ## Development
154
+
155
+ ```bash
156
+ python -m venv .venv
157
+ .venv/bin/python -m pip install -e .[dev]
158
+ .venv/bin/python -m unittest discover -s tests -v
159
+ ```
160
+
161
+ ## License
162
+
163
+ MIT
164
+
165
+
166
+ ## Related projects
167
+
168
+ - [poetry-plugin-export](https://github.com/python-poetry/poetry-plugin-export) exports a Poetry lock file to requirements formats, but does not create a marker-filtered lock file.
169
+ - [poetry-lock-package](https://github.com/bneijt/poetry-lock-package) turns a lock file into a pinned package, but does not filter packages by environment markers.
170
+ - [ofiuco](https://github.com/oxidase/ofiuco) provides Bazel rules for cross-platform Poetry lock files, but is not a Poetry plugin or standalone marker filter.
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "poetry-plugin-lock-filter"
7
+ version = "0.1.0"
8
+ description = "Poetry plugin and CLI for creating marker-specific lock files"
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ authors = [{ name = "RealDioBrando" }]
12
+ requires-python = ">=3.11"
13
+ dependencies = [
14
+ "packaging>=24.2",
15
+ "poetry>=2.1,<3",
16
+ "tomlkit>=0.11",
17
+ ]
18
+ keywords = ["poetry", "plugin", "lock", "markers", "platform"]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Environment :: Console",
22
+ "Intended Audience :: Developers",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Topic :: Software Development :: Build Tools",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/RealDioBrando/poetry-plugin-lock-filter"
32
+ Issues = "https://github.com/RealDioBrando/poetry-plugin-lock-filter/issues"
33
+
34
+ [project.entry-points."poetry.application.plugin"]
35
+ filter-lock = "poetry_plugin_lock_filter.plugin:FilterLockApplicationPlugin"
36
+
37
+ [project.scripts]
38
+ poetry-lock-filter = "poetry_plugin_lock_filter.cli:main"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """poetry-plugin-lock-filter."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """Allow `python -m poetry_plugin_lock_filter`."""
2
+
3
+ from poetry_plugin_lock_filter.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,94 @@
1
+ """Standalone command-line interface for marker-specific Poetry lock filtering."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ from pathlib import Path
8
+
9
+ from poetry_plugin_lock_filter.core import (
10
+ PRESETS,
11
+ LockFilterError,
12
+ build_environment,
13
+ filter_lock_file,
14
+ write_report,
15
+ )
16
+
17
+
18
+ def build_parser() -> argparse.ArgumentParser:
19
+ parser = argparse.ArgumentParser(
20
+ prog="poetry-lock-filter",
21
+ description="Create a marker-specific Poetry lock file.",
22
+ )
23
+ parser.add_argument("--project", type=Path, default=Path.cwd())
24
+ parser.add_argument("--lock", type=Path)
25
+ parser.add_argument("--output", type=Path)
26
+ parser.add_argument(
27
+ "--preset",
28
+ choices=sorted(PRESETS),
29
+ default="linux-aarch64-cp311",
30
+ )
31
+ parser.add_argument(
32
+ "--env",
33
+ action="append",
34
+ default=[],
35
+ metavar="KEY=VALUE",
36
+ help="override a marker environment value; repeatable",
37
+ )
38
+ parser.add_argument("--group", default="main")
39
+ parser.add_argument("--include-optional", action="store_true")
40
+ parser.add_argument("--report", type=Path)
41
+ return parser
42
+
43
+
44
+ def _parse_environment_overrides(values: list[str]) -> dict[str, str]:
45
+ overrides: dict[str, str] = {}
46
+ for value in values:
47
+ key, separator, environment_value = value.partition("=")
48
+ if not separator or not key.strip():
49
+ raise argparse.ArgumentTypeError(
50
+ f"Expected KEY=VALUE environment override, got {value!r}"
51
+ )
52
+ overrides[key.strip()] = environment_value
53
+ return overrides
54
+
55
+
56
+ def _resolve(path: Path, project: Path) -> Path:
57
+ return path if path.is_absolute() else project / path
58
+
59
+
60
+ def main(argv: list[str] | None = None) -> int:
61
+ parser = build_parser()
62
+ args = parser.parse_args(argv)
63
+ project = args.project.resolve()
64
+
65
+ try:
66
+ overrides = _parse_environment_overrides(args.env)
67
+ lock = args.lock.resolve() if args.lock else (project / "poetry.lock").resolve()
68
+ output = (
69
+ _resolve(args.output, project)
70
+ if args.output
71
+ else project / "poetry.target.lock"
72
+ )
73
+ report_path = _resolve(args.report, project) if args.report else None
74
+
75
+ environment = build_environment(args.preset, overrides)
76
+ report = filter_lock_file(
77
+ lock,
78
+ output,
79
+ environment,
80
+ group=args.group,
81
+ include_optional=args.include_optional,
82
+ )
83
+ except (LockFilterError, argparse.ArgumentTypeError) as error:
84
+ parser.exit(1, f"ERROR: {error}\n")
85
+
86
+ if report_path is not None:
87
+ write_report(report_path, report)
88
+
89
+ print(json.dumps(report, indent=2, ensure_ascii=False))
90
+ return 0
91
+
92
+
93
+ if __name__ == "__main__":
94
+ raise SystemExit(main())