diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 875263fe73..cb207b60e2 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
- python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
click-7: [true, false]
fail-fast: false
@@ -25,17 +25,12 @@ jobs:
- name: Install Flit
run: pip install flit
- name: Install Dependencies
- if: ${{ matrix.python-version != '3.6' }}
run: python -m flit install --symlink
- - name: Install Dependencies
- if: ${{ matrix.python-version == '3.6' }}
- # This doesn't install the editable install, so coverage doesn't get subprocesses
- run: python -m pip install ".[test]"
- name: Install Click 7
if: matrix.click-7
run: pip install "click<8.0.0"
- name: Lint
- if: ${{ matrix.python-version != '3.6' && matrix.click-7 == false }}
+ if: ${{ matrix.click-7 == false }}
run: bash scripts/lint.sh
- run: mkdir coverage
- name: Test
diff --git a/.gitignore b/.gitignore
index 8ab16b46cb..1509614ce0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@
*.pyc
__pycache__
env3.7
-env3.6
env
dist
.mypy_cache
diff --git a/README.md b/README.md
index de9420074c..98c6aaad2b 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@
---
-Typer is a library for building CLI applications that users will **love using** and developers will **love creating**. Based on Python 3.6+ type hints.
+Typer is a library for building CLI applications that users will **love using** and developers will **love creating**. Based on Python 3.7+ type hints.
The key features are:
@@ -46,7 +46,7 @@ And it's intended to be the FastAPI of CLIs.
## Requirements
-Python 3.6+
+Python 3.7+
**Typer** stands on the shoulders of a giant. Its only internal dependency is Click.
@@ -286,7 +286,7 @@ You do that with standard modern Python types.
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
-Just standard **Python 3.6+**.
+Just standard **Python 3.7+**.
For example, for an `int`:
diff --git a/docs/features.md b/docs/features.md
index 6b2bbb2b51..e218f25d76 100644
--- a/docs/features.md
+++ b/docs/features.md
@@ -8,7 +8,7 @@ It follows the same design and ideas. If you know **FastAPI**, you already know
## Just Modern Python
-It's all based on standard **Python 3.6 type** declarations. No new syntax to learn. Just standard modern Python.
+It's all based on standard **Python 3.7 type** declarations. No new syntax to learn. Just standard modern Python.
If you need a 2 minute refresher of how to use Python types (even if you don't use FastAPI or Typer), check the FastAPI tutorial section: Python types intro.
diff --git a/docs/index.md b/docs/index.md
index de9420074c..98c6aaad2b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -26,7 +26,7 @@
---
-Typer is a library for building CLI applications that users will **love using** and developers will **love creating**. Based on Python 3.6+ type hints.
+Typer is a library for building CLI applications that users will **love using** and developers will **love creating**. Based on Python 3.7+ type hints.
The key features are:
@@ -46,7 +46,7 @@ And it's intended to be the FastAPI of CLIs.
## Requirements
-Python 3.6+
+Python 3.7+
**Typer** stands on the shoulders of a giant. Its only internal dependency is Click.
@@ -286,7 +286,7 @@ You do that with standard modern Python types.
You don't have to learn a new syntax, the methods or classes of a specific library, etc.
-Just standard **Python 3.6+**.
+Just standard **Python 3.7+**.
For example, for an `int`:
diff --git a/docs/tutorial/package.md b/docs/tutorial/package.md
index 8ad35e60ab..7178b4ed81 100644
--- a/docs/tutorial/package.md
+++ b/docs/tutorial/package.md
@@ -52,7 +52,7 @@ Add `typer[all]` to your dependencies:
$ poetry add "typer[all]"
// It creates a virtual environment for your project
-Creating virtualenv rick-portal-gun-w31dJa0b-py3.6 in /home/rick/.cache/pypoetry/virtualenvs
+Creating virtualenv rick-portal-gun-w31dJa0b-py3.7 in /home/rick/.cache/pypoetry/virtualenvs
Using version ^0.1.0 for typer
Updating dependencies
@@ -83,7 +83,7 @@ Package operations: 15 installs, 0 updates, 0 removals
// Activate that new virtual environment
$ poetry shell
-Spawning shell within /home/rick/.cache/pypoetry/virtualenvs/rick-portal-gun-w31dJa0b-py3.6
+Spawning shell within /home/rick/.cache/pypoetry/virtualenvs/rick-portal-gun-w31dJa0b-py3.7
// Open an editor using this new environment, for example VS Code
$ code ./
@@ -174,7 +174,7 @@ description = ""
authors = ["Rick Sanchez "]
[tool.poetry.dependencies]
-python = "^3.6"
+python = "^3.7"
typer = {extras = ["all"], version = "^0.1.0"}
[tool.poetry.dev-dependencies]
@@ -198,7 +198,7 @@ authors = ["Rick Sanchez "]
readme = "README.md"
[tool.poetry.dependencies]
-python = "^3.6"
+python = "^3.7"
typer = {extras = ["all"], version = "^0.1.0"}
[tool.poetry.dev-dependencies]
@@ -229,7 +229,7 @@ readme = "README.md"
rick-portal-gun = "rick_portal_gun.main:app"
[tool.poetry.dependencies]
-python = "^3.6"
+python = "^3.7"
typer = {extras = ["all"], version = "^0.1.0"}
[tool.poetry.dev-dependencies]
@@ -302,7 +302,7 @@ Your package is installed in the environment created by Poetry, but you can alre
$ which rick-portal-gun
// You get the one from your environment
-/home/rick/.cache/pypoetry/virtualenvs/rick-portal-gun-w31dJa0b-py3.6/bin/rick-portal-gun
+/home/rick/.cache/pypoetry/virtualenvs/rick-portal-gun-w31dJa0b-py3.7/bin/rick-portal-gun
// Try it
$ rick-portal-gun
@@ -659,8 +659,8 @@ Found existing installation: rick-portal-gun 0.1.0
Uninstalling rick-portal-gun-0.1.0:
Would remove:
/home/user/.local/bin/rick-portal-gun
- /home/user/.local/lib/python3.6/site-packages/rick_portal_gun-0.1.0.dist-info/*
- /home/user/.local/lib/python3.6/site-packages/rick_portal_gun/*
+ /home/user/.local/lib/python3.7/site-packages/rick_portal_gun-0.1.0.dist-info/*
+ /home/user/.local/lib/python3.7/site-packages/rick_portal_gun/*
# Proceed (y/n)? $ y
Successfully uninstalled rick-portal-gun-0.1.0
```
@@ -677,10 +677,10 @@ $ pip install --user rick-portal-gun
// Notice that it says "Downloading" 🚀
Collecting rick-portal-gun
Downloading rick_portal_gun-0.1.0-py3-none-any.whl (1.8 kB)
-Requirement already satisfied: typer[all]<0.0.12,>=0.0.11 in ./.local/lib/python3.6/site-packages (from rick-portal-gun) (0.0.11)
-Requirement already satisfied: click<7.2.0,>=7.1.1 in ./anaconda3/lib/python3.6/site-packages (from typer[all]<0.0.12,>=0.0.11->rick-portal-gun) (7.1.1)
-Requirement already satisfied: colorama; extra == "all" in ./anaconda3/lib/python3.6/site-packages (from typer[all]<0.0.12,>=0.0.11->rick-portal-gun) (0.4.3)
-Requirement already satisfied: shellingham; extra == "all" in ./anaconda3/lib/python3.6/site-packages (from typer[all]<0.0.12,>=0.0.11->rick-portal-gun) (1.3.1)
+Requirement already satisfied: typer[all]<0.0.12,>=0.0.11 in ./.local/lib/python3.7/site-packages (from rick-portal-gun) (0.0.11)
+Requirement already satisfied: click<7.2.0,>=7.1.1 in ./anaconda3/lib/python3.7/site-packages (from typer[all]<0.0.12,>=0.0.11->rick-portal-gun) (7.1.1)
+Requirement already satisfied: colorama; extra == "all" in ./anaconda3/lib/python3.7/site-packages (from typer[all]<0.0.12,>=0.0.11->rick-portal-gun) (0.4.3)
+Requirement already satisfied: shellingham; extra == "all" in ./anaconda3/lib/python3.7/site-packages (from typer[all]<0.0.12,>=0.0.11->rick-portal-gun) (1.3.1)
Installing collected packages: rick-portal-gun
Successfully installed rick-portal-gun-0.1.0
```
@@ -738,7 +738,7 @@ readme = "README.md"
rick-portal-gun = "rick_portal_gun.main:app"
[tool.poetry.dependencies]
-python = "^3.6"
+python = "^3.7"
typer = {extras = ["all"], version = "^0.1.0"}
[tool.poetry.dev-dependencies]
diff --git a/docs/tutorial/testing.md b/docs/tutorial/testing.md
index c8b2b76121..31ca867367 100644
--- a/docs/tutorial/testing.md
+++ b/docs/tutorial/testing.md
@@ -85,7 +85,7 @@ Then you can call `pytest` in your directory and it will run your tests:
$ pytest
================ test session starts ================
-platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
+platform linux -- Python 3.7.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /home/user/code/superawesome-cli/app
plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1
collected 1 item
diff --git a/pyproject.toml b/pyproject.toml
index acaf8f895d..e10b2da8da 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,7 +21,6 @@ classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
@@ -33,7 +32,7 @@ requires = [
"click >= 7.1.1, <9.0.0"
]
description-file = "README.md"
-requires-python = ">=3.6"
+requires-python = ">=3.7"
[tool.flit.metadata.urls]
Documentation = "https://typer.tiangolo.com/"
@@ -46,7 +45,7 @@ test = [
"coverage >=6.2,<7.0",
"pytest-xdist >=1.32.0,<4.0.0",
"pytest-sugar >=0.9.4,<0.10.0",
- "mypy ==0.910",
+ "mypy ==1.0.1",
"black >=22.3.0,<23.0.0",
"isort >=5.0.6,<6.0.0",
"rich >=10.11.0,<13.0.0",
diff --git a/scripts/netlify-docs.sh b/scripts/netlify-docs.sh
index e77fbc39ff..1f48dc5b4e 100755
--- a/scripts/netlify-docs.sh
+++ b/scripts/netlify-docs.sh
@@ -4,11 +4,11 @@ set -e
# Install pip
cd /tmp
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
-python3.6 get-pip.py --user
+python3.7 get-pip.py --user
cd -
# Install Flit to be able to install all
-python3.6 -m pip install --user flit
+python3.7 -m pip install --user flit
# Install with Flit
-python3.6 -m flit install --user --deps develop
+python3.7 -m flit install --user --deps develop
# Finally, run mkdocs
-python3.6 -m mkdocs build
+python3.7 -m mkdocs build
diff --git a/tests/test_others.py b/tests/test_others.py
index fb41bdc4f3..a0e1e544b2 100644
--- a/tests/test_others.py
+++ b/tests/test_others.py
@@ -99,8 +99,7 @@ def test_completion_untyped_parameters():
file_path = Path(__file__).parent / "assets/completion_no_types.py"
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
env={
**os.environ,
@@ -121,8 +120,7 @@ def test_completion_untyped_parameters():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
)
assert "Hello World" in result.stdout
@@ -132,8 +130,7 @@ def test_completion_untyped_parameters_different_order_correct_names():
file_path = Path(__file__).parent / "assets/completion_no_types_order.py"
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
env={
**os.environ,
@@ -154,8 +151,7 @@ def test_completion_untyped_parameters_different_order_correct_names():
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
)
assert "Hello World" in result.stdout
diff --git a/tests/test_prog_name.py b/tests/test_prog_name.py
index 58626c7ac2..cfb5a3464f 100644
--- a/tests/test_prog_name.py
+++ b/tests/test_prog_name.py
@@ -7,8 +7,7 @@ def test_custom_prog_name():
file_path = Path(__file__).parent / "assets/prog_name.py"
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path), "--help"],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
)
assert "Usage: custom-name [OPTIONS] I" in result.stdout
diff --git a/tests/test_tracebacks.py b/tests/test_tracebacks.py
index 0289e9c942..8c8ab0295d 100644
--- a/tests/test_tracebacks.py
+++ b/tests/test_tracebacks.py
@@ -8,8 +8,7 @@ def test_traceback_no_rich():
file_path = Path(__file__).parent / "assets/type_error_no_rich.py"
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
env={**os.environ, "_TYPER_STANDARD_TRACEBACK": ""},
)
@@ -17,19 +16,14 @@ def test_traceback_no_rich():
assert "typer.run(main)" in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
def test_traceback_no_rich_short_disable():
file_path = Path(__file__).parent / "assets/type_error_no_rich_short_disable.py"
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
env={**os.environ, "_TYPER_STANDARD_TRACEBACK": ""},
)
@@ -37,19 +31,14 @@ def test_traceback_no_rich_short_disable():
assert "app()" in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
def test_unmodified_traceback():
file_path = Path(__file__).parent / "assets/type_error_normal_traceback.py"
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", str(file_path)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
+ capture_output=True,
encoding="utf-8",
env={**os.environ, "_TYPER_STANDARD_TRACEBACK": ""},
)
@@ -60,8 +49,4 @@ def test_unmodified_traceback():
)
assert "typer.main.get_command(broken_app)()" in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
diff --git a/tests/test_tutorial/test_exceptions/test_tutorial001.py b/tests/test_tutorial/test_exceptions/test_tutorial001.py
index 0a4590bbf5..d58384bcaa 100644
--- a/tests/test_tutorial/test_exceptions/test_tutorial001.py
+++ b/tests/test_tutorial/test_exceptions/test_tutorial001.py
@@ -24,11 +24,7 @@ def test_traceback_rich():
assert "typer.run(main)" not in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
assert "name = 'morty'" in result.stderr
@@ -46,11 +42,7 @@ def test_standard_traceback_env_var():
assert "typer.run(main)" in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
assert "name = 'morty'" not in result.stderr
diff --git a/tests/test_tutorial/test_exceptions/test_tutorial002.py b/tests/test_tutorial/test_exceptions/test_tutorial002.py
index 66286e064d..87390c821e 100644
--- a/tests/test_tutorial/test_exceptions/test_tutorial002.py
+++ b/tests/test_tutorial/test_exceptions/test_tutorial002.py
@@ -24,11 +24,7 @@ def test_traceback_rich():
assert "app()" not in result.stderr
assert "print(password + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
assert "name = 'morty'" not in result.stderr
@@ -46,11 +42,7 @@ def test_standard_traceback_env_var():
assert "app()" in result.stderr
assert "print(password + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
assert "name = 'morty'" not in result.stderr
diff --git a/tests/test_tutorial/test_exceptions/test_tutorial003.py b/tests/test_tutorial/test_exceptions/test_tutorial003.py
index 51cb170eba..86429d4670 100644
--- a/tests/test_tutorial/test_exceptions/test_tutorial003.py
+++ b/tests/test_tutorial/test_exceptions/test_tutorial003.py
@@ -24,11 +24,7 @@ def test_traceback_rich_pretty_short_disable():
assert "app()" in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
assert "name = 'morty'" in result.stderr
diff --git a/tests/test_tutorial/test_exceptions/test_tutorial004.py b/tests/test_tutorial/test_exceptions/test_tutorial004.py
index bb575e4eb2..417e0d4608 100644
--- a/tests/test_tutorial/test_exceptions/test_tutorial004.py
+++ b/tests/test_tutorial/test_exceptions/test_tutorial004.py
@@ -23,11 +23,7 @@ def test_rich_pretty_exceptions_disable():
assert "app()" in result.stderr
assert "print(name + 3)" in result.stderr
- # TODO: when deprecating Python 3.6, remove second option
- assert (
- 'TypeError: can only concatenate str (not "int") to str' in result.stderr
- or "TypeError: must be str, not int" in result.stderr
- )
+ assert 'TypeError: can only concatenate str (not "int") to str' in result.stderr
def test_script():
diff --git a/typer/_completion_shared.py b/typer/_completion_shared.py
index 7cbaf98d75..2e98daa134 100644
--- a/typer/_completion_shared.py
+++ b/typer/_completion_shared.py
@@ -92,7 +92,7 @@ def get_completion_script(*, prog_name: str, complete_var: str, shell: str) -> s
return (
script
% dict(
- complete_func="_{}_completion".format(cf_name),
+ complete_func=f"_{cf_name}_completion",
prog_name=prog_name,
autocomplete_var=complete_var,
)
diff --git a/typer/core.py b/typer/core.py
index c0776368a6..19d8e2b319 100644
--- a/typer/core.py
+++ b/typer/core.py
@@ -400,7 +400,7 @@ def make_metavar(self) -> str:
return self.metavar
var = (self.name or "").upper()
if not self.required:
- var = "[{}]".format(var)
+ var = f"[{var}]"
type_var = self.type.get_metavar(self)
if type_var:
var += f":{type_var}"
diff --git a/typer/main.py b/typer/main.py
index f493e544e2..f10db0b484 100644
--- a/typer/main.py
+++ b/typer/main.py
@@ -51,7 +51,7 @@
def except_hook(
- exc_type: Type[BaseException], exc_value: BaseException, tb: TracebackType
+ exc_type: Type[BaseException], exc_value: BaseException, tb: Optional[TracebackType]
) -> None:
exception_config: Union[DeveloperExceptionConfig, None] = getattr(
exc_value, _typer_developer_exception_attr_name, None
@@ -96,8 +96,8 @@ def except_hook(
)
else:
stack.append(frame)
- # Type ignore ref: https://github.com/python/typeshed/pull/8244
- final_stack_summary = StackSummary.from_list(stack) # type: ignore
+
+ final_stack_summary = StackSummary.from_list(stack)
tb_exc.stack = final_stack_summary
for line in tb_exc.format():
print(line, file=sys.stderr)