extreqs 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.
extreqs-1.2.0/PKG-INFO ADDED
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.3
2
+ Name: extreqs
3
+ Version: 1.2.0
4
+ Summary: Parse python requirements.txt files into setuptools extras
5
+ Classifier: Development Status :: 3 - Alpha
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Dist: requirements-parser>=0.13.0
14
+ Requires-Python: >=3.10, <4.0
@@ -0,0 +1,31 @@
1
+ [project]
2
+ name = "extreqs"
3
+ version = "1.2.0"
4
+ description = "Parse python requirements.txt files into setuptools extras"
5
+ requires-python = ">=3.10,<4.0"
6
+ classifiers = [
7
+ "Development Status :: 3 - Alpha",
8
+ "License :: OSI Approved :: MIT License",
9
+ "Programming Language :: Python :: 3",
10
+ "Programming Language :: Python :: 3.10",
11
+ "Programming Language :: Python :: 3.11",
12
+ "Programming Language :: Python :: 3.12",
13
+ "Programming Language :: Python :: 3.13",
14
+ "Programming Language :: Python :: 3.14",
15
+ ]
16
+
17
+ dependencies = [
18
+ "requirements-parser>=0.13.0",
19
+ ]
20
+
21
+ [build-system]
22
+ requires = ["uv_build>=0.10.0,<0.11.0"]
23
+ build-backend = "uv_build"
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "mypy>=1.19.1",
28
+ "pdoc3>=0.11.6",
29
+ "pytest>=9.0.2",
30
+ "ruff>=0.15.0",
31
+ ]
@@ -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/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2022, Chris L. Barnes
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.
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