Skip to content

Commit 9e54320

Browse files
jerubcopybara-github
authored andcommitted
Update parameterized.CoopTestCase to work with python3 metaclasses.
By setting and accessing __metaclass__, we were not achieving the goals of this function, which is to make it possible to have both the functionality of paramterized.TestCase and another TestCase instance with its own metaclass. Because there are client classes that are using CoopTestCase to combine parameterized.TestCase with another class that isn't using a metaclass we need to support that use-case. We do it by returning a simple multiple inheritance subclass without a combined metaclass, and emit a warning telling the author they don't need to use this method. PiperOrigin-RevId: 548732415
1 parent cadd68c commit 9e54320

File tree

3 files changed

+176
-154
lines changed

3 files changed

+176
-154
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com).
2626
`enum_values` is provided as a single string value. Additionally,
2727
`EnumParser.enum_values` is now stored as a list copy of the provided
2828
`enum_values` parameter.
29+
* (tesing) Updated `paramaterized.CoopTestCase()` to use Python 3 metaclass
30+
idioms. Most uses of this function continued working during the Python 3
31+
migration still worked because a Python 2 compatibility `__metaclass__`
32+
variables also existed. Now pure Python 3 base classes without backwards
33+
compatibility will work as intended.
2934

3035
## 1.4.0 (2023-01-11)
3136

absl/testing/parameterized.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ async def testSomeAsyncFunction(self, arg, expected):
217217
import re
218218
import types
219219
import unittest
220+
import warnings
220221

221222
from absl.testing import absltest
222223

@@ -697,10 +698,27 @@ class ExampleTest(parameterized.CoopTestCase(OtherTestCase)):
697698
Returns:
698699
A new class object.
699700
"""
700-
metaclass = type(
701-
'CoopMetaclass',
702-
(other_base_class.__metaclass__,
703-
TestGeneratorMetaclass), {})
704-
return metaclass(
705-
'CoopTestCase',
706-
(other_base_class, TestCase), {})
701+
# If the other base class has a metaclass of 'type' then trying to combine
702+
# the metaclasses will result in an MRO error. So simply combine them and
703+
# return.
704+
if type(other_base_class) == type: # pylint: disable=unidiomatic-typecheck
705+
warnings.warn(
706+
'CoopTestCase is only necessary when combining with a class that uses'
707+
' a metaclass. Use multiple inheritance like this instead: class'
708+
f' ExampleTest(paramaterized.TestCase, {other_base_class.__name__}):',
709+
stacklevel=2,
710+
)
711+
712+
class CoopTestCaseBase(other_base_class, TestCase):
713+
pass
714+
715+
return CoopTestCaseBase
716+
else:
717+
718+
class CoopMetaclass(type(other_base_class), TestGeneratorMetaclass): # pylint: disable=unused-variable
719+
pass
720+
721+
class CoopTestCaseBase(other_base_class, TestCase, metaclass=CoopMetaclass):
722+
pass
723+
724+
return CoopTestCaseBase

0 commit comments

Comments
 (0)