11"""
22Dependency version management for testing.
3- Generates requirements files for min, max, and default dependency versions.
3+ Generates requirements files for min and default dependency versions.
4+ For min versions, creates flexible constraints (e.g., >=1.2.5,<1.3.0) to allow
5+ compatible patch updates instead of pinning exact versions.
46"""
57
68import toml
@@ -58,6 +60,39 @@ def _extract_versions_from_specifier(self, spec_set_str):
5860 print (f"Warning: Could not parse constraint '{ spec_set_str } ': { e } " , file = sys .stderr )
5961 return None , None
6062
63+ def _create_flexible_minimum_constraint (self , package_name , min_version ):
64+ """Create a flexible minimum constraint that allows compatible updates"""
65+ try :
66+ # Split version into parts
67+ version_parts = min_version .split ('.' )
68+
69+ if len (version_parts ) >= 2 :
70+ major = version_parts [0 ]
71+ minor = version_parts [1 ]
72+
73+ # Special handling for packages that commonly have conflicts
74+ # For these packages, use wider constraints to allow more compatibility
75+ if package_name in ['requests' , 'urllib3' , 'pandas' ]:
76+ # Use wider constraint: >=min_version,<next_major
77+ # e.g., 2.18.1 becomes >=2.18.1,<3.0.0
78+ next_major = int (major ) + 1
79+ upper_bound = f"{ next_major } .0.0"
80+ return f"{ package_name } >={ min_version } ,<{ upper_bound } "
81+ else :
82+ # For other packages, use minor version constraint
83+ # e.g., 1.2.5 becomes >=1.2.5,<1.3.0
84+ next_minor = int (minor ) + 1
85+ upper_bound = f"{ major } .{ next_minor } .0"
86+ return f"{ package_name } >={ min_version } ,<{ upper_bound } "
87+ else :
88+ # If version doesn't have minor version, just use exact version
89+ return f"{ package_name } =={ min_version } "
90+
91+ except (ValueError , IndexError ) as e :
92+ print (f"Warning: Could not create flexible constraint for { package_name } =={ min_version } : { e } " , file = sys .stderr )
93+ # Fallback to exact version
94+ return f"{ package_name } =={ min_version } "
95+
6196 def generate_requirements (self , version_type = "min" , include_optional = False ):
6297 """
6398 Generate requirements for specified version type.
@@ -85,7 +120,9 @@ def generate_requirements(self, version_type="min", include_optional=False):
85120 elif version_type == "min" :
86121 min_version , _ = self ._extract_versions_from_specifier (version_constraint )
87122 if min_version :
88- requirements .append (f"{ name } =={ min_version } " )
123+ # Create flexible constraint that allows patch updates for compatibility
124+ flexible_constraint = self ._create_flexible_minimum_constraint (name , min_version )
125+ requirements .append (flexible_constraint )
89126
90127 return requirements
91128
@@ -95,7 +132,13 @@ def write_requirements_file(self, filename, version_type="min", include_optional
95132 requirements = self .generate_requirements (version_type , include_optional )
96133
97134 with open (filename , 'w' ) as f :
98- f .write (f"# { version_type .title ()} dependency versions generated from pyproject.toml\n " )
135+ if version_type == "min" :
136+ f .write (f"# Minimum compatible dependency versions generated from pyproject.toml\n " )
137+ f .write (f"# Uses flexible constraints to resolve compatibility conflicts:\n " )
138+ f .write (f"# - Common packages (requests, urllib3, pandas): >=min,<next_major\n " )
139+ f .write (f"# - Other packages: >=min,<next_minor\n " )
140+ else :
141+ f .write (f"# { version_type .title ()} dependency versions generated from pyproject.toml\n " )
99142 for req in sorted (requirements ):
100143 f .write (f"{ req } \n " )
101144
0 commit comments