Add input/output support in run command; update docs

This commit is contained in:
Karl Kroening 2018-05-20 01:13:07 -07:00
parent 90561c7a8a
commit ac57e2df13
12 changed files with 238 additions and 44 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ dist/
ffmpeg/tests/sample_data/out*.mp4
ffmpeg_python.egg-info/
venv*
build/

View File

@ -50,12 +50,14 @@
<div class="genindex-jumpbox">
<a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a>
| <a href="#E"><strong>E</strong></a>
| <a href="#F"><strong>F</strong></a>
| <a href="#G"><strong>G</strong></a>
| <a href="#H"><strong>H</strong></a>
| <a href="#I"><strong>I</strong></a>
| <a href="#M"><strong>M</strong></a>
| <a href="#O"><strong>O</strong></a>
| <a href="#P"><strong>P</strong></a>
| <a href="#R"><strong>R</strong></a>
| <a href="#S"><strong>S</strong></a>
| <a href="#T"><strong>T</strong></a>
@ -67,6 +69,8 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#ffmpeg.colorchannelmixer">colorchannelmixer() (in module ffmpeg)</a>
</li>
<li><a href="index.html#ffmpeg.compile">compile() (in module ffmpeg)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
@ -89,6 +93,14 @@
</ul></td>
</tr></table>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#ffmpeg.Error">Error</a>
</li>
</ul></td>
</tr></table>
<h2 id="F">F</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
@ -97,6 +109,8 @@
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#ffmpeg.filter_">filter_() (in module ffmpeg)</a>
</li>
<li><a href="index.html#ffmpeg.filter_multi_output">filter_multi_output() (in module ffmpeg)</a>
</li>
</ul></td>
</tr></table>
@ -151,6 +165,14 @@
</ul></td>
</tr></table>
<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#ffmpeg.probe">probe() (in module ffmpeg)</a>
</li>
</ul></td>
</tr></table>
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>

View File

