pax_global_header00006660000000000000000000000064150353737260014525gustar00rootroot0000000000000052 comment=919b6884afaf151b99a7fcbf255589cdf1b7a567 pyroma-5.0/000077500000000000000000000000001503537372600127005ustar00rootroot00000000000000pyroma-5.0/.gitattributes000066400000000000000000000000441503537372600155710ustar00rootroot00000000000000pyroma/testdata/* linguist-vendored pyroma-5.0/.github/000077500000000000000000000000001503537372600142405ustar00rootroot00000000000000pyroma-5.0/.github/workflows/000077500000000000000000000000001503537372600162755ustar00rootroot00000000000000pyroma-5.0/.github/workflows/lint.yml000066400000000000000000000010651503537372600177700ustar00rootroot00000000000000# Run the linting suite for the pyroma package # Based on https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Lint package on: [push, pull_request, workflow_dispatch] env: FORCE_COLOR: 1 jobs: build: name: Run pre-commit runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x' - name: Run pre-commit hooks uses: pre-commit/action@v3.0.1 pyroma-5.0/.github/workflows/test.yml000066400000000000000000000016401503537372600200000ustar00rootroot00000000000000# Runs the unit tests for the pyroma package # Based on https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Test package on: [push, pull_request, workflow_dispatch] env: FORCE_COLOR: 1 jobs: build: name: Tests runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ['3.9', '3.14', 'pypy-3.11'] steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Upgrade pip run: python -m pip install --upgrade pip - name: Install tox run: python -m pip install --upgrade tox - name: Run tests run: tox -e py pyroma-5.0/.gitignore000066400000000000000000000001541503537372600146700ustar00rootroot00000000000000syntax: glob *.pyc *.egg-info *.egg EGG-INFO dist build py2* py3* .tox *.wpr *.wpu *.bak *.class .venv .env pyroma-5.0/.pre-commit-config.yaml000066400000000000000000000013441503537372600171630ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: check-case-conflict - id: check-merge-conflict - id: check-toml - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black-pre-commit-mirror rev: 24.10.0 hooks: - id: black - repo: https://github.com/pycqa/flake8 rev: 7.1.1 hooks: - id: flake8 - repo: https://github.com/regebro/pyroma rev: '5.0b2' hooks: - id: pyroma - repo: https://github.com/tox-dev/tox-ini-fmt rev: 1.4.1 hooks: - id: tox-ini-fmt - repo: meta hooks: - id: check-hooks-apply - id: check-useless-excludes pyroma-5.0/.pre-commit-hooks.yaml000066400000000000000000000003701503537372600170370ustar00rootroot00000000000000- id: pyroma name: Check package with Pyroma description: Check how well a Python package conforms to best practices. entry: pyroma args: ["-d", "--min=10", "."] language: python pass_filenames: false always_run: true pyroma-5.0/CHANGES.txt000066400000000000000000000255431503537372600145220ustar00rootroot00000000000000Changelog ========= 5.0 (2025-07-15) ---------------- - Re-releasing as final. 5.0b2 (2025-07-10) ------------------ - Fixed a bug that failed to find license-expression fields. 5.0b1 (2025-07-04) ------------------ - Changed the internal metadata names to match Core Metadata. This brings less confusion, especially since setuptools and PyPI aren't exactly the same either, so let's pick the offical standard and run with it. - Added a rating for if the wheel fails to build. Unfortunately it's impossible to get a proper error out of it, so the message tells you to run python -m build. 5.0a1 (2025-07-02) ------------------ - Removed support for fetching data via monkey-patching setup.py. - Added a warning if you have only a setup.cfg, something that is working with some tools, but is not officially supported. - Some general cleanups and simplifications thanks to those changes. 4.3.3 (2025-07-03) ------------------ - Licensing specifications are less flexible than I thought. Updated to reflect that. 4.3.2 (2025-07-02) ------------------ - Added support for License-Expression as per PEP 639. 4.3.1 (2025-07-01) ------------------ - Deprecation warnings? For the packaging configuration? What was I thinking? I'm instead adding a rating telling people that they should add a pyproject.toml. Much nicer. 4.3 (2025-07-01) ---------------- - Added a --skip-tests parameter to allow skipping of certain tests. You shouldn't skip tests, of course, but now you can. This is actually only implemented so that I can add a test using check-manifest and skip it when run from the zest.releaser hook. - If you also have check-manifest installed, pyroma will run that as a test. No longer do you need to call it separately! However, if Pyroma is invoked from zest.releaser, it will not be run, because check-manifest has a separate hook for zest.releaser, so that would run it twice. - Allow private classifiers [hugovk] - Using tox to run tests [hugovk] - Deperating the support for setup.py 4.2 (2023-02-25) ---------------- - Fall back to installing project's build backend in an isolated environment if a compatible version isn't installed in the current env [CAM-Gerlach] - Fix metadata extraction failure when project ``long_description`` is included as a header rather than a payload in the ``METADTA`` file [CAM-Gerlach] - Add a fallback to restore compatibility with Setuptools <61 [CAM-Gerlach] - Fix tests failing due to invalid versions on Setuptools >=66 [CAM-Gerlach] - Add ``python_requires``, update classifiers, add implicit dependencies and remove unused deps in Pyroma's own packaging metadata [CAM-Gerlach] 4.1 (2022-11-24) ---------------- - Moved from a custom trove classifiers list to using the trove-classifiers package [hugovk] - Support checking the Requires-Python metadata [davidandreoletti] - Silence noisy build backend output when building metadata [CAM-Gerlach, wesleybl] - Official support for Python 3.11 [hugovk, radarhere] - Some string formatting bugs [hugovk, CAM-Gerlach] - Now follows black and flake8 rules - Check if author_email field contains author name [bessman] 4.0 (2022-04-14) ---------------- - No changes from 4.0b2. 4.0b2 (2022-03-29) ------------------ - The deprecation test for test_suite is no longer needed, as the patched setuptools method of gathering metadata as a whole is deprecated. - `description_content_type` also needs a mapping in the metadata map. 4.0b1 (2022-03-28) ------------------ - Added support for PEP517 by using `build` to build the metadata as a preferred build method over the old patched setuptools method. The old way is depracated and will be removed in 5.0, which also is planned to support PEP621. Thanks to Christopher A.M. Gerlach for valuable insight into the modern packaging systems. 3.3 (2022-03-28) ---------------- - Add a deprecation for `test_suite` 3.2.1 (2022-03-27) ------------------ - Fixed __getattr__-related crash in tests with python3.7 [Robert T. McGibbon] 3.2 (2021-06-22) ---------------- - Added support for pre-commit [CAM Gerlach] - Rewrote parts of the PyPI support, to avoid using the xmlrpc API, since it's being heavily rate-limited at the moment. Only one call is using it now, which seems to work fine. - Backwards incompatible change: As a result of the above change, when looking for packages on PyPI, the package name must now be spelled exactly correct, including capitalization. - Some more code cleanup/modernization [CAM Gerlach] - Added --quiet option to output only the rating [Hugo van Kemenade] - Pyroma is now an executable module, and can be called with `python -m pyroma` [RuRo] 3.1 (2021-03-06) ---------------- - Added correct detection of setup.py encoding - Code cleanup [CAM Gerlach] 3.0.1 (2021-03-02) ------------------ - Drop support for Python 2 [Florian Bruhin] - Add back official support for Python 3.6, I didn't realize it was still officially supported 2.6.1 (2021-02-16) ------------------ - Update to the current list of Trove classifiers. - Officially support Python 3.8 and 3.9 - Drop official support for Python 3.5 and 3.6 (still works though). 2.6 (2019-11-02) ---------------- - Ran flake8 and black on the code, better formatting for classifiers.py generation. - Support for PEP 517, setup.cfg-only packages. [Max Tyulin] - Adds support for Markdown long_descriptions, if you set long_description_content_type to 'text/markdown' - Installs Pygments to avoid an error message of you have syntax highlighted code in the long_description. 2.5 (2019-06-01) ---------------- - Fixed #35: Correctly restore ``sys.argv``. [maurits] - Added back the BusFactor test, the XMLRPC API supports it. - #26: Adding a test to check for a development status classifier. - #21: Accept the new project_urls distribution data. - Now verifies that classifiers are valid, and that the license field and license classifiers match. - The rating now again reflects if the long_description isn't valid ReST. - #38: Recommendations for the License field has changed. 2.4 (2018-08-15) ---------------- - Get rid of the tests that rely on HTML scraping, it's too brittle. - Update to use pypi.org instead of pypi.python.org [Andreas Lutro, Lennart Regebro] - Added -n command line option to set the minimum rating needed for pyroma to return success, useful in scripts. [Scott Colby] 2.3.1 (2018-05-28) ------------------ - Fixed #12: Installation fails with a non-UTF8 locale under Python 3. [ericof, 4383, regebro] 2.3 (2017-11-28) ---------------- - Check that a classifier specifies the project license. [4383] - Dropped support for Python 2.6, 3.3 and 3.4. - Fixed a unicode issue [gotcha] - Stopped recommending places to keep documentation. 2.2 (2016-10-26) ---------------- - Removed the TestSuite rating. I decided it was too close to looking at code quality. Pyroma no longer cares if you have tests or not. - Fixed #36: PyPI now requires https. 2.1 (2016-10-18) ---------------- - #35: Support for PEP-440. 2.0.2 (2016-03-06) ------------------ - Faked the __name__ variable to allow you to have a "if __name__" construct in the setup.py. 2.0.1 (2016-03-06) ------------------ - Fixed a bug under Python 3 with certain imports. 2.0.0 (2016-02-28) ------------------ - Stable release. 2.0.0b2 (2015-11-09) -------------------- - Made it run under Python 3 again. - PEP8 2.0.0b1 (2015-11-08) -------------------- - Big rewrite of how data is extracted from Distutils/Setuptools. 1.8.3 (2015-11-08) ------------------ - Issue #26: Checking a PyPI package could fail under Python 3. 1.8.2 (2015-06-14) ------------------ - Do not complain that the version number should be a string, when it is a basestring. [maurits] 1.8.1 (2015-04-27) ------------------ - This is what happens when you don't run the tests after merging. 1.8 (2015-04-27) ---------------- - More robust rating. [Jeff Quast] - Closed #24. 1.7 (2014-10-19) ---------------- - Package name lookup is now case insensitive. [Dmitry Vakhrushev] - Fixed yet another error in return value. [Dmitry Vakhrushev] 1.6 (2014-04-17) ---------------- - Fixed issue #17: Integration with zest.releaser stopped working. - Fixed issue #18: Pyroma returns the rating as an exit code, this was a mistake. It now returns 0 on success, 1 on incorrect options and 2 if the rating is below 8. - Fixed issue #19: Implementing a custom test class counts as having tests. - 8: Philadelphia is now considered a "success" based on practical experience. 1.5 (2013-10-18) ---------------- - Fixed issue #13: Pyroma would fail if there was no description. - Dropping support for Python 3.1. It still works, but it is unsupported. - Added support for command line options, implementing #14 and #15. 1.4 (2013-05-29) ---------------- - Issue #13: Pyroma would fail when checking a package name if no source distribution could be found. - Added a check that the package has a source distribution on PyPI. 1.3.1 (2013-05-29) ------------------ - Issue #11: pyroma would fail if long_description was a non-string. - zest.releaser now only runs Pyroma on Python packages. - Because packages that use external test-runners can not get more that 9/10, this value is now also seen as acceptable when running Pyroma through zest.releaser. 1.3 (2013-03-15) ---------------- - Added a test to make sure the version number is a string. - Made sure errors were printed also when a fatal error was encountered. - Better log messages. - The zest.releaser hook is now done before tagging, as it's more useful there. Especially in conjunction with check-manifest. - Having no long_description no longer causes pyroma to fail. 1.2 (2013-03-06) ---------------- - Removed the running of tests. I always found it a bit iffy, and getting rid of it solved a lot of issues. Pyroma is now focused solely on packaging quality. - A package on PyPI with several versions will no longer return an error. - Now looks for documentation on pythonhosted.org or readthedocs.org. - Adds a hook for zest.releaser, so it can be run after doing the checkout, before uploading to PyPI. 1.1 (2013-03-05) ---------------- - Better handling if there is no package data, for example if setup.py doesn't call setup() unless you run it as the "__main__" script. - If setup.py doesn't call setup() look for a main() script and try to run it. 1.0 (2013-03-05) ---------------- - Support for Python 3.3 - Added test for PEP 386 compliance. 0.9.3 (2011-03-17) ------------------ - It's now using a ProxyStub for the PyPI xmlrpclib during tests. - Removed the Dependency rating. - Added a rating that runs tests, to see if they run. This will also take care of checking for dependencies. 0.9.2 (2011-03-13) ------------------ - Commented out the dependency test, it was too unreliable. - Fixed the ReST. - Python 3 support. 0.9.1 (2011-03-08) ------------------ - Initial release pyroma-5.0/DEVELOPMENT.rst000066400000000000000000000021721503537372600152160ustar00rootroot00000000000000Testing ======= Run tests: $ python -m unittest pyroma.tests Some notes on developing ======================== *Note: Since pyroma no longer runs tests, this is probably no longer true.* For each Python version supported by Pyroma you need to make sure the "complete" package that is used for testing also supports that version of Python. The complete data supports both Python 2 and Python 3 and depends on the "six" package. As such it's highly unlikely you'll have to change any code. However, you have to mark the package as supporting the Python version. This is most easily done by searching the code for "Python :: 3.2" and adding the Python version that you want to support to the lists of Python versions that appear in several places in this package. Otherwise Pyroma will not run the complete-packages tests with your Python version, and you'll get errors when running Pyroma's test-suite. You also have to make new test-distributions with the updated data. You do it this way: $ cd pyroma/testdata/complete $ python setup.py sdist --formats=bztar,gztar,tar,zip $ cp dist/complete-1.0.dev1.* ../distributions/ pyroma-5.0/LICENSE.txt000066400000000000000000000020641503537372600145250ustar00rootroot00000000000000The MIT License Copyright (c) 2011 Lennart Regebro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pyroma-5.0/MANIFEST.in000066400000000000000000000003701503537372600144360ustar00rootroot00000000000000include *.txt recursive-include pyroma/testdata *.py *.txt *.cfg *.html *.json *.toml prune pyroma/testdata/complete/*.egg graft pyroma/testdata/distributions include tox.ini include DEVELOPMENT.rst include Makefile exclude .pre-commit-config.yaml pyroma-5.0/Makefile000066400000000000000000000016571503537372600143510ustar00rootroot00000000000000.PHONY: docs define PRINT_HELP_PYSCRIPT import re, sys for line in sys.stdin: match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) if match: target, help = match.groups() print("%-20s %s" % (target, help)) endef export PRINT_HELP_PYSCRIPT help: ## display this message @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) generate: ## generate environment for tests cd pyroma/testdata/complete;python setup.py sdist --formats=bztar,gztar,tar,zip cp pyroma/testdata/complete/dist/complete-1.0.dev1.* pyroma/testdata/distributions/ tests: generate ## run tests python -m unittest pyroma.tests clean: clean-pyc ## remove all clean-pyc: ## remove Python file artifacts find . -name '*.pyc' -exec rm -f {} + find . -name '*.pyo' -exec rm -f {} + find . -name '*~' -exec rm -f {} + find . -name '__pycache__' -exec rm -fr {} + find . -name 'pip-selfcheck.json' -exec rm -fr {} + find . -name 'pyvenv.cfg' -exec rm -fr {} + pyroma-5.0/README.rst000066400000000000000000000077541503537372600144040ustar00rootroot00000000000000pyroma ====== Pyroma rhymes with aroma, and is a product aimed at giving a rating of how well a Python project complies with the best practices of the Python packaging ecosystem, primarily PyPI, pip, Distribute etc, as well as a list of issues that could be improved. The aim of this is both to help people make a project that is nice and usable, but also to improve the quality of Python third-party software, making it easier and more enjoyable to use the vast array of available modules for Python. It's written so that there are a library with methods to call from Python, as well as a script, also called pyroma. It can be run on a project directory before making a release: $ pyroma . On a distribution before uploading it to the CheeseShop: $ pyroma pyroma-1.0.tar.gz Or you can give it a package name on CheeseShop: $ pyroma pyroma Giving it a name on CheeseShop is the most extensive test, as it will test for several things isn't otherwise tested. In all cases the output is similar:: ------------------------------ Checking . Found pyroma ------------------------------ The packages long_description is quite short. ------------------------------ Final rating: 9/10 Cottage Cheese ------------------------------ Tests ----- This is the list of checks that are currently performed: * The package should have a name, a version and a Description. If it does not, it will receive a rating of 0. * The version number should be a string. A floating point number will work with distutils, but most other tools will fail. * The version number should comply to PEP386. * The description should be over 10 characters, and the long_description should be over a 100 characters. * Pyroma will convert your long_description to HTML using Docutils, to verify that it is possible. This guarantees pretty formatting of your description on PyPI. As long as Docutils can convert it, this passes, even if there are warnings or error in the conversion. These warnings and errors are printed to stdout so you will see them. NB! Currently this doesn't change the rating, this is because Docutils no longer raises an error during this process, so I have to rewrite the test. Once it's reinstated, incorrect syntax will be fatal. * You should have the following meta data fields filled in: classifiers, keywords, author, author_email, url and license. * You should have classifiers specifying the supported Python versions. * You should have ``requires-python``/``python_requires`` specifying the Python versions you support. * You should have a classifier specifying the project license. * If you are checking on a PyPI package, and not a local directory or local package, pyroma will check the number of owners the package has on PyPI. It should be three or more, to minimize the "Bus factor", the risk of the index owners suddenly going off-line for whatever reason. * If you are checking on a PyPI package, and not a local directory or local package, pyroma will check that you have uploaded a source distribution, and not just binary distributions. Version control integration --------------------------- With `pre-commit `_, pyroma can be run whenever you commit your work by adding the following to your ``.pre-commit-config.yaml``: .. code-block:: yaml repos: - repo: https://github.com/regebro/pyroma rev: "3.2" hooks: - id: pyroma Credits ------- The project was created by Lennart Regebro, regebro@gmail.com The name "Pyroma" was coined by Wichert Akkerman, wichert@wiggy.net Contributors: * David Andreoletti * Godefroid Chapelle * Dmitry Vakhrushev * Hugo van Kemenade * Jeff Quast * Maurits van Rees * Hervé Beraud * Érico Andrei * Jakub Wilk * Andreas Lutro * Scott Colby * Andrew Murray * Nikita Sobolev * Charles Tapley Hoyt * Max Tyulin * Michael Howitz * Florian Bruhin * Christopher A.M. Gerlach * RuRo * Wesley Barroso Lopes * Alexander Bessman pyroma-5.0/README.txt000066400000000000000000000000171503537372600143740ustar00rootroot00000000000000See README.rst pyroma-5.0/pyproject.toml000066400000000000000000000001611503537372600156120ustar00rootroot00000000000000[build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.black] line-length = 120 pyroma-5.0/pyroma/000077500000000000000000000000001503537372600142075ustar00rootroot00000000000000pyroma-5.0/pyroma/__init__.py000066400000000000000000000120331503537372600163170ustar00rootroot00000000000000import logging import os import sys from argparse import ArgumentParser, ArgumentTypeError from pyroma import projectdata, distributiondata, pypidata, ratings logging.basicConfig(level=logging.DEBUG, stream=sys.stdout, format="%(message)s") def zester(data): main_files = set(os.listdir(data["workingdir"])) config_files = {"setup.py", "setup.cfg", "pyproject.toml"} # If there are no standard Python config files in the main files # it's likely not a Python project, so just return. if not config_files & main_files: return from zest.releaser.utils import ask if ask("Run pyroma on the package before tagging?"): rating = run("directory", os.path.abspath(data["workingdir"]), skip_tests="CheckManifest") if rating < 8: if not ask("Continue?"): sys.exit(1) def min_argument(arg): try: f = int(arg) except ValueError: raise ArgumentTypeError("Must be an integer between 1 and 10") if f < 0: raise ArgumentTypeError("Oh, it's not THAT bad, trust me.") if f < 1: raise ArgumentTypeError("Why run pyroma if you intend it to always pass?") if f > 10: raise ArgumentTypeError("Why run pyroma if you intend it to never pass?") return f def get_all_tests(): return [x.__class__.__name__ for x in ratings.ALL_TESTS] def parse_tests(arg): if not arg: return arg = [arg] for sep in " ,;": skips = [] for t in arg: skips.extend(t.split(sep)) arg = skips tests = get_all_tests() for skip in arg: if skip not in tests: return return skip def skip_tests(arg): test_to_skip = parse_tests(arg) if test_to_skip: return test_to_skip tests = ", ".join(get_all_tests()) message = f"Invalid tests listed. Available tests: {tests}" raise ArgumentTypeError(message) def main(): parser = ArgumentParser() parser.color = True parser.add_argument( "package", help="A python package, can be a directory, a distribution file or a PyPI package name.", ) parser.add_argument( "-n", "--min", dest="min", default=8, action="store", type=min_argument, help="Minimum rating for clean return between 1 and 10, inclusive.", ) group = parser.add_mutually_exclusive_group() group.add_argument( "-a", "--auto", dest="mode", action="store_const", const="auto", help="Select mode automatically (default)", ) group.add_argument( "-d", "--directory", dest="mode", action="store_const", const="directory", help="Run pyroma on a module in a project directory", ) group.add_argument( "-f", "--file", dest="mode", action="store_const", const="file", help="Run pyroma on a distribution file", ) group.add_argument( "-p", "--pypi", dest="mode", action="store_const", const="pypi", help="Run pyroma on a package on PyPI", ) parser.add_argument( "-q", "--quiet", dest="quiet", action="store_true", default=False, help="Output only the rating", ) parser.add_argument( "--skip-tests", type=skip_tests, help="Skip the named tests", ) args = parser.parse_args() mode = args.mode if args.mode is None or args.mode == "auto": if os.path.isdir(args.package): mode = "directory" elif os.path.isfile(args.package): mode = "file" else: mode = "pypi" rating = run(mode, args.package, args.quiet, args.skip_tests) if rating < args.min: sys.exit(2) sys.exit(0) def run(mode, argument, quiet=False, skip_tests=None): if quiet: logger = logging.getLogger() logger.disabled = True logging.info("-" * 30) logging.info("Checking " + argument) if mode == "directory": data = projectdata.get_data(os.path.abspath(argument)) logging.info("Found " + data.get("name", "nothing")) elif mode == "file": data = distributiondata.get_data(os.path.abspath(argument)) logging.info("Found " + data.get("name", "nothing")) else: # It's probably a package name data = pypidata.get_data(argument) logging.info("Found " + data.get("name", "nothing")) rating = ratings.rate(data, skip_tests) logging.info("-" * 30) for problem in rating[1]: # XXX It would be nice with a * pointlist instead, but that requires # that we know how wide the terminal is and nice word-breaks, so that's # for later. logging.info(problem) if rating[1]: logging.info("-" * 30) logging.info("Final rating: " + str(rating[0]) + "/10") logging.info(ratings.LEVELS[rating[0]]) logging.info("-" * 30) if quiet: logger.disabled = False logging.info(rating[0]) return rating[0] pyroma-5.0/pyroma/__main__.py000066400000000000000000000000731503537372600163010ustar00rootroot00000000000000from . import main if __name__ == "__main__": main() pyroma-5.0/pyroma/distributiondata.py000066400000000000000000000030261503537372600201330ustar00rootroot00000000000000""" Extract information from a distribution file by unpacking in a temporary directory and then using projectdata on that. """ import os import pathlib import shutil import tarfile import tempfile import zipfile from pyroma import projectdata def _safe_extract_tar(tar, path=".", members=None, numeric_owner=False): """Safely extract a tar w/o traversing parent dirs to fix CVE-2007-4559.""" root = pathlib.Path(path).resolve() for member in tar.getmembers(): member_path = (root / member.name).resolve() if root not in member_path.parents: raise Exception(f"Attempted path traversal in tar file {tar.name!r}") tar.extractall(path, members, numeric_owner=numeric_owner) def get_data(path): filename = os.path.split(path)[-1] basename, ext = os.path.splitext(filename) if basename.endswith(".tar"): basename, ignored = os.path.splitext(basename) tempdir = tempfile.mkdtemp() try: if ext in (".bz2", ".tbz", "tb2", ".gz", ".tgz", ".tar"): with tarfile.open(name=path, mode="r:*") as tar_file: _safe_extract_tar(tar_file, path=tempdir) elif ext in (".zip", ".egg"): with zipfile.ZipFile(path, mode="r") as zip_file: zip_file.extractall(tempdir) else: raise ValueError("Unknown file type: " + ext) projectpath = os.path.join(tempdir, basename) data = projectdata.get_build_data(projectpath) finally: shutil.rmtree(tempdir, ignore_errors=True) return data pyroma-5.0/pyroma/projectdata.py000066400000000000000000000107761503537372600170740ustar00rootroot00000000000000# Extracts information from a project import build import build.util import os import pathlib import re from setuptools.config.setupcfg import read_configuration from distutils.errors import DistutilsFileError # MAP from old setup.py type keys to Core Metadata keys METADATA_MAP = { "description": "summary", "classifiers": "classifier", "project-urls": "project-url", "url": "home-page", "long-description": "description", "long-description-content-type": "description-content-type", "python-requires": "requires-python", } def normalize(name): return re.sub(r"[-_.]+", "-", name).lower() def wheel_metadata(path, isolated=None): # If explictly specified whether to use isolation, pass it directly if isolated is not None: return build.util.project_wheel_metadata(path, isolated=isolated) # Otherwise, try without build isolation first for efficiency try: return build.util.project_wheel_metadata(path, isolated=False) # If building with build isolation fails, e.g. missing build deps, try with it except (build.BuildException, build.BuildBackendException): return build.util.project_wheel_metadata(path, isolated=True) def build_metadata(path, isolated=None): try: metadata = wheel_metadata(path, isolated) except build.BuildBackendException: # The backend failed spectacularily. This happens with old packages, # when we can't build a wheel. It's not always a fatal error. F ex, if # you are getting info for a package from PyPI, we already have the # metadata from PyPI, we just couldn't get the additional build data. return {"_wheel_build_failed": True} # As far as I can tell, we can't trust that the builders normalize the keys, # so we do it here. Definitely most builders do not lower case them, which # Core Metadata Specs recommend. data = {} for key in set(metadata.keys()): value = metadata.get_all(key) key = normalize(key) if len(value) == 1: value = value[0] if value.strip() == "UNKNOWN": # XXX This is also old behavior that may not hjappen any more. continue data[key] = value if "description" not in data.keys(): # XXX I *think* having the description as a payload doesn't happen anymore, but I haven't checked. # Having the description as a payload tends to add two newlines, we clean that up here: description = metadata.get_payload().strip() if description: data["description"] = description + "\n" return data def get_build_data(path, isolated=None): metadata = build_metadata(path, isolated=isolated) # Check if there is a pyproject_toml if "pyproject.toml" not in os.listdir(path): metadata["_missing_pyproject_toml"] = True return metadata def get_setupcfg_data(path): data = read_configuration(str(pathlib.Path(path) / "setup.cfg")) metadata = {} # Python requires is under "options" in setup.cfg (and so are other # requirements, but those are optional and have no tests) if "python_requires" in data["options"]: metadata["requires-python"] = data["options"]["python_requires"] for key, value in data["metadata"].items(): key = normalize(key) if key in METADATA_MAP: key = METADATA_MAP[key] metadata[key] = value return metadata def get_data(path): data = _get_data(path) if data: # We got something, add the path to it. data["_path"] = path return data def _get_data(path): try: return get_build_data(path) except build.BuildException as e: if "no pyproject.toml or setup.py" in e.args[0]: # It couldn't build the package, because there is no setup.py or pyproject.toml. # Let's see if there is a setup.cfg: try: metadata = get_setupcfg_data(path) # Yes, there's a setup.cfg. Pyroma accepted this earlier, because it worked, # and at some point the idea was that that setup.cfg should replace setup.py. # But that never happened, and instead pyproject.toml arrived. metadata["_missing_build_system"] = True return metadata except DistutilsFileError: # There is no setup.cfg either, so this isn't a python package at all return {"_no_config_found": True} else: # There's something else wrong raise e pyroma-5.0/pyroma/pypidata.py000066400000000000000000000050741503537372600164020ustar00rootroot00000000000000import logging import os import re import requests import tempfile import xmlrpc.client from pyroma import distributiondata # MAP from old PyPI `info` keys to Core Metadata keys INFO_MAP = { "classifiers": "classifier", "project-urls": "project-url", "project-url": "home-page", } def normalize(name): return re.sub(r"[-_.]+", "-", name).lower() def _get_project_data(project): # I think I should be able to monkeypatch a mock-thingy here... I think. response = requests.get(f"https://pypi.org/pypi/{project}/json") if response.status_code == 404: raise ValueError(f"Did not find '{project}' on PyPI. Did you misspell it?") if not response.ok: raise ValueError(f"Unknown http error: {response.status_code} {response.reason}") return response.json() def get_data(project): # Pick the latest release. project_data = _get_project_data(project) releases = project_data["releases"] data = {} for key, value in project_data["info"].items(): key = normalize(key) if key in INFO_MAP: key = INFO_MAP[key] data[key] = value release = data["version"] logging.debug(f"Found {project} version {release}") with xmlrpc.client.ServerProxy("https://pypi.org/pypi") as xmlrpc_client: roles = xmlrpc_client.package_roles(project) data["_owners"] = [user for (role, user) in roles if role == "Owner"] # Get download_urls: urls = releases[release] data["_pypi_downloads"] = bool(urls) # If there is a source download, download it, and get that data. # This is done mostly to do the imports check. data["_source_download"] = False data["_has_sdist"] = False for download in urls: if download["packagetype"] == "sdist": # Found a source distribution. Download and analyze it. data["_has_sdist"] = True tempdir = tempfile.gettempdir() filename = download["url"].split("/")[-1] tmp = os.path.join(tempdir, filename) logging.debug(f"Downloading {filename} to verify distribution") try: with open(tmp, "wb") as outfile: outfile.write(requests.get(download["url"]).content) ddata = distributiondata.get_data(tmp) except Exception: # Clean up the file os.unlink(tmp) raise # Combine them, with the PyPI data winning: ddata.update(data) data = ddata data["_source_download"] = True break return data pyroma-5.0/pyroma/ratings.py000066400000000000000000000424461503537372600162420ustar00rootroot00000000000000# This is a collection of "tests" done on the package data. The resut of the # tests is used to give the package a rating. # # Each test has a couple of attributes. Both attributes are checked only after # the test is performed so the test can choose to set the attributes dependning # on the severity of the failure. # # fatal: If set to True, the failure of this test will cause the # package to achieve the rating of 1, which is minimum # weight: The relative importance of the test. # If the test has fatal set to True this is ignored. # # Tests have two methods: # test(data): Performs the test on the given data. Returns True for pass # False for fail and None for not applicable (meaning it will # not be counted). import io import re from collections import defaultdict from docutils.core import publish_parts from docutils.utils import SystemMessage from trove_classifiers import classifiers as CLASSIFIERS from packaging.specifiers import InvalidSpecifier, SpecifierSet LEVELS = [ "This cheese seems to contain no dairy products", "Vieux Bologne", "Limburger", "Gorgonzola", "Stilton", "Brie", "Comté", "Jarlsberg", "Philadelphia", "Cottage Cheese", "Your cheese is so fresh most people think it's a cream: Mascarpone", ] SHORT_NAME_RE = re.compile(r"\(.*?\)") def get_code_licenses(): licenses = [each for each in list(CLASSIFIERS) if each.startswith("License")] code_map = defaultdict(set) for license in licenses: short_name = SHORT_NAME_RE.findall(license) if short_name: short_name = short_name[0][1:-1] code_map[short_name].add(license) if short_name.startswith("GPL"): code_map["GPL"].add(license) elif short_name.startswith("LGPL"): code_map["LGPL"].add(license) elif "Zope" in license: code_map["ZPL"].add(license) elif "MIT License" in license: code_map["MIT"].add(license) return code_map CODE_LICENSES = get_code_licenses() class BaseTest: fatal = False class FieldTest(BaseTest): """Tests that a specific field is in the data and is not empty or False""" def test(self, data): return bool(data.get(self.field)) def message(self): return (f"Your package does not have {self.field} data") + (self.fatal and "!" or ".") class Name(FieldTest): fatal = True field = "name" class Version(FieldTest): fatal = True field = "version" class VersionIsString(BaseTest): weight = 50 def test(self, data): # Check that the version is a string version = data.get("version") return isinstance(version, str) def message(self): return "The version number should be a string." PEP386_RE = re.compile( r""" ^ (?P\d+\.\d+) # minimum 'N.N' (?P(?:\.\d+)*) # any number of extra '.N' segments (?: (?P[abc]|rc) # 'a'=alpha, 'b'=beta, 'c'=release candidate # 'rc'= alias for release candidate (?P\d+(?:\.\d+)*) )? (?P(\.post(?P\d+))?(\.dev(?P\d+))?)? $""", re.VERBOSE | re.IGNORECASE, ) PEP440_RE = re.compile( r"""^ v? (?: (?:(?P[0-9]+)!)? # epoch (?P[0-9]+(?:\.[0-9]+)*) # release segment (?P
                                          # pre-release
            [-_\.]?
            (?P(a|b|c|rc|alpha|beta|pre|preview))
            [-_\.]?
            (?P[0-9]+)?
        )?
        (?P                                         # post release
            (?:-(?P[0-9]+))
            |
            (?:
                [-_\.]?
                (?Ppost|rev|r)
                [-_\.]?
                (?P[0-9]+)?
            )
        )?
        (?P                                          # dev release
            [-_\.]?
            (?Pdev)
            [-_\.]?
            (?P[0-9]+)?
        )?
    )
    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
$""",
    re.VERBOSE | re.IGNORECASE,
)


class PEPVersion(BaseTest):
    weight = 50
    pep386 = False

    def test(self, data):
        # Check that the version number complies to PEP-386:
        version = data.get("version")
        self.pep386 = False
        if PEP386_RE.search(str(version)) is not None:
            # Matches the old PEP386
            self.weight = 10
            self.pep386 = True
        match = PEP440_RE.search(str(version))
        return match is not None

    def message(self):
        if self.pep386:
            return "The package's version number complies only with PEP-386 and not PEP-440."
        return "The package's version number does not comply with PEP-386 or PEP-440."


class Summary(BaseTest):
    weight = 100

    def test(self, data):
        summary = data.get("summary")
        if not summary:
            # No description at all. That's fatal.
            self.fatal = True
            return False
        self.fatal = False
        return len(summary) > 10

    def message(self):
        if self.fatal:
            return "The package had no Summary!"
        else:
            return "The package's Summary should be longer than 10 characters."


class Description(BaseTest):
    weight = 50

    def test(self, data):
        description = data.get("description", "")
        if not isinstance(description, str):
            description = ""
        return len(description) > 100

    def message(self):
        return "The package's Description is quite short."


class Classifiers(FieldTest):
    weight = 100
    field = "classifier"


class ClassifierVerification(BaseTest):
    weight = 20

    def test(self, data):
        self._incorrect = []
        classifiers = data.get("classifier", [])
        for classifier in classifiers:
            if classifier not in CLASSIFIERS and not classifier.startswith("Private :: "):
                self._incorrect.append(classifier)
        if self._incorrect:
            return False
        return True

    def message(self):
        err = "\n".join(self._incorrect)
        return "Some of your classifiers are not standard classifiers:\n" + err


class PythonClassifierVersion(BaseTest):
    def test(self, data):
        self._major_version_specified = False

        classifiers = data.get("classifier", [])
        for classifier in classifiers:
            parts = [p.strip() for p in classifier.split("::")]
            if parts[0] == "Programming Language" and parts[1] == "Python":
                if len(parts) == 2:
                    # Specified Python, but no version.
                    continue
                version = parts[2]
                try:
                    float(version)
                except ValueError:
                    # Not a proper Python version
                    continue
                try:
                    int(version)
                except ValueError:
                    # It's a valid float, but not a valid int. Hence it's
                    # something like "2.7" or "3.3" but not just "2" or "3".
                    # This is a good specification, and we only need one.
                    # Set weight to 100 and finish.
                    self.weight = 100
                    return True

                # It's a valid int, meaning it specified "2" or "3".
                self._major_version_specified = True

        # There was some sort of failure:
        if self._major_version_specified:
            # Python 2 or 3 was specified but no more detail than that:
            self.weight = 25
        else:
            # No Python version specified at all:
            self.weight = 100
        return False

    def message(self):
        if self._major_version_specified:
            return (
                "The classifiers should specify what minor versions of "
                "Python you support as well as what major version."
            )
        return "The classifiers should specify what Python versions you support."


class PythonRequiresVersion(BaseTest):
    weight = 100

    def test(self, data):
        # https://github.com/regebro/pyroma/pull/83#discussion_r955611236
        python_requires = data.get("requires-python", None)

        if not python_requires:
            return False

        try:
            SpecifierSet(python_requires)
        except InvalidSpecifier:
            return False

        return True

    def message(self):
        return "You should specify what Python versions you support with " "the 'Requires-Python' metadata."


class Keywords(FieldTest):
    weight = 20
    field = "keywords"


class Author(FieldTest):
    weight = 100
    field = "author"

    def test(self, data):
        """Check if author-email field contains author name."""
        email = data.get("author-email")
        # Pass if author name in email, e.g. "Author Name "
        return True if email and "<" in email else super().test(data)


class AuthorEmail(FieldTest):
    weight = 100
    field = "author-email"


class Url(BaseTest):
    weight = 20

    def test(self, data):
        return bool(data.get("home-page")) or bool(data.get("project-url"))

    def message(self):
        return (
            "Your package should have a 'url' field with a link to the "
            "project home page, or a 'project_urls' field, with a "
            "dictionary of links, or both."
        )


class Licensing(BaseTest):
    weight = 50

    def test(self, data):
        license = data.get("license")
        license_expression = data.get("license-expression")
        classifiers = data.get("classifier", [])
        licenses = set()
        for classifier in classifiers:
            parts = [p.strip() for p in classifier.split("::")]
            if parts[0] == "License":
                # license classifiers exist
                licenses.add(classifier)

        if not license and not license_expression and not licenses:
            self._message = "Your package does neither have a license field nor any license classifiers."
            return False

        if license and license_expression:
            self._message = (
                "Specifying both a License and a License-Expression is ambiguous, deprecated, "
                "and may be rejected by package indices."
            )
            return False

        if license_expression and licenses:
            self._message = (
                "Specifying both a License-Expression and license classifiers is ambiguous, deprecated, "
                "and may be rejected by package indices."
            )
            return False

        if license in CODE_LICENSES:
            if not CODE_LICENSES[license].intersection(licenses):
                self._message = f"The license '{license}' specified is not listed in your classifiers."
                return False

        return True

    def message(self):
        return self._message


class DevStatusClassifier(BaseTest):
    weight = 20

    def test(self, data):
        classifiers = data.get("classifier", [])
        for classifier in classifiers:
            parts = [p.strip() for p in classifier.split("::")]
            if parts[0] == "Development Status":
                # license classifier exist
                return True
        return False

    def message(self):
        return "Specifying a development status in the classifiers gives users a hint of how stable your software is."


class SDist(BaseTest):
    weight = 100

    def test(self, data):
        if "_has_sdist" not in data:
            # We aren't checking on PyPI
            self.weight = 0
            return None
        return data["_has_sdist"]

    def message(self):
        return (
            "You have no source distribution on the Cheeseshop. "
            "Uploading the source distribution to the Cheeseshop ensures "
            "maximum availability of your package."
        )


class ValidREST(BaseTest):
    weight = 50

    def test(self, data):
        content_type = data.get("description-content-type", None)
        if content_type in ("text/plain", "text/markdown"):
            # These can't fail. Markdown will just assume everything
            # it doesn't understand is plain text.
            return True

        # This should be ReStructuredText
        source = data.get("description", "")
        stream = io.StringIO()
        settings = {"warning_stream": stream}

        try:
            publish_parts(source=source, writer_name="html4css1", settings_overrides=settings)
        except SystemMessage as e:
            self._message = e.args[0]
        errors = stream.getvalue().strip()
        if not errors:
            return True

        self._message = "\n" + errors
        return False

    def message(self):
        return "Your Description is not valid ReST: " + self._message


class BusFactor(BaseTest):
    def test(self, data):
        if "_owners" not in data:
            self.weight = 0
            return None

        if len(data.get("_owners", [])) == 1:
            self.weight = 100
            return False

        if len(data.get("_owners", [])) == 2:
            self.weight = 50
            return False

        # Three or more, that's good.
        self.weight = 100
        return True

    def message(self):
        return "You should have three or more owners of the project on PyPI."


class MissingBuildSystem(BaseTest):
    def test(self, data):
        if "_missing_build_system" in data:
            # These sort of "negative only/deprecation" ratings only give you negative weight
            self.weight = 400
            return False

    def message(self):
        return (
            "You seem to neither have a setup.py, nor a pyproject.toml, only setup.cfg.\n"
            "This makes it unclear how your project should be built, and some packaging tools may fail."
        )


class MissingPyProjectToml(BaseTest):
    def test(self, data):
        if "_missing_build_system" in data or "_missing_pyproject_toml" in data:
            # These sort of "negative only/deprecation" ratings only give you negative weight
            self.weight = 100
            return False

    def message(self):
        return (
            "Your project does not have a pyproject.toml file, which is highly recommended.\n"
            "You probably want to create one with the following configuration:\n\n"
            "    [build-system]\n"
            '    requires = ["setuptools>=42"]\n'
            '    build-backend = "setuptools.build_meta"\n'
        )


ALL_TESTS = [
    MissingBuildSystem(),
    MissingPyProjectToml(),
    Name(),
    Version(),
    VersionIsString(),
    PEPVersion(),
    Summary(),
    Description(),
    Classifiers(),
    ClassifierVerification(),
    PythonClassifierVersion(),
    PythonRequiresVersion(),
    Keywords(),
    Author(),
    AuthorEmail(),
    Url(),
    Licensing(),
    SDist(),
    ValidREST(),
    BusFactor(),
    DevStatusClassifier(),
]

try:
    import check_manifest

    class CheckManifest(BaseTest):
        weight = 0

        def test(self, data):
            if "_path" not in data:
                return None

            self.weight = 200
            try:
                return check_manifest.check_manifest(data["_path"])
            except check_manifest.Failure:
                # Most likely this means check-manifest didn't find any
                # package configuration, which is the same failure as
                # MissingBuildSystem, so this is double errors, but
                # it does mean your setup is completely broken, so...
                return False

        def message(self):
            return "Check-manifest returned errors"

    ALL_TESTS.append(CheckManifest())

except ImportError:
    pass


def rate(data, skip_tests=None):
    if len([key for key in data if not key.startswith("_")]) == 0:
        if "_no_config_found" in data:
            # Are you in the correct directory?:
            return (0, ["I couldn't find any package data. Are checking the correct directory or file?"])

        if "_wheel_build_failed" in data:
            return (
                0,
                [
                    "Pyroma failed to build your packages wheel metadata, which indicates an error with "
                    "your build configuration, like you not having a pyproject.toml file, or it being faulty.\n"
                    "Running `python -m build` in your package directory may give more information."
                ],
            )

    if skip_tests is None:
        skip_tests = []

    fails = []
    good = 0
    bad = 0
    fatality = False
    for test in ALL_TESTS:
        if test.__class__.__name__ in skip_tests:
            continue
        res = test.test(data)
        if res is False:
            fails.append(test.message())
            if test.fatal:
                fatality = True
            else:
                bad += test.weight
        elif res is True:
            if not test.fatal:
                good += test.weight
    # If res is None, it's ignored.
    if fatality:
        # A fatal test failed. That means we give a 0 rating:
        return 0, fails
    # Multiply good by 9, and add 1 to get a rating between
    # 1: All non-fatal tests failed.
    # 10: All tests succeeded.
    return (good * 9) // (good + bad) + 1, fails
pyroma-5.0/pyroma/testdata/000077500000000000000000000000001503537372600160205ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/complete/000077500000000000000000000000001503537372600176305ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/complete/README.txt000066400000000000000000000024461503537372600213340ustar00rootroot00000000000000Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
pyroma-5.0/pyroma/testdata/complete/complete/000077500000000000000000000000001503537372600214405ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/complete/complete/__init__.py000066400000000000000000000000731503537372600235510ustar00rootroot00000000000000import zope.event

# Stop pyflakes complaining:
zope.event
pyroma-5.0/pyroma/testdata/complete/complete/tests.py000066400000000000000000000002131503537372600231500ustar00rootroot00000000000000import unittest


class PackageDataTest(unittest.TestCase):
    def test_test(self):
        # Stop pyflakes from compaining:
        pass
pyroma-5.0/pyroma/testdata/complete/pyproject.toml000066400000000000000000000000371503537372600225440ustar00rootroot00000000000000[tool.black]
line-length = 120
pyroma-5.0/pyroma/testdata/complete/setup.cfg000066400000000000000000000000661503537372600214530ustar00rootroot00000000000000[egg_info]
tag_build = .dev1
tag_svn_revision = false
pyroma-5.0/pyroma/testdata/complete/setup.py000066400000000000000000000022641503537372600213460ustar00rootroot00000000000000from setuptools import setup, find_packages

version = "1.0"

with open("README.txt", encoding="UTF-8") as readme:
    long_description = readme.read()

setup(
    name="complete",
    version=version,
    description="This is a test package for pyroma.",
    long_description=long_description,
    python_requires=">=2.6",
    classifiers=[
        "Development Status :: 6 - Mature",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 2.6",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3.1",
        "Programming Language :: Python :: 3.2",
        "Programming Language :: Python :: 3.3",
        "License :: OSI Approved :: MIT License",
    ],
    keywords=["pypi", "quality", "example"],
    author="Lennart Regebro",
    author_email="regebro@gmail.com",
    url="https://github.com/regebro/pyroma",
    project_urls={"Source Code": "https://github.com/regebro/pyroma"},
    license="MIT",
    packages=find_packages(exclude=["ez_setup", "examples", "tests"]),
    include_package_data=True,
    install_requires=["zope.event"],
    tests_require=["six"],
    setup_requires=["setuptools"],
    zip_safe=True,
)
pyroma-5.0/pyroma/testdata/custom_test/000077500000000000000000000000001503537372600203715ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/custom_test/minimal/000077500000000000000000000000001503537372600220175ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/custom_test/minimal/__init__.py000066400000000000000000000000001503537372600241160ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/custom_test/pyproject.toml000066400000000000000000000000371503537372600233050ustar00rootroot00000000000000[tool.black]
line-length = 120
pyroma-5.0/pyroma/testdata/custom_test/setup.cfg000066400000000000000000000000651503537372600222130ustar00rootroot00000000000000[egg_info]
tag_build = .dev1
tag_svn_revision = true
pyroma-5.0/pyroma/testdata/custom_test/setup.py000066400000000000000000000011071503537372600221020ustar00rootroot00000000000000from setuptools import setup, find_packages
from setuptools.command.test import test

version = "0.0.1"


class CustomTest(test):
    pass


setup(
    name="minimal",
    version=version,
    description="Test",
    classifiers=[],
    keywords="",
    author="",
    author_email="",
    url="",
    license="",
    packages=find_packages(exclude=["ez_setup", "examples", "tests"]),
    include_package_data=True,
    install_requires=[
        # -*- Extra requirements: -*-
    ],
    entry_points="""
      # -*- Entry points: -*-
      """,
    cmdclass={"test": CustomTest},
)
pyroma-5.0/pyroma/testdata/distributions/000077500000000000000000000000001503537372600207225ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/distributions/complete-1.0.dev1.tar000066400000000000000000001200001503537372600243650ustar00rootroot00000000000000././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751815675.1635697
complete-1.0.dev1/0000775000175000017500000000000015032512773014253 5ustar00lregebrolregebro././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751815675.1635697
complete-1.0.dev1/PKG-INFO0000644000175000017500000000402115032512773015343 0ustar00lregebrolregebroMetadata-Version: 2.1
Name: complete
Version: 1.0.dev1
Summary: This is a test package for pyroma.
Home-page: https://github.com/regebro/pyroma
Author: Lennart Regebro
Author-email: regebro@gmail.com
License: MIT
Project-URL: Source Code, https://github.com/regebro/pyroma
Keywords: pypi,quality,example
Classifier: Development Status :: 6 - Mature
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=2.6
Requires-Dist: zope.event

Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1669279713.0
complete-1.0.dev1/README.txt0000664000175000017500000000244614337627741015770 0ustar00lregebrolregebroComplete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751815675.1625695
complete-1.0.dev1/complete/0000775000175000017500000000000015032512773016063 5ustar00lregebrolregebro././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1669279713.0
complete-1.0.dev1/complete/__init__.py0000664000175000017500000000007314337627741020205 0ustar00lregebrolregebroimport zope.event

# Stop pyflakes complaining:
zope.event
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1669279713.0
complete-1.0.dev1/complete/tests.py0000664000175000017500000000021314337627741017604 0ustar00lregebrolregebroimport unittest


class PackageDataTest(unittest.TestCase):
    def test_test(self):
        # Stop pyflakes from compaining:
        pass
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751815675.1635697
complete-1.0.dev1/complete.egg-info/0000775000175000017500000000000015032512773017555 5ustar00lregebrolregebro././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751815675.0
complete-1.0.dev1/complete.egg-info/PKG-INFO0000644000175000017500000000402115032512773020645 0ustar00lregebrolregebroMetadata-Version: 2.1
Name: complete
Version: 1.0.dev1
Summary: This is a test package for pyroma.
Home-page: https://github.com/regebro/pyroma
Author: Lennart Regebro
Author-email: regebro@gmail.com
License: MIT
Project-URL: Source Code, https://github.com/regebro/pyroma
Keywords: pypi,quality,example
Classifier: Development Status :: 6 - Mature
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=2.6
Requires-Dist: zope.event

Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751815675.0
complete-1.0.dev1/complete.egg-info/SOURCES.txt0000664000175000017500000000041515032512773021441 0ustar00lregebrolregebroREADME.txt
pyproject.toml
setup.cfg
setup.py
complete/__init__.py
complete/tests.py
complete.egg-info/PKG-INFO
complete.egg-info/SOURCES.txt
complete.egg-info/dependency_links.txt
complete.egg-info/requires.txt
complete.egg-info/top_level.txt
complete.egg-info/zip-safe././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751815675.0
complete-1.0.dev1/complete.egg-info/dependency_links.txt0000664000175000017500000000000115032512773023623 0ustar00lregebrolregebro
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751815675.0
complete-1.0.dev1/complete.egg-info/requires.txt0000664000175000017500000000001315032512773022147 0ustar00lregebrolregebrozope.event
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751815675.0
complete-1.0.dev1/complete.egg-info/top_level.txt0000664000175000017500000000001115032512773022277 0ustar00lregebrolregebrocomplete
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1682843648.0
complete-1.0.dev1/complete.egg-info/zip-safe0000664000175000017500000000000114423424000021171 0ustar00lregebrolregebro
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751446426.0
complete-1.0.dev1/pyproject.toml0000664000175000017500000000003715031171632017161 0ustar00lregebrolregebro[tool.black]
line-length = 120
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751815675.1635697
complete-1.0.dev1/setup.cfg0000664000175000017500000000010415032512773016067 0ustar00lregebrolregebro[egg_info]
tag_build = .dev1
tag_svn_revision = false
tag_date = 0

././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1669280970.0
complete-1.0.dev1/setup.py0000664000175000017500000000226414337632312015770 0ustar00lregebrolregebrofrom setuptools import setup, find_packages

version = "1.0"

with open("README.txt", encoding="UTF-8") as readme:
    long_description = readme.read()

setup(
    name="complete",
    version=version,
    description="This is a test package for pyroma.",
    long_description=long_description,
    python_requires=">=2.6",
    classifiers=[
        "Development Status :: 6 - Mature",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 2.6",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3.1",
        "Programming Language :: Python :: 3.2",
        "Programming Language :: Python :: 3.3",
        "License :: OSI Approved :: MIT License",
    ],
    keywords=["pypi", "quality", "example"],
    author="Lennart Regebro",
    author_email="regebro@gmail.com",
    url="https://github.com/regebro/pyroma",
    project_urls={"Source Code": "https://github.com/regebro/pyroma"},
    license="MIT",
    packages=find_packages(exclude=["ez_setup", "examples", "tests"]),
    include_package_data=True,
    install_requires=["zope.event"],
    tests_require=["six"],
    setup_requires=["setuptools"],
    zip_safe=True,
)
pyroma-5.0/pyroma/testdata/distributions/complete-1.0.dev1.tar.bz2000066400000000000000000000051711503537372600250740ustar00rootroot00000000000000BZh91AY&SY36ϐXgo  `
|ɴQEBR)POjF!Ȇzɦ@d@4i hM42  bM@2id4
hDCA04Кd3BzSf#z)́54Ҟ	4fDzMd&4h(;OF쥕uNT7E@ #U<=_2#p 4 4R[@͸Cmd1rgmN@+2!o5w:ĩr_ȵBσ	?'s~2N
:C
6>#BY#ӰIL<6sCOg:
pux|KAɥъý^g#B<
9Z&áY6I$)G
Isn;zajk՘9S
;هV0[v}-2EÖNXaH@ن\7nͣ,?cЗ9\nW΁xw\nÓãVe[rof͜+0Bh(\Hs"^z[N$]IL"5)H1@*Ahl`-Mr~jrӅkICG^0"#7D6J`p^H89mo&q6&w4vH*d$ZH$13`%fE-.IJFXơRq'	DRd#tk7mQ7ABM	
R;g!վ"Gte ~WH ̍N9@;i;4Ho~Eއ
:ćRu08܎A}mL0>I8tz
 y 8" ?qBbobpUfu$U+)m׊3W+ڔ@]mǙ"L[QɽpCloSrH`Uz	l6o:ոju~4~%a@Sk1\0;Gq2z5zGzS
xQ
&2z+n\		t@1H""^*o`uHh4hBM&kbe!‘B5Gn4`fę6
xZdmlfa6snջz
ol@R0A2=lLP5Ca~FC}y5oI`͆?>CCd	ZIer287Au8|B1^I2^HjcЯ)Q39(,H`1ղ**#$(T 0	P"[wцI )Ȇ*h,;}P(<7zЫ--ÇT,J4C!0+FP~Mb>Be
913_4>vCPzƍzUjɢ0w:?.I3k/;!8es~hQ]fANCxXܚ(0ի*BY4pMj0-FFXa,֌K#
w6xd
O9FЪѫ6@)55iD׌:2hJ}-YiF,42Mx!C"lل05*h%7uD<n(ް00{Qa&ttr,	F8&$09a3+WZŘ~@ްid)	9y^,QõK?9RZ9eӅ1ͅYK*8jzp,J5xQ0e&9rLL?OWy%R^h9Sxj߽Ҫge{h/RezD7ˤ0=~Ŝ03ɴ3˲yaaj:ӄkV\1#9=ֆ9=-2^q(;taXX1NPoccta9H69OJK0]2yBqoJӿODVmsYq	Ku}cdtR!Hz]u`UK++6Ʃztew;[zµeJ#K٣"pt,J
̂)WVҞ򂳂RJ
c3QRZ:+j)Ԧx
n7Y[ÒAEY%xUq\rX;HGDu
ɜVCZ{l
ài`z`=S`HNjMёNE$bQ.ήEvf2BL}eT",*֧8@$,Gkt]SsȲdJ@j+yCwv
u&0~m^蝆;)6X81(j]o3&C7d%ˡf]檕5ȈZ.sF毵cjSYІ02'q&_{Opt2
"#߽x\[0 Q84B"t)Bq:E}/&'CwA ? :'L~u]nl'=7eEdɪ.1`DAGGGkG}(Ĉ{Ozn	!ۋGϚ-ϙapcݯgL'cB2>Lǡr&8$1Se^?NtOcUh(fCn뿣p?o=GO|/v\?M1rQ##?{qa\#|BSGGG8N0A
jߡ~w >d駏D%/fA'4q"@cW 27|>u<a2oN;zYL_
fLj^'dxp2a_aiM(=Rriӣ3Qd6&d@]8.
uDl״pҭ]yW}',ڻR'bؼ׬K=h-MYj!EPO%#Q‰*ݭE0B%hcN+E;bdרMep2܅4Ltਣ}
~D`4q"MԠd0)`V,xR+&rz!E10М1m
W镧̍Y
t;MgHD0vAyK0~kԀfɺ)mE!+.*`gf8(pYm9ޑ+ZVib꥝{EݚfhC=/^'Q:]]9ad[54rgF?ɿ}9vcR=$7qkLq2?PK/QxUz#complete-1.0.dev1/setup.pyTQk0~8@-t#vHhiRj_Jrd$SIw|58ZWdme+̈EdI;O$y~
ڠm귞UJ~/}cC,IUZY.Nsa`Ђ\צBlc,xtb̎ih`fZe_iq_WQ#sr%)Znp65*/|`2+89lL3hb<y**\1ҊPer#}e4iTũcLvµ1Vot	O7m-쌤d߅-nEh+-g3TJ<`Vcog(1ƒsq	iw"ψ;[?ulP[˜3*Cǖ7US UY;dGepaűa'#UBxT<==)=kjCwoQK9x0PK{Z%complete-1.0.dev1/PKG-INFOTNF}ﯨJFA((K;7J}q|}N򒀐5mWթ:uNqF)K]v<\\X=;
Oj[iɄMs?iŧ/&@RbRY=?pDZ!
tTa߰bZ~ܷc+nedqwYݧe@Ptw_鯐LkVSt#C]Y5OlCtm.50{uI{>®~ҍ7_^c}ε['ۯ3c;hox*c
]ƘĦg_$Λ@?|h<\;D&r)rХEch:艑l̅Žj%ސ9PzP>j
1$>09M\uYʱ%M[;gEwY
C`c,6%kj{ڢR)RBȃt^๖n)®~ҍ7_^c}ε['ۯ3c;hox*c
]ƘĦg_$Λ@?|h<\;D&r)rХEch:艑l̅Žj%ސ9PzP>j
1$>09M\uYʱ%M[;gEwY
C`c,6%kj{ڢR)RBȃt^๖n) which\n\n  - corrects the typo in  ML_DIR\n\n  - fixes the TMPFILE_XSLT/TMPFILE_XSL typo\n\n  - makes sure the files are XML or SGML files, else prints an error\n\n  - adds various missing quotes around filenames which could have\n    spaces or begin with a hyphen\n\n  - fixes typos in the usage() function\n\n  Thanks a lot, Bastian.\n\n- Fixed some problems in the xmlrev.xslt stylesheet\n\n- Fixed problems in xmlrev caused by the exit status of complete when\n  successful\n\n- Added a man page for complete and xmlrev\n\n\n0.6.5 (2004-09-02)\n------------------\n\n- xmlrev bugfixes\n\n- Fixed packaging problems (missing xsl stylesheets and MANIFEST file)\n\n\n0.6.4 (2003-10-02)\n------------------\n\n- fix recursive mode\n\n- rewrite regression test, add test for the recursive mode\n\n- add --help option to xlmrev\n\n- packaging fixes\n\n- turn API.txt and HELP.txt to correct ReST\n\n\n0.6.3 (2002-11-06)\n------------------\n\n- fix wrong xpath for attributes\n\n- fix bug with temporary duplicate attribute node\n\n- fix for xupdate\n\n- fix ext_pes option bug\n\n- update changelog to new format\n\n\n0.6.2 (2002-09-23)\n------------------\n\n- return number of differences on command line\n\n- reintroduce misc.list_print which caused recursive mode\n  to fail\n\n- use psyco if available (http://psyco.sf.net)\n\n- little changes in C extension\n\n\n0.6.1 (2002-08-29)\n------------------\n\n- fix packaging problems\n\n\n0.6.0 (2002-08-23)\n------------------\n\n- change of the internal representation\n\n- remove support for the EZS algorithm (no more maintened\n  for the moment)\n\n- add command line options to parse html and to control\n  entities inclusion and output encoding\n\n- fixing coalescing text nodes bug\n\n- many other bugs fixes\n\n- great speed improvement\n\n\n0.5.3 (2002-01-31)\n------------------\n\n- add __init__.py in \"logilab\" directory\n\n\n0.5.2 (2001-10-29)\n------------------\n\n- bug fixes in xupdate formatting and in the dom interface.\n\n\n0.5.1 (2001-09-07)\n------------------\n\n- Fast Match / Edit Scritp algorithm, now fully usable\n\n- fixes Unicode problem\n\n\n0.2.1 (2001-08-10)\n------------------\n\n- bug fixes, optimizations for ezs algorithm\n\n\n0.1.1 (2001-08-04)\n------------------\n\n- original revision","description_content_type":"","docs_url":null,"download_url":"","downloads":{"last_day":-1,"last_month":-1,"last_week":-1},"home_page":"https://github.com/Shoobx/complete","keywords":"xml,diff,complete,tree 2 tree","license":"LGPL","maintainer":"","maintainer_email":"","name":"complete","package_url":"https://pypi.org/project/complete/","platform":"","project_url":"https://pypi.org/project/complete/","project_urls":{"Homepage":"https://github.com/Shoobx/complete"},"release_url":"https://pypi.org/project/complete/1.1.0/","requires_dist":null,"requires_python": ">=2.7","summary":"Tree 2 tree correction between xml documents. Extract differences between two xml files. It returns a set of primitives to apply on source tree to obtain the destination tree.","version":"1.1.0","yanked":false,"yanked_reason":null},"last_serial":5948813,"releases":{"0.6.10":[{"comment_text":"","digests":{"md5":"9ab11f838f7e0b1dcadc94bb81eb1539","sha256":"edeb13ae5d2cc1de72b58bc989f10dc006db5acc19d42f4b05309b14bc99bbe0"},"downloads":-1,"filename":"complete-0.6.10.zip","has_sig":false,"md5_digest":"9ab11f838f7e0b1dcadc94bb81eb1539","packagetype":"sdist","python_version":"source","requires_python":null,"size":44447,"upload_time":"2015-04-02T16:07:22","upload_time_iso_8601":"2015-04-02T16:07:22.450850Z","url":"https://files.pythonhosted.org/packages/01/5c/e10197f6b699497bbbb32baa73a7b85b4be4f0117c8dae3d525ff5451987/complete-0.6.10.zip","yanked":false,"yanked_reason":null}],"0.6.4":[{"comment_text":"","digests":{"md5":"65c173fb5adcdce1008ab3a9a39ae6bd","sha256":"678042e7d8fc249f6ae78bc5f26847b1da7705ec887dce63e01a2348bfab0664"},"downloads":-1,"filename":"complete-0.6.4.tar.gz","has_sig":false,"md5_digest":"65c173fb5adcdce1008ab3a9a39ae6bd","packagetype":"sdist","python_version":"source","requires_python":null,"size":28540,"upload_time":"2015-04-02T15:37:18","upload_time_iso_8601":"2015-04-02T15:37:18.791051Z","url":"https://files.pythonhosted.org/packages/78/be/25e4c3b6e295205adcc102c72d3c182366e9adc0a42c9c641b14a710dc3c/complete-0.6.4.tar.gz","yanked":false,"yanked_reason":null}],"0.6.6":[{"comment_text":"","digests":{"md5":"b4461fcf85dbcef9d2dc3f712445f1ae","sha256":"a1d4f928c955d072afcf86bc5d67e1d901a4825fc028f05a30e957693f8369ec"},"downloads":-1,"filename":"complete-0.6.6.tar.gz","has_sig":false,"md5_digest":"b4461fcf85dbcef9d2dc3f712445f1ae","packagetype":"sdist","python_version":"source","requires_python":null,"size":30589,"upload_time":"2015-04-02T15:34:58","upload_time_iso_8601":"2015-04-02T15:34:58.448942Z","url":"https://files.pythonhosted.org/packages/b0/77/222543b1aa3687f4ded31948019a61ffc0e6e1713e5c7116d32a434663ff/complete-0.6.6.tar.gz","yanked":false,"yanked_reason":null}],"0.6.7":[{"comment_text":"","digests":{"md5":"495afb1b4e059af9099ca90cd619e0d3","sha256":"8fa3dce3f000ed5ac97023b4a2d4e0d4aa3cd1db3885c6d0480e63617a5073d9"},"downloads":-1,"filename":"complete-0.6.7.zip","has_sig":false,"md5_digest":"495afb1b4e059af9099ca90cd619e0d3","packagetype":"sdist","python_version":"source","requires_python":null,"size":44737,"upload_time":"2015-04-02T16:06:22","upload_time_iso_8601":"2015-04-02T16:06:22.122578Z","url":"https://files.pythonhosted.org/packages/2a/c1/1a009a72a524974480996e572cdad6eee1fb9c5c51c291111b1b8e240623/complete-0.6.7.zip","yanked":false,"yanked_reason":null}],"0.6.8":[{"comment_text":"","digests":{"md5":"02a6192bb2bb4196077fcf66aaf67129","sha256":"7e2d1e13a991dc490d0ea70b13528b78f6a7e44d0317536d1f54950a90ae8525"},"downloads":-1,"filename":"complete-0.6.8.zip","has_sig":false,"md5_digest":"02a6192bb2bb4196077fcf66aaf67129","packagetype":"sdist","python_version":"source","requires_python":null,"size":44988,"upload_time":"2015-04-02T16:06:45","upload_time_iso_8601":"2015-04-02T16:06:45.550281Z","url":"https://files.pythonhosted.org/packages/01/eb/4395ef31da4129fc1ade423d0728aee0865f85b1dc5cc58d083d805cd220/complete-0.6.8.zip","yanked":false,"yanked_reason":null}],"0.6.9":[{"comment_text":"","digests":{"md5":"57b6b3f0e3c21163744b1abede196749","sha256":"7ea0451330d9e57633c0ae389cedcf30efc3925ab0c2763563bb28c558b47981"},"downloads":-1,"filename":"complete-0.6.9.zip","has_sig":false,"md5_digest":"57b6b3f0e3c21163744b1abede196749","packagetype":"sdist","python_version":"source","requires_python":null,"size":44179,"upload_time":"2015-04-02T16:07:07","upload_time_iso_8601":"2015-04-02T16:07:07.388937Z","url":"https://files.pythonhosted.org/packages/bb/db/df65a8a5a09aa6fd391c2e52edf3d4ab75396f961e36a425aadc3a50dc75/complete-0.6.9.zip","yanked":false,"yanked_reason":null}],"1.0.0":[{"comment_text":"","digests":{"md5":"3d7c20a999963b8f3d8651bb8a18f577","sha256":"81394752277427af4e3783846716a4780d4100724628668e6153eb3c899fa01d"},"downloads":-1,"filename":"complete-1.0.0.tar.gz","has_sig":false,"md5_digest":"3d7c20a999963b8f3d8651bb8a18f577","packagetype":"sdist","python_version":"source","requires_python":null,"size":39642,"upload_time":"2018-04-13T13:22:51","upload_time_iso_8601":"2018-04-13T13:22:51.840164Z","url":"https://files.pythonhosted.org/packages/6b/d3/376909843cdb112f0ce50173fbcfcd9204efde27e1797de99706c95cde55/complete-1.0.0.tar.gz","yanked":false,"yanked_reason":null}],"1.0.0a1":[{"comment_text":"","digests":{"md5":"669a8bc7160c3de61b6f8a9f4005ae53","sha256":"e882b8fb68e07c5e483b9b1395b41324ca46632c5875c61e725e8bdb9a0b97e9"},"downloads":-1,"filename":"complete-1.0.0a1.tar.gz","has_sig":false,"md5_digest":"669a8bc7160c3de61b6f8a9f4005ae53","packagetype":"sdist","python_version":"source","requires_python":null,"size":37723,"upload_time":"2018-04-10T13:22:53","upload_time_iso_8601":"2018-04-10T13:22:53.589597Z","url":"https://files.pythonhosted.org/packages/5d/f3/b3de2527aaeb8d5d8c4c9c8b49fa5fb9b30463c3568fdb04c4891010d3d4/complete-1.0.0a1.tar.gz","yanked":false,"yanked_reason":null}],"1.0.0a2":[{"comment_text":"","digests":{"md5":"8ca07eb4bbb09cce4b07b64e56c7d7d6","sha256":"8bb91f15ecd2a0efa11bcaf8be013df16629af7ab0c909ca4ff1330d0aacae73"},"downloads":-1,"filename":"complete-1.0.0a2.tar.gz","has_sig":false,"md5_digest":"8ca07eb4bbb09cce4b07b64e56c7d7d6","packagetype":"sdist","python_version":"source","requires_python":null,"size":36836,"upload_time":"2018-04-10T15:48:43","upload_time_iso_8601":"2018-04-10T15:48:43.658000Z","url":"https://files.pythonhosted.org/packages/8b/22/88e32c7999c85a6aa97b2c36e4b366bd5e6631f03c14988124b93564bdb1/complete-1.0.0a2.tar.gz","yanked":false,"yanked_reason":null}],"1.0.0a3.dev0":[{"comment_text":"","digests":{"md5":"65c035101c40d30dc0838acaa135ec41","sha256":"79a4955f3585dc8f05d07494a2a35ad41fe26192e831b6fbd062188226bd42f6"},"downloads":-1,"filename":"complete-1.0.0a3.dev0.tar.gz","has_sig":false,"md5_digest":"65c035101c40d30dc0838acaa135ec41","packagetype":"sdist","python_version":"source","requires_python":null,"size":36846,"upload_time":"2018-04-10T15:56:31","upload_time_iso_8601":"2018-04-10T15:56:31.070448Z","url":"https://files.pythonhosted.org/packages/80/70/df743f6777b4a43689aaa6dfad3f8ca96c041d4f959607cb067e7903019a/complete-1.0.0a3.dev0.tar.gz","yanked":false,"yanked_reason":null}],"1.0.0a4.dev0":[{"comment_text":"","digests":{"md5":"f5034450dcd8df3abe0759a62251bc65","sha256":"2ee7f0f4a86e68e537d77e6922ebc79bb3bb1b316c3a7c2e50bc8f61774ca506"},"downloads":-1,"filename":"complete-1.0.0a4.dev0.tar.gz","has_sig":false,"md5_digest":"f5034450dcd8df3abe0759a62251bc65","packagetype":"sdist","python_version":"source","requires_python":null,"size":36899,"upload_time":"2018-04-10T16:02:36","upload_time_iso_8601":"2018-04-10T16:02:36.150652Z","url":"https://files.pythonhosted.org/packages/02/80/86b6e9a5fc6267e1e945734228073a42f40398ff78537d1e17c0f6f11b93/complete-1.0.0a4.dev0.tar.gz","yanked":false,"yanked_reason":null}],"1.0.0a5":[{"comment_text":"","digests":{"md5":"19bbc60ebbf9d290069649f1e24e7d55","sha256":"5a38bc0e7a5daf89c0a960643fcdabbd8b24b0913c94ff1ef0de06321b4bdbbd"},"downloads":-1,"filename":"complete-1.0.0a5.tar.gz","has_sig":false,"md5_digest":"19bbc60ebbf9d290069649f1e24e7d55","packagetype":"sdist","python_version":"source","requires_python":null,"size":37417,"upload_time":"2018-04-11T13:02:26","upload_time_iso_8601":"2018-04-11T13:02:26.425291Z","url":"https://files.pythonhosted.org/packages/0a/e7/d0889a2a39d214ca883873fa1547eda0672b1ef2bd6d7f5d1bb8bb1e3351/complete-1.0.0a5.tar.gz","yanked":false,"yanked_reason":null}],"1.0.0a6":[{"comment_text":"","digests":{"md5":"1785ee59afdf2ff4c634276f33767302","sha256":"02a3ce91aa39a42146e7dae240cb16a6da529f8c725e53939afe1df736ea4475"},"downloads":-1,"filename":"complete-1.0.0a6.tar.gz","has_sig":false,"md5_digest":"1785ee59afdf2ff4c634276f33767302","packagetype":"sdist","python_version":"source","requires_python":null,"size":38050,"upload_time":"2018-04-12T12:48:52","upload_time_iso_8601":"2018-04-12T12:48:52.719912Z","url":"https://files.pythonhosted.org/packages/4e/b4/50f65f8e77da28899e31945ae5719535e9a9e67bea961ecfba77c39399fe/complete-1.0.0a6.tar.gz","yanked":false,"yanked_reason":null}],"1.1.0":[{"comment_text":"","digests":{"md5":"ee08b66cae5d77364f6deee252638b3b","sha256":"462c76c145403eb5e9a8358dc402a53b264ab202ebabf83cdc660ed2cf72c89b"},"downloads":-1,"filename":"complete-1.0.dev1.tar.gz","has_sig":false,"md5_digest":"ee08b66cae5d77364f6deee252638b3b","packagetype":"sdist","python_version":"source","requires_python":null,"size":39258,"upload_time":"2018-06-15T12:24:36","upload_time_iso_8601":"2018-06-15T12:24:36.191454Z","url":"https://files.pythonhosted.org/packages/ab/4a/cab33ec593f433b7cded3cec85d1f7c900261fd503bd894e16782f7c0d09/complete-1.0.dev1.tar.gz","yanked":false,"yanked_reason":null}],"1.1.1":[{"comment_text":"","digests":{"md5":"dd17d5d775b9433df64513265502cdb8","sha256":"b8dc6c36a3499e752cf5b5d2704d961be37fcf2ea5be2e4187572e18f674d053"},"downloads":-1,"filename":"complete-1.1.1.tar.gz","has_sig":false,"md5_digest":"dd17d5d775b9433df64513265502cdb8","packagetype":"sdist","python_version":"source","requires_python":null,"size":39523,"upload_time":"2018-06-20T18:38:14","upload_time_iso_8601":"2018-06-20T18:38:14.221847Z","url":"https://files.pythonhosted.org/packages/35/cc/ae210f70dac681a7566f25f43740a0cbdc53a77e23684f7b9b1d71e4d918/complete-1.1.1.tar.gz","yanked":false,"yanked_reason":null}],"2.0":[{"comment_text":"","digests":{"md5":"dacf1d5fe5e94e0b656e8985e2e81faa","sha256":"31f83117e38d78670e1994e7160b1463adb04ffa34ff267700b2ca61bada5e57"},"downloads":-1,"filename":"complete-2.0-py2.py3-none-any.whl","has_sig":false,"md5_digest":"dacf1d5fe5e94e0b656e8985e2e81faa","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":55479,"upload_time":"2018-09-25T07:05:49","upload_time_iso_8601":"2018-09-25T07:05:49.423913Z","url":"https://files.pythonhosted.org/packages/ce/dc/7caf3ada02afcab68c7330c207f0b05b54dd5ef6ac96fb18e2fa85f1038a/complete-2.0-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"982c288a450198b414363a9388631c26","sha256":"221733cfbfafff1d90756834f1f2bc8a3cfa097a57ad6ab11e83db308c1b486e"},"downloads":-1,"filename":"complete-2.0.tar.gz","has_sig":false,"md5_digest":"982c288a450198b414363a9388631c26","packagetype":"sdist","python_version":"source","requires_python":null,"size":86965,"upload_time":"2018-09-25T07:05:51","upload_time_iso_8601":"2018-09-25T07:05:51.301648Z","url":"https://files.pythonhosted.org/packages/41/80/5c6ef6fc423fb7902cc7fe6d5784545559d11dc157b1dbe50de59192bd08/complete-2.0.tar.gz","yanked":false,"yanked_reason":null}],"2.0b1":[{"comment_text":"","digests":{"md5":"0003996e2c8b62541743c80f1367925f","sha256":"9a15649073d795f2a742f0c46f44ebc732727ae201cf92e796ffb7b31eaebf59"},"downloads":-1,"filename":"complete-2.0b1-py2.py3-none-any.whl","has_sig":false,"md5_digest":"0003996e2c8b62541743c80f1367925f","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":53036,"upload_time":"2018-09-03T12:49:24","upload_time_iso_8601":"2018-09-03T12:49:24.676079Z","url":"https://files.pythonhosted.org/packages/65/35/0820f8a49e5812dbcdb2aee651f19df8bf7c67d379e449699ed4ede5df51/complete-2.0b1-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"5f60ea9a2bc0109d1828ae753c332ed2","sha256":"173ad39aa5c95e9deeb563e94174c944ffd814441b2587f5645f0119c192220c"},"downloads":-1,"filename":"complete-2.0b1.tar.gz","has_sig":false,"md5_digest":"5f60ea9a2bc0109d1828ae753c332ed2","packagetype":"sdist","python_version":"source","requires_python":null,"size":70341,"upload_time":"2018-09-03T12:49:27","upload_time_iso_8601":"2018-09-03T12:49:27.080969Z","url":"https://files.pythonhosted.org/packages/54/45/006a8a3068f261dfbb543e4a4905ea1495a9deaa6b880af881e7112fe590/complete-2.0b1.tar.gz","yanked":false,"yanked_reason":null}],"2.0b2":[{"comment_text":"","digests":{"md5":"e2431ed70e7c940e72b065b3c2fc4d66","sha256":"0ea1eabb994a10160cdeb3b3a93e80e09191bc971ddf10213ec4618e890a79a1"},"downloads":-1,"filename":"complete-2.0b2-py2.py3-none-any.whl","has_sig":false,"md5_digest":"e2431ed70e7c940e72b065b3c2fc4d66","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":53862,"upload_time":"2018-09-06T14:41:53","upload_time_iso_8601":"2018-09-06T14:41:53.157424Z","url":"https://files.pythonhosted.org/packages/10/db/b5e9c37e5e66e86b5f87220db5e18d4f6b79f5b57037fcb251ca1116d9d0/complete-2.0b2-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"0199ffb374b5378b5b3f03b23008ee31","sha256":"4d95ddf206f4c440fcace43c0a9f4d26fb704b1fd5087c6c9b903e04a008bf05"},"downloads":-1,"filename":"complete-2.0b2.tar.gz","has_sig":false,"md5_digest":"0199ffb374b5378b5b3f03b23008ee31","packagetype":"sdist","python_version":"source","requires_python":null,"size":85397,"upload_time":"2018-09-06T14:41:55","upload_time_iso_8601":"2018-09-06T14:41:55.709235Z","url":"https://files.pythonhosted.org/packages/e6/ec/5c92cdd29d86e05b0938c56af54e06962a822689c5c70b5fa4eba727d799/complete-2.0b2.tar.gz","yanked":false,"yanked_reason":null}],"2.0b3":[{"comment_text":"","digests":{"md5":"810ffd544e5de013bbc0ad49258d017c","sha256":"a7c2efc42f6b2e47af36d905521a0e97c5f469d3d8c4243b87db9281c056c5de"},"downloads":-1,"filename":"complete-2.0b3-py2.py3-none-any.whl","has_sig":false,"md5_digest":"810ffd544e5de013bbc0ad49258d017c","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":54110,"upload_time":"2018-09-11T19:48:45","upload_time_iso_8601":"2018-09-11T19:48:45.470945Z","url":"https://files.pythonhosted.org/packages/0a/0c/fa7d475d3be9c376bb46fa7d0db1f70ee7cbce8d7328de750d06c72c1f8a/complete-2.0b3-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"116600a8ebf81955bbdde9716dcb8a70","sha256":"77e234d9e9e2f274e9bd86380f2fd0bb58ad3071278ab4c9df801ff54caead01"},"downloads":-1,"filename":"complete-2.0b3.tar.gz","has_sig":false,"md5_digest":"116600a8ebf81955bbdde9716dcb8a70","packagetype":"sdist","python_version":"source","requires_python":null,"size":85573,"upload_time":"2018-09-11T19:48:47","upload_time_iso_8601":"2018-09-11T19:48:47.787379Z","url":"https://files.pythonhosted.org/packages/a7/2d/22d2e86b795f85aa80676c7668a5e375b44d3239664d72b0b1c32e7291ed/complete-2.0b3.tar.gz","yanked":false,"yanked_reason":null}],"2.0b4":[{"comment_text":"","digests":{"md5":"e238130940a149c44927e30216bc0f74","sha256":"88ba6fb733677579a9bd6b1b1e99808d47d17ba20038075f8731ee12d40efb41"},"downloads":-1,"filename":"complete-2.0b4-py2.py3-none-any.whl","has_sig":false,"md5_digest":"e238130940a149c44927e30216bc0f74","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":54166,"upload_time":"2018-09-12T12:58:38","upload_time_iso_8601":"2018-09-12T12:58:38.798219Z","url":"https://files.pythonhosted.org/packages/f2/99/891565815619416a411b6a43dca887c575035c0dd2da374e7c87df5d9263/complete-2.0b4-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"14f8369167928c97140e55af20438d95","sha256":"63bdf6265dac0213e71001b03c81171b7fb1bf2fab06cd0ea8c9d2ffd4c0cd0c"},"downloads":-1,"filename":"complete-2.0b4.tar.gz","has_sig":false,"md5_digest":"14f8369167928c97140e55af20438d95","packagetype":"sdist","python_version":"source","requires_python":null,"size":87043,"upload_time":"2018-09-12T12:58:41","upload_time_iso_8601":"2018-09-12T12:58:41.083128Z","url":"https://files.pythonhosted.org/packages/eb/ca/24ff95b2da5a77f167e2113b6861f879f04629a5b1834ca221b790b36481/complete-2.0b4.tar.gz","yanked":false,"yanked_reason":null}],"2.0b5":[{"comment_text":"","digests":{"md5":"8660d1531dda6f79bd48a49fbf3d5888","sha256":"01b00bcf84e8f9692215ef1f3d4cb350d076add26b70f29e4f31ac85e5f66a28"},"downloads":-1,"filename":"complete-2.0b5-py2.py3-none-any.whl","has_sig":false,"md5_digest":"8660d1531dda6f79bd48a49fbf3d5888","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":54240,"upload_time":"2018-09-13T19:12:05","upload_time_iso_8601":"2018-09-13T19:12:05.832300Z","url":"https://files.pythonhosted.org/packages/ac/69/3a53d4aeb73dc20d140bdab53036572706e4cfc063d58d43cb73264b86ed/complete-2.0b5-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"c8a97de8115ab5ee9c0d5e1f70ed9060","sha256":"308bff344aed37aa04aae552e9d54d0d8ba625386bd5b8817282ef75c66de407"},"downloads":-1,"filename":"complete-2.0b5.tar.gz","has_sig":false,"md5_digest":"c8a97de8115ab5ee9c0d5e1f70ed9060","packagetype":"sdist","python_version":"source","requires_python":null,"size":87210,"upload_time":"2018-09-13T19:12:09","upload_time_iso_8601":"2018-09-13T19:12:09.026887Z","url":"https://files.pythonhosted.org/packages/55/83/cbd13288511af6f8c55ea340935cf17b244c485f6f776214fbc6bc41d7c4/complete-2.0b5.tar.gz","yanked":false,"yanked_reason":null}],"2.0b6":[{"comment_text":"","digests":{"md5":"6e64c656bd3b495bc2d9f357c6f8901f","sha256":"9e6d41a6ebfe71a90a288ea7f3a5c8efa2b7fe313c3e1aa026fa97f345e07745"},"downloads":-1,"filename":"complete-2.0b6-py2.py3-none-any.whl","has_sig":false,"md5_digest":"6e64c656bd3b495bc2d9f357c6f8901f","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":55113,"upload_time":"2018-09-13T19:14:55","upload_time_iso_8601":"2018-09-13T19:14:55.356378Z","url":"https://files.pythonhosted.org/packages/aa/39/115e4fa64aebf2c57a71c29c53740504f658b1447650a1473edb0c3ebb00/complete-2.0b6-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"5c2d8fafcf16fd0fa9220da91205f696","sha256":"fa4cb24351e678dd56c9b46350cd54b1f39209e03517532a5e8fa8db9adbda56"},"downloads":-1,"filename":"complete-2.0b6.tar.gz","has_sig":false,"md5_digest":"5c2d8fafcf16fd0fa9220da91205f696","packagetype":"sdist","python_version":"source","requires_python":null,"size":88205,"upload_time":"2018-09-13T19:14:58","upload_time_iso_8601":"2018-09-13T19:14:58.034821Z","url":"https://files.pythonhosted.org/packages/2c/59/c47466d69a1293a7e1587a8af04d15c875415967527e9be6b4241723d96b/complete-2.0b6.tar.gz","yanked":false,"yanked_reason":null}],"2.0b7":[{"comment_text":"","digests":{"md5":"7c1beaed9081f6dca0cce01ab4957c6b","sha256":"8dbfdf93bd9d91c07ab5494d316c6083c3d71f673fd66ba497ce2b6a2011dd18"},"downloads":-1,"filename":"complete-2.0b7-py2.py3-none-any.whl","has_sig":false,"md5_digest":"7c1beaed9081f6dca0cce01ab4957c6b","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":56045,"upload_time":"2018-09-14T13:31:42","upload_time_iso_8601":"2018-09-14T13:31:42.874915Z","url":"https://files.pythonhosted.org/packages/bc/6c/e71ecb88f2308d7528c687ce2982fa4dba85cdaa9ac46604af59d844ace7/complete-2.0b7-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"bdc27299ae90128c3bbee2f833be2171","sha256":"e6ba88f2c2b8329d62b3aadfcb30dd782497087759673257e0f688df728a1694"},"downloads":-1,"filename":"complete-2.0b7.tar.gz","has_sig":false,"md5_digest":"bdc27299ae90128c3bbee2f833be2171","packagetype":"sdist","python_version":"source","requires_python":null,"size":89558,"upload_time":"2018-09-14T13:31:45","upload_time_iso_8601":"2018-09-14T13:31:45.969375Z","url":"https://files.pythonhosted.org/packages/4b/7a/349fde975c7b6b7331da2542d0e2cf9f0b7d30054bb5684d94d90f48e12b/complete-2.0b7.tar.gz","yanked":false,"yanked_reason":null}],"2.0rc1":[{"comment_text":"","digests":{"md5":"ff0d9ff18f6ad6b6951aa7f933782280","sha256":"582270dc62708af5ee2b649abde1ee1d6f0374f642f6b0b8771e203f2d4922ed"},"downloads":-1,"filename":"complete-2.0rc1-py2.py3-none-any.whl","has_sig":false,"md5_digest":"ff0d9ff18f6ad6b6951aa7f933782280","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":56194,"upload_time":"2018-09-24T20:19:16","upload_time_iso_8601":"2018-09-24T20:19:16.377778Z","url":"https://files.pythonhosted.org/packages/e6/55/1c65e555d1e952644428da85662ef9c0448becfae5487ab321048b57d339/complete-2.0rc1-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"eaef8d536ee4faedb15b5b6e77c84378","sha256":"e6044d6cf2bb283ad72e7fae3200d275950cbdc7245751c62c51c3a6b12391d6"},"downloads":-1,"filename":"complete-2.0rc1.tar.gz","has_sig":false,"md5_digest":"eaef8d536ee4faedb15b5b6e77c84378","packagetype":"sdist","python_version":"source","requires_python":null,"size":87563,"upload_time":"2018-09-24T20:19:18","upload_time_iso_8601":"2018-09-24T20:19:18.508231Z","url":"https://files.pythonhosted.org/packages/1f/f3/31351b897f110ac00cb5a13b0ea4ca5f272602ee0db46f0f810d8a1baa69/complete-2.0rc1.tar.gz","yanked":false,"yanked_reason":null}],"2.1":[{"comment_text":"","digests":{"md5":"4881924e6245797451bd27c644d5b569","sha256":"62aed6f2d1779a7f934454a897c61a1bc704f7f04d6fb533e6bfe54c17d22224"},"downloads":-1,"filename":"complete-2.1-py2.py3-none-any.whl","has_sig":false,"md5_digest":"4881924e6245797451bd27c644d5b569","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":57198,"upload_time":"2018-10-03T11:05:00","upload_time_iso_8601":"2018-10-03T11:05:00.909986Z","url":"https://files.pythonhosted.org/packages/27/23/91f3184390c709be6ce9419f2dd4e6b5bb2fd1b7a06579ea1625f8898d0b/complete-2.1-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"cc6b38495b180f0d1d852dd1794fef42","sha256":"528aaeff5b12aa7c1fe5909111fd7b46c14bf25f1a5ed759d6b422d45f10b40c"},"downloads":-1,"filename":"complete-2.1.tar.gz","has_sig":false,"md5_digest":"cc6b38495b180f0d1d852dd1794fef42","packagetype":"sdist","python_version":"source","requires_python":null,"size":91935,"upload_time":"2018-10-03T11:05:03","upload_time_iso_8601":"2018-10-03T11:05:03.023229Z","url":"https://files.pythonhosted.org/packages/65/57/604980e6223c09e8b428c128d480ae516548f7d2bd8ad580e72f2b5dfc09/complete-2.1.tar.gz","yanked":false,"yanked_reason":null}],"2.1b1":[{"comment_text":"","digests":{"md5":"3fb0bd3f94cce78d9fdf8838c8aa0313","sha256":"d58675740ed81b6f1397f3adb1fa30cc92d47a96a9e000c0b636772a20ea307c"},"downloads":-1,"filename":"complete-2.1b1-py2.py3-none-any.whl","has_sig":false,"md5_digest":"3fb0bd3f94cce78d9fdf8838c8aa0313","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":56695,"upload_time":"2018-10-01T19:58:52","upload_time_iso_8601":"2018-10-01T19:58:52.535754Z","url":"https://files.pythonhosted.org/packages/a6/5a/ca949df720ed4e8754c61137c0f073452954ff32b2f50791f4a4fdc0e77a/complete-2.1b1-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"a300ab4179a1b744a80d69d02997a453","sha256":"3e7180b09ad27439c295d022be6ef45e8aa3bdd00681b9556afbc8617cb31917"},"downloads":-1,"filename":"complete-2.1b1.tar.gz","has_sig":false,"md5_digest":"a300ab4179a1b744a80d69d02997a453","packagetype":"sdist","python_version":"source","requires_python":null,"size":90728,"upload_time":"2018-10-01T19:58:54","upload_time_iso_8601":"2018-10-01T19:58:54.596506Z","url":"https://files.pythonhosted.org/packages/46/69/30fa7d24f48e0f77fcd4f3c811dc72127b997bb8149488123890bfb42baf/complete-2.1b1.tar.gz","yanked":false,"yanked_reason":null}],"2.2":[{"comment_text":"","digests":{"md5":"381ae9b409adc01109fb4f48a15353e6","sha256":"35e688c7295ce389641bce37cd92fc3482d7d67874a67a9d0cc61a9ccc0f20ac"},"downloads":-1,"filename":"complete-2.2-py2.py3-none-any.whl","has_sig":false,"md5_digest":"381ae9b409adc01109fb4f48a15353e6","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":57344,"upload_time":"2018-10-12T16:21:34","upload_time_iso_8601":"2018-10-12T16:21:34.840456Z","url":"https://files.pythonhosted.org/packages/15/b5/3e4434f95cf68e1acb398dd9c596d07cc881c2fa45ab78659689615989d1/complete-2.2-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"4c5811798dbb0164e075e4026d410633","sha256":"aad7b8b00a49eeef7cd69757b2c548b88d4d7c584b95ac4ea9c0f08e167bc5a0"},"downloads":-1,"filename":"complete-2.2.tar.gz","has_sig":false,"md5_digest":"4c5811798dbb0164e075e4026d410633","packagetype":"sdist","python_version":"source","requires_python":null,"size":92135,"upload_time":"2018-10-12T16:21:36","upload_time_iso_8601":"2018-10-12T16:21:36.870458Z","url":"https://files.pythonhosted.org/packages/46/20/041ec087b8288b86aa71cea6f89c9aed9fc931d543d620d383556f646366/complete-2.2.tar.gz","yanked":false,"yanked_reason":null}],"2.3":[{"comment_text":"","digests":{"md5":"44c51fb9141dc9c2cb2d4a4bdbcc1acb","sha256":"4930ac8c01c5b5c94ae24ee5d26e42d537a3281291b06928529bb97cc11844e8"},"downloads":-1,"filename":"complete-2.3-py2.py3-none-any.whl","has_sig":false,"md5_digest":"44c51fb9141dc9c2cb2d4a4bdbcc1acb","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":59466,"upload_time":"2019-02-27T11:49:48","upload_time_iso_8601":"2019-02-27T11:49:48.609906Z","url":"https://files.pythonhosted.org/packages/ff/37/ed2d26f5f196b6db5a7a53de1ab96c961ab0c0e42d7677ea302cc817ed7f/complete-2.3-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"0510299dba157df2cbfea40426465bf5","sha256":"2727f62ab590c1fc834e86033988a76a86a67f5a78196584049b7a722bd94466"},"downloads":-1,"filename":"complete-2.3.tar.gz","has_sig":false,"md5_digest":"0510299dba157df2cbfea40426465bf5","packagetype":"sdist","python_version":"source","requires_python":null,"size":95947,"upload_time":"2019-02-27T11:49:51","upload_time_iso_8601":"2019-02-27T11:49:51.261375Z","url":"https://files.pythonhosted.org/packages/e6/1c/3dd86bec66fad3a21ac9d093610f83f6e20ad1d835ebf4079af53e65ed6b/complete-2.3.tar.gz","yanked":false,"yanked_reason":null}],"2.4":[{"comment_text":"","digests":{"md5":"d676c724f7e13838edd8a7dcc8cbe3e7","sha256":"213c2f4c39ed71811a9ceeec1c8bdf2e673e5527261ea11708b3acfa6c2bdb00"},"downloads":-1,"filename":"complete-2.4-py2.py3-none-any.whl","has_sig":false,"md5_digest":"d676c724f7e13838edd8a7dcc8cbe3e7","packagetype":"bdist_wheel","python_version":"py2.py3","requires_python":null,"size":57463,"upload_time":"2019-10-09T09:41:14","upload_time_iso_8601":"2019-10-09T09:41:14.821316Z","url":"https://files.pythonhosted.org/packages/36/95/7d9271ae617b6c448fa244b347e4fd43ed5ad1bb35cea282f1c0fa82ea2b/complete-2.4-py2.py3-none-any.whl","yanked":false,"yanked_reason":null},{"comment_text":"","digests":{"md5":"1728f65d01c5cb1f3c3838d489a1569d","sha256":"05bea20ce1f2c9678683bcce0c3ba9981f87d92b709d190e018bcbf047eccf63"},"downloads":-1,"filename":"complete-2.4.tar.gz","has_sig":false,"md5_digest":"1728f65d01c5cb1f3c3838d489a1569d","packagetype":"sdist","python_version":"source","requires_python":null,"size":94826,"upload_time":"2019-10-09T09:41:17","upload_time_iso_8601":"2019-10-09T09:41:17.883138Z","url":"https://files.pythonhosted.org/packages/76/36/a3e41bf7c01f1110d7b5589ca74d2927d3736a5b43ee63053faf3483b991/complete-2.4.tar.gz","yanked":false,"yanked_reason":null}]},"urls":[{"comment_text":"","digests":{"md5":"ee08b66cae5d77364f6deee252638b3b","sha256":"462c76c145403eb5e9a8358dc402a53b264ab202ebabf83cdc660ed2cf72c89b"},"downloads":-1,"filename":"complete-1.0.dev1.tar.gz","has_sig":false,"md5_digest":"ee08b66cae5d77364f6deee252638b3b","packagetype":"sdist","python_version":"source","requires_python":null,"size":39258,"upload_time":"2018-06-15T12:24:36","upload_time_iso_8601":"2018-06-15T12:24:36.191454Z","url":"https://files.pythonhosted.org/packages/ab/4a/cab33ec593f433b7cded3cec85d1f7c900261fd503bd894e16782f7c0d09/complete-1.0.dev1.tar.gz","yanked":false,"yanked_reason":null}]}
pyroma-5.0/pyroma/testdata/lacking/000077500000000000000000000000001503537372600174305ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/lacking/lacking/000077500000000000000000000000001503537372600210405ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/lacking/lacking/__init__.py000066400000000000000000000000001503537372600231370ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/lacking/setup.cfg000066400000000000000000000000651503537372600212520ustar00rootroot00000000000000[egg_info]
tag_build = .dev1
tag_svn_revision = true
pyroma-5.0/pyroma/testdata/lacking/setup.py000066400000000000000000000002101503537372600211330ustar00rootroot00000000000000from setuptools import setup

version = "1.0"

setup(name="lacking", version=version, long_description="``error", packages=["lacking"])
pyroma-5.0/pyroma/testdata/minimal/000077500000000000000000000000001503537372600174465ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/minimal/minimal/000077500000000000000000000000001503537372600210745ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/minimal/minimal/__init__.py000066400000000000000000000000001503537372600231730ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/minimal/pyproject.toml000066400000000000000000000000371503537372600223620ustar00rootroot00000000000000[tool.black]
line-length = 120
pyroma-5.0/pyroma/testdata/minimal/randomfile.txt000066400000000000000000000000571503537372600223310ustar00rootroot00000000000000This should cause an error with check-manifest
pyroma-5.0/pyroma/testdata/minimal/setup.cfg000066400000000000000000000000651503537372600212700ustar00rootroot00000000000000[egg_info]
tag_build = .dev1
tag_svn_revision = true
pyroma-5.0/pyroma/testdata/minimal/setup.py000066400000000000000000000007271503537372600211660ustar00rootroot00000000000000from setuptools import setup, find_packages

version = "0.0.1"

setup(
    name="minimal",
    version=version,
    description="Test",
    classifiers=[],
    keywords="",
    author="",
    author_email="",
    url="",
    license="",
    packages=find_packages(exclude=["ez_setup", "examples", "tests"]),
    include_package_data=True,
    install_requires=[
        # -*- Extra requirements: -*-
    ],
    entry_points="""
      # -*- Entry points: -*-
      """,
)
pyroma-5.0/pyroma/testdata/only_config/000077500000000000000000000000001503537372600203265ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/only_config/README.txt000066400000000000000000000024461503537372600220320ustar00rootroot00000000000000Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
pyroma-5.0/pyroma/testdata/only_config/only_config/000077500000000000000000000000001503537372600226345ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/only_config/only_config/__init__.py000066400000000000000000000000001503537372600247330ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/only_config/setup.cfg000066400000000000000000000013651503537372600221540ustar00rootroot00000000000000[metadata]
name = only_config
version = 1.0
description = This is a test package for pyroma
long_description = file: README.txt
author = Lennart Regebro
author_email = regebro@gmail.com
url = https://github.com/regebro/pyroma
classifiers =
    Development Status :: 6 - Mature
    Operating System :: OS Independent
    Programming Language :: Python :: 2.6
    Programming Language :: Python :: 2.7
    Programming Language :: Python :: 3.1
    Programming Language :: Python :: 3.2
    Programming Language :: Python :: 3.3
    License :: OSI Approved :: MIT License
    License :: OSI Approved :: GNU General Public License (GPL)
keywords =
    pypi
    quality
    example
license-expression = MIT OR GPL-2.0-or-later

[options]
python_requires = >=2.6
pyroma-5.0/pyroma/testdata/pep517/000077500000000000000000000000001503537372600170415ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/pep517/README.txt000066400000000000000000000024461503537372600205450ustar00rootroot00000000000000Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
pyroma-5.0/pyroma/testdata/pep517/only_config/000077500000000000000000000000001503537372600213475ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/pep517/only_config/__init__.py000066400000000000000000000000001503537372600234460ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/pep517/pyproject.toml000066400000000000000000000001251503537372600217530ustar00rootroot00000000000000[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
pyroma-5.0/pyroma/testdata/pep517/setup.cfg000066400000000000000000000012021503537372600206550ustar00rootroot00000000000000[metadata]
name = pep517
version = 1.0
description = This is a test package for pyroma
long_description = file: README.txt
author = Lennart Regebro
author_email = regebro@gmail.com
url = https://github.com/regebro/pyroma
classifiers =
    Development Status :: 6 - Mature
    Operating System :: OS Independent
    Programming Language :: Python :: 2.6
    Programming Language :: Python :: 2.7
    Programming Language :: Python :: 3.1
    Programming Language :: Python :: 3.2
    Programming Language :: Python :: 3.3
    License :: OSI Approved :: MIT License
keywords =
    pypi
    quality
    example
[options]
python_requires = >=2.6
pyroma-5.0/pyroma/testdata/pep621/000077500000000000000000000000001503537372600170355ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/pep621/README.txt000066400000000000000000000024461503537372600205410ustar00rootroot00000000000000Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
pyroma-5.0/pyroma/testdata/pep621/pyproject.toml000066400000000000000000000015121503537372600217500ustar00rootroot00000000000000[build-system]
requires = ["flit_core >=3.4,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "pyroma_pep621_test_pkg"
version = "1.0"
description = "This is a test package for pyroma"
readme = "README.txt"
authors = [{name = "Lennart Regebro", email = "regebro@gmail.com"}]
classifiers = [
    "Development Status :: 6 - Mature",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 2.6",
    "Programming Language :: Python :: 2.7",
    "Programming Language :: Python :: 3.1",
    "Programming Language :: Python :: 3.2",
    "Programming Language :: Python :: 3.3",
    "License :: OSI Approved :: MIT License",
]
keywords = [
    "pypi",
    "quality",
    "example",
]
urls = {Homepage = "https://github.com/regebro/pyroma"}
requires-python = ">3.8"

[tool.setuptools]
include-package-data = false
pyroma-5.0/pyroma/testdata/pep621/pyroma_pep621_test_pkg/000077500000000000000000000000001503537372600233415ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/pep621/pyroma_pep621_test_pkg/__init__.py000066400000000000000000000001001503537372600254410ustar00rootroot00000000000000"""This is a test package for pyroma."""

__version__ = "1.0.0"
pyroma-5.0/pyroma/testdata/private_classifier/000077500000000000000000000000001503537372600216765ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/private_classifier/README.txt000066400000000000000000000024461503537372600234020ustar00rootroot00000000000000Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
pyroma-5.0/pyroma/testdata/private_classifier/private_classifier/000077500000000000000000000000001503537372600255545ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/private_classifier/private_classifier/__init__.py000066400000000000000000000000001503537372600276530ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/private_classifier/pyproject.toml000066400000000000000000000001251503537372600246100ustar00rootroot00000000000000[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
pyroma-5.0/pyroma/testdata/private_classifier/setup.cfg000066400000000000000000000012121503537372600235130ustar00rootroot00000000000000[metadata]
name = private_classifier
version = 1.0
description = A project with a private classifier
long_description = file: README.txt
author = Lennart Regebro
author_email = regebro@gmail.com
url = https://example.com
classifiers =
    Development Status :: 6 - Mature
    Operating System :: OS Independent
    Private :: Do Not Upload
    Programming Language :: Python :: 2.6
    Programming Language :: Python :: 2.7
    Programming Language :: Python :: 3.1
    Programming Language :: Python :: 3.2
    Programming Language :: Python :: 3.3
    License :: OSI Approved :: MIT License
keywords =
    private
[options]
python_requires = >=2.6
pyroma-5.0/pyroma/testdata/setup_config/000077500000000000000000000000001503537372600205055ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/setup_config/README.txt000066400000000000000000000024461503537372600222110ustar00rootroot00000000000000Complete
========

This is a test package for pyroma that is supposed to have a complete
set of metadata and also runnable tests. It should score the maximum possible
on package tests.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at
dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget
velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam
nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla
nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin
orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing
velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac
ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus
nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis
interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit
ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et
dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed
ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit
posuere id dignissim massa molestie.
pyroma-5.0/pyroma/testdata/setup_config/setup.cfg000066400000000000000000000012201503537372600223210ustar00rootroot00000000000000[metadata]
name = only_config
version = 1.0
description = This is a test package for pyroma
long_description = file: README.txt
author = Lennart Regebro
author_email = regebro@gmail.com
url = https://github.com/regebro/pyroma
classifiers =
    Development Status :: 6 - Mature
    Operating System :: OS Independent
    Programming Language :: Python :: 2.6
    Programming Language :: Python :: 2.7
    Programming Language :: Python :: 3.1
    Programming Language :: Python :: 3.2
    Programming Language :: Python :: 3.3
    License :: OSI Approved :: MIT License
keywords =
    pypi
    quality
    example
[options]
python_requires = >=2.6, !=3.1.*
pyroma-5.0/pyroma/testdata/setup_config/setup.py000066400000000000000000000000461503537372600222170ustar00rootroot00000000000000import setuptools

setuptools.setup()
pyroma-5.0/pyroma/testdata/setup_config/setup_config/000077500000000000000000000000001503537372600231725ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/setup_config/setup_config/__init__.py000066400000000000000000000000001503537372600252710ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/xmlrpcdata/000077500000000000000000000000001503537372600201575ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/xmlrpcdata/complete/000077500000000000000000000000001503537372600217675ustar00rootroot00000000000000pyroma-5.0/pyroma/testdata/xmlrpcdata/complete/1.0.dev1.html000066400000000000000000001437651503537372600240310ustar00rootroot00000000000000








  
    
    
    

    
    



    complete · PyPI
    

    
    
    
    
    
    
    



    

    
    

    


    
    
    
    
    
    

    


    

    


    
    
  

  


    
    Skip to main content

    

    

Tree 2 tree correction between xml documents. Extract differences between two xml files. It returns a set of primitives to apply on source tree to obtain the destination tree.

Project description

https://travis-ci.org/Shoobx/complete.png?branch=master https://coveralls.io/repos/github/Shoobx/complete/badge.svg?branch=master

complete is a utility for extracting differences between two xml files. It returns a set of primitives to apply on source tree to obtain the destination tree.

The implementation is based on Change detection in hierarchically structured information, by S. Chawathe, A. Rajaraman, H. Garcia-Molina and J. Widom, Stanford University, 1996

Installation

To install the latest release:

pip install complete

To install the development version:

git clone https://github.com/Shoobx/complete.git
cd complete
virtualenv ./.venv
./.venv/bin/python setup.py install

Then to compare two given XML files:

./.venv/bin/complete 1.xml 2.xml

Running tests

To run the test suite for all python versions:

tox

CHANGES

1.1.1 (2018-06-20)

  • When moving attributes the secondary rename action xpath was ‘//LogilabcompleteTmpAttr<attrib>’ which is a tag specification. Changed this to ‘//@LogilabcompleteTmpAttr<attrib>’, so an attribute is specified.

1.1.0 (2018-06-15)

  • When using namespaces, the returned xpaths are now in the form ns_prefix:tag instead of the earlier {ns_uri}tag, which isn’t correct xpaths.

1.0.0 (2018-04-13)

  • pep8 cleanup, added flake8 checking to tox

1.0.0a6 (2018-04-12)

  • Removed encoding, because python does unicode just fine
  • Switched on namespace handling for XML input

1.0.0a5 (2018-04-11)

  • Brownbag release to make up for bad previous ones.

1.0.0a2 (2018-04-11)

  • Temporary disabling of encoding text (hopefully permanent).
  • Reverted bug fix: Do not remove newlines from text while parsing the XML.

1.0.0a1 (2018-04-10)

  • Bug: Fix a off-by-one issue with insert-after action.
  • Bug: Do not rename children on text node updates.
  • Bug: Text moves were not recorded as part of the fmes edit script.
  • Remove only partially implemented xmlrev script.
  • Removed support for xupdate, which never became a standard.
  • Removed deprecated ezs optional algorithm.
  • Removed support for Debian and RedHat packaging.
  • Removed Windows support
  • LOTS of package cleanup (setup.py, MANIFEST, proper console script, etc)
  • tests moved to py.test and cleaned, added tox, travis, coverage support

0.6.10 (2010-08-27)

  • apply Daiki Ueno patch: fails when comparing minimal trees on i386

0.6.9 (2009-04-02)

  • Fixed complete-xmlrev compilation error

0.6.8 (2006-06-15)

  • Fixed 64bit cleanness issues

0.6.7 (2005-05-04)

  • WARNING: complete is no longer a logilab subpackage. Users may have to manually remove the old logilab/complete directory.
  • fixed debian bug #275750, also reported by Christopher R Newman on the xml-projects mailing list
  • fixed –profile option, wrap function from maplookup when profiling so that they appear in the profile information
  • fixed setup.py to ignore the xmlrev shell script under windows platforms
  • small improvements (remove recursion in object.py, minor enhancement in mydifflib.py, rewrite of lcs4 in C)

0.6.6 (2004-12-23)

  • Applied patch by Bastian Kleineidam <calvin@debian.org> which

    • corrects the typo in ML_DIR
    • fixes the TMPFILE_XSLT/TMPFILE_XSL typo
    • makes sure the files are XML or SGML files, else prints an error
    • adds various missing quotes around filenames which could have spaces or begin with a hyphen
    • fixes typos in the usage() function

    Thanks a lot, Bastian.

  • Fixed some problems in the xmlrev.xslt stylesheet

  • Fixed problems in xmlrev caused by the exit status of complete when successful

  • Added a man page for complete and xmlrev

0.6.5 (2004-09-02)

  • xmlrev bugfixes
  • Fixed packaging problems (missing xsl stylesheets and MANIFEST file)

0.6.4 (2003-10-02)

  • fix recursive mode
  • rewrite regression test, add test for the recursive mode
  • add –help option to xlmrev
  • packaging fixes
  • turn API.txt and HELP.txt to correct ReST

0.6.3 (2002-11-06)

  • fix wrong xpath for attributes
  • fix bug with temporary duplicate attribute node
  • fix for xupdate
  • fix ext_pes option bug
  • update changelog to new format

0.6.2 (2002-09-23)

  • return number of differences on command line
  • reintroduce misc.list_print which caused recursive mode to fail
  • use psyco if available (http://psyco.sf.net)
  • little changes in C extension

0.6.1 (2002-08-29)

  • fix packaging problems

0.6.0 (2002-08-23)

  • change of the internal representation
  • remove support for the EZS algorithm (no more maintened for the moment)
  • add command line options to parse html and to control entities inclusion and output encoding
  • fixing coalescing text nodes bug
  • many other bugs fixes
  • great speed improvement

0.5.3 (2002-01-31)

  • add __init__.py in “logilab” directory

0.5.2 (2001-10-29)

  • bug fixes in xupdate formatting and in the dom interface.

0.5.1 (2001-09-07)

  • Fast Match / Edit Scritp algorithm, now fully usable
  • fixes Unicode problem

0.2.1 (2001-08-10)

  • bug fixes, optimizations for ezs algorithm

0.1.1 (2001-08-04)

  • original revision

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Filename, size & hash SHA256 hash help File type Python version Upload date
complete-1.1.1.tar.gz (39.5 kB) Copy SHA256 hash SHA256 Source None Jun 20, 2018
pyroma-5.0/pyroma/testdata/xmlrpcdata/completedata.py000066400000000000000000000071721503537372600232020ustar00rootroot00000000000000from datetime import datetime args = ("https://pypi.org/pypi",) kw = {} data = { "package_releases": {("complete",): ["1.0.dev1"]}, "release_data": { ("complete", "1.0.dev1"): { "maintainer": None, "requires_python": None, "maintainer_email": None, "cheesecake_code_kwalitee_id": None, "keywords": ["pypi", "quality", "example"], "package_url": "http://pypi.org/project/complete", "author": "Lennart Regebro", "author_email": "regebro@gmail.com", "download_url": "UNKNOWN", "platform": "UNKNOWN", "version": "1.0.dev1", "cheesecake_documentation_id": None, "_pypi_hidden": False, "description": """Complete ======== This is a test package for pyroma that is supposed to have a complete set of metadata and also runnable tests. It should score the maximum possible on package tests. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor, neque at dignissim condimentum, libero est dictum dolor, sit amet tempor urna diam eget velit. Suspendisse at odio quam, ut vestibulum ipsum. Nulla facilisi. Nullam nunc dolor, tempus in vulputate id, fringilla eget metus. Pellentesque nulla nisl, imperdiet ac vulputate non, commodo tincidunt purus. Aenean sollicitudin orci eget diam dignissim scelerisque. Donec quis neque nisl, eu adipiscing velit. Aenean convallis ante sapien. Etiam vitae viverra libero. Nullam ac ligula erat. Aliquam pellentesque, est eget faucibus pharetra, urna orci rhoncus nisi, adipiscing elementum libero lectus ut odio. Duis tincidunt mi quam, quis interdum enim. Nunc sed urna urna, id lacinia turpis. Quisque malesuada, velit ut tincidunt lacinia, dolor augue varius velit, in ultrices lectus enim et dolor. Fusce augue eros, aliquet ac dapibus at, tincidunt vitae leo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus sapien neque, fermentum sed ultrices sit amet, fermentum nec est. Pellentesque imperdiet enim nec velit posuere id dignissim massa molestie.""", "release_url": "http://pypi.org/project/distribute/1.0.dev1", "_pypi_ordering": 115, "classifiers": [ "Development Status :: 6 - Mature", "Operating System :: OS Independent", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "License :: OSI Approved :: MIT License", ], "name": "complete", "license": "MIT", "summary": "This is a test package for pyroma.", "home_page": "https://github.com/regebro/pyroma", "stable_version": None, "cheesecake_installability_id": None, } }, "release_urls": { ("complete", "1.0.dev1"): [ { "has_sig": False, "upload_time": datetime(2011, 3, 16, 16, 31, 39), "comment_text": "", "python_version": "source", "url": "http://pypi.python.org/packages/source/c/complete/complete-1.0.dev1.tar.gz", "md5_digest": "ea52e1412e7ff560c290266ed400e216", "downloads": 0, "filename": "complete-1.0.dev1.tar.gz", "packagetype": "sdist", "size": 289103, } ] }, "package_roles": {("complete",): [["Owner", "someone"], ["Owner", "me"], ["Owner", "other"]]}, } pyroma-5.0/pyroma/tests.py000066400000000000000000000317151503537372600157320ustar00rootroot00000000000000import io import json import os import unittest import unittest.mock from pkg_resources import resource_filename, resource_string from xmlrpc import client as xmlrpclib from pyroma import projectdata, distributiondata, pypidata from pyroma.ratings import rate long_description = resource_string(__name__, os.path.join("testdata", "complete", "README.txt")) if not isinstance(long_description, str): long_description = long_description.decode() # Translate newlines to universal format long_description = io.StringIO(long_description, newline=None).read() COMPLETE = { "metadata-version": "2.4", "name": "complete", "version": "1.0.dev1", "summary": "This is a test package for pyroma.", "description": long_description, "classifier": [ "Development Status :: 6 - Mature", "Operating System :: OS Independent", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "License :: OSI Approved :: MIT License", ], "dynamic": [ "author", "author-email", "classifier", "description", "home-page", "keywords", "license", "project-url", "requires-dist", "requires-python", "summary", ], "keywords": "pypi,quality,example", "author": "Lennart Regebro", "author-email": "regebro@gmail.com", "home-page": "https://github.com/regebro/pyroma", "project-url": "Source Code, https://github.com/regebro/pyroma", "requires-dist": "zope.event", "requires-python": ">=2.6", "license": "MIT", } class ProxyStub: def set_debug_context(self, dataname, real_class, developmode): filename = resource_filename(__name__, os.path.join("testdata", "xmlrpcdata", dataname)) data = {} with open(filename, encoding="UTF-8") as f: exec(f.read(), None, data) self.args = data["args"] self.kw = data["kw"] self._data = data["data"] if developmode: self._real = real_class(*self.args, **self.kw) else: self._real = None def __call__(self, *args, **kw): assert args == self.args assert kw == self.kw return self def _make_proxy(self, name): def _proxy_method(*args, **kw): return self._data[name][args] return _proxy_method def _make_unknown_proxy(self, name): def _proxy_method(*args, **kw): if self._real is None: raise AttributeError("ProxyStub unkown method " + name) print() print("== ProxyStub unknown method ==") print(name, ":", args, kw) result = getattr(self._real, name)(*args, **kw) print("Result :") print(result) return result return _proxy_method def __getattr__(self, attr): if attr in ("_data", "_make_proxy", "_make_unknown_proxy"): raise AttributeError("Break infinite recursion chain") if attr in self._data: return self._make_proxy(attr) return self._make_unknown_proxy(attr) def __enter__(self): return self def __exit__(self, type, value, traceback): return proxystub = ProxyStub() class RatingsTest(unittest.TestCase): maxDiff = None def _get_file_rating(self, dirname, skip_tests=None): directory = resource_filename(__name__, os.path.join("testdata", dirname)) data = projectdata.get_data(directory) return rate(data, skip_tests) def test_complete(self): rating = self._get_file_rating("complete") # Should have a perfect score self.assertEqual(rating, (10, [])) def test_setup_config(self): rating = self._get_file_rating("setup_config") self.assertEqual( rating, ( 9, [ "Your project does not have a pyproject.toml file, which is highly recommended.\n" "You probably want to create one with the following configuration:\n\n" " [build-system]\n" ' requires = ["setuptools>=42"]\n' ' build-backend = "setuptools.build_meta"\n', ], ), ) def test_only_config(self): # In version 5, this is now an error, as there is no legacy setup.py, # nor a modern pyproject.toml. rating = self._get_file_rating("only_config") self.assertEqual( rating, ( 5, [ "You seem to neither have a setup.py, nor a pyproject.toml, only setup.cfg.\n" "This makes it unclear how your project should be built, and some packaging " "tools may fail.", "Your project does not have a pyproject.toml file, which is highly " "recommended.\n" "You probably want to create one with the following configuration:\n\n" " [build-system]\n" ' requires = ["setuptools>=42"]\n' ' build-backend = "setuptools.build_meta"\n', "Specifying both a License-Expression and license classifiers is ambiguous, " "deprecated, and may be rejected by package indices.", "Check-manifest returned errors", ], ), ) def test_skip_tests(self): # Find all errors all_errors = self._get_file_rating("lacking")[1] fewer_errors = self._get_file_rating( "lacking", skip_tests=["PythonRequiresVersion", "Description", "Summary", "Classifiers"] )[1] self.assertEqual(len(all_errors), 13) # Errors have been skipped! self.assertEqual(len(fewer_errors), 9) def test_pep517(self): rating = self._get_file_rating("pep517") self.assertEqual( rating, ( 10, [], ), ) def test_pep621(self): rating = self._get_file_rating("pep621") self.assertEqual( rating, ( 10, [], ), ) def test_minimal(self): rating = self._get_file_rating("minimal") self.assertEqual( rating, ( 2, [ "The package's Summary should be longer than 10 characters.", "The package's Description is quite short.", "Your package does not have classifier data.", "The classifiers should specify what Python versions you support.", "You should specify what Python versions you support with " "the 'Requires-Python' metadata.", "Your package does not have keywords data.", "Your package does not have author data.", "Your package does not have author-email data.", "Your package should have a 'url' field with a link to the project home page, or a " "'project_urls' field, with a dictionary of links, or both.", "Your package does neither have a license field nor any license classifiers.", "Specifying a development status in the classifiers gives users " "a hint of how stable your software is.", "Check-manifest returned errors", ], ), ) def test_lacking(self): rating = self._get_file_rating("lacking") self.assertEqual( rating, ( 0, [ "Your project does not have a pyproject.toml file, which is highly recommended.\n" "You probably want to create one with the following configuration:\n\n" " [build-system]\n" ' requires = ["setuptools>=42"]\n' ' build-backend = "setuptools.build_meta"\n', "The package had no Summary!", "The package's Description is quite short.", "Your package does not have classifier data.", "The classifiers should specify what Python versions you support.", "You should specify what Python versions you support with " "the 'Requires-Python' metadata.", "Your package does not have keywords data.", "Your package does not have author data.", "Your package does not have author-email data.", "Your package should have a 'url' field with a link to the project home page, or a " "'project_urls' field, with a dictionary of links, or both.", "Your package does neither have a license field nor any license classifiers.", "Your Description is not valid ReST: \n:1: (WARNING/2) Inline literal " "start-string without end-string.", "Specifying a development status in the classifiers gives users " "a hint of how stable your software is.", ], ), ) def test_custom_test(self): rating = self._get_file_rating("custom_test") self.assertEqual( rating, ( 3, [ "The package's Summary should be longer than 10 characters.", "The package's Description is quite short.", "Your package does not have classifier data.", "The classifiers should specify what Python versions you support.", "You should specify what Python versions you support with " "the 'Requires-Python' metadata.", "Your package does not have keywords data.", "Your package does not have author data.", "Your package does not have author-email data.", "Your package should have a 'url' field with a link to the project home page, or a " "'project_urls' field, with a dictionary of links, or both.", "Your package does neither have a license field nor any license classifiers.", "Specifying a development status in the classifiers gives users " "a hint of how stable your software is.", ], ), ) def test_private_classifier(self): rating = self._get_file_rating("private_classifier") self.assertEqual(rating, (10, [])) def test_markdown(self): # Markdown and text shouldn't get ReST errors testdata = COMPLETE.copy() testdata["description"] = "# Broken ReST\n\n``Valid Markdown\n" testdata["description-content-type"] = "text/markdown" rating = rate(testdata) self.assertEqual(rating, (9, ["The package's Description is quite short."])) testdata["description-content-type"] = "text/plain" rating = rate(testdata) self.assertEqual(rating, (9, ["The package's Description is quite short."])) class PyPITest(unittest.TestCase): maxDiff = None @unittest.mock.patch("xmlrpc.client.ServerProxy", proxystub) @unittest.mock.patch("pyroma.pypidata._get_project_data") @unittest.mock.patch("requests.get") def test_complete(self, requestmock, projectdatamock): datafile = resource_filename(__name__, os.path.join("testdata", "jsondata", "complete.json")) with open(datafile, encoding="UTF-8") as file: projectdatamock.return_value = json.load(file) srcfile = resource_filename(__name__, os.path.join("testdata", "distributions", "complete-1.0.dev1.tar.gz")) with open(srcfile, "rb") as file: requestmock.return_value = unittest.mock.Mock() requestmock.return_value.content = file.read() proxystub.set_debug_context("completedata.py", xmlrpclib.ServerProxy, False) data = pypidata.get_data("complete") rating = rate(data) self.assertEqual(rating, (10, [])) class ProjectDataTest(unittest.TestCase): maxDiff = None def test_complete(self): directory = resource_filename(__name__, os.path.join("testdata", "complete")) data = projectdata.get_data(directory) del data["_path"] # This changes, so I just ignore it self.assertEqual(data, COMPLETE) class DistroDataTest(unittest.TestCase): maxDiff = None def test_complete(self): directory = resource_filename(__name__, os.path.join("testdata", "distributions")) for filename in os.listdir(directory): if filename.startswith("complete"): data = distributiondata.get_data(os.path.join(directory, filename)) self.assertEqual(data, COMPLETE) pyroma-5.0/setup.cfg000066400000000000000000000033241503537372600145230ustar00rootroot00000000000000[metadata] name = pyroma version = 5.0 description = Test your project's packaging friendliness long_description = file: README.rst, CHANGES.txt classifiers = Development Status :: 5 - Production/Stable Intended Audience :: Developers License :: OSI Approved :: MIT License Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 Programming Language :: Python :: 3.13 Programming Language :: Python :: 3.14 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy keywords = pypi, quality, testing author = Lennart Regebro author_email = regebro@gmail.com url = https://github.com/regebro/pyroma license = MIT project_urls = Source Code = https://github.com/regebro/pyroma [options] zip_safe = True include_package_data = True packages = find: package_dir = = . python_requires = >=3.9 install_requires = build>=0.7.0 docutils packaging pygments requests setuptools>=61 trove-classifiers>=2022.6.26 [options.packages.find] where = . [options.extras_require] test = pytest setuptools>=60 zest.releaser[recommended] flit_core>=3.4,<4 [options.entry_points] console_scripts = pyroma = pyroma:main zest.releaser.prereleaser.before = pyroma = pyroma:zester [flake8] max-line-length=120 [tool:pytest] testpaths = pyroma/tests.py [check-manifest] ignore = .pre-commit-hooks.yaml [zest.releaser] create-wheel = yes pyroma-5.0/setup.py000066400000000000000000000000461503537372600144120ustar00rootroot00000000000000from setuptools import setup setup() pyroma-5.0/tox.ini000066400000000000000000000004031503537372600142100ustar00rootroot00000000000000[tox] requires = tox>=4.2 env_list = py{py3, 314, 313, 312, 311, 310, 39} [testenv] extras = test pass_env = FORCE_COLOR commands = {envpython} -bb -X dev \ -W ignore::UserWarning:setuptools.dist \ -m pytest \ {posargs}