From cc2c8ad1e16cbf81de5e83cbc817d05519ccac5c Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Thu, 11 May 2017 09:42:00 +0300 Subject: [PATCH] Store parsed requirement version in PyRequirementVersionSpec. --- .../python/packaging/PyRequirement.java | 36 +++-- .../requirement/PyRequirementVersion.kt | 40 ++++++ .../PyRequirementVersionNormalizer.java | 127 +++++++++-------- .../requirement/PyRequirementVersionSpec.java | 31 ++++- .../python/packaging/PyRequirementTest.java | 129 +++++++++++------- 5 files changed, 234 insertions(+), 129 deletions(-) create mode 100644 python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersion.kt diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyRequirement.java b/python/openapi/src/com/jetbrains/python/packaging/PyRequirement.java index 1d027e8ce64e..d5fe8108508a 100644 --- a/python/openapi/src/com/jetbrains/python/packaging/PyRequirement.java +++ b/python/openapi/src/com/jetbrains/python/packaging/PyRequirement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,10 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.python.packaging.requirement.PyRequirementRelation; +import com.jetbrains.python.packaging.requirement.PyRequirementVersion; import com.jetbrains.python.packaging.requirement.PyRequirementVersionNormalizer; import com.jetbrains.python.packaging.requirement.PyRequirementVersionSpec; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -271,7 +273,7 @@ public class PyRequirement { if (o == this) return true; if (o == null || getClass() != o.getClass()) return false; - PyRequirement that = (PyRequirement)o; + final PyRequirement that = (PyRequirement)o; if (!myName.equals(that.myName)) return false; if (!myVersionSpecs.equals(that.myVersionSpecs)) return false; @@ -334,10 +336,12 @@ public class PyRequirement { @NotNull public static PyRequirementVersionSpec calculateVersionSpec(@NotNull String version, @NotNull PyRequirementRelation expectedRelation) { - final String normalizedVersion = PyRequirementVersionNormalizer.normalize(version); + if (expectedRelation == PyRequirementRelation.STR_EQ) return new PyRequirementVersionSpec(version); + + final PyRequirementVersion normalizedVersion = PyRequirementVersionNormalizer.normalize(version); return normalizedVersion == null ? - new PyRequirementVersionSpec(PyRequirementRelation.STR_EQ, version) : + new PyRequirementVersionSpec(version) : new PyRequirementVersionSpec(expectedRelation, normalizedVersion); } @@ -412,14 +416,12 @@ public class PyRequirement { visitedFiles.add(containingFile); } - return splitByLinesAndCollapse(text) - .stream() - .map(line -> parseLine(line, containingFile, visitedFiles)) - .flatMap(Collection::stream) - .filter(req -> req != null) - .collect(Collectors.toCollection(LinkedHashSet::new)) - .stream() - .collect(Collectors.toList()); + return StreamEx + .of(splitByLinesAndCollapse(text)) + .flatCollection(line -> parseLine(line, containingFile, visitedFiles)) + .nonNull() + .distinct() + .toList(); } @NotNull @@ -477,7 +479,7 @@ public class PyRequirement { return new PyRequirement(name, Collections.singletonList(calculateVersionSpec(version, PyRequirementRelation.EQ)), installOptions); } - @Nullable + @NotNull private static PyRequirement createVcsRequirement(@NotNull Matcher matcher) { final String path = matcher.group(PATH_IN_VCS_GROUP); final String egg = getEgg(matcher); @@ -675,13 +677,7 @@ public class PyRequirement { if (relation != null) { final int versionIndex = findFirstNotWhiteSpaceAfter(versionSpec, relation.toString().length()); - final String version = versionSpec.substring(versionIndex); - - if (relation == PyRequirementRelation.STR_EQ) { - return new PyRequirementVersionSpec(relation, version); - } - - return calculateVersionSpec(version, relation); + return calculateVersionSpec(versionSpec.substring(versionIndex), relation); } return null; diff --git a/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersion.kt b/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersion.kt new file mode 100644 index 000000000000..25ebe19da241 --- /dev/null +++ b/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersion.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.packaging.requirement + +data class PyRequirementVersion(val epoch: String? = null, + val release: String, + val pre: String? = null, + val post: String? = null, + val dev: String? = null, + val local: String? = null) { + + companion object { + @JvmStatic + fun release(release: String): PyRequirementVersion = PyRequirementVersion(release = release) + } + + val presentableText: String + get() = + sequenceOf(epochPresentable(), release, pre, postPresentable(), devPresentable(), localPresentable()) + .filterNotNull() + .joinToString(separator = "") { it } + + private fun epochPresentable() = if (epoch == null) null else "$epoch!" + private fun postPresentable() = if (post == null) null else ".$post" + private fun devPresentable() = if (dev == null) null else ".$dev" + private fun localPresentable() = if (local == null) null else "+$local" +} \ No newline at end of file diff --git a/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionNormalizer.java b/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionNormalizer.java index a94b930f9050..9856e394ed4f 100644 --- a/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionNormalizer.java +++ b/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionNormalizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package com.jetbrains.python.packaging.requirement; import com.intellij.openapi.util.text.StringUtil; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -103,71 +104,88 @@ public final class PyRequirementVersionNormalizer { Pattern.CASE_INSENSITIVE); @Nullable - public static String normalize(@NotNull String version) { + public static PyRequirementVersion normalize(@NotNull String version) { final Matcher matcher = VERSION.matcher(version); if (matcher.matches()) { - final StringBuilder sb = new StringBuilder(); + return new PyRequirementVersion( + normalizeEpoch(matcher), + normalizeRelease(matcher), + normalizePre(matcher), + normalizePost(matcher), + normalizeDev(matcher), + normalizeLocal(matcher) + ); + } - final String epoch = matcher.group(EPOCH_GROUP); - if (epoch != null) { - final String normalizedEpoch = normalizeNumber(epoch.substring(0, epoch.length() - 1)); - sb - .append(normalizedEpoch) - .append('!'); - } + return null; + } - for (String releasePart : StringUtil.tokenize(matcher.group(RELEASE_GROUP), ".")) { - sb - .append(releasePart.equals("*") ? "*" : normalizeNumber(releasePart)) - .append('.'); - } + @Nullable + private static String normalizeEpoch(@NotNull Matcher matcher) { + final String epoch = matcher.group(EPOCH_GROUP); + if (epoch != null) { + return normalizeNumber(epoch.substring(0, epoch.length() - 1)); + } - if (sb.charAt(sb.length() - 1) == '.') { - sb.setLength(sb.length() - 1); - } + return null; + } - final String preReleaseType = matcher.group(PRE_RELEASE_TYPE_GROUP); - if (preReleaseType != null) { - final String preReleaseNumber = matcher.group(PRE_RELEASE_NUMBER_GROUP); - final String normalizedPreReleaseNumber = preReleaseNumber == null ? "0" : normalizeNumber(preReleaseNumber); + @NotNull + private static String normalizeRelease(@NotNull Matcher matcher) { + return StreamEx + .of(StringUtil.tokenize(matcher.group(RELEASE_GROUP), ".").iterator()) + .map(releasePart -> releasePart.equals("*") ? "*" : normalizeNumber(releasePart)) + .joining("."); + } - sb - .append(normalizePreReleaseType(preReleaseType)) - .append(normalizedPreReleaseNumber); - } + @Nullable + private static String normalizePre(@NotNull Matcher matcher) { + final String preReleaseType = matcher.group(PRE_RELEASE_TYPE_GROUP); + if (preReleaseType != null) { + final String preReleaseNumber = matcher.group(PRE_RELEASE_NUMBER_GROUP); + final String normalizedPreReleaseNumber = preReleaseNumber == null ? "0" : normalizeNumber(preReleaseNumber); - final String postReleaseType = matcher.group(POST_RELEASE_TYPE_GROUP); - if (postReleaseType != null) { - final String postReleaseNumber = matcher.group(POST_RELEASE_NUMBER_GROUP); - final String normalizedPostReleaseNumber = postReleaseNumber == null ? "0" : normalizeNumber(postReleaseNumber); + return normalizePreReleaseType(preReleaseType) + normalizedPreReleaseNumber; + } - sb - .append(".post") - .append(normalizeNumber(normalizedPostReleaseNumber)); - } + return null; + } - final String implicitPostReleaseNumber = matcher.group(IMPLICIT_POST_RELEASE_NUMBER_GROUP); - if (implicitPostReleaseNumber != null) { - sb - .append(".post") - .append(normalizeNumber(implicitPostReleaseNumber)); - } + @Nullable + private static String normalizePost(@NotNull Matcher matcher) { + final String postReleaseType = matcher.group(POST_RELEASE_TYPE_GROUP); + if (postReleaseType != null) { + final String postReleaseNumber = matcher.group(POST_RELEASE_NUMBER_GROUP); + final String normalizedPostReleaseNumber = postReleaseNumber == null ? "0" : normalizeNumber(postReleaseNumber); - if (matcher.group(DEV_RELEASE_TYPE_GROUP) != null) { - final String devReleaseNumber = matcher.group(DEV_RELEASE_NUMBER_GROUP); - final String normalizedDevReleaseNumber = devReleaseNumber == null ? "0" : normalizeNumber(devReleaseNumber); + return "post" + normalizeNumber(normalizedPostReleaseNumber); + } - sb - .append(".dev") - .append(normalizedDevReleaseNumber); - } + final String implicitPostReleaseNumber = matcher.group(IMPLICIT_POST_RELEASE_NUMBER_GROUP); + if (implicitPostReleaseNumber != null) { + return "post" + normalizeNumber(implicitPostReleaseNumber); + } - final String localVersion = matcher.group(LOCAL_VERSION_GROUP); - if (localVersion != null) { - sb.append(normalizeLocalVersion(localVersion)); - } + return null; + } - return sb.toString(); + @Nullable + private static String normalizeDev(@NotNull Matcher matcher) { + if (matcher.group(DEV_RELEASE_TYPE_GROUP) != null) { + final String devReleaseNumber = matcher.group(DEV_RELEASE_NUMBER_GROUP); + final String normalizedDevReleaseNumber = devReleaseNumber == null ? "0" : normalizeNumber(devReleaseNumber); + + return "dev" + normalizedDevReleaseNumber; + } + + return null; + } + + @Nullable + private static String normalizeLocal(@NotNull Matcher matcher) { + final String localVersion = matcher.group(LOCAL_VERSION_GROUP); + if (localVersion != null) { + return localVersion.substring(1).replaceAll("[-_]", "."); } return null; @@ -190,9 +208,4 @@ public final class PyRequirementVersionNormalizer { return "rc"; } } - - @NotNull - private static String normalizeLocalVersion(@NotNull String localVersion) { - return localVersion.replaceAll("[-_]", "."); - } } diff --git a/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionSpec.java b/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionSpec.java index 8dadd784a895..1d51b6bf3cbd 100644 --- a/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionSpec.java +++ b/python/openapi/src/com/jetbrains/python/packaging/requirement/PyRequirementVersionSpec.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,11 @@ package com.jetbrains.python.packaging.requirement; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; import static com.intellij.webcore.packaging.PackageVersionComparator.VERSION_COMPARATOR; @@ -25,11 +29,21 @@ public class PyRequirementVersionSpec { @NotNull private final PyRequirementRelation myRelation; + @Nullable + private final PyRequirementVersion myParsedVersion; + @NotNull private final String myVersion; - public PyRequirementVersionSpec(@NotNull PyRequirementRelation relation, @NotNull String version) { + public PyRequirementVersionSpec(@NotNull PyRequirementRelation relation, @NotNull PyRequirementVersion version) { myRelation = relation; + myParsedVersion = version; + myVersion = myParsedVersion.getPresentableText(); + } + + public PyRequirementVersionSpec(@NotNull String version) { + myRelation = PyRequirementRelation.STR_EQ; + myParsedVersion = null; myVersion = version; } @@ -73,7 +87,9 @@ public class PyRequirementVersionSpec { case GTE: return VERSION_COMPARATOR.compare(version, myVersion) >= 0; case EQ: - final Pair publicAndLocalVersions = splitIntoPublicAndLocalVersions(myVersion); + Objects.requireNonNull(myParsedVersion); + + final Pair publicAndLocalVersions = splitIntoPublicAndLocalVersions(myParsedVersion); final Pair otherPublicAndLocalVersions = splitIntoPublicAndLocalVersions(version); final boolean publicVersionsAreSame = VERSION_COMPARATOR.compare(otherPublicAndLocalVersions.first, publicAndLocalVersions.first) == 0; @@ -91,6 +107,15 @@ public class PyRequirementVersionSpec { } } + @NotNull + private static Pair splitIntoPublicAndLocalVersions(@NotNull PyRequirementVersion version) { + final PyRequirementVersion withoutLocal = + new PyRequirementVersion(version.getEpoch(), version.getRelease(), version.getPre(), version.getPost(), version.getDev(), null); + + return Pair.createNonNull(withoutLocal.getPresentableText(), StringUtil.notNullize(version.getLocal())); + } + + @NotNull private static Pair splitIntoPublicAndLocalVersions(@NotNull String version) { final String[] publicAndLocalVersions = version.split("\\+", 2); diff --git a/python/testSrc/com/jetbrains/python/packaging/PyRequirementTest.java b/python/testSrc/com/jetbrains/python/packaging/PyRequirementTest.java index b988d523da0f..024e31c477c7 100644 --- a/python/testSrc/com/jetbrains/python/packaging/PyRequirementTest.java +++ b/python/testSrc/com/jetbrains/python/packaging/PyRequirementTest.java @@ -21,6 +21,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.packaging.requirement.PyRequirementRelation; +import com.jetbrains.python.packaging.requirement.PyRequirementVersion; import com.jetbrains.python.packaging.requirement.PyRequirementVersionSpec; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -2093,34 +2094,47 @@ public class PyRequirementTest extends PyTestCase { final String name = "django_compressor"; final String version = "dev"; final String line = name + "==" + version; - final List versionSpecs = Collections.singletonList(new PyRequirementVersionSpec(PyRequirementRelation.STR_EQ, - version)); + final List versionSpecs = Collections.singletonList(new PyRequirementVersionSpec(version)); assertEquals(new PyRequirement(name, versionSpecs, Collections.singletonList(line)), PyRequirement.fromLine(line)); } // https://www.python.org/dev/peps/pep-0440/#version-specifiers public void testRequirementRelation() { - doRequirementRelationTest(PyRequirementRelation.LT, "1.4"); - doRequirementRelationTest(PyRequirementRelation.LTE, "1.4"); - doRequirementRelationTest(PyRequirementRelation.NE, "1.4"); - doRequirementRelationTest(PyRequirementRelation.EQ, "1.4"); - doRequirementRelationTest(PyRequirementRelation.GT, "1.4"); - doRequirementRelationTest(PyRequirementRelation.GTE, "1.4"); - doRequirementRelationTest(PyRequirementRelation.COMPATIBLE, "1.*"); - doRequirementRelationTest(PyRequirementRelation.STR_EQ, "version"); + doRequirementRelationTest(PyRequirementRelation.LT, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(PyRequirementRelation.LTE, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(PyRequirementRelation.NE, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(PyRequirementRelation.EQ, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(PyRequirementRelation.GT, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(PyRequirementRelation.GTE, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(PyRequirementRelation.COMPATIBLE, PyRequirementVersion.release("1.*")); + doRequirementRelationTest(PyRequirementRelation.STR_EQ, PyRequirementVersion.release("version")); - doRequirementRelationTest(Arrays.asList(PyRequirementRelation.GTE, PyRequirementRelation.EQ), Arrays.asList("2.8.1", "2.8.*")); - doRequirementRelationTest(Arrays.asList(PyRequirementRelation.LT, PyRequirementRelation.GTE), Arrays.asList("1.4", "1.3.1")); + doRequirementRelationTest(Arrays.asList(PyRequirementRelation.GTE, PyRequirementRelation.EQ), + Arrays.asList(PyRequirementVersion.release("2.8.1"), PyRequirementVersion.release("2.8.*"))); + doRequirementRelationTest(Arrays.asList(PyRequirementRelation.LT, PyRequirementRelation.GTE), + Arrays.asList(PyRequirementVersion.release("1.4"), PyRequirementVersion.release("1.3.1"))); - doRequirementRelationTest(Arrays.asList(PyRequirementRelation.LT, PyRequirementRelation.GT, PyRequirementRelation.NE, - PyRequirementRelation.LT, PyRequirementRelation.EQ), - Arrays.asList("1.6", "1.9", "1.9.6", "2.0a0", "2.4rc1")); + doRequirementRelationTest(Arrays.asList(PyRequirementRelation.LT, + PyRequirementRelation.GT, + PyRequirementRelation.NE, + PyRequirementRelation.LT, + PyRequirementRelation.EQ), + Arrays.asList(PyRequirementVersion.release("1.6"), + PyRequirementVersion.release("1.9"), + PyRequirementVersion.release("1.9.6"), + new PyRequirementVersion(null, "2.0", "a0", null, null, null), + new PyRequirementVersion(null, "2.4", "rc1", null, null, null))); // PY-14583 - doRequirementRelationTest(Arrays.asList(PyRequirementRelation.GTE, PyRequirementRelation.LTE, PyRequirementRelation.GTE, + doRequirementRelationTest(Arrays.asList(PyRequirementRelation.GTE, + PyRequirementRelation.LTE, + PyRequirementRelation.GTE, PyRequirementRelation.LTE), - Arrays.asList("0.8.4", "0.8.99", "0.9.7", "0.9.99")); + Arrays.asList(PyRequirementVersion.release("0.8.4"), + PyRequirementVersion.release("0.8.99"), + PyRequirementVersion.release("0.9.7"), + PyRequirementVersion.release("0.9.99"))); } // https://www.python.org/dev/peps/pep-0508/#extras @@ -2128,7 +2142,7 @@ public class PyRequirementTest extends PyTestCase { public void testRequirementExtras() { final String name = "MyProject1"; final List relations = Collections.emptyList(); - final List versions = Collections.emptyList(); + final List versions = Collections.emptyList(); doRequirementRelationTest(name, "[PDF]", relations, versions); doRequirementRelationTest(name, " [extra1, extra2]", relations, versions); @@ -2147,29 +2161,49 @@ public class PyRequirementTest extends PyTestCase { final String extras3 = " [security,tests]"; final String name3 = "requests"; - doRequirementRelationTest(name1, extras1, PyRequirementRelation.LT, "1.4"); - doRequirementRelationTest(name2, extras2, PyRequirementRelation.LTE, "1.4"); - doRequirementRelationTest(name3, extras3, PyRequirementRelation.NE, "1.4"); - doRequirementRelationTest(name1, extras1, PyRequirementRelation.EQ, "1.4"); - doRequirementRelationTest(name2, extras2, PyRequirementRelation.GT, "1.4"); - doRequirementRelationTest(name3, extras3, PyRequirementRelation.GTE, "1.4"); - doRequirementRelationTest(name1, extras1, PyRequirementRelation.COMPATIBLE, "1.*"); - doRequirementRelationTest(name2, extras2, PyRequirementRelation.STR_EQ, "version"); + doRequirementRelationTest(name1, extras1, PyRequirementRelation.LT, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(name2, extras2, PyRequirementRelation.LTE, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(name3, extras3, PyRequirementRelation.NE, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(name1, extras1, PyRequirementRelation.EQ, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(name2, extras2, PyRequirementRelation.GT, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(name3, extras3, PyRequirementRelation.GTE, PyRequirementVersion.release("1.4")); + doRequirementRelationTest(name1, extras1, PyRequirementRelation.COMPATIBLE, PyRequirementVersion.release("1.*")); + doRequirementRelationTest(name2, extras2, PyRequirementRelation.STR_EQ, PyRequirementVersion.release("version")); - doRequirementRelationTest(name3, extras3, Arrays.asList(PyRequirementRelation.GTE, PyRequirementRelation.EQ), - Arrays.asList("2.8.1", "2.8.*")); + doRequirementRelationTest(name3, + extras3, + Arrays.asList(PyRequirementRelation.GTE, PyRequirementRelation.EQ), + Arrays.asList(PyRequirementVersion.release("2.8.1"), PyRequirementVersion.release("2.8.*"))); - doRequirementRelationTest(name1, extras1, Arrays.asList(PyRequirementRelation.LT, PyRequirementRelation.GTE), - Arrays.asList("1.4", "1.3.1")); + doRequirementRelationTest(name1, + extras1, + Arrays.asList(PyRequirementRelation.LT, PyRequirementRelation.GTE), + Arrays.asList(PyRequirementVersion.release("1.4"), PyRequirementVersion.release("1.3.1"))); - doRequirementRelationTest(name2, extras2, Arrays.asList(PyRequirementRelation.LT, PyRequirementRelation.GT, PyRequirementRelation.NE, - PyRequirementRelation.LT, PyRequirementRelation.EQ), - Arrays.asList("1.6", "1.9", "1.9.6", "2.0a0", "2.4rc1")); + doRequirementRelationTest(name2, + extras2, + Arrays.asList(PyRequirementRelation.LT, + PyRequirementRelation.GT, + PyRequirementRelation.NE, + PyRequirementRelation.LT, + PyRequirementRelation.EQ), + Arrays.asList(PyRequirementVersion.release("1.6"), + PyRequirementVersion.release("1.9"), + PyRequirementVersion.release("1.9.6"), + new PyRequirementVersion(null, "2.0", "a0", null, null, null), + new PyRequirementVersion(null, "2.4", "rc1", null, null, null))); // PY-14583 - doRequirementRelationTest(name3, extras3, Arrays.asList(PyRequirementRelation.GTE, PyRequirementRelation.LTE, PyRequirementRelation.GTE, - PyRequirementRelation.LTE), - Arrays.asList("0.8.4", "0.8.99", "0.9.7", "0.9.99")); + doRequirementRelationTest(name3, + extras3, + Arrays.asList(PyRequirementRelation.GTE, + PyRequirementRelation.LTE, + PyRequirementRelation.GTE, + PyRequirementRelation.LTE), + Arrays.asList(PyRequirementVersion.release("0.8.4"), + PyRequirementVersion.release("0.8.99"), + PyRequirementVersion.release("0.9.7"), + PyRequirementVersion.release("0.9.99"))); } // https://pip.pypa.io/en/stable/reference/pip_install/#per-requirement-overrides @@ -2179,7 +2213,7 @@ public class PyRequirementTest extends PyTestCase { final String linePrefix = name + " >= " + version; final List versionSpecs = - Collections.singletonList(new PyRequirementVersionSpec(PyRequirementRelation.GTE, version)); + Collections.singletonList(new PyRequirementVersionSpec(PyRequirementRelation.GTE, PyRequirementVersion.release(version))); final List installOptions1 = Arrays.asList(linePrefix, "--global-option", "--no-user-cfg", @@ -2202,7 +2236,7 @@ public class PyRequirementTest extends PyTestCase { final String textPrefix = name + " >= " + version; final List versionSpecs = - Collections.singletonList(new PyRequirementVersionSpec(PyRequirementRelation.GTE, version)); + Collections.singletonList(new PyRequirementVersionSpec(PyRequirementRelation.GTE, PyRequirementVersion.release(version))); final String text = textPrefix + " " + "--global-option=\"--no-user-cfg\" \\\n" + @@ -2383,44 +2417,41 @@ public class PyRequirementTest extends PyTestCase { doTest(name, version, line.substring(0, line.lastIndexOf('#') - 1)); } - private static void doRequirementRelationTest(@NotNull PyRequirementRelation relation, @NotNull String version) { + private static void doRequirementRelationTest(@NotNull PyRequirementRelation relation, @NotNull PyRequirementVersion version) { doRequirementRelationTest("Django", null, Collections.singletonList(relation), Collections.singletonList(version)); } - private static void doRequirementRelationTest(@NotNull List relations, @NotNull List versions) { + private static void doRequirementRelationTest(@NotNull List relations, + @NotNull List versions) { doRequirementRelationTest("Django", null, relations, versions); } private static void doRequirementRelationTest(@NotNull String name, @Nullable String extras, @NotNull PyRequirementRelation relation, - @NotNull String version) { + @NotNull PyRequirementVersion version) { doRequirementRelationTest(name, extras, Collections.singletonList(relation), Collections.singletonList(version)); } private static void doRequirementRelationTest(@NotNull String name, @Nullable String extras, @NotNull List relations, - @NotNull List versions) { + @NotNull List versions) { assertEquals(versions.size(), relations.size()); final StringBuilder sb = new StringBuilder(name); final List expectedVersionSpecs = new ArrayList<>(); if (extras != null) sb.append(extras); - final int initialLength = sb.length(); - for (Pair pair : ContainerUtil.zip(relations, versions)) { + for (Pair pair : ContainerUtil.zip(relations, versions)) { final PyRequirementRelation relation = pair.getFirst(); - final String version = pair.getSecond(); + final PyRequirementVersion version = pair.getSecond(); - sb.append(relation).append(version).append(","); expectedVersionSpecs.add(new PyRequirementVersionSpec(relation, version)); } - if (sb.length() != initialLength) { - sb.setLength(sb.length() - 1); - } + sb.append(StringUtil.join(expectedVersionSpecs, ",")); final String options = sb.toString();