3030
3131log = _log .log .getChild ("config" )
3232
33+
34+ def _is_called_from_dataclasses () -> bool :
35+ """Check if the current call is from the dataclasses module."""
36+ import inspect
37+
38+ frame = inspect .currentframe ()
39+ try :
40+ # Walk up to 7 frames to check for dataclasses calls
41+ current_frame = frame
42+ assert current_frame is not None
43+ for _ in range (7 ):
44+ current_frame = current_frame .f_back
45+ if current_frame is None :
46+ break
47+ if "dataclasses.py" in current_frame .f_code .co_filename :
48+ return True
49+ return False
50+ finally :
51+ del frame
52+
53+
54+ class _GitDescribeCommandDescriptor :
55+ """Data descriptor for deprecated git_describe_command field."""
56+
57+ def __get__ (
58+ self , obj : Configuration | None , objtype : type [Configuration ] | None = None
59+ ) -> _t .CMD_TYPE | None :
60+ if obj is None :
61+ return self # type: ignore[return-value]
62+
63+ # Only warn if not being called by dataclasses.replace or similar introspection
64+ is_from_dataclasses = _is_called_from_dataclasses ()
65+ if not is_from_dataclasses :
66+ warnings .warn (
67+ "Configuration field 'git_describe_command' is deprecated. "
68+ "Use 'scm.git.describe_command' instead." ,
69+ DeprecationWarning ,
70+ stacklevel = 2 ,
71+ )
72+ return obj .scm .git .describe_command
73+
74+ def __set__ (self , obj : Configuration , value : _t .CMD_TYPE | None ) -> None :
75+ warnings .warn (
76+ "Configuration field 'git_describe_command' is deprecated. "
77+ "Use 'scm.git.describe_command' instead." ,
78+ DeprecationWarning ,
79+ stacklevel = 2 ,
80+ )
81+ obj .scm .git .describe_command = value
82+
83+
3384DEFAULT_TAG_REGEX = re .compile (
3485 r"^(?:[\w-]+-)?(?P<version>[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$"
3586)
@@ -101,6 +152,7 @@ class GitConfiguration:
101152 pre_parse : git .GitPreParse = dataclasses .field (
102153 default_factory = lambda : _get_default_git_pre_parse ()
103154 )
155+ describe_command : _t .CMD_TYPE | None = None
104156
105157 @classmethod
106158 def from_data (cls , data : dict [str , Any ]) -> GitConfiguration :
@@ -158,7 +210,10 @@ class Configuration:
158210 version_file : _t .PathT | None = None
159211 version_file_template : str | None = None
160212 parse : ParseFunction | None = None
161- git_describe_command : _t .CMD_TYPE | None = None
213+ git_describe_command : dataclasses .InitVar [_t .CMD_TYPE | None ] = (
214+ _GitDescribeCommandDescriptor ()
215+ )
216+
162217 dist_name : str | None = None
163218 version_cls : type [_VersionT ] = _Version
164219 search_parent_directories : bool = False
@@ -170,9 +225,42 @@ class Configuration:
170225 default_factory = lambda : ScmConfiguration ()
171226 )
172227
173- def __post_init__ (self ) -> None :
228+ # Deprecated fields (handled in __post_init__)
229+
230+ def __post_init__ (self , git_describe_command : _t .CMD_TYPE | None ) -> None :
174231 self .tag_regex = _check_tag_regex (self .tag_regex )
175232
233+ # Handle deprecated git_describe_command
234+ # Check if it's a descriptor object (happens when no value is passed)
235+ if git_describe_command is not None and not isinstance (
236+ git_describe_command , _GitDescribeCommandDescriptor
237+ ):
238+ # Check if this is being called from dataclasses
239+ is_from_dataclasses = _is_called_from_dataclasses ()
240+
241+ same_value = (
242+ self .scm .git .describe_command is not None
243+ and self .scm .git .describe_command == git_describe_command
244+ )
245+
246+ if is_from_dataclasses and same_value :
247+ # Ignore the passed value - it's from dataclasses.replace() with same value
248+ pass
249+ else :
250+ warnings .warn (
251+ "Configuration field 'git_describe_command' is deprecated. "
252+ "Use 'scm.git.describe_command' instead." ,
253+ DeprecationWarning ,
254+ stacklevel = 2 ,
255+ )
256+ # Check for conflicts
257+ if self .scm .git .describe_command is not None :
258+ raise ValueError (
259+ "Cannot specify both 'git_describe_command' (deprecated) and "
260+ "'scm.git.describe_command'. Please use only 'scm.git.describe_command'."
261+ )
262+ self .scm .git .describe_command = git_describe_command
263+
176264 @property
177265 def absolute_root (self ) -> str :
178266 return _check_absolute_root (self .root , self .relative_to )
@@ -227,6 +315,9 @@ def from_data(
227315
228316 # Handle nested SCM configuration
229317 scm_data = data .pop ("scm" , {})
318+
319+ # Handle nested SCM configuration
320+
230321 scm_config = ScmConfiguration .from_data (scm_data )
231322
232323 return cls (
0 commit comments