diff --git a/README.md b/README.md index 8f7c49f7eb..1edc910146 100644 --- a/README.md +++ b/README.md @@ -78,29 +78,29 @@ Run your application with the `typer` command: // Run your application $ typer main.py run -// You get a nice error, you are missing NAME -Usage: typer [PATH_OR_MODULE] run [OPTIONS] NAME +// You get a nice error, you are missing 'name' +Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name} Try 'typer [PATH_OR_MODULE] run --help' for help. ╭─ Error ───────────────────────────────────────────╮ -│ Missing argument 'NAME'. │ +│ Missing argument 'name'. │ ╰───────────────────────────────────────────────────╯ // You get a --help for free $ typer main.py run --help -Usage: typer [PATH_OR_MODULE] run [OPTIONS] NAME +Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name} Run the provided Typer app. ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] | +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --help Show this message and exit. │ ╰───────────────────────────────────────────────────╯ -// Now pass the NAME argument +// Now pass the 'name' argument $ typer main.py run Camila Hello Camila @@ -138,27 +138,27 @@ Now you could run it with Python directly: // Run your application $ python main.py -// You get a nice error, you are missing NAME -Usage: main.py [OPTIONS] NAME +// You get a nice error, you are missing 'name' +Usage: main.py [OPTIONS] {name} Try 'main.py --help' for help. ╭─ Error ───────────────────────────────────────────╮ -│ Missing argument 'NAME'. │ +│ Missing argument 'name'. │ ╰───────────────────────────────────────────────────╯ // You get a --help for free $ python main.py --help -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] | +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --help Show this message and exit. │ ╰───────────────────────────────────────────────────╯ -// Now pass the NAME argument +// Now pass the 'name' argument $ python main.py Camila Hello Camila @@ -236,13 +236,13 @@ $ python main.py --help │ and exit. │ ╰───────────────────────────────────────────────────╯ ╭─ Commands ────────────────────────────────────────╮ -│ goodbye │ │ hello │ +│ goodbye │ ╰───────────────────────────────────────────────────╯ // When you create a package you get ✨ auto-completion ✨ for free, installed with --install-completion -// You have 2 subcommands (the 2 functions): goodbye and hello +// You have 2 subcommands (the 2 functions): hello and goodbye ``` @@ -254,10 +254,10 @@ Now check the help for the `hello` command: ```console $ python main.py hello --help - Usage: main.py hello [OPTIONS] NAME + Usage: main.py hello [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] │ +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --help Show this message and exit. │ @@ -273,10 +273,10 @@ And now check the help for the `goodbye` command: ```console $ python main.py goodbye --help - Usage: main.py goodbye [OPTIONS] NAME + Usage: main.py goodbye [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] │ +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --formal --no-formal [default: no-formal] │ diff --git a/docs/index.md b/docs/index.md index ac8ef85860..874cc6df87 100644 --- a/docs/index.md +++ b/docs/index.md @@ -86,29 +86,29 @@ Run your application with the `typer` command: // Run your application $ typer main.py run -// You get a nice error, you are missing NAME -Usage: typer [PATH_OR_MODULE] run [OPTIONS] NAME +// You get a nice error, you are missing 'name' +Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name} Try 'typer [PATH_OR_MODULE] run --help' for help. ╭─ Error ───────────────────────────────────────────╮ -│ Missing argument 'NAME'. │ +│ Missing argument 'name'. │ ╰───────────────────────────────────────────────────╯ // You get a --help for free $ typer main.py run --help -Usage: typer [PATH_OR_MODULE] run [OPTIONS] NAME +Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name} Run the provided Typer app. ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] | +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --help Show this message and exit. │ ╰───────────────────────────────────────────────────╯ -// Now pass the NAME argument +// Now pass the 'name' argument $ typer main.py run Camila Hello Camila @@ -146,27 +146,27 @@ Now you could run it with Python directly: // Run your application $ python main.py -// You get a nice error, you are missing NAME -Usage: main.py [OPTIONS] NAME +// You get a nice error, you are missing 'name' +Usage: main.py [OPTIONS] {name} Try 'main.py --help' for help. ╭─ Error ───────────────────────────────────────────╮ -│ Missing argument 'NAME'. │ +│ Missing argument 'name'. │ ╰───────────────────────────────────────────────────╯ // You get a --help for free $ python main.py --help -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] | +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --help Show this message and exit. │ ╰───────────────────────────────────────────────────╯ -// Now pass the NAME argument +// Now pass the 'name' argument $ python main.py Camila Hello Camila @@ -244,13 +244,13 @@ $ python main.py --help │ and exit. │ ╰───────────────────────────────────────────────────╯ ╭─ Commands ────────────────────────────────────────╮ -│ goodbye │ │ hello │ +│ goodbye │ ╰───────────────────────────────────────────────────╯ // When you create a package you get ✨ auto-completion ✨ for free, installed with --install-completion -// You have 2 subcommands (the 2 functions): goodbye and hello +// You have 2 subcommands (the 2 functions): hello and goodbye ``` @@ -262,10 +262,10 @@ Now check the help for the `hello` command: ```console $ python main.py hello --help - Usage: main.py hello [OPTIONS] NAME + Usage: main.py hello [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] │ +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --help Show this message and exit. │ @@ -281,10 +281,10 @@ And now check the help for the `goodbye` command: ```console $ python main.py goodbye --help - Usage: main.py goodbye [OPTIONS] NAME + Usage: main.py goodbye [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────╮ -│ * name TEXT [default: None] [required] │ +│ * name [required] │ ╰───────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────╮ │ --formal --no-formal [default: no-formal] │ diff --git a/docs/js/custom.js b/docs/js/custom.js index 29f2bf8524..232b2ceb3e 100644 --- a/docs/js/custom.js +++ b/docs/js/custom.js @@ -1,3 +1,17 @@ +function escapePlainCliLine(line) { + return line + .replace(/&/g, "&") + .replace(//g, ">"); +} + +function prepareTermynalLines(lines, isRichHtml) { + if (isRichHtml) { + return lines.join("
"); + } + return lines.map(escapePlainCliLine).join("
"); +} + function setupTermynal() { document.querySelectorAll(".use-termynal").forEach(node => { node.style.display = "block"; @@ -17,6 +31,11 @@ function setupTermynal() { .forEach(node => { const text = node.textContent; const lines = text.split("\n"); + // If it is a type in brackets like or , it won't have + // HTML attributes (=) or a closing tag, while Rich HTML tags do. + const hasHtmlAttribute = /<[A-Za-z][^>]*=/.test(text); + const hasClosingTag = /<\/[a-zA-Z0-9]/.test(text); + const isRichHtml = hasHtmlAttribute || hasClosingTag; const useLines = []; let buffer = []; function saveBuffer() { @@ -36,7 +55,7 @@ function setupTermynal() { // so put an additional one buffer.push(""); } - const bufferValue = buffer.join("
"); + const bufferValue = prepareTermynalLines(buffer, isRichHtml); dataValue["value"] = bufferValue; useLines.push(dataValue); buffer = []; @@ -57,7 +76,11 @@ function setupTermynal() { }); } else if (line.startsWith("// ")) { saveBuffer(); - const value = "💬 " + line.replace("// ", "").trimEnd(); + let comment = line.replace("// ", "").trimEnd(); + if (!isRichHtml) { + comment = escapePlainCliLine(comment); + } + const value = "💬 " + comment; useLines.push({ value: value, class: "termynal-comment", diff --git a/docs/tutorial/arguments/default.md b/docs/tutorial/arguments/default.md index c03e6931e8..248891126b 100644 --- a/docs/tutorial/arguments/default.md +++ b/docs/tutorial/arguments/default.md @@ -27,10 +27,10 @@ Check it: $ python main.py --help // Notice the [default: Wade Wilson] ✨ -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] [default: Wade Wilson] + name [default: Wade Wilson] Options: --help Show this message and exit. @@ -72,10 +72,10 @@ Check it: // Check the help $ python main.py --help -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] [default: (dynamic)] + name [default: (dynamic)] Options: --help Show this message and exit. diff --git a/docs/tutorial/arguments/envvar.md b/docs/tutorial/arguments/envvar.md index 53d04c9862..126f160ac6 100644 --- a/docs/tutorial/arguments/envvar.md +++ b/docs/tutorial/arguments/envvar.md @@ -20,10 +20,10 @@ In this case, the *CLI argument* `name` will have a default value of `"World"`, // Check the help $ python main.py --help -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] [env var: AWESOME_NAME;default: World] + name [env var: AWESOME_NAME; default: World] Options: --help Show this message and exit. @@ -65,10 +65,10 @@ Check it: // Check the help $ python main.py --help -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] [env var: AWESOME_NAME, GOD_NAME;default: World] + name [env var: AWESOME_NAME, GOD_NAME; default: World] Options: --help Show this message and exit. @@ -101,10 +101,10 @@ Check it: $ python main.py --help // It won't show the env var -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] [default: World] + name [default: World] Options: --help Show this message and exit. diff --git a/docs/tutorial/arguments/help.md b/docs/tutorial/arguments/help.md index 9c390ef874..7f8d0e62bf 100644 --- a/docs/tutorial/arguments/help.md +++ b/docs/tutorial/arguments/help.md @@ -22,10 +22,10 @@ And it will be used in the automatic `--help` option: $ python main.py --help // Check the section with Arguments below 🚀 -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Arguments: - NAME The name of the user to greet [required] + name The name of the user to greet [required] Options: --help Show this message and exit. @@ -47,12 +47,12 @@ And the `--help` option will combine all the information: $ python main.py --help // Notice that we have the help text from the docstring and also the Arguments 📝 -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. Arguments: - NAME The name of the user to greet [required] + name The name of the user to greet [required] Options: --help Show this message and exit. @@ -74,12 +74,12 @@ It will show that default value in the help text: $ python main.py --help // Notice the [default: World] 🔍 -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. Arguments: - [NAME] Who to greet [default: World] + name Who to greet [default: World] Options: --help Show this message and exit. @@ -99,12 +99,12 @@ And then it won't show the default value: $ python main.py --help // Notice the there's no [default: World] now 🔥 -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. Arguments: - [NAME] Who to greet + name Who to greet Options: --help Show this message and exit. @@ -125,10 +125,10 @@ And it will be used in the help text: ```console $ python main.py --help -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] Who to greet [default: (Deadpoolio the amazing's name)] + name Who to greet [default: (Deadpoolio the amazing's name)] Options: @@ -143,7 +143,7 @@ Options: You can also customize the text used in the generated help text to represent a *CLI argument*. -By default, it will be the same name you declared, in uppercase letters. +By default, it will be the same name you declared, with casing preserved. So, if you declare it as: @@ -154,16 +154,16 @@ name: str It will be shown as: ``` -NAME +name ``` But you can customize it with the `metavar` parameter for `typer.Argument()`. -For example, let's say you don't want to have the default of `NAME`, you want to have `username`, in lowercase, and you really want ✨ emojis ✨ everywhere: +For example, let's say you don't want to have the default of `name`, you want to have `username`, and you really want ✨ emojis ✨ everywhere: {* docs_src/arguments/help/tutorial006_an_py310.py hl[9] *} -Now the generated help text will have `✨username✨` instead of `NAME`: +Now the generated help text will have `✨username✨` instead of `name`:
@@ -173,7 +173,7 @@ $ python main.py --help Usage: main.py [OPTIONS] [✨username✨] Arguments: - [✨username✨] [default: World] + ✨username✨ [default: World] Options: --help Show this message and exit. @@ -198,16 +198,16 @@ And next you will see other panels for the *CLI arguments* that have a custom pa ```console $ python main.py --help - Usage: main.py [OPTIONS] NAME [LASTNAME] [AGE] + Usage: main.py [OPTIONS] {name} [lastname] [age] - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* name TEXT Who to greet [default: None] [required] │ +* name str Who to greet [default: None] [required]╰───────────────────────────────────────────────────────────────────╯ ╭─ Secondary Arguments ─────────────────────────────────────────────╮ -│ lastname [LASTNAME] The last name │ -│ age [AGE] The user's age │ +│ lastname lastname The last name │ +│ age age The user's age │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ --help Show this message and exit. │ @@ -240,9 +240,9 @@ Check it: $ python main.py --help // Notice there's no Arguments section at all 🔥 -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. Options: --help Show this message and exit. diff --git a/docs/tutorial/arguments/optional.md b/docs/tutorial/arguments/optional.md index 10b03af7b0..cda10c46e9 100644 --- a/docs/tutorial/arguments/optional.md +++ b/docs/tutorial/arguments/optional.md @@ -84,10 +84,10 @@ All we did there achieves the same thing as before, a **required** *CLI argument ```console $ python main.py -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Try "main.py --help" for help. -Error: Missing argument 'NAME'. +Error: Missing argument 'name'. ```
@@ -132,10 +132,10 @@ Check the help: // First check the help $ python main.py --help -Usage: main.py [OPTIONS] [NAME] +Usage: main.py [OPTIONS] [name] Arguments: - [NAME] + name [default: World] Options: --help Show this message and exit. @@ -145,9 +145,9 @@ Options: /// tip -Notice that `NAME` is still a *CLI argument*, it's shown up there in the "`Usage: main.py` ...". +Notice that `name` is still a *CLI argument*, it's shown up there in the "`Usage: main.py` ...". -Also notice that now `[NAME]` has brackets ("`[`" and "`]`") around (before it was just `NAME`) to denote that it's **optional**, not **required**. +Also notice that now `[name]` has rectangular brackets ("`[`" and "`]`") around it to denote that it's **optional**, not **required**. If it would have been required, curly brackets ("`{`" and "`}`") would be used instead. /// diff --git a/docs/tutorial/commands/arguments.md b/docs/tutorial/commands/arguments.md index a20fd82d51..d6bbb61824 100644 --- a/docs/tutorial/commands/arguments.md +++ b/docs/tutorial/commands/arguments.md @@ -10,7 +10,10 @@ The same way as with a CLI application with a single command, subcommands (or ju // Check the help for create $ python main.py create --help -Usage: main.py create [OPTIONS] USERNAME +Usage: main.py create [OPTIONS] {username} + +Arguments: + username [required] Options: --help Show this message and exit. diff --git a/docs/tutorial/commands/callback.md b/docs/tutorial/commands/callback.md index c3db29887a..2d3488de5e 100644 --- a/docs/tutorial/commands/callback.md +++ b/docs/tutorial/commands/callback.md @@ -40,7 +40,7 @@ Usage: main.py [OPTIONS] COMMAND [ARGS]... Manage users in the awesome CLI app. Options: - --verbose / --no-verbose [default: False] + --verbose / --no-verbose [default: no-verbose] --install-completion Install completion for the current shell. --show-completion Show completion for the current shell, to copy it or customize the installation. --help Show this message and exit. @@ -67,7 +67,7 @@ Just created a user // Notice that --verbose belongs to the callback, it has to go before create or delete ⛔️ $ python main.py create --verbose Camila -Usage: main.py create [OPTIONS] USERNAME +Usage: main.py create [OPTIONS] {username} Try "main.py create --help" for help. Error: No such option: --verbose @@ -142,7 +142,7 @@ Usage: main.py [OPTIONS] COMMAND [ARGS]... Use it with the create command. - A new user with the given NAME will be created. + A new user with the given 'name' will be created. Options: --install-completion Install completion for the current shell. diff --git a/docs/tutorial/commands/help.md b/docs/tutorial/commands/help.md index 359339bb78..908ce51c70 100644 --- a/docs/tutorial/commands/help.md +++ b/docs/tutorial/commands/help.md @@ -24,8 +24,8 @@ Options: --help Show this message and exit. Commands: - create Create a new user with USERNAME. - delete Delete a user with USERNAME. + create Create a new user with username. + delete Delete a user with username. delete-all Delete ALL users in the database. init Initialize the users database. @@ -34,9 +34,12 @@ Commands: // Check the help for create $ python main.py create --help -Usage: main.py create [OPTIONS] USERNAME +Usage: main.py create [OPTIONS] {username} - Create a new user with USERNAME. + Create a new user with username. + +Arguments: + username [required] Options: --help Show this message and exit. @@ -44,12 +47,15 @@ Options: // Check the help for delete $ python main.py delete --help -Usage: main.py delete [OPTIONS] USERNAME +Usage: main.py delete [OPTIONS] {username} - Delete a user with USERNAME. + Delete a user with username. If --force is not used, will ask for confirmation. +Arguments: + username [required] + Options: --force / --no-force Force deletion without confirmation. [required] --help Show this message and exit. @@ -112,10 +118,10 @@ Options: --help Show this message and exit. Commands: - create Create a new user with USERNAME. - delete Delete a user with USERNAME. + create Create a new user with username. + delete Delete a user with username. -// It uses "Create a new user with USERNAME." instead of "Some internal utility function to create." +// It uses "Create a new user with username." instead of "Some internal utility function to create." ``` @@ -160,14 +166,14 @@ And if you check the `--help` for the deprecated command (in this example, the c ```console $ python main.py delete --help - Usage: main.py delete [OPTIONS] USERNAME + Usage: main.py delete [OPTIONS] {username} (deprecated) Delete a user. This is deprecated and will stop being supported soon. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT [default: None] [required] │ +* username <str> [required]╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ --help Show this message and exit. │ @@ -232,14 +238,13 @@ Check the help for the `create` command: ```console $ python main.py create --help - Usage: main.py create [OPTIONS] USERNAME + Usage: main.py create [OPTIONS] {username} Create a new shiny user. ✨ This requires a username. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT The username to be created │ -│ [default: None] │ +* username <str> The username to be created[required] ╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ @@ -256,13 +261,12 @@ And check the help for the `delete` command: ```console $ python main.py delete --help - Usage: main.py delete [OPTIONS] USERNAME + Usage: main.py delete [OPTIONS] {username} - Delete a user with USERNAME. + Delete a user with username. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT The username to be deleted │ -│ [default: None] │ +* username <str> The username to be deleted[required] ╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ @@ -291,7 +295,7 @@ Check the help for the `create` command: ```console $ python main.py create --help - Usage: main.py create [OPTIONS] USERNAME + Usage: main.py create [OPTIONS] {username} Create a new shiny user. ✨ @@ -302,8 +306,7 @@ $ python main.py create --help Learn more at the Typer docs website ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT The username to be created │ -│ [default: None] │ +* username <str> The username to be created[required] ╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ @@ -320,13 +323,12 @@ And the same for the `delete` command: ```console $ python main.py delete --help - Usage: main.py delete [OPTIONS] USERNAME + Usage: main.py delete [OPTIONS] {username} - Delete a user with USERNAME. + Delete a user with username. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT The username to be deleted │ -│ [default: None] │ +* username <str> The username to be deleted[required] ╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ @@ -378,8 +380,8 @@ $ python main.py --help delete Delete a user. ❌ │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Utils and Configs ───────────────────────────────────────────────╮ -config Configure the system. ⚙ │ -sync Synchronize the system or something fancy like that. ♻ │ +config Configure the system. ⚙ │ +sync Synchronize the system or something fancy like that. ♻ │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Help and Others ─────────────────────────────────────────────────╮ help Get help with the system. ❓ │ @@ -411,16 +413,16 @@ You can check the `--help` option for the command `create`: ```console $ python main.py create --help - Usage: main.py create [OPTIONS] USERNAME [LASTNAME] + Usage: main.py create [OPTIONS] {username} [lastname] Create a new user. ✨ ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT The username to create [default: None] │ +* username <str> The username to create │ [required] ╰───────────────────────────────────────────────────────────────────╯ ╭─ Secondary Arguments ─────────────────────────────────────────────╮ -│ lastname [LASTNAME] The last name of the new user │ +│ lastname lastname The last name of the new user │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ --force --no-force Force the creation of the user │ @@ -428,11 +430,9 @@ $ python main.py create --help --help Show this message and exit. │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Additional Data ─────────────────────────────────────────────────╮ ---age INTEGER The age of the new user │ -│ [default: None] │ ---favorite-color TEXT The favorite color of the new │ +--age <int> The age of the new user │ +--favorite-color <str> The favorite color of the new │ │ user │ -│ [default: None] │ ╰───────────────────────────────────────────────────────────────────╯ ``` @@ -461,7 +461,7 @@ $ python main.py --help create Create a new user. ✨ │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Utils and Configs ───────────────────────────────────────────────╮ -config Configure the system. ⚙ │ +config Configure the system. ⚙ │ ╰───────────────────────────────────────────────────────────────────╯ ``` @@ -482,12 +482,12 @@ And when you check the `--help` option it will look like: ```console $ python main.py --help - Usage: main.py [OPTIONS] USERNAME + Usage: main.py [OPTIONS] {username} Create a new user. ✨ ╭─ Arguments ───────────────────────────────────────────────────────╮ -* username TEXT [default: None] [required] │ +* username <str> [required]╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ --install-completion Install completion for the current │ diff --git a/docs/tutorial/commands/one-or-multiple.md b/docs/tutorial/commands/one-or-multiple.md index 96f5e3a7de..976ede4d96 100644 --- a/docs/tutorial/commands/one-or-multiple.md +++ b/docs/tutorial/commands/one-or-multiple.md @@ -12,20 +12,20 @@ You might have noticed that if you create a single command, as in the following // Without a CLI argument $ python main.py -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Try "main.py --help" for help. -Error: Missing argument 'NAME'. +Error: Missing argument 'name'. -// With the NAME CLI argument +// With the 'name' CLI argument $ python main.py Camila Hello Camila // Asking for help -$ python main.py +$ python main.py --help -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Options: --install-completion Install completion for the current shell. diff --git a/docs/tutorial/first-steps.md b/docs/tutorial/first-steps.md index cf1db2d522..c7b088157b 100644 --- a/docs/tutorial/first-steps.md +++ b/docs/tutorial/first-steps.md @@ -70,13 +70,13 @@ Update the previous example with an argument `name`: $ python main.py // If you run it without the argument, it shows a nice error -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Try 'main.py --help' for help. ╭─ Error ───────────────────────────────────────────╮ - Missing argument 'NAME'. + Missing argument 'name'. ╰───────────────────────────────────────────────────╯ -// Now pass that NAME CLI argument +// Now pass that 'name' CLI argument $ python main.py Camila Hello Camila @@ -111,29 +111,26 @@ So, extend that to have 2 arguments, `name` and `lastname`: // Check the main --help $ python main.py --help -Usage: main.py [OPTIONS] NAME -Try 'main.py --help' for help. -╭─ Error ───────────────────────────────────────────╮ - Missing argument 'NAME'. -╰───────────────────────────────────────────────────╯ - -typer on  richify [»!?] via 🐍 v3.7.5 (env3.7) - python main.py -Usage: main.py [OPTIONS] NAME LASTNAME -Try 'main.py --help' for help. -╭─ Error ───────────────────────────────────────────╮ - Missing argument 'NAME'. -╰───────────────────────────────────────────────────╯ + Usage: main.py [OPTIONS] {name} {lastname} + +╭─ Arguments ─────────────────────────────────────────────────────╮ +* name <str> [required] │ +* lastname <str> [required] │ +╰─────────────────────────────────────────────────────────────────╯ +╭─ Options ───────────────────────────────────────────────────────╮ +--help Show this message and │ +│ exit. │ +╰─────────────────────────────────────────────────────────────────╯ // There are now 2 CLI arguments, name and lastname // Now pass a single name argument $ python main.py Camila -Usage: main.py [OPTIONS] NAME LASTNAME +Usage: main.py [OPTIONS] {name} {lastname} Try 'main.py --help' for help. ╭─ Error ───────────────────────────────────────────╮ - Missing argument 'LASTNAME'. + Missing argument 'lastname'. ╰───────────────────────────────────────────────────╯ // These 2 arguments are required, so, pass both: @@ -238,11 +235,11 @@ Here `formal` is a `bool` that is `False` by default. // Get the help $ python main.py --help - Usage: main.py [OPTIONS] NAME LASTNAME + Usage: main.py [OPTIONS] {name} {lastname} ╭─ Arguments ─────────────────────────────────────────────────────╮ -* name TEXT [default: None] [required] │ -* lastname TEXT [default: None] [required] │ +* name <str> [required] │ +* lastname <str> [required]╰─────────────────────────────────────────────────────────────────╯ ╭─ Options ───────────────────────────────────────────────────────╮ --formal --no-formal [default: no-formal] │ @@ -298,13 +295,13 @@ As `lastname` now has a default value of `""` (an empty string) it is no longer ```console $ python main.py --help - Usage: main.py [OPTIONS] NAME + Usage: main.py [OPTIONS] {name} ╭─ Arguments ───────────────────────────────────────────────────────╮ -* name TEXT [default: None] [required] │ +* name <str> [required]╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ ---lastname TEXT │ +--lastname <str>--formal --no-formal [default: no-formal] │ --help Show this message │ │ and exit. │ @@ -369,16 +366,16 @@ Now see it with the `--help` option: ```console $ python main.py --help - Usage: main.py [OPTIONS] NAME + Usage: main.py [OPTIONS] {name} - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* name TEXT [default: None] [required] │ +* name <str> [required]╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ ---lastname TEXT │ +--lastname <str>--formal --no-formal [default: no-formal] │ --help Show this message │ │ and exit. │ diff --git a/docs/tutorial/multiple-values/arguments-with-multiple-values.md b/docs/tutorial/multiple-values/arguments-with-multiple-values.md index 2446974667..8a178f4d37 100644 --- a/docs/tutorial/multiple-values/arguments-with-multiple-values.md +++ b/docs/tutorial/multiple-values/arguments-with-multiple-values.md @@ -47,10 +47,10 @@ Check it: // Check the help $ python main.py --help -Usage: main.py [OPTIONS] [NAMES]... +Usage: main.py [OPTIONS] [names]... Arguments: - [NAMES]... Select 3 characters to play with [default: Harry, Hermione, Ron] + names... Select 3 characters to play with [default: Harry, Hermione, Ron] Options: --help Show this message and exit. diff --git a/docs/tutorial/multiple-values/options-with-multiple-values.md b/docs/tutorial/multiple-values/options-with-multiple-values.md index 75b253c4ca..29753eac7c 100644 --- a/docs/tutorial/multiple-values/options-with-multiple-values.md +++ b/docs/tutorial/multiple-values/options-with-multiple-values.md @@ -58,12 +58,12 @@ Now let's see how this works in the terminal: // check the help $ python main.py --help -// Notice the <TEXT INTEGER BOOLEAN> +// Notice the Usage: main.py [OPTIONS] Options: - --user <TEXT INTEGER BOOLEAN>... - --help Show this message and exit. + --user ... + --help Show this message and exit. // Now try it $ python main.py --user Camila 50 yes diff --git a/docs/tutorial/one-file-per-command.md b/docs/tutorial/one-file-per-command.md index 82fc744d69..d9ac0c9b51 100644 --- a/docs/tutorial/one-file-per-command.md +++ b/docs/tutorial/one-file-per-command.md @@ -7,8 +7,8 @@ This tutorial will show you how to use `add_typer` to create sub commands and or We will create a simple CLI with the following commands: - `version` -- `users add NAME` -- `users delete NAME` +- `users add 'name'` +- `users delete 'name'` ## CLI structure diff --git a/docs/tutorial/options/callback-and-context.md b/docs/tutorial/options/callback-and-context.md index 53d87ddaf0..cdccd13e7c 100644 --- a/docs/tutorial/options/callback-and-context.md +++ b/docs/tutorial/options/callback-and-context.md @@ -61,12 +61,12 @@ utils -- Extra utility commands for Typer apps. $ typer ./main.py run --help // You get a help text with your CLI options as you normally would -Usage: typer run [OPTIONS] +Usage: typer [PATH_OR_MODULE] run [OPTIONS] Run the provided Typer app. Options: - --name TEXT [required] + --name --help Show this message and exit. // Then try completion with your program diff --git a/docs/tutorial/options/help.md b/docs/tutorial/options/help.md index c2a115796f..4104077964 100644 --- a/docs/tutorial/options/help.md +++ b/docs/tutorial/options/help.md @@ -31,18 +31,18 @@ Test it: ```console $ python main.py --help -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. Arguments: - NAME [required] + name [required] Options: - --lastname TEXT Last name of person to greet. [default: ] - --formal / --no-formal Say hi formally. [default: False] + --lastname Last name of person to greet. + --formal / --no-formal Say hi formally. [default: no-formal] --help Show this message and exit. // Now you have a help text for the --lastname and --formal CLI options 🎉 @@ -67,16 +67,16 @@ And below you will see other panels for the *CLI options* that have a custom pan ```console $ python main.py --help - Usage: main.py [OPTIONS] NAME + Usage: main.py [OPTIONS] {name} - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. ╭─ Arguments ───────────────────────────────────────────────────────╮ -* name TEXT [default: None] [required] │ +* name <str> [required]╰───────────────────────────────────────────────────────────────────╯ ╭─ Options ─────────────────────────────────────────────────────────╮ ---lastname TEXT Last name of person to greet. │ +--lastname <str> Last name of person to greet. │ --help Show this message and exit. │ ╰───────────────────────────────────────────────────────────────────╯ ╭─ Customization and Utils ─────────────────────────────────────────╮ @@ -119,7 +119,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - --fullname TEXT + --fullname --help Show this message and exit. // Notice there's no [default: Wade Wilson] 🔥 @@ -148,7 +148,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - --fullname TEXT [default: (Deadpoolio the amazing's name)] + --fullname [default: (Deadpoolio the amazing's name)] --help Show this message and exit. // Notice how it shows "(Deadpoolio the amazing's name)" instead of the actual default of "Wade Wilson" diff --git a/docs/tutorial/options/name.md b/docs/tutorial/options/name.md index 621735f7e0..031c3ec431 100644 --- a/docs/tutorial/options/name.md +++ b/docs/tutorial/options/name.md @@ -53,7 +53,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - --name TEXT [required] + --name [required] --help Show this message and exit. // Try it @@ -201,7 +201,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - -n, --name TEXT [required] + -n, --name [required] --help Show this message and exit. // Try the short version @@ -229,7 +229,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - -n TEXT [required] + -n [required] --help Show this message and exit. // Try it @@ -258,7 +258,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - -n, --user-name TEXT [required] + -n, --user-name [required] --help Show this message and exit. // Try it @@ -298,7 +298,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - -n, --name TEXT [required] + -n, --name [required] -f, --formal --help Show this message and exit. diff --git a/docs/tutorial/options/prompt.md b/docs/tutorial/options/prompt.md index 6919e17980..09156f4cb5 100644 --- a/docs/tutorial/options/prompt.md +++ b/docs/tutorial/options/prompt.md @@ -9,7 +9,7 @@ And then your program will ask the user for it in the terminal:
```console -// Call it with the NAME CLI argument +// Call it with the 'name' CLI argument $ python main.py Camila // It asks for the missing CLI option --lastname @@ -31,7 +31,7 @@ And then your program will ask for it using with your custom prompt:
```console -// Call it with the NAME CLI argument +// Call it with the 'name' CLI argument $ python main.py Camila // It uses the custom prompt diff --git a/docs/tutorial/options/required.md b/docs/tutorial/options/required.md index a702bbaa80..24aa4c7df5 100644 --- a/docs/tutorial/options/required.md +++ b/docs/tutorial/options/required.md @@ -42,11 +42,11 @@ And test it:
```console -// Pass the NAME CLI argument +// Pass the 'name' CLI argument $ python main.py Camila // We didn't pass the now required --lastname CLI option -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Try "main.py --help" for help. Error: Missing option '--lastname'. @@ -59,10 +59,13 @@ Hello Camila Gutiérrez // And if you check the help $ python main.py --help -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} + +Arguments: + name [required] Options: - --lastname TEXT [required] + --lastname [required] --help Show this message and exit. // It now tells you that --lastname is required 🎉 diff --git a/docs/tutorial/options/version.md b/docs/tutorial/options/version.md index 609c3978fc..9b4303182d 100644 --- a/docs/tutorial/options/version.md +++ b/docs/tutorial/options/version.md @@ -34,7 +34,7 @@ Usage: main.py [OPTIONS] Options: --version - --name TEXT + --name [default: World] --help Show this message and exit. diff --git a/docs/tutorial/parameter-types/bool.md b/docs/tutorial/parameter-types/bool.md index dc98b30c79..072d83dbca 100644 --- a/docs/tutorial/parameter-types/bool.md +++ b/docs/tutorial/parameter-types/bool.md @@ -24,7 +24,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - --force [default: False] + --force --help Show this message and exit. // Try it: @@ -113,7 +113,7 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - -f, --force / -F, --no-force [default: False] + -f, --force / -F, --no-force [default: no-force] --help Show this message and exit. // Try with the short name -f diff --git a/docs/tutorial/parameter-types/datetime.md b/docs/tutorial/parameter-types/datetime.md index 4b685a3cf1..7b7756cc91 100644 --- a/docs/tutorial/parameter-types/datetime.md +++ b/docs/tutorial/parameter-types/datetime.md @@ -19,10 +19,10 @@ Check it: ```console $ python main.py --help -Usage: main.py [OPTIONS] BIRTH:[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S] +Usage: main.py [OPTIONS] {birth}:<%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S> Arguments: - BIRTH:[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S][required] + birth:<%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S> [required] Options: --help Show this message and exit. @@ -36,9 +36,10 @@ Birth hour: 10 // An invalid date $ python main.py july-19-1989 -Usage: main.py [OPTIONS] [%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d%H:%M:%S] +Usage: main.py [OPTIONS] {birth}:<%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S> +Try 'main.py --help' for help. -Error: Invalid value for 'BIRTH:[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]': 'july-19-1989' does not match the formats '%Y-%m-%d', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d %H:%M:%S'. +Error: Invalid value for 'birth': 'july-19-1989' does not match the formats '%Y-%m-%d', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d %H:%M:%S'. ```
diff --git a/docs/tutorial/parameter-types/enum.md b/docs/tutorial/parameter-types/enum.md index 185ad420c3..bfa5d53aee 100644 --- a/docs/tutorial/parameter-types/enum.md +++ b/docs/tutorial/parameter-types/enum.md @@ -19,11 +19,11 @@ Check it: ```console $ python main.py --help -// Notice the predefined values [simple|conv|lstm] +// Notice the predefined values Usage: main.py [OPTIONS] Options: - --network [simple|conv|lstm] [default: simple] + --network [default: simple] --help Show this message and exit. // Try it @@ -91,8 +91,8 @@ $ python main.py --help Usage: main.py [OPTIONS] Options: - --groceries [Eggs|Bacon|Cheese] [default: Eggs, Cheese] - --help Show this message and exit. + --groceries [default: Eggs, Cheese] + --help Show this message and exit. // Try it with the default values $ python main.py @@ -123,11 +123,11 @@ You can also use `Literal` to represent a set of possible predefined choices, wi ```console $ python main.py --help -// Notice the predefined values [simple|conv|lstm] +// Notice the predefined values Usage: main.py [OPTIONS] Options: - --network [simple|conv|lstm] [default: simple] + --network [default: simple] --help Show this message and exit. // Try it diff --git a/docs/tutorial/parameter-types/index.md b/docs/tutorial/parameter-types/index.md index ffeb1e88e8..88ebe45dfe 100644 --- a/docs/tutorial/parameter-types/index.md +++ b/docs/tutorial/parameter-types/index.md @@ -10,7 +10,7 @@ For example: {* docs_src/parameter_types/index/tutorial001_py310.py hl[7] *} -In this example, the value received for the *CLI argument* `NAME` will be treated as `str`. +In this example, the value received for the *CLI argument* `name` will be treated as `str`. The value for the *CLI option* `--age` will be converted to an `int` and `--height-meters` will be converted to a `float`. @@ -23,23 +23,23 @@ And here's how it looks like: ```console $ python main.py --help -// Notice how --age is an INTEGER and --height-meters is a FLOAT -Usage: main.py [OPTIONS] NAME +// Notice how --age is an 'int' (integer) and --height-meters is a 'float' +Usage: main.py [OPTIONS] {name} Arguments: - NAME [required] + name [required] Options: - --age INTEGER [default: 20] - --height-meters FLOAT [default: 1.89] - --female / --no-female [default: True] - --help Show this message and exit. + --age [default: 20] + --height-meters [default: 1.89] + --female / --no-female [default: female] + --help Show this message and exit. // Call it with CLI parameters $ python main.py Camila --age 15 --height-meters 1.70 --female // All the data has the correct Python type -NAME is Camila, of type: class 'str' +name is Camila, of type: class 'str' --age is 15, of type: class 'int' --height-meters is 1.7, of type: class 'float' --female is True, of type: class 'bool' @@ -47,12 +47,12 @@ NAME is Camila, of type: class 'str' // And if you pass an incorrect type $ python main.py Camila --age 15.3 -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Try "main.py --help" for help. -Error: Invalid value for '--age': '15.3' is not a valid integer +Error: Invalid value for '--age': '15.3' is not a valid int. -// Because 15.3 is not an INTEGER (it's a float) +// Because 15.3 is not an integer (it's a float) ```
diff --git a/docs/tutorial/parameter-types/number.md b/docs/tutorial/parameter-types/number.md index 6ea91bb1b1..2e2da4a9e8 100644 --- a/docs/tutorial/parameter-types/number.md +++ b/docs/tutorial/parameter-types/number.md @@ -15,16 +15,16 @@ Check it: ```console $ python main.py --help -// Notice the extra RANGE in the help text for --age and --score -Usage: main.py [OPTIONS] ID +// Notice the extra range information in the help text for --age and --score +Usage: main.py [OPTIONS] {ID} Arguments: ID [required] Options: - --age INTEGER RANGE [default: 20] - --score FLOAT RANGE [default: 0] - --help Show this message and exit. + --age [default: 20; x>=18] + --score [default: 0; x<=100] + --help Show this message and exit. // Pass all the CLI parameters $ python main.py 5 --age 20 --score 90 @@ -36,7 +36,7 @@ ID is 5 // Pass an invalid ID $ python main.py 1002 -Usage: main.py [OPTIONS] ID +Usage: main.py [OPTIONS] {ID} Try "main.py --help" for help. Error: Invalid value for 'ID': 1002 is not in the range 0<=x<=1000. @@ -44,7 +44,7 @@ Error: Invalid value for 'ID': 1002 is not in the range 0<=x<=1000. // Pass an invalid age $ python main.py 5 --age 15 -Usage: main.py [OPTIONS] ID +Usage: main.py [OPTIONS] {ID} Try "main.py --help" for help. Error: Invalid value for '--age': 15 is not in the range x>=18. @@ -52,7 +52,7 @@ Error: Invalid value for '--age': 15 is not in the range x>=18. // Pass an invalid score $ python main.py 5 --age 20 --score 100.5 -Usage: main.py [OPTIONS] ID +Usage: main.py [OPTIONS] {ID} Try "main.py --help" for help. Error: Invalid value for '--score': 100.5 is not in the range x<=100. @@ -83,7 +83,7 @@ And then, when you pass data that is out of the valid range, it will be "clamped // ID doesn't have clamp, so it shows an error $ python main.py 1002 -Usage: main.py [OPTIONS] ID +Usage: main.py [OPTIONS] {ID} Try "main.py --help" for help. Error: Invalid value for 'ID': 1002 is not in the range 0<=x<=1000. diff --git a/docs/tutorial/parameter-types/path.md b/docs/tutorial/parameter-types/path.md index e2d8177210..dcaada8969 100644 --- a/docs/tutorial/parameter-types/path.md +++ b/docs/tutorial/parameter-types/path.md @@ -16,8 +16,8 @@ Check it: // No config $ python main.py +Aborted. No config file -Aborted! // Pass a config that doesn't exist $ python main.py --config config.txt diff --git a/docs/tutorial/parameter-types/uuid.md b/docs/tutorial/parameter-types/uuid.md index 8de1ef1bf4..187a79b0e7 100644 --- a/docs/tutorial/parameter-types/uuid.md +++ b/docs/tutorial/parameter-types/uuid.md @@ -34,16 +34,16 @@ Check it: // Pass a valid UUID v4 $ python main.py d48edaa6-871a-4082-a196-4daab372d4a1 -USER_ID is d48edaa6-871a-4082-a196-4daab372d4a1 +User ID is d48edaa6-871a-4082-a196-4daab372d4a1 UUID version is: 4 // An invalid value $ python main.py 7479706572-72756c6573 -Usage: main.py [OPTIONS] USER_ID +Usage: main.py [OPTIONS] {user_id} Try "main.py --help" for help. -Error: Invalid value for 'USER_ID': 7479706572-72756c6573 is not a valid UUID. +Error: Invalid value for 'user_id': 7479706572-72756c6573 is not a valid UUID. ```
diff --git a/docs/tutorial/subcommands/add-typer.md b/docs/tutorial/subcommands/add-typer.md index a945c04466..c8d77ad596 100644 --- a/docs/tutorial/subcommands/add-typer.md +++ b/docs/tutorial/subcommands/add-typer.md @@ -84,8 +84,8 @@ Options: --help Show this message and exit. Commands: - items users + items ``` diff --git a/docs/tutorial/subcommands/nested-subcommands.md b/docs/tutorial/subcommands/nested-subcommands.md index 78a116b06a..13e5a7dc94 100644 --- a/docs/tutorial/subcommands/nested-subcommands.md +++ b/docs/tutorial/subcommands/nested-subcommands.md @@ -67,8 +67,8 @@ Options: --help Show this message and exit. Commands: - burn found + burn // Try it $ python towns.py found "New Asgard" @@ -130,8 +130,8 @@ Options: --help Show this message and exit. Commands: - burn found + burn ``` @@ -205,9 +205,9 @@ Options: --help Show this message and exit. Commands: + users items lands - users // Try some users commands $ python main.py users create Camila diff --git a/docs/tutorial/typer-app.md b/docs/tutorial/typer-app.md index 29ff2f6812..f095a2e19b 100644 --- a/docs/tutorial/typer-app.md +++ b/docs/tutorial/typer-app.md @@ -51,12 +51,12 @@ If you run the second example, with the explicit `app`, it works exactly the sam // Without a CLI argument $ python main.py -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} Try "main.py --help" for help. -Error: Missing argument 'NAME'. +Error: Missing argument 'name'. -// With the NAME CLI argument +// With the 'name' CLI argument $ python main.py Camila Hello Camila @@ -64,7 +64,10 @@ Hello Camila // Asking for help $ python main.py --help -Usage: main.py [OPTIONS] NAME +Usage: main.py [OPTIONS] {name} + +Arguments: + name [required] Options: --install-completion Install completion for the current shell. diff --git a/docs/tutorial/typer-command.md b/docs/tutorial/typer-command.md index 5c416a22b6..0c7884bc3c 100644 --- a/docs/tutorial/typer-command.md +++ b/docs/tutorial/typer-command.md @@ -169,13 +169,13 @@ Then you can call it with: ```console $ typer main.py run --help -Usage: typer run [OPTIONS] +Usage: typer [PATH_OR_MODULE] run [OPTIONS] Say hi to someone, by default to the World. Options: - --name TEXT - --help Show this message and exit. + --name [default: World] + --help Show this message and exit. $ typer main.py run --name Camila @@ -196,10 +196,10 @@ For example: ```console $ typer my_package.main run --help -Usage: typer run [OPTIONS] +Usage: typer [PATH_OR_MODULE] run [OPTIONS] Options: - --name TEXT + --name --help Show this message and exit. $ typer my_package.main run --name Camila @@ -265,9 +265,9 @@ $ python -m typer some_script.py utils docs **Options**: -* `--name TEXT`: The name of the CLI program to use in docs. -* `--output FILE`: An output file to write docs to, like README.md. -* `--title TEXT`: A title to use in the docs, by default the name of the command. +* `--name `: The name of the CLI program to use in docs. +* `--output `: An output file to write docs to, like README.md. +* `--title `: A title to use in the docs, by default the name of the command. For example: @@ -305,19 +305,19 @@ $ awesome-cli [OPTIONS] COMMAND [ARGS]... **Commands**: -* `create`: Create a new user with USERNAME. -* `delete`: Delete a user with USERNAME. +* `create`: Create a new user with username. +* `delete`: Delete a user with username. * `delete-all`: Delete ALL users in the database. * `init`: Initialize the users database. ## `awesome-cli create` -Create a new user with USERNAME. +Create a new user with username. **Usage**: ```console -$ awesome-cli create [OPTIONS] USERNAME +$ awesome-cli create [OPTIONS] {username} ``` **Options**: @@ -326,14 +326,14 @@ $ awesome-cli create [OPTIONS] USERNAME ## `awesome-cli delete` -Delete a user with USERNAME. +Delete a user with 'username'. If --force is not used, will ask for confirmation. **Usage**: ```console -$ awesome-cli delete [OPTIONS] USERNAME +$ awesome-cli delete [OPTIONS] {username} ``` **Options**: diff --git a/docs_src/arguments/help/tutorial002_an_py310.py b/docs_src/arguments/help/tutorial002_an_py310.py index 3f029018fb..7fd2b70dbc 100644 --- a/docs_src/arguments/help/tutorial002_an_py310.py +++ b/docs_src/arguments/help/tutorial002_an_py310.py @@ -8,7 +8,7 @@ @app.command() def main(name: Annotated[str, typer.Argument(help="The name of the user to greet")]): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial002_py310.py b/docs_src/arguments/help/tutorial002_py310.py index 27fd086151..11098b1085 100644 --- a/docs_src/arguments/help/tutorial002_py310.py +++ b/docs_src/arguments/help/tutorial002_py310.py @@ -6,7 +6,7 @@ @app.command() def main(name: str = typer.Argument(..., help="The name of the user to greet")): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial003_an_py310.py b/docs_src/arguments/help/tutorial003_an_py310.py index 6dbc67e04e..ef8441f2f5 100644 --- a/docs_src/arguments/help/tutorial003_an_py310.py +++ b/docs_src/arguments/help/tutorial003_an_py310.py @@ -8,7 +8,7 @@ @app.command() def main(name: Annotated[str, typer.Argument(help="Who to greet")] = "World"): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial003_py310.py b/docs_src/arguments/help/tutorial003_py310.py index 3c6c45061e..183cf318da 100644 --- a/docs_src/arguments/help/tutorial003_py310.py +++ b/docs_src/arguments/help/tutorial003_py310.py @@ -6,7 +6,7 @@ @app.command() def main(name: str = typer.Argument("World", help="Who to greet")): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial004_an_py310.py b/docs_src/arguments/help/tutorial004_an_py310.py index fc4e06f6f1..b926ccadd7 100644 --- a/docs_src/arguments/help/tutorial004_an_py310.py +++ b/docs_src/arguments/help/tutorial004_an_py310.py @@ -12,7 +12,7 @@ def main( ] = "World", ): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial004_py310.py b/docs_src/arguments/help/tutorial004_py310.py index e6afb9c855..ef4bcfee9b 100644 --- a/docs_src/arguments/help/tutorial004_py310.py +++ b/docs_src/arguments/help/tutorial004_py310.py @@ -6,7 +6,7 @@ @app.command() def main(name: str = typer.Argument("World", help="Who to greet", show_default=False)): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial007_an_py310.py b/docs_src/arguments/help/tutorial007_an_py310.py index 3a49db9034..a0585678f8 100644 --- a/docs_src/arguments/help/tutorial007_an_py310.py +++ b/docs_src/arguments/help/tutorial007_an_py310.py @@ -17,7 +17,7 @@ def main( ] = "", ): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial007_py310.py b/docs_src/arguments/help/tutorial007_py310.py index d5437028f5..a6924b2363 100644 --- a/docs_src/arguments/help/tutorial007_py310.py +++ b/docs_src/arguments/help/tutorial007_py310.py @@ -14,7 +14,7 @@ def main( ), ): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial008_an_py310.py b/docs_src/arguments/help/tutorial008_an_py310.py index b1a3ee62c9..0db231345f 100644 --- a/docs_src/arguments/help/tutorial008_an_py310.py +++ b/docs_src/arguments/help/tutorial008_an_py310.py @@ -8,7 +8,7 @@ @app.command() def main(name: Annotated[str, typer.Argument(hidden=True)] = "World"): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/arguments/help/tutorial008_py310.py b/docs_src/arguments/help/tutorial008_py310.py index 59f6b52c32..4a30cd8c44 100644 --- a/docs_src/arguments/help/tutorial008_py310.py +++ b/docs_src/arguments/help/tutorial008_py310.py @@ -6,7 +6,7 @@ @app.command() def main(name: str = typer.Argument("World", hidden=True)): """ - Say hi to NAME very gently, like Dirk. + Say hi to 'name' very gently, like Dirk. """ print(f"Hello {name}") diff --git a/docs_src/commands/help/tutorial001_an_py310.py b/docs_src/commands/help/tutorial001_an_py310.py index ada94b6239..5ed82b831b 100644 --- a/docs_src/commands/help/tutorial001_an_py310.py +++ b/docs_src/commands/help/tutorial001_an_py310.py @@ -8,7 +8,7 @@ @app.command() def create(username: str): """ - Create a new user with USERNAME. + Create a new user with username. """ print(f"Creating user: {username}") @@ -25,7 +25,7 @@ def delete( ], ): """ - Delete a user with USERNAME. + Delete a user with username. If --force is not used, will ask for confirmation. """ diff --git a/docs_src/commands/help/tutorial001_py310.py b/docs_src/commands/help/tutorial001_py310.py index 90726a0b13..cc767ce2cc 100644 --- a/docs_src/commands/help/tutorial001_py310.py +++ b/docs_src/commands/help/tutorial001_py310.py @@ -6,7 +6,7 @@ @app.command() def create(username: str): """ - Create a new user with USERNAME. + Create a new user with username. """ print(f"Creating user: {username}") @@ -21,7 +21,7 @@ def delete( ), ): """ - Delete a user with USERNAME. + Delete a user with username. If --force is not used, will ask for confirmation. """ diff --git a/docs_src/commands/help/tutorial002_py310.py b/docs_src/commands/help/tutorial002_py310.py index c3442f071c..4a6b42281c 100644 --- a/docs_src/commands/help/tutorial002_py310.py +++ b/docs_src/commands/help/tutorial002_py310.py @@ -3,7 +3,7 @@ app = typer.Typer() -@app.command(help="Create a new user with USERNAME.") +@app.command(help="Create a new user with username.") def create(username: str): """ Some internal utility function to create. @@ -11,7 +11,7 @@ def create(username: str): print(f"Creating user: {username}") -@app.command(help="Delete a user with USERNAME.") +@app.command(help="Delete a user with username.") def delete(username: str): """ Some internal utility function to delete. diff --git a/docs_src/commands/help/tutorial004_an_py310.py b/docs_src/commands/help/tutorial004_an_py310.py index bdbefcb9e8..da850be178 100644 --- a/docs_src/commands/help/tutorial004_an_py310.py +++ b/docs_src/commands/help/tutorial004_an_py310.py @@ -19,7 +19,7 @@ def create( print(f"Creating user: {username}") -@app.command(help="[bold red]Delete[/bold red] a user with [italic]USERNAME[/italic].") +@app.command(help="[bold red]Delete[/bold red] a user with [italic]username[/italic].") def delete( username: Annotated[ str, typer.Argument(help="The username to be [red]deleted[/red]") diff --git a/docs_src/commands/help/tutorial004_py310.py b/docs_src/commands/help/tutorial004_py310.py index 1e07817329..dacfa5e903 100644 --- a/docs_src/commands/help/tutorial004_py310.py +++ b/docs_src/commands/help/tutorial004_py310.py @@ -17,7 +17,7 @@ def create( print(f"Creating user: {username}") -@app.command(help="[bold red]Delete[/bold red] a user with [italic]USERNAME[/italic].") +@app.command(help="[bold red]Delete[/bold red] a user with [italic]username[/italic].") def delete( username: str = typer.Argument(..., help="The username to be [red]deleted[/red]"), force: bool = typer.Option( diff --git a/docs_src/commands/help/tutorial005_an_py310.py b/docs_src/commands/help/tutorial005_an_py310.py index f01f44189f..19dc48acda 100644 --- a/docs_src/commands/help/tutorial005_an_py310.py +++ b/docs_src/commands/help/tutorial005_an_py310.py @@ -23,7 +23,7 @@ def create( print(f"Creating user: {username}") -@app.command(help="**Delete** a user with *USERNAME*.") +@app.command(help="**Delete** a user with *username*.") def delete( username: Annotated[str, typer.Argument(help="The username to be **deleted**")], force: Annotated[bool, typer.Option(help="Force the **deletion** :boom:")] = False, diff --git a/docs_src/commands/help/tutorial005_py310.py b/docs_src/commands/help/tutorial005_py310.py index 0b577c1c47..a2cc14cf23 100644 --- a/docs_src/commands/help/tutorial005_py310.py +++ b/docs_src/commands/help/tutorial005_py310.py @@ -19,7 +19,7 @@ def create(username: str = typer.Argument(..., help="The username to be **create print(f"Creating user: {username}") -@app.command(help="**Delete** a user with *USERNAME*.") +@app.command(help="**Delete** a user with *username*.") def delete( username: str = typer.Argument(..., help="The username to be **deleted**"), force: bool = typer.Option(False, help="Force the **deletion** :boom:"), diff --git a/docs_src/first_steps/tutorial006_py310.py b/docs_src/first_steps/tutorial006_py310.py index 102ce8d70e..4970833ded 100644 --- a/docs_src/first_steps/tutorial006_py310.py +++ b/docs_src/first_steps/tutorial006_py310.py @@ -3,7 +3,7 @@ def main(name: str, lastname: str = "", formal: bool = False): """ - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. """ diff --git a/docs_src/options/help/tutorial001_an_py310.py b/docs_src/options/help/tutorial001_an_py310.py index 9ae2e34434..0a7f9d0429 100644 --- a/docs_src/options/help/tutorial001_an_py310.py +++ b/docs_src/options/help/tutorial001_an_py310.py @@ -12,7 +12,7 @@ def main( formal: Annotated[bool, typer.Option(help="Say hi formally.")] = False, ): """ - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. """ diff --git a/docs_src/options/help/tutorial001_py310.py b/docs_src/options/help/tutorial001_py310.py index 617d946d55..1b4c0f1178 100644 --- a/docs_src/options/help/tutorial001_py310.py +++ b/docs_src/options/help/tutorial001_py310.py @@ -10,7 +10,7 @@ def main( formal: bool = typer.Option(False, help="Say hi formally."), ): """ - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. """ diff --git a/docs_src/options/help/tutorial002_an_py310.py b/docs_src/options/help/tutorial002_an_py310.py index 104d8b200e..31c5857c15 100644 --- a/docs_src/options/help/tutorial002_an_py310.py +++ b/docs_src/options/help/tutorial002_an_py310.py @@ -23,7 +23,7 @@ def main( ] = False, ): """ - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. """ diff --git a/docs_src/options/help/tutorial002_py310.py b/docs_src/options/help/tutorial002_py310.py index d811348249..43d54ef812 100644 --- a/docs_src/options/help/tutorial002_py310.py +++ b/docs_src/options/help/tutorial002_py310.py @@ -15,7 +15,7 @@ def main( ), ): """ - Say hi to NAME, optionally with a --lastname. + Say hi to 'name', optionally with a --lastname. If --formal is used, say hi very formally. """ diff --git a/docs_src/parameter_types/number/tutorial001_an_py310.py b/docs_src/parameter_types/number/tutorial001_an_py310.py index 1784b13f06..995f64b67f 100644 --- a/docs_src/parameter_types/number/tutorial001_an_py310.py +++ b/docs_src/parameter_types/number/tutorial001_an_py310.py @@ -7,11 +7,11 @@ @app.command() def main( - id: Annotated[int, typer.Argument(min=0, max=1000)], + ID: Annotated[int, typer.Argument(min=0, max=1000)], age: Annotated[int, typer.Option(min=18)] = 20, score: Annotated[float, typer.Option(max=100)] = 0, ): - print(f"ID is {id}") + print(f"ID is {ID}") print(f"--age is {age}") print(f"--score is {score}") diff --git a/docs_src/parameter_types/number/tutorial001_py310.py b/docs_src/parameter_types/number/tutorial001_py310.py index fc4fe0d30e..37e9e39ff8 100644 --- a/docs_src/parameter_types/number/tutorial001_py310.py +++ b/docs_src/parameter_types/number/tutorial001_py310.py @@ -5,11 +5,11 @@ @app.command() def main( - id: int = typer.Argument(..., min=0, max=1000), + ID: int = typer.Argument(..., min=0, max=1000), age: int = typer.Option(20, min=18), score: float = typer.Option(0, max=100), ): - print(f"ID is {id}") + print(f"ID is {ID}") print(f"--age is {age}") print(f"--score is {score}") diff --git a/docs_src/parameter_types/number/tutorial002_an_py310.py b/docs_src/parameter_types/number/tutorial002_an_py310.py index 5d3835817c..9df5e4838e 100644 --- a/docs_src/parameter_types/number/tutorial002_an_py310.py +++ b/docs_src/parameter_types/number/tutorial002_an_py310.py @@ -7,11 +7,11 @@ @app.command() def main( - id: Annotated[int, typer.Argument(min=0, max=1000)], + ID: Annotated[int, typer.Argument(min=0, max=1000)], rank: Annotated[int, typer.Option(max=10, clamp=True)] = 0, score: Annotated[float, typer.Option(min=0, max=100, clamp=True)] = 0, ): - print(f"ID is {id}") + print(f"ID is {ID}") print(f"--rank is {rank}") print(f"--score is {score}") diff --git a/docs_src/parameter_types/number/tutorial002_py310.py b/docs_src/parameter_types/number/tutorial002_py310.py index c0daadfbd5..f4a624619f 100644 --- a/docs_src/parameter_types/number/tutorial002_py310.py +++ b/docs_src/parameter_types/number/tutorial002_py310.py @@ -5,11 +5,11 @@ @app.command() def main( - id: int = typer.Argument(..., min=0, max=1000), + ID: int = typer.Argument(..., min=0, max=1000), rank: int = typer.Option(0, max=10, clamp=True), score: float = typer.Option(0, min=0, max=100, clamp=True), ): - print(f"ID is {id}") + print(f"ID is {ID}") print(f"--rank is {rank}") print(f"--score is {score}") diff --git a/docs_src/parameter_types/uuid/tutorial001_py310.py b/docs_src/parameter_types/uuid/tutorial001_py310.py index b86d2e78fe..cc9fb94ec9 100644 --- a/docs_src/parameter_types/uuid/tutorial001_py310.py +++ b/docs_src/parameter_types/uuid/tutorial001_py310.py @@ -7,7 +7,7 @@ @app.command() def main(user_id: UUID): - print(f"USER_ID is {user_id}") + print(f"User ID is {user_id}") print(f"UUID version is: {user_id.version}") diff --git a/tests/assets/cli/minimum_main.py b/tests/assets/cli/minimum_main.py new file mode 100644 index 0000000000..3bd9c5c84d --- /dev/null +++ b/tests/assets/cli/minimum_main.py @@ -0,0 +1,8 @@ +import typer + +app = typer.Typer() + + +@app.callback() +def main(name: str) -> None: + pass # pragma: no cover diff --git a/tests/assets/cli/multiapp-docs-title.md b/tests/assets/cli/multiapp-docs-title.md index ffde843736..bc19d4fcba 100644 --- a/tests/assets/cli/multiapp-docs-title.md +++ b/tests/assets/cli/multiapp-docs-title.md @@ -65,8 +65,8 @@ $ multiapp sub hello [OPTIONS] **Options**: -* `--name TEXT`: [default: World] -* `--age INTEGER`: The age of the user [default: 0] +* `--name `: [default: World] +* `--age `: The age of the user [default: 0] * `--help`: Show this message and exit. ### `multiapp sub hi` @@ -76,12 +76,12 @@ Say Hi **Usage**: ```console -$ multiapp sub hi [OPTIONS] [USER] +$ multiapp sub hi [OPTIONS] [user] ``` **Arguments**: -* `[USER]`: The name of the user to greet [default: World] +* `user`: The name of the user to greet [default: World] **Options**: diff --git a/tests/assets/cli/multiapp-docs.md b/tests/assets/cli/multiapp-docs.md index 67d02568db..0b22469133 100644 --- a/tests/assets/cli/multiapp-docs.md +++ b/tests/assets/cli/multiapp-docs.md @@ -65,8 +65,8 @@ $ multiapp sub hello [OPTIONS] **Options**: -* `--name TEXT`: [default: World] -* `--age INTEGER`: The age of the user [default: 0] +* `--name `: [default: World] +* `--age `: The age of the user [default: 0] * `--help`: Show this message and exit. ### `multiapp sub hi` @@ -76,12 +76,12 @@ Say Hi **Usage**: ```console -$ multiapp sub hi [OPTIONS] [USER] +$ multiapp sub hi [OPTIONS] [user] ``` **Arguments**: -* `[USER]`: The name of the user to greet [default: World] +* `user`: The name of the user to greet [default: World] **Options**: diff --git a/tests/assets/cli/richformattedapp-docs.md b/tests/assets/cli/richformattedapp-docs.md index 678a2daf6f..ede949b820 100644 --- a/tests/assets/cli/richformattedapp-docs.md +++ b/tests/assets/cli/richformattedapp-docs.md @@ -5,13 +5,13 @@ Say cool name of the user [required] -* `[USER_2]`: The world [default: The World] +* `user_1`: The cool name of the user [required] +* `user_2`: The world [default: The World] **Options**: diff --git a/tests/test_cli/test_help.py b/tests/test_cli/test_help.py index e829c5801b..3bad9035e1 100644 --- a/tests/test_cli/test_help.py +++ b/tests/test_cli/test_help.py @@ -121,7 +121,7 @@ def cmd(value: str) -> None: output_lines = result.output.splitlines() usage_idx = output_lines.index("Usage: very-long-program-name-that-forces-wrap ") args_line = output_lines[usage_idx + 1] - assert args_line.lstrip() == "[OPTIONS] VALUE" + assert args_line.lstrip() == "[OPTIONS] {value}" assert args_line.startswith(" ") @@ -157,3 +157,18 @@ def cmd( "Description is rendered in the next line for long option labels." in continuation_block ) + + +def test_typer_run_usage() -> None: + from typer.cli import app as typer_cli_app + + result = runner.invoke( + typer_cli_app, + ["tests/assets/cli/minimum_main.py", "run"], + prog_name="typer", + ) + + assert result.exit_code == 2 + usage_line = result.output.splitlines()[0] + assert usage_line.startswith("Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name}") + assert "Try 'typer [PATH_OR_MODULE] run --help' for help." in result.output diff --git a/tests/test_completion/example_rich_tags.py b/tests/test_completion/example_rich_tags.py index 4fc85c6d92..78d86e2b71 100644 --- a/tests/test_completion/example_rich_tags.py +++ b/tests/test_completion/example_rich_tags.py @@ -6,7 +6,7 @@ @app.command() def create(username: str): """ - Create a [green]new[green/] user with USERNAME. + Create a [green]new[green/] user with username. """ print(f"Creating user: {username}") @@ -14,7 +14,7 @@ def create(username: str): @app.command() def delete(username: str): """ - Delete a user with [bold]USERNAME[/]. + Delete a user with [bold]username[/]. """ print(f"Deleting user: {username}") diff --git a/tests/test_completion/test_completion_complete.py b/tests/test_completion/test_completion_complete.py index de353f8a0b..96b7dd383f 100644 --- a/tests/test_completion/test_completion_complete.py +++ b/tests/test_completion/test_completion_complete.py @@ -67,7 +67,7 @@ def test_completion_complete_subcommand_zsh(mod: ModuleType): }, ) assert ( - """_arguments '*: :(("delete":"Delete a user with USERNAME."\n""" + """_arguments '*: :(("delete":"Delete a user with username."\n""" """\"delete-all":"Delete ALL users in the database."))'""" ) in result.stdout @@ -101,7 +101,7 @@ def test_completion_complete_subcommand_fish(mod: ModuleType): }, ) assert ( - "delete\tDelete a user with USERNAME.\ndelete-all\tDelete ALL users in the database." + "delete\tDelete a user with username.\ndelete-all\tDelete ALL users in the database." in result.stdout ) @@ -151,7 +151,7 @@ def test_completion_complete_subcommand_powershell(mod: ModuleType): }, ) assert ( - "delete:::Delete a user with USERNAME.\ndelete-all:::Delete ALL users in the database." + "delete:::Delete a user with username.\ndelete-all:::Delete ALL users in the database." ) in result.stdout @@ -168,7 +168,7 @@ def test_completion_complete_subcommand_pwsh(mod: ModuleType): }, ) assert ( - "delete:::Delete a user with USERNAME.\ndelete-all:::Delete ALL users in the database." + "delete:::Delete a user with username.\ndelete-all:::Delete ALL users in the database." ) in result.stdout diff --git a/tests/test_completion/test_completion_complete_rich.py b/tests/test_completion/test_completion_complete_rich.py index 9c53bb1032..44a723ed42 100644 --- a/tests/test_completion/test_completion_complete_rich.py +++ b/tests/test_completion/test_completion_complete_rich.py @@ -58,7 +58,7 @@ def test_completion_complete_subcommand_zsh(): }, ) assert ( - """_arguments '*: :(("delete":"Delete a user with USERNAME."\n""" + """_arguments '*: :(("delete":"Delete a user with username."\n""" """\"delete-all":"Delete ALL users in the database."))'""" ) in result.stdout @@ -76,7 +76,7 @@ def test_completion_complete_subcommand_fish(): }, ) assert ( - "delete\tDelete a user with USERNAME.\ndelete-all\tDelete ALL users in the database." + "delete\tDelete a user with username.\ndelete-all\tDelete ALL users in the database." in result.stdout ) @@ -93,7 +93,7 @@ def test_completion_complete_subcommand_powershell(): }, ) assert ( - "delete:::Delete a user with USERNAME.\ndelete-all:::Delete ALL users in the database." + "delete:::Delete a user with username.\ndelete-all:::Delete ALL users in the database." ) in result.stdout @@ -109,5 +109,5 @@ def test_completion_complete_subcommand_pwsh(): }, ) assert ( - "delete:::Delete a user with USERNAME.\ndelete-all:::Delete ALL users in the database." + "delete:::Delete a user with username.\ndelete-all:::Delete ALL users in the database." ) in result.stdout diff --git a/tests/test_core.py b/tests/test_core.py index 2cb759918b..32a9aeafd1 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -25,7 +25,7 @@ def main( command = typer.main.get_command(app) params = {param.name: param for param in command.params} - assert params["my_arg_1"].human_readable_name == "MY_ARG_1" + assert params["my_arg_1"].human_readable_name == "my_arg_1" assert params["my_arg_2"].human_readable_name == "META_ARG" assert params["my_opt"].human_readable_name == "my_opt" @@ -377,3 +377,63 @@ def main(names: list[str] = typer.Option(None)): result = runner.invoke(app, [], default_map={"names": "not-a-list"}) assert result.exit_code == 2 assert "Invalid value" in result.output + + +def test_parameter_name_casing(): + app = typer.Typer() + + @app.command() + def main( + arg1: int, + arg2: int = 42, + arg3: int = typer.Argument(...), + ARG4: int = typer.Argument(42), + ARG5: int = typer.Option(...), + arg6: int = typer.Option(42), + arg7: int = typer.Argument(42, metavar="meta7"), + arg8: int = typer.Argument(metavar="ARG8"), + arg9: int = typer.Option(metavar="ARG9"), + ): + print( + f"arg1={arg1} arg2={arg2} arg3={arg3} ARG4={ARG4} ARG5={ARG5} " + f"arg6={arg6} arg7={arg7} arg8={arg8} arg9={arg9}" + ) + + result = runner.invoke( + app, + [ + "1", + "3", + "4", + "7", + "8", + "--arg2", + "2", + "--ARG5", + "5", + "--arg6", + "6", + "--ARG9", + "9", + ], + ) + assert result.exit_code == 0 + assert ( + "arg1=1 arg2=2 arg3=3 ARG4=4 ARG5=5 arg6=6 arg7=7 arg8=8 arg9=9" + in result.output + ) + + result = runner.invoke(app, ["1", "3", "4", "7", "8", "--ARG5", "5", "--ARG9", "9"]) + assert result.exit_code == 0 + assert ( + "arg1=1 arg2=42 arg3=3 ARG4=4 ARG5=5 arg6=42 arg7=7 arg8=8 arg9=9" + in result.output + ) + + result = runner.invoke(app, ["1", "3", "4", "7", "8", "--arg5", "5", "--ARG9", "9"]) + assert result.exit_code != 0 + assert "No such option: --arg5" in result.output + + result = runner.invoke(app, ["1", "3", "4", "7", "8", "--ARG5", "5", "--arg9", "9"]) + assert result.exit_code != 0 + assert "No such option: --arg9" in result.output diff --git a/tests/test_others.py b/tests/test_others.py index d2cc8696f1..ade64750f7 100644 --- a/tests/test_others.py +++ b/tests/test_others.py @@ -450,7 +450,8 @@ def main(arg1, arg2: int, arg3: "int", arg4: bool = False, arg5: "bool" = False) result = runner.invoke(app, ["Hello", "2", "invalid"]) - assert "Invalid value for 'ARG3': 'invalid' is not a valid integer" in result.output + assert "Invalid value for 'arg3'" in result.output + assert "'invalid' is not a valid int" in result.output result = runner.invoke(app, ["Hello", "2", "3", "--arg4", "--arg5"]) assert ( "arg1: Hello\narg2: 2\narg3: 3\narg4: True\narg5: True\n" diff --git a/tests/test_prog_name.py b/tests/test_prog_name.py index cfb5a3464f..5de6fd3f7a 100644 --- a/tests/test_prog_name.py +++ b/tests/test_prog_name.py @@ -10,4 +10,4 @@ def test_custom_prog_name(): capture_output=True, encoding="utf-8", ) - assert "Usage: custom-name [OPTIONS] I" in result.stdout + assert "Usage: custom-name [OPTIONS] {i}" in result.stdout diff --git a/tests/test_rich_markup_mode.py b/tests/test_rich_markup_mode.py index abfae82790..94fb4c2ae8 100644 --- a/tests/test_rich_markup_mode.py +++ b/tests/test_rich_markup_mode.py @@ -25,7 +25,7 @@ def main(arg: str): assert "Hello World" in result.stdout result = runner.invoke(app, ["--help"]) - assert "ARG [required]" in result.stdout + assert "arg [required]" in result.stdout assert all(c not in result.stdout for c in rounded) diff --git a/tests/test_rich_utils.py b/tests/test_rich_utils.py index beb914b961..bd6e58799f 100644 --- a/tests/test_rich_utils.py +++ b/tests/test_rich_utils.py @@ -101,7 +101,7 @@ def main(bar: str): result = runner.invoke(app, ["--help"]) assert "Usage" in result.stdout - assert "BAR" in result.stdout + assert "{bar}" in result.stdout @needs_rich @@ -224,6 +224,18 @@ def find_right_boundary_pos(line): ) +def test_rich_help_no_boolean_type() -> None: + app = typer.Typer(rich_markup_mode="rich") + + @app.command() + def main(name: str) -> None: + pass # pragma: no cover + + result = runner.invoke(app, ["--help"]) + assert result.exit_code == 0 + assert "" not in result.output + + def test_rich_help_metavar(): app = typer.Typer(rich_markup_mode="rich") @@ -233,8 +245,8 @@ def main( arg1: int, arg2: int = 42, arg3: int = typer.Argument(...), - arg4: int = typer.Argument(42), - arg5: int = typer.Option(...), + ARG4: int = typer.Argument(42), + ARG5: int = typer.Option(...), arg6: int = typer.Option(42), arg7: int = typer.Argument(42, metavar="meta7"), arg8: int = typer.Argument(metavar="ARG8"), @@ -243,23 +255,46 @@ def main( pass # pragma: no cover result = runner.invoke(app, ["--help"]) - assert "Usage: main [OPTIONS] ARG1 ARG3 [ARG4] [meta7] ARG8 arg9" in result.stdout + assert ( + "Usage: main [OPTIONS] {arg1} {arg3} [ARG4] [meta7] {ARG8} {arg9}" + in result.stdout + ) out_nospace = result.stdout.replace(" ", "") # arguments - assert "arg1INTEGER" in out_nospace - assert "arg3INTEGER" in out_nospace - assert "[arg4]INTEGER" in out_nospace - assert "[meta7]INTEGER" in out_nospace - assert "ARG8INTEGER" in out_nospace - assert "arg9INTEGER" in out_nospace + assert "arg1" in out_nospace + assert "arg3" in out_nospace + assert "ARG4" in out_nospace + assert "meta7" in out_nospace + assert "ARG8" in out_nospace + assert "arg9" in out_nospace assert "arg7" not in result.stdout.lower() assert "arg8" not in result.stdout assert "ARG9" not in result.stdout # options - assert "arg2INTEGER" in out_nospace - assert "arg5INTEGER" in out_nospace - assert "arg6INTEGER" in out_nospace + assert "--arg2" in out_nospace + assert "--ARG5" in out_nospace + assert "--arg6" in out_nospace + + +def test_rich_lowercase_bracketed_metavar() -> None: + # Make sure Rich doesn't "swallow" a lowercased [path] (thinking it's a Rich annotation) + app = typer.Typer(rich_markup_mode="rich") + + @app.callback() + def main(path_or_module: str = typer.Argument(None)) -> None: + pass # pragma: no cover + + @app.command() + def run(name: str) -> None: + pass # pragma: no cover + + result = runner.invoke(app, ["my-module.py", "run"], prog_name="typer") + + assert result.exit_code == 2 + usage_line = result.output.splitlines()[0] + assert usage_line.startswith("Usage: typer [path_or_module] run [OPTIONS] {name}") + assert "Try 'typer [path_or_module] run --help' for help." in result.output diff --git a/tests/test_tutorial/test_arguments/test_default/test_tutorial001.py b/tests/test_tutorial/test_arguments/test_default/test_tutorial001.py index 75104a7d9b..81212ce98b 100644 --- a/tests/test_tutorial/test_arguments/test_default/test_tutorial001.py +++ b/tests/test_tutorial/test_arguments/test_default/test_tutorial001.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "[default: Wade Wilson]" in result.output diff --git a/tests/test_tutorial/test_arguments/test_default/test_tutorial002.py b/tests/test_tutorial/test_arguments/test_default/test_tutorial002.py index f68b61df82..37eedd779d 100644 --- a/tests/test_tutorial/test_arguments/test_default/test_tutorial002.py +++ b/tests/test_tutorial/test_arguments/test_default/test_tutorial002.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "[default: (dynamic)]" in result.output diff --git a/tests/test_tutorial/test_arguments/test_envvar/test_tutorial001.py b/tests/test_tutorial/test_arguments/test_envvar/test_tutorial001.py index 689030a258..179f6936fc 100644 --- a/tests/test_tutorial/test_arguments/test_envvar/test_tutorial001.py +++ b/tests/test_tutorial/test_arguments/test_envvar/test_tutorial001.py @@ -27,7 +27,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "env var: AWESOME_NAME" in result.output assert "default: World" in result.output @@ -37,7 +37,7 @@ def test_help_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): monkeypatch.setattr(typer.core, "HAS_RICH", False) result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "env var: AWESOME_NAME" in result.output assert "default: World" in result.output diff --git a/tests/test_tutorial/test_arguments/test_envvar/test_tutorial002.py b/tests/test_tutorial/test_arguments/test_envvar/test_tutorial002.py index 23679b04b5..3d06a1c869 100644 --- a/tests/test_tutorial/test_arguments/test_envvar/test_tutorial002.py +++ b/tests/test_tutorial/test_arguments/test_envvar/test_tutorial002.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "env var: AWESOME_NAME, GOD_NAME" in result.output assert "default: World" in result.output diff --git a/tests/test_tutorial/test_arguments/test_envvar/test_tutorial003.py b/tests/test_tutorial/test_arguments/test_envvar/test_tutorial003.py index ee979e4762..042620f9a0 100644 --- a/tests/test_tutorial/test_arguments/test_envvar/test_tutorial003.py +++ b/tests/test_tutorial/test_arguments/test_envvar/test_tutorial003.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "env var: AWESOME_NAME" not in result.output assert "default: World" in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial001.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial001.py index fabe28be28..e2e24fe647 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial001.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial001.py @@ -26,9 +26,9 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] NAME" in result.output + assert "[OPTIONS] {name}" in result.output assert "Arguments" in result.output - assert "NAME" in result.output + assert "{name}" in result.output assert "The name of the user to greet" in result.output assert "[required]" in result.output @@ -37,9 +37,9 @@ def test_help_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): monkeypatch.setattr(typer.core, "HAS_RICH", False) result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] NAME" in result.output + assert "[OPTIONS] {name}" in result.output assert "Arguments" in result.output - assert "NAME" in result.output + assert "{name}" in result.output assert "The name of the user to greet" in result.output assert "[required]" in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial002.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial002.py index 91eb30e375..af2181d183 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial002.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial002.py @@ -25,10 +25,10 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] NAME" in result.output - assert "Say hi to NAME very gently, like Dirk." in result.output + assert "[OPTIONS] {name}" in result.output + assert "Say hi to 'name' very gently, like Dirk." in result.output assert "Arguments" in result.output - assert "NAME" in result.output + assert "{name}" in result.output assert "The name of the user to greet" in result.output assert "[required]" in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial003.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial003.py index 20bd6b76ea..c24804b917 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial003.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial003.py @@ -25,10 +25,10 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output - assert "Say hi to NAME very gently, like Dirk." in result.output + assert "[OPTIONS] [name]" in result.output + assert "Say hi to 'name' very gently, like Dirk." in result.output assert "Arguments" in result.output - assert "NAME" in result.output + assert "[name]" in result.output assert "Who to greet" in result.output assert "[default: World]" in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial004.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial004.py index 7a20f48979..a885e3f868 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial004.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial004.py @@ -25,10 +25,10 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output - assert "Say hi to NAME very gently, like Dirk." in result.output + assert "[OPTIONS] [name]" in result.output + assert "Say hi to 'name' very gently, like Dirk." in result.output assert "Arguments" in result.output - assert "NAME" in result.output + assert "[name]" in result.output assert "Who to greet" in result.output assert "[default: World]" not in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial005.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial005.py index 8f6d356d81..4cb17b4e86 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial005.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial005.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "Usage: main [OPTIONS] [NAME]" in result.output + assert "Usage: main [OPTIONS] [name]" in result.output assert "Arguments" in result.output assert "Who to greet" in result.output assert "[default: (Deadpoolio the amazing's name)]" in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial007.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial007.py index a51ca0a3e8..0337e933e6 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial007.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial007.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "Say hi to NAME very gently, like Dirk." in result.output + assert "Say hi to 'name' very gently, like Dirk." in result.output assert "Arguments" in result.output assert "Secondary Arguments" in result.output diff --git a/tests/test_tutorial/test_arguments/test_help/test_tutorial008.py b/tests/test_tutorial/test_arguments/test_help/test_tutorial008.py index f21c883434..646342950e 100644 --- a/tests/test_tutorial/test_arguments/test_help/test_tutorial008.py +++ b/tests/test_tutorial/test_arguments/test_help/test_tutorial008.py @@ -26,8 +26,8 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output - assert "Say hi to NAME very gently, like Dirk." in result.output + assert "[OPTIONS] [name]" in result.output + assert "Say hi to 'name' very gently, like Dirk." in result.output assert "Arguments" not in result.output assert "[default: World]" not in result.output @@ -36,8 +36,8 @@ def test_help_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): monkeypatch.setattr(typer.core, "HAS_RICH", False) result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output - assert "Say hi to NAME very gently, like Dirk." in result.output + assert "[OPTIONS] [name]" in result.output + assert "Say hi to 'name' very gently, like Dirk." in result.output assert "Arguments" not in result.output assert "[default: World]" not in result.output diff --git a/tests/test_tutorial/test_arguments/test_optional/test_tutorial000.py b/tests/test_tutorial/test_arguments/test_optional/test_tutorial000.py index 8f0bd34c7f..76d86ed82e 100644 --- a/tests/test_tutorial/test_arguments/test_optional/test_tutorial000.py +++ b/tests/test_tutorial/test_arguments/test_optional/test_tutorial000.py @@ -39,7 +39,7 @@ def test_cli(app: typer.Typer): def test_cli_missing_argument(app: typer.Typer): result = runner.invoke(app) assert result.exit_code == 2 - assert "Missing argument 'NAME'" in result.output + assert "Missing argument 'name'" in result.output def test_script(mod: ModuleType): diff --git a/tests/test_tutorial/test_arguments/test_optional/test_tutorial001.py b/tests/test_tutorial/test_arguments/test_optional/test_tutorial001.py index 7e26b9eb86..60d4b5d30d 100644 --- a/tests/test_tutorial/test_arguments/test_optional/test_tutorial001.py +++ b/tests/test_tutorial/test_arguments/test_optional/test_tutorial001.py @@ -26,7 +26,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_call_no_arg(mod: ModuleType): result = runner.invoke(mod.app) assert result.exit_code != 0 - assert "Missing argument 'NAME'." in result.output + assert "Missing argument 'name'." in result.output def test_call_no_arg_standalone(mod: ModuleType): @@ -40,7 +40,7 @@ def test_call_no_arg_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): monkeypatch.setattr(typer.core, "HAS_RICH", False) result = runner.invoke(mod.app) assert result.exit_code != 0 - assert "Error: Missing argument 'NAME'" in result.output + assert "Error: Missing argument 'name'" in result.output def test_call_arg(mod: ModuleType): diff --git a/tests/test_tutorial/test_arguments/test_optional/test_tutorial002.py b/tests/test_tutorial/test_arguments/test_optional/test_tutorial002.py index 3e3fdba384..b1b1c9b07b 100644 --- a/tests/test_tutorial/test_arguments/test_optional/test_tutorial002.py +++ b/tests/test_tutorial/test_arguments/test_optional/test_tutorial002.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAME]" in result.output + assert "[OPTIONS] [name]" in result.output def test_call_no_arg(mod: ModuleType): diff --git a/tests/test_tutorial/test_arguments/test_optional/test_tutorial003.py b/tests/test_tutorial/test_arguments/test_optional/test_tutorial003.py index 60addad04d..274616e04c 100644 --- a/tests/test_tutorial/test_arguments/test_optional/test_tutorial003.py +++ b/tests/test_tutorial/test_arguments/test_optional/test_tutorial003.py @@ -15,7 +15,7 @@ def test_call_no_arg(): result = runner.invoke(app) assert result.exit_code != 0 - assert "Missing argument 'NAME'." in result.output + assert "Missing argument 'name'." in result.output def test_call_no_arg_standalone(): @@ -29,7 +29,7 @@ def test_call_no_arg_no_rich(monkeypatch: pytest.MonkeyPatch): monkeypatch.setattr(typer.core, "HAS_RICH", False) result = runner.invoke(app) assert result.exit_code != 0 - assert "Error: Missing argument 'NAME'" in result.output + assert "Error: Missing argument 'name'" in result.output def test_call_arg(): diff --git a/tests/test_tutorial/test_commands/test_arguments/test_tutorial001.py b/tests/test_tutorial/test_commands/test_arguments/test_tutorial001.py index 4efc1fe9ef..58ac250108 100644 --- a/tests/test_tutorial/test_commands/test_arguments/test_tutorial001.py +++ b/tests/test_tutorial/test_commands/test_arguments/test_tutorial001.py @@ -13,13 +13,13 @@ def test_help_create(): result = runner.invoke(app, ["create", "--help"]) assert result.exit_code == 0 - assert "create [OPTIONS] USERNAME" in result.output + assert "create [OPTIONS] {username}" in result.output def test_help_delete(): result = runner.invoke(app, ["delete", "--help"]) assert result.exit_code == 0 - assert "delete [OPTIONS] USERNAME" in result.output + assert "delete [OPTIONS] {username}" in result.output def test_create(): diff --git a/tests/test_tutorial/test_commands/test_help/test_tutorial001.py b/tests/test_tutorial/test_commands/test_help/test_tutorial001.py index 9993765b37..e0fac77895 100644 --- a/tests/test_tutorial/test_commands/test_help/test_tutorial001.py +++ b/tests/test_tutorial/test_commands/test_help/test_tutorial001.py @@ -27,9 +27,9 @@ def test_help(mod: ModuleType): assert result.exit_code == 0 assert "Awesome CLI user manager." in result.output assert "create" in result.output - assert "Create a new user with USERNAME." in result.output + assert "Create a new user with username." in result.output assert "delete" in result.output - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "delete-all" in result.output assert "Delete ALL users in the database." in result.output assert "init" in result.output @@ -39,15 +39,15 @@ def test_help(mod: ModuleType): def test_help_create(mod: ModuleType): result = runner.invoke(mod.app, ["create", "--help"]) assert result.exit_code == 0 - assert "create [OPTIONS] USERNAME" in result.output - assert "Create a new user with USERNAME." in result.output + assert "create [OPTIONS] {username}" in result.output + assert "Create a new user with username." in result.output def test_help_delete(mod: ModuleType): result = runner.invoke(mod.app, ["delete", "--help"]) assert result.exit_code == 0 - assert "delete [OPTIONS] USERNAME" in result.output - assert "Delete a user with USERNAME." in result.output + assert "delete [OPTIONS] {username}" in result.output + assert "Delete a user with username." in result.output assert "--force" in result.output assert "--no-force" in result.output assert "Force deletion without confirmation." in result.output diff --git a/tests/test_tutorial/test_commands/test_help/test_tutorial002.py b/tests/test_tutorial/test_commands/test_help/test_tutorial002.py index e46ce7fce3..dd8aec491f 100644 --- a/tests/test_tutorial/test_commands/test_help/test_tutorial002.py +++ b/tests/test_tutorial/test_commands/test_help/test_tutorial002.py @@ -14,9 +14,9 @@ def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "create" in result.output - assert "Create a new user with USERNAME." in result.output + assert "Create a new user with username." in result.output assert "delete" in result.output - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "Some internal utility function to create." not in result.output assert "Some internal utility function to delete." not in result.output @@ -24,14 +24,14 @@ def test_help(): def test_help_create(): result = runner.invoke(app, ["create", "--help"]) assert result.exit_code == 0 - assert "Create a new user with USERNAME." in result.output + assert "Create a new user with username." in result.output assert "Some internal utility function to create." not in result.output def test_help_delete(): result = runner.invoke(app, ["delete", "--help"]) assert result.exit_code == 0 - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "Some internal utility function to delete." not in result.output diff --git a/tests/test_tutorial/test_commands/test_help/test_tutorial004.py b/tests/test_tutorial/test_commands/test_help/test_tutorial004.py index 5c5f7fc952..dd070141c8 100644 --- a/tests/test_tutorial/test_commands/test_help/test_tutorial004.py +++ b/tests/test_tutorial/test_commands/test_help/test_tutorial004.py @@ -29,7 +29,7 @@ def test_help(mod: ModuleType): assert "create" in result.output assert "Create a new shiny user. ✨" in result.output assert "delete" in result.output - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "Some internal utility function to create." not in result.output assert "Some internal utility function to delete." not in result.output @@ -45,7 +45,7 @@ def test_help_create(mod: ModuleType): def test_help_delete(mod: ModuleType): result = runner.invoke(mod.app, ["delete", "--help"]) assert result.exit_code == 0 - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "The username to be deleted" in result.output assert "Force the deletion 💥" in result.output assert "Some internal utility function to delete." not in result.output diff --git a/tests/test_tutorial/test_commands/test_help/test_tutorial005.py b/tests/test_tutorial/test_commands/test_help/test_tutorial005.py index c6c88c7426..d746e24d5b 100644 --- a/tests/test_tutorial/test_commands/test_help/test_tutorial005.py +++ b/tests/test_tutorial/test_commands/test_help/test_tutorial005.py @@ -29,7 +29,7 @@ def test_help(mod: ModuleType): assert "create" in result.output assert "Create a new shiny user. ✨" in result.output assert "delete" in result.output - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "Some internal utility function to create." not in result.output assert "Some internal utility function to delete." not in result.output @@ -46,7 +46,7 @@ def test_help_create(mod: ModuleType): def test_help_delete(mod: ModuleType): result = runner.invoke(mod.app, ["delete", "--help"]) assert result.exit_code == 0 - assert "Delete a user with USERNAME." in result.output + assert "Delete a user with username." in result.output assert "The username to be deleted" in result.output assert "Force the deletion 💥" in result.output assert "Some internal utility function to delete." not in result.output diff --git a/tests/test_tutorial/test_commands/test_help/test_tutorial007.py b/tests/test_tutorial/test_commands/test_help/test_tutorial007.py index 76c7cb2a4f..7b8fe367ed 100644 --- a/tests/test_tutorial/test_commands/test_help/test_tutorial007.py +++ b/tests/test_tutorial/test_commands/test_help/test_tutorial007.py @@ -36,7 +36,7 @@ def test_main_help(mod: ModuleType): def test_create_help(mod: ModuleType): result = runner.invoke(mod.app, ["create", "--help"]) assert result.exit_code == 0 - assert "create [OPTIONS] USERNAME [LASTNAME]" in result.output + assert "create [OPTIONS] {username} [lastname]" in result.output assert "username" in result.output assert "The username to create" in result.output assert "Secondary Arguments" in result.output diff --git a/tests/test_tutorial/test_first_steps/test_tutorial002.py b/tests/test_tutorial/test_first_steps/test_tutorial002.py index 952f983963..baceee2bc2 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial002.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial002.py @@ -15,7 +15,7 @@ def test_1(): result = runner.invoke(app, []) assert result.exit_code != 0 - assert "Missing argument 'NAME'" in result.output + assert "Missing argument 'name'" in result.output def test_2(): diff --git a/tests/test_tutorial/test_first_steps/test_tutorial003.py b/tests/test_tutorial/test_first_steps/test_tutorial003.py index e92f23521e..5c5ddb39cf 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial003.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial003.py @@ -15,7 +15,7 @@ def test_1(): result = runner.invoke(app, ["Camila"]) assert result.exit_code != 0 - assert "Missing argument 'LASTNAME'" in result.output + assert "Missing argument 'lastname'" in result.output def test_2(): diff --git a/tests/test_tutorial/test_first_steps/test_tutorial004.py b/tests/test_tutorial/test_first_steps/test_tutorial004.py index 6ac326f074..0232605f97 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial004.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial004.py @@ -16,9 +16,9 @@ def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "Arguments" in result.output - assert "NAME" in result.output + assert "{name}" in result.output assert "[required]" in result.output - assert "LASTNAME" in result.output + assert "{lastname}" in result.output assert "[required]" in result.output assert "--formal" in result.output assert "--no-formal" in result.output diff --git a/tests/test_tutorial/test_first_steps/test_tutorial005.py b/tests/test_tutorial/test_first_steps/test_tutorial005.py index 87ce389410..48c80573f1 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial005.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial005.py @@ -16,10 +16,10 @@ def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "Arguments" in result.output - assert "NAME" in result.output + assert "{name}" in result.output assert "[required]" in result.output assert "--lastname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "--formal" in result.output assert "--no-formal" in result.output diff --git a/tests/test_tutorial/test_first_steps/test_tutorial006.py b/tests/test_tutorial/test_first_steps/test_tutorial006.py index e2a85d9c0d..38ce63d9d4 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial006.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial006.py @@ -15,7 +15,7 @@ def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 - assert "Say hi to NAME, optionally with a --lastname." in result.output + assert "Say hi to 'name', optionally with a --lastname." in result.output assert "If --formal is used, say hi very formally." in result.output diff --git a/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py b/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py index 0fd8ed8f33..c31fabce69 100644 --- a/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py +++ b/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py @@ -27,7 +27,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "[OPTIONS] [NAMES]..." in result.output + assert "[OPTIONS] [names]..." in result.output assert "Arguments" in result.output assert "[default: Harry, Hermione, Ron]" in result.output diff --git a/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py b/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py index 4c229209dd..3b95f60868 100644 --- a/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py +++ b/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py @@ -58,3 +58,6 @@ def test_script(mod: ModuleType): encoding="utf-8", ) assert "Usage" in result.stdout + + # ensure that also tuple of None's isn't displayed + assert "[default: None, None, None]" not in result.stdout diff --git a/tests/test_tutorial/test_options/test_help/test_tutorial001.py b/tests/test_tutorial/test_options/test_help/test_tutorial001.py index 067bdffe51..62ee6160e6 100644 --- a/tests/test_tutorial/test_options/test_help/test_tutorial001.py +++ b/tests/test_tutorial/test_options/test_help/test_tutorial001.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "Say hi to NAME, optionally with a --lastname." in result.output + assert "Say hi to 'name', optionally with a --lastname." in result.output assert "If --formal is used, say hi very formally." in result.output assert "Last name of person to greet." in result.output assert "Say hi formally." in result.output diff --git a/tests/test_tutorial/test_options/test_help/test_tutorial003.py b/tests/test_tutorial/test_options/test_help/test_tutorial003.py index de99469dfa..4bb1cc10a9 100644 --- a/tests/test_tutorial/test_options/test_help/test_tutorial003.py +++ b/tests/test_tutorial/test_options/test_help/test_tutorial003.py @@ -32,7 +32,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--fullname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[default: Wade Wilson]" not in result.output diff --git a/tests/test_tutorial/test_options/test_help/test_tutorial004.py b/tests/test_tutorial/test_options/test_help/test_tutorial004.py index 22f902197b..5936ebca97 100644 --- a/tests/test_tutorial/test_options/test_help/test_tutorial004.py +++ b/tests/test_tutorial/test_options/test_help/test_tutorial004.py @@ -34,7 +34,7 @@ def test_help(monkeypatch, mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--fullname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[default: (Deadpoolio the amazing's name)]" in result.output diff --git a/tests/test_tutorial/test_options/test_name/test_tutorial001.py b/tests/test_tutorial/test_options/test_name/test_tutorial001.py index 1c4f2a7cf0..d375a92bfd 100644 --- a/tests/test_tutorial/test_options/test_name/test_tutorial001.py +++ b/tests/test_tutorial/test_options/test_name/test_tutorial001.py @@ -26,7 +26,7 @@ def test_option_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--name" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "--user-name" not in result.output diff --git a/tests/test_tutorial/test_options/test_name/test_tutorial002.py b/tests/test_tutorial/test_options/test_name/test_tutorial002.py index ac9b3db6f1..9e0dcb4892 100644 --- a/tests/test_tutorial/test_options/test_name/test_tutorial002.py +++ b/tests/test_tutorial/test_options/test_name/test_tutorial002.py @@ -27,7 +27,7 @@ def test_option_help(mod: ModuleType): assert result.exit_code == 0 assert "-n" in result.output assert "--name" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "--user-name" not in result.output diff --git a/tests/test_tutorial/test_options/test_name/test_tutorial003.py b/tests/test_tutorial/test_options/test_name/test_tutorial003.py index 0503b410af..e20ca92a63 100644 --- a/tests/test_tutorial/test_options/test_name/test_tutorial003.py +++ b/tests/test_tutorial/test_options/test_name/test_tutorial003.py @@ -26,7 +26,7 @@ def test_option_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "-n" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "--user-name" not in result.output assert "--name" not in result.output diff --git a/tests/test_tutorial/test_options/test_name/test_tutorial004.py b/tests/test_tutorial/test_options/test_name/test_tutorial004.py index f200021042..862890b9c7 100644 --- a/tests/test_tutorial/test_options/test_name/test_tutorial004.py +++ b/tests/test_tutorial/test_options/test_name/test_tutorial004.py @@ -27,7 +27,7 @@ def test_option_help(mod: ModuleType): assert result.exit_code == 0 assert "-n" in result.output assert "--user-name" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "--name" not in result.output diff --git a/tests/test_tutorial/test_options/test_name/test_tutorial005.py b/tests/test_tutorial/test_options/test_name/test_tutorial005.py index 492a0fc4ef..520073b98e 100644 --- a/tests/test_tutorial/test_options/test_name/test_tutorial005.py +++ b/tests/test_tutorial/test_options/test_name/test_tutorial005.py @@ -27,7 +27,7 @@ def test_option_help(mod: ModuleType): assert result.exit_code == 0 assert "-n" in result.output assert "--name" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "-f" in result.output assert "--formal" in result.output diff --git a/tests/test_tutorial/test_options/test_password/test_tutorial001.py b/tests/test_tutorial/test_options/test_password/test_tutorial001.py index 4aca1c0bd8..8374a497a3 100644 --- a/tests/test_tutorial/test_options/test_password/test_tutorial001.py +++ b/tests/test_tutorial/test_options/test_password/test_tutorial001.py @@ -44,7 +44,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 output_without_double_spaces = strip_double_spaces(result.output) - assert "--email TEXT [required]" in output_without_double_spaces + assert "--email [required]" in output_without_double_spaces def test_script(mod: ModuleType): diff --git a/tests/test_tutorial/test_options/test_password/test_tutorial002.py b/tests/test_tutorial/test_options/test_password/test_tutorial002.py index 08d43ff87e..4b63dbc20c 100644 --- a/tests/test_tutorial/test_options/test_password/test_tutorial002.py +++ b/tests/test_tutorial/test_options/test_password/test_tutorial002.py @@ -48,7 +48,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 output_without_double_spaces = strip_double_spaces(result.output) - assert "--password TEXT [required]" in output_without_double_spaces + assert "--password [required]" in output_without_double_spaces def test_script(mod: ModuleType): diff --git a/tests/test_tutorial/test_options/test_prompt/test_tutorial001.py b/tests/test_tutorial/test_options/test_prompt/test_tutorial001.py index 1236f33e57..c0d1e5770c 100644 --- a/tests/test_tutorial/test_options/test_prompt/test_tutorial001.py +++ b/tests/test_tutorial/test_options/test_prompt/test_tutorial001.py @@ -39,7 +39,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--lastname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[required]" in result.output diff --git a/tests/test_tutorial/test_options/test_prompt/test_tutorial002.py b/tests/test_tutorial/test_options/test_prompt/test_tutorial002.py index 0947a5e77e..42def22bd6 100644 --- a/tests/test_tutorial/test_options/test_prompt/test_tutorial002.py +++ b/tests/test_tutorial/test_options/test_prompt/test_tutorial002.py @@ -39,7 +39,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--lastname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[required]" in result.output diff --git a/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py b/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py index 6016dc4acf..daefde09fa 100644 --- a/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py +++ b/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py @@ -48,7 +48,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--project-name" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[required]" in result.output diff --git a/tests/test_tutorial/test_options/test_required/test_tutorial001_tutorial002.py b/tests/test_tutorial/test_options/test_required/test_tutorial001_tutorial002.py index 72ad6e04cd..5003c80ae3 100644 --- a/tests/test_tutorial/test_options/test_required/test_tutorial001_tutorial002.py +++ b/tests/test_tutorial/test_options/test_required/test_tutorial001_tutorial002.py @@ -41,7 +41,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--lastname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[required]" in result.output @@ -50,7 +50,7 @@ def test_help_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--lastname" in result.output - assert "TEXT" in result.output + assert "" in result.output assert "[required]" in result.output diff --git a/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py index eea63c5a8b..20c939c90b 100644 --- a/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py +++ b/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py @@ -20,7 +20,7 @@ def test_type_repr(): def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 - assert "[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]" in result.output + assert "<%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S>" in result.output def test_main(): @@ -42,10 +42,7 @@ def test_main_datetime_object(): def test_invalid(): result = runner.invoke(app, ["july-19-1989"]) assert result.exit_code != 0 - assert ( - "Invalid value for 'BIRTH:[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]':" - in result.output - ) + assert "Invalid value for 'birth'" in result.output assert "'july-19-1989' does not match the formats" in result.output assert "%Y-%m-%d" in result.output assert "%Y-%m-%dT%H:%M:%S" in result.output diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py index 6ec636d7ec..a27d32f1bb 100644 --- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py +++ b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py @@ -13,7 +13,7 @@ def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "--network" in result.output - assert "[simple|conv|lstm]" in result.output + assert "" in result.output assert "default: simple" in result.output diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial003.py b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial003.py index d6c0e532c9..03ffd9c990 100644 --- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial003.py +++ b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial003.py @@ -26,7 +26,7 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--groceries" in result.output - assert "[Eggs|Bacon|Cheese]" in result.output + assert "" in result.output assert "default: Eggs, Cheese" in result.output diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial004.py b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial004.py index 84f0eb3b16..0791fab333 100644 --- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial004.py +++ b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial004.py @@ -25,7 +25,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 - assert "--network [simple|conv|lstm]" in result.output.replace(" ", "") + assert "--network " in result.output.replace(" ", "") def test_main(mod): diff --git a/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py index ee0daa9f06..8d7fdae4f7 100644 --- a/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py +++ b/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py @@ -24,9 +24,9 @@ def test_help(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 assert "--age" in result.output - assert "INTEGER" in result.output + assert "" in result.output assert "--height-meters" in result.output - assert "FLOAT" in result.output + assert "" in result.output def test_params(): @@ -44,7 +44,7 @@ def test_invalid(): result = runner.invoke(app, ["Camila", "--age", "15.3"]) assert result.exit_code != 0 assert "Invalid value for '--age'" in result.output - assert "'15.3' is not a valid integer" in result.output + assert "'15.3' is not a valid int." in result.output def test_script(): diff --git a/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py index ffe3ad09a0..466bc55d1c 100644 --- a/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py +++ b/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py @@ -27,7 +27,7 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType: def test_type_repr(mod: ModuleType): command = typer.main.get_command(mod.app) - id_param = next(param for param in command.params if param.name == "id") + id_param = next(param for param in command.params if param.name == "ID") assert repr(id_param.type) == "" age_param = next(param for param in command.params if param.name == "age") @@ -41,9 +41,9 @@ def test_help(mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--age" in result.output - assert "INTEGER RANGE" in result.output + assert "int range" in result.output assert "--score" in result.output - assert "FLOAT RANGE" in result.output + assert "float range" in result.output def test_help_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): @@ -51,9 +51,9 @@ def test_help_no_rich(monkeypatch: pytest.MonkeyPatch, mod: ModuleType): result = runner.invoke(mod.app, ["--help"]) assert result.exit_code == 0 assert "--age" in result.output - assert "INTEGER RANGE" in result.output + assert "int range" in result.output assert "--score" in result.output - assert "FLOAT RANGE" in result.output + assert "float range" in result.output def test_params(mod: ModuleType): diff --git a/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py index 7b79e81405..f44731968d 100644 --- a/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py +++ b/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py @@ -20,7 +20,7 @@ def test_type_repr(): def test_main(): result = runner.invoke(app, ["d48edaa6-871a-4082-a196-4daab372d4a1"]) assert result.exit_code == 0 - assert "USER_ID is d48edaa6-871a-4082-a196-4daab372d4a1" in result.output + assert "User ID is d48edaa6-871a-4082-a196-4daab372d4a1" in result.output assert "UUID version is: 4" in result.output @@ -28,17 +28,15 @@ def test_main_with_uuid_object(): user_id = uuid.UUID("d48edaa6-871a-4082-a196-4daab372d4a1") result = runner.invoke(app, [], default_map={"user_id": user_id}) assert result.exit_code == 0 - assert "USER_ID is d48edaa6-871a-4082-a196-4daab372d4a1" in result.output + assert "User ID is d48edaa6-871a-4082-a196-4daab372d4a1" in result.output assert "UUID version is: 4" in result.output def test_invalid_uuid(): result = runner.invoke(app, ["7479706572-72756c6573"]) assert result.exit_code != 0 - assert ( - "Invalid value for 'USER_ID': '7479706572-72756c6573' is not a valid UUID" - in result.output - ) + assert "Invalid value for 'user_id'" in result.output + assert "not a valid UUID" in result.output def test_script(): diff --git a/tests/test_tutorial/test_typer_app/test_tutorial001.py b/tests/test_tutorial/test_typer_app/test_tutorial001.py index a951fe1881..175841b304 100644 --- a/tests/test_tutorial/test_typer_app/test_tutorial001.py +++ b/tests/test_tutorial/test_typer_app/test_tutorial001.py @@ -13,7 +13,7 @@ def test_no_arg(): result = runner.invoke(app) assert result.exit_code != 0 - assert "Missing argument 'NAME'." in result.output + assert "Missing argument 'name'." in result.output def test_arg(): diff --git a/tests/test_type_conversion.py b/tests/test_type_conversion.py index 26709db0e2..bf42268818 100644 --- a/tests/test_type_conversion.py +++ b/tests/test_type_conversion.py @@ -1,7 +1,8 @@ import os +from datetime import datetime from enum import Enum from pathlib import Path -from typing import Any +from typing import Annotated, Any, Literal import pytest import typer @@ -398,3 +399,65 @@ def __init__(self, encoding: str | None) -> None: converted = _click.types.STRING.convert(b"\xff", None, None) assert converted == "ÿ" + + +@pytest.mark.parametrize( + ("parameter", "expected_metavar"), + [ + pytest.param(Annotated[str, typer.Option(...)], ""), + pytest.param(Annotated[str, typer.Argument(...)], ""), + pytest.param(Annotated[int, typer.Option(...)], ""), + pytest.param(Annotated[int, typer.Argument(...)], ""), + pytest.param(Annotated[float, typer.Option(...)], ""), + pytest.param( + Annotated[float, typer.Option(..., min=0.666, max=3.42)], "" + ), + pytest.param(Annotated[tuple[str, int], typer.Option(...)], "..."), + pytest.param(Annotated[tuple[Path, str], typer.Option(...)], "..."), + pytest.param(Annotated[str, typer.Option(..., resolve_path=True)], ""), + pytest.param(Annotated[Path, typer.Option(...)], ""), + pytest.param(Annotated[Path, typer.Option(..., dir_okay=False)], ""), + pytest.param( + Annotated[Path, typer.Option(..., file_okay=False)], "" + ), + pytest.param(Annotated[SomeEnum, typer.Option(...)], ""), + pytest.param(Annotated[SomeEnum, typer.Argument()], ""), + pytest.param(Annotated[Literal["x", "y"], typer.Option(...)], ""), + pytest.param( + Annotated[datetime, typer.Option(..., formats=["%Y-%m-%d", "%d/%m/%Y"])], + "<%Y-%m-%d|%d/%m/%Y>", + ), + ], +) +def test_param_type_help_metavar(parameter: Any, expected_metavar: str) -> None: + app = typer.Typer() + + @app.command() + # TODO: type-specific default + def with_default(value: parameter = "my_default"): + pass # pragma: no cover + + @app.command() + def without_default(value: parameter): + pass # pragma: no cover + + result = runner.invoke(app, ["with-default", "--help"]) + assert result.exit_code == 0 + assert expected_metavar in result.output + + result = runner.invoke(app, ["without-default", "--help"]) + assert result.exit_code == 0 + assert expected_metavar in result.output + + +def test_metavar_preformatted_square_brackets() -> None: + app = typer.Typer() + + @app.command() + def main(value: Annotated[str, typer.Argument(metavar="[VALUE]")]): + pass # pragma: no cover + + result = runner.invoke(app, ["--help"]) + assert result.exit_code == 0 + assert "[VALUE]" in result.output + assert "[[VALUE]]" not in result.output diff --git a/tests/test_types.py b/tests/test_types.py index db6dae08da..aa97c3ca68 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -93,11 +93,11 @@ def test_enum_choice_repr() -> None: def test_enum_choice_help() -> None: result = runner.invoke(app, ["hello-argument", "--help"]) assert result.exit_code == 0 - assert "{rick|morty}" in result.output + assert "" in result.output result = runner.invoke(app, ["hello-option", "--help"]) assert result.exit_code == 0 - assert "[rick|morty]" in result.output + assert "" in result.output result = runner.invoke(app, ["hello-no-choices", "--help"]) assert result.exit_code == 0 diff --git a/typer/.agents/skills/typer/SKILL.md b/typer/.agents/skills/typer/SKILL.md index 60cf47a391..1ce63958cb 100644 --- a/typer/.agents/skills/typer/SKILL.md +++ b/typer/.agents/skills/typer/SKILL.md @@ -240,7 +240,7 @@ def create( print(f"Creating user: {username}") -@app.command(help="[bold red]Delete[/bold red] a user with [italic]USERNAME[/italic].") +@app.command(help="[bold red]Delete[/bold red] a user with [italic]username[/italic].") def delete( username: Annotated[ str, typer.Argument(help="The username to be [red]deleted[/red]") @@ -269,7 +269,7 @@ import typer app = typer.Typer(rich_markup_mode="markdown") -@app.command(help="**Delete** a user with *USERNAME*.") +@app.command(help="**Delete** a user with *username*.") def delete( username: Annotated[str, typer.Argument(help="The username to be **deleted** :boom:")] ): diff --git a/typer/_click/core.py b/typer/_click/core.py index 42bf49911b..ada074bcc3 100644 --- a/typer/_click/core.py +++ b/typer/_click/core.py @@ -885,7 +885,11 @@ def make_metavar(self, ctx: Context) -> str: metavar = self.type.get_metavar(param=self, ctx=ctx) if metavar is None: - metavar = self.type.name.upper() + type_name = self.type.name + if type_name.startswith("<") and type_name.endswith(">"): + metavar = type_name + else: + metavar = f"<{type_name}>" if self.nargs != 1: metavar += "..." diff --git a/typer/_click/types.py b/typer/_click/types.py index 5ccf15fe1b..f49244c6c5 100644 --- a/typer/_click/types.py +++ b/typer/_click/types.py @@ -142,7 +142,7 @@ def convert( class StringParamType(ParamType): - name = "text" + name = "str" def convert( self, value: Any, param: Union["Parameter", None], ctx: Union["Context", None] @@ -193,7 +193,7 @@ def __init__(self, formats: Sequence[str] | None = None): ] def get_metavar(self, param: "Parameter", ctx: "Context") -> str | None: - return f"[{'|'.join(self.formats)}]" + return f"<{'|'.join(self.formats)}>" def _try_to_convert_date(self, value: Any, format: str) -> datetime | None: try: @@ -310,7 +310,7 @@ def __repr__(self) -> str: class IntParamType(_NumberParamTypeBase): - name = "integer" + name = "int" _number_class = int def __repr__(self) -> str: @@ -328,7 +328,7 @@ class IntRange(_NumberRangeBase, IntParamType): boundary instead of failing. """ - name = "integer range" + name = "int range" def _clamp( # type: ignore self, bound: int, dir: Literal[1, -1], open: bool diff --git a/typer/_types.py b/typer/_types.py index 09b38afb3f..26086fb270 100644 --- a/typer/_types.py +++ b/typer/_types.py @@ -50,7 +50,7 @@ def normalize_choice( def get_metavar(self, param: _click.Parameter, ctx: _click.Context) -> str | None: if param.param_type_name == "option" and not param.show_choices: # type: ignore choice_metavars = [ - types.convert_type(type(choice)).name.upper() for choice in self.choices + types.convert_type(type(choice)).name for choice in self.choices ] choices_str = "|".join([*dict.fromkeys(choice_metavars)]) else: @@ -58,12 +58,8 @@ def get_metavar(self, param: _click.Parameter, ctx: _click.Context) -> str | Non [str(i) for i in self._normalized_mapping(ctx=ctx).values()] ) - # Use curly braces to indicate a required argument. - if param.required and param.param_type_name == "argument": - return f"{{{choices_str}}}" - - # Use square braces to indicate an option or optional argument. - return f"[{choices_str}]" + # Use square braces as it's a type. + return f"<{choices_str}>" def get_missing_message( self, param: _click.Parameter, ctx: _click.Context | None diff --git a/typer/cli.py b/typer/cli.py index 665bcf5a59..98f9f4ec77 100644 --- a/typer/cli.py +++ b/typer/cli.py @@ -161,7 +161,7 @@ def print_version(ctx: _click.Context, param: TyperOption, value: bool) -> None: def callback( ctx: typer.Context, *, - path_or_module: str = typer.Argument(None), + path_or_module: str = typer.Argument(None, metavar="PATH_OR_MODULE"), app: str = typer.Option(None, help="The typer app object/variable to use."), func: str = typer.Option(None, help="The function to convert to Typer."), version: bool = typer.Option( diff --git a/typer/core.py b/typer/core.py index 6868ab4355..1bfc399505 100644 --- a/typer/core.py +++ b/typer/core.py @@ -93,12 +93,16 @@ def _get_default_string( if show_default_is_str: default_string = f"({obj.show_default})" elif isinstance(default_value, (list, tuple)): - default_string = ", ".join( + parts = [ _get_default_string( obj, ctx=ctx, show_default_is_str=show_default_is_str, default_value=d ) for d in default_value - ) + ] + if all(not part for part in parts): + default_string = "" + else: + default_string = ", ".join(parts) elif isinstance(default_value, Enum): default_string = str(default_value.value) elif inspect.isfunction(default_value): @@ -125,6 +129,8 @@ def _get_default_string( and not default_value ): default_string = "" + elif default_value is None: + default_string = "" else: default_string = str(default_value) return default_string @@ -303,7 +309,7 @@ def human_readable_name(self) -> str: if self.metavar is not None: return self.metavar assert self.name is not None, "self.name or self.metavar should be set" - return self.name.upper() + return self.name def _get_default_string( self, @@ -380,17 +386,21 @@ def get_help_record(self, ctx: _click.Context) -> tuple[str, str] | None: help = f"{help} {extra_str}" if help else f"{extra_str}" return name, help - def make_metavar(self, ctx: _click.Context) -> str: + def make_metavar(self, ctx: _click.Context, *, usage: bool = False) -> str: # Modified version of _click.core.Argument.make_metavar() # to include Argument name if self.metavar is not None: var = self.metavar - if not self.required and not var.startswith("["): - var = f"[{var}]" - return var - var = (self.name or "").upper() - if not self.required: + if var.startswith("[") or not usage: + return var + if not self.required: + return f"[{var}]" + return f"{{{var}}}" + var = self.name or "" + if usage and not self.required: var = f"[{var}]" + elif usage and self.required: + var = f"{{{var}}}" type_var = self.type.get_metavar(self, ctx=ctx) if type_var: var += f":{type_var}" @@ -410,7 +420,7 @@ def _parse_decls( raise TypeError("Argument is marked as exposed, but does not have a name.") if len(decls) == 1: name = arg = decls[0] - name = name.replace("-", "_").lower() + name = name.replace("-", "_") else: raise TypeError( "Arguments take exactly one parameter declaration, got" @@ -419,10 +429,10 @@ def _parse_decls( return name, [arg], [] def get_usage_pieces(self, ctx: _click.Context) -> list[str]: - return [self.make_metavar(ctx)] + return [self.make_metavar(ctx, usage=True)] def get_error_hint(self, ctx: _click.Context) -> str: - return f"'{self.make_metavar(ctx)}'" + return f"'{self.human_readable_name}'" def add_to_parser(self, parser: _OptionParser, ctx: _click.Context) -> None: parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) @@ -575,7 +585,7 @@ def _parse_decls( if name is None and possible_names: possible_names.sort(key=lambda x: -len(x[0])) # group long options first - name = possible_names[0][1].replace("-", "_").lower() + name = possible_names[0][1].replace("-", "_") if not name.isidentifier(): name = None diff --git a/typer/main.py b/typer/main.py index a825c1b14e..700648da66 100644 --- a/typer/main.py +++ b/typer/main.py @@ -1361,6 +1361,15 @@ def get_command_name(name: str) -> str: return name.lower().replace("_", "-") +def get_default_option_flag_name(name: str, metavar: str | None) -> str: + flag_name = name.replace("_", "-") + if metavar is not None: + meta_flag = metavar.replace("_", "-") + if meta_flag.lower() == flag_name.lower(): + return meta_flag + return flag_name + + def get_params_convertors_ctx_param_name_from_function( callback: Callable[..., Any] | None, ) -> tuple[list[TyperArgument | TyperOption], dict[str, Any], str | None]: @@ -1699,7 +1708,9 @@ def get_click_param( # Click doesn't accept a flag of type bool, only None, and then it sets it # to bool internally parameter_type = None - default_option_name = get_command_name(param.name) + default_option_name = get_default_option_flag_name( + param.name, parameter_info.metavar + ) if is_flag: default_option_declaration = ( f"--{default_option_name}/--no-{default_option_name}" diff --git a/typer/rich_utils.py b/typer/rich_utils.py index de68f60644..5c6e510db5 100644 --- a/typer/rich_utils.py +++ b/typer/rich_utils.py @@ -370,13 +370,16 @@ def _print_options_panel( metavar_type = None metavar_str = param.make_metavar(ctx=ctx) if isinstance(param, TyperArgument): - # TODO: revise this legacy behaviour of keeping argument names lowercased for Rich formatting - if param.metavar is None and param.name: - metavar_name = metavar_str.replace(param.name.upper(), param.name) + if param.metavar is not None: + metavar_name = param.metavar else: - metavar_name = metavar_str + metavar_name = param.name or "" if isinstance(param, TyperOption): metavar_type = metavar_str + elif isinstance(param, TyperArgument): + metavar_type = param.type.get_metavar(param=param, ctx=ctx) + if metavar_type is None: + metavar_type = f"<{param.type.name}>" for opt_str in param.opts: if "--" in opt_str: @@ -397,12 +400,8 @@ def _print_options_panel( types_data = Text(style=STYLE_TYPES, overflow="fold") # Fetch type - if metavar_type and metavar_type != "BOOLEAN": + if metavar_type and "bool" not in metavar_type.lower(): types_data.append(metavar_type) - else: - type_str = param.type.name.upper() - if type_str != "BOOLEAN": - types_data.append(type_str) # Range - from # https://github.com/pallets/click/blob/c63c70dabd3f86ca68678b4f00951f78f52d0270/src/click/core.py#L2698-L2706 # noqa: E501 @@ -704,12 +703,13 @@ def rich_format_error(self: _click.ClickException) -> None: console = _get_rich_console(stderr=True) ctx: _click.Context | None = getattr(self, "ctx", None) if ctx is not None: - console.print(ctx.get_usage()) + console.print(highlighter(ctx.get_usage()), style=STYLE_USAGE_COMMAND) if ctx is not None and ctx.command.get_help_option(ctx) is not None: console.print( RICH_HELP.format( - command_path=ctx.command_path, help_option=ctx.help_option_names[0] + command_path=escape(ctx.command_path), + help_option=ctx.help_option_names[0], ), style=STYLE_ERRORS_SUGGESTION, )