From b90ac4d56d14f8beac99d89e682c8208e8e9720a Mon Sep 17 00:00:00 2001 From: stepan Date: Fri, 28 Nov 2025 22:27:21 +0100 Subject: [PATCH] Deprecate python-community artifact --- DEVELOPMENT.md | 5 ++-- .../maven/plugin/AbstractGraalPyMojo.java | 28 +++++++++++++++---- integration-tests/test_gradle_plugin.py | 19 +++++++++++++ integration-tests/test_maven_plugin.py | 26 +++++++++++++++-- .../graalvm/python/GraalPyGradlePlugin.java | 14 ++++++++-- 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b313ad4..a96d3f8 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -68,7 +68,8 @@ mvn -pl org.graalvm.python.gradle.plugin -am clean tl;dr: ``` -mvn install exec:java@integration-tests -Dintegration.test.args="test_maven_plugin.py" -Dgradle.java.home=... +mvn install exec:java@integration-tests # to view the help +mvn install exec:java@integration-tests -Dintegration.tests.args="test_maven_plugin.py" -Dgradle.java.home=... ``` The integration tests are driven by Python and implemented using unittest framework, which is @@ -78,7 +79,7 @@ published in Mavencentral or some snapshot repository configured in Maven settin The whole execution of the tests is wrapped in Maven goal `exec:java@integration-tests`, which passes some necessary arguments to the test driver Python script. One can pass additional arguments for the -unittest framework using system property `integration.test.args`, for example, tests to execute or +unittest framework using system property `integration.tests.args`, for example, tests to execute or verbosity level. diff --git a/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/AbstractGraalPyMojo.java b/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/AbstractGraalPyMojo.java index b02bf04..423e469 100644 --- a/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/AbstractGraalPyMojo.java +++ b/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/AbstractGraalPyMojo.java @@ -293,16 +293,25 @@ protected static String getGraalPyVersion(MavenProject project) throws IOExcepti private static Artifact getGraalPyArtifact(MavenProject project) throws IOException { var projectArtifacts = resolveProjectDependencies(project); - Artifact graalPyArtifact = projectArtifacts.stream().filter(a -> isPythonArtifact(a)).findFirst().orElse(null); + Artifact graalPyArtifact = projectArtifacts.stream().filter(AbstractGraalPyMojo::isPythonArtifact) + .findFirst() + .orElse(null); return Optional.ofNullable(graalPyArtifact).orElseThrow(() -> new IOException( "Missing GraalPy dependency. Please add to your pom either %s:%s or %s:%s".formatted(POLYGLOT_GROUP_ID, - PYTHON_COMMUNITY_ARTIFACT_ID, POLYGLOT_GROUP_ID, PYTHON_ARTIFACT_ID))); + PYTHON_ARTIFACT_ID, GRAALPY_GROUP_ID, PYTHON_ARTIFACT_ID))); } private static boolean isPythonArtifact(Artifact a) { - return (POLYGLOT_GROUP_ID.equals(a.getGroupId()) || GRAALPY_GROUP_ID.equals(a.getGroupId())) - && (PYTHON_COMMUNITY_ARTIFACT_ID.equals(a.getArtifactId()) - || PYTHON_ARTIFACT_ID.equals(a.getArtifactId())); + return isPythonOrPolyglotGroup(a) && (PYTHON_COMMUNITY_ARTIFACT_ID.equals(a.getArtifactId()) + || PYTHON_ARTIFACT_ID.equals(a.getArtifactId())); + } + + private static boolean isPythonCommunityArtifact(Artifact a) { + return isPythonOrPolyglotGroup(a) && (PYTHON_COMMUNITY_ARTIFACT_ID.equals(a.getArtifactId())); + } + + private static boolean isPythonOrPolyglotGroup(Artifact a) { + return POLYGLOT_GROUP_ID.equals(a.getGroupId()) || GRAALPY_GROUP_ID.equals(a.getGroupId()); } private static Collection resolveProjectDependencies(MavenProject project) { @@ -330,6 +339,15 @@ private Set calculateLauncherClasspath(MavenProject project) throws IOEx // and transitively all its dependencies launcherClassPath.addAll(resolveDependencies(graalPyLauncherArtifact)); + // check for deprecated python-community + var projectArtifacts = resolveProjectDependencies(project); + Optional community = projectArtifacts.stream().filter(AbstractGraalPyMojo::isPythonCommunityArtifact).findFirst(); + if (community.isPresent()) { + getLog().warn("Deprecated artifact detected on classpath: " + community.get().getGroupId() + ":" + + community.get().getArtifactId() + ". Please use '" + POLYGLOT_GROUP_ID + ":" + + PYTHON_ARTIFACT_ID + "' instead."); + } + // 2.) graalpy dependencies Artifact graalPyArtifact = getGraalPyArtifact(project); assert graalPyArtifact != null; diff --git a/integration-tests/test_gradle_plugin.py b/integration-tests/test_gradle_plugin.py index 3d9a5ce..6f852f1 100644 --- a/integration-tests/test_gradle_plugin.py +++ b/integration-tests/test_gradle_plugin.py @@ -49,6 +49,7 @@ MISSING_FILE_WARNING = "The list of installed Python packages does not match the packages specified in the graalpy-maven-plugin configuration" PACKAGES_CHANGED_ERROR = "packages and their version constraints in graalpy-gradle-plugin configuration are different then previously used to generate the lock file" VENV_UPTODATE = "Virtual environment is up to date with lock file, skipping install" +DEPRECATION_MSG = "python-community' is deprecated" def append(file, txt): with open(file, "a") as f: @@ -156,6 +157,7 @@ def check_gradle_generated_app(self): util.check_ouput("BUILD SUCCESS", out, logger=log) util.check_ouput("Virtual filesystem is deployed to default resources directory", out, logger=log) util.check_ouput("This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem", out, logger=log) + util.check_ouput(DEPRECATION_MSG, out, contains=False, logger=log) self.check_filelist(target_dir, log) gradlew_cmd = util.get_gradle_wrapper(target_dir, self.env) @@ -224,6 +226,7 @@ def check_lock_packages(self): out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir, logger=log) util.check_ouput("pip install", out, logger=log) util.check_ouput("BUILD SUCCESS", out, logger=log) + util.check_ouput(DEPRECATION_MSG, out, contains=False, logger=log) util.check_ouput(MISSING_FILE_WARNING, out, contains=True, logger=log) assert not os.path.exists(os.path.join(target_dir, "test-graalpy.lock")), log @@ -641,6 +644,22 @@ def test_gradle_python_resources_dir_and_external_dir_error(self): def test_proxy_settings(self): self.check_proxy_settings() + def test_gradle_community_deprecation(self): + with TemporaryTestDirectory() as tmpdir: + target_dir = os.path.join(str(tmpdir), "community_deprecation_gradle" + self.target_dir_name_sufix()) + self.generate_app(target_dir) + build_file = os.path.join(target_dir, self.build_file_name) + append(build_file, textwrap.dedent(""" + graalPy { + community = true + packages = ["termcolor"] + } + """)) + gradlew_cmd = util.get_gradle_wrapper(target_dir, self.env) + cmd = gradlew_cmd + ["graalPyInstallPackages"] + out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) + util.check_ouput(DEPRECATION_MSG, out, contains=True) + def target_dir_name_sufix(self): return "_groovy" diff --git a/integration-tests/test_maven_plugin.py b/integration-tests/test_maven_plugin.py index 9b191e1..22a9b4c 100644 --- a/integration-tests/test_maven_plugin.py +++ b/integration-tests/test_maven_plugin.py @@ -51,6 +51,7 @@ MISSING_FILE_WARNING = "The list of installed Python packages does not match the packages specified in the graalpy-maven-plugin configuration." PACKAGES_CHANGED_ERROR = "but packages and their version constraints in graalpy-maven-plugin configuration are different then previously used to generate the lock file" VENV_UPTODATE = "Virtual environment is up to date with lock file, skipping install" +DEPRECATION_MSG = "Deprecated artifact detected on classpath" class MavenPluginTest(util.BuildToolTestBase): @classmethod @@ -134,8 +135,9 @@ def setUpClass(cls): if util.extra_maven_repos and not found and not cls.extraRemoteRepo: print("WARNING: extra Maven repos passed, but could not find GraalPy Maven archetype " "in any of the local repos and there is no extra remote repo. This is OK only if " - "GraalPy Maven archetype of the required version is available at Mavencentral, " - "otherwise the tests will fail to generate the example application.") + "GraalPy Maven archetype of the required version is available at Mavencentral or " + "it is installed in local repo, otherwise the tests will fail to generate the " + "example application.") def generate_app(self, tmpdir, target_dir, target_name, pom_template=None, group_id="archetype.it", package="it.pkg", log=Logger()): extra_repo = [] @@ -204,6 +206,7 @@ def check_generated_app(self, use_default_vfs_path): util.check_ouput("BUILD SUCCESS", out, logger=log) util.check_ouput("Virtual filesystem is deployed to default resources directory", out, contains=use_default_vfs_path, logger=log) util.check_ouput("This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem.", out, contains=use_default_vfs_path, logger=log) + util.check_ouput(DEPRECATION_MSG, out, contains=False, logger=log) # check fileslist.txt fl_path = os.path.join(target_dir, "target", "classes", vfs_prefix, "fileslist.txt") @@ -310,6 +313,7 @@ def test_lock_file(self): out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) util.check_ouput("pip install", out) util.check_ouput("BUILD SUCCESS", out) + util.check_ouput(DEPRECATION_MSG, out, contains=False) util.check_ouput(MISSING_FILE_WARNING, out, contains=True) assert not os.path.exists(os.path.join(target_dir, "test-graalpy.lock")) @@ -411,6 +415,7 @@ def test_generated_app_external_resources(self): cmd = mvnw_cmd + ["package"] + native_image_arg + ["-DmainClass=it.pkg.GraalPy"] out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) util.check_ouput("BUILD SUCCESS", out) + util.check_ouput(DEPRECATION_MSG, out, contains=False) # execute and check JVM mode cmd = mvnw_cmd + ["exec:java", "-Dexec.mainClass=it.pkg.GraalPy"] @@ -448,7 +453,7 @@ def test_fail_without_graalpy_dep(self): cmd = mvnw_cmd + ["process-resources"] out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) - util.check_ouput("Missing GraalPy dependency. Please add to your pom either org.graalvm.polyglot:python-community or org.graalvm.polyglot:python", out) + util.check_ouput("Missing GraalPy dependency. Please add to your pom org.graalvm.polyglot:python", out) def test_check_home_warning(self): @@ -835,6 +840,21 @@ def test_multiple_namespaced_vfs(self): assert return_code == 0, log + def test_community_dep_deprecation_message(self): + with util.TemporaryTestDirectory() as tmpdir: + target_name = "community_dep_deprecation_test" + target_dir = os.path.join(str(tmpdir), target_name) + self.generate_app(tmpdir, target_dir, target_name) + + mvnw_cmd = util.get_mvn_wrapper(target_dir, self.env) + pom_path = os.path.join(target_dir, "pom.xml") + + util.replace_in_file(pom_path, "python", "python-community") + + cmd = mvnw_cmd + ["process-resources"] + out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) + util.check_ouput(DEPRECATION_MSG, out, contains=True) + if __name__ == "__main__": run_path = os.path.join(os.path.abspath(__file__), 'run.py') print(f"Run this file using the run.py driver ({run_path})") diff --git a/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java b/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java index 749a2a0..bd3ff5b 100644 --- a/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java +++ b/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java @@ -133,6 +133,11 @@ public void apply(Project project) { "WARNING: Property 'polyglotVersion' is experimental and should be used only for testing pre-release versions."); } + if (extension.getCommunity().convention(false).get()) { + proj.getLogger().warn( + "WARNING: 'python-community' is deprecated. The plugin defaults to 'python'. Support for 'python-community' may be removed in a future release."); + } + if (extension.getPythonResourcesDirectory().isPresent() && extension.getExternalDirectory().isPresent()) { throw new GradleException( "Cannot set both 'externalDirectory' and 'resourceDirectory' at the same time. " @@ -332,10 +337,13 @@ private static void makeSureBothEditionsAreNotOnClasspathSimultaneously(Configur } if (hasCommunityEdition && hasOracleEdition) { throw new GradleException( - "You have both 'org.graalvm.python:python' and 'org.graalvm.python:python-community' on the classpath. " - + "This is likely due to an explicit dependency added, or duplicate dependencies. You may configure " - + "the GraalPy plugin to inject the 'python-community' artifact by using the graalPy { community = true } " + "You have both 'org.graalvm.python:python' (or 'org.graalvm.polyglot:python') and 'org.graalvm.python:python-community' (or 'org.graalvm.polyglot:python-community') on the classpath. " + + "The 'python-community' artifact is deprecated. Ensure only one edition is present. You may configure " + + "the GraalPy plugin to inject the deprecated 'python-community' artifact by using the graalPy { community = true } " + "configuration block instead."); + } else if (hasCommunityEdition && !hasOracleEdition) { + org.gradle.api.logging.Logging.getLogger(GraalPyGradlePlugin.class).warn( + "WARNING: 'python-community' is deprecated. Please depend on 'org.graalvm.python:python' or 'org.graalvm.polyglot:python' instead."); } }); }