1111from collections .abc import Iterable
1212from collections .abc import Iterator
1313from collections .abc import Mapping
14+ from collections .abc import MutableMapping
1415from collections .abc import Sequence
1516import contextlib
1617import copy
4849from .compat import PathAwareHookProxy
4950from .exceptions import PrintHelp as PrintHelp
5051from .exceptions import UsageError as UsageError
52+ from .findpaths import ConfigDict
53+ from .findpaths import ConfigValue
5154from .findpaths import determine_setup
5255from _pytest import __version__
5356import _pytest ._code
5659from _pytest ._code .code import TracebackStyle
5760from _pytest ._io import TerminalWriter
5861from _pytest .compat import assert_never
62+ from _pytest .compat import deprecated
5963from _pytest .compat import NOTSET
6064from _pytest .config .argparsing import Argument
6165from _pytest .config .argparsing import FILE_OR_DIR
@@ -979,6 +983,30 @@ def _iter_rewritable_modules(package_files: Iterable[str]) -> Iterator[str]:
979983 yield from _iter_rewritable_modules (new_package_files )
980984
981985
986+ class _DeprecatedInicfgProxy (MutableMapping [str , Any ]):
987+ """Compatibility proxy for the deprecated Config.inicfg."""
988+
989+ __slots__ = ("_config" ,)
990+
991+ def __init__ (self , config : Config ) -> None :
992+ self ._config = config
993+
994+ def __getitem__ (self , key : str ) -> Any :
995+ return self ._config ._inicfg [key ].value
996+
997+ def __setitem__ (self , key : str , value : Any ) -> None :
998+ self ._config ._inicfg [key ] = ConfigValue (value , origin = "override" , mode = "toml" )
999+
1000+ def __delitem__ (self , key : str ) -> None :
1001+ del self ._config ._inicfg [key ]
1002+
1003+ def __iter__ (self ) -> Iterator [str ]:
1004+ return iter (self ._config ._inicfg )
1005+
1006+ def __len__ (self ) -> int :
1007+ return len (self ._config ._inicfg )
1008+
1009+
9821010@final
9831011class Config :
9841012 """Access to configuration values, pluginmanager and plugin hooks.
@@ -1089,6 +1117,7 @@ def __init__(
10891117 self .trace = self .pluginmanager .trace .root .get ("config" )
10901118 self .hook : pluggy .HookRelay = PathAwareHookProxy (self .pluginmanager .hook ) # type: ignore[assignment]
10911119 self ._inicache : dict [str , Any ] = {}
1120+ self ._inicfg : ConfigDict = {}
10921121 self ._cleanup_stack = contextlib .ExitStack ()
10931122 self .pluginmanager .register (self , "pytestconfig" )
10941123 self ._configured = False
@@ -1098,6 +1127,24 @@ def __init__(
10981127 self .args_source = Config .ArgsSource .ARGS
10991128 self .args : list [str ] = []
11001129
1130+ if TYPE_CHECKING :
1131+
1132+ @deprecated (
1133+ "config.inicfg is deprecated, use config.getini() to access configuration values instead." ,
1134+ )
1135+ @property
1136+ def inicfg (self ) -> _DeprecatedInicfgProxy :
1137+ raise NotImplementedError ()
1138+ else :
1139+
1140+ @property
1141+ def inicfg (self ) -> _DeprecatedInicfgProxy :
1142+ warnings .warn (
1143+ _pytest .deprecated .CONFIG_INICFG ,
1144+ stacklevel = 2 ,
1145+ )
1146+ return _DeprecatedInicfgProxy (self )
1147+
11011148 @property
11021149 def rootpath (self ) -> pathlib .Path :
11031150 """The path to the :ref:`rootdir <rootdir>`.
@@ -1428,7 +1475,7 @@ def _warn_or_fail_if_strict(self, message: str) -> None:
14281475
14291476 def _get_unknown_ini_keys (self ) -> set [str ]:
14301477 known_keys = self ._parser ._inidict .keys () | self ._parser ._ini_aliases .keys ()
1431- return self .inicfg .keys () - known_keys
1478+ return self ._inicfg .keys () - known_keys
14321479
14331480 def parse (self , args : list [str ], addopts : bool = True ) -> None :
14341481 # Parse given cmdline arguments into this config object.
@@ -1459,7 +1506,7 @@ def parse(self, args: list[str], addopts: bool = True) -> None:
14591506 self ._rootpath = rootpath
14601507 self ._inipath = inipath
14611508 self ._ignored_config_files = ignored_config_files
1462- self .inicfg = inicfg
1509+ self ._inicfg = inicfg
14631510 self ._parser .extra_info ["rootdir" ] = str (self .rootpath )
14641511 self ._parser .extra_info ["inifile" ] = str (self .inipath )
14651512
@@ -1636,14 +1683,14 @@ def _getini(self, name: str):
16361683 except KeyError as e :
16371684 raise ValueError (f"unknown configuration value: { name !r} " ) from e
16381685
1639- # Collect all possible values (canonical name + aliases) from inicfg .
1686+ # Collect all possible values (canonical name + aliases) from _inicfg .
16401687 # Each candidate is (ConfigValue, is_canonical).
16411688 candidates = []
1642- if canonical_name in self .inicfg :
1643- candidates .append ((self .inicfg [canonical_name ], True ))
1689+ if canonical_name in self ._inicfg :
1690+ candidates .append ((self ._inicfg [canonical_name ], True ))
16441691 for alias , target in self ._parser ._ini_aliases .items ():
1645- if target == canonical_name and alias in self .inicfg :
1646- candidates .append ((self .inicfg [alias ], False ))
1692+ if target == canonical_name and alias in self ._inicfg :
1693+ candidates .append ((self ._inicfg [alias ], False ))
16471694
16481695 if not candidates :
16491696 return default
0 commit comments