tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

check.py (4345B)


      1 # This file is dual licensed under the terms of the Apache License, Version
      2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
      3 # for complete details.
      4 
      5 import itertools
      6 import json
      7 import os.path
      8 import xmlrpc.client
      9 
     10 import invoke
     11 import pkg_resources
     12 import progress.bar
     13 
     14 from packaging.version import Version
     15 
     16 from .paths import CACHE
     17 
     18 
     19 def _parse_version(value):
     20    try:
     21        return Version(value)
     22    except ValueError:
     23        return None
     24 
     25 
     26 @invoke.task
     27 def pep440(cached=False):
     28    cache_path = os.path.join(CACHE, "pep440.json")
     29 
     30    # If we were given --cached, then we want to attempt to use cached data if
     31    # possible
     32    if cached:
     33        try:
     34            with open(cache_path) as fp:
     35                data = json.load(fp)
     36        except Exception:
     37            data = None
     38    else:
     39        data = None
     40 
     41    # If we don't have data, then let's go fetch it from PyPI
     42    if data is None:
     43        bar = progress.bar.ShadyBar("Fetching Versions")
     44        client = xmlrpc.client.Server("https://pypi.python.org/pypi")
     45 
     46        data = {
     47            project: client.package_releases(project, True)
     48            for project in bar.iter(client.list_packages())
     49        }
     50 
     51        os.makedirs(os.path.dirname(cache_path), exist_ok=True)
     52        with open(cache_path, "w") as fp:
     53            json.dump(data, fp)
     54 
     55    # Get a list of all of the version numbers on PyPI
     56    all_versions = list(itertools.chain.from_iterable(data.values()))
     57 
     58    # Determine the total number of versions which are compatible with the
     59    # current routine
     60    parsed_versions = [
     61        _parse_version(v) for v in all_versions if _parse_version(v) is not None
     62    ]
     63 
     64    # Determine a list of projects that sort exactly the same between
     65    # pkg_resources and PEP 440
     66    compatible_sorting = [
     67        project
     68        for project, versions in data.items()
     69        if (
     70            sorted(versions, key=pkg_resources.parse_version)
     71            == sorted((x for x in versions if _parse_version(x)), key=Version)
     72        )
     73    ]
     74 
     75    # Determine a list of projects that sort exactly the same between
     76    # pkg_resources and PEP 440 when invalid versions are filtered out
     77    filtered_compatible_sorting = [
     78        project
     79        for project, versions in (
     80            (p, [v for v in vs if _parse_version(v) is not None])
     81            for p, vs in data.items()
     82        )
     83        if (
     84            sorted(versions, key=pkg_resources.parse_version)
     85            == sorted(versions, key=Version)
     86        )
     87    ]
     88 
     89    # Determine a list of projects which do not have any versions that are
     90    # valid with PEP 440 and which have any versions registered
     91    only_invalid_versions = [
     92        project
     93        for project, versions in data.items()
     94        if (versions and not [v for v in versions if _parse_version(v) is not None])
     95    ]
     96 
     97    # Determine a list of projects which have matching latest versions between
     98    # pkg_resources and PEP 440
     99    differing_latest_versions = [
    100        project
    101        for project, versions in data.items()
    102        if (
    103            sorted(versions, key=pkg_resources.parse_version)[-1:]
    104            != sorted((x for x in versions if _parse_version(x)), key=Version)[-1:]
    105        )
    106    ]
    107 
    108    # Print out our findings
    109    print(
    110        "Total Version Compatibility:              {}/{} ({:.2%})".format(
    111            len(parsed_versions),
    112            len(all_versions),
    113            len(parsed_versions) / len(all_versions),
    114        )
    115    )
    116    print(
    117        "Total Sorting Compatibility (Unfiltered): {}/{} ({:.2%})".format(
    118            len(compatible_sorting), len(data), len(compatible_sorting) / len(data)
    119        )
    120    )
    121    print(
    122        "Total Sorting Compatibility (Filtered):   {}/{} ({:.2%})".format(
    123            len(filtered_compatible_sorting),
    124            len(data),
    125            len(filtered_compatible_sorting) / len(data),
    126        )
    127    )
    128    print(
    129        "Projects with No Compatible Versions:     {}/{} ({:.2%})".format(
    130            len(only_invalid_versions),
    131            len(data),
    132            len(only_invalid_versions) / len(data),
    133        )
    134    )
    135    print(
    136        "Projects with Differing Latest Version:   {}/{} ({:.2%})".format(
    137            len(differing_latest_versions),
    138            len(data),
    139            len(differing_latest_versions) / len(data),
    140        )
    141    )