Skip to content

Commit ca751a6

Browse files
authored
Merge pull request #824 from viash-io/port_automatically_convert_integers
`NextflowRunner`: Automatically convert integers to doubles when argument type is `double`
2 parents 0f80126 + 8d9391f commit ca751a6

6 files changed

Lines changed: 139 additions & 38 deletions

File tree

CHANGELOG.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
# Viash 0.x.x (yyyy-MM-dd): TODO Add title
1+
# Viash 0.9.4 (2025-04-24): Hotfix for Nextflow edge
22

3-
TODO add summary
3+
This is a hotfix release for the changes in Nextflow edge's handling of double arguments.
4+
5+
## BUG FIXES
6+
7+
* `NextflowRunner`: Automatically convert integers to doubles when argument type is `double` (port of PR #823, PR #824).
48

59
# Viash 0.9.3 (2025-03-31): Support upcoming version of Nextflow
610

@@ -212,6 +216,28 @@ Implemented a proper way of caching dependency repositories. The cache is stored
212216

213217
* `viash test`: Fix an issue where the tests would not copy package config settings to determine the docker image name (PR #767).
214218

219+
# Viash 0.8.8 (2025-04-24): Hotfix for Nextflow edge
220+
221+
This is a hotfix release for the changes in Nextflow edge's handling of double arguments.
222+
223+
## BUG FIXES
224+
225+
* `NextflowRunner`: Automatically convert integers to doubles when argument type is `double` (PR #823).
226+
227+
# Viash 0.8.7 (2025-04-01): Backport support upcoming version of Nextflow
228+
229+
The upcoming release of Nextflow introduces a new class for loading scripts and renamed the old class.
230+
This release supports this change by using reflection to detect the available class.
231+
232+
## BUG FIXES
233+
234+
* `viash build`: Fix error handling of non-generic errors in the build process or while pushing docker containers (PR #696).
235+
236+
* `NextflowRunner`: ScriptParser was renamed to ScriptLoaderV1 in Nextflow 25.02.0-edge (PR #817). Backport from Viash 0.9.3 (PR #812).
237+
This fix uses reflection to detect whether ScriptParser exists -- if not the ScriptLoaderFactory is used instead.
238+
239+
* `NextflowRunner`: Backport path handling for `meta.resources_dir` for when symlinks are used (PR #817).
240+
215241
# Viash 0.8.6 (2024-04-26): Bug fixes and improvements for CI
216242

217243
Fix some issues in some edge cases.

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name := "viash"
22

3-
version := "0.9.4-dev"
3+
version := "0.9.4"
44

55
scalaVersion := "3.3.4"
66

src/main/resources/io/viash/runners/nextflow/arguments/_checkArgumentType.nf

Lines changed: 30 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -66,64 +66,56 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
6666
foundClass = "List[${e.foundClass}]"
6767
}
6868
} else if (par.type == "string") {
69-
// cast to string if need be
69+
// cast to string if need be. only cast if the value is a GString
7070
if (value instanceof GString) {
71-
value = value.toString()
71+
value = value as String
7272
}
7373
expectedClass = value instanceof String ? null : "String"
7474
} else if (par.type == "integer") {
7575
// cast to integer if need be
76-
if (value instanceof String) {
76+
if (value !instanceof Integer) {
7777
try {
78-
value = value.toInteger()
78+
value = value as Integer
7979
} catch (NumberFormatException e) {
80-
// do nothing
80+
expectedClass = "Integer"
8181
}
8282
}
83-
if (value instanceof java.math.BigInteger) {
84-
value = value.intValue()
85-
}
86-
expectedClass = value instanceof Integer ? null : "Integer"
8783
} else if (par.type == "long") {
8884
// cast to long if need be
89-
if (value instanceof String) {
85+
if (value !instanceof Long) {
9086
try {
91-
value = value.toLong()
87+
value = value as Long
9288
} catch (NumberFormatException e) {
93-
// do nothing
89+
expectedClass = "Long"
9490
}
9591
}
96-
if (value instanceof Integer) {
97-
value = value.toLong()
98-
}
99-
expectedClass = value instanceof Long ? null : "Long"
10092
} else if (par.type == "double") {
10193
// cast to double if need be
102-
if (value instanceof String) {
94+
if (value !instanceof Double) {
10395
try {
104-
value = value.toDouble()
96+
value = value as Double
10597
} catch (NumberFormatException e) {
106-
// do nothing
98+
expectedClass = "Double"
10799
}
108100
}
109-
if (value instanceof java.math.BigDecimal) {
110-
value = value.doubleValue()
111-
}
112-
if (value instanceof Float) {
113-
value = value.toDouble()
101+
} else if (par.type == "float") {
102+
// cast to float if need be
103+
if (value !instanceof Float) {
104+
try {
105+
value = value as Float
106+
} catch (NumberFormatException e) {
107+
expectedClass = "Float"
108+
}
114109
}
115-
expectedClass = value instanceof Double ? null : "Double"
116110
} else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
117111
// cast to boolean if need be
118-
if (value instanceof String) {
119-
def valueLower = value.toLowerCase()
120-
if (valueLower == "true") {
121-
value = true
122-
} else if (valueLower == "false") {
123-
value = false
112+
if (value !instanceof Boolean) {
113+
try {
114+
value = value as Boolean
115+
} catch (Exception e) {
116+
expectedClass = "Boolean"
124117
}
125118
}
126-
expectedClass = value instanceof Boolean ? null : "Boolean"
127119
} else if (par.type == "file" && (par.direction == "input" || stage == "output")) {
128120
// cast to path if need be
129121
if (value instanceof String) {
@@ -135,10 +127,13 @@ def _checkArgumentType(String stage, Map par, Object value, String errorIdentifi
135127
expectedClass = value instanceof Path ? null : "Path"
136128
} else if (par.type == "file" && stage == "input" && par.direction == "output") {
137129
// cast to string if need be
138-
if (value instanceof GString) {
139-
value = value.toString()
130+
if (value !instanceof String) {
131+
try {
132+
value = value as String
133+
} catch (Exception e) {
134+
expectedClass = "String"
135+
}
140136
}
141-
expectedClass = value instanceof String ? null : "String"
142137
} else {
143138
// didn't find a match for par.type
144139
expectedClass = par.type
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
functionality:
2+
name: integer_as_double
3+
arguments:
4+
- name: "--input"
5+
type: file
6+
required: true
7+
example: input.txt
8+
- name: "--output"
9+
type: file
10+
required: true
11+
direction: output
12+
example: output.txt
13+
- name: "--double"
14+
type: double
15+
required: true
16+
direction: input
17+
example: 10.5
18+
resources:
19+
- type: bash_script
20+
path: script.sh
21+
platforms:
22+
- type: native
23+
- type: docker
24+
image: nextflow/bash:latest
25+
- type: nextflow
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
## VIASH START
4+
par_input='resources/lines3.txt'
5+
par_double='10.5'
6+
par_output='output.txt'
7+
## VIASH END
8+
9+
echo "Copying $par_input to $par_output"
10+
cp "$par_input" "$par_output"
11+
12+
echo "Adding $par_double to $par_output"
13+
echo "Double: $par_double" >> "$par_output"
14+
15+
exit 0

src/test/scala/io/viash/runners/nextflow/Vdsl3StandaloneTest.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,46 @@ class Vdsl3StandaloneTest extends AnyFunSuite with BeforeAndAfterAll {
242242
}
243243
}
244244

245+
246+
test("Whether integers can be converted to doubles", NextflowTest) {
247+
// create params.yaml file
248+
val paramsPath = temporaryFolder.resolve("params.yaml")
249+
val paramsStr = """id: foo
250+
|input: resources/lines3.txt
251+
|double: 10
252+
|publish_dir: integerAsDouble
253+
|""".stripMargin
254+
Files.write(paramsPath, paramsStr.getBytes(StandardCharsets.UTF_8))
255+
256+
val (exitCode, stdOut, stdErr) = NextflowTestHelper.run(
257+
mainScript = "target/nextflow/integer_as_double/main.nf",
258+
args = Nil,
259+
paramsFile = Some(paramsPath.toString()),
260+
cwd = tempFolFile
261+
)
262+
263+
assert(exitCode == 0, s"\nexit code was $exitCode\nStd output:\n$stdOut\nStd error:\n$stdErr")
264+
265+
val expectedFiles =
266+
Map(
267+
"state" -> "state.yaml",
268+
"output" -> "output.txt",
269+
).map{ case (id, suffix) =>
270+
val path = temporaryFolder.resolve("integerAsDouble/foo.integer_as_double." + suffix)
271+
(id, path)
272+
}
273+
274+
// check if files exist
275+
276+
val src = Source.fromFile(tempFolStr + "/integerAsDouble/foo.integer_as_double.output.txt")
277+
try {
278+
val moduleOut = src.getLines().mkString(",")
279+
assert(moduleOut.equals("one,two,three,Double: 10.0"), s"Expected output 'one,two,three,10.0' but got '$moduleOut'")
280+
} finally {
281+
src.close()
282+
}
283+
}
284+
245285
override def afterAll(): Unit = {
246286
IO.deleteRecursively(temporaryFolder)
247287
}

0 commit comments

Comments
 (0)