Skip to content

Commit

Permalink
Merge branch 'master' into features/#182-inject-py-regexp-into-wildcard
Browse files Browse the repository at this point in the history
  • Loading branch information
iromeo authored Aug 21, 2020
2 parents 2366090 + ebb55bd commit 71eb430
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Features:
- Inspection: Warn user if rule from 'rulesorder' isn't available in current or included files (see #254)
- Inspection: Warn about string arguments split on several lines (see #259)
- Injection: Inject regexp language into wildcard_constraints section params values (see #182)
- Inspection: Correct using methods ancient, protected, directory (see #250)
- Inspection: Warn users if they have callable arguments in sections that does not expect it (see #198)
- Inspection: Warn users if they have keyword arguments in sections that does not expect it (see #196)
- Inspection: Warn about usage of rule/checkpoint/subworkflow objects as arguments instead of one of its fields (see #257)
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ downloadIdeSources=true
#
# ide version examples: IC-172.4343, IC-2018.1.3, IC-183-EAP-SNAPSHOT, IC-LATEST-EAP-SNAPSHOT
# ide type examples: IC (IDEA Community), IU (IDEA Ultimate)
#ideVersion=IC-2019.3
#ideVersion=IC-193-EAP-SNAPSHOT
#pythonPlugin=PythonCore:193.5233.84
#ideVersion=IC-202-EAP-SNAPSHOT
## OK with IC-202.6948.36 it is 2020.2.1 RC
#pythonPlugin=PythonCore:202.6948.52
# ---------
# PyCharm
# ---------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ import com.jetbrains.snakecharm.lang.SnakemakeNames.SECTION_THREADS
import com.jetbrains.snakecharm.lang.SnakemakeNames.SECTION_VERSION
import com.jetbrains.snakecharm.lang.SnakemakeNames.SECTION_WILDCARD_CONSTRAINTS
import com.jetbrains.snakecharm.lang.SnakemakeNames.SECTION_WRAPPER
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_ANCIENT
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_DIRECTORY
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_DYNAMIC
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_PIPE
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_PROTECTED
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_REPEAT
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_REPORT
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_TEMP
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_TOUCH
import com.jetbrains.snakecharm.lang.SnakemakeNames.SNAKEMAKE_IO_METHOD_UNPACK

/**
* Also see [ImplicitPySymbolsProvider] class
Expand Down Expand Up @@ -191,4 +201,17 @@ object SnakemakeAPI {
SECTION_PRIORITY, SECTION_GROUP, SECTION_SHADOW, SECTION_CONDA, SECTION_SCRIPT, SECTION_WRAPPER,
SECTION_CWL, SECTION_NOTEBOOK, SECTION_CACHE, SECTION_CONTAINER
)

val IO_FLAG_2_SUPPORTED_SECTION: HashMap<String, List<String>> = hashMapOf(
SNAKEMAKE_IO_METHOD_ANCIENT to listOf(SECTION_INPUT),
SNAKEMAKE_IO_METHOD_PROTECTED to listOf(SECTION_OUTPUT, SECTION_LOG, SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_DIRECTORY to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_REPORT to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_TEMP to listOf(SECTION_INPUT, SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_TOUCH to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_PIPE to listOf(SECTION_OUTPUT),
SNAKEMAKE_IO_METHOD_REPEAT to listOf(SECTION_BENCHMARK),
SNAKEMAKE_IO_METHOD_UNPACK to listOf(SECTION_INPUT),
SNAKEMAKE_IO_METHOD_DYNAMIC to listOf(SECTION_OUTPUT)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.jetbrains.snakecharm.inspections

import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemsHolder
import com.jetbrains.python.psi.PyCallExpression
import com.jetbrains.python.psi.PyReferenceExpression
import com.jetbrains.snakecharm.SnakemakeBundle
import com.jetbrains.snakecharm.codeInsight.SnakemakeAPI.IO_FLAG_2_SUPPORTED_SECTION
import com.jetbrains.snakecharm.lang.psi.SmkFile
import com.jetbrains.snakecharm.lang.psi.SmkRuleOrCheckpointArgsSection

class SmkMisuseUsageIOFlagMethodsInspection : SnakemakeInspection() {
override fun buildVisitor(
holder: ProblemsHolder,
isOnTheFly: Boolean,
session: LocalInspectionToolSession
) = object : SnakemakeInspectionVisitor(holder, session) {

private fun getSupportedSectionIfMisuse(
flagCallName: String,
section: SmkRuleOrCheckpointArgsSection
): List<String> {
val supportedSections = IO_FLAG_2_SUPPORTED_SECTION[flagCallName]
if (supportedSections != null) {
if (section.sectionKeyword !in supportedSections) {
return supportedSections
}
}
// check N/A here
return emptyList()
}

override fun visitSmkRuleOrCheckpointArgsSection(st: SmkRuleOrCheckpointArgsSection) {

if (st.containingFile !is SmkFile) {
return
}

val argList = st.argumentList ?: return
argList.arguments
.filterIsInstance<PyCallExpression>()
.forEach { callExpr ->
val callee = callExpr.callee
if (callee is PyReferenceExpression) {
// We don't need qualified refs here (e.g. like `foo.boo.ancient`)
val callName = when (callee.qualifier) {
null -> callee.referencedName
else -> null
}

if (callName != null) {
val supportedSectionIfMisuse = getSupportedSectionIfMisuse(callName, st)
if (supportedSectionIfMisuse.isNotEmpty()) {
holder.registerProblem(
callExpr,
SnakemakeBundle.message(
"INSP.NAME.misuse.usage.io.flag.methods.warning.message",
callName,
st.sectionKeyword!!,
supportedSectionIfMisuse.sorted().joinToString { "'$it'"}
)
)
}
}
}
}
}
}
}
11 changes: 11 additions & 0 deletions src/main/kotlin/com/jetbrains/snakecharm/lang/SnakemakeNames.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,15 @@ object SnakemakeNames {

const val RUN_SECTION_VARIABLE_RULE = "rule"
const val RUN_SECTION_VARIABLE_JOBID = "jobid"

const val SNAKEMAKE_IO_METHOD_ANCIENT = "ancient"
const val SNAKEMAKE_IO_METHOD_PROTECTED = "protected"
const val SNAKEMAKE_IO_METHOD_DIRECTORY = "directory"
const val SNAKEMAKE_IO_METHOD_TEMP = "temp"
const val SNAKEMAKE_IO_METHOD_REPORT = "report"
const val SNAKEMAKE_IO_METHOD_TOUCH = "touch"
const val SNAKEMAKE_IO_METHOD_PIPE = "pipe"
const val SNAKEMAKE_IO_METHOD_REPEAT = "repeat"
const val SNAKEMAKE_IO_METHOD_UNPACK = "unpack"
const val SNAKEMAKE_IO_METHOD_DYNAMIC = "dynamic"
}
11 changes: 11 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,17 @@
implementationClass="com.jetbrains.snakecharm.inspections.SmkRedundantCommaInspection"
/>

<localInspection
language="Snakemake" shortName="SmkMisuseUsageIOFlagMethodsInspection"
enabledByDefault="true"
level="WARNING"
suppressId="SmkMisuseUsageIOFlagMethods"
bundle="SnakemakeBundle"
groupKey="INSP.GROUP.snakemake"
key="INSP.NAME.misuse.usage.io.flag.methods.title"
implementationClass="com.jetbrains.snakecharm.inspections.SmkMisuseUsageIOFlagMethodsInspection"
/>

<findUsagesHandlerFactory
implementation="com.jetbrains.snakecharm.codeInsight.refactoring.SmkFindUsagesHandlerFactory"
id="Python" order="last, before default"
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/SnakemakeBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ INSP.NAME.wildcards.confusing.name.with.dot.message=Confusing wildcard name: ''{
INSP.NAME.redundant.comma.title=Comma is unnecessary
INSP.NAME.redundant.comma.fix.message=Remove redundant comma

# SmkMisuseUsageIOFlagMethodsInspection
INSP.NAME.misuse.usage.io.flag.methods.title=Correct using methods ancient, protected, directory
INSP.NAME.misuse.usage.io.flag.methods.warning.message=''{0}'' isn''t supported in ''{1}'' section, expected in sections: {2}.

# SmkPyUnboundLocalVariableInspection
INSP.NAME.unbound=Unbound local variable

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
Input/Output flags (e.g. ancient(..), protected(..), directory(..), etc) not supported by all rule sections. This inspection warns about such flags misuse.
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
Feature: Inspection for methods from snakemake library

Scenario Outline: Incorrect using ancient/protected/directory methods
Given a snakemake project
Given I open a file "foo.smk" with text
"""
<rule_like> NAME:
<section>: <method><arg_list>
"""
And SmkMisuseUsageIOFlagMethodsInspection inspection is enabled
Then I expect inspection warning on <<method><arg_list>> in <<section>: <method><arg_list>> with message
"""
'<method>' isn't supported in '<section>' section, expected in sections: <expected>.
"""
When I check highlighting warnings
Examples:
| rule_like | section | method | arg_list | expected |
| rule | input | directory | ('') | 'output' |
| rule | input | pipe | ('') | 'output' |
| rule | input | protected | ('') | 'benchmark', 'log', 'output' |
| rule | log | temp | ('') | 'input', 'output' |
| rule | input | dynamic | ('') | 'output' |
| rule | input | touch | ('') | 'output' |
| rule | input | repeat | ('') | 'benchmark' |
| rule | input | report | ('') | 'output' |
| rule | output | ancient | ('') | 'input' |
| rule | output | unpack | ('') | 'input' |
| checkpoint | input | directory | ('') | 'output' |
| checkpoint | input | pipe | ('') | 'output' |
| checkpoint | input | protected | ('') | 'benchmark', 'log', 'output' |
| checkpoint | log | temp | ('') | 'input', 'output' |
| checkpoint | input | dynamic | ('') | 'output' |
| checkpoint | input | touch | ('') | 'output' |
| checkpoint | input | repeat | ('') | 'benchmark' |
| checkpoint | input | report | ('') | 'output' |
| checkpoint | output | ancient | ('') | 'input' |
| checkpoint | output | unpack | ('') | 'input' |

Scenario Outline: Correct using ancient/protected/directory methods
Given a snakemake project
Given I open a file "foo.smk" with text
"""
<rule_like> NAME:
<section>: <method>
"""
And SmkMisuseUsageIOFlagMethodsInspection inspection is enabled
Then I expect no inspection warnings
When I check highlighting warnings
Examples:
| rule_like | section | method |
| rule | input | ancient('') |
| rule | input | temp('') |
| rule | input | unpack('') |
| rule | output | directory('') |
| rule | output | pipe('') |
| rule | output | protected('') |
| rule | output | dynamic('') |
| rule | output | touch('') |
| rule | output | report('') |
| rule | benchmark | repeat('') |
| rule | benchmark | protected('') |
| checkpoint | input | ancient('') |
| checkpoint | input | temp('') |
| checkpoint | input | unpack('') |
| checkpoint | output | directory('') |
| checkpoint | output | pipe('') |
| checkpoint | output | protected('') |
| checkpoint | output | dynamic('') |
| checkpoint | output | touch('') |
| checkpoint | output | report('') |
| checkpoint | benchmark | repeat('') |
| checkpoint | benchmark | protected('') |


Scenario Outline: Complex cases not be confused
Given a snakemake project
Given I open a file "foo.smk" with text
"""
<rule_like> NAME:
<section>: <method>
"""
And SmkMisuseUsageIOFlagMethodsInspection inspection is enabled
Then I expect no inspection warnings
When I check highlighting warnings
Examples:
| rule_like | section | method |
| rule | output | foo.ancient('') |
| rule | output | ancient.foo('') |

0 comments on commit 71eb430

Please sign in to comment.