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,34 @@ 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+ """Deprecated access to configuration values.
1138+
1139+ .. deprecated:: 9.1
1140+ Use :meth:`getini` to access configuration values instead.
1141+ """
1142+ raise NotImplementedError ()
1143+ else :
1144+
1145+ @property
1146+ def inicfg (self ) -> _DeprecatedInicfgProxy :
1147+ """Deprecated access to configuration values.
1148+
1149+ .. deprecated:: 9.1
1150+ Use :meth:`getini` to access configuration values instead.
1151+ """
1152+ warnings .warn (
1153+ _pytest .deprecated .CONFIG_INICFG ,
1154+ stacklevel = 2 ,
1155+ )
1156+ return _DeprecatedInicfgProxy (self )
1157+
11011158 @property
11021159 def rootpath (self ) -> pathlib .Path :
11031160 """The path to the :ref:`rootdir <rootdir>`.
@@ -1428,7 +1485,7 @@ def _warn_or_fail_if_strict(self, message: str) -> None:
14281485
14291486 def _get_unknown_ini_keys (self ) -> set [str ]:
14301487 known_keys = self ._parser ._inidict .keys () | self ._parser ._ini_aliases .keys ()
1431- return self .inicfg .keys () - known_keys
1488+ return self ._inicfg .keys () - known_keys
14321489
14331490 def parse (self , args : list [str ], addopts : bool = True ) -> None :
14341491 # Parse given cmdline arguments into this config object.
@@ -1459,7 +1516,7 @@ def parse(self, args: list[str], addopts: bool = True) -> None:
14591516 self ._rootpath = rootpath
14601517 self ._inipath = inipath
14611518 self ._ignored_config_files = ignored_config_files
1462- self .inicfg = inicfg
1519+ self ._inicfg = inicfg
14631520 self ._parser .extra_info ["rootdir" ] = str (self .rootpath )
14641521 self ._parser .extra_info ["inifile" ] = str (self .inipath )
14651522
@@ -1636,14 +1693,14 @@ def _getini(self, name: str):
16361693 except KeyError as e :
16371694 raise ValueError (f"unknown configuration value: { name !r} " ) from e
16381695
1639- # Collect all possible values (canonical name + aliases) from inicfg .
1696+ # Collect all possible values (canonical name + aliases) from _inicfg .
16401697 # Each candidate is (ConfigValue, is_canonical).
16411698 candidates = []
1642- if canonical_name in self .inicfg :
1643- candidates .append ((self .inicfg [canonical_name ], True ))
1699+ if canonical_name in self ._inicfg :
1700+ candidates .append ((self ._inicfg [canonical_name ], True ))
16441701 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 ))
1702+ if target == canonical_name and alias in self ._inicfg :
1703+ candidates .append ((self ._inicfg [alias ], False ))
16471704
16481705 if not candidates :
16491706 return default
0 commit comments