Skip to content
This repository has been archived by the owner on Feb 9, 2022. It is now read-only.

Commit

Permalink
Merge pull request #85 from koxudaxi/add_version_inspection
Browse files Browse the repository at this point in the history
[WIP] add a version inspection
  • Loading branch information
koxudaxi authored Aug 10, 2020
2 parents c597cdf + c5d87f9 commit 21fffd8
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ You can install the stable version on PyCharm's `Marketplace` (Preference -> Plu
- update and lock with a popup
- show a message and a link to fix settings (QuickFix)
- install extras and run scripts by clicking a line marker ([Toml plugin](https://plugins.jetbrains.com/plugin/8195-toml) is required)

- show a message for outdated version packages ([Toml plugin](https://plugins.jetbrains.com/plugin/8195-toml) is required)

## Workaround
If the plugin does not detect your poetry environment after changing the environment, then please re-open the project.
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ You can install the stable version on PyCharm's `Marketplace` (Preference -> Plu
- update and lock with a popup
- show a message and a link to fix settings (QuickFix)
- install extras and run scripts by clicking a line marker ([Toml plugin](https://plugins.jetbrains.com/plugin/8195-toml) is required)
- show a message for outdated version packages ([Toml plugin](https://plugins.jetbrains.com/plugin/8195-toml) is required)


## Workaround
Expand Down
1 change: 1 addition & 0 deletions resources/META-INF/only-toml.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
implementationClass="com.koxudaxi.poetry.PoetryExtrasLineMarkerContributor"/>
<runLineMarkerContributor language="TOML"
implementationClass="com.koxudaxi.poetry.PoetryScriptsLineMarkerContributor"/>
<localInspection language="TOML" enabledByDefault="true" implementationClass="com.koxudaxi.poetry.PoetryVersionInspection" displayName="Poetry Package versions" bundle="messages.PoetryPsiBundle" groupKey="INSP.GROUP.python" suppressId="PoetryPackageVersion"/>

</extensions>
</idea-plugin>
7 changes: 6 additions & 1 deletion resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<idea-plugin url="https://github.com/koxudaxi/poetry-pycharm-plugin">
<id>com.koxudaxi.poetry</id>
<name>Poetry</name>
<version>0.1.1</version>
<version>0.1.2</version>
<vendor email="[email protected]">Koudai Aono @koxudaxi</vendor>
<change-notes><![CDATA[
<h2>version 0.1.2</h2>
<p>Features</p>
<ul>
<li>Add a version inspection [#85]</li>
</ul>
<h2>version 0.1.1</h2>
<p>Features</p>
<ul>
Expand Down
47 changes: 47 additions & 0 deletions src/com/koxudaxi/poetry/PoetryVersionInspection.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.koxudaxi.poetry

import com.intellij.codeInspection.*
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiFile
import com.jetbrains.python.sdk.*
import org.toml.lang.psi.*

class PoetryVersionInspection : LocalInspectionTool() {
override fun buildVisitor(holder: ProblemsHolder,
isOnTheFly: Boolean,
session: LocalInspectionToolSession): PsiElementVisitor {
return PoetryFileVisitor(holder, session)
}

class PoetryFileVisitor(val holder: ProblemsHolder,
session: LocalInspectionToolSession) : PsiElementVisitor() {
private fun guessModule(element: PsiElement): Module? {
return ModuleUtilCore.findModuleForPsiElement(element)
?: ModuleManager.getInstance(element.project).modules.let { if (it.size != 1) null else it[0] }
}

override fun visitFile(file: PsiFile) {
val module = guessModule(file) ?: return
val sdk = PythonSdkUtil.findPythonSdk(module) ?: return
if (!isPoetry(file.project, sdk)) return
if (file.virtualFile != module.pyProjectToml) return
file.children
.filter { element ->
(element as? TomlTable)?.header?.names?.joinToString(".") { it.text } in listOf("tool.poetry.dependencies", "tool.poetry.dev-dependencies")
}.flatMap {
it.children.mapNotNull { line -> line as? TomlKeyValue }
}.forEach { keyValue ->
val packageName = keyValue.key.text
val outdatedVersion = PyPoetryPackageManager.getInstance(sdk).getOutdatedPackages()[packageName]
if (outdatedVersion is PoetryOutdatedVersion) {
val message = "'${packageName}' version ${outdatedVersion.currentVersion} is outdated (latest: ${outdatedVersion.latestVersion})"
holder.registerProblem(keyValue, message, ProblemHighlightType.WARNING)
}
}
}
}
}
18 changes: 16 additions & 2 deletions src/com/koxudaxi/poetry/PyPoetryPackageManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class PyPoetryPackageManager(val sdk: Sdk) : PyPackageManager() {

private var requirements: List<PyRequirement>? = null

private var outdatedPackages: Map<String, PoetryOutdatedVersion> = emptyMap()

init {
PyPackageUtil.runOnChangeUnderInterpreterPaths(sdk) {
PythonSdkType.getInstance().setupSdkPaths(sdk)
Expand Down Expand Up @@ -93,22 +95,34 @@ class PyPoetryPackageManager(val sdk: Sdk) : PyPackageManager() {

fun getRequirements() = requirements

fun getOutdatedPackages() = outdatedPackages

override fun refreshAndGetPackages(alwaysRefresh: Boolean): List<PyPackage> {
return refreshAndGetPackages(alwaysRefresh, true)
}

fun refreshAndGetPackages(alwaysRefresh: Boolean, notify: Boolean): List<PyPackage> {
if (alwaysRefresh || packages == null) {
packages = null
val output = try {
val outputInstallDryRun = try {
runPoetry(sdk, "install", "--dry-run", "--no-root")
} catch (e: ExecutionException) {
packages = emptyList()
return packages ?: emptyList()
}
val allPackage = parsePoetryInstallDryRun(output)
val allPackage = parsePoetryInstallDryRun(outputInstallDryRun)
packages = allPackage.first
requirements = allPackage.second

val outputOutdatedPackages = try {
runPoetry(sdk, "show", "--outdated")
} catch (e: ExecutionException) {
outdatedPackages = emptyMap()
}
if (outputOutdatedPackages is String) {
outdatedPackages = parsePoetryShowOutdated(outputOutdatedPackages)
}

if (notify) {
ApplicationManager.getApplication().messageBus.syncPublisher(PACKAGE_MANAGER_TOPIC).packagesRefreshed(sdk)
}
Expand Down
19 changes: 18 additions & 1 deletion src/com/koxudaxi/poetry/poetry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ import org.apache.tuweni.toml.TomlParseResult
import org.apache.tuweni.toml.TomlTable
import org.jetbrains.annotations.SystemDependent
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir
import org.jetbrains.kotlin.utils.getOrPutNullable
import java.io.File
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.regex.Pattern

const val PY_PROJECT_TOML: String = "pyproject.toml"
const val POETRY_LOCK: String = "poetry.lock"
Expand Down Expand Up @@ -635,3 +635,20 @@ inline fun <reified T> syncRunPoetry(projectPath: @SystemDependent String, varar

fun getPythonExecutable(homePath: String): String =
PythonSdkUtil.getPythonExecutable(homePath) ?: FileUtil.join(homePath, "bin", "python")

/**
* Parses the output of `poetry show --outdated` into a list of packages.
*/
fun parsePoetryShowOutdated(input: String): Map<String, PoetryOutdatedVersion> {
return input
.lines()
.mapNotNull { line ->
line.split(Pattern.compile(" +"))
.takeIf { it.size > 3 }?.let { it[0] to PoetryOutdatedVersion(it[1], it[2]) }
}.toMap()
}


data class PoetryOutdatedVersion(
@SerializedName("currentVersion") var currentVersion: String,
@SerializedName("latestVersion") var latestVersion: String)
5 changes: 5 additions & 0 deletions testData/Poetry/parsePoetryShoOutdated/show-outdated.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
boto3 1.13.26 1.14.38 The AWS SDK for Python
botocore 1.16.26 1.17.38 Low-level, data-driven core of boto 3.
docutils 0.15.2 0.16 Docutils -- Python Documentation Utilities
pydantic 1.4 1.6.1 Data validation and settings management using python 3.6 type hinting

22 changes: 20 additions & 2 deletions testSrc/com/koxudaxi/poetry/PoetryTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ package com.koxudaxi.poetry


import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl
import org.jetbrains.kotlin.konan.file.File


class PoetryTest : PoetryTestCase() {
private val testFile: VirtualFile
get() {
return getTestData("pyproject.toml")
}

fun testGetPyProjectTomlForPoetry() {
val result = getPyProjectTomlForPoetry(testFile)
assertEquals(result.first, 0)
Expand All @@ -28,4 +27,23 @@ class PoetryTest : PoetryTestCase() {
assertEquals(result.first, 0)
assertEquals(result.second, null)
}

private val testShowOutdatedDataAsText: String
get() {
return getTestDataAsText("show-outdated.txt")
}

fun testParsePoetryShoOutdated() {
val result = parsePoetryShowOutdated(testShowOutdatedDataAsText)
assertEquals(result.size, 4)
assertEquals(result,
mapOf(
"boto3" to PoetryOutdatedVersion(currentVersion = "1.13.26", latestVersion = "1.14.38"),
"botocore" to PoetryOutdatedVersion(currentVersion = "1.16.26", latestVersion = "1.17.38"),
"docutils" to PoetryOutdatedVersion(currentVersion = "0.15.2", latestVersion = "0.16"),
"pydantic" to PoetryOutdatedVersion(currentVersion = "1.4", latestVersion = "1.6.1")
)
)
}

}

0 comments on commit 21fffd8

Please sign in to comment.