@@ -97,7 +97,7 @@ class BuildOptions:
9797 repair_command : str
9898 manylinux_images : dict [str , str ] | None
9999 musllinux_images : dict [str , str ] | None
100- dependency_constraints : DependencyConstraints | None
100+ dependency_constraints : DependencyConstraints
101101 test_command : str | None
102102 before_test : str | None
103103 test_sources : list [str ]
@@ -591,6 +591,10 @@ def __init__(
591591 except FileNotFoundError :
592592 self .pyproject_toml = None
593593
594+ # cache the build options method so repeated calls don't need to
595+ # resolve the options again
596+ self .build_options = functools .cache (self ._compute_build_options )
597+
594598 @functools .cached_property
595599 def config_file_path (self ) -> Path | None :
596600 args = self .command_line_arguments
@@ -667,9 +671,11 @@ def globals(self) -> GlobalOptions:
667671 allow_empty = allow_empty ,
668672 )
669673
670- def build_options (self , identifier : str | None ) -> BuildOptions :
674+ def _compute_build_options (self , identifier : str | None ) -> BuildOptions :
671675 """
672- Compute BuildOptions for a single run configuration.
676+ Compute BuildOptions for a single run configuration. Normally accessed
677+ through the `build_options` method, which is the same but the result
678+ is cached.
673679 """
674680
675681 with self .reader .identifier (identifier ):
@@ -687,7 +693,6 @@ def build_options(self, identifier: str | None) -> BuildOptions:
687693 "config-settings" , option_format = ShlexTableFormat (sep = " " , pair_sep = "=" )
688694 )
689695
690- dependency_versions = self .reader .get ("dependency-versions" )
691696 test_command = self .reader .get ("test-command" , option_format = ListFormat (sep = " && " ))
692697 before_test = self .reader .get ("before-test" , option_format = ListFormat (sep = " && " ))
693698 test_sources = shlex .split (
@@ -733,15 +738,18 @@ def build_options(self, identifier: str | None) -> BuildOptions:
733738 with contextlib .suppress (KeyError ):
734739 environment .add (env_var_name , self .env [env_var_name ], prepend = True )
735740
736- if dependency_versions == "pinned" :
737- dependency_constraints : DependencyConstraints | None = (
738- DependencyConstraints .with_defaults ()
741+ dependency_versions_str = self .reader .get (
742+ "dependency-versions" ,
743+ env_plat = True ,
744+ option_format = ShlexTableFormat (sep = "; " , pair_sep = ":" , allow_merge = False ),
745+ )
746+ try :
747+ dependency_constraints = DependencyConstraints .from_config_string (
748+ dependency_versions_str
739749 )
740- elif dependency_versions == "latest" :
741- dependency_constraints = None
742- else :
743- dependency_versions_path = Path (dependency_versions )
744- dependency_constraints = DependencyConstraints (dependency_versions_path )
750+ except (ValueError , OSError ) as e :
751+ msg = f"Failed to parse dependency versions. { e } "
752+ raise errors .ConfigurationError (msg ) from e
745753
746754 if test_extras :
747755 test_extras = f"[{ test_extras } ]"
0 commit comments