Repository: nose-devs/nose2

Issue:
v0.15.0 seemed to break my ini config
Here is my ini config file:
```
[flake8]
max-line-length = 120
extend-ignore = E722

[unittest]
plugins = nose2.plugins.layers
          nose2.plugins.junitxml

[junit-xml]
always-on = False
keep_restricted = False
path = nosetests.xml
test_fullname = False

[layer-reporter]
always-on = True
colors = False
```

Running `nose2 -c tox.ini --junit-xml <testNames>` I get:
`nose2: error: Unrecognized arguments: --junit-xml`

Reverting back to v0.14.2 fixes my issue.

Discussion:
@sirosen: Do you have a `pyproject.toml` for your repo? 0.15.0 introduces the possibility of config in `[tool.nose2]` there, so there are two easy possibilities:
- the loading code is somehow broken and is overwriting your config
- you have a `[tool.nose2]` table (which used to do nothing) and which now messes things up

I wouldn't be shocked if the TOML loading code is imperfect. It's the first time that codepath has been touched in a really long time. But I need a little more info to reproduce this.@grhwalls: pyproject.toml:
```
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "axi_hw_devices"
description="Library for device specific operations"
readme = "README.rst"
requires-python = ">=3"

# these are direct, imported dependencies. There may be other packages which are assumed, but
# since alternate packages are possible to use (as long as they have similar interfaces), they are
# not called out explicitly here.
dependencies = [
]

dynamic = ["version"]

[project.optional-dependencies]
dev = [
  "build",
  "nose2",
  "flake8",
  "twine",
]
test = [
  "axi_hw_devices[dev]",
  "vivado_jtag >= 3.0.0.dev",
  "xil_axi_ip >= 2.1.0.dev",
]

[tool.setuptools]
packages = ["axi_hw_devices",]

[tool.setuptools.dynamic]
version = {attr = "axi_hw_devices.version.__version__"}
```@sirosen: I just looked into this and figured it out. It seems obvious in hindsight, but there's a bug introduced in the new pyproject.toml loading code in which it won't read config files (even those passed with `-c`) if they don't end in `.cfg`.

It's simply an incorrect conditional being used to dispatch between INI loading and pyproject.toml loading.

I'm cooking up a regression test, and then I'll make the fix. Expect a v0.15.1 to ship within the next few hours ( :crossed_fingers: ).@sirosen: v0.15.1 is now available! :tada: 

Please let me know if it clears things up (as it should) or if you see other issues.@grhwalls: v0.15.1 fixed my issue! Thanks!

Solution patch:
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 3a842fb..5d0c4b3 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -13,6 +13,13 @@ testsuites.
 Unreleased
 ----------
 
+Fixed
+~~~~~
+
+* Fix a bug with config loading which caused custom ini configs not to load if
+  they were not named with a ``.cfg`` extension. Thanks :user:`grhwalls` for
+  the bug report!
+
 0.15.0 (2024-05-30)
 -------------------
 
diff --git a/nose2/session.py b/nose2/session.py
index bfc3e1d..d6e527e 100644
--- a/nose2/session.py
+++ b/nose2/session.py
@@ -1,8 +1,7 @@
 import argparse
 import logging
 import os
-
-# py2/py3 compatible load of SafeConfigParser/ConfigParser
+import pathlib
 from configparser import ConfigParser
 
 from nose2 import config, events, util
@@ -120,11 +119,12 @@ class Session:
 
         """
         for filename in filenames:
-            if filename.endswith(".cfg"):
-                self.config.read(filename)
-            elif filename.endswith("pyproject.toml"):
-                if not os.path.exists(filename):
-                    continue
+            path = pathlib.Path(filename)
+            if not path.exists():
+                continue
+
+            # handle pyproject.toml case
+            if path.name == "pyproject.toml":
                 toml_config = load_toml(filename)
                 if not isinstance(toml_config.get("tool"), dict):
                     continue
@@ -133,6 +133,10 @@ class Session:
                     continue
                 self.config.read_dict(tool_table["nose2"])
 
+            # else, use the config parser to read config data
+            else:
+                self.config.read(path)
+
     def loadPlugins(self, modules=None, exclude=None):
         """Load plugins.
 


Test patch:
diff --git a/nose2/tests/functional/test_session.py b/nose2/tests/functional/test_session.py
index 9f7061a..27a1eb7 100644
--- a/nose2/tests/functional/test_session.py
+++ b/nose2/tests/functional/test_session.py
@@ -1,4 +1,6 @@
+import pathlib
 import sys
+import tempfile
 import unittest
 
 from nose2 import session
@@ -6,6 +8,25 @@ from nose2._toml import TOML_ENABLED
 from nose2.tests._common import FunctionalTestCase, support_file
 
 
+def test_loading_config_from_ini_file_without_cfg_suffix():
+    """
+    Regression test for https://github.com/nose-devs/nose2/issues/614
+
+    It is possible to have nose2 config embedded in any ini config file, and it might
+    not have a recognizable name.
+    It is not guaranteed that filenames used for config will end in `.cfg`.
+    """
+    sess = session.Session()
+    with tempfile.TemporaryDirectory() as tmpdirname:
+        tmpdir = pathlib.Path(tmpdirname)
+
+        foo_ini = tmpdir / "foo.ini"
+        foo_ini.write_text("""[alpha]\na = 1""")
+
+        sess.loadConfigFiles(str(foo_ini))
+        assert sess.config.has_section("alpha")
+
+
 class SessionFunctionalTests(FunctionalTestCase):
     def setUp(self):
         self.s = session.Session()