Skip to content

Typing #673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -13,17 +13,20 @@ jobs:
fail-fast: false
matrix:
include:
- { python: "3.12", os: "ubuntu-latest", session: "pre-commit" }

- { python: "3.13", os: "ubuntu-latest", session: "pre-commit" }
- { python: "3.10", os: "ubuntu-latest", session: "safety" }

- { python: "3.12", os: "ubuntu-latest", session: "tests" }
- { python: "3.12", os: "windows-latest", session: "tests" }
- { python: "3.12", os: "macos-latest", session: "tests" }
- { python: "3.13", os: "ubuntu-latest", session: "tests" }
- { python: "3.13", os: "windows-latest", session: "tests" }
- { python: "3.13", os: "macos-latest", session: "tests" }

- { python: "3.11", os: "ubuntu-latest", session: "tests" }
- { python: "3.10", os: "ubuntu-latest", session: "tests" }
- { python: "3.11", os: "windows-latest", session: "tests" }
- { python: "3.11", os: "macos-latest", session: "tests" }

- { python: "3.9", os: "ubuntu-latest", session: "tests" }
- { python: "3.8", os: "ubuntu-latest", session: "tests" }
- { python: "3.9", os: "windows-latest", session: "tests" }
- { python: "3.9", os: "macos-latest", session: "tests" }

env:
NOXSESSION: ${{ matrix.session }}
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ repos:
entry: end-of-file-fixer
language: system
types: [text]
stages: [commit, push, manual]
stages: [pre-commit, pre-push, manual]
- id: flake8
name: flake8
entry: flake8
@@ -53,7 +53,7 @@ repos:
entry: trailing-whitespace-fixer
language: system
types: [text]
stages: [commit, push, manual]
stages: [pre-commit, pre-push, manual]
- repo: https://github.com/prettier/pre-commit
rev: v2.1.2
hooks:
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.analysis.typeCheckingMode": "strict"
}
2 changes: 1 addition & 1 deletion examples/replacements.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@


def initials(answers):
return "Are these your initials? {}{}".format(answers["name"][0], answers["surname"][0])
return f"Are these your initials? {answers["name"][0]}{answers["surname"][0]}"


