Skip to content

Commit

Permalink
Merge 0a98e15 into 259ea5f
Browse files Browse the repository at this point in the history
  • Loading branch information
ZwwWayne authored Aug 21, 2021
2 parents 259ea5f + 0a98e15 commit 010f398
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 37 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,72 @@ jobs:
name: codecov-umbrella
fail_ci_if_error: false

build_windows_without_ops:
runs-on: windows-latest
env:
MMCV_WITH_OPS: 0
strategy:
matrix:
torch: [1.7.1, 1.8.0, 1.9.0]
include:
- torch: 1.7.1
torchvision: 0.8.2
- torch: 1.8.0
torchvision: 0.9.0
- torch: 1.9.0
torchvision: 0.10.0
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Pillow
run: pip install Pillow==6.2.2
if: ${{matrix.torchvision == '0.4.2'}}
- name: Install PyTorch
run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu --no-cache-dir -f https://download.pytorch.org/whl/torch_stable.html
- name: Build and install
run: pip install -e .
- name: Validate the installation
run: python -c "import mmcv"
- name: Run unittests
run: |
pip install -r requirements/test.txt
pytest tests/ --ignore=tests/test_ops --ignore tests/test_utils/test_progressbar.py --ignore tests/test_utils/test_timer.py --ignore tests/test_image/test_io.py
build_windows:
runs-on: windows-latest
strategy:
matrix:
torch: [1.7.1, 1.8.0, 1.9.0]
include:
- torch: 1.7.1
torchvision: 0.8.2
- torch: 1.8.0
torchvision: 0.9.0
- torch: 1.9.0
torchvision: 0.10.0
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install Pillow
run: pip install Pillow==6.2.2
if: ${{matrix.torchvision == '0.4.2'}}
- name: Install PyTorch
run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu --no-cache-dir -f https://download.pytorch.org/whl/torch_stable.html
- name: Build and install
run: pip install -e .
- name: Validate the installation
run: python -c "import mmcv"
- name: Run unittests
run: |
pip install -r requirements/test.txt
pytest tests/ --ignore tests/test_utils/test_progressbar.py --ignore tests/test_utils/test_timer.py --ignore tests/test_image/test_io.py
build_macos:
runs-on: macos-latest
strategy:
Expand Down
4 changes: 3 additions & 1 deletion mmcv/runner/hooks/logger/pavi.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ def log(self, runner):
def after_run(self, runner):
if self.add_last_ckpt:
ckpt_path = osp.join(runner.work_dir, 'latest.pth')
if osp.isfile(ckpt_path):
if osp.islink(ckpt_path):
ckpt_path = osp.join(runner.work_dir, os.readlink(ckpt_path))

