Skip to content

Commit 7324f27

Browse files
Erotemichellock
authored andcommitted
Reorganize requirements, make albumentations optional (open-mmlab#1969)
* reorganize requirements, make albumentations optional * fix flake8 error * force older version of Pillow until torchvision is fixed * make imagecorruptions optional and update INSTALL.dm * update INSTALL.md * Add note about pillow version * Add build requirements to install instructions
1 parent f82c8d4 commit 7324f27

File tree

9 files changed

+138
-30
lines changed

9 files changed

+138
-30
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ install:
2727
- pip install Pillow==6.2.2 # remove this line when torchvision>=0.5
2828
- pip install Cython torch==1.2 torchvision==0.4.0 # TODO: fix CI for pytorch>1.2
2929
- pip install -r requirements.txt
30-
- pip install -r tests/requirements.txt
3130

3231
before_script:
3332
- flake8 .

docs/INSTALL.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ git clone https://github.com/open-mmlab/mmdetection.git
3939
cd mmdetection
4040
```
4141

42-
d. Install mmdetection (other dependencies will be installed automatically).
42+
d. Install build requirements and then install mmdetection.
4343

4444
```shell
45-
pip install mmcv
46-
python setup.py develop # or "pip install -v -e ."
45+
pip install -r requirements/build.txt
46+
pip install -v -e . # or "python setup.py develop"
4747
```
4848

4949
Note:
@@ -56,6 +56,8 @@ It is recommended that you run step d each time you pull some updates from githu
5656
3. If you would like to use `opencv-python-headless` instead of `opencv-python`,
5757
you can install it before installing MMCV.
5858

59+
4. Some dependencies are optional. Simply running `pip install -v -e .` will only install the minimum runtime requirements. To use optional dependencies like `albumentations` and `imagecorruptions` either install them manually with `pip install -r requirements/optional.txt` or specify desired extras when calling `pip` (e.g. `pip install -v -e .[optional]`). Valid keys for the extras field are: `all`, `tests`, `build`, and `optional`.
60+
5961
### Another option: Docker Image
6062

6163
We provide a [Dockerfile](https://github.com/open-mmlab/mmdetection/blob/master/docker/Dockerfile) to build an image.

mmdet/datasets/pipelines/transforms.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import inspect
22

3-
import albumentations
43
import mmcv
54
import numpy as np
6-
from albumentations import Compose
7-
from imagecorruptions import corrupt
85
from numpy import random
96

107
from mmdet.core.evaluation.bbox_overlaps import bbox_overlaps
118
from ..registry import PIPELINES
129

10+
try:
11+
from imagecorruptions import corrupt
12+
except ImportError:
13+
corrupt = None
14+
15+
try:
16+
import albumentations
17+
from albumentations import Compose
18+
except ImportError:
19+
albumentations = None
20+
Compose = None
21+
1322

1423
@PIPELINES.register_module
1524
class Resize(object):
@@ -695,6 +704,8 @@ def __init__(self, corruption, severity=1):
695704
self.severity = severity
696705

697706
def __call__(self, results):
707+
if corrupt is None:
708+
raise RuntimeError('imagecorruptions is not installed')
698709
results['img'] = corrupt(
699710
results['img'].astype(np.uint8),
700711
corruption_name=self.corruption,
@@ -728,6 +739,8 @@ def __init__(self,
728739
skip_img_without_anno (bool): whether to skip the image
729740
if no ann left after aug
730741
"""
742+
if Compose is None:
743+
raise RuntimeError('albumentations is not installed')
731744

732745
self.transforms = transforms
733746
self.filter_lost_elements = False
@@ -771,6 +784,8 @@ def albu_builder(self, cfg):
771784

772785
obj_type = args.pop("type")
773786
if mmcv.is_str(obj_type):
787+
if albumentations is None:
788+
raise RuntimeError('albumentations is not installed')
774789
obj_cls = getattr(albumentations, obj_type)
775790
elif inspect.isclass(obj_type):
776791
obj_cls = obj_type

requirements.txt

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
albumentations>=0.3.2
2-
imagecorruptions
3-
matplotlib
4-
mmcv>=0.2.16
5-
numpy
6-
pycocotools
7-
six
8-
terminaltables
9-
torch>=1.1
10-
torchvision
1+
-r requirements/runtime.txt
2+
-r requirements/optional.txt
3+
-r requirements/tests.txt
4+
-r requirements/build.txt

requirements/build.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# These must be installed before building mmdetection
2+
cython
3+
numpy
4+
torch>=1.1

requirements/optional.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
albumentations>=0.3.2
2+
imagecorruptions

requirements/runtime.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
matplotlib
2+
mmcv>=0.2.15
3+
numpy
4+
pycocotools
5+
six
6+
terminaltables
7+
torch>=1.1
8+
torchvision
9+
10+
# need older pillow until torchvision is fixed
11+
Pillow<=6.2.2
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
isort
1+
asynctest
2+
codecov
23
flake8
3-
yapf
4+
isort
5+
pytest
46
pytest-cov
5-
codecov
7+
pytest-runner
68
xdoctest >= 0.10.0
7-
asynctest
8-
9+
yapf
910
# Note: used for kwarray.group_items, this may be ported to mmcv in the future.
1011
kwarray

setup.py

100644100755
Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
13
import os
24
import platform
35
import subprocess
@@ -131,11 +133,83 @@ def make_cython_ext(name, module, sources):
131133
return extension
132134

133135

134-
def get_requirements(filename='requirements.txt'):
135-
here = os.path.dirname(os.path.realpath(__file__))
136-
with open(os.path.join(here, filename), 'r') as f:
137-
requires = [line.replace('\n', '') for line in f.readlines()]
138-
return requires
136+
def parse_requirements(fname='requirements.txt', with_version=True):
137+
"""
138+
Parse the package dependencies listed in a requirements file but strips
139+
specific versioning information.
140+
141+
Args:
142+
fname (str): path to requirements file
143+
with_version (bool, default=False): if True include version specs
144+
145+
Returns:
146+
List[str]: list of requirements items
147+
148+
CommandLine:
149+
python -c "import setup; print(setup.parse_requirements())"
150+
"""
151+
import sys
152+
from os.path import exists
153+
import re
154+
require_fpath = fname
155+
156+
def parse_line(line):
157+
"""
158+
Parse information from a line in a requirements text file
159+
"""
160+
if line.startswith('-r '):
161+
# Allow specifying requirements in other files
162+
target = line.split(' ')[1]
163+
for info in parse_require_file(target):
164+
yield info
165+
else:
166+
info = {'line': line}
167+
if line.startswith('-e '):
168+
info['package'] = line.split('#egg=')[1]
169+
else:
170+
# Remove versioning from the package
171+
pat = '(' + '|'.join(['>=', '==', '>']) + ')'
172+
parts = re.split(pat, line, maxsplit=1)
173+
parts = [p.strip() for p in parts]
174+
175+
info['package'] = parts[0]
176+
if len(parts) > 1:
177+
op, rest = parts[1:]
178+
if ';' in rest:
179+
# Handle platform specific dependencies
180+
# http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies
181+
version, platform_deps = map(str.strip,
182+
rest.split(';'))
183+
info['platform_deps'] = platform_deps
184+
else:
185+
version = rest # NOQA
186+
info['version'] = (op, version)
187+
yield info
188+
189+
def parse_require_file(fpath):
190+
with open(fpath, 'r') as f:
191+
for line in f.readlines():
192+
line = line.strip()
193+
if line and not line.startswith('#'):
194+
for info in parse_line(line):
195+
yield info
196+
197+
def gen_packages_items():
198+
if exists(require_fpath):
199+
for info in parse_require_file(require_fpath):
200+
parts = [info['package']]
201+
if with_version and 'version' in info:
202+
parts.extend(info['version'])
203+
if not sys.version.startswith('3.4'):
204+
# apparently package_deps are broken in 3.4
205+
platform_deps = info.get('platform_deps')
206+
if platform_deps is not None:
207+
parts.append(';' + platform_deps)
208+
item = ''.join(parts)
209+
yield item
210+
211+
packages = list(gen_packages_items())
212+
return packages
139213

140214

141215
if __name__ == '__main__':
@@ -161,9 +235,15 @@ def get_requirements(filename='requirements.txt'):
161235
'Programming Language :: Python :: 3.7',
162236
],
163237
license='Apache License 2.0',
164-
setup_requires=['pytest-runner', 'cython', 'numpy'],
165-
tests_require=['pytest', 'xdoctest', 'asynctest'],
166-
install_requires=get_requirements(),
238+
setup_requires=parse_requirements('requirements/build.txt'),
239+
tests_require=parse_requirements('requirements/tests.txt'),
240+
install_requires=parse_requirements('requirements/runtime.txt'),
241+
extras_require={
242+
'all': parse_requirements('requirements.txt'),
243+
'tests': parse_requirements('requirements/tests.txt'),
244+
'build': parse_requirements('requirements/build.txt'),
245+
'optional': parse_requirements('requirements/optional.txt'),
246+
},
167247
ext_modules=[
168248
make_cuda_ext(
169249
name='compiling_info',

0 commit comments

Comments
 (0)