[wip] Fix loading YAML config from another directory

Bugs: FFmpeg writes to file named "-"
pull/357/head
nyanpasu64 2018-08-27 04:48:35 -07:00
rodzic 590aad12ba
commit ba17f64618
7 zmienionych plików z 48 dodań i 35 usunięć

Wyświetl plik

@ -1,3 +1,4 @@
from os.path import abspath
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from ovgenpy.config import register_config, Alias from ovgenpy.config import register_config, Alias
@ -42,7 +43,7 @@ class Channel:
# Create a Wave object. # Create a Wave object.
wcfg = _WaveConfig(amplification=ovgen_cfg.amplification * cfg.ampl_ratio) wcfg = _WaveConfig(amplification=ovgen_cfg.amplification * cfg.ampl_ratio)
self.wave = Wave(wcfg, cfg.wav_path) self.wave = Wave(wcfg, abspath(cfg.wav_path))
# Compute subsampling (array stride). # Compute subsampling (array stride).
tw = coalesce(cfg.trigger_width, ovgen_cfg.trigger_width) tw = coalesce(cfg.trigger_width, ovgen_cfg.trigger_width)

Wyświetl plik

@ -86,6 +86,7 @@ def main(
# Create cfg: Config object. # Create cfg: Config object.
cfg: Config = None cfg: Config = None
cfg_dir: str = None
wav_list: List[Path] = [] wav_list: List[Path] = []
for name in files: for name in files:
@ -106,6 +107,7 @@ def main(
raise click.ClickException( raise click.ClickException(
f'When supplying config {path}, you cannot supply other files/folders') f'When supplying config {path}, you cannot supply other files/folders')
cfg = yaml.load(path) cfg = yaml.load(path)
cfg_dir = path.parent
break break
else: else:
@ -136,6 +138,7 @@ def main(
# amplification...render=default, # amplification...render=default,
outputs=outputs outputs=outputs
) )
cfg_dir = '.'
if show_gui: if show_gui:
raise OvgenError('GUI not implemented') raise OvgenError('GUI not implemented')
@ -171,4 +174,4 @@ def main(
cProfile.runctx('Ovgen(cfg).play()', globals(), locals(), path) cProfile.runctx('Ovgen(cfg).play()', globals(), locals(), path)
else: else:
Ovgen(cfg).play() Ovgen(cfg, cfg_dir).play()

Wyświetl plik

@ -2,6 +2,7 @@
import shlex import shlex
import subprocess import subprocess
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from os.path import abspath
from typing import TYPE_CHECKING, Type, List, Union from typing import TYPE_CHECKING, Type, List, Union
from ovgenpy.config import register_config from ovgenpy.config import register_config
@ -55,7 +56,7 @@ class _FFmpegCommand:
self.templates += ffmpeg_input_video(ovgen_cfg) # video self.templates += ffmpeg_input_video(ovgen_cfg) # video
if ovgen_cfg.master_audio: if ovgen_cfg.master_audio:
audio_path = shlex.quote(ovgen_cfg.master_audio) audio_path = shlex.quote(abspath(ovgen_cfg.master_audio))
self.templates.append(f'-ss {ovgen_cfg.begin_time}') self.templates.append(f'-ss {ovgen_cfg.begin_time}')
self.templates += ffmpeg_input_audio(audio_path) # audio self.templates += ffmpeg_input_audio(audio_path) # audio
@ -141,7 +142,7 @@ class FFmpegOutput(PipeOutput):
ffmpeg = _FFmpegCommand([FFMPEG, '-y'], ovgen_cfg) ffmpeg = _FFmpegCommand([FFMPEG, '-y'], ovgen_cfg)
ffmpeg.add_output(cfg) ffmpeg.add_output(cfg)
ffmpeg.templates.append(cfg.args) ffmpeg.templates.append(cfg.args)
self.open(ffmpeg.popen([cfg.path], self.bufsize)) self.open(ffmpeg.popen([abspath(cfg.path)], self.bufsize))
# FFplayOutput # FFplayOutput

Wyświetl plik

@ -10,6 +10,7 @@ from ovgenpy.channel import Channel, ChannelConfig
from ovgenpy.config import register_config, register_enum, Ignored from ovgenpy.config import register_config, register_enum, Ignored
from ovgenpy.renderer import MatplotlibRenderer, RendererConfig, LayoutConfig from ovgenpy.renderer import MatplotlibRenderer, RendererConfig, LayoutConfig
from ovgenpy.triggers import ITriggerConfig, CorrelationTriggerConfig, Trigger from ovgenpy.triggers import ITriggerConfig, CorrelationTriggerConfig, Trigger
from ovgenpy.util import pushd
from ovgenpy.utils import keyword_dataclasses as dc from ovgenpy.utils import keyword_dataclasses as dc
from ovgenpy.utils.keyword_dataclasses import field from ovgenpy.utils.keyword_dataclasses import field
from ovgenpy.wave import Wave from ovgenpy.wave import Wave
@ -97,8 +98,9 @@ def default_config(**kwargs):
class Ovgen: class Ovgen:
def __init__(self, cfg: Config): def __init__(self, cfg: Config, cfg_dir: str):
self.cfg = cfg self.cfg = cfg
self.cfg_dir = cfg_dir
self.has_played = False self.has_played = False
if len(self.cfg.channels) == 0: if len(self.cfg.channels) == 0:
@ -110,19 +112,21 @@ class Ovgen:
nchan: int nchan: int
def _load_channels(self): def _load_channels(self):
self.channels = [Channel(ccfg, self.cfg) for ccfg in self.cfg.channels] with pushd(self.cfg_dir):
self.waves = [channel.wave for channel in self.channels] self.channels = [Channel(ccfg, self.cfg) for ccfg in self.cfg.channels]
self.triggers = [channel.trigger for channel in self.channels] self.waves = [channel.wave for channel in self.channels]
self.nchan = len(self.channels) self.triggers = [channel.trigger for channel in self.channels]
self.nchan = len(self.channels)
@contextmanager @contextmanager
def _load_outputs(self): def _load_outputs(self):
with ExitStack() as stack: with pushd(self.cfg_dir):
self.outputs = [ with ExitStack() as stack:
stack.enter_context(output_cfg(self.cfg)) self.outputs = [
for output_cfg in self.cfg.outputs stack.enter_context(output_cfg(self.cfg))
] for output_cfg in self.cfg.outputs
yield ]
yield
def _load_renderer(self): def _load_renderer(self):
renderer = MatplotlibRenderer(self.cfg.render, self.cfg.layout, self.nchan) renderer = MatplotlibRenderer(self.cfg.render, self.cfg.layout, self.nchan)

Wyświetl plik

@ -64,7 +64,7 @@ def test_channel_subsampling(
assert trigger._subsampling == channel.trigger_subsampling assert trigger._subsampling == channel.trigger_subsampling
# Ensure ovgenpy calls render using channel.window_samp and render_subsampling. # Ensure ovgenpy calls render using channel.window_samp and render_subsampling.
ovgen = Ovgen(cfg) ovgen = Ovgen(cfg, '.')
renderer = mocker.patch.object(Ovgen, '_load_renderer').return_value renderer = mocker.patch.object(Ovgen, '_load_renderer').return_value
ovgen.play() ovgen.play()

Wyświetl plik

@ -1,4 +1,5 @@
import shlex import shlex
from os.path import abspath
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Callable from typing import TYPE_CHECKING, Callable
@ -13,7 +14,6 @@ from ovgenpy.config import yaml
from ovgenpy.ovgenpy import Config, Ovgen from ovgenpy.ovgenpy import Config, Ovgen
from ovgenpy.util import pushd from ovgenpy.util import pushd
if TYPE_CHECKING: if TYPE_CHECKING:
import pytest_mock import pytest_mock
@ -49,7 +49,8 @@ def player_sink(mocker) -> Callable:
call_main(argv) call_main(argv)
Ovgen.assert_called_once() Ovgen.assert_called_once()
(cfg,), kwargs = Ovgen.call_args args, kwargs = Ovgen.call_args
cfg = args[0]
assert isinstance(cfg, Config) assert isinstance(cfg, Config)
return cfg, return cfg,
@ -105,36 +106,39 @@ def test_write_dir(yaml_sink):
assert outpath.parent / cfg.master_audio == audio_path assert outpath.parent / cfg.master_audio == audio_path
@pytest.fixture
def Wave(mocker):
""" Logs all calls, and returns a real Wave object. """
Wave = mocker.spy(ovgenpy.channel, 'Wave')
yield Wave
@pytest.mark.usefixtures('Popen') @pytest.mark.usefixtures('Popen')
def test_load_yaml_another_dir(yaml_sink, Popen, Wave): def test_load_yaml_another_dir(yaml_sink, mocker, Popen):
""" Loading `another/dir/YAML` should resolve `master_audio`, `channels[].wav_path`, """ YAML file located in `another/dir` should resolve `master_audio`, `channels[].
and video `path` from `another/dir`. """ wav_path`, and video `path` from `another/dir`. """
with pushd('tests'): subdir = 'tests'
arg_str = 'sine440.wav -a sine440.wav -o foo.mp4' wav = 'sine440.wav'
mp4 = 'foo.mp4'
with pushd(subdir):
arg_str = f'{wav} -a {wav} -o {mp4}'
cfg, outpath = yaml_sink(arg_str) # type: Config, Path cfg, outpath = yaml_sink(arg_str) # type: Config, Path
cfg.begin_time = 100 # To skip all actual rendering cfg.begin_time = 100 # To skip all actual rendering
ovgen = Ovgen(cfg, 'tests')
# Log execution of Ovgen().play()
Wave = mocker.spy(ovgenpy.channel, 'Wave')
ovgen = Ovgen(cfg, subdir)
ovgen.play() ovgen.play()
# Compute absolute paths
wav_abs = abspath(f'{subdir}/{wav}')
mp4_abs = abspath(f'{subdir}/{mp4}')
# Test `wave_path` # Test `wave_path`
args, kwargs = Wave.call_args args, kwargs = Wave.call_args
cfg, wave_path = args cfg, wave_path = args
assert wave_path == 'tests/sine440.wav' assert wave_path == wav_abs
# Test output `master_audio` and video `path` # Test output `master_audio` and video `path`
args, kwargs = Popen.call_args args, kwargs = Popen.call_args
argv = args[0] argv = args[0]
assert argv[-1] == 'tests/foo.mp4' assert argv[-1] == mp4_abs
assert '-i tests/sine440.wav' in ' '.join(argv) assert f'-i {wav_abs}' in ' '.join(argv)
# TODO integration test without --audio # TODO integration test without --audio

Wyświetl plik

@ -67,7 +67,7 @@ def test_ovgen_terminate_ffplay(Popen, mocker: 'pytest_mock.MockFixture'):
master_audio='tests/sine440.wav', master_audio='tests/sine440.wav',
outputs=[FFplayOutputConfig()] outputs=[FFplayOutputConfig()]
) )
ovgen = Ovgen(cfg) ovgen = Ovgen(cfg, '.')
render_frame = mocker.patch.object(MatplotlibRenderer, 'render_frame') render_frame = mocker.patch.object(MatplotlibRenderer, 'render_frame')
render_frame.side_effect = DummyException() render_frame.side_effect = DummyException()