From 41ca1f56330a7bc10b4166c2350cdafd64ca8e46 Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Thu, 25 Apr 2024 14:32:14 -0400 Subject: [PATCH 01/18] local push --- testing/local_testing/add_function.py | 3 +++ testing/local_testing/local_test_0.py | 16 ++++++++++++++++ testing/local_testing/local_test_test.py | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 testing/local_testing/add_function.py create mode 100644 testing/local_testing/local_test_0.py create mode 100644 testing/local_testing/local_test_test.py diff --git a/testing/local_testing/add_function.py b/testing/local_testing/add_function.py new file mode 100644 index 000000000..40bd7ec64 --- /dev/null +++ b/testing/local_testing/add_function.py @@ -0,0 +1,3 @@ +def add(a, b): + return a + b + diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py new file mode 100644 index 000000000..95dbd553c --- /dev/null +++ b/testing/local_testing/local_test_0.py @@ -0,0 +1,16 @@ +import pytest + +@pytest.mark.parametrize("arg1, arg2", [(1, 1)]) +def test_parametrization(arg1, arg2): + assert arg1 == arg2 + assert arg1 + 1 == arg2 + 1 + + +# Gets the error: In test_parametrization: indirect fixture '(1, 1)' doesn't exist +# Goal is to change this message into a more beginner friendly message. + +# The error message lives in this path: pytest/src/_pytest/python.py + + + +#("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function \ No newline at end of file diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py new file mode 100644 index 000000000..a677697bf --- /dev/null +++ b/testing/local_testing/local_test_test.py @@ -0,0 +1,22 @@ +# test_math_operations.py + +import pytest +import add_function + + +result_index = [ + (1, 2, 3), + (-1, 1, 0), + (0, 0, 0), + (5, -3, 2), + (1, 1, 2) +] + +@pytest.mark.parametrize("a, b, expected_result", result_index) + + +def test_add(a, b, expected_result): + assert add_function.add(a, b) == expected_result + + + From 57030e826d7ac7147307a4fd3b8d87ed2c1f661a Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Thu, 25 Apr 2024 19:56:22 -0400 Subject: [PATCH 02/18] initial message improvements --- testing/local_testing/add_function.py | 1 - testing/local_testing/local_test_0.py | 10 +++++----- testing/local_testing/local_test_test.py | 17 ++++------------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/testing/local_testing/add_function.py b/testing/local_testing/add_function.py index 40bd7ec64..4693ad3cf 100644 --- a/testing/local_testing/add_function.py +++ b/testing/local_testing/add_function.py @@ -1,3 +1,2 @@ def add(a, b): return a + b - diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 95dbd553c..76c079dea 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -1,16 +1,16 @@ import pytest -@pytest.mark.parametrize("arg1, arg2", [(1, 1)]) + +@pytest.mark.parametrize("arg1,arg2", [(1, 1)]) def test_parametrization(arg1, arg2): assert arg1 == arg2 assert arg1 + 1 == arg2 + 1 # Gets the error: In test_parametrization: indirect fixture '(1, 1)' doesn't exist -# Goal is to change this message into a more beginner friendly message. - +# Goal is to change this message into a more beginner friendly message. + # The error message lives in this path: pytest/src/_pytest/python.py - -#("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function \ No newline at end of file +# ("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index a677697bf..aeb361f67 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -1,22 +1,13 @@ # test_math_operations.py -import pytest import add_function +import pytest + + +result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)] -result_index = [ - (1, 2, 3), - (-1, 1, 0), - (0, 0, 0), - (5, -3, 2), - (1, 1, 2) -] @pytest.mark.parametrize("a, b, expected_result", result_index) - - def test_add(a, b, expected_result): assert add_function.add(a, b) == expected_result - - - From ababe237fd4b09f502e86bec525545be68856c75 Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Thu, 25 Apr 2024 20:28:49 -0400 Subject: [PATCH 03/18] some changing up --- testing/local_testing/local_test_0.py | 11 +++++++---- testing/local_testing/local_test_test.py | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 76c079dea..2234947c1 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -1,16 +1,19 @@ import pytest -@pytest.mark.parametrize("arg1,arg2", [(1, 1)]) + +@pytest.mark.parametrize("arg1", "arg2", [(1, 1)]) + def test_parametrization(arg1, arg2): assert arg1 == arg2 assert arg1 + 1 == arg2 + 1 # Gets the error: In test_parametrization: indirect fixture '(1, 1)' doesn't exist -# Goal is to change this message into a more beginner friendly message. - +# Goal is to change this message into a more beginner friendly message. + # The error message lives in this path: pytest/src/_pytest/python.py + -# ("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function +#("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function \ No newline at end of file diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index aeb361f67..a677697bf 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -1,13 +1,22 @@ # test_math_operations.py +import pytest import add_function -import pytest - - -result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)] +result_index = [ + (1, 2, 3), + (-1, 1, 0), + (0, 0, 0), + (5, -3, 2), + (1, 1, 2) +] @pytest.mark.parametrize("a, b, expected_result", result_index) + + def test_add(a, b, expected_result): assert add_function.add(a, b) == expected_result + + + From ac15d1ec1de48aed09e354cff806ff7388cf661b Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Thu, 25 Apr 2024 20:36:28 -0400 Subject: [PATCH 04/18] Added first part of error msg fixing to python.py file --- testing/local_testing/local_test_0.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 2234947c1..faab77484 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -2,7 +2,7 @@ import pytest -@pytest.mark.parametrize("arg1", "arg2", [(1, 1)]) +@pytest.mark.parametrize("arg1, arg2", [(1, 1)]) def test_parametrization(arg1, arg2): assert arg1 == arg2 From 64ae653745500c2a1def4b7cb1d174b0c1af12d8 Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Fri, 26 Apr 2024 17:22:28 -0400 Subject: [PATCH 05/18] testing for 2 in quotes and one not --- testing/local_testing/local_test_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index a677697bf..e1003925f 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -12,7 +12,7 @@ result_index = [ (1, 1, 2) ] -@pytest.mark.parametrize("a, b, expected_result", result_index) +@pytest.mark.parametrize("a, b", "expected_result", result_index) def test_add(a, b, expected_result): From 6e5c56ce4bc526d32b00a11696bede1256f16104 Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Fri, 26 Apr 2024 17:29:02 -0400 Subject: [PATCH 06/18] made improvements to error message for basic --- testing/local_testing/local_test_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index e1003925f..e3e434294 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -12,7 +12,7 @@ result_index = [ (1, 1, 2) ] -@pytest.mark.parametrize("a, b", "expected_result", result_index) +@pytest.mark.parametrize("a", "b, expected_result", result_index) def test_add(a, b, expected_result): From 04b028a46e673f0f8cea3313a302fcb69a3b7381 Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Fri, 26 Apr 2024 17:34:21 -0400 Subject: [PATCH 07/18] final addition for comments --- testing/local_testing/local_test_0.py | 2 +- testing/local_testing/local_test_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index faab77484..218606208 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -2,7 +2,7 @@ import pytest -@pytest.mark.parametrize("arg1, arg2", [(1, 1)]) +@pytest.mark.parametrize("arg1,arg2", [(1, 1)]) def test_parametrization(arg1, arg2): assert arg1 == arg2 diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index e3e434294..72ca93062 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -12,7 +12,7 @@ result_index = [ (1, 1, 2) ] -@pytest.mark.parametrize("a", "b, expected_result", result_index) +@pytest.mark.parametrize("a, b,expected_result", result_index) def test_add(a, b, expected_result): From 005684e77b1b8daf03a882a678d610e0c9ddeb14 Mon Sep 17 00:00:00 2001 From: Sirui Huang Date: Sat, 27 Apr 2024 10:21:51 -0400 Subject: [PATCH 08/18] make linter happy --- testing/local_testing/add_function.py | 2 +- testing/local_testing/local_test_0.py | 9 +++------ testing/local_testing/local_test_test.py | 17 ++++------------- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/testing/local_testing/add_function.py b/testing/local_testing/add_function.py index 4693ad3cf..e1829c359 100644 --- a/testing/local_testing/add_function.py +++ b/testing/local_testing/add_function.py @@ -1,2 +1,2 @@ -def add(a, b): +def add(a: int, b: int) -> int: return a + b diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 218606208..76c079dea 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -1,19 +1,16 @@ import pytest - @pytest.mark.parametrize("arg1,arg2", [(1, 1)]) - def test_parametrization(arg1, arg2): assert arg1 == arg2 assert arg1 + 1 == arg2 + 1 # Gets the error: In test_parametrization: indirect fixture '(1, 1)' doesn't exist -# Goal is to change this message into a more beginner friendly message. - +# Goal is to change this message into a more beginner friendly message. + # The error message lives in this path: pytest/src/_pytest/python.py - -#("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function \ No newline at end of file +# ("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index 72ca93062..23ac56060 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -1,22 +1,13 @@ # test_math_operations.py -import pytest import add_function +import pytest + + +result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)] -result_index = [ - (1, 2, 3), - (-1, 1, 0), - (0, 0, 0), - (5, -3, 2), - (1, 1, 2) -] @pytest.mark.parametrize("a, b,expected_result", result_index) - - def test_add(a, b, expected_result): assert add_function.add(a, b) == expected_result - - - From a4d8c1a0ee91877736cffbe169068da215f0b304 Mon Sep 17 00:00:00 2001 From: Chaeil Yun Date: Sat, 27 Apr 2024 12:29:55 -0400 Subject: [PATCH 09/18] Actual changes reflected --- src/.DS_Store | Bin 0 -> 6148 bytes src/_pytest/mark/structures.py | 27 +++++++++++++-------------- src/_pytest/python.py | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 src/.DS_Store diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..112d642aa19639f0cd6be99d8f939dae44b6a2c7 GIT binary patch literal 6148 zcmeHK%}T>S5T3QwrW7FuMUMfm1*?`q@e*o%0V8@)i3u$ljM>tp1}TMH^@V&BpU0Wq z4Ok6$6R|U}`_0bJZsvpR4*-b4Y;*u%1Av8%P>@m~WUh3rnP5Vp<`_c?S(vAjFs_*B zFPiAv8{oqPo*{!z-!DV-yoHlEO0!PqU98pW>l+QLVYRFq?_TC!7G$$@5KOOVbS`Ba zmU<9gMC07Iw@ze|1yM4ds)T4X#*pjFC>hCoAZN)aRk@yaSWTU7yKcCnQ0g-V%h4LDyiR5j`kE zry}Z9VV)R5r=#65ajwBaqfQ5*R>pbE%H`ulsMXQ#sBjRjM(&vbW?-3tnjYG8{-5G6 zQ~AhWPT>(VzzqB|21I@64F_11Ia|M#M`x{r?G_se#TBHWpuThozya+eyUMBk4(S-@ X8Z0!@EM!;dh)'" + f"\n\n" + f"Or if multiple parameters are used, separate them by commas. \n " + f"e.g., '@pytest.mark.parametrize(\"arg1, arg2\", )'", pytrace=False, ) arg_directness[arg] = "indirect" @@ -1415,6 +1439,9 @@ class Metafunc: ) return arg_directness + + + def _validate_if_using_arg_names( self, argnames: Sequence[str], From db507ed468172be36ed0d10900e02df00e1269e4 Mon Sep 17 00:00:00 2001 From: Ben Nguyen Tran Date: Sat, 27 Apr 2024 12:41:50 -0400 Subject: [PATCH 10/18] Added a log_file_verbose option with no functionality --- doc/en/reference/reference.rst | 1 + src/_pytest/logging.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index 39317497e..f3eedd23a 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -2107,6 +2107,7 @@ All the command-line flags can be obtained by running ``pytest --help``:: --log-cli-date-format=LOG_CLI_DATE_FORMAT Log date format used by the logging module --log-file=LOG_FILE Path to a file when logging will be written to + --log-file-verbose Log file verbosity --log-file-mode={w,a} Log file open mode --log-file-level=LOG_FILE_LEVEL diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index af5e443ce..0adecc7c1 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -299,6 +299,12 @@ def pytest_addoption(parser: Parser) -> None: default=None, help="Path to a file when logging will be written to", ) + add_option_ini( + "--log-file-verbose", + dest="log_file_verbosity", + default=None, + help="Log file verbose", + ) add_option_ini( "--log-file-mode", dest="log_file_mode", @@ -677,6 +683,8 @@ class LoggingPlugin: if not os.path.isdir(directory): os.makedirs(directory) + self.log_file_verbose = get_option_ini(config, "log_file_verbose") + self.log_file_mode = get_option_ini(config, "log_file_mode") or "w" self.log_file_handler = _FileHandler( log_file, mode=self.log_file_mode, encoding="UTF-8" From 6e937c0aafef0336c09eac1462e76294d8c0564f Mon Sep 17 00:00:00 2001 From: Ben Nguyen Tran Date: Sun, 28 Apr 2024 13:32:33 -0400 Subject: [PATCH 11/18] Added functionality to log_file_verbose. However, the default value does not work. --- doc/en/how-to/logging.rst | 1 + doc/en/reference/reference.rst | 4 +++- src/_pytest/config/__init__.py | 3 +++ src/_pytest/config/argparsing.py | 10 ++++++---- src/_pytest/logging.py | 13 +++++++++++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/doc/en/how-to/logging.rst b/doc/en/how-to/logging.rst index 300e9f6e6..2f75e57c1 100644 --- a/doc/en/how-to/logging.rst +++ b/doc/en/how-to/logging.rst @@ -208,6 +208,7 @@ option names are: If you need to record the whole test suite logging calls to a file, you can pass ``--log-file=/path/to/log/file``. This log file is opened in write mode by default which means that it will be overwritten at each run tests session. +You can specify the level of verbosity of the log file by passing ```--log-file-verbose=1`` If you'd like the file opened in append mode instead, then you can pass ``--log-file-mode=a``. Note that relative paths for the log-file location, whether passed on the CLI or declared in a config file, are always resolved relative to the current working directory. diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index f3eedd23a..1dd20f7f1 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -2107,7 +2107,7 @@ All the command-line flags can be obtained by running ``pytest --help``:: --log-cli-date-format=LOG_CLI_DATE_FORMAT Log date format used by the logging module --log-file=LOG_FILE Path to a file when logging will be written to - --log-file-verbose Log file verbosity + --log-file-verbose={0,1} Log file verbose --log-file-mode={w,a} Log file open mode --log-file-level=LOG_FILE_LEVEL @@ -2208,6 +2208,8 @@ All the command-line flags can be obtained by running ``pytest --help``:: log_cli_date_format (string): Default value for --log-cli-date-format log_file (string): Default value for --log-file + log_file_verbose (int): + Default value for --log-file-verbose log_file_mode (string): Default value for --log-file-mode log_file_level (string): diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 306b14cce..16f803a24 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1576,6 +1576,7 @@ class Config: ``paths``, ``pathlist``, ``args`` and ``linelist`` : empty list ``[]`` ``bool`` : ``False`` ``string`` : empty string ``""`` + ``int`` : ``0`` If neither the ``default`` nor the ``type`` parameter is passed while registering the configuration through @@ -1643,6 +1644,8 @@ class Config: return value elif type == "bool": return _strtobool(str(value).strip()) + elif type is "int": + return int(value) elif type == "string": return value elif type is None: diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index 95dc28d4a..a79cf9f63 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -180,7 +180,7 @@ class Parser: name: str, help: str, type: Optional[ - Literal["string", "paths", "pathlist", "args", "linelist", "bool"] + Literal["string", "paths", "pathlist", "args", "linelist", "bool", "int"] ] = None, default: Any = NOT_SET, ) -> None: @@ -190,7 +190,7 @@ class Parser: Name of the ini-variable. :param type: Type of the variable. Can be: - + * ``int``: an integer * ``string``: a string * ``bool``: a boolean * ``args``: a list of strings, separated as in a shell @@ -215,7 +215,7 @@ class Parser: The value of ini-variables can be retrieved via a call to :py:func:`config.getini(name) `. """ - assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool") + assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool", "int") if default is NOT_SET: default = get_ini_default_for_type(type) @@ -224,7 +224,7 @@ class Parser: def get_ini_default_for_type( - type: Optional[Literal["string", "paths", "pathlist", "args", "linelist", "bool"]], + type: Optional[Literal["string", "paths", "pathlist", "args", "linelist", "bool", "int"]], ) -> Any: """ Used by addini to get the default value for a given ini-option type, when @@ -236,6 +236,8 @@ def get_ini_default_for_type( return [] elif type == "bool": return False + elif type is "int": + return 0 else: return "" diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 0adecc7c1..e9901b09c 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -301,8 +301,9 @@ def pytest_addoption(parser: Parser) -> None: ) add_option_ini( "--log-file-verbose", - dest="log_file_verbosity", - default=None, + dest="log_file_verbose", + default=0, + type="int", help="Log file verbose", ) add_option_ini( @@ -845,6 +846,14 @@ class LoggingPlugin: @hookimpl(wrapper=True) def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]: + + if self.log_file_verbose: + old_log_file_formatter = self.log_file_handler.formatter + self.log_file_handler.setFormatter(logging.Formatter()) + + self.log_file_handler.emit(logging.LogRecord('N/A', logging.WARNING, 'N/A', 0, f"Running at {item.nodeid}", None, None)) + self.log_file_handler.setFormatter(old_log_file_formatter) + self.log_cli_handler.set_when("setup") empty: Dict[str, List[logging.LogRecord]] = {} From 6e8fa92062af4de3c8892f38f4187646d2e62028 Mon Sep 17 00:00:00 2001 From: Ben Nguyen Tran Date: Sun, 28 Apr 2024 13:37:15 -0400 Subject: [PATCH 12/18] Fixed minor typos in type checks for "int" --- src/_pytest/config/__init__.py | 2 +- src/_pytest/config/argparsing.py | 2 +- src/_pytest/logging.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 16f803a24..5bbd0d957 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1644,7 +1644,7 @@ class Config: return value elif type == "bool": return _strtobool(str(value).strip()) - elif type is "int": + elif type == "int": return int(value) elif type == "string": return value diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index a79cf9f63..b39519e6c 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -236,7 +236,7 @@ def get_ini_default_for_type( return [] elif type == "bool": return False - elif type is "int": + elif type == "int": return 0 else: return "" diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index e9901b09c..7db4f95f2 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -850,8 +850,7 @@ class LoggingPlugin: if self.log_file_verbose: old_log_file_formatter = self.log_file_handler.formatter self.log_file_handler.setFormatter(logging.Formatter()) - - self.log_file_handler.emit(logging.LogRecord('N/A', logging.WARNING, 'N/A', 0, f"Running at {item.nodeid}", None, None)) + self.log_file_handler.emit(logging.LogRecord('N/A', logging.INFO, 'N/A', 0, f"Running at {item.nodeid}", None, None)) self.log_file_handler.setFormatter(old_log_file_formatter) self.log_cli_handler.set_when("setup") From ea6ddbc87074793a640015f6e8e9365e01e070e6 Mon Sep 17 00:00:00 2001 From: Ben Nguyen Tran Date: Sun, 28 Apr 2024 13:57:54 -0400 Subject: [PATCH 13/18] Fixed bug where --file-log-verbose=0 still produced verbose logs. --- src/_pytest/logging.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 7db4f95f2..3220a936e 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -847,7 +847,7 @@ class LoggingPlugin: @hookimpl(wrapper=True) def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]: - if self.log_file_verbose: + if self.log_file_verbose and int(self.log_file_verbose) >= 1: old_log_file_formatter = self.log_file_handler.formatter self.log_file_handler.setFormatter(logging.Formatter()) self.log_file_handler.emit(logging.LogRecord('N/A', logging.INFO, 'N/A', 0, f"Running at {item.nodeid}", None, None)) From 3d04010d7060ed029fcd2ab7022801ab3032428c Mon Sep 17 00:00:00 2001 From: Sirui Huang Date: Sun, 28 Apr 2024 20:06:28 -0400 Subject: [PATCH 14/18] alter wrong parameterize arguement test --- src/_pytest/mark/structures.py | 26 +++++++++++------------- src/_pytest/python.py | 18 +++++++++++++++- testing/local_testing/local_test_0.py | 4 ++-- testing/local_testing/local_test_test.py | 2 +- testing/test_mark.py | 11 ++++++---- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index a6503bf1d..c2057e75d 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -165,22 +165,20 @@ class ParameterSet(NamedTuple): # Check all parameter sets have the correct number of values. for param in parameters: if len(param.values) != len(argnames): + # Construct a string representation of the expected parameter names + expected_argnames = ", ".join(argnames) + # Construct a string representation of the provided parameter values + provided_values = ", ".join(map(repr, param.values)) msg = ( - '{nodeid}: in "parametrize" the number of names ({names_len}):\n' - " {names}\n" - "must be equal to the number of values ({values_len}):\n" - " {values}" - ) - fail( - msg.format( - nodeid=nodeid, - values=param.values, - names=argnames, - names_len=len(argnames), - values_len=len(param.values), - ), - pytrace=False, + f'{nodeid}: \n\n Error in parameterization for test "{func.__name__}".\n ' + f"The number of specified parameters ({len(argnames)}) " + f"does not match the number of provided values ({len(param.values)}): {provided_values}. \n" + f" Please ensure that the correct number of parameter names " + f"({len(param.values)}) are separated by commas within quotes.\n\n" + f'Require more than parameter names: "{expected_argnames}"' ) + + fail(msg, pytrace=False) else: # Empty parameter set (likely computed at runtime): create a single # parameter set with NOTSET values, with the "empty parameter set" mark applied to it. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 5e059f2c4..de23f8026 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1402,8 +1402,24 @@ class Metafunc: arg_directness = dict.fromkeys(argnames, "direct") for arg in indirect: if arg not in argnames: + # Construct a list of valid parameter names + valid_params = ", ".join([f'"{name}"' for name in argnames]) + + # Construct a string representing the expected number of parameters + expected_param_count = len(indirect[0]) + + # Construct a string representing the actual number of parameters provided + actual_param_count = len(argnames) + fail( - f"In {self.function.__name__}: indirect fixture '{arg}' doesn't exist", + f"In function {self.function.__name__}: {argnames} is not a valid parameter. " + f"Expected {expected_param_count} sub parameters, " + f"but only {actual_param_count} were provided. \n\n" + f"Make sure to pass parameter names as strings without quotes, separated by commas, \n " + f"e.g., '@pytest.mark.parametrize({valid_params}, )'" + f"\n\n" + f"Or if multiple parameters are used, separate them by commas. \n " + f"e.g., '@pytest.mark.parametrize(\"arg1, arg2\", )'", pytrace=False, ) arg_directness[arg] = "indirect" diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 76c079dea..fbc477f15 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -1,8 +1,8 @@ import pytest -@pytest.mark.parametrize("arg1,arg2", [(1, 1)]) -def test_parametrization(arg1, arg2): +@pytest.mark.parametrize("arg1, arg2", [(1, 1)]) +def test_parametrization(arg1: int, arg2: int) -> None: assert arg1 == arg2 assert arg1 + 1 == arg2 + 1 diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index 23ac56060..cb1c534bd 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -9,5 +9,5 @@ result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)] @pytest.mark.parametrize("a, b,expected_result", result_index) -def test_add(a, b, expected_result): +def test_add(a: int, b: int, expected_result: int) -> None: assert add_function.add(a, b) == expected_result diff --git a/testing/test_mark.py b/testing/test_mark.py index 2896afa45..eefedf15e 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -419,10 +419,13 @@ def test_parametrized_collect_with_wrong_args(pytester: Pytester) -> None: result = pytester.runpytest(py_file) result.stdout.fnmatch_lines( [ - 'test_parametrized_collect_with_wrong_args.py::test_func: in "parametrize" the number of names (2):', - " ['foo', 'bar']", - "must be equal to the number of values (3):", - " (1, 2, 3)", + "test_parametrized_collect_with_wrong_args.py::test_func: ", + "", + ' Error in parameterization for test "test_func".', + " The number of specified parameters (2) does not match the number of provided values (3): 1, 2, 3. ", + " Please ensure that the correct number of parameter names (3) are separated by commas within quotes.", + "", + 'Require more than parameter names: "foo, bar"', ] ) From 66d9e3b364759c91225ec708f7a97fc012c2266c Mon Sep 17 00:00:00 2001 From: Sirui Huang Date: Sun, 28 Apr 2024 20:30:28 -0400 Subject: [PATCH 15/18] run test suite on the implementation --- src/_pytest/config/__init__.py | 2 +- src/_pytest/config/argparsing.py | 15 +++++++++++++-- src/_pytest/logging.py | 13 +++++++++++-- testing/local_testing/add_function.py | 3 +-- testing/local_testing/local_test_0.py | 10 +++++----- testing/local_testing/local_test_test.py | 19 +++++-------------- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 5bbd0d957..412591991 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1645,7 +1645,7 @@ class Config: elif type == "bool": return _strtobool(str(value).strip()) elif type == "int": - return int(value) + return int(str(value).strip()) elif type == "string": return value elif type is None: diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index b39519e6c..ebb3693c2 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -215,7 +215,16 @@ class Parser: The value of ini-variables can be retrieved via a call to :py:func:`config.getini(name) `. """ - assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool", "int") + assert type in ( + None, + "string", + "paths", + "pathlist", + "args", + "linelist", + "bool", + "int", + ) if default is NOT_SET: default = get_ini_default_for_type(type) @@ -224,7 +233,9 @@ class Parser: def get_ini_default_for_type( - type: Optional[Literal["string", "paths", "pathlist", "args", "linelist", "bool", "int"]], + type: Optional[ + Literal["string", "paths", "pathlist", "args", "linelist", "bool", "int"] + ], ) -> Any: """ Used by addini to get the default value for a given ini-option type, when diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 3220a936e..5e92f3adb 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -846,11 +846,20 @@ class LoggingPlugin: @hookimpl(wrapper=True) def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]: - if self.log_file_verbose and int(self.log_file_verbose) >= 1: old_log_file_formatter = self.log_file_handler.formatter self.log_file_handler.setFormatter(logging.Formatter()) - self.log_file_handler.emit(logging.LogRecord('N/A', logging.INFO, 'N/A', 0, f"Running at {item.nodeid}", None, None)) + self.log_file_handler.emit( + logging.LogRecord( + "N/A", + logging.INFO, + "N/A", + 0, + f"Running at {item.nodeid}", + None, + None, + ) + ) self.log_file_handler.setFormatter(old_log_file_formatter) self.log_cli_handler.set_when("setup") diff --git a/testing/local_testing/add_function.py b/testing/local_testing/add_function.py index 40bd7ec64..e1829c359 100644 --- a/testing/local_testing/add_function.py +++ b/testing/local_testing/add_function.py @@ -1,3 +1,2 @@ -def add(a, b): +def add(a: int, b: int) -> int: return a + b - diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 95dbd553c..fbc477f15 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -1,16 +1,16 @@ import pytest + @pytest.mark.parametrize("arg1, arg2", [(1, 1)]) -def test_parametrization(arg1, arg2): +def test_parametrization(arg1: int, arg2: int) -> None: assert arg1 == arg2 assert arg1 + 1 == arg2 + 1 # Gets the error: In test_parametrization: indirect fixture '(1, 1)' doesn't exist -# Goal is to change this message into a more beginner friendly message. - +# Goal is to change this message into a more beginner friendly message. + # The error message lives in this path: pytest/src/_pytest/python.py - -#("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function \ No newline at end of file +# ("arg1", "arg2"), and "arg1, arg2" works, but cannot put in default parameters as normal function diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index a677697bf..968eff81e 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -1,22 +1,13 @@ # test_math_operations.py -import pytest import add_function +import pytest + + +result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)] -result_index = [ - (1, 2, 3), - (-1, 1, 0), - (0, 0, 0), - (5, -3, 2), - (1, 1, 2) -] @pytest.mark.parametrize("a, b, expected_result", result_index) - - -def test_add(a, b, expected_result): +def test_add(a: int, b: int, expected_result: int) -> None: assert add_function.add(a, b) == expected_result - - - From 938de1b623fd32be548300ee84d7595844d07018 Mon Sep 17 00:00:00 2001 From: Sirui Huang Date: Sun, 28 Apr 2024 20:44:49 -0400 Subject: [PATCH 16/18] add test case for wrong parameterization format --- testing/test_mark.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/testing/test_mark.py b/testing/test_mark.py index eefedf15e..46bbf58a7 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -404,6 +404,35 @@ def test_parametrized_collected_from_command_line(pytester: Pytester) -> None: rec.assertoutcome(passed=3) +def test_parametrized_collect_with_wrong_format(pytester: Pytester) -> None: + """Parametrized test argument format not intuitive + line issue#8593""" + py_file = pytester.makepyfile( + """ + import pytest + + @pytest.mark.parametrize("arg1", "arg2", [(1, 1)]) + def test_parametrization(arg1: int, arg2: int) -> None: + assert arg1 == arg2 + assert arg1 + 1 == arg2 + 1 + """ + ) + + result = pytester.runpytest(py_file) + result.stdout.fnmatch_lines( + [ + """In function test_parametrization: ['arg1'] is not a valid parameter. + Expected 2 sub parameters, but only 1 were provided. """, + "", + "Make sure to pass parameter names as strings without quotes, separated by commas, ", + " e.g., '@pytest.mark.parametrize(\"arg1\", )'", + "", + "Or if multiple parameters are used, separate them by commas. ", + " e.g., '@pytest.mark.parametrize(\"arg1, arg2\", )'", + ] + ) + + def test_parametrized_collect_with_wrong_args(pytester: Pytester) -> None: """Test collect parametrized func with wrong number of args.""" py_file = pytester.makepyfile( From 701e78b95665024a15144c4dccdf8f36429183c1 Mon Sep 17 00:00:00 2001 From: Sirui Huang Date: Sun, 28 Apr 2024 20:56:44 -0400 Subject: [PATCH 17/18] fix line length issue and modify test --- src/_pytest/python.py | 2 +- testing/test_mark.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 4f7313e6b..9238694c3 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1419,7 +1419,7 @@ class Metafunc: actual_param_count = len(argnames) fail( - f"In function {self.function.__name__}: {argnames} is not a valid parameter. " + f"In function {self.function.__name__}: {argnames} is not a valid parameter. \n" f"Expected {expected_param_count} sub parameters, " f"but only {actual_param_count} were provided. \n\n" f"Make sure to pass parameter names as strings without quotes, separated by commas, \n " diff --git a/testing/test_mark.py b/testing/test_mark.py index 46bbf58a7..f9eee67cc 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -421,8 +421,8 @@ def test_parametrized_collect_with_wrong_format(pytester: Pytester) -> None: result = pytester.runpytest(py_file) result.stdout.fnmatch_lines( [ - """In function test_parametrization: ['arg1'] is not a valid parameter. - Expected 2 sub parameters, but only 1 were provided. """, + "In function test_parametrization: ['arg1'] is not a valid parameter. ", + "Expected 2 sub parameters, but only 1 were provided. ", "", "Make sure to pass parameter names as strings without quotes, separated by commas, ", " e.g., '@pytest.mark.parametrize(\"arg1\", )'", From e32e48e95ed8f5b7aeefeec81886877716b041dc Mon Sep 17 00:00:00 2001 From: Sirui Huang Date: Sun, 28 Apr 2024 21:12:48 -0400 Subject: [PATCH 18/18] log file tests incorporated --- testing/test_log_file.py | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 testing/test_log_file.py diff --git a/testing/test_log_file.py b/testing/test_log_file.py new file mode 100644 index 000000000..723203e5b --- /dev/null +++ b/testing/test_log_file.py @@ -0,0 +1,76 @@ +import os + +from _pytest.pytester import Pytester + + +def test_log_file_verbose(pytester: Pytester) -> None: + log_file = str(pytester.path.joinpath("pytest.log")) + + pytester.makepyfile( + """ + import logging + def test_verbose1(): + logging.info("test 1") + + def test_verbose2(): + logging.warning("test 2") + """ + ) + + result = pytester.runpytest( + "-s", f"--log-file={log_file}", "--log-file-verbose=1", "--log-file-level=INFO" + ) + + rec = pytester.inline_run() + rec.assertoutcome(passed=2) + + # make sure that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file, encoding="utf-8") as rfh: + contents = rfh.read() + + for s in [ + "Running at test_log_file_verbose.py::test_verbose1", + "test 1", + "Running at test_log_file_verbose.py::test_verbose2", + "test 2", + ]: + assert s in contents + + +def test_log_file_verbose0(pytester: Pytester) -> None: + log_file = str(pytester.path.joinpath("pytest.log")) + + pytester.makepyfile( + """ + import logging + def test_verbose1(): + logging.info("test 1") + + def test_verbose2(): + logging.warning("test 2") + """ + ) + + result = pytester.runpytest( + "-s", f"--log-file={log_file}", "--log-file-verbose=0", "--log-file-level=INFO" + ) + + rec = pytester.inline_run() + rec.assertoutcome(passed=2) + + # make sure that we get a '0' exit code for the testsuite + assert result.ret == 0 + assert os.path.isfile(log_file) + with open(log_file, encoding="utf-8") as rfh: + contents = rfh.read() + + for s in ["test 1", "test 2"]: + assert s in contents + + for s in [ + "Running at test_log_file_verbose0.py::test_verbose1", + "Running at test_log_file_verbose.py::test_verbose2", + ]: + assert s not in contents