1"""A CLI to evaluate env markers for requirements files.
2
3A simple script to evaluate the `requirements.txt` files. Currently it is only
4handling environment markers in the requirements files, but in the future it
5may handle more things. We require a `python` interpreter that can run on the
6host platform and then we depend on the [packaging] PyPI wheel.
7
8In order to be able to resolve requirements files for any platform, we are
9re-using the same code that is used in the `whl_library` installer. See
10[here](../whl_installer/wheel.py).
11
12Requirements for the code are:
13- Depends only on `packaging` and core Python.
14- Produces the same result irrespective of the Python interpreter platform or version.
15
16[packaging]: https://packaging.pypa.io/en/stable/
17"""
18
19import argparse
20import json
21import pathlib
22
23from packaging.requirements import Requirement
24
25from python.private.pypi.whl_installer.platform import Platform
26
27INPUT_HELP = """\
28Input path to read the requirements as a json file, the keys in the dictionary
29are the requirements lines and the values are strings of target platforms.
30"""
31OUTPUT_HELP = """\
32Output to write the requirements as a json filepath, the keys in the dictionary
33are the requirements lines and the values are strings of target platforms, which
34got changed based on the evaluated markers.
35"""
36
37
38def main():
39    parser = argparse.ArgumentParser(description=__doc__)
40    parser.add_argument("input_path", type=pathlib.Path, help=INPUT_HELP.strip())
41    parser.add_argument("output_path", type=pathlib.Path, help=OUTPUT_HELP.strip())
42    args = parser.parse_args()
43
44    with args.input_path.open() as f:
45        reqs = json.load(f)
46
47    response = {}
48    for requirement_line, target_platforms in reqs.items():
49        entry, prefix, hashes = requirement_line.partition("--hash")
50        hashes = prefix + hashes
51
52        req = Requirement(entry)
53        for p in target_platforms:
54            (platform,) = Platform.from_string(p)
55            if not req.marker or req.marker.evaluate(platform.env_markers("")):
56                response.setdefault(requirement_line, []).append(p)
57
58    with args.output_path.open("w") as f:
59        json.dump(response, f)
60
61
62if __name__ == "__main__":
63    main()
64