@ -313,6 +313,21 @@ and arguments to ffmpeg verbatim.</p>
<p><code class="docutils literal"><span class="pre">ffmpeg.input('in.mp4').filter_('hflip').output('out.mp4').run()</span></code></p>
</dd></dl>
<dl class="function">
<dt id="ffmpeg.filter_multi_output">
<code class="descclassname">ffmpeg.</code><code class="descname">filter_multi_output</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>filter_name</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.filter_multi_output" title="Permalink to this definition"></a></dt>
<dd><p>Apply custom filter with one or more outputs.</p>
<p>This is the same as <code class="docutils literal"><span class="pre">filter_</span></code> except that the filter can produce more than one output.</p>
<p>To reference an output stream, use either the <code class="docutils literal"><span class="pre">.stream</span></code> operator or bracket shorthand:</p>
<p class="rubric">Example</p>
<p><code class="docutils literal"><span class="pre">`</span>
<span class="pre">split</span> <span class="pre">=</span> <span class="pre">ffmpeg.input('in.mp4').filter_multi_output('split')</span>
<span class="pre">split0</span> <span class="pre">=</span> <span class="pre">split.stream(0)</span>
<span class="pre">split1</span> <span class="pre">=</span> <span class="pre">split[1]</span>
<span class="pre">ffmpeg.concat(split0,</span> <span class="pre">split1).output('out.mp4').run()</span>
<span class="pre">`</span></code></p>
</dd></dl>
<dl class="function">
<dt id="ffmpeg.hflip">
<code class="descclassname">ffmpeg.</code><code class="descname">hflip</code><span class="sig-paren">(</span><em>stream</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.hflip" title="Permalink to this definition"></a></dt>
@ -479,6 +494,9 @@ for single input image.</li>
<dt id="ffmpeg.input">
<code class="descclassname">ffmpeg.</code><code class="descname">input</code><span class="sig-paren">(</span><em>filename</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.input" title="Permalink to this definition"></a></dt>
<dd><p>Input file URL (ffmpeg <code class="docutils literal"><span class="pre">-i</span></code> option)</p>
<p>Any supplied kwargs are passed to ffmpeg verbatim (e.g. <code class="docutils literal"><span class="pre">t=20</span></code>,
<code class="docutils literal"><span class="pre">f='mp4'</span></code>, <code class="docutils literal"><span class="pre">acodec='pcm'</span></code>, etc.).</p>
<p>To tell ffmpeg to read from stdin, use <code class="docutils literal"><span class="pre">pipe:</span></code> as the filename.</p>
<p>Official documentation: <a class="reference external" href="https://ffmpeg.org/ffmpeg.html#Main-options">Main options</a></p>
</dd></dl>
@ -490,8 +508,17 @@ for single input image.</li>
<dl class="function">
<dt id="ffmpeg.output">
<code class="descclassname">ffmpeg.</code><code class="descname">output</code><span class="sig-paren">(</span><em>stream</em>, <em>filename</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.output" title="Permalink to this definition"></a></dt>
<code class="descclassname">ffmpeg.</code><code class="descname">output</code><span class="sig-paren">(</span><em>*streams_and_filename</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.output" title="Permalink to this definition"></a></dt>
<dd><p>Output file URL</p>
<dl class="docutils">
<dt>Syntax:</dt>
<dd><cite>ffmpeg.output(stream1[, stream2, stream3…], filename, **ffmpeg_args)</cite></dd>
</dl>
<p>If multiple streams are provided, they are mapped to the same
output.</p>
<p>Any supplied kwargs are passed to ffmpeg verbatim (e.g. <code class="docutils literal"><span class="pre">t=20</span></code>,
<code class="docutils literal"><span class="pre">f='mp4'</span></code>, <code class="docutils literal"><span class="pre">acodec='pcm'</span></code>, etc.).</p>
<p>To tell ffmpeg to write to stdout, use <code class="docutils literal"><span class="pre">pipe:</span></code> as the filename.</p>
<p>Official documentation: <a class="reference external" href="https://ffmpeg.org/ffmpeg.html#Synopsis">Synopsis</a></p>
</dd></dl>
@ -502,24 +529,53 @@ for single input image.</li>
<p>Official documentation: <a class="reference external" href="https://ffmpeg.org/ffmpeg.html#Main-options">Main options</a></p>
</dd></dl>
<dl class="function">
<dt id="ffmpeg.compile">
<code class="descclassname">ffmpeg.</code><code class="descname">compile</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>cmd=u'ffmpeg'</em>, <em>overwrite_output=False</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.compile" title="Permalink to this definition"></a></dt>
<dd><p>Build command-line for invoking ffmpeg.</p>
<p>The <a class="reference internal" href="#ffmpeg.run" title="ffmpeg.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a> function uses this to build the commnad line
arguments and should work in most cases, but calling this function
directly is useful for debugging or if you need to invoke ffmpeg
manually for whatever reason.</p>
<p>This is the same as calling <a class="reference internal" href="#ffmpeg.get_args" title="ffmpeg.get_args"><code class="xref py py-meth docutils literal"><span class="pre">get_args()</span></code></a> except that it also
includes the <code class="docutils literal"><span class="pre">ffmpeg</span></code> command as the first argument.</p>
</dd></dl>
<dl class="exception">
<dt id="ffmpeg.Error">
<em class="property">exception </em><code class="descclassname">ffmpeg.</code><code class="descname">Error</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>stdout</em>, <em>stderr</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.Error" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">exceptions.Exception</span></code></p>
</dd></dl>
<dl class="function">
<dt id="ffmpeg.get_args">
<code class="descclassname">ffmpeg.</code><code class="descname">get_args</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>overwrite_output=False</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.get_args" title="Permalink to this definition"></a></dt>
<dd><p>Get command-line arguments for ffmpeg.</p>
<dd><p>Build command-line arguments to be passed to ffmpeg.</p>
</dd></dl>
<dl class="function">
<dt id="ffmpeg.run">
<code class="descclassname">ffmpeg.</code><code class="descname">run</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>cmd=u'ffmpeg'</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.run" title="Permalink to this definition"></a></dt>
<dd><p>Run ffmpeg on node graph.</p>
<code class="descclassname">ffmpeg.</code><code class="descname">run</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>cmd=u'ffmpeg'</em>, <em>capture_stdout=False</em>, <em>capture_stderr=False</em>, <em>input=None</em>, <em>quiet=False</em>, <em>overwrite_output=False</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.run" title="Permalink to this definition"></a></dt>
<dd><p>Ivoke ffmpeg for the supplied node graph.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>**kwargs</strong> keyword-arguments passed to <code class="docutils literal"><span class="pre">get_args()</span></code> (e.g. <code class="docutils literal"><span class="pre">overwrite_output=True</span></code>).</td>
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>capture_stdout</strong> if True, capture stdout (to be used with
<code class="docutils literal"><span class="pre">pipe:</span></code> ffmpeg outputs).</li>
<li><strong>capture_stderr</strong> if True, capture stderr.</li>
<li><strong>quiet</strong> shorthand for setting <code class="docutils literal"><span class="pre">capture_stdout</span></code> and <code class="docutils literal"><span class="pre">capture_stderr</span></code>.</li>
<li><strong>input</strong> text to be sent to stdin (to be used with <code class="docutils literal"><span class="pre">pipe:</span></code>
ffmpeg inputs)</li>
<li><strong>**kwargs</strong> keyword-arguments passed to <code class="docutils literal"><span class="pre">get_args()</span></code> (e.g.
<code class="docutils literal"><span class="pre">overwrite_output=True</span></code>).</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Returns: (out, err) tuple containing captured stdout and stderr data.</p>
</dd></dl>
<dl class="function">
@ -527,6 +583,23 @@ for single input image.</li>
<code class="descclassname">ffmpeg.</code><code class="descname">view</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.view" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="function">
<dt id="ffmpeg.probe">
<code class="descclassname">ffmpeg.</code><code class="descname">probe</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.probe" title="Permalink to this definition"></a></dt>
<dd><p>Run ffprobe on the specified file and return a JSON representation of the output.</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Raises:</th><td class="field-body"><a class="reference internal" href="#ffmpeg.Error" title="ffmpeg.Error"><code class="xref py py-class docutils literal"><span class="pre">ffmpeg.Error</span></code></a> if ffprobe returns a non-zero exit code,
an <a class="reference internal" href="#ffmpeg.Error" title="ffmpeg.Error"><code class="xref py py-class docutils literal"><span class="pre">Error</span></code></a> is returned with a generic error message.
The stderr output can be retrieved by accessing the
<code class="docutils literal"><span class="pre">stderr</span></code> property of the exception.</td>
</tr>
</tbody>
</table>
</dd></dl>
</div>
<div class="section" id="indices-and-tables">
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -16,6 +16,11 @@ from .nodes import (
def input(filename, **kwargs):
"""Input file URL (ffmpeg ``-i`` option)
Any supplied kwargs are passed to ffmpeg verbatim (e.g. ``t=20``,
``f='mp4'``, ``acodec='pcm'``, etc.).
To tell ffmpeg to read from stdin, use ``pipe:`` as the filename.
Official documentation: `Main options <https://ffmpeg.org/ffmpeg.html#Main-options>`__
"""
kwargs['filename'] = filename
@ -57,7 +62,13 @@ def output(*streams_and_filename, **kwargs):
Syntax:
`ffmpeg.output(stream1[, stream2, stream3...], filename, **ffmpeg_args)`
If multiple streams are provided, they are mapped to the same output.
If multiple streams are provided, they are mapped to the same
output.
Any supplied kwargs are passed to ffmpeg verbatim (e.g. ``t=20``,
``f='mp4'``, ``acodec='pcm'``, etc.).
To tell ffmpeg to write to stdout, use ``pipe:`` as the filename.
Official documentation: `Synopsis <https://ffmpeg.org/ffmpeg.html#Synopsis>`__
"""

16
ffmpeg/_probe.py Executable file → Normal file
View File

@ -1,29 +1,25 @@
import json
import subprocess
class ProbeException(Exception):
def __init__(self, stderr_output):
super(ProbeException, self).__init__('ffprobe error')
self.stderr_output = stderr_output
from ._run import Error
def probe(filename):
"""Run ffprobe on the specified file and return a JSON representation of the output.
Raises:
ProbeException: if ffprobe returns a non-zero exit code, a ``ProbeException`` is returned with a generic error
message. The stderr output can be retrieved by accessing the ``stderr_output`` property of the exception.
:class:`ffmpeg.Error`: if ffprobe returns a non-zero exit code,
an :class:`Error` is returned with a generic error message.
The stderr output can be retrieved by accessing the
``stderr`` property of the exception.
"""
args = ['ffprobe', '-show_format', '-show_streams', '-of', 'json', filename]
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
raise ProbeException(err)
raise Error(err)
return json.loads(out.decode('utf-8'))
__all__ = [
'probe',
'ProbeException',
]

View File

@ -1,13 +1,13 @@
from __future__ import unicode_literals
from builtins import str
from past.builtins import basestring
from .dag import get_outgoing_edges, topo_sort
from functools import reduce
from ._utils import basestring
from builtins import str
from functools import reduce
from past.builtins import basestring
import copy
import operator
import subprocess as _subprocess
import subprocess
from ._ffmpeg import (
input,
@ -23,6 +23,14 @@ from .nodes import (
)
class Error(Exception):
def __init__(self, stream_spec, stdout, stderr):
super(Error, self).__init__('ffmpeg error (see stderr output for detail)')
self.stream_spec = stream_spec
self.stdout = stdout
self.stderr = stderr
def _convert_kwargs_to_cmd_line_args(kwargs):
args = []
for k in sorted(kwargs.keys()):
@ -80,8 +88,9 @@ def _allocate_filter_stream_names(filter_nodes, outgoing_edge_maps, stream_name_
for upstream_label, downstreams in list(outgoing_edge_map.items()):
if len(downstreams) > 1:
# TODO: automatically insert `splits` ahead of time via graph transformation.
raise ValueError('Encountered {} with multiple outgoing edges with same upstream label {!r}; a '
'`split` filter is probably required'.format(upstream_node, upstream_label))
raise ValueError(
'Encountered {} with multiple outgoing edges with same upstream label {!r}; a '
'`split` filter is probably required'.format(upstream_node, upstream_label))
stream_name_map[upstream_node, upstream_label] = 's{}'.format(stream_count)
stream_count += 1
@ -122,7 +131,7 @@ def _get_output_args(node, stream_name_map):
@output_operator()
def get_args(stream_spec, overwrite_output=False):
"""Get command-line arguments for ffmpeg."""
"""Build command-line arguments to be passed to ffmpeg."""
nodes = get_stream_spec_nodes(stream_spec)
args = []
# TODO: group nodes together, e.g. `-i somefile -r somerate`.
@ -144,27 +153,57 @@ def get_args(stream_spec, overwrite_output=False):
@output_operator()
def compile(stream_spec, cmd='ffmpeg', **kwargs):
"""Build command-line for ffmpeg."""
def compile(stream_spec, cmd='ffmpeg', overwrite_output=False):
"""Build command-line for invoking ffmpeg.
The :meth:`run` function uses this to build the commnad line
arguments and should work in most cases, but calling this function
directly is useful for debugging or if you need to invoke ffmpeg
manually for whatever reason.
This is the same as calling :meth:`get_args` except that it also
includes the ``ffmpeg`` command as the first argument.
"""
if isinstance(cmd, basestring):
cmd = [cmd]
elif type(cmd) != list:
cmd = list(cmd)
return cmd + get_args(stream_spec, **kwargs)
return cmd + get_args(stream_spec, overwrite_output=overwrite_output)
@output_operator()
def run(stream_spec, cmd='ffmpeg', **kwargs):
"""Run ffmpeg on node graph.
def run(
stream_spec, cmd='ffmpeg', capture_stdout=False, capture_stderr=False, input=None,
quiet=False, overwrite_output=False):
"""Ivoke ffmpeg for the supplied node graph.
Args:
**kwargs: keyword-arguments passed to ``get_args()`` (e.g. ``overwrite_output=True``).
capture_stdout: if True, capture stdout (to be used with
``pipe:`` ffmpeg outputs).
capture_stderr: if True, capture stderr.
quiet: shorthand for setting ``capture_stdout`` and ``capture_stderr``.
input: text to be sent to stdin (to be used with ``pipe:``
ffmpeg inputs)
**kwargs: keyword-arguments passed to ``get_args()`` (e.g.
``overwrite_output=True``).
Returns: (out, err) tuple containing captured stdout and stderr data.
"""
_subprocess.check_call(compile(stream_spec, cmd, **kwargs))
args = compile(stream_spec, cmd, overwrite_output=overwrite_output)
stdin_stream = subprocess.PIPE if input else None
stdout_stream = subprocess.PIPE if capture_stdout or quiet else None
stderr_stream = subprocess.PIPE if capture_stderr or quiet else None
p = subprocess.Popen(args, stdin=stdin_stream, stdout=stdout_stream, stderr=stderr_stream)
out, err = p.communicate(input)
retcode = p.poll()
if retcode:
raise Error(stream_spec, out, err)
return out, err
__all__ = [
'compile',
'Error',
'get_args',
'run',
]

View File

@ -111,6 +111,10 @@ def test_global_args():
assert out_file.get_args() == ['-i', 'dummy.mp4', 'dummy2.mp4', '-progress', 'someurl']
def _get_simple_example():
return ffmpeg.input(TEST_INPUT_FILE1).output(TEST_OUTPUT_FILE1)
def _get_complex_filter_example():
split = (ffmpeg
.input(TEST_INPUT_FILE1)
@ -313,33 +317,72 @@ def test_compile():
def test_run():
stream = _get_complex_filter_example()
ffmpeg.run(stream)
out, err = ffmpeg.run(stream)
assert out is None
assert err is None
def test_run_multi_output():
@pytest.mark.parametrize('capture_stdout', [True, False])
@pytest.mark.parametrize('capture_stderr', [True, False])
def test_run__capture_out(mocker, capture_stdout, capture_stderr):
mocker.patch.object(ffmpeg._run, 'compile', return_value=['echo', 'test'])
stream = _get_simple_example()
out, err = ffmpeg.run(stream, capture_stdout=capture_stdout, capture_stderr=capture_stderr)
if capture_stdout:
assert out == 'test\n'
else:
assert out is None
if capture_stderr:
assert err == ''
else:
assert err is None
def test_run__input_output(mocker):
mocker.patch.object(ffmpeg._run, 'compile', return_value=['cat'])
stream = _get_simple_example()
out, err = ffmpeg.run(stream, input='test', capture_stdout=True)
assert out == 'test'
assert err is None
@pytest.mark.parametrize('capture_stdout', [True, False])
@pytest.mark.parametrize('capture_stderr', [True, False])
def test_run__error(mocker, capture_stdout, capture_stderr):
mocker.patch.object(ffmpeg._run, 'compile', return_value=['ffmpeg'])
stream = _get_complex_filter_example()
with pytest.raises(ffmpeg.Error) as excinfo:
out, err = ffmpeg.run(stream, capture_stdout=capture_stdout, capture_stderr=capture_stderr)
out = excinfo.value.stdout
err = excinfo.value.stderr
if capture_stdout:
assert out == ''
else:
assert out is None
if capture_stderr:
assert err.startswith('ffmpeg version')
else:
assert err is None
def test_run__multi_output():
in_ = ffmpeg.input(TEST_INPUT_FILE1)
out1 = in_.output(TEST_OUTPUT_FILE1)
out2 = in_.output(TEST_OUTPUT_FILE2)
ffmpeg.run([out1, out2], overwrite_output=True)
def test_run_dummy_cmd():
def test_run__dummy_cmd():
stream = _get_complex_filter_example()
ffmpeg.run(stream, cmd='true')
def test_run_dummy_cmd_list():
def test_run__dummy_cmd_list():
stream = _get_complex_filter_example()
ffmpeg.run(stream, cmd=['true', 'ignored'])
def test_run_failing_cmd():
stream = _get_complex_filter_example()
with pytest.raises(subprocess.CalledProcessError):
ffmpeg.run(stream, cmd='false')
def test_custom_filter():
def test_filter__custom():
stream = ffmpeg.input('dummy.mp4')
stream = ffmpeg.filter_(stream, 'custom_filter', 'a', 'b', kwarg1='c')
stream = ffmpeg.output(stream, 'dummy2.mp4')
@ -351,7 +394,7 @@ def test_custom_filter():
]
def test_custom_filter_fluent():
def test_filter__custom_fluent():
stream = (ffmpeg
.input('dummy.mp4')
.filter_('custom_filter', 'a', 'b', kwarg1='c')

View File

@ -1,5 +1,6 @@
future
pytest
pytest-mock
pytest-runner
sphinx
tox

View File

@ -1,18 +1,26 @@
alabaster==0.7.10
apipkg==1.4
Babel==2.5.1
certifi==2017.7.27.1
chardet==3.0.4
docutils==0.14
execnet==1.5.0
funcsigs==1.0.2
future==0.16.0
idna==2.6
imagesize==0.7.1
Jinja2==2.9.6
MarkupSafe==1.0
mock==2.0.0
pbr==4.0.3
pluggy==0.5.2
py==1.4.34
Pygments==2.2.0
pytest==3.2.3
pytest-forked==0.2
pytest-mock==1.10.0
pytest-runner==3.0
pytest-xdist==1.22.2
pytz==2017.3
requests==2.18.4
six==1.11.0

View File

@ -57,7 +57,7 @@ setup(
name='ffmpeg-python',
packages=['ffmpeg'],
setup_requires=['pytest-runner'],
tests_require=['pytest'],
tests_require=['pytest', 'pytest-mock'],
version=version,
description='Python bindings for FFmpeg - with support for complex filtering',
author='Karl Kroening',