questions = [
123 changes: 59 additions & 64 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -10,22 +10,9 @@
import nox


try:
from nox_poetry import Session
from nox_poetry import session
except ImportError:
message = f"""\
Nox failed to import the 'nox-poetry' package.

Please install it using the following command:

{sys.executable} -m pip install nox-poetry"""
raise SystemExit(dedent(message)) from None


package = "inquirer"
python_versions = ["3.12", "3.11", "3.10", "3.9", "3.8"]
nox.needs_version = ">= 2021.6.6"
PACKAGE = "inquirer"
python_versions = ["3.13", "3.12", "3.11", "3.10", "3.9"]
nox.needs_version = ">= 2023.4.22"
nox.options.sessions = (
"pre-commit",
"safety",
@@ -34,7 +21,7 @@
)


def activate_virtualenv_in_precommit_hooks(session: Session) -> None:
def activate_virtualenv_in_precommit_hooks(session: nox.Session) -> None:
"""Activate virtualenv in hooks installed by pre-commit.

This function patches git hooks installed by pre-commit to activate the
@@ -44,45 +31,38 @@ def activate_virtualenv_in_precommit_hooks(session: Session) -> None:
Args:
session: The Session object.
"""
assert session.bin is not None # nosec

# Only patch hooks containing a reference to this session's bindir. Support
# quoting rules for Python and bash, but strip the outermost quotes so we
# can detect paths within the bindir, like <bindir>/python.
bindirs = [
bindir[1:-1] if bindir[0] in "'\"" else bindir for bindir in (repr(session.bin), shlex.quote(session.bin))
]
hookdir = Path(".git") / "hooks"
if not hookdir.is_dir():
return

virtualenv = session.env.get("VIRTUAL_ENV")
if virtualenv is None:
return

# Only patch hooks containing a reference to this session's bindir
bindir = Path(session.bin)
bindirs = [str(bindir), shlex.quote(str(bindir))]

# Modern headers for different shell types
headers = {
# pre-commit < 2.16.0
"python": f"""\
import os
os.environ["VIRTUAL_ENV"] = {virtualenv!r}
os.environ["PATH"] = os.pathsep.join((
{session.bin!r},
{str(bindir)!r},
os.environ.get("PATH", ""),
))
""",
# pre-commit >= 2.16.0
"bash": f"""\
VIRTUAL_ENV={shlex.quote(virtualenv)}
PATH={shlex.quote(session.bin)}"{os.pathsep}$PATH"
PATH={shlex.quote(str(bindir))}{os.pathsep}$PATH
""",
# pre-commit >= 2.17.0 on Windows forces sh shebang
"/bin/sh": f"""\
VIRTUAL_ENV={shlex.quote(virtualenv)}
PATH={shlex.quote(session.bin)}"{os.pathsep}$PATH"
PATH={shlex.quote(str(bindir))}{os.pathsep}$PATH
""",
}

hookdir = Path(".git") / "hooks"
if not hookdir.is_dir():
return

for hook in hookdir.iterdir():
if hook.name.endswith(".sample") or not hook.is_file():
continue
@@ -92,7 +72,10 @@ def activate_virtualenv_in_precommit_hooks(session: Session) -> None:

text = hook.read_text()

if not any(Path("A") == Path("a") and bindir.lower() in text.lower() or bindir in text for bindir in bindirs):
if not any(
Path("A") == Path("a") and bindir_str.lower() in text.lower() or bindir_str in text
for bindir_str in bindirs
):
continue

lines = text.splitlines()
@@ -104,19 +87,16 @@ def activate_virtualenv_in_precommit_hooks(session: Session) -> None:
break


@session(name="pre-commit", python=python_versions[0])
def precommit(session: Session) -> None:
@nox.session(name="pre-commit", python=python_versions[0])
def pre_commit(session: nox.Session) -> None:
"""Lint using pre-commit."""
args = session.posargs or ["run", "--all-files", "--show-diff-on-failure"]
session.install(
"bandit",
"black",
# "darglint",
"flake8",
# "flake8-bugbear",
"flake8-docstrings",
"isort",
# "pep8-naming",
"pre-commit",
"pre-commit-hooks",
"pyupgrade",
@@ -126,17 +106,32 @@ def precommit(session: Session) -> None:
activate_virtualenv_in_precommit_hooks(session)


@session(python=python_versions[2])
def safety(session: Session) -> None:
@nox.session(python=["3.13", "3.10"])
def safety(session: nox.Session) -> None:
"""Scan dependencies for insecure packages."""
ignore_CVEs = [70612]
requirements = session.poetry.export_requirements()

# Use modern approach for requirements export
requirements: str | None = session.run(
"poetry",
"export",
"--dev",
"--format=requirements.txt",
"--without-hashes",
"--output=-",
external=True,
silent=True,
)
if requirements is None:
session.error("Failed to export requirements.txt from poetry.")
session.install("safety")
session.run("safety", "check", f"--file={requirements}", *[f"-i{id}" for id in ignore_CVEs])
with session.chdir(session.create_tmp()):
requirements_file = Path("requirements.txt")
requirements_file.write_text(requirements, encoding="utf-8")
session.run("safety", "check", f"--file={requirements_file}")


@session(python=python_versions)
def mypy(session: Session) -> None:
@nox.session(python=python_versions)
def mypy(session: nox.Session) -> None:
"""Type-check using mypy."""
args = session.posargs or ["src", "tests", "docs/conf.py"]
session.install(".")
@@ -146,20 +141,20 @@ def mypy(session: Session) -> None:
session.run("mypy", f"--python-executable={sys.executable}", "noxfile.py")


@session(python=python_versions)
def tests(session: Session) -> None:
@nox.session(python=python_versions)
def tests(session: nox.Session) -> None:
"""Run the test suite."""
session.install(".")
session.install("coverage[toml]", "pexpect", "pytest", "pygments")
try:
session.run("coverage", "run", "--parallel", "-m", "pytest", *session.posargs)
finally:
if session.interactive:
session.notify("coverage", posargs=[])
session.notify("coverage")


@session(python=python_versions[0])
def coverage(session: Session) -> None:
@nox.session(python=python_versions[0])
def coverage(session: nox.Session) -> None:
"""Produce the coverage report."""
args = session.posargs or ["report"]

@@ -171,21 +166,21 @@ def coverage(session: Session) -> None:
session.run("coverage", *args)


@session(python=python_versions)
def typeguard(session: Session) -> None:
@nox.session(python=python_versions)
def typeguard(session: nox.Session) -> None:
"""Runtime type checking using Typeguard."""
session.install(".")
session.install("pytest", "typeguard", "pygments")
session.run("pytest", f"--typeguard-packages={package}", *session.posargs)
session.run("pytest", f"--typeguard-packages={PACKAGE}", *session.posargs)


@session(python=python_versions)
def xdoctest(session: Session) -> None:
@nox.session(python=python_versions)
def xdoctest(session: nox.Session) -> None:
"""Run examples with xdoctest."""
if session.posargs:
args = [package, *session.posargs]
args = [PACKAGE, *session.posargs]
else:
args = [f"--modname={package}", "--command=all"]
args = [f"--modname={PACKAGE}", "--command=all"]
if "FORCE_COLOR" in os.environ:
args.append("--colored=1")

@@ -194,8 +189,8 @@ def xdoctest(session: Session) -> None:
session.run("python", "-m", "xdoctest", *args)


@session(name="docs-build", python=python_versions[0])
def docs_build(session: Session) -> None:
@nox.session(name="docs-build", python=python_versions[0])
def docs_build(session: nox.Session) -> None:
"""Build the documentation."""
args = session.posargs or ["docs", "docs/_build"]
if not session.posargs and "FORCE_COLOR" in os.environ:
@@ -211,8 +206,8 @@ def docs_build(session: Session) -> None:
session.run("sphinx-build", *args)


@session(python="3.9")
def docs(session: Session) -> None:
@nox.session(python=python_versions[0])
def docs(session: nox.Session) -> None:
"""Build and serve the documentation with live reloading on file changes."""
args = session.posargs or ["--open-browser", "docs", "docs/_build"]
session.install(".")
34 changes: 17 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -10,11 +10,11 @@ repository = "https://github.com/magmax/python-inquirer"
documentation = "https://python-inquirer.readthedocs.io"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
@@ -24,24 +24,24 @@ classifiers = [
]

[tool.poetry.dependencies]
python = ">=3.8.1"
blessed = ">=1.19.0"
readchar = ">=4.2.0"
editor = ">=1.6.0"
python = ">=3.9"
blessed = ">=1.20.0"
readchar = ">=4.2.1"
editor = ">=1.6.6"

[tool.poetry.dev-dependencies]
bandit = ">=1.7.4"
flake8 = ">=6.1.0"
flake8-docstrings = ">=1.6.0"
furo = ">=2022.9.29"
isort = ">=5.10.1"
pexpect = ">=4.8.0"
pre-commit = ">=2.17.0"
pre-commit-hooks = ">=4.3.0"
pyupgrade = ">=2.31.1"
safety = ">=2.3.1"
sphinx = ">=5.3.0"
sphinx-autobuild = ">=2021.3.14"
bandit = ">=1.8.3"
flake8 = ">=7.1.1"
flake8-docstrings = ">=1.7.0"
furo = ">=2024.8.6"
isort = ">=6.0.0"
pexpect = ">=4.9.0"
pre-commit = ">=4.0.0"
pre-commit-hooks = ">=5.0.0"
pyupgrade = ">=3.19.1"
safety = ">=3.3.1"
sphinx = ">=8.2.3"
sphinx-autobuild = ">=2024.10.3"

[tool.coverage.paths]
source = ["src", "*/site-packages"]
2 changes: 1 addition & 1 deletion src/inquirer/__init__.py
Original file line number Diff line number Diff line change
@@ -14,8 +14,8 @@
from inquirer.shortcuts import editor
from inquirer.shortcuts import list_input
from inquirer.shortcuts import password
from inquirer.shortcuts import text
from inquirer.shortcuts import path
from inquirer.shortcuts import text


__all__ = [
7 changes: 5 additions & 2 deletions src/inquirer/errors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from typing import Any, Optional


class ValidationError(Exception):
def __init__(self, value, reason=None, *args):
def __init__(self, value: Any, reason: Optional[str] = None, *args: Any):
super().__init__(*args)
self.value = value
self.reason = reason
@@ -10,7 +13,7 @@ class UnknownQuestionTypeError(Exception):


class EndOfInput(Exception):
def __init__(self, selection, *args):
def __init__(self, selection: Any, *args: Any):
super().__init__(*args)
self.selection = selection

Loading