11from __future__ import annotations
22
3+ import dataclasses
34import os
45import platform
56import re
67import sys
78from pathlib import Path
8- from typing import TYPE_CHECKING , Any , Literal
9+ from typing import TYPE_CHECKING , Any , Generic , Literal , TypeVar
910
1011import packaging .tags
1112from packaging .specifiers import SpecifierSet
1819from ..errors import CMakeNotFoundError
1920from ..resources import resources
2021
21- __all__ = ["process_overides" , "regex_match" ]
22+ __all__ = ["OverrideRecord" , " process_overides" , "regex_match" ]
2223
2324
2425def __dir__ () -> list [str ]:
@@ -29,6 +30,33 @@ def __dir__() -> list[str]:
2930 from collections .abc import Mapping
3031
3132
33+ T = TypeVar ("T" )
34+
35+
36+ @dataclasses .dataclass
37+ class OverrideRecord (Generic [T ]):
38+ """
39+ Record of the override action.
40+
41+ Saves the original and final values, and the override reasons.
42+ """
43+
44+ key : str
45+ """Settings key that is overridden."""
46+ original_value : T | None
47+ """
48+ Original value in the pyproject table.
49+
50+ If the pyproject table did not have the key, this is a ``None``.
51+ """
52+ value : T
53+ """Final value."""
54+ passed_all : dict [str , str ] | None
55+ """All if statements that passed (except the effective ``match_any``)."""
56+ passed_any : dict [str , str ] | None
57+ """All if.any statements that passed."""
58+
59+
3260def strtobool (value : str ) -> bool :
3361 """
3462 Converts a environment variable string into a boolean value.
@@ -257,20 +285,72 @@ def inherit_join(
257285 raise TypeError (msg )
258286
259287
288+ def record_override (
289+ * keys : str ,
290+ value : Any ,
291+ tool_skb : dict [str , Any ],
292+ overriden_items : dict [str , OverrideRecord [Any ]],
293+ passed_all : dict [str , str ] | None ,
294+ passed_any : dict [str , str ] | None ,
295+ ) -> None :
296+ full_key = "." .join (keys )
297+ # Get the original_value to construct the record
298+ if full_key in overriden_items :
299+ # We found the original value from a previous override record
300+ original_value = overriden_items [full_key ].original_value
301+ else :
302+ # Otherwise navigate the original pyproject table until we resolved all keys
303+ _dict_or_value = tool_skb
304+ keys_list = [* keys ]
305+ while keys_list :
306+ k = keys_list .pop (0 )
307+ if k not in _dict_or_value :
308+ # We hit a dead end so we imply the original_value was not set (`None`)
309+ original_value = None
310+ break
311+ _dict_or_value = tool_skb [k ]
312+ if isinstance (_dict_or_value , dict ):
313+ # If the value is a dict it is either the final value or we continue
314+ # to navigate it
315+ continue
316+ # Otherwise it should be the final value
317+ original_value = _dict_or_value
318+ if keys_list :
319+ msg = f"Could not navigate to the key { full_key } because { k } is a { type (_dict_or_value )} "
320+ raise TypeError (msg )
321+ break
322+ else :
323+ # We exhausted all keys so the current value should be the table key we are
324+ # interested in
325+ original_value = _dict_or_value
326+ # Now save the override record
327+ overriden_items [full_key ] = OverrideRecord (
328+ key = keys [- 1 ],
329+ original_value = original_value ,
330+ value = value ,
331+ passed_any = passed_any ,
332+ passed_all = passed_all ,
333+ )
334+
335+
260336def process_overides (
261337 tool_skb : dict [str , Any ],
262338 * ,
263339 state : Literal ["sdist" , "wheel" , "editable" , "metadata_wheel" , "metadata_editable" ],
264340 retry : bool ,
265341 env : Mapping [str , str ] | None = None ,
266- ) -> set [str ]:
342+ ) -> tuple [ set [str ], dict [ str , OverrideRecord [ Any ]] ]:
267343 """
268344 Process overrides into the main dictionary if they match. Modifies the input
269345 dictionary. Must be run from the package directory.
346+
347+ :return: A tuple of the set of matching overrides and a dict of changed keys and
348+ override record
270349 """
271350 has_dist_info = Path ("PKG-INFO" ).is_file ()
272351
273352 global_matched : set [str ] = set ()
353+ overriden_items : dict [str , OverrideRecord [Any ]] = {}
274354 for override in tool_skb .pop ("overrides" , []):
275355 passed_any : dict [str , str ] | None = None
276356 passed_all : dict [str , str ] | None = None
@@ -354,17 +434,33 @@ def process_overides(
354434 inherit1 = inherit_override .get (key , {})
355435 if isinstance (value , dict ):
356436 for key2 , value2 in value .items ():
437+ record_override (
438+ * [key , key2 ],
439+ value = value ,
440+ tool_skb = tool_skb ,
441+ overriden_items = overriden_items ,
442+ passed_all = passed_all ,
443+ passed_any = passed_any ,
444+ )
357445 inherit2 = inherit1 .get (key2 , "none" )
358446 inner = tool_skb .get (key , {})
359447 inner [key2 ] = inherit_join (
360448 value2 , inner .get (key2 , None ), inherit2
361449 )
362450 tool_skb [key ] = inner
363451 else :
452+ record_override (
453+ key ,
454+ value = value ,
455+ tool_skb = tool_skb ,
456+ overriden_items = overriden_items ,
457+ passed_all = passed_all ,
458+ passed_any = passed_any ,
459+ )
364460 inherit_override_tmp = inherit_override or "none"
365461 if isinstance (inherit_override_tmp , dict ):
366462 assert not inherit_override_tmp
367463 tool_skb [key ] = inherit_join (
368464 value , tool_skb .get (key ), inherit_override_tmp
369465 )
370- return global_matched
466+ return global_matched , overriden_items
0 commit comments