Repository: pytest-dev/pytest
Pull request: Check if config args and args_source exist
Closes #10626 
<!--
Thanks for submitting a PR, your contribution is really appreciated!

Here is a quick checklist that should be present in PRs.

- [ ] Include documentation when adding new features.
- [ ] Include new tests or update existing tests when applicable.
- [X] Allow maintainers to push and squash when merging my commits. Please uncheck this if you prefer to squash the commits yourself.

If this change fixes an issue, please:

- [ ] Add text like ``closes #XYZW`` to the PR description and/or commits (where ``XYZW`` is the issue number). See the [github docs](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) for more information.

Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:

- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/main/changelog/README.rst) for details.

  Write sentences in the **past or present tense**, examples:

  * *Improved verbose diff output with sequences.*
  * *Terminal summary statistics now use multiple colors.*

  Also make sure to end the sentence with a `.`.

- [ ] Add yourself to `AUTHORS` in alphabetical order.
-->


Problem statement:
Exception on  `pytest --fixture --help`
## minimal example

```python-traceback
$ pytest --fixtures --help
=============== test session starts ===============
platform darwin -- Python 3.11.0, pytest-7.2.0, pluggy-1.0.0
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/_pytest/main.py", line 268, in wrap_session
INTERNALERROR>     config.hook.pytest_sessionstart(session=session)
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/_pytest/terminal.py", line 720, in pytest_sessionstart
INTERNALERROR>     lines = self.config.hook.pytest_report_header(
INTERNALERROR>             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/_pytest/config/compat.py", line 67, in fixed_hook
INTERNALERROR>     return hook(**kw)
INTERNALERROR>            ^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/private/tmp/foo/.venv/lib/python3.11/site-packages/_pytest/terminal.py", line 741, in pytest_report_header
INTERNALERROR>     if config.args_source == Config.ArgsSource.TESTPATHS:
INTERNALERROR>        ^^^^^^^^^^^^^^^^^^
INTERNALERROR> AttributeError: 'Config' object has no attribute 'args_source'
```

## pip list

```
Package    Version
---------- -------
attrs      22.2.0
iniconfig  1.1.1
packaging  22.0
pip        22.3.1
pluggy     1.0.0
pytest     7.2.0
setuptools 65.6.3
wheel      0.38.4
```

## pytest and operating system versions

```
$ python -V
Python 3.11.0

$ pytest -V
pytest 7.2.0

$ sw_vers
ProductName:		macOS
ProductVersion:		13.0.1
BuildVersion:		22A400
```

Hints from issue discussion:
Can I take this issue up? @Zac-HD 
@Pierre-Sassoulas can you give me a **short guidance** on how to start contributing. I have already done the setup and followed the contribution page. I just wanted to have a guidance on start so I can proceed on my own.
Really Grateful.
Thank You
Do you have a particular question, I'm not sure what to tell you that is not already in the contributor guide ?

Commit message: Check if config args and args_source exist

Patch to review:
diff --git a/AUTHORS b/AUTHORS
index 7cf1748e606..f345c0cab93 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -290,6 +290,7 @@ Prashant Sharma
 Pulkit Goyal
 Punyashloka Biswal
 Quentin Pradet
+q0w
 Ralf Schmitt
 Ralph Giles
 Ram Rachum
diff --git a/changelog/10626.bugfix.rst b/changelog/10626.bugfix.rst
new file mode 100644
index 00000000000..510b05cdfc1
--- /dev/null
+++ b/changelog/10626.bugfix.rst
@@ -0,0 +1 @@
+Check if ``Config.args`` and ``Config.args_source`` exist.
diff --git a/src/_pytest/main.py b/src/_pytest/main.py
index 61fb7eaa4e3..8bbc1eec14b 100644
--- a/src/_pytest/main.py
+++ b/src/_pytest/main.py
@@ -619,7 +619,7 @@ def perform_collect(  # noqa: F811
         and ``session.items`` is empty.
         """
         if args is None:
-            args = self.config.args
+            args = self.config.args if hasattr(self.config, "args") else ()
 
         self.trace("perform_collect", self, args)
         self.trace.root.indent += 1
diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py
index d967a3ee6f1..34bc9719eee 100644
--- a/src/_pytest/terminal.py
+++ b/src/_pytest/terminal.py
@@ -737,8 +737,10 @@ def pytest_report_header(self, config: Config) -> List[str]:
 
         if config.inipath:
             line += ", configfile: " + bestrelpath(config.rootpath, config.inipath)
-
-        if config.args_source == Config.ArgsSource.TESTPATHS:
+        if (
+            hasattr(config, "args_source")
+            and config.args_source == Config.ArgsSource.TESTPATHS
+        ):
             testpaths: List[str] = config.getini("testpaths")
             line += ", testpaths: {}".format(", ".join(testpaths))
 
diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py
index 3ce5cb34ddd..d996f80bb93 100644
--- a/testing/python/fixtures.py
+++ b/testing/python/fixtures.py
@@ -3338,6 +3338,10 @@ def test_funcarg_compat(self, pytester: Pytester) -> None:
         config = pytester.parseconfigure("--funcargs")
         assert config.option.showfixtures
 
+    def test_show_help(self, pytester: Pytester) -> None:
+        result = pytester.runpytest("--fixtures", "--help")
+        assert not result.ret
+
     def test_show_fixtures(self, pytester: Pytester) -> None:
         result = pytester.runpytest("--fixtures")
         result.stdout.fnmatch_lines(


Code review comments:
diff_hunk: @@ -0,0 +1 @@
+Check if ``Config.args`` and ``Config.args_source`` exist.
path: changelog/10626.bugfix.rst
text: @user1:
```suggestion
Fix crash if ``--fixtures`` and ``--help`` are passed at the same time.
```