if osp.isfile(ckpt_path):
# runner.epoch += 1 has been done before `after_run`.
iteration = runner.epoch if self.by_epoch else runner.iter
return self.writer.add_snapshot_file(
Expand Down
3 changes: 2 additions & 1 deletion mmcv/video/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def concat_video(video_list,
log_level (str): Logging level of ffmpeg.
print_cmd (bool): Whether to print the final ffmpeg command.
"""
_, tmp_filename = tempfile.mkstemp(suffix='.txt', text=True)
tmp_filehandler, tmp_filename = tempfile.mkstemp(suffix='.txt', text=True)
with open(tmp_filename, 'w') as f:
for filename in video_list:
f.write(f'file {osp.abspath(filename)}\n')
Expand All @@ -156,4 +156,5 @@ def concat_video(video_list,
print_cmd,
pre_options='-f concat -safe 0',
**options)
os.close(tmp_filehandler)
os.remove(tmp_filename)
8 changes: 7 additions & 1 deletion tests/test_runner/test_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""
import logging
import os.path as osp
import platform
import random
import re
import shutil
Expand Down Expand Up @@ -208,9 +209,14 @@ def test_pavi_hook():
'learning_rate': 0.02,
'momentum': 0.95
}, 1)
# in windows environment, the latest checkpoint is copied from epoch_1.pth
if platform.system() == 'Windows':
snapshot_file_path = osp.join(runner.work_dir, 'latest.pth')
else:
snapshot_file_path = osp.join(runner.work_dir, 'epoch_1.pth')
hook.writer.add_snapshot_file.assert_called_with(
tag=runner.work_dir.split('/')[-1],
snapshot_file_path=osp.join(runner.work_dir, 'epoch_1.pth'),
snapshot_file_path=snapshot_file_path,
iteration=1)


Expand Down
8 changes: 7 additions & 1 deletion tests/test_runner/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import os
import os.path as osp
import platform
import random
import string
import tempfile
Expand Down Expand Up @@ -169,7 +170,12 @@ def test_save_checkpoint(runner_class):
first_ckp_path = osp.join(root, 'iter_1.pth')

assert osp.exists(first_ckp_path)
assert osp.realpath(latest_path) == osp.realpath(first_ckp_path)

if platform.system() != 'Windows':
assert osp.realpath(latest_path) == osp.realpath(first_ckp_path)
else:
# use copy instead of symlink on windows
pass

torch.load(latest_path)

Expand Down
27 changes: 17 additions & 10 deletions tests/test_utils/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os.path as osp
import shutil
import tempfile
from pathlib import Path

import pytest
import yaml
Expand Down Expand Up @@ -66,10 +67,14 @@ def test_construct():

# test h.py
cfg_file = osp.join(data_path, 'config/h.py')
cfg_dict = dict(
item1='h.py',
item2=f'{osp.dirname(__file__)}/data/config',
item3='abc_h')
path = osp.join(osp.dirname(__file__), 'data', 'config')
# the value of osp.dirname(__file__) may be `D:\a\xxx` in windows
# environment. When dumping the cfg_dict to file, `D:\a\xxx` will be
# converted to `D:\x07\xxx` and it will cause unexpected result when
# checking whether `D:\a\xxx` equals to `D:\x07\xxx`. Therefore, we forcely
# convert a string representation of the path with forward slashes (/)
path = Path(path).as_posix()
cfg_dict = dict(item1='h.py', item2=path, item3='abc_h')
cfg = Config(cfg_dict, filename=cfg_file)
assert isinstance(cfg, Config)
assert cfg.filename == cfg_file
Expand All @@ -96,7 +101,7 @@ def test_construct():

# test p.yaml
cfg_file = osp.join(data_path, 'config/p.yaml')
cfg_dict = dict(item1=f'{osp.dirname(__file__)}/data/config')
cfg_dict = dict(item1=osp.join(osp.dirname(__file__), 'data', 'config'))
cfg = Config(cfg_dict, filename=cfg_file)
assert isinstance(cfg, Config)
assert cfg.filename == cfg_file
Expand All @@ -115,7 +120,7 @@ def test_construct():

# test o.json
cfg_file = osp.join(data_path, 'config/o.json')
cfg_dict = dict(item1=f'{osp.dirname(__file__)}/data/config')
cfg_dict = dict(item1=osp.join(osp.dirname(__file__), 'data', 'config'))
cfg = Config(cfg_dict, filename=cfg_file)
assert isinstance(cfg, Config)
assert cfg.filename == cfg_file
Expand Down Expand Up @@ -490,17 +495,19 @@ def test_reserved_key():


def test_syntax_error():
temp_cfg_file = tempfile.NamedTemporaryFile(suffix='.py')
# the name can not be used to open the file a second time in windows,
# so `delete` should be set as `False` and we need to manually remove it
# more details can be found at https://github.com/open-mmlab/mmcv/pull/1077
temp_cfg_file = tempfile.NamedTemporaryFile(suffix='.py', delete=False)
temp_cfg_path = temp_cfg_file.name
# write a file with syntax error
with open(temp_cfg_path, 'w') as f:
f.write('a=0b=dict(c=1)')
with pytest.raises(
SyntaxError,
match='There are syntax errors in config '
f'file {temp_cfg_path}'):
SyntaxError, match='There are syntax errors in config file'):
Config.fromfile(temp_cfg_path)
temp_cfg_file.close()
os.remove(temp_cfg_path)


def test_pickle_support():
Expand Down
45 changes: 33 additions & 12 deletions tests/test_utils/test_logging.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import os
import platform
import tempfile
from unittest.mock import patch
Expand Down Expand Up @@ -28,15 +29,21 @@ def test_get_logger_rank0():
assert len(logger.handlers) == 1
assert logger.handlers[0].level == logging.DEBUG

with tempfile.NamedTemporaryFile() as f:
# the name can not be used to open the file a second time in windows,
# so `delete` should be set as `False` and we need to manually remove it
# more details can be found at https://github.com/open-mmlab/mmcv/pull/1077
with tempfile.NamedTemporaryFile(delete=False) as f:
logger = get_logger('rank0.pkg3', log_file=f.name)
assert isinstance(logger, logging.Logger)
assert len(logger.handlers) == 2
assert isinstance(logger.handlers[0], logging.StreamHandler)
assert isinstance(logger.handlers[1], logging.FileHandler)
assert isinstance(logger, logging.Logger)
assert len(logger.handlers) == 2
assert isinstance(logger.handlers[0], logging.StreamHandler)
assert isinstance(logger.handlers[1], logging.FileHandler)
logger_pkg3 = get_logger('rank0.pkg3')
assert id(logger_pkg3) == id(logger)
# flushing and closing all handlers in order to remove `f.name`
logging.shutdown()

logger_pkg3 = get_logger('rank0.pkg3')
assert id(logger_pkg3) == id(logger)
os.remove(f.name)

logger_pkg3 = get_logger('rank0.pkg3.subpkg')
assert logger_pkg3.handlers == logger_pkg3.handlers
Expand All @@ -52,11 +59,18 @@ def test_get_logger_rank1():
assert isinstance(logger.handlers[0], logging.StreamHandler)
assert logger.handlers[0].level == logging.INFO

with tempfile.NamedTemporaryFile() as f:
# the name can not be used to open the file a second time in windows,
# so `delete` should be set as `False` and we need to manually remove it
# more details can be found at https://github.com/open-mmlab/mmcv/pull/1077
with tempfile.NamedTemporaryFile(delete=False) as f:
logger = get_logger('rank1.pkg2', log_file=f.name)
assert isinstance(logger, logging.Logger)
assert len(logger.handlers) == 1
assert logger.handlers[0].level == logging.INFO
assert isinstance(logger, logging.Logger)
assert len(logger.handlers) == 1
assert logger.handlers[0].level == logging.INFO
# flushing and closing all handlers in order to remove `f.name`
logging.shutdown()

os.remove(f.name)


def test_print_log_print(capsys):
Expand All @@ -79,7 +93,10 @@ def test_print_log_logger(caplog):
print_log('welcome', logger='mmcv', level=logging.ERROR)
assert caplog.record_tuples[-1] == ('mmcv', logging.ERROR, 'welcome')

with tempfile.NamedTemporaryFile() as f:
# the name can not be used to open the file a second time in windows,
# so `delete` should be set as `False` and we need to manually remove it
# more details can be found at https://github.com/open-mmlab/mmcv/pull/1077
with tempfile.NamedTemporaryFile(delete=False) as f:
logger = get_logger('abc', log_file=f.name)
print_log('welcome', logger=logger)
assert caplog.record_tuples[-1] == ('abc', logging.INFO, 'welcome')
Expand All @@ -89,6 +106,10 @@ def test_print_log_logger(caplog):
match = re.fullmatch(regex_time + r' - abc - INFO - welcome\n',
log_text)
assert match is not None
# flushing and closing all handlers in order to remove `f.name`
logging.shutdown()

os.remove(f.name)


def test_print_log_exception():
Expand Down
7 changes: 5 additions & 2 deletions tests/test_utils/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ def test_scandir():
])
assert set(mmcv.scandir(folder, '.png')) == set()

# path of sep is `\\` in windows but `/` in linux, so osp.join should be
# used to join string for compatibility
filenames_recursive = [
'a.bin', '1.txt', '2.txt', '1.json', '2.json', 'sub/1.json',
'sub/1.txt', '.file'
'a.bin', '1.txt', '2.txt', '1.json', '2.json',
osp.join('sub', '1.json'),
osp.join('sub', '1.txt'), '.file'
]
# .file starts with '.' and is a file so it will not be scanned
assert set(mmcv.scandir(folder, recursive=True)) == set(
Expand Down
3 changes: 2 additions & 1 deletion tests/test_video/test_optflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ def test_flowwrite():
flow = np.random.rand(100, 100, 2).astype(np.float32)

# write to a .flo file
_, filename = tempfile.mkstemp()
tmp_filehandler, filename = tempfile.mkstemp()
mmcv.flowwrite(flow, filename)
flow_from_file = mmcv.flowread(filename)
assert_array_equal(flow, flow_from_file)
os.close(tmp_filehandler)
os.remove(filename)

# write to two .jpg files
Expand Down
5 changes: 5 additions & 0 deletions tests/test_video/test_processing.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Copyright (c) OpenMMLab. All rights reserved.
import os
import os.path as osp
import platform
import tempfile

import pytest

import mmcv


Expand All @@ -13,6 +16,7 @@ def setup_class(cls):
cls.video_path = osp.join(osp.dirname(__file__), '../data/test.mp4')
cls.num_frames = 168

@pytest.mark.skipif(platform.system() == 'Windows', reason='skip windows')
def test_cut_concat_video(self):
part1_file = osp.join(tempfile.gettempdir(), '.mmcv_test1.mp4')
part2_file = osp.join(tempfile.gettempdir(), '.mmcv_test2.mp4')
Expand All @@ -31,6 +35,7 @@ def test_cut_concat_video(self):
os.remove(part2_file)
os.remove(out_file)

@pytest.mark.skipif(platform.system() == 'Windows', reason='skip windows')
def test_resize_video(self):
out_file = osp.join(tempfile.gettempdir(), '.mmcv_test.mp4')
mmcv.resize_video(
Expand Down
16 changes: 8 additions & 8 deletions tests/test_video/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,12 @@ def test_frames2video(self):
start=10,
end=50,
show_progress=False)
v = mmcv.VideoReader(out_filename)
assert v.fps == 25
assert len(v) == 40

for i in range(self.num_frames):
filename = f'{frame_dir}/{i:06d}.jpg'
os.remove(filename)
shutil.rmtree(frame_dir)
os.remove(out_filename)
with mmcv.VideoReader(out_filename) as v:
assert v.fps == 25
assert len(v) == 40

for i in range(self.num_frames):
filename = f'{frame_dir}/{i:06d}.jpg'
os.remove(filename)
shutil.rmtree(frame_dir)

0 comments on commit 010f398

Please sign in to comment.