1
1
from __future__ import annotations
2
2
3
3
import logging
4
- import os
5
4
import warnings
6
5
7
6
from pathlib import Path
11
10
import setuptools
12
11
13
12
from .. import _config
13
+ from .pyproject_reading import read_pyproject
14
+ from .setup_cfg import _dist_name_from_legacy
15
+ from .version_inference import VersionInferenceConfig
16
+ from .version_inference import VersionInferenceError
17
+ from .version_inference import VersionInferenceException
18
+ from .version_inference import get_version_inference_config
14
19
15
20
log = logging .getLogger (__name__ )
16
21
17
22
18
- def read_dist_name_from_setup_cfg (
19
- input : str | os .PathLike [str ] = "setup.cfg" ,
20
- ) -> str | None :
21
- # minimal effort to read dist_name off setup.cfg metadata
22
- import configparser
23
-
24
- parser = configparser .ConfigParser ()
25
- parser .read ([input ], encoding = "utf-8" )
26
- dist_name = parser .get ("metadata" , "name" , fallback = None )
27
- return dist_name
28
-
29
-
30
23
def _warn_on_old_setuptools (_version : str = setuptools .__version__ ) -> None :
31
24
if int (_version .split ("." )[0 ]) < 61 :
32
25
warnings .warn (
@@ -85,14 +78,15 @@ def _assign_version(
85
78
86
79
87
80
def _log_hookstart (hook : str , dist : setuptools .Distribution ) -> None :
88
- log .debug ("%s %r" , hook , vars (dist .metadata ))
81
+ log .debug ("%s %s %s % r" , hook , id ( dist ), id ( dist . metadata ) , vars (dist .metadata ))
89
82
90
83
91
84
def version_keyword (
92
85
dist : setuptools .Distribution ,
93
86
keyword : str ,
94
87
value : bool | dict [str , Any ] | Callable [[], dict [str , Any ]],
95
88
) -> None :
89
+ # Parse overrides (integration point responsibility)
96
90
overrides : dict [str , Any ]
97
91
if value is True :
98
92
overrides = {}
@@ -105,73 +99,96 @@ def version_keyword(
105
99
assert "dist_name" not in overrides , (
106
100
"dist_name may not be specified in the setup keyword "
107
101
)
108
- dist_name : str | None = dist .metadata .name
102
+
103
+ dist_name : str | None = _dist_name_from_legacy (dist )
104
+
105
+ was_set_by_infer = getattr (dist , "_setuptools_scm_version_set_by_infer" , False )
109
106
_log_hookstart ("version_keyword" , dist )
110
107
111
- if dist .metadata .version is not None :
112
- # Check if version was set by infer_version
113
- was_set_by_infer = getattr (dist , "_setuptools_scm_version_set_by_infer" , False )
108
+ # Get pyproject data
109
+ try :
110
+ pyproject_data = read_pyproject (
111
+ Path ("pyproject.toml" ), missing_section_ok = True , missing_file_ok = True
112
+ )
113
+ except (LookupError , ValueError ) as e :
114
+ log .debug ("Configuration issue in pyproject.toml: %s" , e )
115
+ return
114
116
117
+ # Get decision
118
+ result = get_version_inference_config (
119
+ dist_name = dist_name ,
120
+ current_version = dist .metadata .version ,
121
+ pyproject_data = pyproject_data ,
122
+ overrides = overrides ,
123
+ was_set_by_infer = was_set_by_infer ,
124
+ )
125
+
126
+ # Handle result
127
+ if result is None :
128
+ return # Don't infer
129
+ elif isinstance (result , VersionInferenceError ):
130
+ if result .should_warn :
131
+ warnings .warn (result .message )
132
+ return
133
+ elif isinstance (result , VersionInferenceException ):
134
+ raise result .exception
135
+ elif isinstance (result , VersionInferenceConfig ):
136
+ # Clear version if it was set by infer_version
115
137
if was_set_by_infer :
116
- # Version was set by infer_version, check if we have overrides
117
- if not overrides :
118
- # No overrides, just use the infer_version result
119
- return
120
- # We have overrides, clear the marker and proceed to override the version
121
138
dist ._setuptools_scm_version_set_by_infer = False # type: ignore[attr-defined]
122
139
dist .metadata .version = None
123
- else :
124
- # Version was set by something else, warn and return
125
- warnings .warn (f"version of { dist_name } already set" )
126
- return
127
-
128
- if dist_name is None :
129
- dist_name = read_dist_name_from_setup_cfg ()
130
140
131
- config = _config .Configuration .from_file (
132
- dist_name = dist_name ,
133
- missing_file_ok = True ,
134
- missing_section_ok = True ,
135
- ** overrides ,
136
- )
137
- _assign_version (dist , config )
141
+ # Proceed with inference
142
+ config = _config .Configuration .from_file (
143
+ dist_name = result .dist_name ,
144
+ pyproject_data = result .pyproject_data ,
145
+ missing_file_ok = True ,
146
+ missing_section_ok = True ,
147
+ ** overrides ,
148
+ )
149
+ _assign_version (dist , config )
138
150
139
151
140
152
def infer_version (dist : setuptools .Distribution ) -> None :
141
153
_log_hookstart ("infer_version" , dist )
142
- log .debug ("dist %s %s" , id (dist ), id (dist .metadata ))
143
- if dist .metadata .version is not None :
144
- return # metadata already added by hook
145
- dist_name = dist .metadata .name
146
- if dist_name is None :
147
- dist_name = read_dist_name_from_setup_cfg ()
148
- if not os .path .isfile ("pyproject.toml" ):
149
- return
150
- if dist_name == "setuptools-scm" :
151
- return
152
154
153
- # Check if setuptools-scm is configured before proceeding
154
- try :
155
- from .pyproject_reading import read_pyproject
155
+ dist_name = _dist_name_from_legacy (dist )
156
156
157
+ # Get pyproject data (integration point responsibility)
158
+ try :
157
159
pyproject_data = read_pyproject (Path ("pyproject.toml" ), missing_section_ok = True )
158
- # Only proceed if setuptools-scm is either in build_requires or has a tool section
159
- if not pyproject_data .is_required and not pyproject_data .section_present :
160
- return # No setuptools-scm configuration, silently return
161
- except (FileNotFoundError , LookupError ):
162
- return # No pyproject.toml or other issues, silently return
163
- except ValueError as e :
164
- # Log the error as debug info instead of raising it
160
+ except FileNotFoundError :
161
+ log .debug ("pyproject.toml not found" )
162
+ return
163
+ except (LookupError , ValueError ) as e :
165
164
log .debug ("Configuration issue in pyproject.toml: %s" , e )
166
- return # Configuration issue, silently return
165
+ return
167
166
168
- try :
169
- config = _config .Configuration .from_file (
170
- dist_name = dist_name , pyproject_data = pyproject_data
171
- )
172
- except LookupError as e :
173
- log .info (e , exc_info = True )
174
- else :
175
- _assign_version (dist , config )
176
- # Mark that this version was set by infer_version
177
- dist ._setuptools_scm_version_set_by_infer = True # type: ignore[attr-defined]
167
+ # Get decision
168
+ result = get_version_inference_config (
169
+ dist_name = dist_name ,
170
+ current_version = dist .metadata .version ,
171
+ pyproject_data = pyproject_data ,
172
+ )
173
+
174
+ # Handle result
175
+ if result is None :
176
+ return # Don't infer
177
+ elif isinstance (result , VersionInferenceError ):
178
+ if result .should_warn :
179
+ log .warning (result .message )
180
+ return
181
+ elif isinstance (result , VersionInferenceException ):
182
+ raise result .exception
183
+ elif isinstance (result , VersionInferenceConfig ):
184
+ # Proceed with inference
185
+ try :
186
+ config = _config .Configuration .from_file (
187
+ dist_name = result .dist_name , pyproject_data = result .pyproject_data
188
+ )
189
+ except LookupError as e :
190
+ log .info (e , exc_info = True )
191
+ else :
192
+ _assign_version (dist , config )
193
+ # Mark that this version was set by infer_version
194
+ dist ._setuptools_scm_version_set_by_infer = True # type: ignore[attr-defined]
0 commit comments