Skip to content

Commit

Permalink
Set context on NoSuchOption exceptions (#401)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajalt committed Apr 2, 2023
1 parent 76e8bff commit 98105aa
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ internal object Parser {
invocationsByOption.forEach { (o, inv) -> if (o.isEager) o.finalize(context, inv) }

// Finalize arguments before options, so that options can reference them
val (excess, parsedArgs) = parseArguments(positionalArgs, arguments)
val (excess, parsedArgs) = parseArguments(context, positionalArgs, arguments)
val retries = finalizeArguments(parsedArgs, context)
i = handleExcessArguments(
excess,
Expand Down Expand Up @@ -261,7 +261,8 @@ internal object Parser {
throw NoSuchOption(
givenName = name,
possibilities = context.correctionSuggestor(name,
optionsByName.filterNot { it.value.hidden }.keys.toList())
optionsByName.filterNot { it.value.hidden }.keys.toList()),
context = context,
)
}

Expand Down Expand Up @@ -290,7 +291,7 @@ internal object Parser {
prefix == "-" && "-$tok" in optionsByName -> listOf("-$tok")
else -> emptyList()
}
throw NoSuchOption(name, possibilities)
throw NoSuchOption(name, possibilities, context = context)
}
val result = option.parser.parseShortOpt(option, name, tokens, index, i)
invocations += OptInvocation(option, result.invocation)
Expand All @@ -300,6 +301,7 @@ internal object Parser {
}

private fun parseArguments(
context: Context,
positionalArgs: List<String>,
arguments: List<Argument>,
): Pair<Int, Map<Argument, List<String>>> {
Expand All @@ -320,8 +322,8 @@ internal object Parser {
else -> argument.nvalues
}
if (consumed > remaining) {
if (remaining == 0) throw MissingArgument(argument)
else throw IncorrectArgumentValueCount(argument)
if (remaining == 0) throw MissingArgument(argument, context)
else throw IncorrectArgumentValueCount(argument, context)
}
out[argument] = out.getValue(argument) + positionalArgs.subList(i, i + consumed)
i += consumed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.ajalt.clikt.parameters

import com.github.ajalt.clikt.core.*
import com.github.ajalt.clikt.output.Localization
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.default
import com.github.ajalt.clikt.parameters.options.*
Expand Down Expand Up @@ -67,6 +68,26 @@ class OptionTest {
}.message shouldBe message
}

@Test
@JsName("no_such_option_custom_localization")
fun `no such option custom localization`() {
if (skipDueToKT43490) return
class L : Localization {
override fun noSuchOption(name: String, possibilities: List<String>) =
"custom message"
}

class C : TestCommand(called = false) {
init {
context { localization = L() }
}
}

shouldThrow<NoSuchOption> {
C().parse("-z")
}.message shouldBe "custom message"
}

@Test
@JsName("one_option")
fun `one option`() = forAll(
Expand Down Expand Up @@ -396,7 +417,8 @@ class OptionTest {
@JsName("default_option")
fun `default option`() = forAll(
row("", "def"),
row("-x4", "4")) { argv, expected ->
row("-x4", "4")
) { argv, expected ->
class C : TestCommand() {
val x by option("-x", "--xx").default("def")
override fun run_() {
Expand All @@ -411,7 +433,8 @@ class OptionTest {
@JsName("defaultLazy_option")
fun `defaultLazy option`() = forAll(
row("", "default", true),
row("-xbar", "bar", false)) { argv, expected, ec ->
row("-xbar", "bar", false)
) { argv, expected, ec ->
var called = false

class C : TestCommand() {
Expand Down Expand Up @@ -579,12 +602,13 @@ class OptionTest {
val u by option().flag()
override fun run_() {
registeredOptions().forEach {
assertTrue(it is EagerOption || // skip help option
"--x" in it.names && it.metavar(currentContext) == "TEXT" ||
"--y" in it.names && it.metavar(currentContext) == "FOO" ||
"--z" in it.names && it.metavar(currentContext) == "FOO" ||
"--w" in it.names && it.metavar(currentContext) == "BAR" ||
"--u" in it.names && it.metavar(currentContext) == null,
assertTrue(
it is EagerOption || // skip help option
"--x" in it.names && it.metavar(currentContext) == "TEXT" ||
"--y" in it.names && it.metavar(currentContext) == "FOO" ||
"--z" in it.names && it.metavar(currentContext) == "FOO" ||
"--w" in it.names && it.metavar(currentContext) == "BAR" ||
"--u" in it.names && it.metavar(currentContext) == null,
message = "bad option $it"
)
}
Expand Down Expand Up @@ -738,7 +762,8 @@ class OptionTest {
row("-xx=asd", "asd"),
row("-x 4", "4"),
row("-x -xx -xx foo", "foo"),
row("-xfoo", "foo")) { argv, expected ->
row("-xfoo", "foo")
) { argv, expected ->
class C : TestCommand() {
val x by option("-x", "-xx")
override fun run_() {
Expand All @@ -761,7 +786,8 @@ class OptionTest {
row("-y +y", false, true),
row("+y -y", false, false),
row("-x -y", false, false),
row("-x -y +xy", true, true)) { argv, ex, ey ->
row("-x -y +xy", true, true)
) { argv, ex, ey ->
class C : TestCommand() {
val x by option("+x").flag("-x")
val y by option("+y").flag("-y")
Expand All @@ -780,7 +806,8 @@ class OptionTest {
row("", null),
row("--XX=FOO", "FOO"),
row("--xx=FOO", "FOO"),
row("-XX", "X")) { argv, expected ->
row("-XX", "X")
) { argv, expected ->
class C : TestCommand() {
val x by option("-x", "--xx")
override fun run_() {
Expand All @@ -795,7 +822,8 @@ class OptionTest {
@JsName("aliased_tokens")
fun `aliased tokens`() = forAll(
row("", null),
row("--yy 3", "3")) { argv, expected ->
row("--yy 3", "3")
) { argv, expected ->
class C : TestCommand() {
val x by option("-x", "--xx")
override fun run_() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import org.junit.rules.TemporaryFolder
import kotlin.test.Test


class ParserTest {
class AtFileParserTest {
@get:Rule
var testFolder = TemporaryFolder()

Expand Down

0 comments on commit 98105aa

Please sign in to comment.