support for () in version spec; proper equals op

(cherry picked from commit b6dcc1204e225369df009a59ece08f5797138b0f)

GitOrigin-RevId: 74ca04448d7eac28d4454f70e88dd260a02fb3ec
This commit is contained in:
Aleksandr Sorotskii
2025-06-19 14:14:33 +02:00
committed by intellij-monorepo-bot
parent 99ba241ed3
commit dbcc824467
5 changed files with 23 additions and 9 deletions

View File

@@ -45,12 +45,12 @@ class PyRequirementImpl(
return when (other) {
is String -> name == normalizePackageName(other)
is PyRequirementImpl -> name == other.name // TODO: should we match specs & options ?
is PyRequirementImpl -> name == other.name && versionSpecs == other.versionSpecs
else -> false
}
}
override fun hashCode(): Int = name.hashCode()
override fun hashCode(): Int = 31 * name.hashCode() + versionSpecs.hashCode()
override fun toString(): String {
return presentableText

View File

@@ -30,9 +30,6 @@ import static com.jetbrains.python.packaging.parser.RequirementsParserHelper.VCS
* @see <a href="https://www.python.org/dev/peps/pep-0440/">PEP-440</a>
* @see PyRequirement
* @see PyPackageVersionNormalizer
* @see PyPackageManager#parseRequirement(String)
* @see PyPackageManager#parseRequirements(String)
* @see PyPackageManager#parseRequirements(VirtualFile)
*/
public final class PyRequirementParser {
@@ -148,8 +145,8 @@ public final class PyRequirementParser {
private static final @NotNull String REQUIREMENT_VERSION_SPEC_REGEXP = "(<=?|!=|===?|>=?|~=)" + LINE_WS_REGEXP + "*[\\.\\*\\+!\\w-]+";
private static final @NotNull String REQUIREMENT_VERSIONS_SPECS_REGEXP =
"(?<" + REQUIREMENT_VERSIONS_SPECS_GROUP + ">" + REQUIREMENT_VERSION_SPEC_REGEXP +
"(" + LINE_WS_REGEXP + "*," + LINE_WS_REGEXP + "*" + REQUIREMENT_VERSION_SPEC_REGEXP + ")*)?";
"(?<" + REQUIREMENT_VERSIONS_SPECS_GROUP + ">\\(?" + REQUIREMENT_VERSION_SPEC_REGEXP +
"(" + LINE_WS_REGEXP + "*," + LINE_WS_REGEXP + "*" + REQUIREMENT_VERSION_SPEC_REGEXP + ")*\\)?)?";
private static final @NotNull String REQUIREMENT_OPTIONS_GROUP = "options";
@@ -371,6 +368,11 @@ public final class PyRequirementParser {
private static @NotNull List<PyRequirementVersionSpec> parseVersionSpecs(@Nullable String versionSpecs) {
if (versionSpecs == null) return Collections.emptyList();
versionSpecs = versionSpecs.trim();
if (versionSpecs.startsWith("(") && versionSpecs.endsWith(")")) {
versionSpecs = versionSpecs.substring(1, versionSpecs.length() - 1);
}
return StreamSupport
.stream(StringUtil.tokenize(versionSpecs, ",").spliterator(), false)
.map(String::trim)

View File

@@ -3,7 +3,7 @@ from setuptools import setup
setup(name='foo',
version=0.1,
install_requires = ["sqlalchemy >=1.0.12, <1.1",
"mysql-connector-python >=2.1.3, <2.2",],
"mysql-connector-python ==2.1.3",],
dependency_links = [
"git+https://github.com/mysql/mysql-connector-python.git@2.1.3#egg=mysql-connector-python-2.1.3",
])

View File

@@ -1969,6 +1969,18 @@ public class PyRequirementTest extends PyTestCase {
assertEquals(pyRequirement("no_limit_nester", EQ, "1.0+local.version.10"), fromLine("no_limit_nester==1.0+local.version.10"));
}
public void testRequirementVersionWithBraces() {
assertEquals(pyRequirement("Orange-Bioinformatics", EQ, "2.5a20"), fromLine("Orange-Bioinformatics (==2.5a20)"));
assertEquals(pyRequirement("MOCPy", EQ, "0.1.0.dev0"), fromLine("MOCPy (==0.1.0.dev0)"));
assertEquals(pyRequirement("score.webassets", EQ, "0.2.3"), fromLine("score.webassets (==0.2.3)"));
assertEquals(pyRequirement("pip_helpers", EQ, "0.5.post6"), fromLine("pip_helpers (==0.5.post6)"));
assertEquals(pyRequirement("Django", EQ, "1.9rc1"), fromLine("Django (==1.9rc1)"));
assertEquals(pyRequirement("django", EQ, "1!1"), fromLine("django (==1!1)"));
assertEquals(pyRequirement("pinax-utils", EQ, "1.0b1.dev3"), fromLine("pinax-utils (==1.0b1.dev3)"));
assertEquals(pyRequirement("Flask-Celery-py3", EQ, "0.1.*"), fromLine("Flask-Celery-py3 (==0.1.*)"));
assertEquals(pyRequirement("no_limit_nester", EQ, "1.0+local.version.10"), fromLine("no_limit_nester (==1.0+local.version.10)"));
}
// https://www.python.org/dev/peps/pep-0440/#normalization
public void testRequirementAlternatePreReleaseVersion() {
doRequirementVersionNormalizationTest("1.9rc1", "1.9RC1");

View File

@@ -31,7 +31,7 @@ class CondaEnvironmentTest {
// Exact version specifications
PyRequirementParser.fromLine("scipy==1.9.3")!!,
PyRequirementParser.fromLine("requests==2.28.1")!!,
PyRequirementParser.fromLine("requests~=2.28.1")!!,
PyRequirementParser.fromLine("flask==2.2.2")!!,
// Version ranges with operators