diff --git a/.gitignore b/.gitignore index 11b71aa3..c3c267ce 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ Pipfile.lock # pyenv version file .python-version + +# uv +uv.lock diff --git a/Pipfile b/Pipfile index b9cdea27..f3b932ff 100644 --- a/Pipfile +++ b/Pipfile @@ -10,11 +10,13 @@ wcwidth = ">=0.1.7" [dev-packages] black = "*" +build = "*" cmd2 = {editable = true,path = "."} cmd2_ext_test = {editable = true,path = "plugins/ext_test"} codecov = "*" doc8 = "*" flake8 = "*" +Flake8-pyproject = "*" gnureadline = {version = "*",sys_platform = "== 'darwin'"} invoke = "*" ipython = "*" @@ -24,6 +26,7 @@ pyreadline3 = {version = ">=3.4",sys_platform = "== 'win32'"} pytest = "*" pytest-cov = "*" pytest-mock = "*" +ruff = "*" sphinx = "*" sphinx-autobuild = "*" sphinx-rtd-theme = "*" diff --git a/cmd2/__init__.py b/cmd2/__init__.py index 8f1f030e..e12827ae 100644 --- a/cmd2/__init__.py +++ b/cmd2/__init__.py @@ -106,4 +106,5 @@ 'CompletionMode', 'CustomCompletionSettings', 'Settable', + 'PassThroughException', ] diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index e4601307..9bb86e9f 100644 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -92,7 +92,7 @@ def _looks_like_flag(token: str, parser: argparse.ArgumentParser) -> bool: return False # Flags have to start with a prefix character - if not token[0] in parser.prefix_chars: + if token[0] not in parser.prefix_chars: return False # If it looks like a negative number, it is not a flag unless there are negative-number-like flags diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 566d7878..5b033d04 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -5537,7 +5537,7 @@ def cmdloop(self, intro: Optional[str] = None) -> int: # type: ignore[override] """ # cmdloop() expects to be run in the main thread to support extensive use of KeyboardInterrupts throughout the # other built-in functions. You are free to override cmdloop, but much of cmd2's features will be limited. - if not threading.current_thread() is threading.main_thread(): + if threading.current_thread() is not threading.main_thread(): raise RuntimeError("cmdloop must be run in the main thread") # Register signal handlers diff --git a/pyproject.toml b/pyproject.toml index de8bb406..af2667b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,86 @@ [build-system] -requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"] +requires = [ + "setuptools>=64", + "setuptools-scm>=8", +] + +#[project] +#name = "cmd2" +#description = "Quickly build feature-rich and user-friendly interactive command line applications in Python" +#readme = "README.md" +#license.file = "LICENSE" +#authors = [ { name = "cmd2 Contributors" } ] +#requires-python = ">=3.8" +#classifiers = [ +# "Development Status :: 5 - Production/Stable", +# "Environment :: Console", +# "Intended Audience :: Developers", +# "Intended Audience :: System Administrators", +# "License :: OSI Approved :: MIT License", +# "Operating System :: MacOS", +# "Operating System :: Microsoft :: Windows", +# "Operating System :: POSIX", +# "Operating System :: Unix", +# "Programming Language :: Python", +# "Programming Language :: Python :: 3 :: Only", +# "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 :: Implementation :: CPython", +# "Topic :: Software Development :: Libraries", +#] +#keywords = [ +# "cmd", +# "command", +# "console", +# "prompt", +#] +#dynamic = [ +# "version", +#] +#dependencies = [ +# "pyperclip", +# "wcwidth", +# 'gnureadline ; platform_system == "Darwin"', +# 'pyreadline3 ; platform_system == "Windows"', +#] +#[project.optional-dependencies] +#dev = [ +# "codecov", +# "doc8", +# "flake8", +# "Flake8-pyproject", +# "black", +# "isort", +# "invoke", +# "mypy", +# "nox", +# "pytest", +# "pytest-cov", +# "pytest-mock", +# "sphinx", +# "sphinx-rtd-theme", +# "sphinx-autobuild", +# "twine", +#] +#test = [ +# "codecov", +# "coverage", +# "pytest", +# "pytest-cov", +# "pytest-mock", +#] +#validate = [ +# "flake8", +# "Flake8-pyproject", +# "mypy", +# "types-setuptools", +#] +#[project.urls] +#documentation = "https://cmd2.readthedocs.io/" +#repository = "https://github.com/python-cmd2/cmd2" [tool.black] skip-string-normalization = true @@ -25,3 +106,134 @@ exclude = ''' | htmlcov )/ ''' + +[tool.doc8] +ignore-path = [ + "__pycache__", + "*.egg", + ".git", + ".idea", + ".nox", + ".pytest_cache", + ".tox", + ".venv", + ".vscode", + "build", + "cmd2", + "cmd2.egg-info", + "dist", + "docs/_build", + "examples", + "htmlcov", + "plugins", + "tests", +] +max-line-length = 120 +verbose = 0 + +[tool.flake8] +count = true +ignore = ['E203', 'E704', 'W503'] +max-complexity = 26 +max-line-length = 127 +per-file-ignores = [ + '__init__.py:F401', +] +show-source = true +statistics = true +exclude = [ + "__pycache__", + ".eggs", + "*.eggs", + ".git", + ".idea", + ".nox", + ".pytest_cache", + ".tox", + ".venv", + ".vscode", + "build", + "dist", + "htmlcov", +] + +[tool.isort] +profile = "black" +force_grid_wrap = 0 +include_trailing_comma = true +line_length = 1 +multi_line_output = 3 +use_parentheses = true +skip = [ + "__pycache", + ".eggs", + ".git", + ".idea", + ".nox", + ".tox", + ".venv", + ".vscode", + "cmd2/__init__.py", + "build", + "dist", + "htmlcov", +] + +[tool.mypy] +disallow_incomplete_defs = true +disallow_untyped_calls = true +disallow_untyped_defs = true +exclude = [ + "examples", + "plugins", +] +strict = true +show_column_numbers = true +show_error_codes = true +show_error_context = true +warn_redundant_casts = true +warn_return_any = true +warn_unused_ignores = false +warn_unreachable = true + +[tool.pytest.ini_options] +minversion = "8" +addopts = "--cov=cmd2 --cov-append --cov-report=term --cov-report=html" +testpaths = [ + "tests", +] + +[tool.ruff] +src = ["cmd2"] +fix = true +line-length = 127 +lint.preview = true +exclude=[ + ".git", + "__pycache__", + "dist", + "docs/_build", + "build", +] + +[tool.ruff.format] +docstring-code-format = true +#quote-style = "double" + +[tool.ruff.lint.isort] +force-single-line = true +from-first = false +lines-between-types = 1 +order-by-type = true + +[tool.setuptools.package-data] +"cmd2" = ["py.typed"] + +[tool.setuptools.packages.find] +where = ["cmd2"] +namespaces = false + +[tool.setuptools_scm] +git_describe_command = "git describe --dirty --tags --long --exclude plugin-*" + + diff --git a/setup.cfg b/setup.cfg index 5f26578f..8aef9e0b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,37 +7,6 @@ addopts = --cov-report=term --cov-report=html -[flake8] -count = True -ignore = E203,W503,E704 -max-complexity = 26 -max-line-length = 127 -show-source = True -statistics = True -exclude = - .git - __pycache__ - .tox - .nox - .eggs - *.eggs, - .venv, - .idea, - .pytest_cache, - .vscode, - build, - dist, - htmlcov - -[isort] -line_length = 1 -skip = cmd2/__init__.py,.git,__pycache,.tox,.nox,.venv,.eggs,.idea,.vscode,build,dist.htmlcov -profile = black -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true - [doc8] ignore-path=docs/_build,.git,.idea,.pytest_cache,.tox,.nox,.venv,.vscode,build,cmd2,examples,tests,cmd2.egg-info,dist,htmlcov,__pycache__,*.egg,plugins max-line-length=120 diff --git a/tasks.py b/tasks.py index e0eb16a0..b43800f4 100644 --- a/tasks.py +++ b/tasks.py @@ -366,3 +366,14 @@ def format(context): namespace.add_task(format) + + +# Ruff fast auto-formatter and linter +@invoke.task() +def ruff(context): + """Run ruff auto-formatter and linter""" + with context.cd(TASK_ROOT_STR): + context.run("ruff check") + + +namespace.add_task(ruff) \ No newline at end of file diff --git a/tests/test_completion.py b/tests/test_completion.py index 2eebaaeb..f7e0b585 100755 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -274,7 +274,7 @@ def test_cmd2_help_completion_nomatch(cmd2_app): def test_set_allow_style_completion(cmd2_app): """Confirm that completing allow_style presents AllowStyle strings""" text = '' - line = 'set allow_style'.format(text) + line = 'set allow_style'.format() endidx = len(line) begidx = endidx - len(text) @@ -288,7 +288,7 @@ def test_set_allow_style_completion(cmd2_app): def test_set_bool_completion(cmd2_app): """Confirm that completing a boolean Settable presents true and false strings""" text = '' - line = 'set debug'.format(text) + line = 'set debug'.format() endidx = len(line) begidx = endidx - len(text)