From 29b6f0929805b09a20184a1d4500bf31e4dbc138 Mon Sep 17 00:00:00 2001 From: Karl Kroening Date: Mon, 7 Mar 2022 00:05:43 -0800 Subject: [PATCH 1/8] Use GitHub Actions for CI. (#641) This sets up GitHub Actions (GHA) to run in place of the currently broken Travis CI. Initially, this only covers running tox/pytest and Black, but may eventually be extended to run pylint, mypy, flake8, etc. - see #605, for example. Notes: * Python 3.10 is not yet supported due to the `collections.Iterable` issue discussed in #330, #624, etc. * The Black CI step acts as a linting step, rather than attempting to have the GHA job automatically update/commit/push the reformarted code. * Black is currently pinned to an older version that supports `--target-version py27` until Python 2 compatibility can be dropped in the final Python 2 compatibility release of ffmpeg-python. * Only the main source directory (`ffmpeg/`) is checked with Black at the moment. The `examples/` directory should also be checked, but will be done as a separate PR. Co-authored by: Christian Clauss --- .github/workflows/ci.yml | 44 ++++++++++++++++++++++++++++++++++++++++ .travis.yml | 32 ----------------------------- README.md | 5 ++++- ffmpeg/_utils.py | 1 - setup.py | 2 -- tox.ini | 11 +++++++++- 6 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..6289d8bc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + python-version: + - "2.7" + - "3.5" + - "3.6" + - "3.7" + - "3.8" + - "3.9" + # - "3.10" # FIXME: broken due to `collections.Iterable` issue; see #330 / #624 / etc. + steps: + - uses: actions/checkout@v1 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install ffmpeg + run: | + sudo apt update + sudo apt install ffmpeg + - name: Setup pip + tox + run: | + python -m pip install --upgrade \ + "pip==20.3.4; python_version < '3.6'" \ + "pip==21.3.1; python_version >= '3.6'" + python -m pip install tox==3.24.5 tox-gh-actions==2.9.1 + - name: Test with tox + run: tox + black: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: psf/black@21.12b0 # TODO: upgrade after dropping Python 2 support. + with: + src: ffmpeg # TODO: also format `examples`. + version: 21.12b0 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e4d7d758..00000000 --- a/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -language: python -before_install: - - > - [ -f ffmpeg-release/ffmpeg ] || ( - curl -O https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && - mkdir -p ffmpeg-release && - tar Jxf ffmpeg-release-amd64-static.tar.xz --strip-components=1 -C ffmpeg-release - ) -matrix: - include: - - python: 2.7 - env: TOX_ENV=py27 - - python: 3.4 - env: TOX_ENV=py34 - - python: 3.5 - env: TOX_ENV=py35 - - python: 3.6 - env: TOX_ENV=py36 - - python: 3.7 - dist: xenial # required for Python >= 3.7 - env: TOX_ENV=py37 - - python: pypy - env: TOX_ENV=pypy -install: - - pip install tox -script: - - export PATH=$(readlink -f ffmpeg-release):$PATH - - tox -e $TOX_ENV -cache: - directories: - - .tox - - ffmpeg-release diff --git a/README.md b/README.md index 8cfe89ae..2ac9d628 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # ffmpeg-python: Python bindings for FFmpeg -[![Build status](https://travis-ci.org/kkroening/ffmpeg-python.svg?branch=master)](https://travis-ci.org/kkroening/ffmpeg-python) +[![CI][ci-badge]][ci] + +[ci-badge]: https://github.com/kkroening/ffmpeg-python/actions/workflows/ci.yml/badge.svg +[ci]: https://github.com/kkroening/ffmpeg-python/actions/workflows/ci.yml ffmpeg-python logo diff --git a/ffmpeg/_utils.py b/ffmpeg/_utils.py index 55682a28..94ef9d07 100644 --- a/ffmpeg/_utils.py +++ b/ffmpeg/_utils.py @@ -40,7 +40,6 @@ def __new__(cls, name, this_bases, d): class basestring(with_metaclass(BaseBaseString)): pass - else: # noinspection PyUnresolvedReferences,PyCompatibility from builtins import basestring diff --git a/setup.py b/setup.py index 0282c67e..743deb22 100644 --- a/setup.py +++ b/setup.py @@ -60,8 +60,6 @@ setup( name='ffmpeg-python', packages=['ffmpeg'], - setup_requires=['pytest-runner'], - tests_require=['pytest', 'pytest-mock'], version=version, description='Python bindings for FFmpeg - with complex filtering support', author='Karl Kroening', diff --git a/tox.ini b/tox.ini index 1e3ba533..e317207f 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,16 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py34, py35, py36, py37, pypy +envlist = py27, py35, py36, py37, py38, py39 + +[gh-actions] +python = + 2.7: py27 + 3.5: py35 + 3.6: py36 + 3.7: py37 + 3.8: py38 + 3.9: py39 [testenv] commands = py.test -vv From cb9d400467014dd371ff5bb24d86be3fa6df8a2b Mon Sep 17 00:00:00 2001 From: Karl Kroening Date: Mon, 7 Mar 2022 01:19:09 -0800 Subject: [PATCH 2/8] Add FFmpeg installation instructions (#642) Co-authored-by: digitalcircuits <59550818+digitalcircuits@users.noreply.github.com> Co-authored-by: digitalcircuits --- README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ac9d628..b8ee9221 100644 --- a/README.md +++ b/README.md @@ -81,9 +81,11 @@ Real-world signal graphs can get a heck of a lot more complex, but `ffmpeg-pytho ## Installation +### Installing `ffmpeg-python` + The latest version of `ffmpeg-python` can be acquired via a typical pip install: -``` +```bash pip install ffmpeg-python ``` @@ -93,6 +95,24 @@ git clone git@github.com:kkroening/ffmpeg-python.git pip install -e ./ffmpeg-python ``` +> **Note**: `ffmpeg-python` makes no attempt to download/install FFmpeg, as `ffmpeg-python` is merely a pure-Python wrapper - whereas FFmpeg installation is platform-dependent/environment-specific, and is thus the responsibility of the user, as described below. + +### Installing FFmpeg + +Before using `ffmpeg-python`, FFmpeg must be installed and accessible via the `$PATH` environment variable. + +There are a variety of ways to install FFmpeg, such as the [official download links](https://ffmpeg.org/download.html), or using your package manager of choice (e.g. `sudo apt install ffmpeg` on Debian/Ubuntu, `brew install ffmpeg` on OS X, etc.). + +Regardless of how FFmpeg is installed, you can check if your environment path is set correctly by running the `ffmpeg` command from the terminal, in which case the version information should appear, as in the following example (truncated for brevity): + +``` +$ ffmpeg +ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers + built with gcc 9 (Ubuntu 9.3.0-10ubuntu2) +``` + +> **Note**: The actual version information displayed here may vary from one system to another; but if a message such as `ffmpeg: command not found` appears instead of the version information, FFmpeg is not properly installed. + ## [Examples](https://github.com/kkroening/ffmpeg-python/tree/master/examples) When in doubt, take a look at the [examples](https://github.com/kkroening/ffmpeg-python/tree/master/examples) to see if there's something that's close to whatever you're trying to do. @@ -197,7 +217,7 @@ When in doubt, refer to the [existing filters](https://github.com/kkroening/ffmp **Why do I get an import/attribute/etc. error from `import ffmpeg`?** -Make sure you ran `pip install ffmpeg-python` and not `pip install ffmpeg` or `pip install python-ffmpeg`. +Make sure you ran `pip install ffmpeg-python` and _**not**_ `pip install ffmpeg` (wrong) or `pip install python-ffmpeg` (also wrong). **Why did my audio stream get dropped?** From 6189cd6861a90f6f52e6a8ba2db0fada54134194 Mon Sep 17 00:00:00 2001 From: Karthikeyan Singaravelan Date: Mon, 7 Mar 2022 15:16:52 +0530 Subject: [PATCH 3/8] Import ABC from collections.abc for Python 3.9+ compatibility (#330) * Import ABC from collections.abc instead of collections for Python 3.9 compatibility. * Fix deprecation warnings due to invalid escape sequences. * Support Python 3.10 Co-authored-by: Karl Kroening --- .github/workflows/ci.yml | 2 +- examples/split_silence.py | 6 +++--- ffmpeg/_run.py | 10 ++++++---- ffmpeg/_utils.py | 8 ++++++-- ffmpeg/tests/test_ffmpeg.py | 2 +- setup.py | 4 ++++ tox.ini | 3 ++- 7 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6289d8bc..cf65206d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: - "3.7" - "3.8" - "3.9" - # - "3.10" # FIXME: broken due to `collections.Iterable` issue; see #330 / #624 / etc. + - "3.10" steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} diff --git a/examples/split_silence.py b/examples/split_silence.py index a889db10..90b46d95 100755 --- a/examples/split_silence.py +++ b/examples/split_silence.py @@ -27,10 +27,10 @@ parser.add_argument('--end-time', type=float, help='End time (seconds)') parser.add_argument('-v', dest='verbose', action='store_true', help='Verbose mode') -silence_start_re = re.compile(' silence_start: (?P[0-9]+(\.?[0-9]*))$') -silence_end_re = re.compile(' silence_end: (?P[0-9]+(\.?[0-9]*)) ') +silence_start_re = re.compile(r' silence_start: (?P[0-9]+(\.?[0-9]*))$') +silence_end_re = re.compile(r' silence_end: (?P[0-9]+(\.?[0-9]*)) ') total_duration_re = re.compile( - 'size=[^ ]+ time=(?P[0-9]{2}):(?P[0-9]{2}):(?P[0-9\.]{5}) bitrate=') + r'size=[^ ]+ time=(?P[0-9]{2}):(?P[0-9]{2}):(?P[0-9\.]{5}) bitrate=') def _logged_popen(cmd_line, *args, **kwargs): diff --git a/ffmpeg/_run.py b/ffmpeg/_run.py index 5f25a347..f42d1d73 100644 --- a/ffmpeg/_run.py +++ b/ffmpeg/_run.py @@ -3,7 +3,6 @@ from ._utils import basestring, convert_kwargs_to_cmd_line_args from builtins import str from functools import reduce -import collections import copy import operator import subprocess @@ -18,6 +17,11 @@ output_operator, ) +try: + from collections.abc import Iterable +except ImportError: + from collections import Iterable + class Error(Exception): def __init__(self, cmd, stdout, stderr): @@ -136,9 +140,7 @@ def _get_output_args(node, stream_name_map): args += ['-b:a', str(kwargs.pop('audio_bitrate'))] if 'video_size' in kwargs: video_size = kwargs.pop('video_size') - if not isinstance(video_size, basestring) and isinstance( - video_size, collections.Iterable - ): + if not isinstance(video_size, basestring) and isinstance(video_size, Iterable): video_size = '{}x{}'.format(video_size[0], video_size[1]) args += ['-video_size', video_size] args += convert_kwargs_to_cmd_line_args(kwargs) diff --git a/ffmpeg/_utils.py b/ffmpeg/_utils.py index 94ef9d07..9baa2c78 100644 --- a/ffmpeg/_utils.py +++ b/ffmpeg/_utils.py @@ -3,13 +3,17 @@ from past.builtins import basestring import hashlib import sys -import collections if sys.version_info.major == 2: # noinspection PyUnresolvedReferences,PyShadowingBuiltins str = str +try: + from collections.abc import Iterable +except ImportError: + from collections import Iterable + # `past.builtins.basestring` module can't be imported on Python3 in some environments (Ubuntu). # This code is copy-pasted from it to avoid crashes. @@ -92,7 +96,7 @@ def convert_kwargs_to_cmd_line_args(kwargs): args = [] for k in sorted(kwargs.keys()): v = kwargs[k] - if isinstance(v, collections.Iterable) and not isinstance(v, str): + if isinstance(v, Iterable) and not isinstance(v, str): for value in v: args.append('-{}'.format(k)) if value is not None: diff --git a/ffmpeg/tests/test_ffmpeg.py b/ffmpeg/tests/test_ffmpeg.py index ba1fa361..8dbc271a 100644 --- a/ffmpeg/tests/test_ffmpeg.py +++ b/ffmpeg/tests/test_ffmpeg.py @@ -30,7 +30,7 @@ def test_escape_chars(): - assert ffmpeg._utils.escape_chars('a:b', ':') == 'a\:b' + assert ffmpeg._utils.escape_chars('a:b', ':') == r'a\:b' assert ffmpeg._utils.escape_chars('a\\:b', ':\\') == 'a\\\\\\:b' assert ( ffmpeg._utils.escape_chars('a:b,c[d]e%{}f\'g\'h\\i', '\\\':,[]%') diff --git a/setup.py b/setup.py index 743deb22..72f381cb 100644 --- a/setup.py +++ b/setup.py @@ -92,5 +92,9 @@ 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', ], ) diff --git a/tox.ini b/tox.ini index e317207f..98814078 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py35, py36, py37, py38, py39 +envlist = py27, py35, py36, py37, py38, py39, py310 [gh-actions] python = @@ -14,6 +14,7 @@ python = 3.7: py37 3.8: py38 3.9: py39 + 3.10: py310 [testenv] commands = py.test -vv From fc41f4aa84084bfae6e2db6a5a1fe7949bb28bae Mon Sep 17 00:00:00 2001 From: lcjh <120989324@qq.com> Date: Mon, 7 Mar 2022 17:55:30 +0800 Subject: [PATCH 4/8] Fix `heigth` -> `height` typo (#596) Co-authored-by: Karl Kroening --- doc/html/index.html | 6 +++--- ffmpeg/_filters.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/html/index.html b/doc/html/index.html index eac8967c..55d31a94 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -168,7 +168,7 @@

ffmpeg-python: Python bindings for FFmpeg ffmpeg.compile(stream_spec, cmd='ffmpeg', overwrite_output=False)

Build command-line for invoking ffmpeg.

-

The run() function uses this to build the commnad line +

The run() function uses this to build the command 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.

@@ -340,7 +340,7 @@

ffmpeg-python: Python bindings for FFmpeg Date: Mon, 11 Jul 2022 22:39:36 +0200 Subject: [PATCH 5/8] Upgrade GitHub Actions (#643) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf65206d..bb9842ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,9 +17,9 @@ jobs: - "3.9" - "3.10" steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - name: Install ffmpeg From ef00863269588f79031a56a17509198ded8b8da2 Mon Sep 17 00:00:00 2001 From: Karl Kroening Date: Mon, 11 Jul 2022 13:51:06 -0700 Subject: [PATCH 6/8] Fix Black in GHA for Python 2.7 (#680) (At least until Python 2.7 support is finally eliminated) --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb9842ba..0bd614b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,8 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - uses: psf/black@21.12b0 # TODO: upgrade after dropping Python 2 support. - with: - src: ffmpeg # TODO: also format `examples`. - version: 21.12b0 + - name: Black + run: | + # TODO: use standard `psf/black` action after dropping Python 2 support. + pip install black==21.12b0 click==8.0.2 # https://stackoverflow.com/questions/71673404 + black ffmpeg --check --color --diff From 35886c970c7b3a757115f5a7b6fd1753e64832ce Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 11 Jul 2022 23:02:31 +0200 Subject: [PATCH 7/8] Upgrade GitHub Actions again (#679) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bd614b7..90ae317c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,9 +17,9 @@ jobs: - "3.9" - "3.10" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install ffmpeg @@ -37,7 +37,7 @@ jobs: black: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Black run: | # TODO: use standard `psf/black` action after dropping Python 2 support. From df129c7ba30aaa9ffffb81a48f53aa7253b0b4e6 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 11 Jul 2022 23:03:07 +0200 Subject: [PATCH 8/8] Let's implicitly fix a typo (#681) --- ffmpeg/dag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffmpeg/dag.py b/ffmpeg/dag.py index 3508dd49..4bdac44d 100644 --- a/ffmpeg/dag.py +++ b/ffmpeg/dag.py @@ -74,7 +74,7 @@ def incoming_edge_map(self): """Provides information about all incoming edges that connect to this node. The edge map is a dictionary that maps an ``incoming_label`` to - ``(outgoing_node, outgoing_label)``. Note that implicity, ``incoming_node`` is + ``(outgoing_node, outgoing_label)``. Note that implicitly, ``incoming_node`` is ``self``. See "Edges" section above. """ raise NotImplementedError()