-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Provide callables for popular tools
- Loading branch information
Showing
15 changed files
with
3,601 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
"""Module containing callables for many tools. | ||
Tip: Call to developers! | ||
If you are the author or maintainer of one of the tools we support | ||
(or more generally if you are the author/maintainer of a Python CLI/library), | ||
we kindly request that you add such a callable to your code base. Why? | ||
- Most of the time, all `duty` can do is hook into the CLI entrypoint | ||
for the lack of a better alternative. This is not ideal because | ||
we have to translate function arguments to CLI arguments, | ||
that are then parsed again and translated back to Python objects | ||
by the tool itself. This is not efficient. | ||
- It is not feasible for `duty` to maintain callables for different versions | ||
of these tools. Having the callables maintained in the tools | ||
themselves would make this support transparent. | ||
- We believe it simply provides a better user- *and* developer-experience. | ||
Clear separation of concerns: don't intertwine logic into the CLI parser. | ||
Easy to maintain, easy to test. The CLI parser just has to translate CLI args | ||
to their equivalent Python arguments. | ||
Tips for writing such a library entry point: | ||
- Make it equivalent to the CLI entry point: every flag and option must have an equivalent parameter. | ||
Slight customizations can be made to support `--flag` / `--no-flag` with single parameters. | ||
- Use only built-in types: don't make users import and use objects from your API. | ||
For example, accept a list of strings, not a list of `MyCustomClass` instances. | ||
""" | ||
|
||
from functools import wraps | ||
from typing import Callable | ||
|
||
|
||
def _named(name: str) -> Callable: | ||
def decorator(func: Callable) -> Callable: | ||
@wraps(func) | ||
def inner(*args, **kwargs): # noqa: ANN002,ANN003,ANN202 | ||
return func(*args, **kwargs) | ||
|
||
inner.__name__ = name | ||
return inner | ||
|
||
return decorator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import sys | ||
from io import StringIO | ||
|
||
|
||
class _LazyStdout(StringIO): | ||
def __repr__(self) -> str: | ||
return "stdout" | ||
|
||
def write(self, value: str) -> int: | ||
return sys.stdout.write(value) | ||
|
||
|
||
class _LazyStderr(StringIO): | ||
def __repr__(self) -> str: | ||
return "stderr" | ||
|
||
def write(self, value: str) -> int: | ||
return sys.stderr.write(value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
"""Callable for [autoflake](https://github.com/PyCQA/autoflake).""" | ||
|
||
from __future__ import annotations | ||
|
||
from autoflake import _main as autoflake | ||
|
||
from duty.callables import _io, _named | ||
|
||
|
||
@_named("autoflake") | ||
def run( | ||
*files: str, | ||
config: str | None = None, | ||
check: bool | None = None, | ||
check_diff: bool | None = None, | ||
imports: list[str] | None = None, | ||
remove_all_unused_imports: bool | None = None, | ||
recursive: bool | None = None, | ||
jobs: int | None = None, | ||
exclude: list[str] | None = None, | ||
expand_star_imports: bool | None = None, | ||
ignore_init_module_imports: bool | None = None, | ||
remove_duplicate_keys: bool | None = None, | ||
remove_unused_variables: bool | None = None, | ||
remove_rhs_for_unused_variables: bool | None = None, | ||
ignore_pass_statements: bool | None = None, | ||
ignore_pass_after_docstring: bool | None = None, | ||
quiet: bool | None = None, | ||
verbose: bool | None = None, | ||
stdin_display_name: str | None = None, | ||
in_place: bool | None = None, | ||
stdout: bool | None = None, | ||
) -> int: | ||
r"""Run `autoflake`. | ||
Parameters: | ||
*files: Files to format. | ||
config: Explicitly set the config file instead of auto determining based on file location. | ||
check: Return error code if changes are needed. | ||
check_diff: Return error code if changes are needed, also display file diffs. | ||
imports: By default, only unused standard library imports are removed; specify a comma-separated list of additional modules/packages. | ||
remove_all_unused_imports: Remove all unused imports (not just those from the standard library). | ||
recursive: Drill down directories recursively. | ||
jobs: Number of parallel jobs; match CPU count if value is 0 (default: 0). | ||
exclude: Exclude file/directory names that match these comma-separated globs. | ||
expand_star_imports: Expand wildcard star imports with undefined names; this only triggers if there is only one star import in the file; this is skipped if there are any uses of `__all__` or `del` in the file. | ||
ignore_init_module_imports: Exclude `__init__.py` when removing unused imports. | ||
remove_duplicate_keys: Remove all duplicate keys in objects. | ||
remove_unused_variables: Remove unused variables. | ||
remove_rhs_for_unused_variables: Remove RHS of statements when removing unused variables (unsafe). | ||
ignore_pass_statements: Ignore all pass statements. | ||
ignore_pass_after_docstring: Ignore pass statements after a newline ending on `\"\"\"`. | ||
quiet: Suppress output if there are no issues. | ||
verbose: Print more verbose logs (you can repeat `-v` to make it more verbose). | ||
stdin_display_name: The name used when processing input from stdin. | ||
in_place: Make changes to files instead of printing diffs. | ||
stdout: Print changed text to stdout. defaults to true when formatting stdin, or to false otherwise. | ||
""" | ||
cli_args = list(files) | ||
|
||
if check: | ||
cli_args.append("--check") | ||
|
||
if check_diff: | ||
cli_args.append("--check-diff") | ||
|
||
if imports: | ||
cli_args.append("--imports") | ||
cli_args.append(",".join(imports)) | ||
|
||
if remove_all_unused_imports: | ||
cli_args.append("--remove-all-unused-imports") | ||
|
||
if recursive: | ||
cli_args.append("--recursive") | ||
|
||
if jobs: | ||
cli_args.append("--jobs") | ||
cli_args.append(str(jobs)) | ||
|
||
if exclude: | ||
cli_args.append("--exclude") | ||
cli_args.append(",".join(exclude)) | ||
|
||
if expand_star_imports: | ||
cli_args.append("--expand-star-imports") | ||
|
||
if ignore_init_module_imports: | ||
cli_args.append("--ignore-init-module-imports") | ||
|
||
if remove_duplicate_keys: | ||
cli_args.append("--remove-duplicate-keys") | ||
|
||
if remove_unused_variables: | ||
cli_args.append("--remove-unused-variables") | ||
|
||
if remove_rhs_for_unused_variables: | ||
cli_args.append("remove-rhs-for-unused-variables") | ||
|
||
if ignore_pass_statements: | ||
cli_args.append("--ignore-pass-statements") | ||
|
||
if ignore_pass_after_docstring: | ||
cli_args.append("--ignore-pass-after-docstring") | ||
|
||
if quiet: | ||
cli_args.append("--quiet") | ||
|
||
if verbose: | ||
cli_args.append("--verbose") | ||
|
||
if stdin_display_name: | ||
cli_args.append("--stdin-display-name") | ||
cli_args.append(stdin_display_name) | ||
|
||
if config: | ||
cli_args.append("--config") | ||
cli_args.append(config) | ||
|
||
if in_place: | ||
cli_args.append("--in-place") | ||
|
||
if stdout: | ||
cli_args.append("--stdout") | ||
|
||
return autoflake(cli_args, standard_out=_io._LazyStdout(), standard_error=_io._LazyStderr()) # noqa: SLF001 |
Oops, something went wrong.