├── .editorconfig ├── .github └── workflows │ ├── pypi-publish.yml │ └── tests.yml ├── .gitignore ├── AUTHORS.rst ├── CHANGES.rst ├── CONTRIBUTING.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── docs ├── Makefile ├── conf.py ├── index.rst └── requirements.txt ├── pytest.ini ├── requirements.devel.txt ├── requirements.latest.txt ├── requirements.lowest.txt ├── requirements_builder ├── __init__.py ├── cli.py ├── requirements_builder.py └── version.py ├── run-tests.sh ├── setup.cfg ├── setup.py ├── tests ├── data │ ├── other_req.txt │ ├── req.txt │ ├── setup.py │ ├── setup_if_main.py │ └── testpkh │ │ └── __init__.py ├── fixtures │ ├── pyproject.toml │ ├── requirements.devel.txt │ ├── setup.txt │ └── setup_py_placeholder.txt ├── test_cli.py └── test_requirements_builder.py └── tox.ini /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | # http://editorconfig.org 9 | 10 | root = true 11 | 12 | [*] 13 | charset = utf-8 14 | end_of_line = lf 15 | indent_size = 4 16 | indent_style = space 17 | insert_final_newline = true 18 | trim_trailing_whitespace = true 19 | 20 | # Python files 21 | [*.py] 22 | indent_size = 4 23 | # isort plugin configuration 24 | multi_line_output = 2 25 | known_first_party = requirements_builder 26 | default_section = THIRDPARTY 27 | 28 | # RST files (used by sphinx) 29 | [*.rst] 30 | indent_size = 4 31 | 32 | # CSS, HTML, JS, JSON, YML 33 | [*.{css,html,js,json,yml}] 34 | indent_size = 2 35 | 36 | # Matches the exact files either package.json or .travis.yml 37 | [{package.json,.travis.yml}] 38 | indent_size = 2 39 | 40 | # Dockerfile 41 | [Dockerfile] 42 | indent_size = 4 43 | -------------------------------------------------------------------------------- /.github/workflows/pypi-publish.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Invenio. 4 | # Copyright (C) 2020 CERN. 5 | # 6 | # Invenio is free software; you can redistribute it and/or modify it 7 | # under the terms of the MIT License; see LICENSE file for more details. 8 | 9 | name: Publish 10 | 11 | on: 12 | push: 13 | tags: 14 | - v* 15 | 16 | jobs: 17 | Publish: 18 | runs-on: ubuntu-20.04 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: 3.7 27 | 28 | - name: Install dependencies 29 | run: | 30 | python -m pip install --upgrade pip 31 | pip install setuptools wheel 32 | 33 | - name: Build package 34 | run: | 35 | python setup.py sdist bdist_wheel 36 | 37 | - name: Publish on PyPI 38 | uses: pypa/gh-action-pypi-publish@v1.3.1 39 | with: 40 | user: __token__ 41 | password: ${{ secrets.pypi_token }} 42 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Invenio. 4 | # Copyright (C) 2020 CERN. 5 | # 6 | # Invenio is free software; you can redistribute it and/or modify it 7 | # under the terms of the MIT License; see LICENSE file for more details. 8 | 9 | name: CI 10 | 11 | on: 12 | push: 13 | branches: master 14 | pull_request: 15 | branches: master 16 | schedule: 17 | # * is a special character in YAML so you have to quote this string 18 | - cron: '0 3 * * 6' 19 | workflow_dispatch: 20 | inputs: 21 | reason: 22 | description: 'Reason' 23 | required: false 24 | default: 'Manual trigger' 25 | 26 | jobs: 27 | Tests: 28 | runs-on: ubuntu-20.04 29 | timeout-minutes: 20 30 | strategy: 31 | matrix: 32 | python-version: [3.6, 3.7, 3.8] 33 | requirements-level: [min, pypi] 34 | 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@v2 38 | 39 | - name: Set up Python ${{ matrix.python-version }} 40 | uses: actions/setup-python@v2 41 | with: 42 | python-version: ${{ matrix.python-version }} 43 | 44 | - name: Generate dependencies 45 | run: | 46 | python -m pip install --upgrade pip setuptools py wheel requirements-builder 47 | requirements-builder -e all --level=${{ matrix.requirements-level }} setup.py > .${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt 48 | 49 | - name: Cache pip 50 | uses: actions/cache@v2 51 | with: 52 | path: ~/.cache/pip 53 | key: ${{ runner.os }}-pip-${{ hashFiles('.${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt') }} 54 | 55 | - name: Install dependencies 56 | run: | 57 | pip install -r .${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt 58 | pip install .[all] 59 | pip freeze 60 | 61 | - name: Run tests 62 | run: | 63 | ./run-tests.sh 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | Authors 2 | ------- 3 | 4 | * Jiri Kuncar 5 | * Lars Holm Nielsen 6 | * Marco Neumann 7 | * Tibor Simko 8 | * Yoan Blanc 9 | -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- 1 | .. 2 | This file is part of Requirements-Builder 3 | Copyright (C) 2015, 2016, 2020 CERN. 4 | Copyright (C) 2018 Swiss Data Science Center (SDSC) 5 | A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and 6 | Eidgenössische Technische Hochschule Zürich (ETHZ). 7 | 8 | Requirements-Builder is free software; you can redistribute it and/or 9 | modify it under the terms of the Revised BSD License; see LICENSE 10 | file for more details. 11 | 12 | .. :changes: 13 | 14 | Changes 15 | ======= 16 | 17 | Version 0.4.4 (released 2021-05-12) 18 | ----------------------------------- 19 | 20 | Bug fixes 21 | ~~~~~~~~~ 22 | 23 | - Fixes compatibility with ``click`` v8.0. 24 | 25 | Version 0.4.3 (released 2021-05-12) 26 | ----------------------------------- 27 | 28 | Bug fixes 29 | ~~~~~~~~~ 30 | 31 | - Pins ``click`` to ``<8.0`` due to incompatibility. 32 | 33 | 34 | Version 0.4.2 (released 2020-05-25) 35 | ----------------------------------- 36 | 37 | Bug fixes 38 | ~~~~~~~~~ 39 | 40 | - Fixes ``configparser`` import for Python 2. 41 | 42 | Version 0.4.1 (released 2020-05-25) 43 | ----------------------------------- 44 | 45 | Bug fixes 46 | ~~~~~~~~~ 47 | 48 | - Fixes "setup.cfg" file reading issue. 49 | 50 | Version 0.4.0 (released 2020-05-25) 51 | ----------------------------------- 52 | 53 | New features 54 | ~~~~~~~~~~~~ 55 | 56 | - Adds support for parsing setup.cfg. 57 | 58 | 59 | Version 0.3.0 (released 2018-05-17) 60 | ----------------------------------- 61 | 62 | New features 63 | ~~~~~~~~~~~~ 64 | 65 | - Includes package extras in the generated result. 66 | 67 | Bug fixes 68 | --------- 69 | 70 | - Fixes ``~=`` selector output by including the minimum version 71 | additionally to the X.* specifier. 72 | 73 | Version 0.2.6 (released 2017-07-13) 74 | ----------------------------------- 75 | 76 | Bug fixes 77 | ~~~~~~~~~ 78 | 79 | - Fixes fatal error if setup() is called under 'if __name__ == "__main__":' 80 | 81 | 82 | Version 0.2.5 (released 2017-04-11) 83 | ----------------------------------- 84 | 85 | Bug fixes 86 | ~~~~~~~~~ 87 | 88 | - Fixes support of recursive requirements files. 89 | 90 | Version 0.2.4 (released 2017-03-10) 91 | ----------------------------------- 92 | 93 | Bug fixes 94 | ~~~~~~~~~ 95 | 96 | - Fixes issue with upper version requirements being stripped from the output. 97 | 98 | Version 0.2.3 (released 2017-03-09) 99 | ----------------------------------- 100 | 101 | Bug fixes 102 | ~~~~~~~~~ 103 | 104 | - Fixes the issue with conditions on extra_require not being taken into 105 | account. 106 | 107 | Version 0.2.2 (released 2017-02-01) 108 | ----------------------------------- 109 | 110 | Bug fixes 111 | ~~~~~~~~~ 112 | 113 | - Fixes issue with properly building requirements for packages with version 114 | markers. 115 | 116 | Improvements 117 | ~~~~~~~~~~~~ 118 | 119 | - Adds YAPF auto-formatting configuration. 120 | 121 | Version 0.2.1 (released 2017-01-23) 122 | ----------------------------------- 123 | 124 | Bug fixes 125 | ~~~~~~~~~ 126 | 127 | - Accepts non-`-e` packages from devel file. 128 | - Sphinx 1.5+ drops support for Python 2.6 and 3.3. 129 | - Adds Python 3.6 support. 130 | - Makes `--extras` option accepting comma separated values as 131 | described in help. (#14) 132 | 133 | 134 | Version 0.2.0 (released 2016-09-13) 135 | ----------------------------------- 136 | 137 | New features 138 | ~~~~~~~~~~~~ 139 | 140 | - Adds an output option which is useful in the tox context where one 141 | cannot redirect the output to a file. See more at 142 | https://bitbucket.org/hpk42/tox/issues/73/pipe-output-of-command-into-file 143 | 144 | Bug fixes 145 | ~~~~~~~~~ 146 | 147 | - Fixes problem when the setup.py command try to import the package 148 | its about to install in order to get the information like the 149 | version. E.g. Django does that. 150 | - Fixes problem when the setup.py command plays with `__file__` to 151 | read, exec, or whatever. 152 | 153 | 154 | Version 0.1.0 (released 2015-10-05) 155 | ----------------------------------- 156 | 157 | - Initial public release 158 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. 2 | This file is part of Requirements-Builder 3 | Copyright (C) 2015 CERN. 4 | 5 | Requirements-Builder is free software; you can redistribute it and/or 6 | modify it under the terms of the Revised BSD License; see LICENSE 7 | file for more details. 8 | 9 | Contributing 10 | ============ 11 | 12 | Contributions are welcome, and they are greatly appreciated! Every 13 | little bit helps, and credit will always be given. 14 | 15 | Types of Contributions 16 | ---------------------- 17 | 18 | Report Bugs 19 | ~~~~~~~~~~~ 20 | 21 | Report bugs at https://github.com/inveniosoftware/requirements-builder/issues. 22 | 23 | If you are reporting a bug, please include: 24 | 25 | * Your operating system name and version. 26 | * Any details about your local setup that might be helpful in troubleshooting. 27 | * Detailed steps to reproduce the bug. 28 | 29 | Fix Bugs 30 | ~~~~~~~~ 31 | 32 | Look through the GitHub issues for bugs. Anything tagged with "bug" 33 | is open to whoever wants to implement it. 34 | 35 | Implement Features 36 | ~~~~~~~~~~~~~~~~~~ 37 | 38 | Look through the GitHub issues for features. Anything tagged with "feature" 39 | is open to whoever wants to implement it. 40 | 41 | Write Documentation 42 | ~~~~~~~~~~~~~~~~~~~ 43 | 44 | Requirements-Builder could always use more documentation, whether as part of the 45 | official Requirements-Builder docs, in docstrings, or even on the web in blog posts, 46 | articles, and such. 47 | 48 | Submit Feedback 49 | ~~~~~~~~~~~~~~~ 50 | 51 | The best way to send feedback is to file an issue at https://github.com/inveniosoftware/requirements-builder/issues. 52 | 53 | If you are proposing a feature: 54 | 55 | * Explain in detail how it would work. 56 | * Keep the scope as narrow as possible, to make it easier to implement. 57 | * Remember that this is a volunteer-driven project, and that contributions 58 | are welcome :) 59 | 60 | Get Started! 61 | ------------ 62 | 63 | Ready to contribute? Here's how to set up `requirements-builder` for local development. 64 | 65 | 1. Fork the `requirements-builder` repo on GitHub. 66 | 2. Clone your fork locally: 67 | 68 | .. code-block:: console 69 | 70 | $ git clone git@github.com:your_name_here/requirements-builder.git 71 | 72 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development: 73 | 74 | .. code-block:: console 75 | 76 | $ mkvirtualenv requirements-builder 77 | $ cd requirements-builder/ 78 | $ python setup.py develop 79 | 80 | 4. Create a branch for local development: 81 | 82 | .. code-block:: console 83 | 84 | $ git checkout -b name-of-your-bugfix-or-feature 85 | 86 | Now you can make your changes locally. 87 | 88 | 5. When you're done making changes, check that your changes pass tests, including testing other Python versions with tox: 89 | 90 | .. code-block:: console 91 | 92 | $ ./run-tests.sh 93 | $ tox 94 | 95 | The tests will provide you with test coverage and also check PEP8 96 | (code style), PEP257 (documentation), flake8 as well as build the Sphinx 97 | documentation and run doctests. 98 | 99 | 6. Commit your changes and push your branch to GitHub: 100 | 101 | .. code-block:: console 102 | 103 | $ git add . 104 | $ git commit -s -m "Your detailed description of your changes." 105 | $ git push origin name-of-your-bugfix-or-feature 106 | 107 | 7. Submit a pull request through the GitHub website. 108 | 109 | Pull Request Guidelines 110 | ----------------------- 111 | 112 | Before you submit a pull request, check that it meets these guidelines: 113 | 114 | 1. The pull request should include tests and must not decrease test coverage. 115 | 2. If the pull request adds functionality, the docs should be updated. Put 116 | your new functionality into a function with a docstring, and add the 117 | feature to the list in README.rst. 118 | 3. The pull request should work for Python 2.6, 2.7, 3.3, 3.4, 3.5 and for PyPy. Check 119 | https://github.com/inveniosoftware/requirements-builder/actions?query=event%3Apull_request 120 | and make sure that the tests pass for all supported Python versions. 121 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Requirements-Builder is free software; you can redistribute it and/or 2 | modify it under the terms of the Revised BSD License; see LICENSE 3 | file for more details. 4 | 5 | Copyright (C) 2015, CERN 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | 15 | * Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | * Neither the name of the copyright holder nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 30 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 31 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 32 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 33 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 34 | DAMAGE. 35 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | 10 | include .coveragerc 11 | include .editorconfig 12 | include .isort.cfg 13 | include .lgtm MAINTAINERS 14 | include AUTHORS.rst 15 | include CHANGES.rst 16 | include CONTRIBUTING.rst 17 | include LICENSE 18 | include README.rst 19 | include RELEASE-NOTES.rst 20 | include docs/requirements.txt 21 | include pytest.ini 22 | include requirements.*.txt 23 | include run-tests.sh 24 | include tox.ini 25 | recursive-include docs *.rst conf.py Makefile 26 | recursive-include tests * 27 | recursive-exclude * *.py[co] 28 | recursive-exclude * __pycache__ 29 | recursive-include .github/workflows *.yml 30 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. 2 | This file is part of Requirements-Builder 3 | Copyright (C) 2015 CERN. 4 | 5 | Requirements-Builder is free software; you can redistribute it and/or 6 | modify it under the terms of the Revised BSD License; see LICENSE 7 | file for more details. 8 | 9 | ====================== 10 | Requirements-Builder 11 | ====================== 12 | 13 | .. image:: https://github.com/inveniosoftware/requirements-builder/workflows/CI/badge.svg 14 | :target: https://github.com/inveniosoftware/requirements-builder/actions?query=workflow%3ACI 15 | 16 | .. image:: https://img.shields.io/coveralls/inveniosoftware/requirements-builder.svg 17 | :target: https://coveralls.io/r/inveniosoftware/requirements-builder 18 | 19 | .. image:: https://img.shields.io/github/tag/inveniosoftware/requirements-builder.svg 20 | :target: https://github.com/inveniosoftware/requirements-builder/releases 21 | 22 | .. image:: https://img.shields.io/pypi/dm/requirements-builder.svg 23 | :target: https://pypi.python.org/pypi/requirements-builder 24 | 25 | .. image:: https://img.shields.io/pypi/l/requirements-builder.svg 26 | :target: https://github.com/inveniosoftware/requirements-builder/blob/master/LICENSE 27 | 28 | About 29 | ===== 30 | 31 | Build requirements from setup.py to test your package against minimum, 32 | latest and development versions of your package dependencies. Particularly 33 | useful when combined with your CI systems build matrix. 34 | 35 | Full documentation at `requirements-builder.readthedocs.io `__ 36 | 37 | Installation 38 | ============ 39 | 40 | Requirements-Builder is on PyPI so all you need is:: 41 | 42 | $ pip install requirements-builder 43 | 44 | Or, if you have virtualenvwrapper installed:: 45 | 46 | $ mkvirtualenv requirements-builder 47 | $ pip install requirements-builder 48 | 49 | Testing 50 | ======= 51 | 52 | Running the test suite is as simple as:: 53 | 54 | $ ./run-tests.sh 55 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/requirements-builder.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/requirements-builder.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/requirements-builder" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/requirements-builder" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # requirements-builder documentation build configuration file, created by 5 | # sphinx-quickstart on Tue Jul 9 22:26:36 2013. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import os 17 | import sys 18 | 19 | import sphinx.environment 20 | from docutils.utils import get_source_line 21 | 22 | # If extensions (or modules to document with autodoc) are in another 23 | # directory, add these directories to sys.path here. If the directory is 24 | # relative to the documentation root, use os.path.abspath to make it 25 | # absolute, like shown here. 26 | #sys.path.insert(0, os.path.abspath('.')) 27 | 28 | # Get the project root dir, which is the parent dir of this 29 | cwd = os.getcwd() 30 | project_root = os.path.dirname(cwd) 31 | 32 | # Insert the project root dir as the first element in the PYTHONPATH. 33 | # This lets us ensure that the source package is imported, and that its 34 | # version is used. 35 | sys.path.insert(0, project_root) 36 | 37 | # -- General configuration --------------------------------------------- 38 | 39 | # If your documentation needs a minimal Sphinx version, state it here. 40 | #needs_sphinx = '1.0' 41 | 42 | # Do not warn on external images. 43 | suppress_warnings = ['image.nonlocal_uri'] 44 | 45 | # Add any Sphinx extension module names here, as strings. They can be 46 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 47 | extensions = [ 48 | 'sphinx.ext.autodoc', 49 | 'sphinx.ext.doctest', 50 | 'sphinx.ext.viewcode', 51 | ] 52 | 53 | # Add any paths that contain templates here, relative to this directory. 54 | templates_path = ['_templates'] 55 | 56 | # The suffix of source filenames. 57 | source_suffix = '.rst' 58 | 59 | # The encoding of source files. 60 | #source_encoding = 'utf-8-sig' 61 | 62 | # The master toctree document. 63 | master_doc = 'index' 64 | 65 | # General information about the project. 66 | project = u'Requirements-Builder' 67 | copyright = u'2015, CERN' 68 | 69 | # The version info for the project you're documenting, acts as replacement 70 | # for |version| and |release|, also used in various other places throughout 71 | # the built documents. 72 | # 73 | # The short X.Y version. 74 | # Get the version string. Cannot be done with import! 75 | g = {} 76 | with open(os.path.join('..', 'requirements_builder', 'version.py'), 'rt') \ 77 | as fp: 78 | exec(fp.read(), g) 79 | version = g['__version__'] 80 | 81 | # The full version, including alpha/beta/rc tags. 82 | release = version 83 | 84 | # The language for content autogenerated by Sphinx. Refer to documentation 85 | # for a list of supported languages. 86 | #language = None 87 | 88 | # There are two options for replacing |today|: either, you set today to 89 | # some non-false value, then it is used: 90 | #today = '' 91 | # Else, today_fmt is used as the format for a strftime call. 92 | #today_fmt = '%B %d, %Y' 93 | 94 | # List of patterns, relative to source directory, that match files and 95 | # directories to ignore when looking for source files. 96 | exclude_patterns = ['_build'] 97 | 98 | # The reST default role (used for this markup: `text`) to use for all 99 | # documents. 100 | #default_role = None 101 | 102 | # If true, '()' will be appended to :func: etc. cross-reference text. 103 | #add_function_parentheses = True 104 | 105 | # If true, the current module name will be prepended to all description 106 | # unit titles (such as .. function::). 107 | #add_module_names = True 108 | 109 | # If true, sectionauthor and moduleauthor directives will be shown in the 110 | # output. They are ignored by default. 111 | #show_authors = False 112 | 113 | # The name of the Pygments (syntax highlighting) style to use. 114 | pygments_style = 'sphinx' 115 | 116 | # A list of ignored prefixes for module index sorting. 117 | #modindex_common_prefix = [] 118 | 119 | # If true, keep warnings as "system message" paragraphs in the built 120 | # documents. 121 | #keep_warnings = False 122 | 123 | 124 | # -- Options for HTML output ------------------------------------------- 125 | 126 | # The theme to use for HTML and HTML Help pages. See the documentation for 127 | # a list of builtin themes. 128 | html_theme = 'alabaster' 129 | 130 | # Theme options are theme-specific and customize the look and feel of a 131 | # theme further. For a list of options available for each theme, see the 132 | # documentation. 133 | html_theme_options = { 134 | 'description': 'Build requirements files from setup.py requirements.', 135 | 'github_user': 'inveniosoftware', 136 | 'github_repo': 'requirements-builder', 137 | 'github_button': False, 138 | 'github_banner': True, 139 | 'show_powered_by': False, 140 | 'extra_nav_links' : { 141 | 'requirements-builder@GitHub' : 'http://github.com/inveniosoftware/requirements-builder/', 142 | 'requirements-builder@PyPI' : 'http://pypi.python.org/pypi/requirements-builder/', 143 | } 144 | } 145 | 146 | # Add any paths that contain custom themes here, relative to this directory. 147 | #html_theme_path = [] 148 | 149 | # The name for this set of Sphinx documents. If None, it defaults to 150 | # " v documentation". 151 | #html_title = None 152 | 153 | # A shorter title for the navigation bar. Default is the same as 154 | # html_title. 155 | #html_short_title = None 156 | 157 | # The name of an image file (relative to this directory) to place at the 158 | # top of the sidebar. 159 | #html_logo = None 160 | 161 | # The name of an image file (within the static path) to use as favicon 162 | # of the docs. This file should be a Windows icon file (.ico) being 163 | # 16x16 or 32x32 pixels large. 164 | #html_favicon = None 165 | 166 | # Add any paths that contain custom static files (such as style sheets) 167 | # here, relative to this directory. They are copied after the builtin 168 | # static files, so a file named "default.css" will overwrite the builtin 169 | # "default.css". 170 | # html_static_path = ['_static'] 171 | 172 | # If not '', a 'Last updated on:' timestamp is inserted at every page 173 | # bottom, using the given strftime format. 174 | #html_last_updated_fmt = '%b %d, %Y' 175 | 176 | # If true, SmartyPants will be used to convert quotes and dashes to 177 | # typographically correct entities. 178 | #html_use_smartypants = True 179 | 180 | # Custom sidebar templates, maps document names to template names. 181 | html_sidebars = { 182 | '**': [ 183 | 'about.html', 184 | 'navigation.html', 185 | 'relations.html', 186 | 'searchbox.html', 187 | 'donate.html', 188 | ] 189 | } 190 | 191 | # Additional templates that should be rendered to pages, maps page names 192 | # to template names. 193 | #html_additional_pages = {} 194 | 195 | # If false, no module index is generated. 196 | #html_domain_indices = True 197 | 198 | # If false, no index is generated. 199 | #html_use_index = True 200 | 201 | # If true, the index is split into individual pages for each letter. 202 | #html_split_index = False 203 | 204 | # If true, links to the reST sources are added to the pages. 205 | #html_show_sourcelink = True 206 | 207 | # If true, "Created using Sphinx" is shown in the HTML footer. 208 | # Default is True. 209 | #html_show_sphinx = True 210 | 211 | # If true, "(C) Copyright ..." is shown in the HTML footer. 212 | # Default is True. 213 | #html_show_copyright = True 214 | 215 | # If true, an OpenSearch description file will be output, and all pages 216 | # will contain a tag referring to it. The value of this option 217 | # must be the base URL from which the finished HTML is served. 218 | #html_use_opensearch = '' 219 | 220 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 221 | #html_file_suffix = None 222 | 223 | # Output file base name for HTML help builder. 224 | htmlhelp_basename = 'requirements-builderdoc' 225 | 226 | 227 | # -- Options for LaTeX output ------------------------------------------ 228 | 229 | latex_elements = { 230 | # The paper size ('letterpaper' or 'a4paper'). 231 | #'papersize': 'letterpaper', 232 | 233 | # The font size ('10pt', '11pt' or '12pt'). 234 | #'pointsize': '10pt', 235 | 236 | # Additional stuff for the LaTeX preamble. 237 | #'preamble': '', 238 | } 239 | 240 | # Grouping the document tree into LaTeX files. List of tuples 241 | # (source start file, target name, title, author, documentclass 242 | # [howto/manual]). 243 | latex_documents = [ 244 | ('index', 'requirements-builder.tex', 245 | u'Requirements-Builder Documentation', 246 | u'Invenio Collaboration', 'manual'), 247 | ] 248 | 249 | # The name of an image file (relative to this directory) to place at 250 | # the top of the title page. 251 | #latex_logo = None 252 | 253 | # For "manual" documents, if this is true, then toplevel headings 254 | # are parts, not chapters. 255 | #latex_use_parts = False 256 | 257 | # If true, show page references after internal links. 258 | #latex_show_pagerefs = False 259 | 260 | # If true, show URL addresses after external links. 261 | #latex_show_urls = False 262 | 263 | # Documents to append as an appendix to all manuals. 264 | #latex_appendices = [] 265 | 266 | # If false, no module index is generated. 267 | #latex_domain_indices = True 268 | 269 | 270 | # -- Options for manual page output ------------------------------------ 271 | 272 | # One entry per manual page. List of tuples 273 | # (source start file, name, description, authors, manual section). 274 | man_pages = [ 275 | ('index', 'requirements-builder', 276 | u'Requirements-Builder Documentation', 277 | [u'Invenio Collaboration'], 1) 278 | ] 279 | 280 | # If true, show URL addresses after external links. 281 | #man_show_urls = False 282 | 283 | 284 | # -- Options for Texinfo output ---------------------------------------- 285 | 286 | # Grouping the document tree into Texinfo files. List of tuples 287 | # (source start file, target name, title, author, 288 | # dir menu entry, description, category) 289 | texinfo_documents = [ 290 | ('index', 'requirements-builder', 291 | u'Requirements-Builder Documentation', 292 | u'Invenio Collaboration', 293 | 'requirements-builder', 294 | 'One line description of project.', 295 | 'Miscellaneous'), 296 | ] 297 | 298 | # Documents to append as an appendix to all manuals. 299 | #texinfo_appendices = [] 300 | 301 | # If false, no module index is generated. 302 | #texinfo_domain_indices = True 303 | 304 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 305 | #texinfo_show_urls = 'footnote' 306 | 307 | # If true, do not generate a @detailmenu in the "Top" node's menu. 308 | #texinfo_no_detailmenu = False 309 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | This file is part of Requirements-Builder 3 | Copyright (C) 2015 CERN. 4 | 5 | Requirements-Builder is free software; you can redistribute it and/or 6 | modify it under the terms of the Revised BSD License; see LICENSE 7 | file for more details. 8 | 9 | .. include:: ../README.rst 10 | 11 | Usage 12 | ===== 13 | 14 | .. automodule:: requirements_builder 15 | 16 | 17 | API Reference 18 | ============= 19 | 20 | .. automodule:: requirements_builder.requirements_builder 21 | :members: 22 | :undoc-members: 23 | 24 | 25 | .. include:: ../CONTRIBUTING.rst 26 | 27 | .. include:: ../CHANGES.rst 28 | 29 | License 30 | ======= 31 | 32 | .. include:: ../LICENSE 33 | 34 | .. include:: ../AUTHORS.rst 35 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | -e .[docs,tests] 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | [pytest] 9 | addopts = --isort --pydocstyle --pycodestyle --doctest-glob="*.rst" --doctest-modules --cov=requirements_builder --cov-report=term-missing 10 | testpaths = tests requirements_builder -------------------------------------------------------------------------------- /requirements.devel.txt: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015, 2018, 2020 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | # Latest click uses f-str, re-enable once 3.5 support is dropped by September 2020 9 | #-e git+https://github.com/pallets/click.git#egg=click 10 | -------------------------------------------------------------------------------- /requirements.latest.txt: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | click 9 | -------------------------------------------------------------------------------- /requirements.lowest.txt: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | click==6.1.0 9 | -------------------------------------------------------------------------------- /requirements_builder/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2017 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """Build requirements files from setup.py requirements. 11 | 12 | .. code-block:: console 13 | 14 | $ requirements-builder --help 15 | Usage: requirements-builder [OPTIONS] SETUP 16 | 17 | Calculate requirements for different purposes. 18 | 19 | Options: 20 | -l, --level [min|pypi|dev] Specifies desired requirements level."min" 21 | requests the minimal requirement that is 22 | specified, "pypi" requests the maximum version 23 | that satisfies the constrains and is available 24 | in PyPi. "dev" includes experimental developer 25 | versions for VCSs. 26 | -e, --extras TEXT Comma separated list of extras. 27 | -r, --req PATH Requirements file. 28 | --help Show this message and exit. 29 | 30 | TravisCI 31 | -------- 32 | Following is an example of how to integrate Requirements-Builder with 33 | TravisCI: 34 | 35 | .. code-block:: yaml 36 | 37 | env: 38 | - REQUIREMENTS=lowest 39 | - REQUIREMENTS=release 40 | - REQUIREMENTS=devel 41 | 42 | python: 43 | - "2.7" 44 | - "3.5" 45 | - "3.6" 46 | - "3.7" 47 | 48 | before_install: 49 | - "travis_retry pip install --upgrade pip" 50 | - "travis_retry pip install requirements-builder" 51 | - "requirements-builder --level=min setup.py 52 | > .travis-lowest-requirements.txt" 53 | - "requirements-builder --level=pypi setup.py 54 | > .travis-release-requirements.txt" 55 | - "requirements-builder --level=dev --req requirements-devel.txt setup.py 56 | > .travis-devel-requirements.txt" 57 | 58 | install: 59 | - "travis_retry pip install -r .travis-$REQUIREMENTS-requirements.txt" 60 | - "pip install -e ." 61 | 62 | Tox 63 | --- 64 | How to integrate Requirements-Builder with tox: 65 | 66 | .. code-block:: ini 67 | 68 | [tox] 69 | skipdist = True 70 | 71 | envlist = 72 | {py27}-{min,pypi,dev} 73 | {py35}-{min,pypi,dev} 74 | {py36}-{min,pypi,dev} 75 | {py37}-{min,pypi,dev} 76 | 77 | [testenv] 78 | setenv = 79 | PYTHONPATH = {toxinidir}:{toxinidir} 80 | 81 | deps = 82 | Requirements-Builder 83 | 84 | commands = 85 | min: requirements-builder --level=min -o .tox/min.txt setup.py 86 | min: pip install -r .tox/min.txt 87 | pypi: requirements-builder --level=min -o .tox/pypi.txt setup.py 88 | pypi: pip install -r .tox/pypi.txt 89 | dev: requirements-builder -l dev -r devel.txt -o .tox/dev.txt setup.py 90 | dev: pip install -r .tox/requirements-dev.txt 91 | pip install -e . 92 | {envpython} setup.py test # or: py.test, nose, coverage run, etc. 93 | 94 | Tox-travis 95 | ^^^^^^^^^^ 96 | When you are using tox, the TravisCI setup becomes much simpler. 97 | 98 | .. code-block:: yaml 99 | 100 | language: python 101 | 102 | python: 103 | - "2.7" 104 | - "3.5" 105 | - "3.6" 106 | - "3.7" 107 | 108 | install: 109 | - pip install tox tox-travis 110 | 111 | script: 112 | - tox 113 | """ 114 | 115 | from __future__ import absolute_import, print_function 116 | 117 | from .requirements_builder import iter_requirements 118 | from .version import __version__ 119 | 120 | __all__ = ('__version__', ) 121 | -------------------------------------------------------------------------------- /requirements_builder/cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016, 2017 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """CLI for requirements builder.""" 11 | 12 | from __future__ import absolute_import, print_function 13 | 14 | import os.path 15 | 16 | import click 17 | 18 | from .requirements_builder import iter_requirements 19 | 20 | 21 | @click.command() 22 | @click.option( 23 | '--level', 24 | '-l', 25 | default='pypi', 26 | type=click.Choice(['min', 'pypi', 'dev']), 27 | help='Specifies desired requirements level.' 28 | '"min" requests the minimal requirement that is specified, ' 29 | '"pypi" requests the maximum version that satisfies the ' 30 | 'constrains and is available in PyPi. ' 31 | '"dev" includes experimental developer versions for VCSs.' 32 | ) 33 | @click.option( 34 | '--extras', 35 | '-e', 36 | default=[], 37 | help='Comma separated list of extras.', 38 | multiple=True 39 | ) 40 | @click.option( 41 | '--req', 42 | '-r', 43 | default=None, 44 | help='Requirements file.', 45 | metavar='PATH', 46 | type=click.Path( 47 | exists=True, dir_okay=False, readable=True, resolve_path=True 48 | ) 49 | ) 50 | @click.option( 51 | '--output', '-o', default='-', help='Output file.', type=click.File('w') 52 | ) 53 | @click.argument('setup', type=click.File('rb'), required=False) 54 | @click.pass_context 55 | def cli(ctx, level, extras, req, output, setup): 56 | """Calculate requirements for different purposes.""" 57 | if level == 'dev' and not req: 58 | raise click.UsageError( 59 | "You must specify --req when using 'dev' level." 60 | ) 61 | if not setup and not req: 62 | raise click.MissingParameter( 63 | ctx=ctx, param_hint='"setup"', param_type='argument' 64 | ) 65 | extras = set(req.strip() for extra in extras for req in extra.split(',')) 66 | 67 | # figure out the setup.cfg and pyproject.toml file 68 | setup_cfg = None 69 | pyproject_toml_fp = None 70 | 71 | if setup: 72 | cfg = os.path.splitext(setup.name)[0] + ".cfg" 73 | if os.path.exists(cfg): 74 | setup_cfg = open(cfg, 'r') 75 | 76 | toml_path = os.path.join(os.path.dirname(setup.name), "pyproject.toml") 77 | if os.path.exists(toml_path): 78 | pyproject_toml_fp = open(toml_path, 'rb') 79 | 80 | try: 81 | lines = ( 82 | '{0}\n'.format(req) 83 | for req in iter_requirements( 84 | level, 85 | extras, 86 | req, 87 | setup, 88 | setup_cfg, 89 | pyproject_toml_fp 90 | ) 91 | ) 92 | output.writelines(lines) 93 | finally: 94 | if setup_cfg: 95 | setup_cfg.close() 96 | -------------------------------------------------------------------------------- /requirements_builder/requirements_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016, 2017, 2018 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """Generate requirements from `setup.py` and `requirements-devel.txt`.""" 11 | 12 | from __future__ import absolute_import, print_function 13 | 14 | import os 15 | import re 16 | import sys 17 | 18 | try: 19 | import configparser 20 | except ImportError: # pragma: no cover 21 | import ConfigParser as configparser 22 | try: 23 | import tomllib 24 | except ImportError: # pragma: no cover 25 | # python 3.10 and older 26 | import tomli as tomllib 27 | 28 | 29 | import mock 30 | import pkg_resources 31 | import setuptools 32 | 33 | 34 | def parse_set(string): 35 | """Parse set from comma separated string.""" 36 | string = string.strip() 37 | if string: 38 | return set(string.split(",")) 39 | else: 40 | return set() 41 | 42 | 43 | def minver_error(pkg_name): 44 | """Report error about missing minimum version constraint and exit.""" 45 | print( 46 | 'ERROR: specify minimal version of "{0}" using ' 47 | '">=" or "=="'.format(pkg_name), 48 | file=sys.stderr 49 | ) 50 | sys.exit(1) 51 | 52 | 53 | def build_pkg_name(pkg): 54 | """Build package name, including extras if present.""" 55 | if pkg.extras: 56 | return '{0}[{1}]'.format( 57 | pkg.project_name, ','.join(sorted(pkg.extras))) 58 | return pkg.project_name 59 | 60 | 61 | def parse_pip_file(path): 62 | """Parse pip requirements file.""" 63 | # requirement lines sorted by importance 64 | # also collect other pip commands 65 | rdev = {} 66 | rnormal = [] 67 | stuff = [] 68 | 69 | try: 70 | with open(path) as f: 71 | for line in f: 72 | line = line.strip() 73 | 74 | # see https://pip.readthedocs.io/en/1.1/requirements.html 75 | if line.startswith('-e'): 76 | # devel requirement 77 | splitted = line.split('#egg=') 78 | rdev[splitted[1].lower()] = line 79 | 80 | elif line.startswith('-r'): 81 | # recursive file command 82 | splitted = re.split('-r\\s+', line) 83 | subrdev, subrnormal, substuff = parse_pip_file( 84 | os.path.join(os.path.dirname(path), splitted[1]) 85 | ) 86 | for k, v in subrdev.items(): 87 | if k not in rdev: 88 | rdev[k] = v 89 | rnormal.extend(subrnormal) 90 | elif line.startswith('-'): 91 | # another special command we don't recognize 92 | stuff.append(line) 93 | else: 94 | # ordinary requirement, similarly to them used in setup.py 95 | rnormal.append(line) 96 | except IOError: 97 | print( 98 | 'Warning: could not parse requirements file "{0}"!'.format(path), 99 | file=sys.stderr 100 | ) 101 | 102 | return rdev, rnormal, stuff 103 | 104 | 105 | def iter_requirements( 106 | level, 107 | extras, 108 | pip_file, 109 | setup_fp, 110 | setup_cfg_fp=None, 111 | pyproject_toml_fp=None 112 | ): 113 | """Iterate over requirements.""" 114 | result = dict() 115 | requires = [] 116 | stuff = [] 117 | if level == 'dev' or setup_fp is None: 118 | result, requires, stuff = parse_pip_file(pip_file) 119 | 120 | install_requires = [] 121 | requires_extras = {} 122 | if setup_fp is not None: 123 | with mock.patch.object(setuptools, 'setup') as mock_setup: 124 | sys.path.append(os.path.dirname(setup_fp.name)) 125 | g = {'__file__': setup_fp.name, '__name__': '__main__'} 126 | exec(setup_fp.read(), g) 127 | sys.path.pop() 128 | assert g['setup'] # silence warning about unused imports 129 | 130 | # called arguments are in `mock_setup.call_args` 131 | mock_args, mock_kwargs = mock_setup.call_args 132 | install_requires = mock_kwargs.get( 133 | 'install_requires', install_requires 134 | ) 135 | requires_extras = mock_kwargs.get('extras_require', requires_extras) 136 | 137 | if setup_cfg_fp is not None: 138 | parser = configparser.ConfigParser() 139 | parser.read_file(setup_cfg_fp) 140 | 141 | if parser.has_section("options"): 142 | value = parser.get("options", "install_requires", 143 | fallback="").strip() 144 | 145 | if value: 146 | install_requires = [s.strip() for s in value.splitlines()] 147 | 148 | if parser.has_section("options.extras_require"): 149 | for name, value in parser.items("options.extras_require"): 150 | requires_extras[name] = [s.strip() 151 | for s in value.strip().splitlines()] 152 | 153 | if pyproject_toml_fp is not None: 154 | toml_dict = tomllib.load(pyproject_toml_fp) 155 | toml_project = toml_dict.get("project") 156 | toml_requires = toml_project.get("dependencies") 157 | if toml_requires is not None: 158 | install_requires.extend(toml_requires) 159 | optional_dependencies = toml_project.get("optional-dependencies") 160 | if optional_dependencies is not None: 161 | for name, value in optional_dependencies.items(): 162 | requires_extras[name] = value 163 | 164 | install_requires.extend(requires) 165 | 166 | for e, reqs in requires_extras.items(): 167 | # Handle conditions on extras. See pkginfo_to_metadata function 168 | # in Wheel for details. 169 | condition = '' 170 | if ':' in e: 171 | e, condition = e.split(':', 1) 172 | if not e or e in extras: 173 | if condition: 174 | reqs = ['{0}; {1}'.format(r, condition) for r in reqs] 175 | install_requires.extend(reqs) 176 | 177 | for pkg in pkg_resources.parse_requirements(install_requires): 178 | # skip things we already know 179 | # FIXME be smarter about merging things 180 | 181 | # Evaluate environment markers skip if not applicable 182 | if hasattr(pkg, 'marker') and pkg.marker is not None: 183 | if not pkg.marker.evaluate(): 184 | continue 185 | else: 186 | # Remove markers from the output 187 | pkg.marker = None 188 | 189 | if pkg.key in result: 190 | continue 191 | 192 | specs = dict(pkg.specs) 193 | if (('>=' in specs) and ('>' in specs)) \ 194 | or (('<=' in specs) and ('<' in specs)): 195 | print( 196 | 'ERROR: Do not specify such weird constraints! ' 197 | '("{0}")'.format(pkg), 198 | file=sys.stderr 199 | ) 200 | sys.exit(1) 201 | 202 | if '==' in specs: 203 | result[pkg.key] = '{0}=={1}'.format( 204 | build_pkg_name(pkg), specs['==']) 205 | 206 | elif '>=' in specs: 207 | if level == 'min': 208 | result[pkg.key] = '{0}=={1}'.format( 209 | build_pkg_name(pkg), specs['>='] 210 | ) 211 | else: 212 | result[pkg.key] = pkg 213 | 214 | elif '>' in specs: 215 | if level == 'min': 216 | minver_error(build_pkg_name(pkg)) 217 | else: 218 | result[pkg.key] = pkg 219 | 220 | elif '~=' in specs: 221 | if level == 'min': 222 | result[pkg.key] = '{0}=={1}'.format( 223 | build_pkg_name(pkg), specs['~=']) 224 | else: 225 | ver, _ = os.path.splitext(specs['~=']) 226 | result[pkg.key] = '{0}>={1},=={2}.*'.format( 227 | build_pkg_name(pkg), specs['~='], ver) 228 | 229 | else: 230 | if level == 'min': 231 | minver_error(build_pkg_name(pkg)) 232 | else: 233 | result[pkg.key] = build_pkg_name(pkg) 234 | 235 | for s in stuff: 236 | yield s 237 | 238 | for k in sorted(result.keys()): 239 | yield str(result[k]) 240 | -------------------------------------------------------------------------------- /requirements_builder/version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015-2020 CERN. 5 | # Copyright (C) 2018 Swiss Data Science Center (SDSC) 6 | # A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and 7 | # Eidgenössische Technische Hochschule Zürich (ETHZ). 8 | # 9 | # Requirements-Builder is free software; you can redistribute it and/or 10 | # modify it under the terms of the Revised BSD License; see LICENSE 11 | # file for more details. 12 | # 13 | """Version information for Requirements-Builder. 14 | 15 | This file is imported by ``requirements-builder.__init__``, and parsed by 16 | ``setup.py`` as well as ``docs/conf.py``. 17 | """ 18 | 19 | # Do not change the format of this next line. Doing so risks breaking 20 | # setup.py and docs/conf.py 21 | 22 | __version__ = "0.4.4" 23 | -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This file is part of Invenio. 5 | # Copyright (C) 2015-2020 CERN. 6 | # 7 | # Invenio is free software; you can redistribute it and/or modify it 8 | # under the terms of the MIT License; see LICENSE file for more details. 9 | 10 | # Quit on errors 11 | set -o errexit 12 | 13 | # Quit on unbound symbols 14 | set -o nounset 15 | 16 | python -m check_manifest --ignore ".*-requirements.txt" 17 | python -m sphinx.cmd.build -qnNW docs docs/_build/html 18 | python -m pytest 19 | python -m sphinx.cmd.build -qnNW -b doctest docs docs/_build/doctest 20 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015, 2017, 2020 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | [metadata] 9 | name = requirements-builder 10 | version = attr:requirements_builder.__version__ 11 | url = https://github.com/inveniosoftware/requirements-builder/ 12 | author = Invenio Collaboration 13 | author_email = info@inveniosoftware.org 14 | description = Build requirements files from setup.py requirements. 15 | long_description = file: README.rst 16 | license = BSD 17 | license_file = LICENSE 18 | classifiers = 19 | Intended Audience :: Developers 20 | License :: OSI Approved :: BSD License 21 | Programming Language :: Python 22 | Programming Language :: Python :: 3 23 | Programming Language :: Python :: 3.5 24 | Programming Language :: Python :: 3.6 25 | Programming Language :: Python :: 3.7 26 | Programming Language :: Python :: 3.8 27 | 28 | [options] 29 | packages = find: 30 | include_package_data = true 31 | zip_safe = false 32 | install_requires = 33 | click >= 7.0 34 | mock <4,>= 1.3.0 35 | tomli >= 2.0.0; python_version < '3.11' 36 | setup_requires = 37 | pytest-runner >= 2.6.2 38 | importlib-metadata >= 1.6.0 39 | mock >= 1.3.0 40 | tests_require = 41 | pytest-cache >= 1.0 42 | pytest-invenio >= 1.4.0 43 | 44 | [options.packages.find] 45 | include = requirements_builder 46 | 47 | [options.entry_points] 48 | console_scripts = 49 | requirements-builder = requirements_builder.cli:cli 50 | 51 | [options.extras_require] 52 | docs = 53 | Sphinx >= 3 54 | all = 55 | Sphinx >= 3 56 | pytest-invenio >= 1.4.0 57 | pytest-cache >= 1.0 58 | 59 | [aliases] 60 | test = pytest 61 | 62 | [wheel] 63 | universal = 1 64 | 65 | [yapf] 66 | coalesce_brackets = 1 67 | join_multiple_lines = 0 68 | indent_dictionary_value = 1 69 | dedent_closing_brackets = 1 70 | space_between_ending_comma_and_closing_bracket = 1 71 | 72 | split_penalty_after_opening_bracket = 0 73 | split_penalty_for_added_line_split = 0 74 | 75 | [build_sphinx] 76 | source-dir = docs/ 77 | build-dir = docs/_build 78 | all_files = 1 79 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | 11 | from setuptools import setup 12 | 13 | setup() 14 | -------------------------------------------------------------------------------- /tests/data/other_req.txt: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2017 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | -e git+https://github.com/mitsuhiko/click.git#egg=click 9 | -------------------------------------------------------------------------------- /tests/data/req.txt: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015, 2017 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | -r other_req.txt 9 | Cython>=0.20 10 | -------------------------------------------------------------------------------- /tests/data/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016, 2017, 2018 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """Build requirements files from setup.py requirements.""" 11 | 12 | import os 13 | 14 | import testpkh 15 | from setuptools import setup 16 | 17 | dirname = os.path.dirname(__file__) 18 | 19 | requirements = [ 20 | 'click>=5.0.0', 21 | 'mock>=1.3.0', 22 | 'CairoSVG<2.0.0,>=1.0.20', 23 | 'functools32>=3.2.3-2; python_version=="2.7"', 24 | 'invenio-records~=1.0.0', 25 | 'invenio[base,auth,metadata]>=3.0.0', 26 | ] 27 | 28 | extras_require = { 29 | 'docs': ['Sphinx>=1.4.2'], 30 | 'tests': ['pytest>=2.7'], 31 | 'flask': ['Flask>=0.11'], 32 | ':python_version=="2.7"': ['ipaddr>=2.1.11'] 33 | } 34 | 35 | setup( 36 | name='testpkh', 37 | version=testpkh.__version__, 38 | install_requires=requirements, 39 | extras_require=extras_require, 40 | ) 41 | -------------------------------------------------------------------------------- /tests/data/setup_if_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2017 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """Build requirements files from setup.py requirements.""" 11 | 12 | import testpkh 13 | from setuptools import setup 14 | 15 | requirements = [ 16 | 'click>=5.0.0', 17 | ] 18 | 19 | extras_require = { 20 | 'docs': ['Sphinx>=1.4.2'], 21 | } 22 | 23 | if __name__ == "__main__": 24 | setup( 25 | name='testpkh', 26 | version=testpkh.__version__, 27 | install_requires=requirements, 28 | extras_require=extras_require, 29 | ) 30 | -------------------------------------------------------------------------------- /tests/data/testpkh/__init__.py: -------------------------------------------------------------------------------- 1 | """Version.""" 2 | __version__ = '0.0.1' 3 | -------------------------------------------------------------------------------- /tests/fixtures/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=61.2", 4 | "pytest-runner >= 2.6.2", 5 | "importlib-metadata >= 1.6.0", 6 | "mock >= 1.3.0", 7 | ] 8 | build-backend = "setuptools.build_meta" 9 | 10 | [project] 11 | name = "requirements-builder" 12 | version = "0.4.4dev" 13 | authors = [{name = "Invenio Collaboration", email = "info@inveniosoftware.org"}] 14 | description = "Build requirements files from setup.py requirements." 15 | readme = "README.rst" 16 | license = {text = "BSD"} 17 | classifiers = [ 18 | "Intended Audience :: Developers", 19 | "License :: OSI Approved :: BSD License", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3", 22 | "Programming Language :: Python :: 3.5", 23 | "Programming Language :: Python :: 3.6", 24 | "Programming Language :: Python :: 3.7", 25 | "Programming Language :: Python :: 3.8", 26 | ] 27 | dependencies = [ 28 | "click >= 7.0", 29 | "mock <4,>= 1.3.0", 30 | "tomli >= 2.0.0; python_version < '3.11'", 31 | ] 32 | 33 | [project.urls] 34 | Homepage = "https://github.com/inveniosoftware/requirements-builder/" 35 | 36 | [project.optional-dependencies] 37 | docs = ["Sphinx >= 3"] 38 | all = [ 39 | "Sphinx >= 3", 40 | "pytest-invenio >= 1.4.0", 41 | "pytest-cache >= 1.0", 42 | ] 43 | testing = [ 44 | "pytest-cache >= 1.0", 45 | "pytest-invenio >= 1.4.0", 46 | ] 47 | 48 | [project.scripts] 49 | requirements-builder = "requirements_builder.cli:cli" 50 | -------------------------------------------------------------------------------- /tests/fixtures/requirements.devel.txt: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015, 2018, 2020 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | 8 | -e git+https://github.com/pallets/click.git#egg=click 9 | -------------------------------------------------------------------------------- /tests/fixtures/setup.txt: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """Build requirements files from setup.py requirements.""" 11 | 12 | import os 13 | 14 | from setuptools import setup 15 | 16 | # Get the version string. Cannot be done with import! 17 | g = {} 18 | with open(os.path.join('requirements_builder', 'version.py'), 'rt') as fp: 19 | exec(fp.read(), g) 20 | version = g['__version__'] 21 | 22 | with open('README.rst') as readme_file: 23 | readme = readme_file.read() 24 | 25 | with open('CHANGES.rst') as history_file: 26 | history = history_file.read().replace('.. :changes:', '') 27 | 28 | install_requires = [ 29 | 'click>=6.1.0', 30 | 'mock>=1.3.0', 31 | ] 32 | 33 | tests_require = [ 34 | 'check-manifest>=0.25', 35 | 'coverage>=4.0', 36 | 'isort>=4.0.0', 37 | 'pydocstyle>=1.0.0', 38 | 'pytest-cache>=1.0', 39 | 'pytest-cov>=2.0.0', 40 | 'pytest-pep8>=1.0.6', 41 | 'pytest>=2.8.0', 42 | ] 43 | 44 | extras_require = { 45 | 'docs': [ 46 | 'Sphinx>=2.4', 47 | ], 48 | 'tests': tests_require, 49 | } 50 | 51 | extras_require['all'] = extras_require['tests'] + extras_require['docs'] 52 | 53 | setup_requires = ['pytest-runner>=2.6.2', ] 54 | 55 | setup( 56 | name='requirements-builder', 57 | version=version, 58 | description=__doc__, 59 | long_description=readme + '\n\n' + history, 60 | author="Invenio Collaboration", 61 | author_email='info@inveniosoftware.org', 62 | url='https://github.com/inveniosoftware/requirements-builder', 63 | entry_points={ 64 | 'console_scripts': 65 | ["requirements-builder = requirements_builder.cli:cli"] 66 | }, 67 | packages=['requirements_builder', ], 68 | include_package_data=True, 69 | extras_require=extras_require, 70 | install_requires=install_requires, 71 | setup_requires=setup_requires, 72 | tests_require=tests_require, 73 | license='BSD', 74 | zip_safe=False, 75 | keywords='requirements-builder', 76 | classifiers=[ 77 | 'Intended Audience :: Developers', 78 | 'License :: OSI Approved :: BSD License', 79 | 'Natural Language :: English', 80 | 'Programming Language :: Python :: 3', 81 | 'Programming Language :: Python :: 3.5', 82 | 'Programming Language :: Python :: 3.6', 83 | 'Programming Language :: Python :: 3.7', 84 | 'Programming Language :: Python :: 3.8', 85 | ], 86 | ) 87 | -------------------------------------------------------------------------------- /tests/fixtures/setup_py_placeholder.txt: -------------------------------------------------------------------------------- 1 | # an empty placeholder setup.py fixture for use with tests 2 | # that set dependencies in setup.cfg/pyproject.toml 3 | 4 | from setuptools import setup 5 | 6 | setup() -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015, 2016, 2017, 2018 CERN. 5 | # Copyright (C) 2018 Swiss Data Science Center (SDSC) 6 | # A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and 7 | # Eidgenössische Technische Hochschule Zürich (ETHZ). 8 | # 9 | # Requirements-Builder is free software; you can redistribute it and/or 10 | # modify it under the terms of the Revised BSD License; see LICENSE 11 | # file for more details. 12 | # 13 | """Tests for CLI module.""" 14 | 15 | import shutil 16 | import sys 17 | from os import getcwd 18 | from os.path import abspath, dirname, join 19 | 20 | import pytest 21 | from click.testing import CliRunner 22 | 23 | from requirements_builder.cli import cli 24 | 25 | DATA = abspath(join(dirname(__file__), 'data/')) 26 | 27 | 28 | @pytest.fixture(scope='function') 29 | def runner(): 30 | """Click test runner.""" 31 | runner = CliRunner() 32 | with runner.isolated_filesystem(): 33 | shutil.copytree(DATA, abspath(join(getcwd(), 'data/'))) 34 | yield runner 35 | 36 | 37 | def test_cli_min(runner): 38 | """Test cli.""" 39 | result = runner.invoke(cli, ['-l', 'min', 'data/setup.py']) 40 | assert result.exit_code == 0 41 | if sys.version_info[:2] == (2, 7): 42 | assert result.output == \ 43 | 'CairoSVG==1.0.20\n' \ 44 | 'click==5.0.0\n' \ 45 | 'functools32==3.2.3-2\n' \ 46 | 'invenio[auth,base,metadata]==3.0.0\n' \ 47 | 'invenio-records==1.0.0\n' \ 48 | 'ipaddr==2.1.11\n' \ 49 | 'mock==1.3.0\n' 50 | else: 51 | assert result.output == \ 52 | 'CairoSVG==1.0.20\n' \ 53 | 'click==5.0.0\n' \ 54 | 'invenio[auth,base,metadata]==3.0.0\n' \ 55 | 'invenio-records==1.0.0\n' \ 56 | 'mock==1.3.0\n' 57 | 58 | 59 | def test_cli_pypi(runner): 60 | """Test cli.""" 61 | result = runner.invoke(cli, ['-l', 'pypi', 'data/setup.py']) 62 | assert result.exit_code == 0 63 | 64 | if sys.version_info[:2] == (2, 7): 65 | assert result.output == \ 66 | 'CairoSVG<2.0.0,>=1.0.20\n' \ 67 | 'click>=5.0.0\n' \ 68 | 'functools32>=3.2.3-2\n' \ 69 | 'invenio[auth,base,metadata]>=3.0.0\n' \ 70 | 'invenio-records>=1.0.0,==1.0.*\n' \ 71 | 'ipaddr>=2.1.11\n' \ 72 | 'mock>=1.3.0\n' 73 | else: 74 | assert result.output == \ 75 | 'CairoSVG<2.0.0,>=1.0.20\n' \ 76 | 'click>=5.0.0\n' \ 77 | 'invenio[auth,base,metadata]>=3.0.0\n' \ 78 | 'invenio-records>=1.0.0,==1.0.*\n' \ 79 | 'mock>=1.3.0\n' 80 | 81 | 82 | def test_cli_dev_erro(runner): 83 | """Test cli.""" 84 | result = runner.invoke(cli, ['-l', 'dev', 'data/setup.py']) 85 | assert result.exit_code == 2 86 | 87 | 88 | def test_cli_dev(runner): 89 | """Test cli.""" 90 | result = runner.invoke( 91 | cli, ['-l', 'dev', '-r', 'data/req.txt', 'data/setup.py'] 92 | ) 93 | assert result.exit_code == 0 94 | if sys.version_info[:2] == (2, 7): 95 | assert result.output == \ 96 | 'CairoSVG<2.0.0,>=1.0.20\n' \ 97 | '-e git+https://github.com/mitsuhiko/click.git#egg=click\n' \ 98 | 'Cython>=0.20\n' \ 99 | 'functools32>=3.2.3-2\n' \ 100 | 'invenio[auth,base,metadata]>=3.0.0\n' \ 101 | 'invenio-records>=1.0.0,==1.0.*\n' \ 102 | 'ipaddr>=2.1.11\n' \ 103 | 'mock>=1.3.0\n' 104 | else: 105 | assert result.output == \ 106 | 'CairoSVG<2.0.0,>=1.0.20\n' \ 107 | '-e git+https://github.com/mitsuhiko/click.git#egg=click\n' \ 108 | 'Cython>=0.20\n' \ 109 | 'invenio[auth,base,metadata]>=3.0.0\n' \ 110 | 'invenio-records>=1.0.0,==1.0.*\n' \ 111 | 'mock>=1.3.0\n' 112 | 113 | 114 | def test_cli_min_output(runner): 115 | """Test cli.""" 116 | result = runner.invoke( 117 | cli, ['-l', 'min', '-o', 'requirements.txt', 'data/setup.py'] 118 | ) 119 | assert result.exit_code == 0 120 | assert result.output == '' 121 | with open(join(getcwd(), 'requirements.txt')) as f: 122 | if sys.version_info[:2] == (2, 7): 123 | assert f.read() == \ 124 | 'CairoSVG==1.0.20\n' \ 125 | 'click==5.0.0\n' \ 126 | 'functools32==3.2.3-2\n' \ 127 | 'invenio[auth,base,metadata]==3.0.0\n' \ 128 | 'invenio-records==1.0.0\n' \ 129 | 'ipaddr==2.1.11\n' \ 130 | 'mock==1.3.0\n' 131 | else: 132 | assert f.read() == \ 133 | 'CairoSVG==1.0.20\n' \ 134 | 'click==5.0.0\n' \ 135 | 'invenio[auth,base,metadata]==3.0.0\n' \ 136 | 'invenio-records==1.0.0\n' \ 137 | 'mock==1.3.0\n' 138 | 139 | 140 | def test_cli_extras(runner): 141 | """Test cli option extras.""" 142 | output = ['CairoSVG==1.0.20', 143 | 'click==5.0.0', 144 | 'invenio[auth,base,metadata]==3.0.0', 145 | 'invenio-records==1.0.0', 146 | 'mock==1.3.0'] 147 | if sys.version_info[:2] == (2, 7): 148 | output.append('functools32==3.2.3-2') 149 | output.append('ipaddr==2.1.11') 150 | 151 | result = runner.invoke( 152 | cli, ['-l', 'min', '-e', 'docs', 'data/setup.py'] 153 | ) 154 | assert result.exit_code == 0 155 | assert set(result.output.split('\n') 156 | ) == set(output + ['Sphinx==1.4.2', '']) 157 | 158 | result = runner.invoke( 159 | cli, ['-l', 'min', '-e', 'docs, tests', 'data/setup.py'] 160 | ) 161 | assert result.exit_code == 0 162 | assert set(result.output.split('\n') 163 | ) == set(output + ['pytest==2.7', 'Sphinx==1.4.2', '']) 164 | 165 | result = runner.invoke( 166 | cli, 167 | ['-l', 'min', '-e', 'docs, tests', '-e', 'flask', 'data/setup.py'] 168 | ) 169 | assert result.exit_code == 0 170 | assert set( 171 | result.output.split('\n') 172 | ) == set(output + ['pytest==2.7', 'Sphinx==1.4.2', 'Flask==0.11', '']) 173 | 174 | 175 | def test_cli_no_setup(runner): 176 | """Test cli with no setup.py provided.""" 177 | with runner.isolated_filesystem(): 178 | result = runner.invoke(cli, ['-l', 'min']) 179 | 180 | assert result.exit_code != 0 181 | assert ( 182 | result.output.strip().split('\n')[-1] == 183 | 'Error: Missing argument "setup".' 184 | ) 185 | 186 | 187 | def test_cli_with_only_requirements(runner): 188 | """Test cli with no setup.py provided but a req.txt""" 189 | with runner.isolated_filesystem(): 190 | shutil.copytree(DATA, abspath(join(getcwd(), 'data/'))) 191 | 192 | result = runner.invoke(cli, ['-l', 'min', '-r', 'data/req.txt']) 193 | 194 | assert result.exit_code == 0 195 | assert set(result.output.strip().split('\n')) == set([ 196 | 'Cython==0.20', 197 | '-e git+https://github.com/mitsuhiko/click.git#egg=click' 198 | ]), result.output.split('\n') 199 | 200 | 201 | def test_cli_setup_with_if_main(runner): 202 | """Test loading setup.py with 'if __name__ == '__main__' around setup.""" 203 | with runner.isolated_filesystem(): 204 | shutil.copytree(DATA, abspath(join(getcwd(), 'data/'))) 205 | result = runner.invoke(cli, ['-l', 'min', 'data/setup_if_main.py']) 206 | 207 | assert result.exit_code == 0 208 | assert result.output == 'click==5.0.0\n' 209 | -------------------------------------------------------------------------------- /tests/test_requirements_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # This file is part of Requirements-Builder 4 | # Copyright (C) 2015 CERN. 5 | # 6 | # Requirements-Builder is free software; you can redistribute it and/or 7 | # modify it under the terms of the Revised BSD License; see LICENSE 8 | # file for more details. 9 | # 10 | """Tests for `requirements-builder` module.""" 11 | 12 | import sys 13 | from os.path import abspath, dirname, join 14 | 15 | from requirements_builder import __version__, iter_requirements 16 | 17 | REQ = abspath(join(dirname(__file__), "./fixtures/requirements.devel.txt")) 18 | SETUP = abspath(join(dirname(__file__), "./fixtures/setup.txt")) 19 | 20 | 21 | def _has_toml_lib(): 22 | # tomlib is part of the batteries included since 3.11 23 | return sys.version_info >= (3, 11) 24 | 25 | 26 | def test_version(): 27 | """Test requirements-builder.""" 28 | assert __version__ 29 | 30 | 31 | def test_iter_requirements(): 32 | """Test requirements-builder.""" 33 | # Min 34 | with open(SETUP) as f: 35 | assert list(iter_requirements("min", [], '', f)) == \ 36 | ['click==6.1.0', 'mock==1.3.0'] 37 | 38 | # PyPI 39 | with open(SETUP) as f: 40 | assert list(iter_requirements("pypi", [], '', f)) == \ 41 | ['click>=6.1.0', 'mock>=1.3.0'] 42 | 43 | # Dev 44 | with open(SETUP) as f: 45 | assert list(iter_requirements("dev", [], REQ, f)) == \ 46 | ['-e git+https://github.com/pallets/click.git#egg=click', 47 | 'mock>=1.3.0'] 48 | 49 | 50 | def test_iter_requirements_cfg(): 51 | """Test requirements-builder.""" 52 | req = abspath(join(dirname(__file__), "../requirements.devel.txt")) 53 | setup = abspath(join(dirname(__file__), "../setup.py")) 54 | setup_cfg = abspath(join(dirname(__file__), "../setup.cfg")) 55 | 56 | # Min 57 | with open(setup) as f: 58 | with open(setup_cfg) as g: 59 | expected = ['click==7.0', 'mock==1.3.0'] 60 | if not _has_toml_lib(): 61 | expected.append("tomli==2.0.0") 62 | assert list(iter_requirements("min", [], '', f, g)) == \ 63 | expected 64 | 65 | # PyPI 66 | with open(setup) as f: 67 | with open(setup_cfg) as g: 68 | expected = ['click>=7.0', 'mock<4,>=1.3.0'] 69 | if not _has_toml_lib(): 70 | expected.append("tomli>=2.0.0") 71 | assert list(iter_requirements("pypi", [], '', f, g)) == \ 72 | expected 73 | 74 | # Dev 75 | with open(setup) as f: 76 | with open(setup_cfg) as g: 77 | expected = ['click>=7.0', 'mock<4,>=1.3.0'] 78 | if not _has_toml_lib(): 79 | expected.append("tomli>=2.0.0") 80 | assert list(iter_requirements("dev", [], req, f, g)) == \ 81 | expected 82 | 83 | 84 | def test_iter_requirements_toml(): 85 | """Test requirements-builder for 86 | pyproject.toml (pep621).""" 87 | 88 | setup_py = abspath( 89 | join(dirname(__file__), "fixtures", "setup_py_placeholder.txt") 90 | ) 91 | pyproject_toml = abspath( 92 | join(dirname(__file__), "fixtures", "pyproject.toml") 93 | ) 94 | req = abspath(join(dirname(__file__), "../requirements.devel.txt")) 95 | 96 | # Min 97 | with open(setup_py) as setup_py_fp: 98 | with open(pyproject_toml, 'rb') as pyproject_toml_fp: 99 | expected = ['click==7.0', 'mock==1.3.0'] 100 | if not _has_toml_lib(): 101 | expected.append("tomli==2.0.0") 102 | assert list(iter_requirements( 103 | "min", 104 | [], 105 | '', 106 | setup_fp=setup_py_fp, 107 | pyproject_toml_fp=pyproject_toml_fp 108 | )) == expected 109 | # # PyPI 110 | with open(setup_py) as setup_py_fp: 111 | with open(pyproject_toml, 'rb') as pyproject_toml_fp: 112 | expected = ['click>=7.0', 'mock<4,>=1.3.0'] 113 | if not _has_toml_lib(): 114 | expected.append("tomli>=2.0.0") 115 | assert list(iter_requirements( 116 | "pypi", 117 | [], 118 | '', 119 | setup_fp=setup_py_fp, 120 | pyproject_toml_fp=pyproject_toml_fp 121 | )) == expected 122 | 123 | # Dev 124 | with open(setup_py) as setup_py_fp: 125 | with open(pyproject_toml, 'rb') as pyproject_toml_fp: 126 | expected = ['click>=7.0', 'mock<4,>=1.3.0'] 127 | if not _has_toml_lib(): 128 | expected.append("tomli>=2.0.0") 129 | assert list(iter_requirements( 130 | "dev", 131 | [], 132 | req, 133 | setup_fp=setup_py_fp, 134 | pyproject_toml_fp=pyproject_toml_fp 135 | )) == expected 136 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # This file is part of Requirements-Builder 2 | # Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 CERN. 3 | # 4 | # Requirements-Builder is free software; you can redistribute it and/or 5 | # modify it under the terms of the Revised BSD License; see LICENSE 6 | # file for more details. 7 | [tox] 8 | envlist = pypy, pypy3, py27, py35, py36, py37, py38 9 | skip_missing_interpreters = true 10 | 11 | [testenv] 12 | setenv = 13 | PYTHONPATH = {toxinidir}:{toxinidir}/requirements-builder 14 | commands = 15 | python setup.py test 16 | 17 | 18 | # See https://wiki.python.org/moin/TestPyPI 19 | [testenv:release] 20 | deps = 21 | twine >= 1.4.0 22 | wheel 23 | commands = 24 | /bin/rm -Rf {toxinidir}/dist 25 | {envpython} setup.py clean --all 26 | {envpython} setup.py sdist bdist_wheel 27 | twine upload -r pypi {posargs} dist/* 28 | --------------------------------------------------------------------------------