diff --git a/src/pytest_cases/case_funcs.py b/src/pytest_cases/case_funcs.py index 54a1ae59..2455fb7d 100644 --- a/src/pytest_cases/case_funcs.py +++ b/src/pytest_cases/case_funcs.py @@ -54,7 +54,7 @@ def __init__(self, self.add_tags(tags) def __repr__(self): - return "_CaseInfo(id=%r,marks=%r,tags=%r)" % (self.id, self.marks, self.tags) + return f"_CaseInfo(id={self.id!r},marks={self.marks!r},tags={self.tags!r})" @classmethod def get_from(cls, diff --git a/src/pytest_cases/case_parametrizer_new.py b/src/pytest_cases/case_parametrizer_new.py index ddd36bb8..8a743d11 100644 --- a/src/pytest_cases/case_parametrizer_new.py +++ b/src/pytest_cases/case_parametrizer_new.py @@ -250,7 +250,7 @@ def get_all_cases(parametrization_target=None, # type: Callable # validate prefix if not isinstance(prefix, str): - raise TypeError("`prefix` should be a string, found: %r" % prefix) + raise TypeError(f"`prefix` should be a string, found: {prefix} ({type(prefix)})") # validate glob and filter and merge them in a single tuple of callables filters = () @@ -276,7 +276,7 @@ def get_all_cases(parametrization_target=None, # type: Callable elif callable(parametrization_target): caller_module_name = getattr(parametrization_target, '__module__', None) else: - raise ValueError("Can't handle parametrization_target=%s" % parametrization_target) + raise ValueError(f"Can't handle parametrization_target={parametrization_target}") parent_pkg_name = '.'.join(caller_module_name.split('.')[:-1]) if caller_module_name is not None else None @@ -295,7 +295,7 @@ def get_all_cases(parametrization_target=None, # type: Callable shall_bind, bound_c = needs_binding(c, return_bound=True) cases_funs.append(bound_c) else: - raise ValueError("Unsupported case function: %r" % c) + raise ValueError(f"Unsupported case function: {c!r}") else: # module if c is AUTO: @@ -306,9 +306,8 @@ def get_all_cases(parametrization_target=None, # type: Callable # import_default_cases_module. See #309. if not caller_module_name.split('.')[-1].startswith('test_'): raise ValueError( - 'Cannot use `cases=AUTO` in file "%s". `cases=AUTO` is ' + f'Cannot use `cases=AUTO` in file "{caller_module_name}". `cases=AUTO` is ' 'only allowed in files whose name starts with "test_" ' - % caller_module_name ) # First try `test__cases.py` Then `cases_.py` c = import_default_cases_module(caller_module_name) @@ -447,8 +446,8 @@ def case_to_argvalues(host_class_or_module, # type: Union[Type, ModuleType] # single unparametrized case function if debug: case_fun_str = qname(case_fun.func if isinstance(case_fun, functools.partial) else case_fun) - print("Case function %s > 1 lazy_value() with id %s and additional marks %s" - % (case_fun_str, case_id, case_marks)) + print(f"Case function {case_fun_str} > 1 lazy_value() with id {case_id} " + f"and additional marks {case_marks}") return (_LazyValueCaseParamValue(case_fun, id=case_id, marks=case_marks),) # else: # THIS WAS A PREMATURE OPTIMIZATION WITH MANY SHORTCOMINGS. For example what if the case function is @@ -459,11 +458,12 @@ def case_to_argvalues(host_class_or_module, # type: Union[Type, ModuleType] # # do not forget to merge the marks ! # if debug: # case_fun_str = qname(case_fun.func if isinstance(case_fun, functools.partial) else case_fun) - # print("Case function %s > tuple of lazy_value() with ids %s and additional marks %s" - # % (case_fun_str, ["%s-%s" % (case_id, c.id) for c in meta._calls], - # [case_marks + tuple(c.marks) for c in meta._calls])) + # ids = [f"{case_id}-{case_id}" for c in meta._calls] + # additional_marks = [case_marks + tuple(c.marks) for c in meta._calls] + # print(f"Case function {case_fun_str} > tuple of lazy_value() with ids {ids} " + # f" and additional marks {additional_marks}") # return tuple(lazy_value(functools.partial(case_fun, **c.funcargs), - # id="%s-%s" % (case_id, c.id), marks=case_marks + tuple(c.marks)) + # id=f"{case_id}-{c.id}", marks=case_marks + tuple(c.marks)) # for c in meta._calls) else: # at least 1 required fixture (direct req or through @pytest.mark.usefixtures ), OR parametrized. @@ -480,7 +480,7 @@ def case_to_argvalues(host_class_or_module, # type: Union[Type, ModuleType] argvalues = _FixtureRefCaseParamValue(fix_name, id=case_id) if debug: case_fun_str = qname(case_fun.func if isinstance(case_fun, functools.partial) else case_fun) - print("Case function %s > fixture_ref(%r) with marks %s" % (case_fun_str, fix_name, remaining_marks)) + print(f"Case function {case_fun_str} > fixture_ref({fix_name!r}) with marks {remaining_marks}") # return a length-1 tuple because there is a single case created return (make_marked_parameter_value((argvalues,), marks=remaining_marks) if remaining_marks else argvalues,) @@ -518,8 +518,8 @@ def get_or_create_case_fixture(case_id, # type: str """ if is_fixture(case_fun): raise ValueError("A case function can not be decorated as a `@fixture`. This seems to be the case for" - " %s. If you did not decorate it but still see this error, please report this issue" - % case_fun) + f" {case_fun}. If you did not decorate it but still see this error, please report this issue" + ) # source: detect a functools.partial wrapper created by us because of a host class true_case_func, case_in_class = _get_original_case_func(case_fun) @@ -537,7 +537,7 @@ def get_or_create_case_fixture(case_id, # type: str try: fix_name, marks = fix_cases_dct[(true_case_func, scope)] if debug: - print("Case function %s > Reusing fixture %r and marks %s" % (qname(true_case_func), fix_name, marks)) + print(f"Case function {qname(true_case_func)} > Reusing fixture {fix_name!r} and marks {marks}") return fix_name, marks except KeyError: pass @@ -558,9 +558,9 @@ def get_or_create_case_fixture(case_id, # type: str for f in list_all_fixtures_in(true_case_func_host, recurse_to_module=False, return_names=False): f_name = get_fixture_name(f) if (f_name in existing_fixture_names) or (f.__name__ in existing_fixture_names): - raise ValueError("Cannot import fixture %r from %r as it would override an existing symbol " - "in %r. Please set `@parametrize_with_cases(import_fixtures=False)`" - "" % (f, from_module, target_host)) + raise ValueError(f"Cannot import fixture {f!r} from {from_module!r} as it would override " + f"an existing symbol in {target_host!r}. " + "Please set `@parametrize_with_cases(import_fixtures=False)`") target_host_module = target_host if not target_in_class else get_host_module(target_host) setattr(target_host_module, f.__name__, f) @@ -592,7 +592,7 @@ def name_changer(name, i): if_name_exists=CHANGE, name_changer=name_changer) if debug: - print("Case function %s > Creating fixture %r in %s" % (qname(true_case_func), fix_name, target_host)) + print(f"Case function {qname(true_case_func)} > Creating fixture {fix_name!r} in {target_host}") if case_in_class: if target_in_class: @@ -687,7 +687,7 @@ def import_default_cases_module(test_module_name): :return: """ # First try `test__cases.py` - cases_module_name1 = "%s_cases" % test_module_name + cases_module_name1 = f"{test_module_name}_cases" try: cases_module = import_module(cases_module_name1) @@ -695,15 +695,14 @@ def import_default_cases_module(test_module_name): # Then try `cases_.py` parts = test_module_name.split('.') assert parts[-1][0:5] == 'test_' - cases_module_name2 = "%s.cases_%s" % ('.'.join(parts[:-1]), parts[-1][5:]) + cases_module_name2 = f"{'.'.join(parts[:-1])}.cases_{parts[-1][5:]}" try: cases_module = import_module(cases_module_name2) except ModuleNotFoundError: # Nothing worked - raise ValueError("Error importing test cases module to parametrize %r: unable to import AUTO " - "cases module %r nor %r. Maybe you wish to import cases from somewhere else ? In that case" - " please specify `cases=...`." - % (test_module_name, cases_module_name1, cases_module_name2)) + raise ValueError(f"Error importing test cases module to parametrize {test_module_name}: unable to import " + f"AUTO cases module {cases_module_name1!r} nor {cases_module_name2!r}. Maybe you wish " + "to import cases from somewhere else ? In that case please specify `cases=...`.") return cases_module @@ -763,18 +762,16 @@ def extract_cases_from_class(cls, if hasinit(cls): warn( CasesCollectionWarning( - "cannot collect cases class %r because it has a " + f"cannot collect cases class {cls.__name__!r} because it has a " "__init__ constructor" - % (cls.__name__, ) ) ) return [] elif hasnew(cls): warn( CasesCollectionWarning( - "cannot collect test class %r because it has a " + f"cannot collect test class {cls.__name__!r} because it has a " "__new__ constructor" - % (cls.__name__, ) ) ) return [] @@ -826,8 +823,8 @@ def extract_cases_from_module(module, # type: Union[st module = import_module(module, package=package_name) except ModuleNotFoundError as e: raise ModuleNotFoundError( - "Error loading cases from module. `import_module(%r, package=%r)` raised an error: %r" - % (module, package_name, e) + f"Error loading cases from module. `import_module({module!r}, package={package_name!r})` " + f"raised an error: {e!r}" ) return _extract_cases_from_module_or_class(module=module, _case_param_factory=_case_param_factory, @@ -905,9 +902,9 @@ def _of_interest(x): # noqa else: # currently we only support replacing inside the same module if m_for_placing.__module__ != m.__module__: - raise ValueError("Unsupported value for 'place_as' special pytest attribute on case function %s: %s" - ". Virtual placing in another module is not supported yet by pytest-cases." - % (m, m_for_placing)) + raise ValueError("Unsupported value for 'place_as' special pytest attribute on case function " + f"{m}: {m_for_placing}. Virtual placing in another module is not supported yet " + "by pytest-cases.") co_firstlineno = get_code_first_line(m_for_placing) if cls is not None: @@ -926,7 +923,7 @@ def _of_interest(x): # noqa pass else: if len(s.parameters) < 1 or (tuple(s.parameters.keys())[0] != "self"): - raise TypeError("case method is missing 'self' argument but is not static: %s" % m) + raise TypeError(f"case method is missing 'self' argument but is not static: {m}") # partialize the function to get one without the 'self' argument new_m = functools.partial(m, cls()) @@ -944,8 +941,8 @@ def _of_interest(x): # noqa if _case_param_factory is None: # Nominal usage: put the case in the dictionary if co_firstlineno in cases_dct: - raise ValueError("Error collecting case functions, line number used by %r is already used by %r !" - % (m, cases_dct[co_firstlineno])) + raise ValueError(f"Error collecting case functions, line number used by {m!r} is already used by " + f"{cases_dct[co_firstlineno]!r} !") cases_dct[co_firstlineno] = m else: # Not used anymore @@ -1115,7 +1112,7 @@ def get_current_param(value, argname_or_fixturename, mp_fix_to_args): if len(argnames) == 1 and not isinstance(value, FixtureParamAlternative): actual_value = actual_value[0] else: - raise TypeError("Unsupported type, please report: %r" % type(value)) + raise TypeError(f"Unsupported type, please report: {type(value)!r}") else: # (3) "normal" parameter: each (argname, value) pair is received independently argnames = (argname_or_fixturename,) @@ -1349,7 +1346,7 @@ def get_current_case_id(request_or_item, # """ An adapted copy of _pytest.python.pytest_pycollect_makeitem """ # if safe_isclass(obj): # if self.iscaseclass(obj, name): -# raise ValueError("Case classes are not yet supported: %r" % obj) +# raise ValueError(f"Case classes are not yet supported: {obj!r}") # elif self.iscasefunction(obj, name): # # mock seems to store unbound methods (issue473), normalize it # obj = getattr(obj, "__func__", obj) @@ -1360,7 +1357,7 @@ def get_current_case_id(request_or_item, # filename, lineno = compat_getfslineno(obj) # warn_explicit( # message=PytestCasesCollectionWarning( -# "cannot collect %r because it is not a function." % name +# f"cannot collect {name!r} because it is not a function." # ), # category=None, # filename=str(filename), @@ -1371,7 +1368,7 @@ def get_current_case_id(request_or_item, # filename, lineno = compat_getfslineno(obj) # warn_explicit( # message=PytestCasesCollectionWarning( -# "cannot collect %r because it is a generator function." % name +# f"cannot collect {name!r} because it is a generator function." # ), # category=None, # filename=str(filename), diff --git a/src/pytest_cases/common_others.py b/src/pytest_cases/common_others.py index 38d3e7ba..0b5f7213 100644 --- a/src/pytest_cases/common_others.py +++ b/src/pytest_cases/common_others.py @@ -36,7 +36,7 @@ def get_code_first_line(f): _, lineno = findsource(f) return lineno except: # noqa - raise ValueError("Cannot get code information for function or class %r" % f) + raise ValueError(f"Cannot get code information for function or class {f!r}") # Below is the beginning of a switch from our scanning code to the same one than pytest. See `case_parametrizer_new` @@ -187,27 +187,27 @@ def __exit__(self, exc_type, exc_val, exc_tb): # Type check if not isinstance(exc_val, self.err_type): - raise ExceptionCheckingError("Caught exception %r is not an instance of expected type %r" - % (exc_val, self.err_type)) + raise ExceptionCheckingError(f"Caught exception {exc_val!r} is not an instance of " + f"expected type {self.err_type!r}") # Optional - pattern matching if self.err_ptrn is not None: if not self.err_ptrn.match(repr(exc_val)): - raise ExceptionCheckingError("Caught exception %r does not match expected pattern %r" - % (exc_val, self.err_ptrn)) + raise ExceptionCheckingError(f"Caught exception {exc_val!r} does not match expected " + f"pattern {self.err_ptrn!r}") # Optional - Additional Exception instance check with equality if self.err_inst is not None: # note: do not use != because in python 2 that is not equivalent if not (exc_val == self.err_inst): - raise ExceptionCheckingError("Caught exception %r does not equal expected instance %r" - % (exc_val, self.err_inst)) + raise ExceptionCheckingError(f"Caught exception {exc_val!r} does not equal " + f"expected instance {self.err_inst!r}") # Optional - Additional Exception instance check with custom checker if self.err_checker is not None: if self.err_checker(exc_val) is False: - raise ExceptionCheckingError("Caught exception %r is not valid according to %r" - % (exc_val, self.err_checker)) + raise ExceptionCheckingError(f"Caught exception {exc_val!r} is not valid " + f"according to {self.err_checker!r}") # Suppress the exception since it is valid. # See https://docs.python.org/2/reference/datamodel.html#object.__exit__ @@ -446,8 +446,8 @@ def get_class_that_defined_method(meth): # non-resolvable __qualname__ raise HostNotConstructedYet( "__qualname__ is not resolvable, this can happen if the host class of this method " - "%r has not yet been created. PEP3155 does not seem to tell us what we should do " - "in this case." % meth + f"{meth!r} has not yet been created. PEP3155 does not seem to tell us what we should do " + "in this case." ) if host is None: raise ValueError("__qualname__ leads to `None`, this is strange and not PEP3155 compliant, please " @@ -553,7 +553,7 @@ def make_identifier(name # type: str ): """Transform the given name into a valid python identifier""" if not isinstance(name, string_types): - raise TypeError("name should be a string, found : %r" % name) + raise TypeError(f"name should be a string, found : {name!r}") if iskeyword(name) or (not PY3 and name == "None"): # reserved keywords: add an underscore diff --git a/src/pytest_cases/common_pytest.py b/src/pytest_cases/common_pytest.py index afad9d39..9af82306 100644 --- a/src/pytest_cases/common_pytest.py +++ b/src/pytest_cases/common_pytest.py @@ -191,8 +191,8 @@ def assert_is_fixture(fixture_fun # type: Any :return: """ if not is_fixture(fixture_fun): - raise ValueError("The provided fixture function does not seem to be a fixture: %s. Did you properly decorate " - "it ?" % fixture_fun) + raise ValueError(f"The provided fixture function does not seem to be a fixture: {fixture_fun}. Did you " + "properly decorate it ?") if PYTEST84_OR_GREATER: @@ -409,8 +409,8 @@ def resolve_ids(ids, # type: Optional[Union[Callable, Iterable[st nb_ids = len(ids) if nb_ids != len(argvalues): - raise ValueError("Explicit list or generator of `ids` provided has a different length (%s) than the number " - "of argvalues (%s). Ids provided: %r" % (len(ids), len(argvalues), ids)) + raise ValueError(f"Explicit list or generator of `ids` provided has a different length ({len(ids)}) than " + f"the number of argvalues ({len(argvalues)}). Ids provided: {ids!r}") return ids @@ -426,7 +426,7 @@ def make_test_ids_from_param_values(param_names, :return: a list of param ids """ if isinstance(param_names, string_types): - raise TypeError("param_names must be an iterable. Found %r" % param_names) + raise TypeError(f"param_names must be an iterable. Found {param_names!r}") nb_params = len(param_names) if nb_params == 0: @@ -440,8 +440,7 @@ def make_test_ids_from_param_values(param_names, paramids = [] for _idx, vv in enumerate(param_values): if len(vv) != nb_params: - raise ValueError("Inconsistent lengths for parameter names and values: '%s' and '%s'" - "" % (param_names, vv)) + raise ValueError(f"Inconsistent lengths for parameter names and values: '{param_names}' and '{vv}'") _id = mini_idvalset(param_names, vv, _idx) paramids.append(_id) return paramids @@ -494,7 +493,7 @@ def extract_parameterset_info(argnames, argvalues, check_nb=True): pmarks = [] pvalues = [] if isinstance(argnames, string_types): - raise TypeError("argnames must be an iterable. Found %r" % argnames) + raise TypeError(f"argnames must be an iterable. Found {argnames!r}") nbnames = len(argnames) for v in argvalues: _pid, _pmark, _pvalue = extract_pset_info_single(nbnames, v) @@ -504,8 +503,8 @@ def extract_parameterset_info(argnames, argvalues, check_nb=True): pvalues.append(_pvalue) if check_nb and nbnames > 1 and (len(_pvalue) != nbnames): - raise ValueError("Inconsistent number of values in pytest parametrize: %s items found while the " - "number of parameters is %s: %s." % (len(_pvalue), nbnames, _pvalue)) + raise ValueError(f"Inconsistent number of values in pytest parametrize: {len(_pvalue)} items found while " + f"the number of parameters is {nbnames}: {_pvalue}.") return pids, pmarks, pvalues @@ -852,7 +851,7 @@ def add_fixture_params(func, new_names): # prepend all new parameters if needed for n in new_names: if n in old_sig.parameters: - raise ValueError("argument named %s already present in signature" % n) + raise ValueError(f"argument named {n} already present in signature") new_sig = add_signature_parameters(old_sig, first=[Parameter(n, kind=Parameter.POSITIONAL_OR_KEYWORD) for n in new_names]) @@ -996,7 +995,7 @@ def inject_host(apply_decorator): # # # path, lineno = get_fslocation_from_item(self) # # warn_explicit( - # # "Error parametrizing function %s : [%s] %s" % (self._target, e.__class__, e), + # # f"Error parametrizing function {self._target} : [{e.__class__}] {e}", # # category=None, # # filename=str(path), # # lineno=lineno + 1 if lineno is not None else None, diff --git a/src/pytest_cases/common_pytest_lazy_values.py b/src/pytest_cases/common_pytest_lazy_values.py index 89303bc2..5fe5dce6 100644 --- a/src/pytest_cases/common_pytest_lazy_values.py +++ b/src/pytest_cases/common_pytest_lazy_values.py @@ -60,9 +60,8 @@ def __eq__(self, other): def __repr__(self): """Default repr method based on the _field_names""" - - return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%r" % (k, getattr(self, k)) - for k in self._field_names)) + parenthesis_part = ", ".join(f"{k}={getattr(self, k)!r}" for k in self._field_names) + return f"{self.__class__.__name__}({parenthesis_part})" @property def __name__(self): @@ -107,14 +106,14 @@ def _unwrap(obj): def partial_to_str(partialfun): """Return a string representation of a partial function, to use in lazy_value ids""" - strwds = ", ".join("%s=%s" % (k, v) for k, v in partialfun.keywords.items()) + strwds = ", ".join(f"{k}={v}" for k, v in partialfun.keywords.items()) if len(partialfun.args) > 0: strargs = ', '.join(str(i) for i in partialfun.args) if len(partialfun.keywords) > 0: - strargs = "%s, %s" % (strargs, strwds) + strargs = f"{strargs}, {strwds}" else: strargs = strwds - return "%s(%s)" % (partialfun.func.__name__, strargs) + return f"{partialfun.func.__name__}({strargs})" # noinspection PyPep8Naming @@ -314,10 +313,11 @@ def __repr__(self): ('item', self.item), # item number first for easier debug ('tuple', tuple_to_represent), ) - return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%r" % (k, v) for k, v in vals_to_display)) + parenthesis_part = ", ".join(f"{k}={v!r}" for k, v in vals_to_display) + return f"{self.__class__.__name__}({parenthesis_part})" def get_id(self): - return "%s[%s]" % (self.host.get_id(), self.item) + return f"{self.host.get_id()}[{self.item}]" def get(self, request_or_item): """ Call the underlying value getter if needed (cache), then return the result tuple item value (not self). @@ -418,11 +418,10 @@ def force_getitem(self, item, request): try: return argvalue[item] except TypeError as e: - raise ValueError("(lazy_value) The parameter value returned by `%r` is not compliant with the number" - " of argnames in parametrization (%s). A %s-tuple-like was expected. " - "Returned lazy argvalue is %r and argvalue[%s] raised %s: %s" - % (self._lazyvalue, self.theoretical_size, self.theoretical_size, - argvalue, item, e.__class__, e)) + raise ValueError(f"(lazy_value) The parameter value returned by `{self._lazyvalue}` is not compliant " + f"with the number of argnames in parametrization ({self.theoretical_size}). " + f"A {self.theoretical_size}-tuple-like was expected. Returned lazy argvalue " + f"is {argvalue!r} and argvalue[{item}] raised {e.__class__}: {e}") if PYTEST53_OR_GREATER: diff --git a/src/pytest_cases/common_pytest_marks.py b/src/pytest_cases/common_pytest_marks.py index 74ce1b5b..c42a43e1 100644 --- a/src/pytest_cases/common_pytest_marks.py +++ b/src/pytest_cases/common_pytest_marks.py @@ -90,8 +90,8 @@ def __init__(self, mark): pass else: if len(remaining_kwargs) > 0: - warnings.warn("parametrize kwargs not taken into account: %s. Please report it at" - " https://github.com/smarie/python-pytest-cases/issues" % remaining_kwargs) + warnings.warn(f"parametrize kwargs not taken into account: {remaining_kwargs}. Please report it at" + " https://github.com/smarie/python-pytest-cases/issues") self.param_names = get_param_argnames_as_list(bound.arguments['argnames']) self.param_values = bound.arguments['argvalues'] try: @@ -325,7 +325,7 @@ def markinfos_to_markdecorators(marks, # type: Iterable[Mark] marks_mod.append(md) except Exception as e: - warnings.warn("Caught exception while trying to mark case: [%s] %s" % (type(e), e)) + warnings.warn(f"Caught exception while trying to mark case: [{type(e)}] {e}") return marks_mod diff --git a/src/pytest_cases/fixture__creation.py b/src/pytest_cases/fixture__creation.py index 48812349..2e7bc855 100644 --- a/src/pytest_cases/fixture__creation.py +++ b/src/pytest_cases/fixture__creation.py @@ -27,8 +27,8 @@ def __init__(self, module, name, caller): self.caller = caller def __str__(self): - return "Symbol `%s` already exists in module %s and therefore a corresponding fixture can not be created by " \ - "`%s`" % (self.name, self.module, self.caller) + return f"Symbol `{self.name}` already exists in module {self.module} and therefore a corresponding " \ + f"fixture can not be created by `{self.caller}`" RAISE = 0 @@ -61,15 +61,15 @@ def check_name_available(module, new_name = make_identifier(name) if new_name != name: if if_name_exists is RAISE: - raise ValueError("Proposed name is an invalid identifier: %s" % name) + raise ValueError(f"Proposed name is an invalid identifier: {name}") elif if_name_exists is WARN: - warn("%s name was not a valid identifier, changed it to %s" % (name, new_name)) + warn(f"{name} name was not a valid identifier, changed it to {new_name}") name = new_name if name_changer is None: # default style for name changing. i starts with 1 def name_changer(name, i): - return name + '_%s' % i + return f'{name}_{i}' ref_list = dir(module) + list(extra_forbidden_names) @@ -82,7 +82,7 @@ def name_changer(name, i): raise ExistingFixtureNameError(module, name, caller) elif if_name_exists is WARN: - warn("%s Overriding symbol %s in module %s" % (caller, name, module)) + warn(f"{caller} Overriding symbol {name} in module {module}") elif if_name_exists is CHANGE: # find a non-used name in that module @@ -94,7 +94,7 @@ def name_changer(name, i): name = name2 else: - raise ValueError("invalid value for `if_name_exists`: %s" % if_name_exists) + raise ValueError(f"invalid value for `if_name_exists`: {if_name_exists}") return name diff --git a/src/pytest_cases/fixture_core1_unions.py b/src/pytest_cases/fixture_core1_unions.py index af5582bd..bddc7bc5 100644 --- a/src/pytest_cases/fixture_core1_unions.py +++ b/src/pytest_cases/fixture_core1_unions.py @@ -76,14 +76,14 @@ def compact(cls, param # type: UnionFixtureAlternative ): """ ids are / """ - return "/%s" % (param.get_alternative_id(),) + return f"/{param.get_alternative_id()}" @classmethod def explicit(cls, param # type: UnionFixtureAlternative ): """ ids are / """ - return "%s/%s" % (param.get_union_id(), param.get_alternative_id()) + return f"{param.get_union_id()}/{param.get_alternative_id()}" @classmethod def get(cls, style # type: Union[str, Callable] @@ -102,7 +102,7 @@ def get(cls, style # type: Union[str, Callable] try: return getattr(cls, style) except AttributeError: - raise ValueError("Unknown style: %r" % style) + raise ValueError(f"Unknown style: {style!r}") else: # assume a callable: return it directly return style @@ -142,11 +142,11 @@ def get_alternative_id(self): def __str__(self): # This string representation can be used as an id if you pass `ids=str` to fixture_union for example - return "%s/%s/%s" % (self.get_union_id(), self.get_alternative_idx(), self.get_alternative_id()) + return f"{self.get_union_id()}/{self.get_alternative_idx()}/{self.get_alternative_id()}" def __repr__(self): - return "%s(union_name=%s, alternative_index=%s, alternative_name=%s)" \ - % (self.__class__.__name__, self.union_name, self.alternative_index, self.alternative_name) + return f"{self.__class__.__name__}(union_name={self.union_name}, " \ + f"alternative_index={self.alternative_index}, alternative_name={self.alternative_name})" @staticmethod def to_list_of_fixture_names(alternatives_lst # type: List[UnionFixtureAlternative] @@ -171,7 +171,7 @@ def __init__(self, params): def __str__(self): return "Invalid parameters list (`argvalues`) in pytest parametrize. `list(argvalues)` returned an error. " \ - "Please make sure that `argvalues` is a list, tuple or iterable : %r" % self.params + f"Please make sure that `argvalues` is a list, tuple or iterable : {self.params!r}" def is_fixture_union_params(params): @@ -338,7 +338,7 @@ def fixture_union(name, # type: str # remove duplicates in the fixture arguments: each is required only once by the union fixture to create if _name in f_names_args: - warn("Creating a fixture union %r where two alternatives are the same fixture %r." % (name, _name)) + warn(f"Creating a fixture union {name!r} where two alternatives are the same fixture {_name!r}.") else: f_names_args.append(_name) @@ -399,7 +399,7 @@ def _fixture_union(fixtures_dest, # then generate the body of our union fixture. It will require all of its dependent fixtures and receive as # a parameter the name of the fixture to use - @with_signature("%s(%s, request)" % (name, ', '.join(unique_fix_alt_names))) + @with_signature(f"{name}({', '.join(unique_fix_alt_names)}, request)") def _new_fixture(request, **all_fixtures): # ignore the "not used" marks, like in @ignore_unused if not is_used_request(request): @@ -410,8 +410,8 @@ def _new_fixture(request, **all_fixtures): fixture_to_use = _alternative.alternative_name return all_fixtures[fixture_to_use] else: - raise TypeError("Union Fixture %s received invalid parameter type: %s. Please report this issue." - "" % (name, _alternative.__class__)) + raise TypeError(f"Union Fixture {name} received invalid parameter type: {_alternative.__class__}. " + "Please report this issue.") if ids is None: ids = UnionIdMakers.get(idstyle) @@ -539,9 +539,9 @@ def _unpack_fixture(fixtures_dest, # type: ModuleType # we'll need to create their signature if in_cls: - _sig = "(self, %s, request)" % source_f_name + _sig = f"(self, {source_f_name}, request)" else: - _sig = "(%s, request)" % source_f_name + _sig = f"({source_f_name}, request)" for value_idx, argname in enumerate(argnames_lst): # create the fixture diff --git a/src/pytest_cases/fixture_core2.py b/src/pytest_cases/fixture_core2.py index b41ba472..840f0e0c 100644 --- a/src/pytest_cases/fixture_core2.py +++ b/src/pytest_cases/fixture_core2.py @@ -119,23 +119,23 @@ def _create_param_fixture(fixtures_dest, raise ValueError("When auto_simplify=True the argvalue can not be a pytest.param") # create the fixture - set its name so that the optional hook can read it easily - @with_signature("%s(request)" % argname) + @with_signature(f"{argname}(request)") def __param_fixture(request): # do not forget to resolve the lazy values ! return get_lazy_args(argvalue_to_return, request) if debug: - print("Creating unparametrized fixture %r returning %r" % (argname, argvalue_to_return)) + print(f"Creating unparametrized fixture {argname!r} returning {argvalue_to_return!r}") fix = fixture(name=argname, scope=scope, autouse=autouse, ids=ids, hook=hook, **kwargs)(__param_fixture) else: # create the fixture - set its name so that the optional hook can read it easily - @with_signature("%s(request)" % argname) + @with_signature(f"{argname}(request)") def __param_fixture(request): return get_lazy_args(request.param, request) if debug: - print("Creating parametrized fixture %r returning %r" % (argname, argvalues)) + print(f"Creating parametrized fixture {argname!r} returning {argvalues!r}") fix = fixture(name=argname, scope=scope, autouse=autouse, params=argvalues, ids=ids, hook=hook, **kwargs)(__param_fixture) @@ -218,18 +218,18 @@ def _create_params_fixture(fixtures_dest, # create the root fixture that will contain all parameter values # note: we sort the list so that the first in alphabetical order appears first. Indeed pytest uses this order. - root_fixture_name = "%s__param_fixtures_root" % ('_'.join(sorted(argnames_lst))) + root_fixture_name = f"{'_'.join(sorted(argnames_lst))}__param_fixtures_root" # Dynamically add fixture to caller's module as explained in https://github.com/pytest-dev/pytest/issues/2424 root_fixture_name = check_name_available(fixtures_dest, root_fixture_name, if_name_exists=CHANGE, caller=param_fixtures) if debug: - print("Creating parametrized 'root' fixture %r returning %r" % (root_fixture_name, argvalues)) + print(f"Creating parametrized 'root' fixture {root_fixture_name!r} returning {argvalues!r}") @fixture(name=root_fixture_name, autouse=autouse, scope=scope, hook=hook, **kwargs) @pytest.mark.parametrize(argnames, argvalues, ids=ids) - @with_signature("%s(%s)" % (root_fixture_name, argnames)) + @with_signature(f"{root_fixture_name}({argnames})") def _root_fixture(**_kwargs): return tuple(_kwargs[k] for k in argnames_lst) @@ -244,11 +244,11 @@ def _root_fixture(**_kwargs): def _create_fixture(_param_idx): if debug: - print("Creating nonparametrized 'view' fixture %r returning %r[%s]" - % (argname, root_fixture_name, _param_idx)) + print(f"Creating nonparametrized 'view' fixture {argname!r} " + f"returning {root_fixture_name!r}[{_param_idx}]") @fixture(name=argname, scope=scope, autouse=autouse, hook=hook, **kwargs) - @with_signature("%s(%s)" % (argname, root_fixture_name)) + @with_signature(f"{argname}({root_fixture_name})") def _param_fixture(**_kwargs): params = _kwargs.pop(root_fixture_name) return params[_param_idx] @@ -345,7 +345,7 @@ def __init__(self, argnames): self.argnames = argnames def __repr__(self): - return "FixtureParam(argnames=%s)" % self.argnames + return f"FixtureParam(argnames={self.argnames})" class CombinedFixtureParamValue(object): @@ -362,8 +362,8 @@ def iterparams(self): return ((pdef.argnames, v) for pdef, v in zip(self.param_defs, self.argvalues)) def __repr__(self): - list_str = " ; ".join(["<%r: %s>" % (a, v) for a, v in self.iterparams()]) - return "CombinedFixtureParamValue(%s)" % list_str + list_str = " ; ".join([f"<{a!r}: {v}>" for a, v in self.iterparams()]) + return f"CombinedFixtureParamValue({list_str})" def _decorate_fixture_plus(fixture_func, @@ -452,7 +452,7 @@ def _decorate_fixture_plus(fixture_func, # check number of parameter names in this parameterset if len(pmark.param_names) < 1: - raise ValueError("Fixture function '%s' decorated with '@fixture' has an empty parameter " + raise ValueError(f"Fixture function '{fixture_func!r}' decorated with '@fixture' has an empty parameter " "name in a @pytest.mark.parametrize mark") # remember the argnames @@ -507,8 +507,7 @@ def _decorate_fixture_plus(fixture_func, old_sig = signature(fixture_func) for p in all_param_names: if p not in old_sig.parameters: - raise ValueError("parameter '%s' not found in fixture signature '%s%s'" - "" % (p, fixture_func.__name__, old_sig)) + raise ValueError(f"parameter '{p}' not found in fixture signature '{fixture_func.__name__}{old_sig}'") new_sig = remove_signature_parameters(old_sig, *all_param_names) # add request if needed func_needs_request = 'request' in old_sig.parameters diff --git a/src/pytest_cases/fixture_parametrize_plus.py b/src/pytest_cases/fixture_parametrize_plus.py index 13a73431..b6a3492e 100644 --- a/src/pytest_cases/fixture_parametrize_plus.py +++ b/src/pytest_cases/fixture_parametrize_plus.py @@ -115,7 +115,7 @@ def _tuple_generator(request, all_fixtures): yield all_fixtures[fix_at_pos_i] # then generate the body of our product fixture. It will require all of its dependent fixtures - @with_signature("(request, %s)" % ', '.join(all_names)) + @with_signature(f"(request, {', '.join(all_names)})") def _new_fixture(request, **all_fixtures): return tuple(_tuple_generator(request, all_fixtures)) @@ -173,9 +173,9 @@ def __str__(self): def __repr__(self): if self._id is not None: - return "fixture_ref<%s, id=%s>" % (self.fixture, self._id) + return f"fixture_ref<{self.fixture}, id={self._id}>" else: - return "fixture_ref<%s>" % self.fixture + return f"fixture_ref<{self.fixture}>" def _check_iterable(self): """Raise a TypeError if this fixture reference is not iterable, that is, it does not represent a tuple""" @@ -213,7 +213,7 @@ def __init__(self, self.item = item def __repr__(self): - return "%r[%s]" % (self.host, self.item) + return f"{self.host!r}[{self.item}]" # Fix for https://github.com/smarie/python-pytest-cases/issues/71 @@ -263,10 +263,10 @@ def __init__(self, self.decorated = decorated def get_union_id(self): - return ("(%s)" % ",".join(self.argnames)) if len(self.argnames) > 1 else self.argnames[0] + return (f"({','.join(self.argnames)})") if len(self.argnames) > 1 else self.argnames[0] def get_alternative_idx(self): - return "P%s" % self.alternative_index + return f"P{self.alternative_index}" def get_alternative_id(self): """Subclasses should return the smallest id representing this parametrize fixture union alternative""" @@ -341,11 +341,11 @@ def create(cls, param_names_str = '_'.join(argnames).replace(' ', '') # Create a unique fixture name - p_fix_name = "%s_%s_P%s" % (test_func.__name__, param_names_str, i) + p_fix_name = f"{test_func.__name__}_{param_names_str}_P{i}" p_fix_name = check_name_available(new_fixture_host, p_fix_name, if_name_exists=CHANGE, caller=parametrize) if debug: - print(" - Creating new fixture %r to handle parameter %s" % (p_fix_name, i)) + print(f" - Creating new fixture {p_fix_name!r} to handle parameter {i}") # Now we'll create the fixture that will return the unique parameter value # since this parameter is unique, we do not parametrize the fixture (_create_param_fixture "auto_simplify" flag) @@ -408,10 +408,10 @@ def __init__(self, self.param_index_to = param_index_to def __str__(self): - return "%s/%s/" % (self.get_union_id(), self.get_alternative_idx()) + return f"{self.get_union_id()}/{self.get_alternative_idx()}/" def get_alternative_idx(self): - return "P%s:%s" % (self.param_index_from, self.param_index_to) + return f"P{self.param_index_from}:{self.param_index_to}" def get_alternative_id(self): # The alternative id is the parameter range - the parameter themselves appear on the referenced fixture @@ -454,11 +454,11 @@ def create(cls, param_names_str = '_'.join(argnames).replace(' ', '') # Create a unique fixture name - p_fix_name = "%s_%s_is_P%stoP%s" % (test_func.__name__, param_names_str, from_i, to_i - 1) + p_fix_name = f"{test_func.__name__}_{param_names_str}_is_P{from_i}toP{to_i - 1}" p_fix_name = check_name_available(new_fixture_host, p_fix_name, if_name_exists=CHANGE, caller=parametrize) if debug: - print(" - Creating new fixture %r to handle parameters %s to %s" % (p_fix_name, from_i, to_i - 1)) + print(f" - Creating new fixture {p_fix_name!r} to handle parameters {from_i} to {to_i - 1}") # Create the fixture # - it will be parametrized to take all the values in argvalues @@ -529,7 +529,7 @@ def __init__(self, argval=fixture_ref, id=id, decorated=decorated) def get_alternative_idx(self): - return "P%sF" % self.alternative_index + return f"P{self.alternative_index}F" def get_alternative_id(self): if self.id is not None: @@ -544,7 +544,7 @@ class ProductParamAlternative(SingleParamAlternative): """alternative class for a single product parameter containing fixture refs""" def get_alternative_idx(self): - return "P%sF" % self.alternative_index + return f"P{self.alternative_index}F" def get_alternative_id(self): """Similar to SingleParamAlternative: create an id representing this tuple, since the fixture won't be @@ -624,7 +624,7 @@ def nostyle(cls, # ): # """Same than parent but display the argnames as prefix instead of the fixture union name generated by # @parametrize, because the latter is too complex (for unicity reasons)""" - # return "%s/%s" % (, param.get_id(prepend_index=True)) + # return f"/{param.get_id(prepend_index=True)}" _IDGEN = object() @@ -654,7 +654,7 @@ def parametrize(argnames=None, # type: Union[str, Tuple[str], List[str]] parameters at once (`**args`) and returning an id ; or it can be a string template using the new-style string formatting where the argnames can be used as variables (e.g. `idgen=lambda **args: "a={a}".format(**args)` or `idgen="my_id where a={a}"`). The special `idgen=AUTO` symbol can be used to generate a default string template - equivalent to `lambda **args: "-".join("%s=%s" % (n, v) for n, v in args.items())`. This is enabled by default + equivalent to `lambda **args: "-".join(f"{n}={v}" for n, v in args.items())`. This is enabled by default if you use the alternate style for argnames/argvalues (e.g. if `len(args) > 0`), and if there are no `fixture_ref`s in your argvalues. @@ -735,9 +735,8 @@ def __str__(self): return repr(self) def __repr__(self): - return "Error generating test id using name template '%s' with parameter values " \ - "%r. Please check the name template. Caught: %s - %s" \ - % (self.idgen, self.params, self.caught.__class__, self.caught) + return f"Error generating test id using name template '{self.idgen}' with parameter values " \ + f"{self.params!r}. Please check the name template. Caught: {self.caught.__class__} - {self.caught}" def _parametrize_plus(argnames=None, # type: Union[str, Tuple[str], List[str]] @@ -780,7 +779,7 @@ def _parametrize_plus(argnames=None, # type: Union[str, Tuple[str], List[str]] # note: we use a "trick" here with mini_idval to get the appropriate result (argname='', idx=v) def _make_ids(**args): for n, v in args.items(): - yield "%s=%s" % (n, mini_idval(val=v, argname='', idx=v)) + yield f"{n}={mini_idval(val=v, argname='', idx=v)}" idgen = lambda **args: "-".join(_make_ids(**args)) # noqa @@ -794,9 +793,9 @@ def _make_ids(**args): # No fixture reference: fallback to a standard pytest.mark.parametrize if debug: print("No fixture reference found. Calling @pytest.mark.parametrize...") - print(" - argnames: %s" % initial_argnames) - print(" - argvalues: %s" % marked_argvalues) - print(" - ids: %s" % ids) + print(f" - argnames: {initial_argnames}") + print(f" - argvalues: {marked_argvalues}") + print(f" - ids: {ids}") # handle infinite iterables like latest pytest, for convenience ids = resolve_ids(ids, marked_argvalues, full_resolve=False) @@ -815,8 +814,8 @@ def _apply(test_func): s = signature(test_func) for p in argnames: if p not in s.parameters: - raise ValueError("parameter '%s' not found in test function signature '%s%s'" - "" % (p, test_func.__name__, s)) + raise ValueError(f"parameter '{p}' not found in test function " + f"signature '{test_func.__name__}{s}'") else: # a Class: we cannot really perform any check. pass @@ -901,7 +900,7 @@ def _create_fixture_ref_alt(union_name, test_func, i): # noqa f_fix_name = argvalues[i].fixture if debug: - print(" - Creating reference to existing fixture %r" % (f_fix_name,)) + print(f" - Creating reference to existing fixture {f_fix_name!r}") # Create the alternative f_fix_alt = FixtureParamAlternative(union_name=union_name, fixture_ref=argvalues[i], @@ -923,11 +922,11 @@ def _create_fixture_ref_product(fh, union_name, i, fixture_ref_positions, test_f param_values = argvalues[i] # Create a unique fixture name - p_fix_name = "%s_%s_P%s" % (test_func.__name__, param_names_str, i) + p_fix_name = f"{test_func.__name__}_{param_names_str}_P{i}" p_fix_name = check_name_available(fh, p_fix_name, if_name_exists=CHANGE, caller=parametrize) if debug: - print(" - Creating new fixture %r to handle parameter %s that is a cross-product" % (p_fix_name, i)) + print(f" - Creating new fixture {p_fix_name!r} to handle parameter {i} that is a cross-product") # Create the fixture _make_fixture_product(fh, name=p_fix_name, hook=hook, caller=parametrize, @@ -964,13 +963,12 @@ def parametrize_plus_decorate(test_func, fixtures_dest): old_sig = signature(test_func) for p in argnames: if p not in old_sig.parameters: - raise ValueError("parameter '%s' not found in test function signature '%s%s'" - "" % (p, test_func_name, old_sig)) + raise ValueError(f"parameter '{p}' not found in test function " + f"signature '{test_func_name}{old_sig}'") # The name for the final "union" fixture # style_template = "%s_param__%s" - main_fixture_style_template = "%s_%s" - fixture_union_name = main_fixture_style_template % (test_func_name, param_names_str) + fixture_union_name = f"{test_func_name}_{param_names_str}" fixture_union_name = check_name_available(fixtures_dest, fixture_union_name, if_name_exists=CHANGE, caller=parametrize) @@ -1028,8 +1026,8 @@ def parametrize_plus_decorate(test_func, fixtures_dest): # Finally create a "main" fixture with a unique name for this test function if debug: - print("Creating final union fixture %r with alternatives %r" - % (fixture_union_name, UnionFixtureAlternative.to_list_of_fixture_names(fixture_alternatives))) + print(f"Creating final union fixture {fixture_union_name!r} with alternatives " + f"{UnionFixtureAlternative.to_list_of_fixture_names(fixture_alternatives)!r}") # use the custom subclass of idstyle that was created for ParamAlternatives if idstyle is None or isinstance(idstyle, string_types): @@ -1058,7 +1056,7 @@ def parametrize_plus_decorate(test_func, fixtures_dest): kind=Parameter.POSITIONAL_OR_KEYWORD)) if debug: - print("Creating final test function wrapper with signature %s%s" % (test_func_name, new_sig)) + print(f"Creating final test function wrapper with signature {test_func_name}{new_sig}") # --Finally create the fixture function, a wrapper of user-provided fixture with the new signature def replace_paramfixture_with_values(kwargs): # noqa @@ -1070,7 +1068,7 @@ def replace_paramfixture_with_values(kwargs): # noqa try: kwargs[p] = encompassing_fixture[i] except TypeError: - raise Exception("Unable to unpack parameter value to a tuple: %r" % encompassing_fixture) + raise Exception(f"Unable to unpack parameter value to a tuple: {encompassing_fixture}") else: kwargs[argnames[0]] = encompassing_fixture # return @@ -1204,7 +1202,7 @@ def _gen_ids(argnames, argvalues, idgen): if not callable(idgen): # idgen is a new-style string formatting template if not isinstance(idgen, string_types): - raise TypeError("idgen should be a callable or a string, found: %r" % idgen) + raise TypeError(f"idgen should be a callable or a string, found: {idgen!r}") _formatter = idgen @@ -1375,8 +1373,8 @@ def _process_argvalues(argnames, marked_argvalues, nb_params, has_custom_ids, au else: # Tuple: check nb params for consistency if len(v) != len(argnames): - raise ValueError("Inconsistent number of values in pytest parametrize: %s items found while the " - "number of parameters is %s: %s." % (len(v), len(argnames), v)) + raise ValueError(f"Inconsistent number of values in pytest parametrize: {len(v)} items found " + f"while the number of parameters is {len(argnames)}: {v}.") # let's dig into the tuple to check if there are fixture_refs or lazy_values lv_pos_list = [j for j, _pval in enumerate(v) if is_lazy_value(_pval)] diff --git a/src/pytest_cases/plugin.py b/src/pytest_cases/plugin.py index 907ebb1d..84c1f302 100644 --- a/src/pytest_cases/plugin.py +++ b/src/pytest_cases/plugin.py @@ -163,10 +163,11 @@ def to_str(self, indent_nb=0, with_children=True): if not self.is_closure_built(): str_repr = "" else: - str_repr = "%s(%s)" % (indent, ",".join([("%s" % f) for f in self.fixture_defs.keys()])) + list_part = ",".join([(f"{f}") for f in self.fixture_defs.keys()]) + str_repr = f"{indent}({list_part})" if self.has_split() and with_children: - children_str_prefix = "\n%s - " % indent + children_str_prefix = f"\n{indent} - " children_str = children_str_prefix + children_str_prefix.join([c.to_str(indent_nb=indent_nb + 1) for c in self.children]) str_repr = str_repr + " split: " + self.split_fixture_name + children_str @@ -598,11 +599,13 @@ def __repr__(self): """ Return a synthetic view, and a detailed tree view, of this closure """ alternatives = self.tree.get_alternatives() nb_alternative_closures = len(alternatives) - return "SuperClosure with %s alternative closures:\n" % nb_alternative_closures \ - + "\n".join(" - %s (filters: %s)" % (p, ", ".join("%s=%s[%s]=%s" % (k, k, v[0], v[1]) - for k, v in f.items())) - for f, p in alternatives) \ - + "\nThe 'super closure list' is %s\n\nThe fixture tree is :\n%s\n" % (list(self), self.tree) + filter_list = [] + for f, p in alternatives: + filters = ", ".join(f"{k}={k}[{v[0]}]={v[1]}" for k, v in f.items()) + filter_list.append(f" - {p} (filters: {filters})") + return f"SuperClosure with {nb_alternative_closures} alternative closures:\n" \ + + "\n".join(filter_list) \ + + f"\nThe 'super closure list' is {list(self)}\n\nThe fixture tree is :\n{self.tree}\n" def get_all_fixture_defs(self, drop_fake_fixtures=True): """ @@ -816,7 +819,7 @@ def create_super_closure(fm, parentid = parentnode.nodeid if _DEBUG: - print("Creating closure for %s:" % parentid) + print(f"Creating closure for {parentid}:") # -- auto-use fixtures if hasattr(pytest, "version_tuple") and pytest.version_tuple >= (8, 1): @@ -863,7 +866,7 @@ def _merge(new_items, into_list): super_closure = list(super_closure) if _DEBUG: - print("Closure for %s completed:" % parentid) + print(f"Closure for {parentid} completed:") print(closure_tree) print(super_closure) @@ -890,9 +893,8 @@ class UnionParamz(namedtuple('UnionParamz', ['union_fixture_name', 'alternative_ __slots__ = () def __str__(self): - return "[UNION] %s=[%s], ids=%s, scope=%s, kwargs=%s" \ - "" % (self.union_fixture_name, ','.join([str(a) for a in self.alternative_names]), - self.ids, self.scope, self.kwargs) + return f"[UNION] {self.union_fixture_name}=[{','.join([str(a) for a in self.alternative_names])}], " \ + f"ids={self.ids}, scope={self.scope}, kwargs={self.kwargs}" class NormalParamz(namedtuple('NormalParamz', ['argnames', 'argvalues', 'indirect', 'ids', 'scope', 'kwargs'])): @@ -901,8 +903,8 @@ class NormalParamz(namedtuple('NormalParamz', ['argnames', 'argvalues', 'indirec __slots__ = () def __str__(self): - return "[NORMAL] %s=[%s], indirect=%s, ids=%s, scope=%s, kwargs=%s" \ - "" % (self.argnames, self.argvalues, self.indirect, self.ids, self.scope, self.kwargs) + return f"[NORMAL] {self.argnames}=[{self.argvalues}], indirect={self.indirect}, ids={self.ids}, " \ + f"scope={self.scope}, kwargs={self.kwargs}" def parametrize(metafunc, argnames, argvalues, indirect=False, ids=None, scope=None, **kwargs): @@ -1050,9 +1052,8 @@ def create_call_list_from_pending_parametrizations(self): # calls += get_calls_for_partition(self.metafunc, super_closure, i, pending.copy()) if _DEBUG: - print("\n".join(["%s[%s]: funcargs=%s, params=%s" % (get_pytest_nodeid(self.metafunc), - c.id, c.params if PYTEST8_OR_GREATER else c.funcargs, - c.params) + print("\n".join([f"{get_pytest_nodeid(self.metafunc)}[{c.id}]: " + f"funcargs={c.params if PYTEST8_OR_GREATER else c.funcargs}, params={c.params}" for c in calls]) + "\n") # clean EMPTY_ID set by @parametrize when there is at least a MultiParamsAlternative @@ -1220,8 +1221,8 @@ def _cleanup_calls_list(metafunc, # # assert selected_alternative.alternative_name == selected_filter # # if _DEBUG: -# print("[Partition %s] Applying parametrization for UNION fixture %r=%r" -# "" % (p_idx, p_to_apply.union_fixture_name, selected_alternative)) +# print(f"[Partition {p_idx}] Applying parametrization for UNION " +# f"fixture {p_to_apply.union_fixture_name!r}={selected_alternative!r}") # # # always use 'indirect' since that's a fixture. # calls = _parametrize_calls(metafunc, calls, p_to_apply.union_fixture_name, @@ -1231,14 +1232,13 @@ def _cleanup_calls_list(metafunc, # elif isinstance(p_to_apply, NormalParamz): # # ******** Normal parametrization ********** # if _DEBUG: -# print("[Partition %s] Applying parametrization for NORMAL %s" -# "" % (p_idx, p_to_apply.argnames)) +# print(f"[Partition {p_idx}] Applying parametrization for NORMAL {p_to_apply.argnames}") # # calls = _parametrize_calls(metafunc, calls, p_to_apply.argnames, p_to_apply.argvalues, # indirect=p_to_apply.indirect, ids=p_to_apply.ids, # scope=p_to_apply.scope, **p_to_apply.kwargs) # else: -# raise TypeError("Invalid parametrization type: %s" % p_to_apply.__class__) +# raise TypeError(f"Invalid parametrization type: {p_to_apply.__class__}") # # # Cleaning # for i in range(len(calls)): @@ -1364,14 +1364,14 @@ def _process_node(metafunc, elif isinstance(p_to_apply, NormalParamz): # ******** Normal parametrization ********** if _DEBUG: - print("[Node %s] Applying parametrization for NORMAL %s" - "" % (current_node.to_str(with_children=False), p_to_apply.argnames)) + print(f"[Node {current_node.to_str(with_children=False)}] Applying parametrization " + f"for NORMAL {p_to_apply.argnames}") calls = _parametrize_calls(metafunc, calls, p_to_apply.argnames, p_to_apply.argvalues, indirect=p_to_apply.indirect, ids=p_to_apply.ids, scope=p_to_apply.scope, **p_to_apply.kwargs) else: - raise TypeError("Invalid parametrization type: %s" % p_to_apply.__class__) + raise TypeError(f"Invalid parametrization type: {p_to_apply.__class__}") # (2) then is there a "union" = a split between two sub-branches in the tree ? if not current_node.has_split(): @@ -1391,8 +1391,8 @@ def _process_node(metafunc, elif isinstance(p_to_apply, UnionParamz): # ******** Union parametrization ********** if _DEBUG: - print("[Node %s] Applying parametrization for UNION %s" - "" % (current_node.to_str(with_children=False), p_to_apply.union_fixture_name)) + print(f"[Node {current_node.to_str(with_children=False)}] " + f"Applying parametrization for UNION {p_to_apply.union_fixture_name}") # always use 'indirect' since that's a fixture. calls = _parametrize_calls(metafunc, calls, p_to_apply.union_fixture_name, @@ -1481,10 +1481,11 @@ def sort_according_to_ref_list(fixturenames, param_names): # @hookspec(historic=True) def pytest_addoption(parser): group = parser.getgroup('pytest-cases ordering', 'pytest-cases reordering options', after='general') - help_str = """String specifying one of the reordering alternatives to use. Should be one of : - - %s""" % ("\n - ".join(["%s: %s" % (k, v) for k, v in _OPTIONS.items()])) + options_str = "\n - ".join([f"{k}: {v}" for k, v in _OPTIONS.items()]) + help_str = f"""String specifying one of the reordering alternatives to use. Should be one of : + - {options_str}""" group.addoption( - '--%s' % _OPTION_NAME.replace('_', '-'), type=str, default='normal', help=help_str + f"--{_OPTION_NAME.replace('_', '-')}", type=str, default='normal', help=help_str ) @@ -1504,8 +1505,8 @@ def pytest_configure(config): allowed_values = ('normal', 'skip') reordering_choice = config.getoption(_OPTION_NAME) if reordering_choice not in allowed_values: - raise ValueError("[pytest-cases] Wrong --%s option: %s. Allowed values: %s" - "" % (_OPTION_NAME, reordering_choice, allowed_values)) + raise ValueError(f"[pytest-cases] Wrong --{_OPTION_NAME} option: {reordering_choice}. " + f"Allowed values: {allowed_values}") @pytest.hookimpl(tryfirst=True, hookwrapper=True)