PY-79488 Get rid of the "Module" term in the API names

"External Project" is a better name. IJ Module is
an implementation detail. It could easily be another entity.

GitOrigin-RevId: d263f110d2851d11fb411ef93d973e5e05eeff05
This commit is contained in:
Mikhail Golubev
2025-06-11 16:54:32 +00:00
committed by intellij-monorepo-bot
parent f12dd4e8f2
commit 4d3376bd64
4 changed files with 33 additions and 34 deletions
@@ -6,7 +6,6 @@ import com.intellij.openapi.util.NlsSafe
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.ide.progress.withBackgroundProgress
import com.intellij.platform.workspace.jps.entities.*
import com.intellij.platform.workspace.jps.entities.ModuleDependency
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityStorage
import com.intellij.platform.workspace.storage.MutableEntityStorage
@@ -78,7 +77,7 @@ abstract class BaseProjectModelService<E : EntitySource> {
if (graph.isEmpty()) {
return
}
val allModules = graph.flatMap { it.modules }
val allModules = graph.flatMap { it.projects }
val storage = createProjectModel(project, allModules, source)
project.workspaceModel.update("$systemName sync at ${projectRoot}") { mutableStorage ->
// Fake module entity is added by default if nothing was discovered
@@ -95,7 +94,7 @@ abstract class BaseProjectModelService<E : EntitySource> {
private fun createProjectModel(
project: Project,
graph: List<ModuleDescriptor>,
graph: List<ExternalProject>,
source: EntitySource,
): EntityStorage {
val fileUrlManager = project.workspaceModel.getVirtualFileUrlManager()
@@ -112,7 +111,7 @@ abstract class BaseProjectModelService<E : EntitySource> {
storage addEntity ModuleEntity(module.name, emptyList(), source) {
dependencies += sdkDependency
dependencies += ModuleSourceDependency
for (moduleName in module.moduleDependencies) {
for (moduleName in module.dependencies) {
dependencies += ModuleDependency(ModuleId(moduleName.name), true, DependencyScope.COMPILE, false)
}
contentRoots = listOf(ContentRootEntity(module.root.toVirtualFileUrl(fileUrlManager), emptyList(), source))
@@ -1,9 +1,9 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.projectModel.poetry
import com.jetbrains.python.projectModel.ModuleDependency
import com.jetbrains.python.projectModel.ModuleDescriptor
import com.jetbrains.python.projectModel.ProjectModelGraph
import com.jetbrains.python.projectModel.ExternalProject
import com.jetbrains.python.projectModel.ExternalProjectDependency
import com.jetbrains.python.projectModel.ExternalProjectGraph
import com.jetbrains.python.projectModel.PythonProjectModelResolver
import org.apache.tuweni.toml.Toml
import org.apache.tuweni.toml.TomlTable
@@ -12,7 +12,7 @@ import kotlin.io.path.*
@OptIn(ExperimentalPathApi::class)
object PoetryProjectModelResolver : PythonProjectModelResolver {
override fun discoverProjectRootSubgraph(root: Path): ProjectModelGraph? {
override fun discoverProjectRootSubgraph(root: Path): ExternalProjectGraph? {
if (!root.resolve(PoetryConstants.PYPROJECT_TOML).exists()) {
return null
}
@@ -23,16 +23,16 @@ object PoetryProjectModelResolver : PythonProjectModelResolver {
if (poetryProjects.isNotEmpty()) {
val modules = poetryProjects
.map {
ModuleDescriptor(
ExternalProject(
name = it.projectName,
root = it.root,
moduleDependencies = it.editablePathDependencies.map { entry ->
ModuleDependency(entry.key, entry.value)
dependencies = it.editablePathDependencies.map { entry ->
ExternalProjectDependency(entry.key, entry.value)
})
}
return ProjectModelGraph(
return ExternalProjectGraph(
root = root,
modules = modules
projects = modules
)
}
return null
@@ -12,15 +12,15 @@ import kotlin.io.path.visitFileTree
* These modules might depend on each other, but it's not a requirement.
* The root itself can be a valid module root, but it's not a requirement.
*/
data class ProjectModelGraph(val root: Path, val modules: List<ModuleDescriptor>)
data class ExternalProjectGraph(val root: Path, val projects: List<ExternalProject>)
/**
* Defines a project module in a particular directory with its unique name, and a set of module dependencies
* (usually editable Python path dependencies to other modules in the same IJ project).
*/
data class ModuleDescriptor(val name: String, val root: Path, val moduleDependencies: List<ModuleDependency>)
data class ExternalProject(val name: String, val root: Path, val dependencies: List<ExternalProjectDependency>)
data class ModuleDependency(val name: String, val path: Path)
data class ExternalProjectDependency(val name: String, val path: Path)
interface PythonProjectModelResolver {
/**
@@ -41,7 +41,7 @@ interface PythonProjectModelResolver {
* this method should return `null` for `libs/` but module graphs containing *only* modules `project1` and `project2`
* for the directories `project1/` and `project2` respectively, even if there is a dependency between them.
*/
fun discoverProjectRootSubgraph(root: Path): ProjectModelGraph?
fun discoverProjectRootSubgraph(root: Path): ExternalProjectGraph?
/**
* Find all project model graphs within the given directory (presumably the root directory of an IJ project).
@@ -61,8 +61,8 @@ interface PythonProjectModelResolver {
* If these two projects are independents, there will be two graphs for `project1` and `project2` respectively.
*/
@OptIn(ExperimentalPathApi::class)
fun discoverIndependentProjectGraphs(root: Path): List<ProjectModelGraph> {
val graphs = mutableListOf<ProjectModelGraph>()
fun discoverIndependentProjectGraphs(root: Path): List<ExternalProjectGraph> {
val graphs = mutableListOf<ExternalProjectGraph>()
root.visitFileTree {
onPreVisitDirectory { dir, _ ->
val buildSystemRoot = discoverProjectRootSubgraph(dir)
@@ -91,22 +91,22 @@ interface ProjectModelSyncListener {
fun onFinish(projectRoot: Path): Unit = Unit
}
private fun mergeRootsReferringToEachOther(roots: MutableList<ProjectModelGraph>): List<ProjectModelGraph> {
private fun mergeRootsReferringToEachOther(roots: MutableList<ExternalProjectGraph>): List<ExternalProjectGraph> {
fun commonAncestorPath(paths: Iterable<Path>): Path {
val normalized = paths.map { it.normalize() }
return normalized.reduce { p1, p2 -> FileUtil.findAncestor(p1, p2)!! }
}
val expandedProjectRoots = roots.map { root ->
val allModuleRootsAndDependencies = root.modules.asSequence()
.flatMap { module -> listOf(module.root) + module.moduleDependencies.map { it.path } }
val allModuleRootsAndDependencies = root.projects.asSequence()
.flatMap { module -> listOf(module.root) + module.dependencies.map { it.path } }
.distinct()
.toList()
root.copy(root = commonAncestorPath(allModuleRootsAndDependencies))
}
val expandedProjectRootsByRootPath = expandedProjectRoots.sortedBy { it.root }
val mergedProjectRoots = mutableListOf<ProjectModelGraph>()
val mergedProjectRoots = mutableListOf<ExternalProjectGraph>()
for (root in expandedProjectRootsByRootPath) {
if (mergedProjectRoots.isEmpty()) {
mergedProjectRoots.add(root)
@@ -114,7 +114,7 @@ private fun mergeRootsReferringToEachOther(roots: MutableList<ProjectModelGraph>
else {
val lastCluster = mergedProjectRoots.last()
if (root.root.startsWith(lastCluster.root)) {
mergedProjectRoots[mergedProjectRoots.lastIndex] = lastCluster.copy(modules = lastCluster.modules + root.modules)
mergedProjectRoots[mergedProjectRoots.lastIndex] = lastCluster.copy(projects = lastCluster.projects + root.projects)
}
else {
mergedProjectRoots.add(root)
@@ -2,9 +2,9 @@
package com.jetbrains.python.projectModel.uv
import com.intellij.openapi.util.getPathMatcher
import com.jetbrains.python.projectModel.ModuleDependency
import com.jetbrains.python.projectModel.ModuleDescriptor
import com.jetbrains.python.projectModel.ProjectModelGraph
import com.jetbrains.python.projectModel.ExternalProject
import com.jetbrains.python.projectModel.ExternalProjectDependency
import com.jetbrains.python.projectModel.ExternalProjectGraph
import com.jetbrains.python.projectModel.PythonProjectModelResolver
import org.apache.tuweni.toml.Toml
import org.apache.tuweni.toml.TomlTable
@@ -15,7 +15,7 @@ private const val DEFAULT_VENV_DIR = ".venv"
@OptIn(ExperimentalPathApi::class)
object UvProjectModelResolver : PythonProjectModelResolver {
override fun discoverProjectRootSubgraph(root: Path): ProjectModelGraph? {
override fun discoverProjectRootSubgraph(root: Path): ExternalProjectGraph? {
if (!root.resolve(UvConstants.PYPROJECT_TOML).exists()) {
return null
}
@@ -48,20 +48,20 @@ object UvProjectModelResolver : PythonProjectModelResolver {
}.associateBy { it.projectName }
}
return ProjectModelGraph(
return ExternalProjectGraph(
root = root,
modules = allUvProjects
projects = allUvProjects
.map { uvProject ->
val pathDependencies = uvProject.editablePathDependencies.map { ModuleDependency(it.key, it.value) }
val pathDependencies = uvProject.editablePathDependencies.map { ExternalProjectDependency(it.key, it.value) }
val resolvedWorkspaceDependencies = uvProject.workspaceDependencies.mapNotNull {
val workspaceMember = workspaceMembers[it]
if (workspaceMember != null) ModuleDependency(it, workspaceMember.root)
if (workspaceMember != null) ExternalProjectDependency(it, workspaceMember.root)
else null
}
ModuleDescriptor(
ExternalProject(
name = uvProject.projectName,
root =uvProject.root,
moduleDependencies = pathDependencies + resolvedWorkspaceDependencies
dependencies = pathDependencies + resolvedWorkspaceDependencies
)
}
)