Hello community, here is the log from the commit of package python-pymediainfo for openSUSE:Factory checked in at 2020-11-07 21:03:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pymediainfo (Old) and /work/SRC/openSUSE:Factory/.python-pymediainfo.new.11331 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pymediainfo" Sat Nov 7 21:03:04 2020 rev:8 rq:846858 version:4.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pymediainfo/python-pymediainfo.changes 2020-05-01 11:14:24.307984707 +0200 +++ /work/SRC/openSUSE:Factory/.python-pymediainfo.new.11331/python-pymediainfo.changes 2020-11-07 21:05:40.353616769 +0100 @@ -1,0 +2,8 @@ +Sat Nov 7 18:48:37 UTC 2020 - Luigi Baldoni <aloi...@gmx.com> + +- Update to version 4.3 + * MediaInfo.parse: add support for file-like objects + * Improvements to documentation + * Python 3.9 is now officially supported + +------------------------------------------------------------------- Old: ---- pymediainfo-4.2.1.tar.gz New: ---- pymediainfo-4.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pymediainfo.spec ++++++ --- /var/tmp/diff_new_pack.AFOgpZ/_old 2020-11-07 21:05:40.961615798 +0100 +++ /var/tmp/diff_new_pack.AFOgpZ/_new 2020-11-07 21:05:40.965615792 +0100 @@ -17,7 +17,7 @@ Name: python-pymediainfo -Version: 4.2.1 +Version: 4.3 Release: 0 Summary: Python wrapper for the mediainfo library License: MIT ++++++ pymediainfo-4.2.1.tar.gz -> pymediainfo-4.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/PKG-INFO new/pymediainfo-4.3/PKG-INFO --- old/pymediainfo-4.2.1/PKG-INFO 2020-04-30 00:08:01.000000000 +0200 +++ new/pymediainfo-4.3/PKG-INFO 2020-11-07 18:47:40.092912400 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: pymediainfo -Version: 4.2.1 +Version: 4.3 Summary: A Python wrapper for the mediainfo library. Home-page: https://github.com/sbraz/pymediainfo Author: Louis Sautier @@ -23,8 +23,8 @@ .. image:: https://img.shields.io/pypi/implementation/pymediainfo.svg :target: https://pypi.org/project/pymediainfo - .. image:: https://api.travis-ci.org/sbraz/pymediainfo.svg?branch=master - :target: https://travis-ci.org/sbraz/pymediainfo + .. image:: https://travis-ci.com/sbraz/pymediainfo.svg?branch=master + :target: https://travis-ci.com/sbraz/pymediainfo .. image:: https://ci.appveyor.com/api/projects/status/g15a2daem1oub57n/branch/master?svg=true :target: https://ci.appveyor.com/project/sbraz/pymediainfo @@ -32,7 +32,7 @@ This small package is a wrapper around the MediaInfo library. - It works on Linux, Mac OS X and Windows and is tested with Python 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, PyPy and PyPy3. + It works on Linux, Mac OS X and Windows and is tested with Python 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, PyPy and PyPy3. See https://pymediainfo.readthedocs.io/ for more information. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/README.rst new/pymediainfo-4.3/README.rst --- old/pymediainfo-4.2.1/README.rst 2020-04-30 00:07:55.000000000 +0200 +++ new/pymediainfo-4.3/README.rst 2020-11-07 18:47:33.000000000 +0100 @@ -13,8 +13,8 @@ .. image:: https://img.shields.io/pypi/implementation/pymediainfo.svg :target: https://pypi.org/project/pymediainfo -.. image:: https://api.travis-ci.org/sbraz/pymediainfo.svg?branch=master - :target: https://travis-ci.org/sbraz/pymediainfo +.. image:: https://travis-ci.com/sbraz/pymediainfo.svg?branch=master + :target: https://travis-ci.com/sbraz/pymediainfo .. image:: https://ci.appveyor.com/api/projects/status/g15a2daem1oub57n/branch/master?svg=true :target: https://ci.appveyor.com/project/sbraz/pymediainfo @@ -22,6 +22,6 @@ This small package is a wrapper around the MediaInfo library. -It works on Linux, Mac OS X and Windows and is tested with Python 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, PyPy and PyPy3. +It works on Linux, Mac OS X and Windows and is tested with Python 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, PyPy and PyPy3. See https://pymediainfo.readthedocs.io/ for more information. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/appveyor.yml new/pymediainfo-4.3/appveyor.yml --- old/pymediainfo-4.2.1/appveyor.yml 2020-04-30 00:07:55.000000000 +0200 +++ new/pymediainfo-4.3/appveyor.yml 2020-11-07 18:47:33.000000000 +0100 @@ -1,5 +1,8 @@ +image: + # Currently required to support Python 3.9 + - Visual Studio 2019 environment: - MEDIAINFO_VERSION: 20.03 + MEDIAINFO_VERSION: 20.09 TWINE_PASSWORD: secure: /EO8CxTxhQVNsGNZZvU51jjHwPW524rgddNlwOAyLoA= matrix: @@ -8,11 +11,13 @@ - PYTHON: "C:/Python36" - PYTHON: "C:/Python37" - PYTHON: "C:/Python38" + - PYTHON: "C:/Python39" - PYTHON: "C:/Python27-x64" - PYTHON: "C:/Python35-x64" - PYTHON: "C:/Python36-x64" - PYTHON: "C:/Python37-x64" - PYTHON: "C:/Python38-x64" + - PYTHON: "C:/Python39-x64" install: - "SET PATH=%PYTHON%;%PYTHON%/Scripts;%PATH%" - "python --version" @@ -23,10 +28,11 @@ - ps: "7z -y x MediaInfo_DLL_${Env:MEDIAINFO_VERSION}_Windows_${Env:ARCH}_WithoutInstaller.7z MediaInfo.dll Developers/License.html" - "move MediaInfo.dll pymediainfo" - "move Developers\\License.html docs" - - "pip install --upgrade setuptools pytest pytest-runner twine wheel" + - "pip install --upgrade setuptools pytest twine wheel" + - "python setup.py install" build_script: - "python setup.py bdist_wheel" test_script: - - "python setup.py test" + - "pytest" deploy_script: - ps: If ($env:APPVEYOR_REPO_TAG -eq "true") { Invoke-Expression "twine upload --skip-existing -u sbraz dist/*" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/docs/index.rst new/pymediainfo-4.3/docs/index.rst --- old/pymediainfo-4.2.1/docs/index.rst 2020-04-30 00:07:55.000000000 +0200 +++ new/pymediainfo-4.3/docs/index.rst 2020-11-07 18:47:33.000000000 +0100 @@ -13,11 +13,17 @@ ============ This is a simple wrapper around the MediaInfo library, which you can find -at https://mediaarea.net/en/MediaInfo +at https://mediaarea.net/en/MediaInfo. -Binary wheels containing the library are provided for Windows and Mac OS X. +.. note:: + * Without the library, this package **cannot parse media files**, + which severely limits its functionality. -Packages are available for `several Linux distributions <https://repology.org/metapackage/python:pymediainfo>`_. + * Binary wheels containing a bundled library version are provided for Windows and Mac OS X. + + * Packages are available for `several major Linux distributions <https://repology.org/metapackage/python:pymediainfo>`_. + They depend on the library most of the time and are the preferred way to use pymediainfo + on Linux unless a specific version of the package is required. =============== Using MediaInfo @@ -26,26 +32,96 @@ There isn't much to this library so instead of a lot of documentation it is probably best to just demonstrate how it works: +Getting information from an image +--------------------------------- + .. code-block:: python - from pymediainfo import MediaInfo - media_info = MediaInfo.parse('my_video_file.mov') - for track in media_info.tracks: - if track.track_type == 'Video': - print(track.bit_rate, track.bit_rate_mode, track.codec) - - # output: 46033920 CBR DV + from pymediainfo import MediaInfo + + media_info = MediaInfo.parse("/home/user/image.jpg") + for track in media_info.tracks: + if track.track_type == "Image": + print(f"{track.format} of {track.width}×{track.height} pixels.") + +Will return something like: + +.. code-block:: none + + JPEG of 828×828 pixels. + +Getting information from a video +-------------------------------- + +.. code-block:: python + + from pprint import pprint + from pymediainfo import MediaInfo + + media_info = MediaInfo.parse("my_video_file.mp4") + for track in media_info.tracks: + if track.track_type == "Video": + print("Bit rate: {t.bit_rate}, Frame rate: {t.frame_rate}, " + "Format: {t.format}".format(t=track) + ) + print("Duration (raw value):", track.duration) + print("Duration (other values:") + pprint(track.other_duration) + elif track.track_type == "Audio": + print("Track data:") + pprint(track.to_data()) + +Will return something like: + +.. code-block:: none + + Bit rate: 3117597, Frame rate: 23.976, Format: AVC + Duration (raw value): 958 + Duration (other values): + ['958 ms', + '958 ms', + '958 ms', + '00:00:00.958', + '00:00:00;23', + '00:00:00.958 (00:00:00;23)'] + Track data: + {'bit_rate': 236392, + 'bit_rate_mode': 'VBR', + 'channel_layout': 'L R', + 'channel_positions': 'Front: L R', + 'channel_s': 2, + 'codec_id': 'mp4a-40-2', + 'commercial_name': 'AAC', + 'compression_mode': 'Lossy', + … + } + + +Dumping objects +--------------- + +In order to make debugging easier, :class:`pymediainfo.MediaInfo` +and :class:`pymediainfo.Track` objects can be converted to `dict` +using :py:meth:`pymediainfo.MediaInfo.to_data` and +:py:meth:`pymediainfo.Track.to_data` respectively. The previous +example demonstrates that. + +Parsing existing MediaInfo output +--------------------------------- If you already have the XML data in a string in memory (e.g. you have previously -parsed the file or were sent the dump from `mediainfo` from someone else) you -can call the constructor directly: +parsed the file or were sent the dump from ``mediainfo --output=OLDXML`` by someone +else), you can call the constructor directly: .. code-block:: python from pymediainfo import MediaInfo media_info = MediaInfo(raw_xml_string) -Since the attributes on the `Track` objects are being dynamically added as the +Accessing Track attributes +-------------------------- + +Since the attributes on the :class:`pymediainfo.Track` objects are being dynamically added as the XML output from MediaInfo is being parsed, there isn't a firm definition of what will be available at runtime. In order to make consuming the objects easier so that you can avoid having to use `hasattr` or `try/except` blocks, the @@ -57,13 +133,13 @@ .. code-block:: python from pymediainfo import MediaInfo - media_info = MediaInfo.parse('my_video_file.mov') + media_info = MediaInfo.parse("my_video_file.mp4") for track in media_info.tracks: - if track.bit_rate is not None: - print("{}: {}".format(track.track_type, track.bit_rate)) - else: + if track.bit_rate is None: print("""{} tracks do not have bit rate associated with them.""".format(track.track_type)) + else: + print("{}: {}".format(track.track_type, track.bit_rate)) Output: @@ -88,4 +164,3 @@ * :ref:`genindex` * :ref:`modindex` * :ref:`search` - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/pymediainfo/__init__.py new/pymediainfo-4.3/pymediainfo/__init__.py --- old/pymediainfo-4.2.1/pymediainfo/__init__.py 2020-04-30 00:07:55.000000000 +0200 +++ new/pymediainfo-4.3/pymediainfo/__init__.py 2020-11-07 18:47:33.000000000 +0100 @@ -160,14 +160,12 @@ for xml_track in xml_dom.iterfind(xpath): self.tracks.append(Track(xml_track)) @staticmethod - def _parse_filename(filename): + def _normalize_filename(filename): if hasattr(os, "PathLike") and isinstance(filename, os.PathLike): - return os.fspath(filename), False - elif pathlib is not None and isinstance(filename, pathlib.PurePath): - return str(filename), False - else: - url = urlparse.urlparse(filename) - return filename, bool(url.scheme) + return os.fspath(filename) + if pathlib is not None and isinstance(filename, pathlib.PurePath): + return str(filename) + return filename @staticmethod def _get_library(library_file=None): os_is_nt = os.name in ("nt", "dos", "os2", "ce") @@ -205,6 +203,14 @@ lib.MediaInfo_Inform.restype = ctypes.c_wchar_p lib.MediaInfo_Open.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p] lib.MediaInfo_Open.restype = ctypes.c_size_t + lib.MediaInfo_Open_Buffer_Init.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64,] + lib.MediaInfo_Open_Buffer_Init.restype = ctypes.c_size_t + lib.MediaInfo_Open_Buffer_Continue.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t,] + lib.MediaInfo_Open_Buffer_Continue.restype = ctypes.c_size_t + lib.MediaInfo_Open_Buffer_Continue_GoTo_Get.argtypes = [ctypes.c_void_p] + lib.MediaInfo_Open_Buffer_Continue_GoTo_Get.restype = ctypes.c_uint64 + lib.MediaInfo_Open_Buffer_Finalize.argtypes = [ctypes.c_void_p] + lib.MediaInfo_Open_Buffer_Finalize.restype = ctypes.c_size_t lib.MediaInfo_Delete.argtypes = [ctypes.c_void_p] lib.MediaInfo_Delete.restype = None lib.MediaInfo_Close.argtypes = [ctypes.c_void_p] @@ -248,7 +254,7 @@ Doing so will cause inconsistencies or failures by changing library options that are shared across threads. - :param filename: path to the media file which will be analyzed. + :param filename: path to the media file or file-like object which will be analyzed. A URL can also be used if libmediainfo was compiled with CURL support. :param str library_file: path to the libmediainfo library, this should only be used if the library cannot be auto-detected. @@ -280,13 +286,12 @@ * ``"JSON"`` * ``%``-delimited templates (see ``mediainfo --Info-Parameters``) - :type filename: str or pathlib.Path or os.PathLike + :type filename: str or pathlib.Path or os.PathLike or file-like object. :rtype: str if `output` is set. :rtype: :class:`MediaInfo` otherwise. - :raises FileNotFoundError: if passed a non-existent file - (Python ≥ 3.3), does not work on Windows. - :raises IOError: if passed a non-existent file (Python < 3.3), - does not work on Windows. + :raises FileNotFoundError: if passed a non-existent file. + :raises IOError: if passed a non-existent file (Python < 3.3). + :raises ValueError: if passed a file-like object opened in text mode. :raises RuntimeError: if parsing fails, this should not happen unless libmediainfo itself fails. @@ -304,13 +309,6 @@ """ lib, handle, lib_version_str, lib_version = cls._get_library(library_file) - filename, is_url = cls._parse_filename(filename) - # Try to open the file (if it's not a URL) - # Doesn't work on Windows because paths are URLs - if not is_url: - # Test whether the file is readable - with open(filename, "rb"): - pass # The XML option was renamed starting with version 17.10 if lib_version >= (17, 10): xml_option = "OLDXML" @@ -346,11 +344,51 @@ ) for option_name, option_value in mediainfo_options.items(): lib.MediaInfo_Option(handle, option_name, option_value) - if lib.MediaInfo_Open(handle, filename) == 0: - lib.MediaInfo_Close(handle) - lib.MediaInfo_Delete(handle) - raise RuntimeError("An eror occured while opening {}" - " with libmediainfo".format(filename)) + try: + filename.seek(0, 2) + file_size = filename.tell() + filename.seek(0) + except AttributeError: # filename is not a file-like object + file_size = None + + if file_size is not None: # We have a file-like object, use the buffer protocol: + # Some file-like objects do not have a mode + if "b" not in getattr(filename, "mode", "b"): + raise ValueError("File should be opened in binary mode") + lib.MediaInfo_Open_Buffer_Init(handle, file_size, 0) + while True: + buffer = filename.read(64 * 1024) + if buffer: + # https://github.com/MediaArea/MediaInfoLib/blob/v20.09/Source/MediaInfo/File__Analyze.h#L1429 + # 4th bit = finished + if lib.MediaInfo_Open_Buffer_Continue(handle, buffer, len(buffer)) & 0x08: + break + # Ask MediaInfo if we need to seek + seek = lib.MediaInfo_Open_Buffer_Continue_GoTo_Get(handle) + # https://github.com/MediaArea/MediaInfoLib/blob/v20.09/Source/MediaInfoDLL/MediaInfoJNI.cpp#L127 + if seek != ctypes.c_uint64(-1).value: + filename.seek(seek) + # Inform MediaInfo we have sought + lib.MediaInfo_Open_Buffer_Init(handle, file_size, filename.tell()) + else: + break + lib.MediaInfo_Open_Buffer_Finalize(handle) + else: # We have a filename, simply pass it: + filename = cls._normalize_filename(filename) + # If an error occured + if lib.MediaInfo_Open(handle, filename) == 0: + lib.MediaInfo_Close(handle) + lib.MediaInfo_Delete(handle) + # If filename doesn't look like a URL and doesn't exist + if "://" not in filename and not os.path.exists(filename): + try: + Error = FileNotFoundError + except NameError: # Python 2 compat + Error = IOError + raise Error(filename) + # We ran into another kind of error + raise RuntimeError("An error occured while opening {}" + " with libmediainfo".format(filename)) info = lib.MediaInfo_Inform(handle, 0) # Reset all options to their defaults so that they aren't # retained when the parse method is called several times diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/pymediainfo.egg-info/PKG-INFO new/pymediainfo-4.3/pymediainfo.egg-info/PKG-INFO --- old/pymediainfo-4.2.1/pymediainfo.egg-info/PKG-INFO 2020-04-30 00:08:01.000000000 +0200 +++ new/pymediainfo-4.3/pymediainfo.egg-info/PKG-INFO 2020-11-07 18:47:40.000000000 +0100 @@ -1,6 +1,6 @@ -Metadata-Version: 1.1 +Metadata-Version: 1.2 Name: pymediainfo -Version: 4.2.1 +Version: 4.3 Summary: A Python wrapper for the mediainfo library. Home-page: https://github.com/sbraz/pymediainfo Author: Louis Sautier @@ -23,8 +23,8 @@ .. image:: https://img.shields.io/pypi/implementation/pymediainfo.svg :target: https://pypi.org/project/pymediainfo - .. image:: https://api.travis-ci.org/sbraz/pymediainfo.svg?branch=master - :target: https://travis-ci.org/sbraz/pymediainfo + .. image:: https://travis-ci.com/sbraz/pymediainfo.svg?branch=master + :target: https://travis-ci.com/sbraz/pymediainfo .. image:: https://ci.appveyor.com/api/projects/status/g15a2daem1oub57n/branch/master?svg=true :target: https://ci.appveyor.com/project/sbraz/pymediainfo @@ -32,7 +32,7 @@ This small package is a wrapper around the MediaInfo library. - It works on Linux, Mac OS X and Windows and is tested with Python 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, PyPy and PyPy3. + It works on Linux, Mac OS X and Windows and is tested with Python 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, PyPy and PyPy3. See https://pymediainfo.readthedocs.io/ for more information. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/pymediainfo.egg-info/SOURCES.txt new/pymediainfo-4.3/pymediainfo.egg-info/SOURCES.txt --- old/pymediainfo-4.2.1/pymediainfo.egg-info/SOURCES.txt 2020-04-30 00:08:01.000000000 +0200 +++ new/pymediainfo-4.3/pymediainfo.egg-info/SOURCES.txt 2020-11-07 18:47:40.000000000 +0100 @@ -23,6 +23,9 @@ tests/data/accentué.txt tests/data/invalid.xml tests/data/issue55.flv +tests/data/mp3.mp3 +tests/data/mp4-with-audio.mp4 +tests/data/mpeg4.mp4 tests/data/sample.mkv tests/data/sample.mp4 tests/data/sample.xml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/setup.cfg new/pymediainfo-4.3/setup.cfg --- old/pymediainfo-4.2.1/setup.cfg 2020-04-30 00:08:01.000000000 +0200 +++ new/pymediainfo-4.3/setup.cfg 2020-11-07 18:47:40.096912400 +0100 @@ -14,6 +14,7 @@ [tool:pytest] addopts = -vv -r a +markers = internet: tests that require Internet access [bdist_wheel] universal = 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/setup.py new/pymediainfo-4.3/setup.py --- old/pymediainfo-4.2.1/setup.py 2020-04-30 00:07:55.000000000 +0200 +++ new/pymediainfo-4.3/setup.py 2020-11-07 18:47:33.000000000 +0100 @@ -51,7 +51,6 @@ use_scm_version=True, setup_requires=["setuptools_scm"], install_requires=["setuptools"], - tests_require=["pytest", "pytest-runner"], package_data={'pymediainfo': bin_files}, cmdclass=cmdclass, classifiers=[ Binary files old/pymediainfo-4.2.1/tests/data/mp3.mp3 and new/pymediainfo-4.3/tests/data/mp3.mp3 differ Binary files old/pymediainfo-4.2.1/tests/data/mp4-with-audio.mp4 and new/pymediainfo-4.3/tests/data/mp4-with-audio.mp4 differ Binary files old/pymediainfo-4.2.1/tests/data/mpeg4.mp4 and new/pymediainfo-4.3/tests/data/mpeg4.mp4 differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pymediainfo-4.2.1/tests/test_pymediainfo.py new/pymediainfo-4.3/tests/test_pymediainfo.py --- old/pymediainfo-4.2.1/tests/test_pymediainfo.py 2020-04-30 00:07:55.000000000 +0200 +++ new/pymediainfo-4.3/tests/test_pymediainfo.py 2020-11-07 18:47:33.000000000 +0100 @@ -12,14 +12,14 @@ from pymediainfo import MediaInfo -os_is_nt = os.name in ("nt", "dos", "os2", "ce") - if sys.version_info < (3, 3): FileNotFoundError = IOError if sys.version_info < (3, 2): unittest.TestCase.assertRegex = unittest.TestCase.assertRegexpMatches data_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data") +test_media_files = ["sample.mkv", "sample.mp4", "sample_with_cover.mp3", + "mpeg4.mp4", "mp3.mp3", "mp4-with-audio.mp4"] def _get_library_version(): lib, handle, lib_version_str, lib_version = MediaInfo._get_library() @@ -85,6 +85,19 @@ self.assertEqual(self.mi.tracks[0].footersize, "59") self.assertEqual(self.non_full_mi.tracks[0].footersize, None) +class MediaInfoFileLikeTest(unittest.TestCase): + def test_can_parse(self): + with open(os.path.join(data_dir, "sample.mp4"), "rb") as f: + MediaInfo.parse(f) + @pytest.mark.skipif(sys.version_info <= (3,), reason="r and rb are equivalent in Python 2") + def test_raises_on_text_mode_even_with_text(self): + with open(os.path.join(data_dir, "sample.xml")) as f: + self.assertRaises(ValueError, MediaInfo.parse, f) + @pytest.mark.skipif(sys.version_info <= (3,), reason="r and rb are equivalent in Python 2") + def test_raises_on_text_mode(self): + with open(os.path.join(data_dir, "sample.mkv")) as f: + self.assertRaises(ValueError, MediaInfo.parse, f) + class MediaInfoUnicodeXMLTest(unittest.TestCase): def setUp(self): self.mi = MediaInfo.parse(os.path.join(data_dir, "sample.mkv")) @@ -102,6 +115,7 @@ def test_parse_unicode_file(self): self.assertEqual(len(self.mi.tracks), 1) +@pytest.mark.internet class MediaInfoURLTest(unittest.TestCase): def setUp(self): self.mi = MediaInfo.parse("https://github.com/sbraz/pymediainfo/raw/master/tests/data/sample.mkv") @@ -115,40 +129,33 @@ path = self.pathlib.Path(data_dir) / "sample.mp4" mi = MediaInfo.parse(path) self.assertEqual(len(mi.tracks), 3) - @pytest.mark.skipif(os_is_nt, reason="Windows paths are URLs") def test_parse_non_existent_path_pathlib(self): path = self.pathlib.Path(data_dir) / "this file does not exist" self.assertRaises(FileNotFoundError, MediaInfo.parse, path) class MediaInfoFilenameTypesTest(unittest.TestCase): - def test_parse_filename_str(self): + def test_normalize_filename_str(self): path = os.path.join(data_dir, "test.txt") - filename, is_url = MediaInfo._parse_filename(path) - # Windows paths are URLs - if not os_is_nt: - self.assertFalse(is_url) + filename = MediaInfo._normalize_filename(path) self.assertEqual(filename, path) - def test_parse_filename_pathlib(self): + def test_normalize_filename_pathlib(self): pathlib = pytest.importorskip("pathlib") path = pathlib.Path(data_dir, "test.txt") - filename, is_url = MediaInfo._parse_filename(path) - self.assertFalse(is_url) + filename = MediaInfo._normalize_filename(path) self.assertEqual(filename, os.path.join(data_dir, "test.txt")) @pytest.mark.skipif(sys.version_info < (3, 6), reason="os.PathLike requires Python 3.6") - def test_parse_filename_pathlike(self): + def test_normalize_filename_pathlike(self): class PathLikeObject(os.PathLike): def __fspath__(self): return os.path.join(data_dir, "test.txt") path = PathLikeObject() - filename, is_url = MediaInfo._parse_filename(path) - self.assertFalse(is_url) + filename = MediaInfo._normalize_filename(path) self.assertEqual(filename, os.path.join(data_dir, "test.txt")) - def test_parse_filename_url(self): - filename, is_url = MediaInfo._parse_filename("https://localhost") - self.assertTrue(is_url) + def test_normalize_filename_url(self): + filename = MediaInfo._normalize_filename("https://localhost") + self.assertEqual(filename, "https://localhost") class MediaInfoTestParseNonExistentFile(unittest.TestCase): - @pytest.mark.skipif(os_is_nt, reason="Windows paths are URLs") def test_parse_non_existent_path(self): path = os.path.join(data_dir, "this file does not exist") self.assertRaises(FileNotFoundError, MediaInfo.parse, path) @@ -250,7 +257,7 @@ # Unittests can't be parametrized # https://github.com/pytest-dev/pytest/issues/541 -@pytest.mark.parametrize("test_file", ["sample.mkv", "sample.mp4", "sample_with_cover.mp3"]) +@pytest.mark.parametrize("test_file", test_media_files) def test_thread_safety(test_file): lib_version_str, lib_version = _get_library_version() if lib_version < (20, 3): @@ -284,6 +291,20 @@ assert r.to_data() == expected_result.to_data() assert r == expected_result +@pytest.mark.parametrize("test_file", test_media_files) +def test_filelike_returns_the_same(test_file): + filename = os.path.join(data_dir, test_file) + mi_from_filename = MediaInfo.parse(filename) + with open(filename, "rb") as f: + mi_from_file = MediaInfo.parse(f) + assert len(mi_from_file.tracks) == len(mi_from_filename.tracks) + for track_from_file, track_from_filename in zip(mi_from_file.tracks, mi_from_filename.tracks): + # The General track will differ, typically not giving the file name + if track_from_file.track_type != "General": + # Test dicts first because they will produce a diff + assert track_from_file.to_data() == track_from_filename.to_data() + assert track_from_file == track_from_filename + class MediaInfoOutputTest(unittest.TestCase): def test_text_output(self): mi = MediaInfo.parse(os.path.join(data_dir, "sample.mp4"), output="")