30
30
31
31
log = _log .log .getChild ("config" )
32
32
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
+
33
84
DEFAULT_TAG_REGEX = re .compile (
34
85
r"^(?:[\w-]+-)?(?P<version>[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$"
35
86
)
@@ -101,6 +152,7 @@ class GitConfiguration:
101
152
pre_parse : git .GitPreParse = dataclasses .field (
102
153
default_factory = lambda : _get_default_git_pre_parse ()
103
154
)
155
+ describe_command : _t .CMD_TYPE | None = None
104
156
105
157
@classmethod
106
158
def from_data (cls , data : dict [str , Any ]) -> GitConfiguration :
@@ -158,7 +210,10 @@ class Configuration:
158
210
version_file : _t .PathT | None = None
159
211
version_file_template : str | None = None
160
212
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
+
162
217
dist_name : str | None = None
163
218
version_cls : type [_VersionT ] = _Version
164
219
search_parent_directories : bool = False
@@ -170,9 +225,42 @@ class Configuration:
170
225
default_factory = lambda : ScmConfiguration ()
171
226
)
172
227
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 :
174
231
self .tag_regex = _check_tag_regex (self .tag_regex )
175
232
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
+
176
264
@property
177
265
def absolute_root (self ) -> str :
178
266
return _check_absolute_root (self .root , self .relative_to )
@@ -227,6 +315,9 @@ def from_data(
227
315
228
316
# Handle nested SCM configuration
229
317
scm_data = data .pop ("scm" , {})
318
+
319
+ # Handle nested SCM configuration
320
+
230
321
scm_config = ScmConfiguration .from_data (scm_data )
231
322
232
323
return cls (
0 commit comments