diff --git a/README.md b/README.md
index a15ac0090f..e8ec1a3135 100644
--- a/README.md
+++ b/README.md
@@ -98,7 +98,7 @@ Options:
--show-completion Show completion for the current shell, to copy it or customize the installation.
--help Show this message and exit.
-// You get a ✨ auto completion ✨ for free, installed with --install-completion
+// You get ✨ auto completion ✨ for free, installed with --install-completion
// Now pass the NAME argument
$ python main.py Camila
diff --git a/docs/css/custom.css b/docs/css/custom.css
index 4c9a17852e..d4063f29d6 100644
--- a/docs/css/custom.css
+++ b/docs/css/custom.css
@@ -1,4 +1,9 @@
.termynal-comment {
- color: #999;
+ color: #4a968f;
font-style: italic;
+ display: block;
+}
+
+.termy {
+ white-space: pre-wrap;
}
diff --git a/docs/index.md b/docs/index.md
index a15ac0090f..e8ec1a3135 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -98,7 +98,7 @@ Options:
--show-completion Show completion for the current shell, to copy it or customize the installation.
--help Show this message and exit.
-// You get a ✨ auto completion ✨ for free, installed with --install-completion
+// You get ✨ auto completion ✨ for free, installed with --install-completion
// Now pass the NAME argument
$ python main.py Camila
diff --git a/docs/js/custom.js b/docs/js/custom.js
index bbd0b29317..cd21d165e7 100644
--- a/docs/js/custom.js
+++ b/docs/js/custom.js
@@ -6,6 +6,7 @@ document.querySelectorAll(".use-termynal").forEach(node => {
});
const progressLiteralStart = "---> 100%";
const promptLiteralStart = "$ ";
+const customPromptLiteralStart = "# ";
const termynalActivateClass = "termy";
let termynals = [];
@@ -29,8 +30,8 @@ function createTermynals() {
if (isBlankSpace) {
dataValue["delay"] = 0;
}
- if (buffer.length > 1 && buffer[buffer.length - 1] === "") {
- // The last single
won't have effect
+ if (buffer[buffer.length - 1] === "") {
+ // A last single
won't have effect
// so put an additional one
buffer.push("");
}
@@ -55,12 +56,25 @@ function createTermynals() {
});
} else if (line.startsWith("// ")) {
saveBuffer();
- const value = line.replace("// ", "").trimEnd();
+ const value = "💬 " + line.replace("// ", "").trimEnd();
useLines.push({
value: value,
class: "termynal-comment",
delay: 0
});
+ } else if (line.startsWith(customPromptLiteralStart)) {
+ saveBuffer();
+ const promptStart = line.indexOf(promptLiteralStart);
+ if (promptStart === -1) {
+ console.error("Custom prompt found but no end delimiter", line)
+ }
+ const prompt = line.slice(0, promptStart).replace(customPromptLiteralStart, "")
+ let value = line.slice(promptStart + promptLiteralStart.length);
+ useLines.push({
+ type: "input",
+ value: value,
+ prompt: prompt
+ });
} else {
buffer.push(line);
}
diff --git a/docs/js/termynal.js b/docs/js/termynal.js
index e66321effe..47f7f47e62 100644
--- a/docs/js/termynal.js
+++ b/docs/js/termynal.js
@@ -243,12 +243,10 @@ class Termynal {
attrs += ` class=${line[prop]} `
continue
}
- attrs += this.pfx;
-
if (prop === 'type') {
- attrs += `="${line[prop]}" `
+ attrs += `${this.pfx}="${line[prop]}" `
} else if (prop !== 'value') {
- attrs += `-${prop}="${line[prop]}" `
+ attrs += `${this.pfx}-${prop}="${line[prop]}" `
}
}
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 5b620f0b57..bb7e52a70d 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -3,7 +3,7 @@
## 0.0.5
* Clean exports from Typer. Remove unneeded components from Click and add needed `Exit` exception. PR [#11](https://github.com/tiangolo/typer/pull/11).
-* Fix and document extracting help from a functions' docstring [First Steps: Document your CLI app](https://typer.tiangolo.com/tutorial/first-steps/#document-your-cli-app). PR [#10](https://github.com/tiangolo/typer/pull/10).
+* Fix and document extracting help from a function's docstring [First Steps: Document your CLI app](https://typer.tiangolo.com/tutorial/first-steps/#document-your-cli-app). PR [#10](https://github.com/tiangolo/typer/pull/10).
* Update references to `--install-completion` and `--show-completion` in docs. PR [#9](https://github.com/tiangolo/typer/pull/9).
* Fix testing utilities, add tests for First Steps examples. PR [#8](https://github.com/tiangolo/typer/pull/8).
* Add auto completion options by default when [click-completion](https://github.com/click-contrib/click-completion) is installed: `--install-completion` and `--show-completion`. PR [#7](https://github.com/tiangolo/typer/pull/7).
diff --git a/docs/src/options/tutorial001.py b/docs/src/options/tutorial001.py
new file mode 100644
index 0000000000..1e3bddcd30
--- /dev/null
+++ b/docs/src/options/tutorial001.py
@@ -0,0 +1,21 @@
+import typer
+
+
+def main(
+ name: str,
+ lastname: str = typer.Option("", help="Last name of person to greet."),
+ formal: bool = typer.Option(False, help="Say hi formally."),
+):
+ """
+ Say hi to NAME, optionally with a --lastname.
+
+ If --formal is used, say hi very formally.
+ """
+ if formal:
+ typer.echo(f"Good day Ms. {name} {lastname}.")
+ else:
+ typer.echo(f"Hello {name} {lastname}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs/src/options/tutorial002.py b/docs/src/options/tutorial002.py
new file mode 100644
index 0000000000..f62221b75b
--- /dev/null
+++ b/docs/src/options/tutorial002.py
@@ -0,0 +1,9 @@
+import typer
+
+
+def main(name: str, lastname: str = typer.Option(...)):
+ typer.echo(f"Hello {name} {lastname}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs/src/options/tutorial003.py b/docs/src/options/tutorial003.py
new file mode 100644
index 0000000000..2da2592455
--- /dev/null
+++ b/docs/src/options/tutorial003.py
@@ -0,0 +1,9 @@
+import typer
+
+
+def main(name: str, lastname: str = typer.Option(..., prompt=True)):
+ typer.echo(f"Hello {name} {lastname}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs/src/options/tutorial004.py b/docs/src/options/tutorial004.py
new file mode 100644
index 0000000000..d9a19a9c76
--- /dev/null
+++ b/docs/src/options/tutorial004.py
@@ -0,0 +1,12 @@
+import typer
+
+
+def main(
+ name: str,
+ lastname: str = typer.Option(..., prompt="Please tell me your last name"),
+):
+ typer.echo(f"Hello {name} {lastname}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs/src/options/tutorial005.py b/docs/src/options/tutorial005.py
new file mode 100644
index 0000000000..11471d7a64
--- /dev/null
+++ b/docs/src/options/tutorial005.py
@@ -0,0 +1,9 @@
+import typer
+
+
+def main(project_name: str = typer.Option(..., prompt=True, confirmation_prompt=True)):
+ typer.echo(f"Deleting project {project_name}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs/src/options/tutorial006.py b/docs/src/options/tutorial006.py
new file mode 100644
index 0000000000..9beb205b01
--- /dev/null
+++ b/docs/src/options/tutorial006.py
@@ -0,0 +1,9 @@
+import typer
+
+
+def main(fullname: str = typer.Option("Wade Wilson", show_default=True)):
+ typer.echo(f"Hello {fullname}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs/tutorial/first-steps.md b/docs/tutorial/first-steps.md
index 92316261c0..fedad69580 100644
--- a/docs/tutorial/first-steps.md
+++ b/docs/tutorial/first-steps.md
@@ -22,7 +22,7 @@ Hello World
// Now check the --help
$ python main.py --help
-Usage: tryit.py [OPTIONS]
+Usage: main.py [OPTIONS]
Options:
--install-completion Install completion for the current shell.
@@ -174,16 +174,28 @@ $ ls --size ./myproject
The main visual difference between a *CLI option* and and a *CLI argument* is that the *CLI option* has `--` prepended to the name, like in "`--size`".
-A *CLI option* doesn't depend on the order because it has a predefined name (here it's `--size`). This is because the CLI app is looking specifically for a literal `--size` parameter or "flag", with that specific "name" (here the specific name is "`--size`"). The CLI app will check if you typed it or not, it will be actively looking for `--size` even if you didn't type it (to check if it's there or not).
+A *CLI option* doesn't depend on the order because it has a predefined name (here it's `--size`). This is because the CLI app is looking specifically for a literal `--size` parameter (also known as "flag" or "switch"), with that specific "name" (here the specific name is "`--size`"). The CLI app will check if you typed it or not, it will be actively looking for `--size` even if you didn't type it (to check if it's there or not).
-In contrast, the CLI app is not actively looking for the *CLI argument* with a text "`./myproject`", it has no way to know if you would type `./myproject` or `./mysuperawesomeproject` or anything else. It's just waiting to get whatever you give it. The only way to know that you refer to a specific *CLI argument* is because of the order. The same way that it knows that the first *CLI argument* was the `name` and the second was the `lastname`, but if you mixed the order, it wouldn't be able to handle it.
+In contrast, the CLI app is not actively looking for the *CLI argument* with a text "`./myproject`", it has no way to know if you would type `./myproject` or `./my-super-awesome-project` or anything else. It's just waiting to get whatever you give it. The only way to know that you refer to a specific *CLI argument* is because of the order. The same way that it knows that the first *CLI argument* was the `name` and the second was the `lastname`, but if you mixed the order, it wouldn't be able to handle it.
Instead, with a *CLI option*, the order doesn't matter.
Also, by default, a *CLI option* is *optional* (not *required*).
+So, by default:
+
+* A *CLI argument* is **required**
+* A *CLI option* is **optional**
+
+But the *required* and *optional* defaults can be changed.
+
+So, the main and **most important** difference is that:
+
+* *CLI options* **start with `--`** and don't depend on the order
+* *CLI arguments* depend on the **sequence order**
+
!!! tip
- In this example above the *CLI option* `--size` is just a "flag", it's a boolean value, `True` or `False`.
+ In this example above the *CLI option* `--size` is just a "flag" or "switch" that will contain a boolean value, `True` or `False`, depending on if it was added to the command or not.
This one doesn't receive any values. But *CLI options* can also receive values like *CLI arguments*. You'll see how later.
@@ -319,7 +331,7 @@ Now see it with the `--help` option:
```console
$ python main.py --help
-Usage: tutorial006.py [OPTIONS] NAME
+Usage: main.py [OPTIONS] NAME
Say hi to NAME, optionally with a --lastname.
@@ -394,11 +406,11 @@ And a parameter like `name`, that doesn't have a default value, is considered *r
### In CLIs
-When talking about command line interfaces/applications, the words "argument" and "parameter" are commonly used to refer to that data passed to a CLI app, those parameters.
+When talking about command line interfaces/applications, the words **"argument"** and **"parameter"** are commonly used to refer to that data passed to a CLI app, those parameters.
-But those words don't imply anything about the data being required, needing to be passed in a certain order, nor having a flag like `--lastname`.
+But those words **don't imply** anything about the data being required, needing to be passed in a certain order, nor having a flag like `--lastname`.
-The parameters that come with a flag like `--lastname` and a value (or when the flag itself is the value, like `--formal`) are commonly optional, not required. So, when talking about CLIs it's common to call them *optional arguments* or *optional parameters*.
+The parameters that come with a name like `--lastname` (and optionally a value) are commonly optional, not required. So, when talking about CLIs it's common to call them **optional arguments** or **optional parameters**. Sometimes these *optional parameters* that start with `--` are also called a **flag** or a **switch**.
In reality, the parameters that require an order can be made *optional* too. And the ones that come with a flag (like `--lastname`) can be *required* too.
@@ -408,6 +420,6 @@ To try and make it a bit easier, we'll normally use the words "parameter" or "ar
We'll use ***CLI argument*** to refer to those *CLI parameters* that depend on an order. That are **required** by default.
-And we'll use ***CLI option*** to refer to those *CLI parameters* that depend on a flag (like `--lastname`). That are **optional** by default.
+And we'll use ***CLI option*** to refer to those *CLI parameters* that depend on a name that starts with `--` (like `--lastname`). That are **optional** by default.
We will use ***CLI parameter*** to refer to both, *CLI arguments* and *CLI options*.
diff --git a/docs/tutorial/options.md b/docs/tutorial/options.md
new file mode 100644
index 0000000000..a1dc05ddd9
--- /dev/null
+++ b/docs/tutorial/options.md
@@ -0,0 +1,263 @@
+## *CLI options* with help
+
+In the *First Steps* section you saw how to add help for a CLI app/command by adding it to a function's docstring.
+
+Here's how that last example looked like:
+
+```Python
+{!./src/first_steps/tutorial006.py!}
+```
+
+Now we'll add a *help* section to the *CLI options*:
+
+```Python hl_lines="6 7"
+{!./src/options/tutorial001.py!}
+```
+
+We are replacing the default values we had before with `typer.Option()`.
+
+As we no longer have a default value there, the first parameter to `typer.Option()` serves the same purpose of defining that default value.
+
+So, if we had:
+
+```Python
+lastname: str = ""
+```
+
+now we write:
+
+```Python
+lastname: str = typer.Option("")
+```
+
+And both forms achieve the same: a *CLI option* with a default value of an empty string (`""`).
+
+And then we can pass the `help` keyword parameter:
+
+```Python
+lastname: str = typer.Option("", help="this option does this and that")
+```
+
+to create the help for that *CLI option*.
+
+Copy that example from above to a file `main.py`.
+
+Test it:
+
+