diff --git a/.flake8 b/.flake8 index 6c3b6d91..7c9b9bd7 100644 --- a/.flake8 +++ b/.flake8 @@ -1,5 +1,8 @@ [flake8] -ignore = E203, E266, E501, W503, E221 +# B028 No explicit stacklevel argument found. +# B907 'foo' is manually surrounded by quotes, consider using the `!r` conversion flag. +# B905 `zip()` without an explicit `strict=` parameter. +ignore = E203, E266, E501, W503, E221, B028, B905, B907 max-line-length = 88 max-complexity = 18 select = B,C,E,F,W,T4,B9 diff --git a/pytorch3d/implicitron/dataset/load_llff.py b/pytorch3d/implicitron/dataset/load_llff.py index e9fecb89..d19337a9 100644 --- a/pytorch3d/implicitron/dataset/load_llff.py +++ b/pytorch3d/implicitron/dataset/load_llff.py @@ -34,11 +34,7 @@ def _minify(basedir, path_manager, factors=(), resolutions=()): imgdir = os.path.join(basedir, "images") imgs = [os.path.join(imgdir, f) for f in sorted(_ls(path_manager, imgdir))] - imgs = [ - f - for f in imgs - if any([f.endswith(ex) for ex in ["JPG", "jpg", "png", "jpeg", "PNG"]]) - ] + imgs = [f for f in imgs if f.endswith("JPG", "jpg", "png", "jpeg", "PNG")] imgdir_orig = imgdir wd = os.getcwd() diff --git a/pytorch3d/implicitron/dataset/utils.py b/pytorch3d/implicitron/dataset/utils.py index 439de5b2..01573a1a 100644 --- a/pytorch3d/implicitron/dataset/utils.py +++ b/pytorch3d/implicitron/dataset/utils.py @@ -200,7 +200,7 @@ def resize_image( mode: str = "bilinear", ) -> Tuple[torch.Tensor, float, torch.Tensor]: - if type(image) == np.ndarray: + if isinstance(image, np.ndarray): image = torch.from_numpy(image) if image_height is None or image_width is None: diff --git a/pytorch3d/io/obj_io.py b/pytorch3d/io/obj_io.py index bc2f5789..834c51ed 100644 --- a/pytorch3d/io/obj_io.py +++ b/pytorch3d/io/obj_io.py @@ -750,7 +750,7 @@ def save_obj( if path_manager is None: path_manager = PathManager() - save_texture = all([t is not None for t in [faces_uvs, verts_uvs, texture_map]]) + save_texture = all(t is not None for t in [faces_uvs, verts_uvs, texture_map]) output_path = Path(f) # Save the .obj file diff --git a/pytorch3d/renderer/utils.py b/pytorch3d/renderer/utils.py index 2a15438e..e2c37871 100644 --- a/pytorch3d/renderer/utils.py +++ b/pytorch3d/renderer/utils.py @@ -453,6 +453,6 @@ def parse_image_size( raise ValueError("Image size can only be a tuple/list of (H, W)") if not all(i > 0 for i in image_size): raise ValueError("Image sizes must be greater than 0; got %d, %d" % image_size) - if not all(type(i) == int for i in image_size): + if not all(isinstance(i, int) for i in image_size): raise ValueError("Image sizes must be integers; got %f, %f" % image_size) return tuple(image_size) diff --git a/pytorch3d/structures/meshes.py b/pytorch3d/structures/meshes.py index 19f11264..e1ad35d2 100644 --- a/pytorch3d/structures/meshes.py +++ b/pytorch3d/structures/meshes.py @@ -1698,7 +1698,7 @@ def join_meshes_as_batch(meshes: List[Meshes], include_textures: bool = True) -> # Now we know there are multiple meshes and they have textures to merge. all_textures = [mesh.textures for mesh in meshes] first = all_textures[0] - tex_types_same = all(type(tex) == type(first) for tex in all_textures) + tex_types_same = all(type(tex) == type(first) for tex in all_textures) # noqa: E721 if not tex_types_same: raise ValueError("All meshes in the batch must have the same type of texture.") diff --git a/pytorch3d/transforms/transform3d.py b/pytorch3d/transforms/transform3d.py index c0433064..cbef7cbb 100644 --- a/pytorch3d/transforms/transform3d.py +++ b/pytorch3d/transforms/transform3d.py @@ -440,22 +440,22 @@ class Transform3d: def translate(self, *args, **kwargs) -> "Transform3d": return self.compose( - Translate(device=self.device, dtype=self.dtype, *args, **kwargs) + Translate(*args, device=self.device, dtype=self.dtype, **kwargs) ) def scale(self, *args, **kwargs) -> "Transform3d": return self.compose( - Scale(device=self.device, dtype=self.dtype, *args, **kwargs) + Scale(*args, device=self.device, dtype=self.dtype, **kwargs) ) def rotate(self, *args, **kwargs) -> "Transform3d": return self.compose( - Rotate(device=self.device, dtype=self.dtype, *args, **kwargs) + Rotate(*args, device=self.device, dtype=self.dtype, **kwargs) ) def rotate_axis_angle(self, *args, **kwargs) -> "Transform3d": return self.compose( - RotateAxisAngle(device=self.device, dtype=self.dtype, *args, **kwargs) + RotateAxisAngle(*args, device=self.device, dtype=self.dtype, **kwargs) ) def clone(self) -> "Transform3d": diff --git a/tests/implicitron/models/test_utils.py b/tests/implicitron/models/test_utils.py index b86f7fd4..17c21c0e 100644 --- a/tests/implicitron/models/test_utils.py +++ b/tests/implicitron/models/test_utils.py @@ -15,15 +15,14 @@ from pytorch3d.implicitron.models.utils import preprocess_input, weighted_sum_lo class TestUtils(unittest.TestCase): def test_prepare_inputs_wrong_num_dim(self): img = torch.randn(3, 3, 3) - with self.assertRaises(ValueError) as context: + text = ( + "Model received unbatched inputs. " + + "Perhaps they came from a FrameData which had not been collated." + ) + with self.assertRaisesRegex(ValueError, text): img, fg_prob, depth_map = preprocess_input( img, None, None, True, True, 0.5, (0.0, 0.0, 0.0) ) - self.assertEqual( - "Model received unbatched inputs. " - + "Perhaps they came from a FrameData which had not been collated.", - context.exception, - ) def test_prepare_inputs_mask_image_true(self): batch, channels, height, width = 2, 3, 10, 10 diff --git a/tests/implicitron/test_frame_data_builder.py b/tests/implicitron/test_frame_data_builder.py index 28b5e046..73145815 100644 --- a/tests/implicitron/test_frame_data_builder.py +++ b/tests/implicitron/test_frame_data_builder.py @@ -224,6 +224,7 @@ class TestFrameDataBuilder(TestCaseMixin, unittest.TestCase): def test_load_mask(self): path = os.path.join(self.dataset_root, self.frame_annotation.mask.path) + path = self.path_manager.get_local_path(path) mask = load_mask(path) self.assertEqual(mask.dtype, np.float32) self.assertLessEqual(np.max(mask), 1.0) @@ -231,12 +232,14 @@ class TestFrameDataBuilder(TestCaseMixin, unittest.TestCase): def test_load_depth(self): path = os.path.join(self.dataset_root, self.frame_annotation.depth.path) + path = self.path_manager.get_local_path(path) depth_map = load_depth(path, self.frame_annotation.depth.scale_adjustment) self.assertEqual(depth_map.dtype, np.float32) self.assertEqual(len(depth_map.shape), 3) def test_load_16big_png_depth(self): path = os.path.join(self.dataset_root, self.frame_annotation.depth.path) + path = self.path_manager.get_local_path(path) depth_map = load_16big_png_depth(path) self.assertEqual(depth_map.dtype, np.float32) self.assertEqual(len(depth_map.shape), 2) @@ -245,6 +248,7 @@ class TestFrameDataBuilder(TestCaseMixin, unittest.TestCase): mask_path = os.path.join( self.dataset_root, self.frame_annotation.depth.mask_path ) + mask_path = self.path_manager.get_local_path(mask_path) mask = load_1bit_png_mask(mask_path) self.assertEqual(mask.dtype, np.float32) self.assertEqual(len(mask.shape), 2) @@ -253,6 +257,7 @@ class TestFrameDataBuilder(TestCaseMixin, unittest.TestCase): mask_path = os.path.join( self.dataset_root, self.frame_annotation.depth.mask_path ) + mask_path = self.path_manager.get_local_path(mask_path) mask = load_depth_mask(mask_path) self.assertEqual(mask.dtype, np.float32) self.assertEqual(len(mask.shape), 3) diff --git a/tests/implicitron/test_models_renderer_base.py b/tests/implicitron/test_models_renderer_base.py index 7c1f978d..2a4ff16d 100644 --- a/tests/implicitron/test_models_renderer_base.py +++ b/tests/implicitron/test_models_renderer_base.py @@ -38,22 +38,23 @@ class TestRendererBase(TestCaseMixin, unittest.TestCase): def test_implicitron_raise_value_error_bins_is_set_and_try_to_set_lengths( self, ) -> None: - with self.assertRaises(ValueError) as context: - ray_bundle = ImplicitronRayBundle( - origins=torch.rand(2, 3, 4, 3), - directions=torch.rand(2, 3, 4, 3), - lengths=None, - xys=torch.rand(2, 3, 4, 2), - bins=torch.rand(2, 3, 4, 1), - ) + ray_bundle = ImplicitronRayBundle( + origins=torch.rand(2, 3, 4, 3), + directions=torch.rand(2, 3, 4, 3), + lengths=None, + xys=torch.rand(2, 3, 4, 2), + bins=torch.rand(2, 3, 4, 14), + ) + with self.assertRaisesRegex( + ValueError, + "If the bins attribute is not None you cannot set the lengths attribute.", + ): ray_bundle.lengths = torch.empty(2) - self.assertEqual( - str(context.exception), - "If the bins attribute is not None you cannot set the lengths attribute.", - ) def test_implicitron_raise_value_error_if_bins_dim_equal_1(self) -> None: - with self.assertRaises(ValueError) as context: + with self.assertRaisesRegex( + ValueError, "The last dim of bins must be at least superior or equal to 2." + ): ImplicitronRayBundle( origins=torch.rand(2, 3, 4, 3), directions=torch.rand(2, 3, 4, 3), @@ -61,15 +62,14 @@ class TestRendererBase(TestCaseMixin, unittest.TestCase): xys=torch.rand(2, 3, 4, 2), bins=torch.rand(2, 3, 4, 1), ) - self.assertEqual( - str(context.exception), - "The last dim of bins must be at least superior or equal to 2.", - ) def test_implicitron_raise_value_error_if_neither_bins_or_lengths_provided( self, ) -> None: - with self.assertRaises(ValueError) as context: + with self.assertRaisesRegex( + ValueError, + "Please set either bins or lengths to initialize an ImplicitronRayBundle.", + ): ImplicitronRayBundle( origins=torch.rand(2, 3, 4, 3), directions=torch.rand(2, 3, 4, 3), @@ -77,10 +77,6 @@ class TestRendererBase(TestCaseMixin, unittest.TestCase): xys=torch.rand(2, 3, 4, 2), bins=None, ) - self.assertEqual( - str(context.exception), - "Please set either bins or lengths to initialize an ImplicitronRayBundle.", - ) def test_conical_frustum_to_gaussian(self) -> None: origins = torch.zeros(3, 3, 3) @@ -266,8 +262,6 @@ class TestRendererBase(TestCaseMixin, unittest.TestCase): ray = ImplicitronRayBundle( origins=origins, directions=directions, lengths=lengths, xys=None ) - with self.assertRaises(ValueError) as context: - _ = conical_frustum_to_gaussian(ray) expected_error_message = ( "RayBundle pixel_radii_2d or bins have not been provided." @@ -276,7 +270,8 @@ class TestRendererBase(TestCaseMixin, unittest.TestCase): "`cast_ray_bundle_as_cone` to True?" ) - self.assertEqual(expected_error_message, str(context.exception)) + with self.assertRaisesRegex(ValueError, expected_error_message): + _ = conical_frustum_to_gaussian(ray) # Ensure message is coherent with AbstractMaskRaySampler class FakeRaySampler(AbstractMaskRaySampler): diff --git a/tests/test_cameras.py b/tests/test_cameras.py index 7ca86d7d..c953e457 100644 --- a/tests/test_cameras.py +++ b/tests/test_cameras.py @@ -964,8 +964,8 @@ class TestFoVPerspectiveProjection(TestCaseMixin, unittest.TestCase): with self.assertRaisesRegex(IndexError, "out of bounds"): cam[N_CAMERAS] + index = torch.tensor([1, 0, 1], dtype=torch.bool) with self.assertRaisesRegex(ValueError, "does not match cameras"): - index = torch.tensor([1, 0, 1], dtype=torch.bool) cam[index] with self.assertRaisesRegex(ValueError, "Invalid index type"): @@ -974,8 +974,8 @@ class TestFoVPerspectiveProjection(TestCaseMixin, unittest.TestCase): with self.assertRaisesRegex(ValueError, "Invalid index type"): cam[[True, False]] + index = torch.tensor(SLICE, dtype=torch.float32) with self.assertRaisesRegex(ValueError, "Invalid index type"): - index = torch.tensor(SLICE, dtype=torch.float32) cam[index] def test_get_full_transform(self): diff --git a/tests/test_io_obj.py b/tests/test_io_obj.py index a6c7025d..3668be4e 100644 --- a/tests/test_io_obj.py +++ b/tests/test_io_obj.py @@ -422,9 +422,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): def test_save_obj_invalid_shapes(self): # Invalid vertices shape + verts = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4]]) # (V, 4) + faces = torch.LongTensor([[0, 1, 2]]) with self.assertRaises(ValueError) as error: - verts = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4]]) # (V, 4) - faces = torch.LongTensor([[0, 1, 2]]) with NamedTemporaryFile(mode="w", suffix=".obj") as f: save_obj(Path(f.name), verts, faces) expected_message = ( @@ -433,9 +433,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): self.assertTrue(expected_message, error.exception) # Invalid faces shape + verts = torch.FloatTensor([[0.1, 0.2, 0.3]]) + faces = torch.LongTensor([[0, 1, 2, 3]]) # (F, 4) with self.assertRaises(ValueError) as error: - verts = torch.FloatTensor([[0.1, 0.2, 0.3]]) - faces = torch.LongTensor([[0, 1, 2, 3]]) # (F, 4) with NamedTemporaryFile(mode="w", suffix=".obj") as f: save_obj(Path(f.name), verts, faces) expected_message = ( diff --git a/tests/test_io_ply.py b/tests/test_io_ply.py index 2b560cad..7bd2bc79 100644 --- a/tests/test_io_ply.py +++ b/tests/test_io_ply.py @@ -308,9 +308,9 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): def test_save_ply_invalid_shapes(self): # Invalid vertices shape + verts = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4]]) # (V, 4) + faces = torch.LongTensor([[0, 1, 2]]) with self.assertRaises(ValueError) as error: - verts = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4]]) # (V, 4) - faces = torch.LongTensor([[0, 1, 2]]) save_ply(BytesIO(), verts, faces) expected_message = ( "Argument 'verts' should either be empty or of shape (num_verts, 3)." @@ -318,9 +318,9 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): self.assertTrue(expected_message, error.exception) # Invalid faces shape + verts = torch.FloatTensor([[0.1, 0.2, 0.3]]) + faces = torch.LongTensor([[0, 1, 2, 3]]) # (F, 4) with self.assertRaises(ValueError) as error: - verts = torch.FloatTensor([[0.1, 0.2, 0.3]]) - faces = torch.LongTensor([[0, 1, 2, 3]]) # (F, 4) save_ply(BytesIO(), verts, faces) expected_message = ( "Argument 'faces' should either be empty or of shape (num_faces, 3)." diff --git a/tests/test_meshes.py b/tests/test_meshes.py index b14753b0..ed87437e 100644 --- a/tests/test_meshes.py +++ b/tests/test_meshes.py @@ -324,17 +324,15 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ] faces_list = mesh.faces_list() - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "same device"): Meshes(verts=verts_list, faces=faces_list) - self.assertTrue("same device" in cm.msg) verts_padded = mesh.verts_padded() # on cpu verts_padded = verts_padded.to("cuda:0") faces_padded = mesh.faces_padded() - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "same device"): Meshes(verts=verts_padded, faces=faces_padded) - self.assertTrue("same device" in cm.msg) def test_simple_random_meshes(self): diff --git a/tests/test_pointclouds.py b/tests/test_pointclouds.py index 9ad80d50..25289263 100644 --- a/tests/test_pointclouds.py +++ b/tests/test_pointclouds.py @@ -148,31 +148,28 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): features_list = clouds.features_list() normals_list = clouds.normals_list() - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "same device"): Pointclouds( points=points_list, features=features_list, normals=normals_list ) - self.assertTrue("same device" in cm.msg) points_list = clouds.points_list() features_list = [ f.to("cpu") if random.uniform(0, 1) > 0.2 else f for f in features_list ] - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "same device"): Pointclouds( points=points_list, features=features_list, normals=normals_list ) - self.assertTrue("same device" in cm.msg) points_padded = clouds.points_padded() # on cuda:0 features_padded = clouds.features_padded().to("cpu") normals_padded = clouds.normals_padded() - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "same device"): Pointclouds( points=points_padded, features=features_padded, normals=normals_padded ) - self.assertTrue("same device" in cm.msg) def test_all_constructions(self): public_getters = [ diff --git a/tests/test_rasterize_rectangle_images.py b/tests/test_rasterize_rectangle_images.py index 7a41a84c..536eb04f 100644 --- a/tests/test_rasterize_rectangle_images.py +++ b/tests/test_rasterize_rectangle_images.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import re import unittest from itertools import product @@ -102,62 +103,56 @@ class TestRasterizeRectangleImagesErrors(TestCaseMixin, unittest.TestCase): def test_mesh_image_size_arg(self): meshes = Meshes(verts=[verts0], faces=[faces0]) - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, re.escape("tuple/list of (H, W)")): rasterize_meshes( meshes, (100, 200, 3), 0.0001, faces_per_pixel=1, ) - self.assertTrue("tuple/list of (H, W)" in cm.msg) - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "sizes must be greater than 0"): rasterize_meshes( meshes, (0, 10), 0.0001, faces_per_pixel=1, ) - self.assertTrue("sizes must be positive" in cm.msg) - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "sizes must be integers"): rasterize_meshes( meshes, (100.5, 120.5), 0.0001, faces_per_pixel=1, ) - self.assertTrue("sizes must be integers" in cm.msg) def test_points_image_size_arg(self): points = Pointclouds([verts0]) - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, re.escape("tuple/list of (H, W)")): rasterize_points( points, (100, 200, 3), 0.0001, points_per_pixel=1, ) - self.assertTrue("tuple/list of (H, W)" in cm.msg) - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "sizes must be greater than 0"): rasterize_points( points, (0, 10), 0.0001, points_per_pixel=1, ) - self.assertTrue("sizes must be positive" in cm.msg) - with self.assertRaises(ValueError) as cm: + with self.assertRaisesRegex(ValueError, "sizes must be integers"): rasterize_points( points, (100.5, 120.5), 0.0001, points_per_pixel=1, ) - self.assertTrue("sizes must be integers" in cm.msg) class TestRasterizeRectangleImagesMeshes(TestCaseMixin, unittest.TestCase): diff --git a/tests/test_rasterizer.py b/tests/test_rasterizer.py index 062be7b6..8f9e6173 100644 --- a/tests/test_rasterizer.py +++ b/tests/test_rasterizer.py @@ -419,16 +419,16 @@ class TestMeshRasterizerOpenGLUtils(TestCaseMixin, unittest.TestCase): fragments = rasterizer(self.meshes_world, raster_settings=raster_settings) self.assertEqual(fragments.pix_to_face.shape, torch.Size([1, 10, 2047, 1])) + raster_settings.image_size = (2049, 512) with self.assertRaisesRegex(ValueError, "Max rasterization size is"): - raster_settings.image_size = (2049, 512) rasterizer(self.meshes_world, raster_settings=raster_settings) + raster_settings.image_size = (512, 2049) with self.assertRaisesRegex(ValueError, "Max rasterization size is"): - raster_settings.image_size = (512, 2049) rasterizer(self.meshes_world, raster_settings=raster_settings) + raster_settings.image_size = (2049, 2049) with self.assertRaisesRegex(ValueError, "Max rasterization size is"): - raster_settings.image_size = (2049, 2049) rasterizer(self.meshes_world, raster_settings=raster_settings) diff --git a/tests/test_struct_utils.py b/tests/test_struct_utils.py index 17df2bee..a40a6548 100644 --- a/tests/test_struct_utils.py +++ b/tests/test_struct_utils.py @@ -80,8 +80,8 @@ class TestStructUtils(TestCaseMixin, unittest.TestCase): self.assertClose(x_padded, torch.stack(x, 0)) # catch ValueError for invalid dimensions + pad_size = [K] * (ndim + 1) with self.assertRaisesRegex(ValueError, "Pad size must"): - pad_size = [K] * (ndim + 1) struct_utils.list_to_padded( x, pad_size=pad_size, pad_value=0.0, equisized=False ) @@ -196,9 +196,9 @@ class TestStructUtils(TestCaseMixin, unittest.TestCase): # Case 6: Input has more than 3 dims. # Raise an error. + x = torch.rand((N, K, K, K, K), device=device) + split_size = torch.randint(1, K, size=(N,)).tolist() with self.assertRaisesRegex(ValueError, "Supports only"): - x = torch.rand((N, K, K, K, K), device=device) - split_size = torch.randint(1, K, size=(N,)).tolist() struct_utils.padded_to_packed(x, split_size=split_size) def test_list_to_packed(self): diff --git a/tests/test_texturing.py b/tests/test_texturing.py index 26350b54..35269586 100644 --- a/tests/test_texturing.py +++ b/tests/test_texturing.py @@ -1055,7 +1055,7 @@ class TestRectanglePacking(TestCaseMixin, unittest.TestCase): def test_simple(self): self.assert_bb([(3, 4), (4, 3)], {6, 4}) - self.assert_bb([(2, 2), (2, 4), (2, 2)], {4, 4}) + self.assert_bb([(2, 2), (2, 4), (2, 2)], {4}) # many squares self.assert_bb([(2, 2)] * 9, {2, 18}) diff --git a/tests/test_transforms.py b/tests/test_transforms.py index 8c471e87..5a2d729f 100644 --- a/tests/test_transforms.py +++ b/tests/test_transforms.py @@ -936,8 +936,8 @@ class TestTransformBroadcast(unittest.TestCase): y = torch.tensor([0.3] * M) z = torch.tensor([0.4] * M) tM = Translate(x, y, z) + t = tN.compose(tM) with self.assertRaises(ValueError): - t = tN.compose(tM) t.get_matrix() def test_multiple_broadcast_compose(self):