From c583fcf0c1080568cf5a91f255e12c228135f7fd Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Tue, 18 Jun 2024 10:15:13 -0700 Subject: [PATCH] [torchcodec] refactor test utils into its own library (#25) Summary: Pull Request resolved: https://github.com/pytorch-labs/torchcodec/pull/25 Refactors utility functions that were defined directly in test source files into a library that can be shared among tests. This diff: 1. Creates a Python test utility library that can be imported by Python tests. 2. Moves the test resources to the test top-level. 3. Defines a C++ target for those resources. This is in preparation for adding new tests that will need this library. Reviewed By: NicolasHug Differential Revision: D58530481 --- test/__init__.py | 0 test/decoders/VideoDecoderOpsTest.cpp | 5 +- test/decoders/VideoDecoderTest.cpp | 5 +- test/decoders/__init__.py | 0 test/decoders/manual_smoke_test.py | 2 +- test/decoders/video_decoder_ops_test.py | 44 +++------------ test/{decoders => }/resources/nasa_13013.mp4 | Bin .../resources/nasa_13013.mp4.audio.mp3 | Bin .../resources/nasa_13013.mp4.frame000001.pt | Bin .../resources/nasa_13013.mp4.frame000002.pt | Bin .../resources/nasa_13013.mp4.time10.000000.pt | Bin .../resources/nasa_13013.mp4.time12.979633.pt | Bin .../resources/nasa_13013.mp4.time6.000000.pt | Bin .../resources/nasa_13013.mp4.time6.100000.pt | Bin test/samplers/__init__.py | 0 test/samplers/video_clip_sampler_test.py | 35 ++++-------- test/test_utils.py | 53 ++++++++++++++++++ 17 files changed, 75 insertions(+), 69 deletions(-) create mode 100644 test/__init__.py create mode 100644 test/decoders/__init__.py rename test/{decoders => }/resources/nasa_13013.mp4 (100%) rename test/{decoders => }/resources/nasa_13013.mp4.audio.mp3 (100%) rename test/{decoders => }/resources/nasa_13013.mp4.frame000001.pt (100%) rename test/{decoders => }/resources/nasa_13013.mp4.frame000002.pt (100%) rename test/{decoders => }/resources/nasa_13013.mp4.time10.000000.pt (100%) rename test/{decoders => }/resources/nasa_13013.mp4.time12.979633.pt (100%) rename test/{decoders => }/resources/nasa_13013.mp4.time6.000000.pt (100%) rename test/{decoders => }/resources/nasa_13013.mp4.time6.100000.pt (100%) create mode 100644 test/samplers/__init__.py create mode 100644 test/test_utils.py diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/decoders/VideoDecoderOpsTest.cpp b/test/decoders/VideoDecoderOpsTest.cpp index f23d28f4..bd72f29a 100644 --- a/test/decoders/VideoDecoderOpsTest.cpp +++ b/test/decoders/VideoDecoderOpsTest.cpp @@ -17,13 +17,12 @@ namespace facebook::torchcodec { std::string getResourcePath(const std::string& filename) { #ifdef FBCODE_BUILD - std::string filepath = - "pytorch/torchcodec/test/decoders/resources/" + filename; + std::string filepath = "pytorch/torchcodec/test/resources/" + filename; filepath = build::getResourcePath(filepath).string(); #else std::filesystem::path dirPath = std::filesystem::path(__FILE__); std::string filepath = - dirPath.parent_path().string() + "/resources/" + filename; + dirPath.parent_path().string() + "/../resources/" + filename; #endif return filepath; } diff --git a/test/decoders/VideoDecoderTest.cpp b/test/decoders/VideoDecoderTest.cpp index 506791ae..58dced45 100644 --- a/test/decoders/VideoDecoderTest.cpp +++ b/test/decoders/VideoDecoderTest.cpp @@ -24,13 +24,12 @@ namespace facebook::torchcodec { std::string getResourcePath(const std::string& filename) { #ifdef FBCODE_BUILD - std::string filepath = - "pytorch/torchcodec/test/decoders/resources/" + filename; + std::string filepath = "pytorch/torchcodec/test/resources/" + filename; filepath = build::getResourcePath(filepath).string(); #else std::filesystem::path dirPath = std::filesystem::path(__FILE__); std::string filepath = - dirPath.parent_path().string() + "/resources/" + filename; + dirPath.parent_path().string() + "/../resources/" + filename; #endif return filepath; } diff --git a/test/decoders/__init__.py b/test/decoders/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/decoders/manual_smoke_test.py b/test/decoders/manual_smoke_test.py index 07869c54..7fe5878b 100644 --- a/test/decoders/manual_smoke_test.py +++ b/test/decoders/manual_smoke_test.py @@ -4,7 +4,7 @@ import torchcodec decoder = torchcodec.decoders._core.create_from_file( - os.path.dirname(__file__) + "/resources/nasa_13013.mp4" + os.path.dirname(__file__) + "/../resources/nasa_13013.mp4" ) torchcodec.decoders._core.add_video_stream(decoder, stream_index=3) frame = torchcodec.decoders._core.get_frame_at_index( diff --git a/test/decoders/video_decoder_ops_test.py b/test/decoders/video_decoder_ops_test.py index 151417dd..06c3e2eb 100644 --- a/test/decoders/video_decoder_ops_test.py +++ b/test/decoders/video_decoder_ops_test.py @@ -1,9 +1,7 @@ import os os.environ["TORCH_LOGS"] = "output_code" -import importlib import json -import pathlib from typing import Tuple import numpy as np @@ -24,42 +22,14 @@ seek_to_pts, ) -torch._dynamo.config.capture_dynamic_output_shape_ops = True -IN_FBCODE = os.environ.get("IN_FBCODE_TORCHCODEC") == "1" - - -# TODO: Eventually move that as a common test util -def assert_equal(*args, **kwargs): - torch.testing.assert_close(*args, **kwargs, atol=0, rtol=0) - - -# TODO: Eventually move that as a common test util -def get_video_path(filename: str) -> pathlib.Path: - if IN_FBCODE: - resource = ( - importlib.resources.files(__package__) - .joinpath("resources") - .joinpath(filename) - ) - with importlib.resources.as_file(resource) as path: - return path - else: - return pathlib.Path(__file__).parent / "resources" / filename - - -# TODO: make this a fixture or wrap with @functools.lru_cache to avoid -# re-computing? -def load_tensor_from_file(filename: str) -> torch.Tensor: - file_path = get_video_path(filename) - return torch.load(file_path) - - -def get_reference_video_path() -> pathlib.Path: - return get_video_path("nasa_13013.mp4") - +from ..test_utils import ( + assert_equal, + get_reference_audio_path, + get_reference_video_path, + load_tensor_from_file, +) -def get_reference_audio_path() -> pathlib.Path: - return get_video_path("nasa_13013.mp4.audio.mp3") +torch._dynamo.config.capture_dynamic_output_shape_ops = True class ReferenceDecoder: diff --git a/test/decoders/resources/nasa_13013.mp4 b/test/resources/nasa_13013.mp4 similarity index 100% rename from test/decoders/resources/nasa_13013.mp4 rename to test/resources/nasa_13013.mp4 diff --git a/test/decoders/resources/nasa_13013.mp4.audio.mp3 b/test/resources/nasa_13013.mp4.audio.mp3 similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.audio.mp3 rename to test/resources/nasa_13013.mp4.audio.mp3 diff --git a/test/decoders/resources/nasa_13013.mp4.frame000001.pt b/test/resources/nasa_13013.mp4.frame000001.pt similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.frame000001.pt rename to test/resources/nasa_13013.mp4.frame000001.pt diff --git a/test/decoders/resources/nasa_13013.mp4.frame000002.pt b/test/resources/nasa_13013.mp4.frame000002.pt similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.frame000002.pt rename to test/resources/nasa_13013.mp4.frame000002.pt diff --git a/test/decoders/resources/nasa_13013.mp4.time10.000000.pt b/test/resources/nasa_13013.mp4.time10.000000.pt similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.time10.000000.pt rename to test/resources/nasa_13013.mp4.time10.000000.pt diff --git a/test/decoders/resources/nasa_13013.mp4.time12.979633.pt b/test/resources/nasa_13013.mp4.time12.979633.pt similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.time12.979633.pt rename to test/resources/nasa_13013.mp4.time12.979633.pt diff --git a/test/decoders/resources/nasa_13013.mp4.time6.000000.pt b/test/resources/nasa_13013.mp4.time6.000000.pt similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.time6.000000.pt rename to test/resources/nasa_13013.mp4.time6.000000.pt diff --git a/test/decoders/resources/nasa_13013.mp4.time6.100000.pt b/test/resources/nasa_13013.mp4.time6.100000.pt similarity index 100% rename from test/decoders/resources/nasa_13013.mp4.time6.100000.pt rename to test/resources/nasa_13013.mp4.time6.100000.pt diff --git a/test/samplers/__init__.py b/test/samplers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/samplers/video_clip_sampler_test.py b/test/samplers/video_clip_sampler_test.py index 490db70a..67c41ac6 100644 --- a/test/samplers/video_clip_sampler_test.py +++ b/test/samplers/video_clip_sampler_test.py @@ -1,11 +1,6 @@ # (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. -import importlib -import os -from pathlib import Path - -import numpy as np import pytest import torch from torchcodec.samplers import ( @@ -15,23 +10,10 @@ VideoClipSampler, ) - -# TODO: move this to a common util -IN_FBCODE = os.environ.get("IN_FBCODE_TORCHCODEC") == "1" - - -# TODO: Eventually rely on common util for this -@pytest.fixture() -def nasa_13013() -> torch.Tensor: - if IN_FBCODE: - video_path = importlib.resources.path(__package__, "nasa_13013.mp4") - else: - video_path = ( - Path(__file__).parent.parent / "decoders" / "resources" / "nasa_13013.mp4" - ) - arr = np.fromfile(video_path, dtype=np.uint8) - video_tensor = torch.from_numpy(arr) - return video_tensor +from ..test_utils import ( # noqa: F401; see use in test_sampler + assert_equal, + reference_video_tensor, +) @pytest.mark.parametrize( @@ -51,13 +33,16 @@ def nasa_13013() -> torch.Tensor: ), ], ) -def test_sampler(sampler_args, nasa_13013): +def test_sampler( + sampler_args, + reference_video_tensor, # noqa: F811; linter does not see this as a use +): torch.manual_seed(0) desired_width, desired_height = 320, 240 video_args = VideoArgs(desired_width=desired_width, desired_height=desired_height) sampler = VideoClipSampler(video_args, sampler_args) - clips = sampler(nasa_13013) - assert len(clips) == sampler_args.clips_per_video + clips = sampler(reference_video_tensor) + assert_equal(len(clips), sampler_args.clips_per_video) clip = clips[0] if isinstance(sampler_args, TimeBasedSamplerArgs): # TODO FIXME: Looks like we have an API inconsistency. diff --git a/test/test_utils.py b/test/test_utils.py new file mode 100644 index 00000000..313186a6 --- /dev/null +++ b/test/test_utils.py @@ -0,0 +1,53 @@ +import importlib +import os +import pathlib + +import numpy as np +import pytest + +import torch + + +def in_fbcode() -> bool: + return os.environ.get("IN_FBCODE_TORCHCODEC") == "1" + + +def assert_equal(*args, **kwargs): + torch.testing.assert_close(*args, **kwargs, atol=0, rtol=0) + + +def get_video_path(filename: str) -> pathlib.Path: + if in_fbcode(): + resource = ( + importlib.resources.files(__spec__.parent) + .joinpath("resources") + .joinpath(filename) + ) + with importlib.resources.as_file(resource) as path: + return path + else: + return pathlib.Path(__file__).parent / "resources" / filename + + +def get_reference_video_path() -> pathlib.Path: + return get_video_path("nasa_13013.mp4") + + +def get_reference_audio_path() -> pathlib.Path: + return get_video_path("nasa_13013.mp4.audio.mp3") + + +def load_tensor_from_file(filename: str) -> torch.Tensor: + file_path = get_video_path(filename) + return torch.load(file_path, weights_only=True) + + +def get_reference_video_tensor() -> torch.Tensor: + arr = np.fromfile(get_reference_video_path(), dtype=np.uint8) + video_tensor = torch.from_numpy(arr) + return video_tensor + + +@pytest.fixture() +def reference_video_tensor() -> torch.Tensor: + return get_reference_video_tensor()