extreqs 1.1.0__tar.gz → 1.2.1__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.
extreqs-1.2.1/PKG-INFO ADDED
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: extreqs
3
+ Version: 1.2.1
4
+ Summary: Parse python requirements.txt files into setuptools extras
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Dist: requirements-parser>=0.13.0
16
+ Requires-Python: >=3.10, <4.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ # extreqs
20
+
21
+ Parse python requirements.txt files into setuptools extras.
22
+
23
+ `extreqs` is a build-time dependency used in projects with a `requirements.txt` and a `setup.py`,
24
+ where the `setup.py` reads the `requirements.txt` to determine the runtime dependencies.
25
+
26
+ ## Do not use this package
27
+
28
+ `extreqs` was written in a simpler but much worse time for python packaging.
29
+ Historically, `setup.cfg` or `setup.py` was used to specify runtime dependencies.
30
+ Applications were supposed to use strict version constraints,
31
+ and libraries permissive version constraints.
32
+
33
+ For CI and development purposes,
34
+ it was convenient to use `requirements.txt` files to fix specific versions,
35
+ or to specify additional dependencies used at development time and not at runtime.
36
+
37
+ This meant manually syncing two files, which is a pain.
38
+ So the intended walls between the use of `requirements.txt` and `setup.py` started to break down, and a pattern emerged of parsing your single-source-of-truth `requirements.txt` to feed into your `setup.py`.
39
+
40
+ `extreqs` was developed to fill the need of describing ["extras"](https://stackoverflow.com/questions/52474931/what-is-extra-in-pypi-dependency) while still maintaining `requirements.txt` as your single source of truth.
41
+ `extreqs` was always intended primarily to support application development,
42
+ but could be used for library development as well as a bridge (or crutch?) for people who preferred using `requirements.txt` for specifying dependencies.
43
+
44
+ Today, various development tools, most notably [`uv`](https://docs.astral.sh/uv/), handle lock files for you based on the canonical `pyproject.toml` dependency list, which also handles extras and groups (for development dependencies).
45
+ Those tools, in particular `uv`, should be used instead.
46
+
47
+ This package is maintained for legacy purposes.
48
+
49
+ ## Usage
50
+
51
+ `extreqs` looks for special comments (`#extra:`) in your requirements files.
52
+ Note the lack of space after the `#`!
53
+ Anything which follows that (until the end of line, or another `#`) is treated as a whitespace-separated list of extras.
54
+ For example, `#extra: dev test doc` marks dependencies belonging to the `dev`, `test`, and `doc` extras.
55
+
56
+ If the `#extra:` comment is on the same line as (following) a dependency, then just that dependency belongs to that extra.
57
+ If the `#extra:` comment is on a line on its own, all dependencies below it belong to that extra, until the next `#extra:` line.
58
+
59
+ For example:
60
+
61
+ ```txt
62
+ # requirements.txt
63
+ dep1
64
+ dep2 #extra: e1
65
+
66
+ #extra: e2
67
+ dep3
68
+
69
+ #extra: e3 # you can still have freeform comments!
70
+ dep4 #extra: e4 e5
71
+ dep5
72
+ ```
73
+
74
+ would be parsed into
75
+
76
+ ```python
77
+ install_requires = ["dep1"]
78
+ extras_require = {
79
+ "e1": ["dep2"],
80
+ "e2": ["dep3"],
81
+ "e3": ["dep4", "dep5"],
82
+ "e4": ["dep4"],
83
+ "e5": ["dep4"],
84
+ }
85
+ ```
86
+
87
+ Additionally, entire files can belong to a particular extra.
88
+
89
+ Note that python extras are not smart enough to deal with dependencies which belong only to _combinations_ of extras, or _negative_ extras: a dependency which belongs to multiple extras (given by the context of the file, block, or line) just belongs to multiple extras.
90
+ This is a limitation of python packaging and cannot be addressed here.
91
+
92
+ In your `setup.py`:
93
+
94
+ ```python
95
+ #!/usr/bin/env python3
96
+ """setup.py"""
97
+ from pathlib import Path
98
+
99
+ from extreqs import parse_requirements_files_dict
100
+ from setuptools import setup
101
+
102
+ here = Path(__file__).resolve().parent
103
+
104
+ req_kwargs = parse_requirements_files_dict(
105
+ # files without an extra context are in *args
106
+ here / "requirements.txt",
107
+ # files with an extra context are in **kwargs
108
+ optional=here / "requirements-optional.txt",
109
+ )
110
+
111
+ setup(
112
+ name="my_package",
113
+ ...
114
+ **req_kwargs,
115
+ ...
116
+ )
117
+ ```
118
+
119
+ `extreqs` is an install-time dependency, and so must be added to your `pyproject.toml`:
120
+
121
+ ```toml
122
+ # pyproject.toml
123
+ [build-system]
124
+ requires = ["setuptools", "extreqs"]
125
+ build-backend = "setuptools.build_meta"
126
+ ```
127
+
128
+ Look out for dependency specifiers which are accepted by pip, but not by setuptools (e.g. editable install `-e` or references to other requirement files `-r`).
129
+
130
+ ## Development
131
+
132
+ Contributions are welcome, although any broadening of extreqs' scope is unlikely to be accepted - raise an issue first!
133
+
134
+ Releases are made like this
135
+
136
+ ```sh
137
+ # commit all your changes, push, and ensure that CI passes
138
+ git add .
139
+ git commit -m "Prepare for a new version"
140
+ git push
141
+
142
+ # bump the version
143
+ uv version --bump minor
144
+
145
+ # commit the version bump
146
+ git add .
147
+ git commit -m "Bump to version $(uv version --short)"
148
+
149
+ # tag the commit
150
+ git tag -a "v$(uv version --short)" -m "New feature X"
151
+
152
+ # push to CI, which will do the releasing
153
+ git push --follow-tags
154
+ ```
@@ -0,0 +1,136 @@
1
+ # extreqs
2
+
3
+ Parse python requirements.txt files into setuptools extras.
4
+
5
+ `extreqs` is a build-time dependency used in projects with a `requirements.txt` and a `setup.py`,
6
+ where the `setup.py` reads the `requirements.txt` to determine the runtime dependencies.
7
+
8
+ ## Do not use this package
9
+
10
+ `extreqs` was written in a simpler but much worse time for python packaging.
11
+ Historically, `setup.cfg` or `setup.py` was used to specify runtime dependencies.
12
+ Applications were supposed to use strict version constraints,
13
+ and libraries permissive version constraints.
14
+
15
+ For CI and development purposes,
16
+ it was convenient to use `requirements.txt` files to fix specific versions,
17
+ or to specify additional dependencies used at development time and not at runtime.
18
+
19
+ This meant manually syncing two files, which is a pain.
20
+ So the intended walls between the use of `requirements.txt` and `setup.py` started to break down, and a pattern emerged of parsing your single-source-of-truth `requirements.txt` to feed into your `setup.py`.
21
+
22
+ `extreqs` was developed to fill the need of describing ["extras"](https://stackoverflow.com/questions/52474931/what-is-extra-in-pypi-dependency) while still maintaining `requirements.txt` as your single source of truth.
23
+ `extreqs` was always intended primarily to support application development,
24
+ but could be used for library development as well as a bridge (or crutch?) for people who preferred using `requirements.txt` for specifying dependencies.
25
+
26
+ Today, various development tools, most notably [`uv`](https://docs.astral.sh/uv/), handle lock files for you based on the canonical `pyproject.toml` dependency list, which also handles extras and groups (for development dependencies).
27
+ Those tools, in particular `uv`, should be used instead.
28
+
29
+ This package is maintained for legacy purposes.
30
+
31
+ ## Usage
32
+
33
+ `extreqs` looks for special comments (`#extra:`) in your requirements files.
34
+ Note the lack of space after the `#`!
35
+ Anything which follows that (until the end of line, or another `#`) is treated as a whitespace-separated list of extras.
36
+ For example, `#extra: dev test doc` marks dependencies belonging to the `dev`, `test`, and `doc` extras.
37
+
38
+ If the `#extra:` comment is on the same line as (following) a dependency, then just that dependency belongs to that extra.
39
+ If the `#extra:` comment is on a line on its own, all dependencies below it belong to that extra, until the next `#extra:` line.
40
+
41
+ For example:
42
+
43
+ ```txt
44
+ # requirements.txt
45
+ dep1
46
+ dep2 #extra: e1
47
+
48
+ #extra: e2
49
+ dep3
50
+
51
+ #extra: e3 # you can still have freeform comments!
52
+ dep4 #extra: e4 e5
53
+ dep5
54
+ ```
55
+
56
+ would be parsed into
57
+
58
+ ```python
59
+ install_requires = ["dep1"]
60
+ extras_require = {
61
+ "e1": ["dep2"],
62
+ "e2": ["dep3"],
63
+ "e3": ["dep4", "dep5"],
64
+ "e4": ["dep4"],
65
+ "e5": ["dep4"],
66
+ }
67
+ ```
68
+
69
+ Additionally, entire files can belong to a particular extra.
70
+
71
+ Note that python extras are not smart enough to deal with dependencies which belong only to _combinations_ of extras, or _negative_ extras: a dependency which belongs to multiple extras (given by the context of the file, block, or line) just belongs to multiple extras.
72
+ This is a limitation of python packaging and cannot be addressed here.
73
+
74
+ In your `setup.py`:
75
+
76
+ ```python
77
+ #!/usr/bin/env python3
78
+ """setup.py"""
79
+ from pathlib import Path
80
+
81
+ from extreqs import parse_requirements_files_dict
82
+ from setuptools import setup
83
+
84
+ here = Path(__file__).resolve().parent
85
+
86
+ req_kwargs = parse_requirements_files_dict(
87
+ # files without an extra context are in *args
88
+ here / "requirements.txt",
89
+ # files with an extra context are in **kwargs
90
+ optional=here / "requirements-optional.txt",
91
+ )
92
+
93
+ setup(
94
+ name="my_package",
95
+ ...
96
+ **req_kwargs,
97
+ ...
98
+ )
99
+ ```
100
+
101
+ `extreqs` is an install-time dependency, and so must be added to your `pyproject.toml`:
102
+
103
+ ```toml
104
+ # pyproject.toml
105
+ [build-system]
106
+ requires = ["setuptools", "extreqs"]
107
+ build-backend = "setuptools.build_meta"
108
+ ```
109
+
110
+ Look out for dependency specifiers which are accepted by pip, but not by setuptools (e.g. editable install `-e` or references to other requirement files `-r`).
111
+
112
+ ## Development
113
+
114
+ Contributions are welcome, although any broadening of extreqs' scope is unlikely to be accepted - raise an issue first!
115
+
116
+ Releases are made like this
117
+
118
+ ```sh
119
+ # commit all your changes, push, and ensure that CI passes
120
+ git add .
121
+ git commit -m "Prepare for a new version"
122
+ git push
123
+
124
+ # bump the version
125
+ uv version --bump minor
126
+
127
+ # commit the version bump
128
+ git add .
129
+ git commit -m "Bump to version $(uv version --short)"
130
+
131
+ # tag the commit
132
+ git tag -a "v$(uv version --short)" -m "New feature X"
133
+
134
+ # push to CI, which will do the releasing
135
+ git push --follow-tags
136
+ ```
@@ -0,0 +1,34 @@
1
+ [project]
2
+ name = "extreqs"
3
+ version = "1.2.1"
4
+ description = "Parse python requirements.txt files into setuptools extras"
5
+ requires-python = ">=3.10,<4.0"
6
+ readme = "README.md"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ classifiers = [
10
+ "Development Status :: 3 - Alpha",
11
+ "License :: OSI Approved :: MIT License",
12
+ "Programming Language :: Python :: 3",
13
+ "Programming Language :: Python :: 3.10",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
17
+ "Programming Language :: Python :: 3.14",
18
+ ]
19
+
20
+ dependencies = [
21
+ "requirements-parser>=0.13.0",
22
+ ]
23
+
24
+ [build-system]
25
+ requires = ["uv_build>=0.10.0,<0.11.0"]
26
+ build-backend = "uv_build"
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "mypy>=1.19.1",
31
+ "pdoc3>=0.11.6",
32
+ "pytest>=9.0.2",
33
+ "ruff>=0.15.0",
34
+ ]
@@ -1,8 +1,10 @@
1
1
  """
2
2
  # extreqs package
3
3
  """
4
+
4
5
  from .main import parse_requirement_files, parse_requirement_files_dict
5
- from .version import version as __version__ # noqa: F401
6
- from .version import version_tuple as __version_info__ # noqa: F401
6
+ from importlib.metadata import version as _version
7
+
8
+ __version__ = _version("extreqs")
7
9
 
8
10
  __all__ = ["parse_requirement_files", "parse_requirement_files_dict"]
@@ -4,7 +4,7 @@ import typing as tp
4
4
  from collections import defaultdict
5
5
  from pathlib import Path
6
6
 
7
- import pkg_resources
7
+ from requirements.requirement import Requirement
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
 
@@ -17,6 +17,9 @@ def str_as_list(s: tp.Optional[tp.Union[str, tp.List[str]]]) -> tp.List[str]:
17
17
  return s
18
18
 
19
19
 
20
+ UNSUPPORTED_VCS = {"git", "hg", "svn", "bzr"}
21
+
22
+
20
23
  class Parser:
21
24
  def __init__(self, fpath, file_context=None) -> None:
22
25
  self.file_context = str_as_list(file_context)
@@ -45,6 +48,15 @@ class Parser:
45
48
  if req.startswith("#"):
46
49
  return None
47
50
 
51
+ components = req.split("+", maxsplit=1)
52
+ if len(components) == 2:
53
+ vcs = components[0]
54
+ if vcs in UNSUPPORTED_VCS:
55
+ raise RuntimeError(
56
+ f"Invalid VCS dependency `{req}`. Use this format instead: "
57
+ "`{package_name} @ {vcs}+{url}`"
58
+ )
59
+
48
60
  if len(extra_specs) > 1:
49
61
  logger.warning(
50
62
  "Multiple extra specs found; ignoring all but the first %s:%s",
@@ -76,11 +88,12 @@ class Parser:
76
88
 
77
89
  req, context = result
78
90
 
79
- if not is_valid_req(req):
91
+ try:
92
+ Requirement.parse(req)
93
+ except ValueError as e:
80
94
  raise ValueError(
81
- f"'{req}' is not a valid requirement string "
82
- f"{self.fpath}:{self.line_num}"
83
- )
95
+ f"'{req}' ({self.fpath}:{self.line_num}) is not a valid requirement string: {e}"
96
+ ) from e
84
97
 
85
98
  if not context:
86
99
  install_requires.append(req)
@@ -127,11 +140,8 @@ def parse_requirement_files(
127
140
  `install_requires` and `extras_require` arguments
128
141
  respectively.
129
142
  """
130
- to_merge = [Parser(fpath).parse() for fpath in req_files]
131
- to_merge.extend(
132
- Parser(fpath, extra).parse() for extra, fpath in extra_req_files.items()
133
- )
134
- return merge_install_extras(*to_merge)
143
+ d = parse_requirement_files_dict(*req_files, **extra_req_files)
144
+ return (d["install_requires"], d["extras_require"])
135
145
 
136
146
 
137
147
  if sys.version_info < (3, 8):
@@ -171,17 +181,20 @@ def parse_requirement_files_dict(
171
181
  "extras_require": {"extra_name": ["some", "requirement]},
172
182
  }
173
183
  """
174
- install_requires, extras_require = parse_requirement_files(
175
- *req_files, **extra_req_files
184
+ to_merge = [Parser(fpath).parse() for fpath in req_files]
185
+ to_merge.extend(
186
+ Parser(fpath, extra).parse() for extra, fpath in extra_req_files.items()
187
+ )
188
+ install_requires, extras_require = merge_install_extras(*to_merge)
189
+ return ParsedFiles(
190
+ install_requires=install_requires,
191
+ extras_require=extras_require,
176
192
  )
177
- return ParsedFiles(install_requires=install_requires, extras_require=extras_require)
178
193
 
179
194
 
180
- def is_valid_req(req):
195
+ def is_valid_req(req: str):
181
196
  try:
182
- reqs = list(pkg_resources.parse_requirements(req))
183
- if len(reqs) != 1:
184
- return False
185
- except Exception:
197
+ Requirement.parse(req)
198
+ return True
199
+ except ValueError:
186
200
  return False
187
- return True
@@ -1,16 +0,0 @@
1
- [*]
2
- indent_style = space
3
- indent_size = 4
4
- insert_final_newline = true
5
- trim_trailing_whitespace = true
6
- end_of_line = lf
7
- charset = utf-8
8
-
9
- [*.py]
10
- max_line_length = 88
11
-
12
- [Makefile]
13
- indent_style = tab
14
-
15
- [*.{yaml,json}]
16
- indent_size = 2
extreqs-1.1.0/.flake8 DELETED
@@ -1,5 +0,0 @@
1
- [flake8]
2
- max-line-length = 88
3
- extend-ignore = E203
4
-
5
- exclude = env
@@ -1,55 +0,0 @@
1
- on: [push, pull_request]
2
- name: Lint, test, deploy package
3
-
4
- defaults:
5
- run:
6
- shell: bash
7
-
8
- jobs:
9
-
10
- lint:
11
- runs-on: ubuntu-20.04
12
- steps:
13
- - uses: actions/checkout@v3
14
- - uses: actions/setup-python@v4
15
- with:
16
- python-version: '3.x'
17
- - run: pip install $(grep -E '^(black|flake8|isort|mypy)' requirements.txt)
18
- - run: make lint
19
-
20
- test:
21
- strategy:
22
- fail-fast: false
23
- matrix:
24
- python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
25
- runs-on: ubuntu-20.04
26
- steps:
27
- - uses: actions/checkout@v3
28
- - uses: actions/setup-python@v4
29
- with:
30
- python-version: ${{ matrix.python-version }}
31
- - run: |
32
- pip install -U pip wheel setuptools
33
- pip install -r requirements.txt
34
- name: Install dependencies
35
- - run: |
36
- pip install .
37
- name: Install package
38
- - run: pytest --verbose
39
-
40
- deploy-package:
41
- runs-on: ubuntu-20.04
42
- needs: [lint, test]
43
- if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
44
- steps:
45
- - uses: actions/checkout@v3
46
- - uses: actions/setup-python@v4
47
- with:
48
- python-version: 3.9
49
- - run: pip install build
50
- - run: python -m build --sdist --wheel -o dist/ .
51
- - name: Publish package
52
- uses: pypa/gh-action-pypi-publish@master
53
- with:
54
- user: __token__
55
- password: ${{ secrets.pypi_password }}
extreqs-1.1.0/.gitignore DELETED
@@ -1,143 +0,0 @@
1
- # Byte-compiled / optimized / DLL files
2
- __pycache__/
3
- *.py[cod]
4
- *$py.class
5
-
6
- # C extensions
7
- *.so
8
-
9
- # Distribution / packaging
10
- .Python
11
- build/
12
- develop-eggs/
13
- dist/
14
- downloads/
15
- eggs/
16
- .eggs/
17
- lib/
18
- lib64/
19
- parts/
20
- sdist/
21
- var/
22
- wheels/
23
- share/python-wheels/
24
- *.egg-info/
25
- .installed.cfg
26
- *.egg
27
- MANIFEST
28
-
29
- # PyInstaller
30
- # Usually these files are written by a python script from a template
31
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
- *.manifest
33
- *.spec
34
-
35
- # Installer logs
36
- pip-log.txt
37
- pip-delete-this-directory.txt
38
-
39
- # Unit test / coverage reports
40
- htmlcov/
41
- .tox/
42
- .nox/
43
- .coverage
44
- .coverage.*
45
- .cache
46
- nosetests.xml
47
- coverage.xml
48
- *.cover
49
- *.py,cover
50
- .hypothesis/
51
- .pytest_cache/
52
- cover/
53
-
54
- # Translations
55
- *.mo
56
- *.pot
57
-
58
- # Django stuff:
59
- *.log
60
- local_settings.py
61
- db.sqlite3
62
- db.sqlite3-journal
63
-
64
- # Flask stuff:
65
- instance/
66
- .webassets-cache
67
-
68
- # Scrapy stuff:
69
- .scrapy
70
-
71
- # Sphinx documentation
72
- docs/_build/
73
-
74
- # PyBuilder
75
- .pybuilder/
76
- target/
77
-
78
- # Jupyter Notebook
79
- .ipynb_checkpoints
80
-
81
- # IPython
82
- profile_default/
83
- ipython_config.py
84
-
85
- # pyenv
86
- # For a library or package, you might want to ignore these files since the code is
87
- # intended to run in multiple environments; otherwise, check them in:
88
- # .python-version
89
-
90
- # pipenv
91
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
- # install all needed dependencies.
95
- #Pipfile.lock
96
-
97
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98
- __pypackages__/
99
-
100
- # Celery stuff
101
- celerybeat-schedule
102
- celerybeat.pid
103
-
104
- # SageMath parsed files
105
- *.sage.py
106
-
107
- # Environments
108
- .env
109
- .venv
110
- env/
111
- venv/
112
- ENV/
113
- env.bak/
114
- venv.bak/
115
-
116
- # Spyder project settings
117
- .spyderproject
118
- .spyproject
119
-
120
- # Rope project settings
121
- .ropeproject
122
-
123
- # mkdocs documentation
124
- /site
125
-
126
- # mypy
127
- .mypy_cache/
128
- .dmypy.json
129
- dmypy.json
130
-
131
- # Pyre type checker
132
- .pyre/
133
-
134
- # pytype static type analyzer
135
- .pytype/
136
-
137
- # Cython debug symbols
138
- cython_debug/
139
-
140
- extreqs/version.py
141
-
142
- docs/
143
- env/
extreqs-1.1.0/Makefile DELETED
@@ -1,35 +0,0 @@
1
- .PHONY: fmt
2
- fmt:
3
- isort . \
4
- && black .
5
-
6
- .PHONY: lint
7
- lint:
8
- black --check .
9
- isort --check .
10
- flake8 .
11
-
12
- lint-type: lint
13
- mypy .
14
-
15
- .PHONY: test
16
- test:
17
- pytest --verbose
18
-
19
- .PHONY: install
20
- install:
21
- pip install .
22
-
23
- .PHONY: install-dev
24
- install-dev:
25
- pip install -r requirements.txt \
26
- && pip install -e .
27
-
28
- .PHONY: clean-docs
29
- clean-docs:
30
- rm -rf docs
31
-
32
- .PHONY: docs
33
- docs: clean-docs
34
- mkdir -p docs \
35
- && pdoc --html --output-dir docs extreqs
extreqs-1.1.0/PKG-INFO DELETED
@@ -1,109 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: extreqs
3
- Version: 1.1.0
4
- Summary: Parse python requirements.txt files into setuptools extras
5
- Home-page: https://github.com/clbarnes/extreqs
6
- Author: Chris L. Barnes
7
- Classifier: Development Status :: 3 - Alpha
8
- Classifier: License :: OSI Approved :: MIT License
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.7
11
- Classifier: Programming Language :: Python :: 3.8
12
- Classifier: Programming Language :: Python :: 3.9
13
- Classifier: Programming Language :: Python :: 3.10
14
- Requires-Python: >=3.7, <4.0
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
-
18
- # extreqs
19
-
20
- Parse python requirements.txt files into setuptools extras.
21
-
22
- ## Usage
23
-
24
- `extreqs` looks for special comments (`#extra:`) in your requirements files.
25
- Note the lack of space after the `#`!
26
- Anything which follows that (until the end of line, or another `#`) is treated as a whitespace-separated list of extras.
27
- For example, `#extra: dev test doc` marks dependencies belonging to the `dev`, `test`, and `doc` extras.
28
-
29
- If the `#extra:` comment is on the same line as (following) a dependency, then just that dependency belongs to that extra.
30
- If the `#extra:` comment is on a line on its own, all dependencies below it belong to that extra, until the next `#extra:` line.
31
-
32
- For example:
33
-
34
- ```txt
35
- # requirements.txt
36
- dep1
37
- dep2 #extra: extra1
38
-
39
- #extra: extra2
40
- dep3
41
-
42
- #extra: extra3 # you can still have freeform comments!
43
- dep4 #extra: extra4 extra5
44
- dep5
45
- ```
46
-
47
- would be parsed into
48
-
49
- ```python
50
- install_requires = ["dep1"]
51
- extras_require = {
52
- "extra1": ["dep2"],
53
- "extra2": ["dep3"],
54
- "extra3": ["dep4", "dep5"],
55
- "extra4": ["dep4"],
56
- "extra5": ["dep4"],
57
- }
58
- ```
59
-
60
- Additionally, entire files can belong to a particular extra.
61
-
62
- Note that python extras are not smart enough to deal with dependencies which belong only to _combinations_ of extras, or _negative_ extras: a dependency which belongs to multiple extras (given by the context of the file, block, or line) just belongs to multiple extras.
63
- This is a limitation of python packaging and cannot be addressed here.
64
-
65
- In your `setup.py`:
66
-
67
- ```python
68
- #!/usr/bin/env python3
69
- """setup.py"""
70
- from pathlib import Path
71
-
72
- from extreqs import parse_requirements_files_dict
73
- from setuptools import setup
74
-
75
- here = Path(__file__).resolve().parent
76
-
77
- req_kwargs = parse_requirements_files_dict(
78
- # files without an extra context are in *args
79
- here / "requirements.txt",
80
- # files with an extra context are in **kwargs
81
- optional=here / "requirements-optional.txt",
82
- )
83
-
84
- setup(
85
- name="my_package",
86
- ...
87
- **req_kwargs,
88
- ...
89
- )
90
- ```
91
-
92
- `extreqs` is an install-time dependency, and so must be added to your `pyproject.toml`:
93
-
94
- ```toml
95
- # pyproject.toml
96
- [build-system]
97
- requires = ["setuptools", "extreqs"]
98
- build-backend = "setuptools.build_meta"
99
- ```
100
-
101
- Look out for dependency specifiers which are accepted by pip, but not by setuptools (e.g. editable install `-e` or references to other requirement files `-r`).
102
-
103
- ## Notes
104
-
105
- This package should only be used in certain circumstances, and may lead to bad habits if over-used.
106
- Requirements files are intended for specifying reproducible (i.e. hard version constraints), maximal environments for other developers, CI, and so on to be able to run all tests, features, lints etc..
107
- Package dependencies are intended to specify the minimal dependencies with permissive version constraints for users to install the package for use.
108
-
109
- This package is, therefore, more applicable to distributing applications (CLI, web backends, etc.) than it is libraries.
extreqs-1.1.0/README.md DELETED
@@ -1,92 +0,0 @@
1
- # extreqs
2
-
3
- Parse python requirements.txt files into setuptools extras.
4
-
5
- ## Usage
6
-
7
- `extreqs` looks for special comments (`#extra:`) in your requirements files.
8
- Note the lack of space after the `#`!
9
- Anything which follows that (until the end of line, or another `#`) is treated as a whitespace-separated list of extras.
10
- For example, `#extra: dev test doc` marks dependencies belonging to the `dev`, `test`, and `doc` extras.
11
-
12
- If the `#extra:` comment is on the same line as (following) a dependency, then just that dependency belongs to that extra.
13
- If the `#extra:` comment is on a line on its own, all dependencies below it belong to that extra, until the next `#extra:` line.
14
-
15
- For example:
16
-
17
- ```txt
18
- # requirements.txt
19
- dep1
20
- dep2 #extra: extra1
21
-
22
- #extra: extra2
23
- dep3
24
-
25
- #extra: extra3 # you can still have freeform comments!
26
- dep4 #extra: extra4 extra5
27
- dep5
28
- ```
29
-
30
- would be parsed into
31
-
32
- ```python
33
- install_requires = ["dep1"]
34
- extras_require = {
35
- "extra1": ["dep2"],
36
- "extra2": ["dep3"],
37
- "extra3": ["dep4", "dep5"],
38
- "extra4": ["dep4"],
39
- "extra5": ["dep4"],
40
- }
41
- ```
42
-
43
- Additionally, entire files can belong to a particular extra.
44
-
45
- Note that python extras are not smart enough to deal with dependencies which belong only to _combinations_ of extras, or _negative_ extras: a dependency which belongs to multiple extras (given by the context of the file, block, or line) just belongs to multiple extras.
46
- This is a limitation of python packaging and cannot be addressed here.
47
-
48
- In your `setup.py`:
49
-
50
- ```python
51
- #!/usr/bin/env python3
52
- """setup.py"""
53
- from pathlib import Path
54
-
55
- from extreqs import parse_requirements_files_dict
56
- from setuptools import setup
57
-
58
- here = Path(__file__).resolve().parent
59
-
60
- req_kwargs = parse_requirements_files_dict(
61
- # files without an extra context are in *args
62
- here / "requirements.txt",
63
- # files with an extra context are in **kwargs
64
- optional=here / "requirements-optional.txt",
65
- )
66
-
67
- setup(
68
- name="my_package",
69
- ...
70
- **req_kwargs,
71
- ...
72
- )
73
- ```
74
-
75
- `extreqs` is an install-time dependency, and so must be added to your `pyproject.toml`:
76
-
77
- ```toml
78
- # pyproject.toml
79
- [build-system]
80
- requires = ["setuptools", "extreqs"]
81
- build-backend = "setuptools.build_meta"
82
- ```
83
-
84
- Look out for dependency specifiers which are accepted by pip, but not by setuptools (e.g. editable install `-e` or references to other requirement files `-r`).
85
-
86
- ## Notes
87
-
88
- This package should only be used in certain circumstances, and may lead to bad habits if over-used.
89
- Requirements files are intended for specifying reproducible (i.e. hard version constraints), maximal environments for other developers, CI, and so on to be able to run all tests, features, lints etc..
90
- Package dependencies are intended to specify the minimal dependencies with permissive version constraints for users to install the package for use.
91
-
92
- This package is, therefore, more applicable to distributing applications (CLI, web backends, etc.) than it is libraries.
@@ -1,4 +0,0 @@
1
- # file generated by setuptools_scm
2
- # don't change, don't track in version control
3
- __version__ = version = '1.1.0'
4
- __version_tuple__ = version_tuple = (1, 1, 0)
@@ -1,109 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: extreqs
3
- Version: 1.1.0
4
- Summary: Parse python requirements.txt files into setuptools extras
5
- Home-page: https://github.com/clbarnes/extreqs
6
- Author: Chris L. Barnes
7
- Classifier: Development Status :: 3 - Alpha
8
- Classifier: License :: OSI Approved :: MIT License
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.7
11
- Classifier: Programming Language :: Python :: 3.8
12
- Classifier: Programming Language :: Python :: 3.9
13
- Classifier: Programming Language :: Python :: 3.10
14
- Requires-Python: >=3.7, <4.0
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
-
18
- # extreqs
19
-
20
- Parse python requirements.txt files into setuptools extras.
21
-
22
- ## Usage
23
-
24
- `extreqs` looks for special comments (`#extra:`) in your requirements files.
25
- Note the lack of space after the `#`!
26
- Anything which follows that (until the end of line, or another `#`) is treated as a whitespace-separated list of extras.
27
- For example, `#extra: dev test doc` marks dependencies belonging to the `dev`, `test`, and `doc` extras.
28
-
29
- If the `#extra:` comment is on the same line as (following) a dependency, then just that dependency belongs to that extra.
30
- If the `#extra:` comment is on a line on its own, all dependencies below it belong to that extra, until the next `#extra:` line.
31
-
32
- For example:
33
-
34
- ```txt
35
- # requirements.txt
36
- dep1
37
- dep2 #extra: extra1
38
-
39
- #extra: extra2
40
- dep3
41
-
42
- #extra: extra3 # you can still have freeform comments!
43
- dep4 #extra: extra4 extra5
44
- dep5
45
- ```
46
-
47
- would be parsed into
48
-
49
- ```python
50
- install_requires = ["dep1"]
51
- extras_require = {
52
- "extra1": ["dep2"],
53
- "extra2": ["dep3"],
54
- "extra3": ["dep4", "dep5"],
55
- "extra4": ["dep4"],
56
- "extra5": ["dep4"],
57
- }
58
- ```
59
-
60
- Additionally, entire files can belong to a particular extra.
61
-
62
- Note that python extras are not smart enough to deal with dependencies which belong only to _combinations_ of extras, or _negative_ extras: a dependency which belongs to multiple extras (given by the context of the file, block, or line) just belongs to multiple extras.
63
- This is a limitation of python packaging and cannot be addressed here.
64
-
65
- In your `setup.py`:
66
-
67
- ```python
68
- #!/usr/bin/env python3
69
- """setup.py"""
70
- from pathlib import Path
71
-
72
- from extreqs import parse_requirements_files_dict
73
- from setuptools import setup
74
-
75
- here = Path(__file__).resolve().parent
76
-
77
- req_kwargs = parse_requirements_files_dict(
78
- # files without an extra context are in *args
79
- here / "requirements.txt",
80
- # files with an extra context are in **kwargs
81
- optional=here / "requirements-optional.txt",
82
- )
83
-
84
- setup(
85
- name="my_package",
86
- ...
87
- **req_kwargs,
88
- ...
89
- )
90
- ```
91
-
92
- `extreqs` is an install-time dependency, and so must be added to your `pyproject.toml`:
93
-
94
- ```toml
95
- # pyproject.toml
96
- [build-system]
97
- requires = ["setuptools", "extreqs"]
98
- build-backend = "setuptools.build_meta"
99
- ```
100
-
101
- Look out for dependency specifiers which are accepted by pip, but not by setuptools (e.g. editable install `-e` or references to other requirement files `-r`).
102
-
103
- ## Notes
104
-
105
- This package should only be used in certain circumstances, and may lead to bad habits if over-used.
106
- Requirements files are intended for specifying reproducible (i.e. hard version constraints), maximal environments for other developers, CI, and so on to be able to run all tests, features, lints etc..
107
- Package dependencies are intended to specify the minimal dependencies with permissive version constraints for users to install the package for use.
108
-
109
- This package is, therefore, more applicable to distributing applications (CLI, web backends, etc.) than it is libraries.
@@ -1,23 +0,0 @@
1
- .editorconfig
2
- .flake8
3
- .gitignore
4
- LICENSE
5
- Makefile
6
- README.md
7
- mypy.ini
8
- pyproject.toml
9
- requirements.txt
10
- setup.py
11
- .github/workflows/ci.yaml
12
- extreqs/__init__.py
13
- extreqs/main.py
14
- extreqs/version.py
15
- extreqs.egg-info/PKG-INFO
16
- extreqs.egg-info/SOURCES.txt
17
- extreqs.egg-info/dependency_links.txt
18
- extreqs.egg-info/requires.txt
19
- extreqs.egg-info/top_level.txt
20
- tests/__init__.py
21
- tests/conftest.py
22
- tests/test_extreqs.py
23
- tests/fixtures/requirements.txt
@@ -1 +0,0 @@
1
- setuptools
@@ -1 +0,0 @@
1
- extreqs
extreqs-1.1.0/mypy.ini DELETED
@@ -1,2 +0,0 @@
1
- [mypy]
2
- ignore_missing_imports = True
@@ -1,10 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [tool.setuptools_scm]
6
- write_to = "extreqs/version.py"
7
-
8
- [tool.isort]
9
- profile = "black"
10
- multi_line_output = 3
@@ -1,12 +0,0 @@
1
- # dev
2
-
3
- black
4
- flake8
5
- isort
6
- mypy
7
- pdoc3
8
- pytest
9
- setuptools
10
- setuptools-scm
11
- types-setuptools
12
- wheel
extreqs-1.1.0/setup.cfg DELETED
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
extreqs-1.1.0/setup.py DELETED
@@ -1,29 +0,0 @@
1
- from pathlib import Path
2
-
3
- from setuptools import find_packages, setup
4
-
5
- with open(Path(__file__).resolve().parent / "README.md") as f:
6
- readme = f.read()
7
-
8
- setup(
9
- name="extreqs",
10
- url="https://github.com/clbarnes/extreqs",
11
- author="Chris L. Barnes",
12
- description="Parse python requirements.txt files into setuptools extras",
13
- long_description=readme,
14
- long_description_content_type="text/markdown",
15
- packages=find_packages(include=["extreqs"]),
16
- install_requires=["setuptools"],
17
- python_requires=">=3.7, <4.0",
18
- classifiers=[
19
- "Development Status :: 3 - Alpha",
20
- "License :: OSI Approved :: MIT License",
21
- "Programming Language :: Python :: 3",
22
- "Programming Language :: Python :: 3.7",
23
- "Programming Language :: Python :: 3.8",
24
- "Programming Language :: Python :: 3.9",
25
- "Programming Language :: Python :: 3.10",
26
- ],
27
- use_scm_version=True,
28
- setup_requires=["setuptools_scm"],
29
- )
File without changes
@@ -1,10 +0,0 @@
1
- from pathlib import Path
2
-
3
- import pytest
4
-
5
- here = Path(__file__).resolve().parent
6
-
7
-
8
- @pytest.fixture
9
- def fixture_dir():
10
- return here / "fixtures"
@@ -1,9 +0,0 @@
1
- dep1
2
- dep2 #extra: extra1
3
-
4
- #extra: extra2
5
- dep3
6
-
7
- #extra: extra3 # you can still have freeform comments!
8
- dep4 #extra: extra4 extra5
9
- dep5
@@ -1,43 +0,0 @@
1
- from extreqs import parse_requirement_files, parse_requirement_files_dict
2
-
3
-
4
- def test_importable():
5
- import extreqs
6
-
7
- assert extreqs.__version__
8
-
9
-
10
- def test_complex(fixture_dir):
11
- fpath = fixture_dir / "requirements.txt"
12
- install, extras = parse_requirement_files(fpath)
13
-
14
- assert install == ["dep1"]
15
- assert extras == {
16
- "extra1": ["dep2"],
17
- "extra2": ["dep3"],
18
- "extra3": ["dep4", "dep5"],
19
- "extra4": ["dep4"],
20
- "extra5": ["dep4"],
21
- }
22
-
23
-
24
- def test_file_context(fixture_dir):
25
- fpath = fixture_dir / "requirements.txt"
26
- install, extras = parse_requirement_files(optional=fpath)
27
-
28
- assert install == []
29
- assert extras["optional"] == ["dep1", "dep2", "dep3", "dep4", "dep5"]
30
-
31
-
32
- def test_as_dict(fixture_dir):
33
- fpath = fixture_dir / "requirements.txt"
34
- kwargs = parse_requirement_files_dict(fpath)
35
- assert kwargs["install_requires"] == ["dep1"]
36
- assert kwargs["extras_require"] == {
37
- "extra1": ["dep2"],
38
- "extra2": ["dep3"],
39
- "extra3": ["dep4", "dep5"],
40
- "extra4": ["dep4"],
41
- "extra5": ["dep4"],
42
- }
43
- assert len(kwargs) == 2
File without changes