Skip to content

Commit b308ad3

Browse files
committed
update requirements
1 parent 9842f42 commit b308ad3

File tree

2 files changed

+140
-1
lines changed

2 files changed

+140
-1
lines changed

requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# This file is auto-generated from py3.6.yml, do not modify.
22
# See that file for comments about the need/usage of each dependency.
33

4-
owslib
4+
dataclasses
55
pip
6+
pygeoogc
67
rasterio
8+
scipy
79
shapely
810
xarray
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/env python
2+
"""Convert the conda py3.6.yml to the pip requirements-dev.txt.
3+
4+
It also checks that they have the same packages (for the CI).
5+
The original script is taken from Pandas github repository.
6+
https://github.com/pandas-dev/pandas/blob/master/scripts/generate_pip_deps_from_conda.py.
7+
8+
Usage
9+
-----
10+
11+
Generate `requirements-dev.txt`
12+
$ ./generate_pip_deps_from_conda.py
13+
14+
Compare and fail (exit status != 0) if `requirements-dev.txt` has not been
15+
generated with this script:
16+
$ ./generate_pip_deps_from_conda.py --compare
17+
"""
18+
import argparse
19+
import os
20+
import re
21+
import sys
22+
23+
import yaml
24+
25+
EXCLUDE = {"python"}
26+
RENAME = {
27+
"pytables": "tables",
28+
"pyqt": "pyqt5",
29+
"dask-core": "dask",
30+
"matplotlib-base": "matplotlib",
31+
"seaborn-base": "seaborn",
32+
}
33+
34+
35+
def conda_package_to_pip(package):
36+
"""Convert a conda package to its pip equivalent.
37+
38+
In most cases they are the same, those are the exceptions:
39+
- Packages that should be excluded (in `EXCLUDE`)
40+
- Packages that should be renamed (in `RENAME`)
41+
- A package requiring a specific version, in conda is defined with a single
42+
equal (e.g. ``pandas=1.0``) and in pip with two (e.g. ``pandas==1.0``)
43+
"""
44+
package = re.sub("(?<=[^<>])=", "==", package).strip()
45+
46+
for compare in ("<=", ">=", "=="):
47+
if compare not in package:
48+
continue
49+
50+
pkg, version = package.split(compare)
51+
if pkg in EXCLUDE:
52+
return
53+
54+
if pkg in RENAME:
55+
return "".join((RENAME[pkg], compare, version))
56+
57+
break
58+
59+
if package in RENAME:
60+
return RENAME[package]
61+
62+
return package
63+
64+
65+
def main(conda_fname, pip_fname, compare=False):
66+
"""Generate the pip dependencies file from the conda file.
67+
68+
It also compares that they are synchronized (``compare=True``).
69+
70+
Parameters
71+
----------
72+
conda_fname : str
73+
Path to the conda file with dependencies (e.g. `py3.6.yml`).
74+
pip_fname : str
75+
Path to the pip file with dependencies (e.g. `requirements-dev.txt`).
76+
compare : bool, default False
77+
Whether to generate the pip file (``False``) or to compare if the
78+
pip file has been generated with this script and the last version
79+
of the conda file (``True``).
80+
81+
Returns
82+
-------
83+
bool
84+
True if the comparison fails, False otherwise
85+
"""
86+
with open(conda_fname) as conda_fd:
87+
deps = yaml.safe_load(conda_fd)["dependencies"]
88+
89+
pip_deps = []
90+
for dep in deps:
91+
if isinstance(dep, str):
92+
conda_dep = conda_package_to_pip(dep)
93+
if conda_dep:
94+
pip_deps.append(conda_dep)
95+
elif isinstance(dep, dict) and len(dep) == 1 and "pip" in dep:
96+
pip_deps += dep["pip"]
97+
else:
98+
raise ValueError(f"Unexpected dependency {dep}")
99+
100+
fname = os.path.split(conda_fname)[1]
101+
header = (
102+
f"# This file is auto-generated from {fname}, do not modify.\n"
103+
"# See that file for comments about the need/usage of each dependency.\n\n"
104+
)
105+
pip_content = header + "\n".join(pip_deps)
106+
107+
if compare:
108+
with open(pip_fname) as pip_fd:
109+
return pip_content != pip_fd.read()
110+
else:
111+
with open(pip_fname, "w") as pip_fd:
112+
pip_fd.write(pip_content)
113+
return False
114+
115+
116+
if __name__ == "__main__":
117+
argparser = argparse.ArgumentParser(description="convert (or compare) conda file to pip")
118+
argparser.add_argument(
119+
"--compare", action="store_true", help="compare whether the two files are equivalent",
120+
)
121+
args = argparser.parse_args()
122+
123+
repo_path = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
124+
res = main(
125+
os.path.join(repo_path, "ci/requirements/py3.6.yml"),
126+
os.path.join(repo_path, "requirements.txt"),
127+
compare=args.compare,
128+
)
129+
if res:
130+
msg = (
131+
f"`requirements-dev.txt` has to be generated with `{sys.argv[0]}` after "
132+
"`py3.6.yml` is modified.\n"
133+
)
134+
if args.azure:
135+
msg = f"##vso[task.logissue type=error;sourcepath=requirements-dev.txt]{msg}"
136+
sys.stderr.write(msg)
137+
sys.exit(res)

0 commit comments

Comments
 (0)